diff options
author | BT Templeton <bpt@hcoop.net> | 2011-07-09 18:49:02 -0400 |
---|---|---|
committer | BT Templeton <bpt@hcoop.net> | 2012-02-03 18:53:49 -0500 |
commit | 03e00c5c9ddbeda56543da94601142df40e2bcbb (patch) | |
tree | a290b060f4a3b3912eda55a7e886d276fa52b94e /module | |
parent | d4cb18ad9cf09f54552d82463acf1269a11a8764 (diff) | |
download | guile-03e00c5c9ddbeda56543da94601142df40e2bcbb.tar.gz |
emacs-compatible lexical binding
* module/language/elisp/bindings.scm (global?): New function.
* module/language/elisp/compile-tree-il.scm (lexical-binding): New
variable.
(bind-lexically?): If lexical binding is enabled, bind lexically
unless a special binding exists.
(compile-%set-lexical-binding-mode): New function.
* module/language/elisp/lexer.scm (lexical-binding-regexp): New
variable.
(lex): Return a `set-lexical-binding-mode!' token if a comment is
found while reading the first line.
* module/language/elisp/parser.scm (get-expression): Add support for
`set-lexical-binding-mode!' tokens.
* module/language/elisp/runtime/function-slot.scm: Import and re-export
the `%set-lexical-binding-mode' special form.
* test-suite/tests/elisp-compiler.test
("Let and Let*")["lambda args inside lexical-let"]: Update.
Diffstat (limited to 'module')
-rw-r--r-- | module/language/elisp/bindings.scm | 4 | ||||
-rw-r--r-- | module/language/elisp/compile-tree-il.scm | 16 | ||||
-rw-r--r-- | module/language/elisp/lexer.scm | 26 | ||||
-rw-r--r-- | module/language/elisp/parser.scm | 2 | ||||
-rw-r--r-- | module/language/elisp/runtime/function-slot.scm | 7 |
5 files changed, 46 insertions, 9 deletions
diff --git a/module/language/elisp/bindings.scm b/module/language/elisp/bindings.scm index 0d03ab521..4c8e15940 100644 --- a/module/language/elisp/bindings.scm +++ b/module/language/elisp/bindings.scm @@ -24,6 +24,7 @@ #:use-module (srfi srfi-9) #:use-module (srfi srfi-26) #:export (make-bindings + global? mark-global! map-globals with-lexical-bindings @@ -57,6 +58,9 @@ (define (make-bindings) (%make-bindings '() (make-hash-table))) +(define (global? bindings sym module) + (and=> (assoc-ref (globals bindings) module) (cut memq sym <>))) + ;;; Mark that a given symbol is needed as global in the specified ;;; slot-module. diff --git a/module/language/elisp/compile-tree-il.scm b/module/language/elisp/compile-tree-il.scm index 08cb0bdde..20d79421b 100644 --- a/module/language/elisp/compile-tree-il.scm +++ b/module/language/elisp/compile-tree-il.scm @@ -50,7 +50,8 @@ compile-defmacro compile-defun #{compile-`}# - compile-quote)) + compile-quote + compile-%set-lexical-binding-mode)) ;;; Certain common parameters (like the bindings data structure or ;;; compiler options) are not always passed around but accessed using @@ -66,6 +67,8 @@ (define always-lexical (make-fluid)) +(define lexical-binding (make-fluid)) + ;;; Find the source properties of some parsed expression if there are ;;; any associated with it. @@ -245,7 +248,10 @@ (let ((always (fluid-ref always-lexical))) (or (eq? always 'all) (memq sym always) - (get-lexical-binding (fluid-ref bindings-data) sym)))))) + (get-lexical-binding (fluid-ref bindings-data) sym) + (and + (fluid-ref lexical-binding) + (not (global? (fluid-ref bindings-data) sym module)))))))) (define (split-let-bindings bindings module) (let iterate ((tail bindings) @@ -854,6 +860,12 @@ ((,val) (make-const loc val)))) +(defspecial %set-lexical-binding-mode (loc args) + (pmatch args + ((,val) + (fluid-set! lexical-binding val) + (make-void loc)))) + ;;; Compile a compound expression to Tree-IL. (define (compile-pair loc expr) diff --git a/module/language/elisp/lexer.scm b/module/language/elisp/lexer.scm index af7e02add..2e52cc780 100644 --- a/module/language/elisp/lexer.scm +++ b/module/language/elisp/lexer.scm @@ -252,7 +252,15 @@ ;;; Main lexer routine, which is given a port and does look for the next ;;; token. +(define lexical-binding-regexp + (make-regexp + "-\\*-(|.*;)[ \t]*lexical-binding:[ \t]*([^;]*[^ \t;]).*-\\*-")) + (define (lex port) + (define (lexical-binding-value string) + (and=> (regexp-exec lexical-binding-regexp string) + (lambda (match) + (not (member (match:substring match 2) '("nil" "()")))))) (let ((return (let ((file (if (file-port? port) (port-filename port) #f)) @@ -283,11 +291,19 @@ (case c ;; A line comment, skip until end-of-line is found. ((#\;) - (let iterate () - (let ((cur (read-char port))) - (if (or (eof-object? cur) (char=? cur #\newline)) - (lex port) - (iterate))))) + (if (= (port-line port) 0) + (let iterate ((chars '())) + (let ((cur (read-char port))) + (if (or (eof-object? cur) (char=? cur #\newline)) + (let ((string (list->string (reverse chars)))) + (return 'set-lexical-binding-mode! + (lexical-binding-value string))) + (iterate (cons cur chars))))) + (let iterate () + (let ((cur (read-char port))) + (if (or (eof-object? cur) (char=? cur #\newline)) + (lex port) + (iterate)))))) ;; A character literal. ((#\?) (return 'character (get-character port #f))) diff --git a/module/language/elisp/parser.scm b/module/language/elisp/parser.scm index df825eb4e..e83f136bb 100644 --- a/module/language/elisp/parser.scm +++ b/module/language/elisp/parser.scm @@ -201,6 +201,8 @@ (setter expr) (force-promises! expr) expr)) + ((set-lexical-binding-mode!) + (return `(%set-lexical-binding-mode ,(cdr token)))) (else (parse-error token "expected expression, got" token))))) diff --git a/module/language/elisp/runtime/function-slot.scm b/module/language/elisp/runtime/function-slot.scm index 3fe47fb6e..edb4ebf63 100644 --- a/module/language/elisp/runtime/function-slot.scm +++ b/module/language/elisp/runtime/function-slot.scm @@ -41,7 +41,9 @@ (compile-defun . defun) (compile-defmacro . defmacro) (#{compile-`}# . #{`}#) - (compile-quote . quote))) + (compile-quote . quote) + (compile-%set-lexical-binding-mode + . %set-lexical-binding-mode))) #:duplicates (last) ;; special operators #:re-export (progn @@ -64,6 +66,7 @@ defun defmacro #{`}# - quote) + quote + %set-lexical-binding-mode) ;; functions #:re-export (apply)) |