mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
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.
This commit is contained in:
parent
d4cb18ad9c
commit
03e00c5c9d
6 changed files with 47 additions and 10 deletions
|
@ -24,6 +24,7 @@
|
||||||
#:use-module (srfi srfi-9)
|
#:use-module (srfi srfi-9)
|
||||||
#:use-module (srfi srfi-26)
|
#:use-module (srfi srfi-26)
|
||||||
#:export (make-bindings
|
#:export (make-bindings
|
||||||
|
global?
|
||||||
mark-global!
|
mark-global!
|
||||||
map-globals
|
map-globals
|
||||||
with-lexical-bindings
|
with-lexical-bindings
|
||||||
|
@ -57,6 +58,9 @@
|
||||||
(define (make-bindings)
|
(define (make-bindings)
|
||||||
(%make-bindings '() (make-hash-table)))
|
(%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
|
;;; Mark that a given symbol is needed as global in the specified
|
||||||
;;; slot-module.
|
;;; slot-module.
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,8 @@
|
||||||
compile-defmacro
|
compile-defmacro
|
||||||
compile-defun
|
compile-defun
|
||||||
#{compile-`}#
|
#{compile-`}#
|
||||||
compile-quote))
|
compile-quote
|
||||||
|
compile-%set-lexical-binding-mode))
|
||||||
|
|
||||||
;;; Certain common parameters (like the bindings data structure or
|
;;; Certain common parameters (like the bindings data structure or
|
||||||
;;; compiler options) are not always passed around but accessed using
|
;;; compiler options) are not always passed around but accessed using
|
||||||
|
@ -66,6 +67,8 @@
|
||||||
|
|
||||||
(define always-lexical (make-fluid))
|
(define always-lexical (make-fluid))
|
||||||
|
|
||||||
|
(define lexical-binding (make-fluid))
|
||||||
|
|
||||||
;;; Find the source properties of some parsed expression if there are
|
;;; Find the source properties of some parsed expression if there are
|
||||||
;;; any associated with it.
|
;;; any associated with it.
|
||||||
|
|
||||||
|
@ -245,7 +248,10 @@
|
||||||
(let ((always (fluid-ref always-lexical)))
|
(let ((always (fluid-ref always-lexical)))
|
||||||
(or (eq? always 'all)
|
(or (eq? always 'all)
|
||||||
(memq sym always)
|
(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)
|
(define (split-let-bindings bindings module)
|
||||||
(let iterate ((tail bindings)
|
(let iterate ((tail bindings)
|
||||||
|
@ -854,6 +860,12 @@
|
||||||
((,val)
|
((,val)
|
||||||
(make-const loc 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.
|
;;; Compile a compound expression to Tree-IL.
|
||||||
|
|
||||||
(define (compile-pair loc expr)
|
(define (compile-pair loc expr)
|
||||||
|
|
|
@ -252,7 +252,15 @@
|
||||||
;;; Main lexer routine, which is given a port and does look for the next
|
;;; Main lexer routine, which is given a port and does look for the next
|
||||||
;;; token.
|
;;; token.
|
||||||
|
|
||||||
|
(define lexical-binding-regexp
|
||||||
|
(make-regexp
|
||||||
|
"-\\*-(|.*;)[ \t]*lexical-binding:[ \t]*([^;]*[^ \t;]).*-\\*-"))
|
||||||
|
|
||||||
(define (lex port)
|
(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)
|
(let ((return (let ((file (if (file-port? port)
|
||||||
(port-filename port)
|
(port-filename port)
|
||||||
#f))
|
#f))
|
||||||
|
@ -283,11 +291,19 @@
|
||||||
(case c
|
(case c
|
||||||
;; A line comment, skip until end-of-line is found.
|
;; A line comment, skip until end-of-line is found.
|
||||||
((#\;)
|
((#\;)
|
||||||
|
(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 iterate ()
|
||||||
(let ((cur (read-char port)))
|
(let ((cur (read-char port)))
|
||||||
(if (or (eof-object? cur) (char=? cur #\newline))
|
(if (or (eof-object? cur) (char=? cur #\newline))
|
||||||
(lex port)
|
(lex port)
|
||||||
(iterate)))))
|
(iterate))))))
|
||||||
;; A character literal.
|
;; A character literal.
|
||||||
((#\?)
|
((#\?)
|
||||||
(return 'character (get-character port #f)))
|
(return 'character (get-character port #f)))
|
||||||
|
|
|
@ -201,6 +201,8 @@
|
||||||
(setter expr)
|
(setter expr)
|
||||||
(force-promises! expr)
|
(force-promises! expr)
|
||||||
expr))
|
expr))
|
||||||
|
((set-lexical-binding-mode!)
|
||||||
|
(return `(%set-lexical-binding-mode ,(cdr token))))
|
||||||
(else
|
(else
|
||||||
(parse-error token "expected expression, got" token)))))
|
(parse-error token "expected expression, got" token)))))
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,9 @@
|
||||||
(compile-defun . defun)
|
(compile-defun . defun)
|
||||||
(compile-defmacro . defmacro)
|
(compile-defmacro . defmacro)
|
||||||
(#{compile-`}# . #{`}#)
|
(#{compile-`}# . #{`}#)
|
||||||
(compile-quote . quote)))
|
(compile-quote . quote)
|
||||||
|
(compile-%set-lexical-binding-mode
|
||||||
|
. %set-lexical-binding-mode)))
|
||||||
#:duplicates (last)
|
#:duplicates (last)
|
||||||
;; special operators
|
;; special operators
|
||||||
#:re-export (progn
|
#:re-export (progn
|
||||||
|
@ -64,6 +66,7 @@
|
||||||
defun
|
defun
|
||||||
defmacro
|
defmacro
|
||||||
#{`}#
|
#{`}#
|
||||||
quote)
|
quote
|
||||||
|
%set-lexical-binding-mode)
|
||||||
;; functions
|
;; functions
|
||||||
#:re-export (apply))
|
#:re-export (apply))
|
||||||
|
|
|
@ -295,7 +295,7 @@
|
||||||
(defun dyna () a)
|
(defun dyna () a)
|
||||||
(lexical-let ((a 2) (b 42))
|
(lexical-let ((a 2) (b 42))
|
||||||
(and (= a 2) (= (dyna) 1)
|
(and (= a 2) (= (dyna) 1)
|
||||||
((lambda (a) (and (= a 3) (= b 42) (= (dyna) 3))) 3)
|
((lambda (a) (and (= a 3) (= b 42) (= (dyna) 1))) 3)
|
||||||
((lambda () (let ((a 3))
|
((lambda () (let ((a 3))
|
||||||
(and (= a 3) (= (dyna) 1)))))
|
(and (= a 3) (= (dyna) 1)))))
|
||||||
(= a 2) (= (dyna) 1)))
|
(= a 2) (= (dyna) 1)))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue