- (let ((bindings (mapcar #'ensure-list bindings)))
- (let ((variables (mapcar #'first bindings))
- (values (mapcar #'second bindings)))
- (let ((cvalues (mapcar #'ls-compile values))
- (*environment*
- (extend-local-env (remove-if (lambda (v)(claimp v 'variable 'special))
- variables)))
- (dynamic-bindings))
- (concat "(function("
- (join (mapcar (lambda (x)
- (if (claimp x 'variable 'special)
- (let ((v (gvarname x)))
- (push (cons x v) dynamic-bindings)
- v)
- (translate-variable x)))
- variables)
- ",")
- "){" *newline*
- (let ((body (ls-compile-block body t)))
- (indent (dynamic-binding-wrapper dynamic-bindings body)))
- "})(" (join cvalues ",") ")")))))
-
-
-(defun let*-initialize (x)
- (let ((var (first x))
- (value (second x)))
- (if (claimp var 'variable 'special)
- (ls-compile `(setq ,var ,value))
- (let ((v (gvarname var)))
- (let ((b (make-binding var 'variable v)))
- (prog1 (concat "var " v " = " (ls-compile value) ";" *newline*)
- (push-to-lexenv b *environment* 'variable)))))))
+ (let* ((bindings (mapcar #'ensure-list bindings))
+ (variables (mapcar #'first bindings))
+ (cvalues (mapcar #'ls-compile (mapcar #'second bindings)))
+ (*environment* (extend-local-env (remove-if #'special-variable-p variables)))
+ (dynamic-bindings))
+ (concat "(function("
+ (join (mapcar (lambda (x)
+ (if (special-variable-p x)
+ (let ((v (gvarname x)))
+ (push (cons x v) dynamic-bindings)
+ v)
+ (translate-variable x)))
+ variables)
+ ",")
+ "){" *newline*
+ (let ((body (ls-compile-block body t)))
+ (indent (let-binding-wrapper dynamic-bindings body)))
+ "})(" (join cvalues ",") ")")))
+
+
+;;; Return the code to initialize BINDING, and push it extending the
+;;; current lexical environment if the variable is not special.
+(defun let*-initialize-value (binding)
+ (let ((var (first binding))
+ (value (second binding)))
+ (if (special-variable-p var)
+ (concat (ls-compile `(setq ,var ,value)) ";" *newline*)
+ (let* ((v (gvarname var))
+ (b (make-binding var 'variable v)))
+ (prog1 (concat "var " v " = " (ls-compile value) ";" *newline*)
+ (push-to-lexenv b *environment* 'variable))))))
+
+;;; Wrap BODY to restore the symbol values of SYMBOLS after body. It
+;;; DOES NOT generate code to initialize the value of the symbols,
+;;; unlike let-binding-wrapper.
+(defun let*-binding-wrapper (symbols body)
+ (when (null symbols)
+ (return-from let*-binding-wrapper body))
+ (let ((store (mapcar (lambda (s) (cons s (gvarname s)))
+ (remove-if-not #'special-variable-p symbols))))
+ (concat
+ "try {" *newline*
+ (indent
+ (mapconcat (lambda (b)
+ (let ((s (ls-compile `(quote ,(car b)))))
+ (concat "var " (cdr b) " = " s ".value;" *newline*)))
+ store)
+ body)
+ "}" *newline*
+ "finally {" *newline*
+ (indent
+ (mapconcat (lambda (b)
+ (let ((s (ls-compile `(quote ,(car b)))))
+ (concat s ".value" " = " (cdr b) ";" *newline*)))
+ store))
+ "}" *newline*)))