summaryrefslogtreecommitdiff
path: root/geiser/emacs.scm
blob: 90e03ddb6be06bf56270fc94134b4b82ba18c0b7 (plain)
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
;; emacs.scm -- procedures for emacs interaction

;; Copyright (C) 2009 Jose Antonio Ortega Ruiz

;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
;; Start date: Sun Feb 08, 2009 18:39

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3 of the License, or
;; (at your option) any later version.

;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

;;; Comentary:

;; Re-exports of procedures used by Emacs.

;;; Code:

(define-module (geiser emacs)
  #:export (ge:eval
            ge:compile
            ge:compile-file
            ge:load-file)
  #:re-export (ge:arguments
               ge:completions
               ge:symbol-location
               ge:symbol-documentation
               ge:all-modules
               ge:module-children
               ge:module-location)
  #:use-module (srfi srfi-1)
  #:use-module (system base compile)
  #:use-module (system vm program)
  #:use-module (ice-9 debugger utils)
  #:use-module ((geiser introspection) :renamer (symbol-prefix-proc 'ge:)))

(define (make-result result output)
  (list (cons 'result result) (cons 'output output)))

(define (make-error key args stack)
  (list (cons 'error (apply parse-error (cons key args)))
        (cons 'stack (parse-stack stack))))

(define (parse-stack stack)
  (if stack
      (map (lambda (n) (parse-frame (stack-ref stack n)))
           (iota (stack-length stack)))
      '()))

(define (parse-frame frame)
  (list (cons 'frame (frame-number frame))
        (cons 'procedure (or (and (frame-procedure? frame)
                                  (procedure-name (frame-procedure frame)))
                             '()))
        (cons 'source (or (frame->source-position frame) '()))
        (cons 'description (with-output-to-string
                             (lambda ()
                               (if (frame-procedure? frame)
                                   (write-frame-short/application frame)
                                   (write-frame-short/expression frame)))))))

(define (frame->source-position frame)
  (let ((source (if (frame-procedure? frame)
                    (or (frame-source frame)
                        (let ((proc (frame-procedure frame)))
                          (and proc
                               (procedure? proc)
                               (procedure-source proc))))
                    (frame-source frame))))
    (and source
         (cond ((string? (source-property source 'filename))
                (list (source-property source 'filename)
                      (+ 1 (source-property source 'line))
                      (source-property source 'column)))
               ((and (pair? source) (list? (cadr source)))
                (list (caadr source)
                      (+ 1 (caddr source))
                      (cdddr source)))
               (else #f)))))

(define (parse-error key . args)
  (let* ((len (length args))
         (subr (and (> len 0) (first args)))
         (msg (and (> len 1) (second args)))
         (margs (and (> len 2) (third args)))
         (rest (and (> len 3) (fourth args))))
    (list (cons 'key key)
          (cons 'subr (or subr '()))
          (cons 'msg (if msg (apply format (cons #f (cons msg margs))) '()))
          (cons 'rest (or rest '())))))

(define (evaluate form module-name evaluator)
  (let ((module (or (and (list? module-name)
                         (resolve-module module-name))
                    (current-module)))
        (result #f)
        (captured-stack #f)
        (error #f))
    (let ((output
           (with-output-to-string
             (lambda ()
               (set! result
                     (catch #t
                       (lambda ()
                         (start-stack 'id (evaluator form module)))
                       (lambda (key . args)
                         (set! error (make-error key args captured-stack)))
                       (lambda (key . args)
                         (set! captured-stack (make-stack #t 2 2)))))))))
      (write (or error (make-result result output)))
      (newline))))

(define (eval-compile form module)
  (save-module-excursion
   (lambda ()
     (set-current-module module)
     (compile form))))

(define (ge:eval form module-name)
  "Evals @var{form} in the module designated by @var{module-name}.
If @var{module-name} is @var{#f} or resolution fails, the current module is used instead.
The result is a list of the form ((RESULT . <form-value>) (OUTPUT . <string>))
if no evaluation error happens, or ((ERROR (KEY . <error-key>) <error-arg>...))
in case of errors. Each error arg is a cons (NAME . VALUE), where NAME includes
SUBR, MSG and REST."
  (evaluate form module-name eval))

(define (ge:compile form module-name)
  "Compiles @var{form} in the module designated by @var{module-name}.
If @var{module-name} is @var{#f} or resolution fails, the current module is used instead.
The result is a list of the form ((RESULT . <form-value>) (OUTPUT . <string>))
if no evaluation error happens, or ((ERROR (KEY . <error-key>) <error-arg>...))
in case of errors. Each error arg is a cons (NAME . VALUE), where NAME includes
SUBR, MSG and REST."
  (evaluate form module-name eval-compile))

(define (ge:compile-file path)
  "Compile and load file, given its full @var{path}."
  (evaluate `(and (compile-file ,path)
                  (load-compiled ,(compiled-file-name path)))
            '(geiser emacs)
            eval))

(define (ge:load-file path)
  "Load file, given its full @var{path}."
  (evaluate `(load ,path) '(geiser emacs) eval))

;;; emacs.scm ends here