(defmacro dolist (iter &body body)
(let ((var (first iter))
(g!list (gensym)))
- `(let ((,g!list ,(second iter))
- (,var nil))
- (while ,g!list
- (setq ,var (car ,g!list))
- ,@body
- (setq ,g!list (cdr ,g!list)))
- ,(third iter))))
+ `(block nil
+ (let ((,g!list ,(second iter))
+ (,var nil))
+ (%while ,g!list
+ (setq ,var (car ,g!list))
+ ,@body
+ (setq ,g!list (cdr ,g!list)))
+ ,(third iter)))))
(defmacro dotimes (iter &body body)
(let ((g!to (gensym))
(var (first iter))
(to (second iter))
(result (third iter)))
- `(let ((,var 0)
- (,g!to ,to))
- (while (< ,var ,g!to)
- ,@body
- (incf ,var))
- ,result)))
+ `(block nil
+ (let ((,var 0)
+ (,g!to ,to))
+ (%while (< ,var ,g!to)
+ ,@body
+ (incf ,var))
+ ,result))))
(defmacro cond (&rest clausules)
(if (null clausules)
(concat "(function(){" *newline*
(indent "try {" *newline*
(indent "return " (ls-compile `(progn ,@body)
- (extend-lexenv b env 'block))) ";" *newline*
+ (extend-lexenv b env 'block))
+ ";" *newline*)
"}" *newline*
"catch (cf){" *newline*
" if (cf.type == 'block' && cf.id == " tr ")" *newline*
"})})()")
(error (concat "Unknown block `" (symbol-name name) "'.")))))
+
+(define-compilation catch (id &rest body)
+ (concat "(function(){" *newline*
+ (indent "var id = " (ls-compile id env) ";" *newline*
+ "try {" *newline*
+ (indent "return " (ls-compile `(progn ,@body))
+ ";" *newline*)
+ "}" *newline*
+ "catch (cf){" *newline*
+ " if (cf.type == 'catch' && cf.id == id)" *newline*
+ " return cf.value;" *newline*
+ " else" *newline*
+ " throw cf;" *newline*
+ "}" *newline*)
+ "})()"))
+
+(define-compilation throw (id &optional value)
+ (concat "(function(){ throw ({"
+ "type: 'catch', "
+ "id: " (ls-compile id env) ", "
+ "value: " (ls-compile value env) ", "
+ "message: 'Throw uncatched.'"
+ "})})()"))
+
+
;;; A little backquote implementation without optimizations of any
;;; kind for ecmalisp.
(defun backquote-expand-1 (form)