summaryrefslogtreecommitdiff
path: root/module
diff options
context:
space:
mode:
authorBT Templeton <bpt@hcoop.net>2011-07-09 18:49:02 -0400
committerBT Templeton <bpt@hcoop.net>2012-02-03 18:53:49 -0500
commit03e00c5c9ddbeda56543da94601142df40e2bcbb (patch)
treea290b060f4a3b3912eda55a7e886d276fa52b94e /module
parentd4cb18ad9cf09f54552d82463acf1269a11a8764 (diff)
downloadguile-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.scm4
-rw-r--r--module/language/elisp/compile-tree-il.scm16
-rw-r--r--module/language/elisp/lexer.scm26
-rw-r--r--module/language/elisp/parser.scm2
-rw-r--r--module/language/elisp/runtime/function-slot.scm7
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))