1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 11:50:28 +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:
BT Templeton 2011-07-09 18:49:02 -04:00
parent d4cb18ad9c
commit 03e00c5c9d
6 changed files with 47 additions and 10 deletions

View file

@ -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.

View file

@ -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)

View file

@ -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.
((#\;) ((#\;)
(let iterate () (if (= (port-line port) 0)
(let ((cur (read-char port))) (let iterate ((chars '()))
(if (or (eof-object? cur) (char=? cur #\newline)) (let ((cur (read-char port)))
(lex port) (if (or (eof-object? cur) (char=? cur #\newline))
(iterate))))) (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. ;; A character literal.
((#\?) ((#\?)
(return 'character (get-character port #f))) (return 'character (get-character port #f)))

View file

@ -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)))))

View file

@ -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))

View file

@ -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)))