summaryrefslogtreecommitdiff
path: root/module
diff options
context:
space:
mode:
authorDaniel Kraft <d@domob.eu>2009-08-26 21:36:37 +0200
committerDaniel Kraft <d@domob.eu>2009-08-26 21:36:37 +0200
commite840cc654032c60e43aec0f868d67905a3bf5523 (patch)
treef8acb132df51b45ba909b553b9828503c3f72a23 /module
parentddb4364b1a1635fce0b1d2eaa7d50a951c6c4dfc (diff)
downloadguile-e840cc654032c60e43aec0f868d67905a3bf5523.tar.gz
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.
Diffstat (limited to 'module')
-rw-r--r--module/language/elisp/README2
-rw-r--r--module/language/elisp/lexer.scm20
-rw-r--r--module/language/elisp/parser.scm76
-rw-r--r--module/language/elisp/spec.scm6
4 files changed, 96 insertions, 8 deletions
diff --git a/module/language/elisp/README b/module/language/elisp/README
index be625ffd3..4f33711de 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 05df03d89..0a981ca24 100644
--- a/module/language/elisp/lexer.scm
+++ b/module/language/elisp/lexer.scm
@@ -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
@@ -338,6 +345,8 @@
; 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))
@@ -346,12 +355,15 @@
(lambda ()
(if finished
'*eoi*
- (let ((next (lex)))
+ (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))))
- (if (<= paren-level 0)
+ (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 000000000..431eba3d0
--- /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 061bcb830..f89e0c1d4 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)))