diff options
author | Brian Templeton <bpt@hcoop.net> | 2010-06-07 16:37:24 -0400 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2010-12-07 13:21:01 +0100 |
commit | abcf4a9e1dc06607ddb43861e33a982e36ffac4b (patch) | |
tree | 821f899e0dedae1297093707669942d1160d65cb | |
parent | 9c933e1d3f72d9d8693e030c24de44adc9f9e0b9 (diff) |
whitespace changes
* module/language/elisp/bindings.scm:
* module/language/elisp/compile-tree-il.scm:
* module/language/elisp/lexer.scm:
* module/language/elisp/parser.scm:
* module/language/elisp/runtime.scm:
* module/language/elisp/runtime/function-slot.scm:
* module/language/elisp/runtime/macro-slot.scm: Ensure that all
top-level forms and comments are separated by exactly one newline.
Remove blank lines in most procedure bodies. Delete trailing
whitespace.
Signed-off-by: Andy Wingo <wingo@pobox.com>
-rw-r--r-- | module/language/elisp/bindings.scm | 6 | ||||
-rw-r--r-- | module/language/elisp/compile-tree-il.scm | 72 | ||||
-rw-r--r-- | module/language/elisp/lexer.scm | 31 | ||||
-rw-r--r-- | module/language/elisp/parser.scm | 9 | ||||
-rw-r--r-- | module/language/elisp/runtime.scm | 13 | ||||
-rw-r--r-- | module/language/elisp/runtime/function-slot.scm | 40 | ||||
-rw-r--r-- | module/language/elisp/runtime/macro-slot.scm | 11 | ||||
-rw-r--r-- | module/language/elisp/spec.scm | 4 |
8 files changed, 71 insertions, 115 deletions
diff --git a/module/language/elisp/bindings.scm b/module/language/elisp/bindings.scm index 074b95aae..7ac3b4c56 100644 --- a/module/language/elisp/bindings.scm +++ b/module/language/elisp/bindings.scm @@ -36,21 +36,18 @@ ; with-dynamic-binding routines to associate symbols to different bindings ; over a dynamic extent. - ; Record type used to hold the data necessary. (define bindings-type (make-record-type 'bindings '(needed-globals lexical-bindings))) - ; Construct an 'empty' instance of the bindings data structure to be used ; at the start of a fresh compilation. (define (make-bindings) ((record-constructor bindings-type) '() (make-hash-table))) - ; Mark that a given symbol is needed as global in the specified slot-module. (define (mark-global-needed! bindings sym module) @@ -62,7 +59,6 @@ (new-needed (assoc-set! old-needed module new-in-module))) ((record-modifier bindings-type 'needed-globals) bindings new-needed))) - ; Cycle through all globals needed in order to generate the code for their ; creation or some other analysis. @@ -85,7 +81,6 @@ (cons (proc module (car sym-tail)) sym-result)))))))))) - ; Get the current lexical binding (gensym it should refer to in the current ; scope) for a symbol or #f if it is dynamically bound. @@ -96,7 +91,6 @@ (fluid-ref slot) #f))) - ; Establish a binding or mark a symbol as dynamically bound for the extent of ; calling proc. diff --git a/module/language/elisp/compile-tree-il.scm b/module/language/elisp/compile-tree-il.scm index 1701f0f19..173123292 100644 --- a/module/language/elisp/compile-tree-il.scm +++ b/module/language/elisp/compile-tree-il.scm @@ -6,12 +6,12 @@ ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. -;; +;; ;; This program 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; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, @@ -27,21 +27,22 @@ #:use-module (srfi srfi-1) #:export (compile-tree-il)) - ; Certain common parameters (like the bindings data structure or compiler ; options) are not always passed around but accessed using fluids to simulate ; dynamic binding (hey, this is about elisp). ; The bindings data structure to keep track of symbol binding related data. + (define bindings-data (make-fluid)) ; Store for which symbols (or all/none) void checks are disabled. + (define disable-void-check (make-fluid)) ; Store which symbols (or all/none) should always be bound lexically, even ; with ordinary let and as lambda arguments. -(define always-lexical (make-fluid)) +(define always-lexical (make-fluid)) ; Find the source properties of some parsed expression if there are any ; associated with it. @@ -52,20 +53,21 @@ (and (not (null? props)) props)))) - ; Values to use for Elisp's nil and t. (define (nil-value loc) (make-const loc (@ (language elisp runtime) nil-value))) -(define (t-value loc) (make-const loc (@ (language elisp runtime) t-value))) +(define (t-value loc) (make-const loc (@ (language elisp runtime) t-value))) ; Modules that contain the value and function slot bindings. (define runtime '(language elisp runtime)) + (define macro-slot '(language elisp runtime macro-slot)) + (define value-slot (@ (language elisp runtime) value-slot-module)) -(define function-slot (@ (language elisp runtime) function-slot-module)) +(define function-slot (@ (language elisp runtime) function-slot-module)) ; The backquoting works the same as quasiquotes in Scheme, but the forms are ; named differently; to make easy adaptions, we define these predicates checking @@ -80,13 +82,11 @@ (define (unquote-splicing? sym) (and (symbol? sym) (eq? sym '\,@))) - ; Build a call to a primitive procedure nicely. (define (call-primitive loc sym . args) (make-application loc (make-primitive-ref loc sym) args)) - ; Error reporting routine for syntax/compilation problems or build code for ; a runtime-error output. @@ -97,7 +97,6 @@ (make-application loc (make-primitive-ref loc 'error) (cons (make-const loc msg) args))) - ; Generate code to ensure a global symbol is there for further use of a given ; symbol. In general during the compilation, those needed are only tracked with ; the bindings data structure. Afterwards, however, for all those needed @@ -108,7 +107,6 @@ (list (make-const loc module) (make-const loc sym)))) - ; See if we should do a void-check for a given variable. That means, check ; that this check is not disabled via the compiler options for this symbol. ; Disabling of void check is only done for the value-slot module! @@ -119,7 +117,6 @@ (and (not (eq? disabled 'all)) (not (memq sym disabled)))))) - ; Build a construct that establishes dynamic bindings for certain variables. ; We may want to choose between binding with fluids and with-fluids* and ; using just ordinary module symbols and setting/reverting their values with @@ -135,7 +132,6 @@ (make-lambda loc '() (make-lambda-case #f '() #f #f #f '() '() body #f)))) - ; Handle access to a variable (reference/setting) correctly depending on ; whether it is currently lexically or dynamically bound. ; lexical access is done only for references to the value-slot module! @@ -146,7 +142,6 @@ (handle-lexical lexical) (handle-dynamic)))) - ; Generate code to reference a variable. ; For references in the value-slot module, we may want to generate a lexical ; reference instead if the variable has a lexical binding. @@ -160,7 +155,6 @@ (call-primitive loc 'fluid-ref (make-module-ref loc module sym #t))))) - ; Reference a variable and error if the value is void. (define (reference-with-check loc sym module) @@ -175,7 +169,6 @@ (make-lexical-ref loc 'value var)))) (reference-variable loc sym module))) - ; Generate code to set a variable. ; Just as with reference-variable, in case of a reference to value-slot, ; we want to generate a lexical set when the variable has a lexical binding. @@ -190,7 +183,6 @@ (make-module-ref loc module sym #t) value)))) - ; Process the bindings part of a let or let* expression; that is, check for ; correctness and bring it to the form ((sym1 . val1) (sym2 . val2) ...). @@ -206,7 +198,6 @@ (cons (car b) (cadr b)))))) bindings)) - ; Split the let bindings into a list to be done lexically and one dynamically. ; A symbol will be bound lexically if and only if: ; We're processing a lexical-let (i.e. module is 'lexical), OR @@ -231,7 +222,6 @@ (iterate (cdr tail) (cons (car tail) lexical) dynamic) (iterate (cdr tail) lexical (cons (car tail) dynamic)))))) - ; Compile let and let* expressions. The code here is used both for let/let* ; and flet/flet*, just with a different bindings module. ; @@ -244,6 +234,7 @@ ; among the bindings, we first do a let for all of them to evaluate all ; values before any bindings take place, and then call let-dynamic for the ; variables to bind dynamically. + (define (generate-let loc module bindings body) (let ((bind (process-let-bindings loc bindings))) (call-with-values @@ -278,9 +269,9 @@ dynamic-syms) (make-body))))))))))))) - ; Let* is compiled to a cascaded set of "small lets" for each binding in turn ; so that each one already sees the preceding bindings. + (define (generate-let* loc module bindings body) (let ((bind (process-let-bindings loc bindings))) (begin @@ -304,7 +295,6 @@ `(,(caar tail)) module `(,value) (iterate (cdr tail)))))))))) - ; Split the argument list of a lambda expression into required, optional and ; rest arguments and also check it is actually valid. ; Additionally, we create a list of all "local variables" (that is, required, @@ -325,7 +315,6 @@ (lexical '()) (dynamic '())) (cond - ((null? tail) (let ((final-required (reverse required)) (final-optional (reverse optional)) @@ -333,11 +322,9 @@ (final-dynamic (reverse dynamic))) (values final-required final-optional #f final-lexical final-dynamic))) - ((and (eq? mode 'required) (eq? (car tail) '&optional)) (iterate (cdr tail) 'optional required optional lexical dynamic)) - ((eq? (car tail) '&rest) (if (or (null? (cdr tail)) (not (null? (cddr tail)))) @@ -354,7 +341,6 @@ (cons rest dynamic))))) (values final-required final-optional rest final-lexical final-dynamic)))) - (else (if (not (symbol? (car tail))) (report-error loc "expected symbol in argument list, got" (car tail)) @@ -376,7 +362,6 @@ (else (error "invalid mode in split-lambda-arguments" mode))))))))) - ; Compile a lambda expression. Things get a little complicated because TreeIL ; does not allow optional arguments but only one rest argument, and also the ; rest argument should be nil instead of '() for no values given. Because of @@ -486,6 +471,7 @@ ; Build the code to handle setting of optional arguments that are present ; and updating the rest list. + (define (process-optionals loc optional rest-name rest-sym) (let iterate ((tail optional)) (if (null? tail) @@ -503,6 +489,7 @@ (iterate (cdr tail)))))))) ; This builds the code to set the rest variable to nil if it is empty. + (define (process-rest loc rest rest-name rest-sym) (let ((rest-empty (call-primitive loc 'null? (make-lexical-ref loc rest-name rest-sym)))) @@ -518,7 +505,6 @@ (runtime-error loc "too many arguments and no rest argument"))) (else (make-void loc))))) - ; Handle the common part of defconst and defvar, that is, checking for a correct ; doc string and arguments as well as maybe in the future handling the docstring ; somehow. @@ -533,7 +519,6 @@ ; TODO: Handle doc string if present. (else #t))) - ; Handle macro bindings. (define (is-macro? sym) @@ -550,7 +535,6 @@ (define (get-macro sym) (module-ref (resolve-module macro-slot) sym)) - ; See if a (backquoted) expression contains any unquotes. (define (contains-unquotes? expr) @@ -561,15 +545,15 @@ (contains-unquotes? (cdr expr)))) #f)) - ; Process a backquoted expression by building up the needed cons/append calls. -; For splicing, it is assumed that the expression spliced in evaluates to a +; For splicing, it is assumed that the expression spliced in evaluates to a ; list. The emacs manual does not really state either it has to or what to do ; if it does not, but Scheme explicitly forbids it and this seems reasonable ; also for elisp. (define (unquote-cell? expr) (and (list? expr) (= (length expr) 2) (unquote? (car expr)))) + (define (unquote-splicing-cell? expr) (and (list? expr) (= (length expr) 2) (unquote-splicing? (car expr)))) @@ -595,7 +579,6 @@ (report-error loc "non-pair expression contains unquotes" expr)) (make-const loc expr))) - ; Temporarily update a list of symbols that are handled specially (disabled ; void check or always lexical) for compiling body. ; We need to handle special cases for already all / set to all and the like. @@ -617,7 +600,6 @@ (with-fluids ((fluid new)) (make-body)))))) - ; Compile a symbol expression. This is a variable reference or maybe some ; special value like nil. @@ -627,12 +609,10 @@ ((t) (t-value loc)) (else (reference-with-check loc sym value-slot)))) - ; Compile a pair-expression (that is, any structure-like construct). (define (compile-pair loc expr) (pmatch expr - ((progn . ,forms) (make-sequence loc (map compile-expr forms))) @@ -640,10 +620,12 @@ (make-conditional loc (compile-expr condition) (compile-expr ifclause) (nil-value loc))) + ((if ,condition ,ifclause ,elseclause) (make-conditional loc (compile-expr condition) (compile-expr ifclause) (compile-expr elseclause))) + ((if ,condition ,ifclause . ,elses) (make-conditional loc (compile-expr condition) (compile-expr ifclause) @@ -659,6 +641,7 @@ (make-const loc sym))))) ((defvar ,sym) (make-const loc sym)) + ((defvar ,sym ,value . ,doc) (if (handle-var-def loc sym doc) (make-sequence loc @@ -674,6 +657,7 @@ ; Build a set form for possibly multiple values. The code is not formulated ; tail recursive because it is clearer this way and large lists of symbol ; expression pairs are very unlikely. + ((setq . ,args) (guard (not (null? args))) (make-sequence loc (let iterate ((tail args)) @@ -702,10 +686,12 @@ (not (null? bindings)) (not (null? body)))) (generate-let loc value-slot bindings body)) + ((lexical-let ,bindings . ,body) (guard (and (list? bindings) (not (null? bindings)) (not (null? body)))) (generate-let loc 'lexical bindings body)) + ((flet ,bindings . ,body) (guard (and (list? bindings) (not (null? bindings)) (not (null? body)))) @@ -715,10 +701,12 @@ (not (null? bindings)) (not (null? body)))) (generate-let* loc value-slot bindings body)) + ((lexical-let* ,bindings . ,body) (guard (and (list? bindings) (not (null? bindings)) (not (null? body)))) (generate-let* loc 'lexical bindings body)) + ((flet* ,bindings . ,body) (guard (and (list? bindings) (not (null? bindings)) (not (null? body)))) @@ -737,11 +725,13 @@ ; elisp as a way to access data within ; the Guile universe. The module and symbol referenced are static values, ; just like (@ module symbol) does! + ((guile-ref ,module ,sym) (guard (and (list? module) (symbol? sym))) (make-module-ref loc module sym #t)) ; guile-primitive allows to create primitive references, which are still ; a little faster. + ((guile-primitive ,sym) (guard (symbol? sym)) (make-primitive-ref loc sym)) @@ -755,6 +745,7 @@ ; ; As letrec is not directly accessible from elisp, while is implemented here ; instead of with a macro. + ((while ,condition . ,body) (let* ((itersym (gensym)) (compiled-body (map compile-expr body)) @@ -775,14 +766,17 @@ ; Either (lambda ...) or (function (lambda ...)) denotes a lambda-expression ; that should be compiled. + ((lambda ,args . ,body) (compile-lambda loc args body)) + ((function (lambda ,args . ,body)) (compile-lambda loc args body)) ; Build a lambda and also assign it to the function cell of some symbol. ; This is no macro as we might want to honour the docstring at some time; ; just as with defvar/defconst. + ((defun ,name ,args . ,body) (if (not (symbol? name)) (report-error loc "expected symbol as function name" name) @@ -793,6 +787,7 @@ ; Define a macro (this is done directly at compile-time!). ; FIXME: Recursive macros don't work! + ((defmacro ,name ,args . ,body) (if (not (symbol? name)) (report-error loc "expected symbol as macro name" name) @@ -803,14 +798,17 @@ (make-const loc name)))) ; XXX: Maybe we could implement backquotes in macros, too. + ((,backq ,val) (guard (backquote? backq)) (process-backquote loc val)) ; XXX: Why do we need 'quote here instead of quote? + (('quote ,val) (make-const loc val)) ; Macro calls are simply expanded and recursively compiled. + ((,macro . ,args) (guard (and (symbol? macro) (is-macro? macro))) (let ((expander (get-macro macro))) (compile-expr (apply expander args)))) @@ -819,6 +817,7 @@ ; take the function value of a symbol if it is one. It seems that functions ; in form of uncompiled lists are not supported in this syntax, so we don't ; have to care for them. + ((,func . ,args) (make-application loc (if (symbol? func) @@ -829,7 +828,6 @@ (else (report-error loc "unrecognized elisp" expr)))) - ; Compile a single expression to TreeIL. (define (compile-expr expr) @@ -841,7 +839,6 @@ (compile-pair loc expr)) (else (make-const loc expr))))) - ; Process the compiler options. ; FIXME: Why is '(()) passed as options by the REPL? @@ -867,7 +864,6 @@ (report-error #f "Invalid value for #:always-lexical" value))) (else (report-error #f "Invalid compiler option" key))))))) - ; Entry point for compilation to TreeIL. ; This creates the bindings data structure, and after compiling the main ; expression we need to make sure all globals for symbols used during the diff --git a/module/language/elisp/lexer.scm b/module/language/elisp/lexer.scm index 758b27742..959acff98 100644 --- a/module/language/elisp/lexer.scm +++ b/module/language/elisp/lexer.scm @@ -34,20 +34,17 @@ ; TODO: #@count comments - ; Report an error from the lexer (that is, invalid input given). (define (lexer-error port msg . args) (apply error msg args)) - ; In a character, set a given bit. This is just some bit-wise or'ing on the ; characters integer code and converting back to character. (define (set-char-bit chr bit) (logior chr (ash 1 bit))) - ; Check if a character equals some other. This is just like char=? except that ; the tested one could be EOF in which case it simply isn't equal. @@ -55,7 +52,6 @@ (and (not (eof-object? tested)) (char=? tested should-be))) - ; For a character (as integer code), find the real character it represents or ; #\nul if out of range. This is used to work with Scheme character functions ; like char-numeric?. @@ -65,7 +61,6 @@ (integer->char chr) #\nul)) - ; Return the control modified version of a character. This is not just setting ; a modifier bit, because ASCII conrol characters must be handled as such, and ; in elisp C-? is the delete character for historical reasons. @@ -80,7 +75,6 @@ ((#\@) 0) (else (set-char-bit chr 26)))))) - ; Parse a charcode given in some base, basically octal or hexadecimal are ; needed. A requested number of digits can be given (#f means it does ; not matter and arbitrary many are allowed), and additionally early @@ -113,7 +107,6 @@ (lexer-error port "invalid digit in escape-code" base cur)) (iterate (+ (* result base) value) (1+ procdigs))))))) - ; Read a character and process escape-sequences when necessary. The special ; in-string argument defines if this character is part of a string literal or ; a single character literal, the difference being that in strings the @@ -129,13 +122,11 @@ (#\S . 25) (#\M . ,(if in-string 7 27)))) (cur (read-char port))) (if (char=? cur #\\) - ; Handle an escape-sequence. (let* ((escaped (read-char port)) (esc-code (assq-ref basic-escape-codes escaped)) (meta (assq-ref meta-bits escaped))) (cond - ; Meta-check must be before esc-code check because \s- must be ; recognized as the super-meta modifier if a - follows. ; If not, it will be caught as \s -> space escape code. @@ -143,16 +134,13 @@ (if (not (char=? (read-char port) #\-)) (error "expected - after control sequence")) (set-char-bit (get-character port in-string) meta)) - ; One of the basic control character escape names? (esc-code esc-code) - ; Handle \ddd octal code if it is one. ((and (char>=? escaped #\0) (char<? escaped #\8)) (begin (unread-char escaped port) (charcode-escape port 8 3 #t))) - ; Check for some escape-codes directly or otherwise ; use the escaped character literally. (else @@ -169,12 +157,10 @@ ((#\u) (charcode-escape port 16 4 #f)) ((#\U) (charcode-escape port 16 8 #f)) (else (char->integer escaped)))))) - ; No escape-sequence, just the literal character. ; But remember to get the code instead! (char->integer cur)))) - ; Read a symbol or number from a port until something follows that marks the ; start of a new token (like whitespace or parentheses). The data read is ; returned as a string for further conversion to the correct type, but we also @@ -184,11 +170,13 @@ ; if it is possibly an integer or a float. (define integer-regex (make-regexp "^[+-]?[0-9]+\\.?$")) + (define float-regex (make-regexp "^[+-]?([0-9]+\\.?[0-9]*|[0-9]*\\.?[0-9]+)(e[+-]?[0-9]+)?$")) ; A dot is also allowed literally, only a single dort alone is parsed as the ; 'dot' terminal for dotted lists. + (define no-escape-punctuation (string->char-set "-+=*/_~!@$%^&:<>{}?.")) (define (get-symbol-or-number port) @@ -220,7 +208,6 @@ (unread-char c port) (finish)))))) - ; Parse a circular structure marker without the leading # (which was already ; read and recognized), that is, a number as identifier and then either ; = or #. @@ -239,7 +226,6 @@ ((#\#) `(circular-ref . ,id)) ((#\=) `(circular-def . ,id)) (else (lexer-error port "invalid circular marker character" type)))))) - ; Main lexer routine, which is given a port and does look for the next token. @@ -257,23 +243,18 @@ ; and actually point to the very character to be read. (c (read-char port))) (cond - ; End of input must be specially marked to the parser. ((eof-object? c) '*eoi*) - ; Whitespace, just skip it. ((char-whitespace? c) (lex port)) - ; The dot is only the one for dotted lists if followed by ; whitespace. Otherwise it is considered part of a number of symbol. ((and (char=? c #\.) (char-whitespace? (peek-char port))) (return 'dot #f)) - ; Continue checking for literal character values. (else (case c - ; A line comment, skip until end-of-line is found. ((#\;) (let iterate () @@ -281,11 +262,9 @@ (if (or (eof-object? cur) (char=? cur #\newline)) (lex port) (iterate))))) - ; A character literal. ((#\?) (return 'character (get-character port #f))) - ; A literal string. This is mainly a sequence of characters just ; as in the character literals, the only difference is that escaped ; newline and space are to be completely ignored and that meta-escapes @@ -307,12 +286,10 @@ (iterate (cons (integer->char (get-character port #t)) result-chars)))))) (else (iterate (cons cur result-chars))))))) - ; Circular markers (either reference or definition). ((#\#) (let ((mark (get-circular-marker port))) (return (car mark) (cdr mark)))) - ; Parentheses and other special-meaning single characters. ((#\() (return 'paren-open #f)) ((#\)) (return 'paren-close #f)) @@ -320,7 +297,6 @@ ((#\]) (return 'square-close #f)) ((#\') (return 'quote #f)) ((#\`) (return 'backquote #f)) - ; Unquote and unquote-splicing. ((#\,) (if (is-char? (peek-char port) #\@) @@ -328,7 +304,6 @@ (error "expected @ in unquote-splicing") (return 'unquote-splicing #f)) (return 'unquote #f))) - ; Remaining are numbers and symbols. Process input until next ; whitespace is found, and see if it looks like a number ; (float/integer) or symbol and return accordingly. @@ -369,7 +344,6 @@ num))) (else (error "wrong number/symbol type" type))))))))))) - ; Build a lexer thunk for a port. This is the exported routine which can be ; used to create a lexer for the parser to use. @@ -377,7 +351,6 @@ (lambda () (lex port))) - ; Build a special lexer that will only read enough for one expression and then ; always return end-of-input. ; If we find one of the quotation stuff, one more expression is needed in any diff --git a/module/language/elisp/parser.scm b/module/language/elisp/parser.scm index 4d9b0c32d..dee683895 100644 --- a/module/language/elisp/parser.scm +++ b/module/language/elisp/parser.scm @@ -28,14 +28,12 @@ ; lexer ((text parse-lalr) seems not to allow access to the original lexer ; token-pair) and is easy enough anyways. - ; Report a parse error. The first argument is some current lexer token ; where source information is available should it be useful. (define (parse-error token msg . args) (apply error msg args)) - ; For parsing circular structures, we keep track of definitions in a ; hash-map that maps the id's to their values. ; When defining a new id, though, we immediatly fill the slot with a promise @@ -64,6 +62,7 @@ ; Returned is a closure that, when invoked, will set the final value. ; This means both the variable the promise will return and the hash-table ; slot so we don't generate promises any longer. + (define (circular-define! token) (if (not (eq? (car token) 'circular-def)) (error "invalid token for circular-define!" token)) @@ -80,6 +79,7 @@ ; this may lead to infinite recursion with a circular structure, and ; additionally this value was already processed when it was defined. ; All deep data structures that can be parsed must be handled here! + (define (force-promises! data) (cond ((pair? data) @@ -102,7 +102,6 @@ ; Else nothing needs to be done. )) - ; We need peek-functionality for the next lexer token, this is done with some ; single token look-ahead storage. This is handled by a closure which allows ; getting or peeking the next token. @@ -128,7 +127,6 @@ result)) (else (error "invalid lexer-buffer action" action)))))))) - ; Get the contents of a list, where the opening parentheses has already been ; found. The same code is used for vectors and lists, where lists allow the ; dotted tail syntax and vectors not; additionally, the closing parenthesis @@ -159,8 +157,6 @@ (tail (get-list lex allow-dot close-square))) (cons head tail)))))) - - ; Parse a single expression from a lexer-buffer. This is the main routine in ; our recursive-descent parser. @@ -197,7 +193,6 @@ (else (parse-error token "expected expression, got" token))))) - ; Define the reader function based on this; build a lexer, a lexer-buffer, ; and then parse a single expression to return. ; We also define a circular-definitions data structure to use. diff --git a/module/language/elisp/runtime.scm b/module/language/elisp/runtime.scm index 0d783b6fa..3a041568b 100644 --- a/module/language/elisp/runtime.scm +++ b/module/language/elisp/runtime.scm @@ -22,36 +22,31 @@ #:export (void nil-value t-value value-slot-module function-slot-module - elisp-bool - ensure-fluid! reference-variable reference-variable-with-check set-variable! - runtime-error macro-error) #:export-syntax (built-in-func built-in-macro prim)) ; This module provides runtime support for the Elisp front-end. - ; The reserved value to mean (when eq?) void. (define void (list 42)) - ; Values for t and nil. (FIXME remove this abstraction) (define nil-value #nil) -(define t-value #t) +(define t-value #t) ; Modules for the binding slots. ; Note: Naming those value-slot and/or function-slot clashes with the ; submodules of these names! (define value-slot-module '(language elisp runtime value-slot)) -(define function-slot-module '(language elisp runtime function-slot)) +(define function-slot-module '(language elisp runtime function-slot)) ; Report an error during macro compilation, that means some special compilation ; (syntax) error; or report a simple runtime-error from a built-in function. @@ -61,7 +56,6 @@ (define runtime-error macro-error) - ; Convert a scheme boolean to Elisp. (define (elisp-bool b) @@ -69,7 +63,6 @@ t-value nil-value)) - ; Routines for access to elisp dynamically bound symbols. ; This is used for runtime access using functions like symbol-value or set, ; where the symbol accessed might not be known at compile-time. @@ -101,7 +94,6 @@ (fluid-set! (module-ref resolved sym) value) value)) - ; Define a predefined function or predefined macro for use in the function-slot ; and macro-slot modules, respectively. @@ -117,7 +109,6 @@ ((_ name value) (define-public name value)))) - ; Call a guile-primitive that may be rebound for elisp and thus needs absolute ; addressing. diff --git a/module/language/elisp/runtime/function-slot.scm b/module/language/elisp/runtime/function-slot.scm index 9d88b2250..f794caa59 100644 --- a/module/language/elisp/runtime/function-slot.scm +++ b/module/language/elisp/runtime/function-slot.scm @@ -25,7 +25,6 @@ ; This module contains the function-slots of elisp symbols. Elisp built-in ; functions are implemented as predefined function bindings here. - ; Equivalence and equalness predicates. (built-in-func eq (lambda (a b) @@ -34,7 +33,6 @@ (built-in-func equal (lambda (a b) (elisp-bool (equal? a b)))) - ; Number predicates. (built-in-func floatp (lambda (num) @@ -57,31 +55,34 @@ (built-in-func zerop (lambda (num) (elisp-bool (prim = num 0)))) - ; Number comparisons. (built-in-func = (lambda (num1 num2) (elisp-bool (prim = num1 num2)))) + (built-in-func /= (lambda (num1 num2) (elisp-bool (prim not (prim = num1 num2))))) (built-in-func < (lambda (num1 num2) (elisp-bool (prim < num1 num2)))) + (built-in-func <= (lambda (num1 num2) (elisp-bool (prim <= num1 num2)))) + (built-in-func > (lambda (num1 num2) (elisp-bool (prim > num1 num2)))) + (built-in-func >= (lambda (num1 num2) (elisp-bool (prim >= num1 num2)))) (built-in-func max (lambda (. nums) (prim apply (@ (guile) max) nums))) + (built-in-func min (lambda (. nums) (prim apply (@ (guile) min) nums))) (built-in-func abs (@ (guile) abs)) - ; Number conversion. (built-in-func float (lambda (num) @@ -91,32 +92,38 @@ ; TODO: truncate, floor, ceiling, round. - ; Arithmetic functions. (built-in-func 1+ (@ (guile) 1+)) + (built-in-func 1- (@ (guile) 1-)) + (built-in-func + (@ (guile) +)) + (built-in-func - (@ (guile) -)) + (built-in-func * (@ (guile) *)) + (built-in-func % (@ (guile) modulo)) ; TODO: / with correct integer/real behaviour, mod (for floating-piont values). - ; Floating-point rounding operations. (built-in-func ffloor (@ (guile) floor)) + (built-in-func fceiling (@ (guile) ceiling)) + (built-in-func ftruncate (@ (guile) truncate)) -(built-in-func fround (@ (guile) round)) +(built-in-func fround (@ (guile) round)) ; List predicates. (built-in-func consp (lambda (el) (elisp-bool (pair? el)))) + (built-in-func atomp (lambda (el) (elisp-bool (prim not (pair? el))))) @@ -124,6 +131,7 @@ (built-in-func listp (lambda (el) (elisp-bool (or (pair? el) (null? el))))) + (built-in-func nlistp (lambda (el) (elisp-bool (and (prim not (pair? el)) @@ -133,7 +141,6 @@ (lambda (el) (elisp-bool (null? el)))) - ; Accessing list elements. (built-in-func car @@ -141,6 +148,7 @@ (if (null? el) nil-value (prim car el)))) + (built-in-func cdr (lambda (el) (if (null? el) @@ -152,6 +160,7 @@ (if (pair? el) (prim car el) nil-value))) + (built-in-func cdr-safe (lambda (el) (if (pair? el) @@ -168,6 +177,7 @@ ((null? tail) nil-value) ((zero? i) (prim car tail)) (else (iterate (prim 1- i) (prim cdr tail)))))))) + (built-in-func nthcdr (lambda (n lst) (if (negative? n) @@ -181,17 +191,20 @@ (built-in-func length (@ (guile) length)) - ; Building lists. (built-in-func cons (@ (guile) cons)) + (built-in-func list (@ (guile) list)) + (built-in-func make-list (lambda (len obj) (prim make-list len obj))) (built-in-func append (@ (guile) append)) + (built-in-func reverse (@ (guile) reverse)) + (built-in-func copy-tree (@ (guile) copy-tree)) (built-in-func number-sequence @@ -223,7 +236,6 @@ (prim cons i result) (iterate (prim - i sep) (prim cons i result))))))))))) - ; Changing lists. (built-in-func setcar @@ -236,12 +248,12 @@ (prim set-cdr! cell val) val)) - ; Accessing symbol bindings for symbols known only at runtime. (built-in-func symbol-value (lambda (sym) (reference-variable-with-check value-slot-module sym))) + (built-in-func symbol-function (lambda (sym) (reference-variable-with-check function-slot-module sym))) @@ -249,6 +261,7 @@ (built-in-func set (lambda (sym value) (set-variable! value-slot-module sym value))) + (built-in-func fset (lambda (sym value) (set-variable! function-slot-module sym value))) @@ -257,6 +270,7 @@ (lambda (sym) (set-variable! value-slot-module sym void) sym)) + (built-in-func fmakunbound (lambda (sym) (set-variable! function-slot-module sym void) @@ -266,12 +280,12 @@ (lambda (sym) (elisp-bool (prim not (eq? void (reference-variable value-slot-module sym)))))) + (built-in-func fboundp (lambda (sym) (elisp-bool (prim not (eq? void (reference-variable function-slot-module sym)))))) - ; Function calls. These must take care of special cases, like using symbols ; or raw lambda-lists as functions! @@ -294,14 +308,12 @@ (lambda (func . args) (myapply func args)))) - ; Throw can be implemented as built-in function. (built-in-func throw (lambda (tag value) (prim throw 'elisp-exception tag value))) - ; Miscellaneous. (built-in-func not diff --git a/module/language/elisp/runtime/macro-slot.scm b/module/language/elisp/runtime/macro-slot.scm index e28fa31ce..0a55b7896 100644 --- a/module/language/elisp/runtime/macro-slot.scm +++ b/module/language/elisp/runtime/macro-slot.scm @@ -26,7 +26,6 @@ ; course, so not really in runtime. But I think it fits well to the others ; here. - ; The prog1 and prog2 constructs can easily be defined as macros using progn ; and some lexical-let's to save the intermediate value to return at the end. @@ -42,7 +41,6 @@ (lambda (form1 form2 . rest) `(progn ,form1 (prog1 ,form2 ,@rest)))) - ; Define the conditionals when and unless as macros. (built-in-macro when @@ -53,7 +51,6 @@ (lambda (condition . elses) `(if ,condition nil (progn ,@elses)))) - ; Impement the cond form as nested if's. A special case is a (condition) ; subform, in which case we need to return the condition itself if it is true ; and thus save it in a local variable before testing it. @@ -80,7 +77,6 @@ (progn ,@(cdr cur)) ,rest)))))))) - ; The and and or forms can also be easily defined with macros. (built-in-macro and @@ -111,7 +107,6 @@ ,var ,(iterate (car tail) (cdr tail))))))))))) - ; Define the dotimes and dolist iteration macros. (built-in-macro dotimes @@ -155,7 +150,6 @@ (list (caddr args)) '()))))))))) - ; Exception handling. unwind-protect and catch are implemented as macros (throw ; is a built-in function). @@ -165,6 +159,7 @@ ; for matches using eq (eq?). We handle this by using always #t as key ; for the Guile primitives and check for matches inside the handler; if ; the elisp keys are not eq?, we rethrow the exception. + (built-in-macro catch (lambda (tag . body) (if (null? body) @@ -185,8 +180,9 @@ ((guile-primitive throw) ,dummy-key ,elisp-key ,value)))))))))) -; unwind-protect is just some weaker construct as dynamic-wind, so +; unwind-protect is just some weaker construct as dynamic-wind, so ; straight-forward to implement. + (built-in-macro unwind-protect (lambda (body . clean-ups) (if (null? clean-ups) @@ -196,7 +192,6 @@ (lambda () ,body) (lambda () ,@clean-ups)))) - ; Pop off the first element from a list or push one to it. (built-in-macro pop diff --git a/module/language/elisp/spec.scm b/module/language/elisp/spec.scm index d93208e41..1fc3e06e5 100644 --- a/module/language/elisp/spec.scm +++ b/module/language/elisp/spec.scm @@ -6,12 +6,12 @@ ;;;; modify it under the terms of the GNU Lesser General Public ;;;; License as published by the Free Software Foundation; either ;;;; version 3 of the License, or (at your option) any later version. -;;;; +;;;; ;;;; This library 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 ;;;; Lesser General Public License for more details. -;;;; +;;;; ;;;; You should have received a copy of the GNU Lesser General Public ;;;; License along with this library; if not, write to the Free Software ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |