guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] GNU Guile branch, elisp, updated. release_1-9-1-79-ge840


From: Daniel Kraft
Subject: [Guile-commits] GNU Guile branch, elisp, updated. release_1-9-1-79-ge840cc6
Date: Wed, 26 Aug 2009 19:43:30 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".

http://git.savannah.gnu.org/cgit/guile.git/commit/?id=e840cc654032c60e43aec0f868d67905a3bf5523

The branch, elisp has been updated
       via  e840cc654032c60e43aec0f868d67905a3bf5523 (commit)
       via  ddb4364b1a1635fce0b1d2eaa7d50a951c6c4dfc (commit)
      from  5b1ee3bef15380745f6c2fc598768d9f3a46e85e (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit e840cc654032c60e43aec0f868d67905a3bf5523
Author: Daniel Kraft <address@hidden>
Date:   Wed Aug 26 21:36:37 2009 +0200

    Parser for elisp and use it as reader.
    
    * module/language/elisp/parser.scm: New parser file.
    * module/language/elisp/lexer.scm: Fix lexer/1 and add unquote-splicing 
support.
    * module/language/elisp/spec.scm: Use new elisp-reader.
    * module/language/elisp/README: Document we've got a reader now.
    * test-suite/tests/elisp-reader.test: Test the parser.

commit ddb4364b1a1635fce0b1d2eaa7d50a951c6c4dfc
Author: Daniel Kraft <address@hidden>
Date:   Wed Aug 26 21:03:06 2009 +0200

    get-lexer/1 for elisp that finishes after the first full expression is read.
    
    * module/language/elisp/lexer.scm: Add get-lexer/1.
    * test-suite/tests/elisp-reader.test: Test lexer/1.

-----------------------------------------------------------------------

Summary of changes:
 module/language/elisp/README       |    2 +-
 module/language/elisp/lexer.scm    |   41 +++++++++++++++++--
 module/language/elisp/parser.scm   |   76 ++++++++++++++++++++++++++++++++++++
 module/language/elisp/spec.scm     |    6 +-
 test-suite/tests/elisp-reader.test |   66 ++++++++++++++++++++++++++-----
 5 files changed, 173 insertions(+), 18 deletions(-)
 create mode 100644 module/language/elisp/parser.scm

diff --git a/module/language/elisp/README b/module/language/elisp/README
index be625ff..4f33711 100644
--- a/module/language/elisp/README
+++ b/module/language/elisp/README
@@ -21,9 +21,9 @@ Already implemented:
   * defconst, defvar, defun
   * macros
   * quotation and backquotation with unquote/unquote-splicing
+  * specific elisp reader
 
 Especially still missing:
-  * real elisp reader instead of Scheme's
   * more general built-ins
   * advice?
   * defsubst and inlining
diff --git a/module/language/elisp/lexer.scm b/module/language/elisp/lexer.scm
index 3dbce86..0a981ca 100644
--- a/module/language/elisp/lexer.scm
+++ b/module/language/elisp/lexer.scm
@@ -21,11 +21,11 @@
 
 (define-module (language elisp lexer)
   #:use-module (ice-9 regex)
-  #:export (get-lexer))
+  #:export (get-lexer get-lexer/1))
 
 ; This is the lexical analyzer for the elisp reader.  It is hand-written
-; instead of using some generator because I think that's most viable in this
-; case and easy enough.
+; instead of using some generator.  I think this is the best solution
+; because of all that fancy escape sequence handling and the like.
 
 ; Characters are handled internally as integers representing their
 ; code value.  This is necessary because elisp allows a lot of fancy modifiers
@@ -297,7 +297,14 @@
           ((#\]) (return 'square-close #f))
           ((#\') (return 'quote #f))
           ((#\`) (return 'backquote #f))
-          ((#\,) (return 'unquote #f))
+
+          ; Unquote and unquote-splicing.
+          ((#\,)
+           (if (is-char? (peek-char port) #\@)
+             (if (not (char=? (read-char port) #\@))
+               (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
@@ -334,3 +341,29 @@
 (define (get-lexer port)
   (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
+; case.
+
+(define (get-lexer/1 port)
+  (let ((lex (get-lexer port))
+        (finished #f)
+        (paren-level 0))
+    (lambda ()
+      (if finished
+        '*eoi*
+        (let ((next (lex))
+              (quotation #f))
+          (case (car next)
+            ((paren-open square-open)
+             (set! paren-level (1+ paren-level)))
+            ((paren-close square-close)
+             (set! paren-level (1- paren-level)))
+            ((quote backquote unquote unquote-splicing)
+             (set! quotation #t)))
+          (if (and (not quotation) (<= paren-level 0))
+            (set! finished #t))
+          next)))))
diff --git a/module/language/elisp/parser.scm b/module/language/elisp/parser.scm
new file mode 100644
index 0000000..431eba3
--- /dev/null
+++ b/module/language/elisp/parser.scm
@@ -0,0 +1,76 @@
+;;; Guile Emac Lisp
+
+;; Copyright (C) 2001 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, 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,
+;; Boston, MA 02111-1307, USA.
+
+;;; Code:
+
+(define-module (language elisp parser)
+  #:use-module (language elisp lexer)
+  #:use-module (language ecmascript parse-lalr)
+  #:export (read-elisp))
+
+; The parser (reader) for elisp expressions.  It is implemented using the
+; (text parse-lalr) parser generator and uses my hand-written lexer as
+; the tokenizer.
+
+
+; Build the parser itself using parse-lalr.
+
+(define elisp-parser
+  (lalr-parser (integer float symbol character string
+                paren-open paren-close square-open square-close
+                dot quote backquote unquote unquote-splicing)
+
+    ; Expressions are our main interest.
+    ; It seems the symbol we're interested for return from the parser must
+    ; come very first, so here it is.
+    (expression (integer) -> $1
+                (float) -> $1
+                (symbol) -> $1
+                (character) -> $1
+                (string) -> $1
+                (list) -> $1
+                (quotation) -> $1
+                (vector) -> $1)
+
+    ; Pairs, lists and dotted lists.
+    (partial-list (expression) -> (list $1)
+                  (expression dot expression) -> (cons $1 $3)
+                  (expression partial-list) -> (cons $1 $2))
+    (list (paren-open paren-close) -> '()
+          (paren-open dot expression paren-close) -> $3
+          (paren-open partial-list paren-close) -> $2)
+
+    ; Quotation and unquotation expressions.
+    (quotation (quote expression) -> `(quote ,$2)
+               (backquote expression) -> `(\` ,$2)
+               (unquote expression) -> `(\, ,$2)
+               (unquote-splicing expression) -> `(\,@ ,$2))
+
+    ; Vectors.
+    (vector-elements (expression) -> (list $1)
+                     (expression vector-elements) -> (cons $1 $2))
+    (vector (square-open square-close) -> (make-vector 0)
+            (square-open vector-elements square-close) -> (list->vector $2))))
+
+
+; Use the parser to define the elisp reader function.
+; We only want to read a single expression at a time, so use get-lexer/1.
+
+(define (read-elisp port)
+  (elisp-parser (get-lexer/1 port) error))
diff --git a/module/language/elisp/spec.scm b/module/language/elisp/spec.scm
index 061bcb8..f89e0c1 100644
--- a/module/language/elisp/spec.scm
+++ b/module/language/elisp/spec.scm
@@ -20,13 +20,13 @@
 
 (define-module (language elisp spec)
   #:use-module (language elisp compile-tree-il)
+  #:use-module (language elisp parser)
   #:use-module (system base language)
   #:export (elisp))
 
 (define-language elisp
   #:title      "Emacs Lisp"
   #:version    "0.0"
-  #:reader     read
+  #:reader     (lambda () (read-elisp (current-input-port)))
   #:printer    write
-  #:compilers  `((tree-il . ,compile-tree-il))
-  )
+  #:compilers  `((tree-il . ,compile-tree-il)))
diff --git a/test-suite/tests/elisp-reader.test 
b/test-suite/tests/elisp-reader.test
index 15d5344..ab91792 100644
--- a/test-suite/tests/elisp-reader.test
+++ b/test-suite/tests/elisp-reader.test
@@ -19,7 +19,8 @@
 
 (define-module (test-elisp-reader)
   :use-module (test-suite lib)
-  :use-module (language elisp lexer))
+  :use-module (language elisp lexer)
+  :use-module (language elisp parser))
 
 
 ; 
==============================================================================
@@ -31,13 +32,15 @@
 (define (get-string-lexer str)
   (call-with-input-string str get-lexer))
 
+(define (lex-all lexer)
+  (let iterate ((result '()))
+    (let ((token (lexer)))
+      (if (eq? token '*eoi*)
+        (reverse result)
+        (iterate (cons token result))))))
+
 (define (lex-string str)
-  (let ((lexer (get-string-lexer str)))
-    (let iterate ((result '()))
-      (let ((token (lexer)))
-        (if (eq? token '*eoi*)
-          (reverse result)
-          (iterate (cons token result)))))))
+  (lex-all (get-string-lexer str)))
 
 (with-test-prefix "Lexer"
 
@@ -48,10 +51,11 @@
            (eq? (lexer) '*eoi*))))
 
   (pass-if "single character tokens"
-    (equal? (lex-string "()[]'`, . ")
+    (equal? (lex-string "()[]'`,,@ . ")
       '((paren-open . #f) (paren-close . #f)
         (square-open . #f) (square-close . #f)
-        (quote . #f) (backquote . #f) (unquote . #f) (dot . #f))))
+        (quote . #f) (backquote . #f)
+        (unquote . #f) (unquote-splicing . #f) (dot . #f))))
 
   (pass-if "whitespace and comments"
     (equal? (lex-string "   (\n\t) ; this is a comment\n.   ; until eof")
@@ -113,4 +117,46 @@ test\"ab\"\\ abcd
             `(,(+ (expt 2 26) (char->integer #\[))
               ,(+ (expt 2 27) (expt 2 25) (char->integer #\Z))
               ,(- (char->integer #\X) (char->integer #\@))
-              ,(+ (expt 2 22) (expt 2 23) (expt 2 24) 32)))))
+              ,(+ (expt 2 22) (expt 2 23) (expt 2 24) 32))))
+
+  (let* ((lex1-string "'((1 2) [2 [3]] 5)")
+         (lexer (call-with-input-string (string-append lex1-string " 1 2")
+                                        get-lexer/1)))
+    (pass-if "lexer/1"
+      (and (equal? (lex-all lexer) (lex-string lex1-string))
+           (eq? (lexer) '*eoi*)
+           (eq? (lexer) '*eoi*)))))
+
+
+; 
==============================================================================
+; Test the parser.
+
+(define (parse-str str)
+  (call-with-input-string str read-elisp))
+
+(with-test-prefix "Parser"
+
+  (pass-if "only next expression"
+    (equal? (parse-str "1 2 3") 1))
+
+  (pass-if "constants"
+    (and (equal? (parse-str "-12") -12)
+         (equal? (parse-str ".123") 0.123)
+         (equal? (parse-str "foobar") 'foobar)
+         (equal? (parse-str "\"abc\"") "abc")
+         (equal? (parse-str "?A") 65)
+         (equal? (parse-str "?\\C-@") 0)))
+
+  (pass-if "quotation"
+    (and (equal? (parse-str "'(1 2 3 '4)")
+                 '(quote (1 2 3 (quote 4))))
+         (equal? (parse-str "`(1 2 ,3 ,@a)")
+                 '(\` (1 2 (\, 3) (\,@ a))))))
+
+  (pass-if "lists"
+    (equal? (parse-str "(1 2 (3) () 4 (. 5) (1 2 . (3 4)) (1 . 2) . 42)")
+            '(1 2 (3) () 4 5 (1 2 3 4) (1 . 2) . 42)))
+
+  (pass-if "vectors"
+    (equal? (parse-str "[1 2 [] (3 4) \"abc\" d]")
+            #(1 2 #() (3 4) "abc" d))))


hooks/post-receive
-- 
GNU Guile




reply via email to

[Prev in Thread] Current Thread [Next in Thread]