summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Kraft <d@domob.eu>2009-07-18 18:38:42 +0200
committerDaniel Kraft <d@domob.eu>2009-07-18 18:38:42 +0200
commit7d1a978289c75efbb99684c4feb29dfb10cf1229 (patch)
tree23bc4cfb13578480aca3d90facb1d8f53971407c
parent570c12aca7dcab2adb60bd56319dcfc3e0d6379b (diff)
downloadguile-7d1a978289c75efbb99684c4feb29dfb10cf1229.tar.gz
Implemented unless, when and dotimes using built-in macros.
* module/language/elisp/README: Document that. * module/language/elisp/runtime.scm: Defined built-in-macro macro. * module/language/elisp/runtime/macro-slot.scm: Implement unless, when, dotimes. * test-suite/tests/elisp-compiler.test: Test for those constructs.
-rw-r--r--module/language/elisp/README9
-rw-r--r--module/language/elisp/runtime.scm29
-rw-r--r--module/language/elisp/runtime/macro-slot.scm39
-rw-r--r--test-suite/tests/elisp-compiler.test35
4 files changed, 92 insertions, 20 deletions
diff --git a/module/language/elisp/README b/module/language/elisp/README
index 684677bf4..8068351e7 100644
--- a/module/language/elisp/README
+++ b/module/language/elisp/README
@@ -6,10 +6,10 @@ as status information.
Already implemented:
* progn
- * if, cond
- * and, or
+ * if, cond, when, unless
+ * not, and, or
* referencing and setting (setq) variables
- * while
+ * while, dotimes
* let, let*
* lambda expressions, function calls using list notation
* some built-ins (mainly numbers/arithmetic)
@@ -19,8 +19,7 @@ Already implemented:
Especially still missing:
* other progX forms, will be done in macros
- * where, unless, will be done in macros
- * dolist, dotimes using macros
+ * dolist using macros
* catch/throw, unwind-protect
* real elisp reader instead of Scheme's
* set, makunbound, boundp functions
diff --git a/module/language/elisp/runtime.scm b/module/language/elisp/runtime.scm
index afdf59152..2bdadf9b4 100644
--- a/module/language/elisp/runtime.scm
+++ b/module/language/elisp/runtime.scm
@@ -20,8 +20,8 @@
;;; Code:
(define-module (language elisp runtime)
- #:export (void nil-value t-value elisp-bool)
- #:export-syntax (built-in-func))
+ #:export (void nil-value t-value elisp-bool macro-error)
+ #:export-syntax (built-in-func built-in-macro))
; This module provides runtime support for the Elisp front-end.
@@ -38,6 +38,13 @@
(define t-value #t)
+; Report an error during macro compilation, that means some special compilation
+; (syntax) error.
+
+(define (macro-error msg . args)
+ (apply error msg args))
+
+
; Convert a scheme boolean to Elisp.
(define (elisp-bool b)
@@ -46,9 +53,17 @@
nil-value))
-; Define a predefined function; convenient macro for this task.
+; Define a predefined function or predefined macro for use in the function-slot
+; and macro-slot modules, respectively.
+
+(define-syntax built-in-func
+ (syntax-rules ()
+ ((_ name value)
+ (begin
+ (define-public name (make-fluid))
+ (fluid-set! name value)))))
-(define-macro (built-in-func name value)
- `(begin
- (define-public ,name (make-fluid))
- (fluid-set! ,name ,value)))
+(define-syntax built-in-macro
+ (syntax-rules ()
+ ((_ name value)
+ (define-public name value))))
diff --git a/module/language/elisp/runtime/macro-slot.scm b/module/language/elisp/runtime/macro-slot.scm
index d17b6f414..9d0477be9 100644
--- a/module/language/elisp/runtime/macro-slot.scm
+++ b/module/language/elisp/runtime/macro-slot.scm
@@ -19,9 +19,46 @@
;;; Code:
-(define-module (language elisp runtime macro-slot))
+(define-module (language elisp runtime macro-slot)
+ #:use-module (language elisp runtime))
; This module contains the macro definitions of elisp symbols. In contrast to
; the other runtime modules, those are used directly during compilation, of
; course, so not really in runtime. But I think it fits well to the others
; here.
+
+
+; Define the conditionals when and unless as macros.
+
+(built-in-macro when
+ (lambda (condition . thens)
+ `(if ,condition (progn ,@thens) nil)))
+
+(built-in-macro unless
+ (lambda (condition . elses)
+ `(if ,condition nil (progn ,@elses))))
+
+
+; Define the dotimes and dolist iteration macros.
+; As the variable has to be bound locally for elisp, this needs to go through
+; the dynamic scoping fluid system. So we can't speed these forms up by
+; implementing them directly in the compiler with just a lexical variable
+; anyways.
+
+(built-in-macro dotimes
+ (lambda (args . body)
+ (if (or (not (list? args))
+ (< (length args) 2)
+ (> (length args) 3))
+ (macro-error "invalid dotimes arguments" args)
+ (let ((var (car args))
+ (count (cadr args)))
+ (if (not (symbol? var))
+ (macro-error "expected symbol as dotimes variable"))
+ `(let ((,var 0))
+ (while (< ,var ,count)
+ ,@body
+ (setq ,var (1+ ,var)))
+ ,@(if (= (length args) 3)
+ (list (caddr args))
+ '()))))))
diff --git a/test-suite/tests/elisp-compiler.test b/test-suite/tests/elisp-compiler.test
index 1705a971e..d36f47c77 100644
--- a/test-suite/tests/elisp-compiler.test
+++ b/test-suite/tests/elisp-compiler.test
@@ -56,12 +56,24 @@
(pass-if-equal "succeeding if" 1
(if t 1 2))
- (pass-if-equal "failing if" 3
- (if nil
- 1
- (setq a 2)
- (setq a (1+ a))
- a))
+ (pass-if "failing if"
+ (and (= (if nil
+ 1
+ (setq a 2) (setq a (1+ a)) a)
+ 3)
+ (equal (if nil 1) nil)))
+
+ (pass-if-equal "failing when" nil-value
+ (when nil 1 2 3))
+ (pass-if-equal "succeeding when" 42
+ (progn (setq a 0)
+ (when t (setq a 42) a)))
+
+ (pass-if-equal "failing unless" nil-value
+ (unless t 1 2 3))
+ (pass-if-equal "succeeding unless" 42
+ (progn (setq a 0)
+ (unless nil (setq a 42) a)))
(pass-if-equal "empty cond" nil-value
(cond))
@@ -101,7 +113,16 @@
(while (<= i 5)
(setq prod (* i prod))
(setq i (1+ i)))
- prod)))
+ prod))
+
+ (pass-if "dotimes"
+ (progn (setq a 0)
+ (setq count 100)
+ (setq b (dotimes (i count)
+ (setq j (1+ i))
+ (setq a (+ a j))))
+ (setq c (dotimes (i 10 42) nil))
+ (and (= a 5050) (equal b nil) (= c 42)))))
; Test handling of variables.