-
Notifications
You must be signed in to change notification settings - Fork 1
/
fuel-stack.el
142 lines (112 loc) · 4.24 KB
/
fuel-stack.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
;;; fuel-stack.el -- stack inference help -*- lexical-binding: t -*-
;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
;; See https://factorcode.org/license.txt for BSD license.
;; Author: Jose Antonio Ortega Ruiz <[email protected]>
;; Keywords: languages, fuel, factor
;; Start date: Sat Dec 20, 2008 01:08
;;; Comentary:
;; Utilities and a minor mode to show inferred stack effects in the
;; echo area.
;;; Code:
(require 'fuel-autodoc)
(require 'fuel-eval)
(require 'fuel-base)
(require 'factor-mode)
;;; Customization
;;;###autoload
(defgroup fuel-stack nil
"Customization for FUEL's stack inference engine."
:group 'fuel)
(defface fuel-stack-region-face '((t (:inherit highlight)))
"Highlights the region being stack inferenced."
:group 'fuel-stack
:group 'fuel-faces
:group 'fuel)
(defcustom fuel-stack-highlight-period 1.0
"Time, in seconds, the region is highlighted when showing its
stack effect.
Set it to 0 to disable highlighting."
:group 'fuel-stack
:type 'float)
(defcustom fuel-stack-mode-show-sexp-p t
"Whether to show in the echo area the sexp together with its stack effect."
:group 'fuel-stack
:type 'boolean)
;;; Querying for stack effects
(defun fuel-stack--infer-effect (str)
(let ((cmd `(:fuel*
((:using stack-checker effects)
([ (:factor ,str) ] infer effect>string)))))
(fuel-eval--retort-result (fuel-eval--send/wait cmd 500))))
(defsubst fuel-stack--infer-effect/prop (str)
(let ((e (fuel-stack--infer-effect str)))
(when e
(put-text-property 0 (length e) 'face 'factor-font-lock-stack-effect e))
e))
(defvar fuel-stack--overlay
(let ((overlay (make-overlay 0 0)))
(overlay-put overlay 'face 'fuel-stack-region-face)
(delete-overlay overlay)
overlay))
(defun fuel-stack-effect-region (begin end)
"Displays the inferred stack effect of the code in current region."
(interactive "r")
(when (> fuel-stack-highlight-period 0)
(move-overlay fuel-stack--overlay begin end))
(condition-case nil
(let* ((str (fuel-region-to-string begin end))
(effect (fuel-stack--infer-effect/prop str)))
(if effect (message "%s" effect)
(message "Couldn't infer effect for '%s'"
(fuel-shorten-region begin end 60)))
(sit-for fuel-stack-highlight-period))
(error))
(delete-overlay fuel-stack--overlay))
(defun fuel-stack-effect-sexp (&optional arg)
"Displays the inferred stack effect for the current sexp.
With prefix argument, use current region instead"
(interactive "P")
(if arg
(call-interactively 'fuel-stack-effect-region)
(fuel-stack-effect-region (1+ (factor-beginning-of-sexp-pos))
(if (looking-at-p ";")
(point)
(save-excursion
(factor-end-of-symbol) (point))))))
;;; Stack mode:
(defvar-local fuel-stack-mode-string " S"
"Modeline indicator for fuel-stack-mode")
(defvar-local fuel-stack--region-function
'(lambda ()
(fuel-region-to-string (1+ (factor-beginning-of-sexp-pos)))))
(defun fuel-stack--eldoc ()
(when (looking-at-p " \\|$")
(let* ((r (funcall fuel-stack--region-function))
(e (and r
(not (string-match "^ *$" r))
(fuel-stack--infer-effect/prop r))))
(when e
(if fuel-stack-mode-show-sexp-p
(concat (fuel-shorten-str r 30) " -> " e)
e)))))
;;;###autoload
(define-minor-mode fuel-stack-mode
"Toggle Fuel's Stack mode.
With no argument, this command toggles the mode.
Non-null prefix argument turns on the mode.
Null prefix argument turns off the mode.
When Stack mode is enabled, inferred stack effects for current
sexp are automatically displayed in the echo area."
:init-value nil
:lighter fuel-stack-mode-string
:group 'fuel-stack
(setq fuel-autodoc--fallback-function
(when fuel-stack-mode 'fuel-stack--eldoc))
(setq-local eldoc-minor-mode-string nil)
(unless fuel-autodoc-mode
(setq-local eldoc-documentation-function
(when fuel-stack-mode 'fuel-stack--eldoc))
(eldoc-mode fuel-stack-mode)
(message "Fuel Stack Autodoc %s" (if fuel-stack-mode "enabled" "disabled"))))
(provide 'fuel-stack)
;;; fuel-stack.el ends here