sysrpl-mode.el 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. ;;; -*- mode: emacs-lisp; lexical-binding: t -*-
  2. ;;; sysrpl-mode.el -- Major mode for the SysRPL programming language
  3. ;; Copyright (C) 2014 Paul Onions
  4. ;; Author: Paul Onions <paul.onions@acm.org>
  5. ;; Keywords: RPL, SysRPL, HP48, HP49, HP50, calculator
  6. ;; This file is free software, see the LICENCE file in this directory
  7. ;; for copying terms.
  8. ;;; Commentary:
  9. ;; A major mode for the SysRPL language, the system programming
  10. ;; language of HP48/49/50-series calculators.
  11. ;;; Code:
  12. (require 'cl-lib)
  13. (require 'rpl-base)
  14. (require 'rpl-edb)
  15. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  16. ;; Customizations
  17. ;;
  18. (defcustom sysrpl-default-calculator :HP50G
  19. "Default calculator type for SysRPL mode."
  20. :type '(radio :HP38G :HP39G :HP48G :HP49G :HP50G)
  21. :group 'rpl)
  22. (defcustom sysrpl-compiler-program "rplcomp"
  23. "External SysRPL compiler program name."
  24. :type 'string
  25. :group 'rpl)
  26. (defcustom sysrpl-compiler-output-bufname "*rplcomp*"
  27. "Buffer name in which to capture SysRPL compiler output."
  28. :type 'string
  29. :group 'rpl)
  30. (defface sysrpl-name '((t :foreground "darkblue"))
  31. "Face used for displaying SysRPL names (e.g DROP)."
  32. :group 'rpl)
  33. (defface sysrpl-keyword '((t :foreground "purple"))
  34. "Face used for displaying SysRPL keywords (e.g. :: ;)."
  35. :group 'rpl)
  36. (defface sysrpl-comment '((t :foreground "darkgreen"))
  37. "Face used for displaying SysRPL comments."
  38. :group 'rpl)
  39. (defcustom sysrpl-font-lock-name-face 'sysrpl-name
  40. "Name of face to use for displaying SysRPL names."
  41. :type 'symbol
  42. :group 'rpl)
  43. (defcustom sysrpl-font-lock-keyword-face 'sysrpl-keyword
  44. "Name of face to use for displaying SysRPL keywords."
  45. :type 'symbol
  46. :group 'rpl)
  47. (defcustom sysrpl-font-lock-comment-face 'sysrpl-comment
  48. "Name of face to use for displaying SysRPL comments."
  49. :type 'symbol
  50. :group 'rpl)
  51. (defun sysrpl-edb-calculator (calculator)
  52. "Map SysRPL calculator identifier to EDB identifier."
  53. (cond ((eql calculator :HP38G) :38G)
  54. ((eql calculator :HP39G) :39G)
  55. ((eql calculator :HP48G) :48G)
  56. ((eql calculator :HP49G) :49G)
  57. ((eql calculator :HP50G) :49G)))
  58. (defvar sysrpl-mode-syntax-table
  59. (let ((table (make-syntax-table prog-mode-syntax-table)))
  60. (modify-syntax-entry ?: "w" table)
  61. (modify-syntax-entry ?\; "w" table)
  62. (modify-syntax-entry ?! "w" table)
  63. (modify-syntax-entry ?@ "w" table)
  64. (modify-syntax-entry ?# "w" table)
  65. (modify-syntax-entry ?$ "w" table)
  66. (modify-syntax-entry ?% "w" table)
  67. (modify-syntax-entry ?^ "w" table)
  68. (modify-syntax-entry ?& "w" table)
  69. (modify-syntax-entry ?\? "w" table)
  70. (modify-syntax-entry ?- "w" table)
  71. (modify-syntax-entry ?_ "w" table)
  72. (modify-syntax-entry ?= "w" table)
  73. (modify-syntax-entry ?+ "w" table)
  74. (modify-syntax-entry ?* "w" table)
  75. (modify-syntax-entry ?/ "w" table)
  76. (modify-syntax-entry ?< "w" table)
  77. (modify-syntax-entry ?> "w" table)
  78. (modify-syntax-entry ?| "w" table)
  79. table)
  80. "The SysRPL syntax table.")
  81. (defun sysrpl-font-lock-compile-keywords (names)
  82. "Construct a list of keyword matcher clauses suitable for `font-lock-keywords'."
  83. (append (list (list "^\\*.*$" (list 0 'sysrpl-font-lock-comment-face))
  84. (list "(.*)" (list 0 'sysrpl-font-lock-comment-face))
  85. (list (concat "\\<" (regexp-opt '("::" ";")) "\\>") (list 0 'sysrpl-font-lock-keyword-face)))
  86. (mapcar (lambda (str) (list (concat "\\<" (regexp-quote str) "\\>")
  87. (list 0 'sysrpl-font-lock-name-face)))
  88. names)))
  89. (defvar sysrpl-font-lock-keywords
  90. (sysrpl-font-lock-compile-keywords (rpl-edb-all-names (sysrpl-edb-calculator sysrpl-default-calculator))))
  91. (defvar sysrpl-selected-calculator sysrpl-default-calculator
  92. "Currently selected calculator model.")
  93. (defun sysrpl-select-hp38g ()
  94. "Set the currently selected calculator model to be the HP38G."
  95. (interactive)
  96. (setq sysrpl-selected-calculator :HP38G)
  97. (setq sysrpl-font-lock-keywords
  98. (sysrpl-font-lock-compile-keywords (rpl-edb-all-names (sysrpl-edb-calculator :HP38G))))
  99. (sysrpl-mode))
  100. (defun sysrpl-select-hp39g ()
  101. "Set the currently selected calculator model to be the HP39G."
  102. (interactive)
  103. (setq sysrpl-selected-calculator :HP39G)
  104. (setq sysrpl-font-lock-keywords
  105. (sysrpl-font-lock-compile-keywords (rpl-edb-all-names (sysrpl-edb-calculator :HP39G))))
  106. (sysrpl-mode))
  107. (defun sysrpl-select-hp48g ()
  108. "Set the currently selected calculator model to be the HP48G."
  109. (interactive)
  110. (setq sysrpl-selected-calculator :HP48G)
  111. (setq sysrpl-font-lock-keywords
  112. (sysrpl-font-lock-compile-keywords (rpl-edb-all-names (sysrpl-edb-calculator :HP48G))))
  113. (sysrpl-mode))
  114. (defun sysrpl-select-hp49g ()
  115. "Set the currently selected calculator model to be the HP49G."
  116. (interactive)
  117. (setq sysrpl-selected-calculator :HP49G)
  118. (setq sysrpl-font-lock-keywords
  119. (sysrpl-font-lock-compile-keywords (rpl-edb-all-names (sysrpl-edb-calculator :HP49G))))
  120. (sysrpl-mode))
  121. (defun sysrpl-select-hp50g ()
  122. "Set the currently selected calculator model to be the HP50G."
  123. (interactive)
  124. (setq sysrpl-selected-calculator :HP50G)
  125. (setq sysrpl-font-lock-keywords
  126. (sysrpl-font-lock-compile-keywords (rpl-edb-all-names (sysrpl-edb-calculator :HP50G))))
  127. (sysrpl-mode))
  128. (defun sysrpl-get-eldoc-message ()
  129. (interactive)
  130. (rpl-edb-get-stack-effect (sysrpl-edb-calculator sysrpl-selected-calculator)
  131. (thing-at-point 'word)))
  132. (defun sysrpl-apropos-thing-at-point (name)
  133. "Show information about NAME in a popup buffer.
  134. When called interactively NAME defaults to the word around
  135. point."
  136. (interactive (list (completing-read "Apropos: " (rpl-edb-all-names (sysrpl-edb-calculator sysrpl-selected-calculator))
  137. nil nil (thing-at-point 'word))))
  138. (let ((bufname (format "*SysRPL: %s*" name)))
  139. (with-current-buffer (get-buffer-create bufname)
  140. (setq buffer-read-only nil)
  141. (erase-buffer)
  142. (insert (rpl-edb-get-stack-effect (sysrpl-edb-calculator sysrpl-selected-calculator) name))
  143. (newline)
  144. (insert (rpl-edb-get-description (sysrpl-edb-calculator sysrpl-selected-calculator) name))
  145. (newline)
  146. (insert (format "Address: %s" (rpl-edb-get-address (sysrpl-edb-calculator sysrpl-selected-calculator) name)))
  147. (newline)
  148. (insert (format "Flags: %s" (rpl-edb-get-flags (sysrpl-edb-calculator sysrpl-selected-calculator) name)))
  149. (newline)
  150. (end-of-buffer)
  151. (help-mode)
  152. (set-buffer-modified-p nil)
  153. (setq buffer-read-only t))
  154. (fit-window-to-buffer (display-buffer bufname))))
  155. (defun sysrpl-compile-buffer ()
  156. "Compile the current buffer."
  157. (interactive)
  158. (let ((tmp-filename (make-temp-file "sysrpl" nil ".s")))
  159. (write-region (point-min) (point-max) tmp-filename)
  160. (with-current-buffer (get-buffer-create sysrpl-compiler-output-bufname)
  161. (setq buffer-read-only nil)
  162. (erase-buffer)
  163. (call-process sysrpl-compiler-program tmp-filename t nil "-" "-"))
  164. (display-buffer sysrpl-compiler-output-bufname)))
  165. (defvar sysrpl-mode-map
  166. (let ((map (make-sparse-keymap))
  167. (menu-map (make-sparse-keymap)))
  168. (set-keymap-parent map rpl-common-keymap)
  169. ;; Menu items
  170. (define-key map [menu-bar rpl-menu] (cons "RPL" menu-map))
  171. (define-key menu-map [sysrpl-menu-separator-1]
  172. '(menu-item "--"))
  173. (define-key menu-map [sysrpl-menu-select-hp50g]
  174. '(menu-item "HP50G" sysrpl-select-hp50g
  175. :button (:radio . (eql :HP50G sysrpl-selected-calculator))))
  176. (define-key menu-map [sysrpl-menu-select-hp49g]
  177. '(menu-item "HP49G" sysrpl-select-hp49g
  178. :button (:radio . (eql :HP49G sysrpl-selected-calculator))))
  179. (define-key menu-map [sysrpl-menu-select-hp48g]
  180. '(menu-item "HP48G" sysrpl-select-hp48g
  181. :button (:radio . (eql :HP48G sysrpl-selected-calculator))))
  182. (define-key menu-map [sysrpl-menu-select-hp39g]
  183. '(menu-item "HP39G" sysrpl-select-hp39g
  184. :button (:radio . (eql :HP39G sysrpl-selected-calculator))))
  185. (define-key menu-map [sysrpl-menu-select-hp38g]
  186. '(menu-item "HP38G" sysrpl-select-hp38g
  187. :button (:radio . (eql :HP38G sysrpl-selected-calculator))))
  188. map)
  189. "The SysRPL mode local keymap.")
  190. (defvar sysrpl-mode-hook nil
  191. "Hook for customizing SysRPL mode.")
  192. (define-derived-mode sysrpl-mode prog-mode "SysRPL"
  193. "Major mode for the SysRPL language."
  194. :group 'rpl
  195. (make-local-variable 'eldoc-documentation-function)
  196. (setq eldoc-documentation-function 'sysrpl-get-eldoc-message)
  197. (setq font-lock-defaults (list 'sysrpl-font-lock-keywords))
  198. (setq rpl-menu-compile-buffer-enable t))
  199. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  200. ;; End of file
  201. ;;
  202. (provide 'sysrpl-mode)