ref: ecfd81148fe6a4d77924b8201051fadc36c3e42b
parent: eceeddf6d218e12cefb36fb9594c29be37852dd2
author: JeffBezanson <jeff.bezanson@gmail.com>
date: Tue Jul 28 00:16:20 EDT 2009
changing optional args to allow default values to be computed from preceding arguments tidying some stuff with keywords
--- a/femtolisp/builtins.c
+++ b/femtolisp/builtins.c
@@ -135,8 +135,7 @@
{
argcount("keyword?", nargs, 1);
symbol_t *sym = tosymbol(args[0], "keyword?");
- char *str = sym->name;
- return fl_is_keyword_name(str, strlen(str)) ? FL_T : FL_F;
+ return iskeyword(sym) ? FL_T : FL_F;
}
static value_t fl_top_level_value(value_t *args, u_int32_t nargs)
@@ -152,7 +151,7 @@
{
argcount("set-top-level-value!", nargs, 2);
symbol_t *sym = tosymbol(args[0], "set-top-level-value!");
- if (!sym->isconst)
+ if (!isconstant(sym))
sym->binding = args[1];
return args[1];
}
@@ -187,7 +186,7 @@
{
argcount("constant?", nargs, 1);
if (issymbol(args[0]))
- return (isconstant(args[0]) ? FL_T : FL_F);
+ return (isconstant((symbol_t*)ptr(args[0])) ? FL_T : FL_F);
if (iscons(args[0])) {
if (car_(args[0]) == QUOTE)
return FL_T;
--- a/femtolisp/compiler.lsp
+++ b/femtolisp/compiler.lsp
@@ -3,30 +3,30 @@
(define Instructions
(let ((e (table))
(keys
- [:nop :dup :pop :call :tcall :jmp :brf :brt :jmp.l :brf.l :brt.l :ret
+ [nop dup pop call tcall jmp brf brt jmp.l brf.l brt.l ret
- :eq? :eqv? :equal? :atom? :not :null? :boolean? :symbol?
- :number? :bound? :pair? :builtin? :vector? :fixnum? :function?
+ eq? eqv? equal? atom? not null? boolean? symbol?
+ number? bound? pair? builtin? vector? fixnum? function?
- :cons :list :car :cdr :set-car! :set-cdr!
- :apply
+ cons list car cdr set-car! set-cdr!
+ apply
- :+ :- :* :/ :div0 := :< :compare
+ + - * / div0 = < compare
- :vector :aref :aset!
+ vector aref aset!
- :loadt :loadf :loadnil :load0 :load1 :loadi8
- :loadv :loadv.l
- :loadg :loadg.l
- :loada :loada.l :loadc :loadc.l
- :setg :setg.l
- :seta :seta.l :setc :setc.l
+ loadt loadf loadnil load0 load1 loadi8
+ loadv loadv.l
+ loadg loadg.l
+ loada loada.l loadc loadc.l
+ setg setg.l
+ seta seta.l setc setc.l
- :closure :argc :vargc :trycatch :copyenv :let :for :tapply
- :add2 :sub2 :neg :largc :lvargc
- :loada0 :loada1 :loadc00 :loadc01 :call.l :tcall.l
- :brne :brne.l :cadr :brnn :brnn.l :brn :brn.l
- :optargs
+ closure argc vargc trycatch copyenv let for tapply
+ add2 sub2 neg largc lvargc
+ loada0 loada1 loadc00 loadc01 call.l tcall.l
+ brne brne.l cadr brnn brnn.l brn brn.l
+ optargs brbound
dummy_t dummy_f dummy_nil]))
(for 0 (1- (length keys))
@@ -34,19 +34,19 @@
(put! e (aref keys i) i)))))
(define arg-counts
- (table :eq? 2 :eqv? 2
- :equal? 2 :atom? 1
- :not 1 :null? 1
- :boolean? 1 :symbol? 1
- :number? 1 :bound? 1
- :pair? 1 :builtin? 1
- :vector? 1 :fixnum? 1
- :cons 2 :car 1
- :cdr 1 :set-car! 2
- :set-cdr! 2 := 2
- :< 2 :compare 2
- :aref 2 :aset! 3
- :div0 2))
+ (table eq? 2 eqv? 2
+ equal? 2 atom? 1
+ not 1 null? 1
+ boolean? 1 symbol? 1
+ number? 1 bound? 1
+ pair? 1 builtin? 1
+ vector? 1 fixnum? 1
+ cons 2 car 1
+ cdr 1 set-car! 2
+ set-cdr! 2 = 2
+ < 2 compare 2
+ aref 2 aset! 3
+ div0 2))
(define (make-code-emitter) (vector () (table) 0 +inf.0))
(define (bcode:code b) (aref b 0))
@@ -64,60 +64,60 @@
(aset! b 2 (+ nconst 1)))))))
(define (emit e inst . args)
(if (null? args)
- (if (and (eq? inst :car) (pair? (aref e 0))
- (eq? (car (aref e 0)) :cdr))
- (set-car! (aref e 0) :cadr)
+ (if (and (eq? inst 'car) (pair? (aref e 0))
+ (eq? (car (aref e 0)) 'cdr))
+ (set-car! (aref e 0) 'cadr)
(aset! e 0 (cons inst (aref e 0))))
(begin
- (if (memq inst '(:loadv :loadg :setg))
+ (if (memq inst '(loadv loadg setg))
(set! args (list (bcode:indexfor e (car args)))))
(let ((longform
- (assq inst '((:loadv :loadv.l) (:loadg :loadg.l) (:setg :setg.l)
- (:loada :loada.l) (:seta :seta.l)))))
+ (assq inst '((loadv loadv.l) (loadg loadg.l) (setg setg.l)
+ (loada loada.l) (seta seta.l)))))
(if (and longform
(> (car args) 255))
(set! inst (cadr longform))))
(let ((longform
- (assq inst '((:loadc :loadc.l) (:setc :setc.l)))))
+ (assq inst '((loadc loadc.l) (setc setc.l)))))
(if (and longform
(or (> (car args) 255)
(> (cadr args) 255)))
(set! inst (cadr longform))))
- (if (eq? inst :loada)
+ (if (eq? inst 'loada)
(cond ((equal? args '(0))
- (set! inst :loada0)
+ (set! inst 'loada0)
(set! args ()))
((equal? args '(1))
- (set! inst :loada1)
+ (set! inst 'loada1)
(set! args ()))))
- (if (eq? inst :loadc)
+ (if (eq? inst 'loadc)
(cond ((equal? args '(0 0))
- (set! inst :loadc00)
+ (set! inst 'loadc00)
(set! args ()))
((equal? args '(0 1))
- (set! inst :loadc01)
+ (set! inst 'loadc01)
(set! args ()))))
(let ((lasti (if (pair? (aref e 0))
(car (aref e 0)) ()))
(bc (aref e 0)))
- (cond ((and (eq? inst :brf) (eq? lasti :not)
- (eq? (cadr bc) :null?))
- (aset! e 0 (cons (car args) (cons :brn (cddr bc)))))
- ((and (eq? inst :brf) (eq? lasti :not))
- (aset! e 0 (cons (car args) (cons :brt (cdr bc)))))
- ((and (eq? inst :brf) (eq? lasti :eq?))
- (aset! e 0 (cons (car args) (cons :brne (cdr bc)))))
- ((and (eq? inst :brf) (eq? lasti :null?))
- (aset! e 0 (cons (car args) (cons :brnn (cdr bc)))))
- ((and (eq? inst :brt) (eq? lasti :null?))
- (aset! e 0 (cons (car args) (cons :brn (cdr bc)))))
+ (cond ((and (eq? inst 'brf) (eq? lasti 'not)
+ (eq? (cadr bc) 'null?))
+ (aset! e 0 (cons (car args) (cons 'brn (cddr bc)))))
+ ((and (eq? inst 'brf) (eq? lasti 'not))
+ (aset! e 0 (cons (car args) (cons 'brt (cdr bc)))))
+ ((and (eq? inst 'brf) (eq? lasti 'eq?))
+ (aset! e 0 (cons (car args) (cons 'brne (cdr bc)))))
+ ((and (eq? inst 'brf) (eq? lasti 'null?))
+ (aset! e 0 (cons (car args) (cons 'brnn (cdr bc)))))
+ ((and (eq? inst 'brt) (eq? lasti 'null?))
+ (aset! e 0 (cons (car args) (cons 'brn (cdr bc)))))
(else
(aset! e 0 (nreconc (cons inst args) bc)))))))
e)
(define (make-label e) (gensym))
-(define (mark-label e l) (emit e :label l))
+(define (mark-label e l) (emit e 'label l))
; convert symbolic bytecode representation to a byte array.
; labels are fixed-up.
@@ -127,13 +127,7 @@
(long? (>= (+ (length v) ; 1 byte for each entry, plus...
; at most half the entries in this vector can be
; instructions accepting 32-bit arguments
- (* 3 (div0 (length v) 2))
- #;(* 3 (count (lambda (i)
- (memq i '(:loadv.l :loadg.l :setg.l
- :loada.l :seta.l :loadc.l
- :setc.l :jmp :brt :brf
- :largc :lvargc)))
- cl)))
+ (* 3 (div0 (length v) 2)))
65536)))
(let ((n (length v))
(i 0)
@@ -146,7 +140,7 @@
(while (< i n)
(begin
(set! vi (aref v i))
- (if (eq? vi :label)
+ (if (eq? vi 'label)
(begin (put! label-to-loc (aref v (+ i 1)) (sizeof bcode))
(set! i (+ i 2)))
(begin
@@ -155,34 +149,40 @@
(get Instructions
(if long?
(case vi
- (:jmp :jmp.l)
- (:brt :brt.l)
- (:brf :brf.l)
- (:brne :brne.l)
- (:brnn :brnn.l)
- (:brn :brn.l)
+ (jmp 'jmp.l)
+ (brt 'brt.l)
+ (brf 'brf.l)
+ (brne 'brne.l)
+ (brnn 'brnn.l)
+ (brn 'brn.l)
(else vi))
vi))))
(set! i (+ i 1))
(set! nxt (if (< i n) (aref v i) #f))
- (cond ((memq vi '(:jmp :brf :brt :brne :brnn :brn))
+ (cond ((memq vi '(jmp brf brt brne brnn brn))
(put! fixup-to-label (sizeof bcode) nxt)
(io.write bcode ((if long? int32 int16) 0))
(set! i (+ i 1)))
+ ((eq? vi 'brbound)
+ (io.write bcode (int32 nxt))
+ (set! i (+ i 1))
+ (put! fixup-to-label (sizeof bcode) (aref v i))
+ (io.write bcode (int32 0))
+ (set! i (+ i 1)))
((number? nxt)
(case vi
- ((:loadv.l :loadg.l :setg.l :loada.l :seta.l
- :largc :lvargc :call.l :tcall.l :optargs)
+ ((loadv.l loadg.l setg.l loada.l seta.l
+ largc lvargc call.l tcall.l)
(io.write bcode (int32 nxt))
(set! i (+ i 1)))
- ((:loadc :setc) ; 2 uint8 args
+ ((loadc setc) ; 2 uint8 args
(io.write bcode (uint8 nxt))
(set! i (+ i 1))
(io.write bcode (uint8 (aref v i)))
(set! i (+ i 1)))
- ((:loadc.l :setc.l) ; 2 int32 args
+ ((loadc.l setc.l optargs) ; 2 int32 args
(io.write bcode (int32 nxt))
(set! i (+ i 1))
(io.write bcode (int32 (aref v i)))
@@ -245,7 +245,7 @@
(else
(if (and (constant? s)
(printable? (top-level-value s)))
- (emit g :loadv (top-level-value s))
+ (emit g 'loadv (top-level-value s))
(emit g (aref Is 2) s))))))
(define (compile-if g env tail? x)
@@ -262,11 +262,11 @@
(compile-in g env tail? else))
(else
(compile-in g env #f test)
- (emit g :brf elsel)
+ (emit g 'brf elsel)
(compile-in g env tail? then)
(if tail?
- (emit g :ret)
- (emit g :jmp endl))
+ (emit g 'ret)
+ (emit g 'jmp endl))
(mark-label g elsel)
(compile-in g env tail? else)
(mark-label g endl)))))
@@ -277,7 +277,7 @@
(compile-in g env tail? (car forms)))
(else
(compile-in g env #f (car forms))
- (emit g :pop)
+ (emit g 'pop)
(compile-begin g env tail? (cdr forms)))))
(define (compile-prog1 g env x)
@@ -284,7 +284,7 @@
(compile-in g env #f (cadr x))
(if (pair? (cddr x))
(begin (compile-begin g env #f (cddr x))
- (emit g :pop))))
+ (emit g 'pop))))
(define (compile-while g env cond body)
(let ((top (make-label g))
@@ -292,10 +292,10 @@
(compile-in g env #f #f)
(mark-label g top)
(compile-in g env #f cond)
- (emit g :brf end)
- (emit g :pop)
+ (emit g 'brf end)
+ (emit g 'pop)
(compile-in g env #f body)
- (emit g :jmp top)
+ (emit g 'jmp top)
(mark-label g end)))
(define (1arg-lambda? func)
@@ -310,7 +310,7 @@
(begin (compile-in g env #f lo)
(compile-in g env #f hi)
(compile-in g env #f func)
- (emit g :for))
+ (emit g 'for))
(error "for: third form must be a 1-argument lambda")))
(define (compile-short-circuit g env tail? forms default branch)
@@ -319,16 +319,16 @@
(else
(let ((end (make-label g)))
(compile-in g env #f (car forms))
- (emit g :dup)
+ (emit g 'dup)
(emit g branch end)
- (emit g :pop)
+ (emit g 'pop)
(compile-short-circuit g env tail? (cdr forms) default branch)
(mark-label g end)))))
(define (compile-and g env tail? forms)
- (compile-short-circuit g env tail? forms #t :brf))
+ (compile-short-circuit g env tail? forms #t 'brf))
(define (compile-or g env tail? forms)
- (compile-short-circuit g env tail? forms #f :brt))
+ (compile-short-circuit g env tail? forms #f 'brt))
(define (compile-arglist g env lst)
(for-each (lambda (a)
@@ -337,10 +337,10 @@
(length lst))
(define (argc-error head count)
- (error (string "compile error: " head " expects " count
- (if (= count 1)
- " argument."
- " arguments."))))
+ (error "compile error: " head " expects " count
+ (if (= count 1)
+ " argument."
+ " arguments.")))
(define (compile-app g env tail? x)
(let ((head (car x)))
@@ -356,28 +356,28 @@
(let ((head (car x))
(args (cdr x)))
(unless (length= args (length (cadr head)))
- (error (string "apply: incorrect number of arguments to " head)))
+ (error "apply: incorrect number of arguments to " head))
(receive (the-f dept) (compile-f- env head #t)
- (emit g :loadv the-f)
+ (emit g 'loadv the-f)
(bcode:cdepth g dept))
(let ((nargs (compile-arglist g env args)))
- (emit g :copyenv)
- (emit g (if tail? :tcall :call) (+ 1 nargs)))))
+ (emit g 'copyenv)
+ (emit g (if tail? 'tcall 'call) (+ 1 nargs)))))
(define builtin->instruction
- (let ((b2i (table number? :number? cons :cons
- fixnum? :fixnum? equal? :equal?
- eq? :eq? symbol? :symbol?
- div0 :div0 builtin? :builtin?
- aset! :aset! - :- boolean? :boolean? not :not
- apply :apply atom? :atom?
- set-cdr! :set-cdr! / :/
- function? :function? vector :vector
- list :list bound? :bound?
- < :< * :* cdr :cdr null? :null?
- + :+ eqv? :eqv? compare :compare aref :aref
- set-car! :set-car! car :car
- pair? :pair? = := vector? :vector?)))
+ (let ((b2i (table number? 'number? cons 'cons
+ fixnum? 'fixnum? equal? 'equal?
+ eq? 'eq? symbol? 'symbol?
+ div0 'div0 builtin? 'builtin?
+ aset! 'aset! - '- boolean? 'boolean? not 'not
+ apply 'apply atom? 'atom?
+ set-cdr! 'set-cdr! / '/
+ function? 'function? vector 'vector
+ list 'list bound? 'bound?
+ < '< * '* cdr 'cdr null? 'null?
+ + '+ eqv? 'eqv? compare 'compare aref 'aref
+ set-car! 'set-car! car 'car
+ pair? 'pair? = '= vector? 'vector?)))
(lambda (b)
(get b2i b #f))))
@@ -387,25 +387,25 @@
(not (length= (cdr x) count)))
(argc-error head count))
(case b ; handle special cases of vararg builtins
- (:list (if (= nargs 0) (emit g :loadnil) (emit g b nargs)))
- (:+ (cond ((= nargs 0) (emit g :load0))
- ((= nargs 2) (emit g :add2))
- (else (emit g b nargs))))
- (:- (cond ((= nargs 0) (argc-error head 1))
- ((= nargs 1) (emit g :neg))
- ((= nargs 2) (emit g :sub2))
- (else (emit g b nargs))))
- (:* (if (= nargs 0) (emit g :load1)
- (emit g b nargs)))
- (:/ (if (= nargs 0)
- (argc-error head 1)
- (emit g b nargs)))
- (:vector (if (= nargs 0)
- (emit g :loadv [])
- (emit g b nargs)))
- (:apply (if (< nargs 2)
- (argc-error head 2)
- (emit g (if tail? :tapply :apply) nargs)))
+ (list (if (= nargs 0) (emit g 'loadnil) (emit g b nargs)))
+ (+ (cond ((= nargs 0) (emit g 'load0))
+ ((= nargs 2) (emit g 'add2))
+ (else (emit g b nargs))))
+ (- (cond ((= nargs 0) (argc-error head 1))
+ ((= nargs 1) (emit g 'neg))
+ ((= nargs 2) (emit g 'sub2))
+ (else (emit g b nargs))))
+ (* (if (= nargs 0) (emit g 'load1)
+ (emit g b nargs)))
+ (/ (if (= nargs 0)
+ (argc-error head 1)
+ (emit g b nargs)))
+ (vector (if (= nargs 0)
+ (emit g 'loadv [])
+ (emit g b nargs)))
+ (apply (if (< nargs 2)
+ (argc-error head 2)
+ (emit g (if tail? 'tapply 'apply) nargs)))
(else (emit g b)))))
(define (compile-call g env tail? x)
@@ -422,7 +422,7 @@
; more than 255 arguments, need long versions of instructions
(begin (compile-in g env #f head)
(let ((nargs (compile-arglist g env (cdr x))))
- (emit g (if tail? :tcall.l :call.l) nargs)))
+ (emit g (if tail? 'tcall.l 'call.l) nargs)))
(let ((b (and (builtin? head)
(builtin->instruction head))))
(if (and (eq? head 'cadr)
@@ -430,7 +430,7 @@
(equal? (top-level-value 'cadr) cadr)
(length= x 2))
(begin (compile-in g env #f (cadr x))
- (emit g :cadr))
+ (emit g 'cadr))
(begin
(if (not b)
(compile-in g env #f head))
@@ -437,7 +437,7 @@
(let ((nargs (compile-arglist g env (cdr x))))
(if b
(compile-builtin-call g env tail? x head b nargs)
- (emit g (if tail? :tcall :call) nargs))))))))))
+ (emit g (if tail? 'tcall 'call) nargs))))))))))
(define (expand-define form body)
(if (symbol? form)
@@ -448,34 +448,34 @@
(define (fits-i8 x) (and (fixnum? x) (>= x -128) (<= x 127)))
(define (compile-in g env tail? x)
- (cond ((symbol? x) (compile-sym g env x [:loada :loadc :loadg]))
+ (cond ((symbol? x) (compile-sym g env x [loada loadc loadg]))
((atom? x)
- (cond ((eq? x 0) (emit g :load0))
- ((eq? x 1) (emit g :load1))
- ((eq? x #t) (emit g :loadt))
- ((eq? x #f) (emit g :loadf))
- ((eq? x ()) (emit g :loadnil))
- ((fits-i8 x) (emit g :loadi8 x))
- (else (emit g :loadv x))))
+ (cond ((eq? x 0) (emit g 'load0))
+ ((eq? x 1) (emit g 'load1))
+ ((eq? x #t) (emit g 'loadt))
+ ((eq? x #f) (emit g 'loadf))
+ ((eq? x ()) (emit g 'loadnil))
+ ((fits-i8 x) (emit g 'loadi8 x))
+ (else (emit g 'loadv x))))
(else
(case (car x)
- (quote (emit g :loadv (cadr x)))
+ (quote (emit g 'loadv (cadr x)))
(if (compile-if g env tail? x))
(begin (compile-begin g env tail? (cdr x)))
(prog1 (compile-prog1 g env x))
(lambda (receive (the-f dept) (compile-f- env x)
- (begin (emit g :loadv the-f)
+ (begin (emit g 'loadv the-f)
(bcode:cdepth g dept)
(if (< dept (nnn env))
- (emit g :closure)))))
+ (emit g 'closure)))))
(and (compile-and g env tail? (cdr x)))
(or (compile-or g env tail? (cdr x)))
(while (compile-while g env (cadr x) (cons 'begin (cddr x))))
(for (compile-for g env (cadr x) (caddr x) (cadddr x)))
(return (compile-in g env #t (cadr x))
- (emit g :ret))
+ (emit g 'ret))
(set! (compile-in g env #f (caddr x))
- (compile-sym g env (cadr x) [:seta :setc :setg]))
+ (compile-sym g env (cadr x) [seta setc setg]))
(define (compile-in g env tail?
(expand-define (cadr x) (cddr x))))
(trycatch (compile-in g env #f `(lambda () ,(cadr x)))
@@ -482,7 +482,7 @@
(unless (1arg-lambda? (caddr x))
(error "trycatch: second form must be a 1-argument lambda"))
(compile-in g env #f (caddr x))
- (emit g :trycatch))
+ (emit g 'trycatch))
(else (compile-app g env tail? x))))))
(define (compile-f env f . let?)
@@ -516,19 +516,29 @@
(or (symbol? (car l))
(and (pair? (car l))
(or (every pair? (cdr l))
- (error (string "compile error: invalid argument list "
- o ". optional arguments must come last."))))
- (error (string "compile error: invalid formal argument " (car l)
- " in list " o)))
+ (error "compile error: invalid argument list "
+ o ". optional arguments must come last.")))
+ (error "compile error: invalid formal argument " (car l)
+ " in list " o))
(check-formals (cdr l) o))
(if (eq? l o)
- (error (string "compile error: invalid argument list " o))
- (error (string "compile error: invalid formal argument " l
- " in list " o)))))
+ (error "compile error: invalid argument list " o)
+ (error "compile error: invalid formal argument " l " in list " o))))
(check-formals l l)
(map (lambda (s) (if (pair? s) (car s) s))
(to-proper l)))
+(define (emit-optional-arg-inits g env opta vars i)
+ ; i is the lexical var index of the opt arg to process next
+ (if (pair? opta)
+ (let ((nxt (make-label g)))
+ (emit g 'brbound i nxt)
+ (compile-in g (cons (list-head vars i) env) #f (cadar opta))
+ (emit g 'seta i)
+ (emit g 'pop)
+ (mark-label g nxt)
+ (emit-optional-arg-inits g env (cdr opta) vars (+ i 1)))))
+
(define compile-f-
(let ((*defines-processed-token* (gensym)))
; to eval a top-level expression we need to avoid internal define
@@ -553,24 +563,26 @@
(let ((g (make-code-emitter))
(args (cadr f))
+ (atail (lastcdr (cadr f)))
(vars (lambda-vars (cadr f)))
(opta (filter pair? (cadr f)))
(name (if (eq? (lastcdr f) *defines-processed-token*)
'lambda
(lastcdr f))))
- (let ((nargs (if (atom? args) 0 (length args))))
+ (let* ((nargs (if (atom? args) 0 (length args)))
+ (nreq (- nargs (length opta))))
; emit argument checking prologue
(if (not (null? opta))
- (begin (bcode:indexfor g (list->vector (map cadr opta)))
- (emit g :optargs (- nargs (length opta)))))
+ (begin (emit g 'optargs (if (null? atail) nreq (- nreq)) nargs)
+ (emit-optional-arg-inits g env opta vars nreq)))
- (cond ((not (null? let?)) (emit g :let))
- ((> nargs 255) (emit g (if (null? (lastcdr args))
- :largc :lvargc)
+ (cond ((not (null? let?)) (emit g 'let))
+ ((> nargs 255) (emit g (if (null? atail)
+ 'largc 'lvargc)
nargs))
- ((null? (lastcdr args)) (emit g :argc nargs))
- (else (emit g :vargc nargs)))
+ ((not (null? atail)) (emit g 'vargc nargs))
+ ((null? opta) (emit g 'argc nargs)))
; compile body and return
(compile-in g (cons vars env) #t
@@ -577,7 +589,7 @@
(if (eq? (lastcdr f) *defines-processed-token*)
(caddr f)
(lambda-body f)))
- (emit g :ret)
+ (emit g 'ret)
(values (function (encode-byte-code (bcode:code g))
(const-to-idx-vec g) name)
(aref g 3)))))))
@@ -623,43 +635,49 @@
(if (> i 4) (newline))
(dotimes (xx lev) (princ "\t"))
(princ (hex5 (- i 4)) ": "
- (string.tail (string inst) 1) "\t")
+ (string inst) "\t")
(set! i (+ i 1))
(case inst
- ((:loadv.l :loadg.l :setg.l)
+ ((loadv.l loadg.l setg.l)
(print-val (aref vals (ref-int32-LE code i)))
(set! i (+ i 4)))
- ((:loadv :loadg :setg)
+ ((loadv loadg setg)
(print-val (aref vals (aref code i)))
(set! i (+ i 1)))
- ((:loada :seta :call :tcall :list :+ :- :* :/ :vector
- :argc :vargc :loadi8 :apply :tapply)
+ ((loada seta call tcall list + - * / vector
+ argc vargc loadi8 apply tapply)
(princ (number->string (aref code i)))
(set! i (+ i 1)))
- ((:loada.l :seta.l :largc :lvargc :call.l :tcall.l :optargs)
+ ((loada.l seta.l largc lvargc call.l tcall.l)
(princ (number->string (ref-int32-LE code i)))
(set! i (+ i 4)))
-
- ((:loadc :setc)
+
+ ((loadc setc)
(princ (number->string (aref code i)) " ")
(set! i (+ i 1))
(princ (number->string (aref code i)))
(set! i (+ i 1)))
- ((:loadc.l :setc.l)
+ ((loadc.l setc.l optargs)
(princ (number->string (ref-int32-LE code i)) " ")
(set! i (+ i 4))
(princ (number->string (ref-int32-LE code i)))
(set! i (+ i 4)))
- ((:jmp :brf :brt :brne :brnn :brn)
+ ((brbound)
+ (princ (number->string (ref-int32-LE code i)) " ")
+ (set! i (+ i 4))
+ (princ "@" (hex5 (+ i -4 (ref-int32-LE code i))))
+ (set! i (+ i 4)))
+
+ ((jmp brf brt brne brnn brn)
(princ "@" (hex5 (+ i -4 (ref-int16-LE code i))))
(set! i (+ i 2)))
- ((:jmp.l :brf.l :brt.l :brne.l :brnn.l :brn.l)
+ ((jmp.l brf.l brt.l brne.l brnn.l brn.l)
(princ "@" (hex5 (+ i -4 (ref-int32-LE code i))))
(set! i (+ i 4)))
--- a/femtolisp/flisp.boot
+++ b/femtolisp/flisp.boot
@@ -1,1 +1,1 @@
-(*banner* "; _\n; |_ _ _ |_ _ | . _ _\n; | (-||||_(_)|__|_)|_)\n;-------------------|----------------------------------------------------------\n\n" *syntax-environment* #table(assert #function("<000r1c0~]c1c2c3~L2L2L2L4;" [if raise quote assert-failed]) letrec #function("?000s1e0e0c1L1e2c3~32L1e2c4~32e5\x7f3134L1e2c6~3242;" [nconc lambda map #.car #function("9000r1e0c1L1e2~3142;" [nconc set! copy-list]) copy-list #function("6000r1^;" [])]) backquote #function("7000r1e0~41;" [bq-process]) label #function(":000r2c0~L1c1~\x7fL3L3^L2;" [lambda set!]) do #function("A000s2c0e130\x7fMe2c3~32e2e4~32e2c5~32u46;" [#function("B000vc0~c1g2c2\x7fe3c4L1e5\x81N3132e3c4L1e5i0231e3~L1g432L133L4L3L2L1e3~L1g332L3;" [letrec lambda if nconc begin copy-list]) gensym map #.car cadr #function("7000r1e0~31F680e1~41;~M;" [cddr caddr])]) when #function("<000s1c0~c1\x7fK^L4;" [if begin]) unwind-protect #function("9000r2c0e130e130u43;" [#function("@000vc0\x7fc1_\x81L3L2L1c2c3\x80c1~L1c4\x7fL1c5~L2L3L3L3\x7fL1L3L3;" [let lambda prog1 trycatch begin raise]) gensym]) dotimes #function("<000s1c0~M~\x86u43;" [#function("=000vc0`c1\x7faL3e2c3L1~L1L1e4\x813133L4;" [for - nconc lambda copy-list])]) define-macro #function("?000s1c0c1~ML2e2c3L1~NL1e4\x7f3133L3;" [set-syntax! quote nconc lambda copy-list]) receive #function("@000s2c0c1_\x7fL3e2c1L1~L1e3g23133L3;" [call-with-values lambda nconc copy-list]) unless #function("=000s1c0~^c1\x7fKL4;" [if begin]) let #function(";000s1c0^u42;" [#function("<000v\x80C6D0\x80m02\x81Mo002\x81No01530^2c0e1c2L1e3c4\x8032L1e5\x813133e3c6\x8032u43;" [#function("8000v\x806;0c0\x80~L3530~\x7fK;" [label]) nconc lambda map #function("6000r1~F650~M;~;" []) copy-list #function("6000r1~F650~\x86;^;" [])])]) cond #function(":000s0c0^u42;" [#function("7000vc0qm02~\x8041;" [#function("8000r1~?640^;c0~Mu42;" [#function(";000v~Mc0<17702~M]<6@0~N\x8750~M;c1~NK;~N\x87@0c2~Mi10\x80N31L3;c3~Mc1~NKi10\x80N31L4;" [else begin or if])] cond-clauses->if)])]) throw #function(":000r2c0c1c2c3L2~\x7fL4L2;" [raise list quote thrown-value]) time #function("8000r1c0e130u42;" [#function(">000vc0~c1L1L2L1c2\x80c3c4c5c1L1~L3c6L4L3L3;" [let time.now prog1 princ "Elapsed time: " - " seconds\n"]) gensym]) let* #function("A000s1~?6E0e0c1L1_L1e2\x7f3133L1;e0c1L1e3~31L1L1e2~NF6H0e0c4L1~NL1e2\x7f3133L1530\x7f3133e5~31L2;" [nconc lambda copy-list caar let* cadar]) case #function(";000s1c0^u42;" [#function("8000vc0m02c1e230u42;" [#function(";000r2\x7fc0\x8450c0;\x7f\x8740^;\x7fC6=0c1~e2\x7f31L3;\x7f?6=0c3~e2\x7f31L3;\x7fN\x87>0c3~e2\x7fM31L3;e4c5\x7f326=0c6~c7\x7fL2L3;c8~c7\x7fL2L3;" [else eq? quote-value eqv? every #.symbol? memq quote memv] vals->cond) #function("<000vc0~i10L2L1e1c2L1e3c4qi113232L3;" [let nconc cond map #function("8000r1i10\x80~M32~NK;" [])]) gensym])]) catch #function("8000r2c0e130u42;" [#function("@000vc0\x81c1~L1c2c3c4~L2c5c6~L2c7c8L2L3c5c9~L2\x80L3L4c:~L2c;~L2L4L3L3;" [trycatch lambda if and pair? eq car quote thrown-value cadr caddr raise]) gensym])) *whitespace* "\t\n\v\f\r \u0085 \u2028\u2029 " /= #function("7000r2~\x7fW@;" [] /=) 1+ #function("7000r1~ay;" [] 1+) 1- #function("7000r1~az;" [] 1-) 1arg-lambda? #function("8000r1~F16T02~Mc0<16J02~NF16B02~\x86F16:02e1~\x86a42;" [lambda length=] 1arg-lambda?) <= #function("7000r2~\x7fX17602~\x7fW;" [] <=) > #function("7000r2\x7f~X;" [] >) >= #function("7000r2\x7f~X17602~\x7fW;" [] >=) Instructions #table(:sub2 74 :nop 0 :set-cdr! 32 :/ 37 :setc 63 :tapply 72 :lvargc 77 :cons 27 :loada1 79 :tcall.l 83 dummy_nil 94 :equal? 14 :cdr 30 :call 3 :eqv? 13 := 39 :setg.l 60 :list 28 :atom? 15 :aref 43 :load0 48 :let 70 dummy_t 92 :argc 66 :brne.l 85 :< 40 :null? 17 :loadg 53 :load1 49 :car 29 :brt.l 10 :vargc 67 :loada 55 :set-car! 31 :setg 59 :aset! 44 :loadc01 81 :bound? 21 :optargs 91 :pair? 22 :symbol? 19 :brn 89 :fixnum? 25 :loadi8 50 :not 16 :* 36 :neg 75 :pop 2 :largc 76 :loadnil 47 :brf 6 :vector 42 :- 35 :loadv 51 :loada.l 56 :seta.l 62 :closure 65 :loadc00 80 :number? 2
\ No newline at end of file
+(*banner* "; _\n; |_ _ _ |_ _ | . _ _\n; | (-||||_(_)|__|_)|_)\n;-------------------|----------------------------------------------------------\n\n" *syntax-environment* #table(assert #function("<000r1c0~]c1c2c3~L2L2L2L4;" [if raise quote assert-failed]) letrec #function("?000s1e0e0c1L1e2c3~32L1e2c4~32e5\x7f3134L1e2c6~3242;" [nconc lambda map #.car #function("9000r1e0c1L1e2~3142;" [nconc set! copy-list]) copy-list #function("6000r1^;" [])]) backquote #function("7000r1e0~41;" [bq-process]) label #function(":000r2c0~L1c1~\x7fL3L3^L2;" [lambda set!]) do #function("A000s2c0e130\x7fMe2c3~32e2e4~32e2c5~32u46;" [#function("B000vc0~c1g2c2\x7fe3c4L1e5\x81N3132e3c4L1e5i0231e3~L1g432L133L4L3L2L1e3~L1g332L3;" [letrec lambda if nconc begin copy-list]) gensym map #.car cadr #function("7000r1e0~31F680e1~41;~M;" [cddr caddr])]) when #function("<000s1c0~c1\x7fK^L4;" [if begin]) unwind-protect #function("9000r2c0e130e130u43;" [#function("@000vc0\x7fc1_\x81L3L2L1c2c3\x80c1~L1c4\x7fL1c5~L2L3L3L3\x7fL1L3L3;" [let lambda prog1 trycatch begin raise]) gensym]) dotimes #function("<000s1c0~M~\x86u43;" [#function("=000vc0`c1\x7faL3e2c3L1~L1L1e4\x813133L4;" [for - nconc lambda copy-list])]) define-macro #function("?000s1c0c1~ML2e2c3L1~NL1e4\x7f3133L3;" [set-syntax! quote nconc lambda copy-list]) receive #function("@000s2c0c1_\x7fL3e2c1L1~L1e3g23133L3;" [call-with-values lambda nconc copy-list]) unless #function("=000s1c0~^c1\x7fKL4;" [if begin]) let #function(";000s1c0^u42;" [#function("<000v\x80C6D0\x80m02\x81Mo002\x81No01530^2c0e1c2L1e3c4\x8032L1e5\x813133e3c6\x8032u43;" [#function("8000v\x806;0c0\x80~L3530~\x7fK;" [label]) nconc lambda map #function("6000r1~F650~M;~;" []) copy-list #function("6000r1~F650~\x86;^;" [])])]) cond #function(":000s0c0^u42;" [#function("7000vc0qm02~\x8041;" [#function("8000r1~?640^;c0~Mu42;" [#function(";000v~Mc0<17702~M]<6@0~N\x8750~M;c1~NK;~N\x87@0c2~Mi10\x80N31L3;c3~Mc1~NKi10\x80N31L4;" [else begin or if])] cond-clauses->if)])]) throw #function(":000r2c0c1c2c3L2~\x7fL4L2;" [raise list quote thrown-value]) time #function("8000r1c0e130u42;" [#function(">000vc0~c1L1L2L1c2\x80c3c4c5c1L1~L3c6L4L3L3;" [let time.now prog1 princ "Elapsed time: " - " seconds\n"]) gensym]) let* #function("A000s1~?6E0e0c1L1_L1e2\x7f3133L1;e0c1L1e3~31L1L1e2~NF6H0e0c4L1~NL1e2\x7f3133L1530\x7f3133e5~31L2;" [nconc lambda copy-list caar let* cadar]) case #function(";000s1c0^u42;" [#function("8000vc0m02c1e230u42;" [#function(";000r2\x7fc0\x8450c0;\x7f\x8740^;\x7fC6=0c1~e2\x7f31L3;\x7f?6=0c3~e2\x7f31L3;\x7fN\x87>0c3~e2\x7fM31L3;e4c5\x7f326=0c6~c7\x7fL2L3;c8~c7\x7fL2L3;" [else eq? quote-value eqv? every #.symbol? memq quote memv] vals->cond) #function("<000vc0~i10L2L1e1c2L1e3c4qi113232L3;" [let nconc cond map #function("8000r1i10\x80~M32~NK;" [])]) gensym])]) catch #function("8000r2c0e130u42;" [#function("@000vc0\x81c1~L1c2c3c4~L2c5c6~L2c7c8L2L3c5c9~L2\x80L3L4c:~L2c;~L2L4L3L3;" [trycatch lambda if and pair? eq car quote thrown-value cadr caddr raise]) gensym])) *whitespace* "\t\n\v\f\r \u0085 \u2028\u2029 " /= #function("7000r2~\x7fW@;" [] /=) 1+ #function("7000r1~ay;" [] 1+) 1- #function("7000r1~az;" [] 1-) 1arg-lambda? #function("8000r1~F16T02~Mc0<16J02~NF16B02~\x86F16:02e1~\x86a42;" [lambda length=] 1arg-lambda?) <= #function("7000r2~\x7fX17602~\x7fW;" [] <=) > #function("7000r2\x7f~X;" [] >) >= #function("7000r2\x7f~X17602~\x7fW;" [] >=) Instructions #table(not 16 vargc 67 load1 49 = 39 setc.l 64 sub2 74 brne.l 85 largc 76 brnn 87 loadc.l 58 loadi8 50 < 40 nop 0 set-cdr! 32 loada 55 bound? 21 / 37 neg 75 brn.l 90 lvargc 77 brt 7 trycatch 68 null? 17 load0 48 jmp.l 8 loadv 51 seta 61 * 36 function? 26 builtin? 23 aref 43 optargs 91 vector? 24 loadt 45 brf 6 symbol? 19 cdr 30 for 71 loadc00 80 pop 2 pair? 22 cadr 86 closure 65 loadf 46 compare 41 loadv.l 52 setg.l 60 brn 89 eqv? 13 aset! 44 eq? 12 atom? 15 boolean? 18 brt.l 10 tapply 72 dummy_nil 95 loada0 78 brbound 92 list 28 dup 1 apply 33 loadc 57 loadc01 81 dummy_t
\ No newline at end of file
--- a/femtolisp/flisp.c
+++ b/femtolisp/flisp.c
@@ -237,13 +237,14 @@
sym = (symbol_t*)malloc(sizeof(symbol_t)-sizeof(void*) + len + 1);
assert(((uptrint_t)sym & 0x7) == 0); // make sure malloc aligns 8
sym->left = sym->right = NULL;
+ sym->flags = 0;
if (fl_is_keyword_name(str, len)) {
value_t s = tagptr(sym, TAG_SYM);
setc(s, s);
+ sym->flags |= 0x2;
}
else {
sym->binding = UNBOUND;
- sym->isconst = 0;
}
sym->type = sym->dlcache = NULL;
sym->hash = memhash32(str, len)^0xAAAAAAAA;
@@ -932,29 +933,42 @@
curr_frame = SP;
NEXT_OP;
OP(OP_OPTARGS)
+ i = GET_INT32(ip); ip+=4;
n = GET_INT32(ip); ip+=4;
- v = fn_vals(Stack[bp-1]);
- v = vector_elt(v, 0);
- if (nargs >= n) { // if we have all required args
- s = vector_size(v);
- n += s;
- if (nargs < n) { // but not all optional args
- i = n - nargs;
- SP += i;
- Stack[SP-1] = Stack[SP-i-1];
- Stack[SP-2] = Stack[SP-i-2];
- Stack[SP-3] = Stack[SP-i-3];
- Stack[SP-4] = Stack[SP-i-4];
- Stack[SP-5] = Stack[SP-i-5];
- curr_frame = SP;
- s = s - i;
- for(n=0; n < i; n++) {
- Stack[bp+nargs+n] = vector_elt(v, s+n);
- }
- nargs += i;
+ if ((int32_t)i < 0) {
+ if (nargs < -i)
+ lerror(ArgError, "apply: too few arguments");
+ }
+ else if (nargs < i) {
+ lerror(ArgError, "apply: too few arguments");
+ }
+ else if (nargs > n) {
+ lerror(ArgError, "apply: too many arguments");
+ }
+ if (n > nargs) {
+ n -= nargs;
+ SP += n;
+ Stack[SP-1] = Stack[SP-n-1];
+ Stack[SP-2] = Stack[SP-n-2];
+ Stack[SP-3] = nargs+n;
+ Stack[SP-4] = Stack[SP-n-4];
+ Stack[SP-5] = Stack[SP-n-5];
+ curr_frame = SP;
+ for(i=0; i < n; i++) {
+ Stack[bp+nargs+i] = UNBOUND;
}
+ nargs += n;
}
NEXT_OP;
+ OP(OP_BRBOUND)
+ i = GET_INT32(ip); ip+=4;
+ if (captured)
+ v = vector_elt(Stack[bp], i);
+ else
+ v = Stack[bp+i];
+ if (v != UNBOUND) ip += (ptrint_t)GET_INT32(ip);
+ else ip += 4;
+ NEXT_OP;
OP(OP_NOP) NEXT_OP;
OP(OP_DUP) SP++; Stack[SP-1] = Stack[SP-2]; NEXT_OP;
OP(OP_POP) POPN(1); NEXT_OP;
@@ -1525,7 +1539,7 @@
assert(issymbol(v));
sym = (symbol_t*)ptr(v);
v = Stack[SP-1];
- if (!sym->isconst)
+ if (!isconstant(sym))
sym->binding = v;
NEXT_OP;
@@ -1686,11 +1700,11 @@
#endif
}
-static uint32_t compute_maxstack(uint8_t *code, size_t len, value_t vals)
+static uint32_t compute_maxstack(uint8_t *code, size_t len)
{
uint8_t *ip = code+4, *end = code+len;
uint8_t op;
- uint32_t n, sp = 0, maxsp = 0;
+ uint32_t i, n, sp = 0, maxsp = 0;
while (1) {
if ((int32_t)sp > (int32_t)maxsp) maxsp = sp;
@@ -1713,11 +1727,13 @@
break;
case OP_LET: break;
case OP_OPTARGS:
- ip += 4;
- assert(isvector(vals));
- if (vector_size(vals) > 0)
- sp += vector_size(vector_elt(vals, 0));
+ i = abs(GET_INT32(ip)); ip+=4;
+ n = GET_INT32(ip); ip+=4;
+ sp += (n-i);
break;
+ case OP_BRBOUND:
+ ip+=8;
+ break;
case OP_TCALL: case OP_CALL:
n = *ip++; // nargs
@@ -1848,13 +1864,13 @@
cvalue_t *arr = (cvalue_t*)ptr(args[0]);
cv_pin(arr);
char *data = cv_data(arr);
- if (data[4] >= N_OPCODES) {
+ if ((uint8_t)data[4] >= N_OPCODES) {
// read syntax, shifted 48 for compact text representation
size_t i, sz = cv_len(arr);
for(i=0; i < sz; i++)
data[i] -= 48;
}
- uint32_t ms = compute_maxstack((uint8_t*)data, cv_len(arr), args[1]);
+ uint32_t ms = compute_maxstack((uint8_t*)data, cv_len(arr));
PUT_INT32(data, ms);
function_t *fn = (function_t*)alloc_words(4);
value_t fv = tagptr(fn, TAG_FUNCTION);
--- a/femtolisp/flisp.h
+++ b/femtolisp/flisp.h
@@ -15,7 +15,7 @@
} cons_t;
typedef struct _symbol_t {
- value_t isconst;
+ uptrint_t flags;
value_t binding; // global value binding
struct _fltype_t *type;
uint32_t hash;
@@ -87,9 +87,10 @@
#define fn_name(f) (((value_t*)ptr(f))[3])
#define set(s, v) (((symbol_t*)ptr(s))->binding = (v))
-#define setc(s, v) do { ((symbol_t*)ptr(s))->isconst = 1; \
+#define setc(s, v) do { ((symbol_t*)ptr(s))->flags |= 1; \
((symbol_t*)ptr(s))->binding = (v); } while (0)
-#define isconstant(s) (((symbol_t*)ptr(s))->isconst)
+#define isconstant(s) ((s)->flags&0x1)
+#define iskeyword(s) ((s)->flags&0x2)
#define symbol_value(s) (((symbol_t*)ptr(s))->binding)
#define ismanaged(v) ((((unsigned char*)ptr(v)) >= fromspace) && \
(((unsigned char*)ptr(v)) < fromspace+heapsize))
--- a/femtolisp/opcodes.h
+++ b/femtolisp/opcodes.h
@@ -27,7 +27,7 @@
OP_TAPPLY, OP_ADD2, OP_SUB2, OP_NEG, OP_LARGC, OP_LVARGC,
OP_LOADA0, OP_LOADA1, OP_LOADC00, OP_LOADC01, OP_CALLL, OP_TCALLL,
OP_BRNE, OP_BRNEL, OP_CADR, OP_BRNN, OP_BRNNL, OP_BRN, OP_BRNL,
- OP_OPTARGS,
+ OP_OPTARGS, OP_BRBOUND,
OP_BOOL_CONST_T, OP_BOOL_CONST_F, OP_THE_EMPTY_LIST,
@@ -70,7 +70,8 @@
&&L_OP_LVARGC, \
&&L_OP_LOADA0, &&L_OP_LOADA1, &&L_OP_LOADC00, &&L_OP_LOADC01, \
&&L_OP_CALLL, &&L_OP_TCALLL, &&L_OP_BRNE, &&L_OP_BRNEL, &&L_OP_CADR,\
- &&L_OP_BRNN, &&L_OP_BRNNL, &&L_OP_BRN, &&L_OP_BRNL, &&L_OP_OPTARGS \
+ &&L_OP_BRNN, &&L_OP_BRNNL, &&L_OP_BRN, &&L_OP_BRNL, \
+ &&L_OP_OPTARGS, &&L_OP_BRBOUND \
}
#define VM_APPLY_LABELS \
--- a/femtolisp/print.c
+++ b/femtolisp/print.c
@@ -424,7 +424,7 @@
break;
case TAG_CVALUE:
case TAG_CPRIM:
- if (v == UNBOUND) { outs("#<undefined>", f); break; }
+ if (v == UNBOUND) { outs("#<undefined>", f); break; }
case TAG_VECTOR:
case TAG_CONS:
if (print_circle_prefix(f, v)) return;
--- a/femtolisp/test.lsp
+++ b/femtolisp/test.lsp
@@ -280,3 +280,17 @@
lastcdr to-proper reverse reverse! list->vector
table.foreach list-head list-tail assq memq assoc member
assv memv nreconc bq-process))
+
+(define (filt1 pred lst)
+ (define (filt1- pred lst accum)
+ (if (null? lst) accum
+ (if (pred (car lst))
+ (filt1- pred (cdr lst) (cons (car lst) accum))
+ (filt1- pred (cdr lst) accum))))
+ (filt1- pred lst ()))
+
+(define (filto pred lst (accum ()))
+ (if (atom? lst) accum
+ (if (pred (car lst))
+ (filto pred (cdr lst) (cons (car lst) accum))
+ (filto pred (cdr lst) accum))))
--- a/femtolisp/todo
+++ b/femtolisp/todo
@@ -1128,3 +1128,25 @@
uint32_t SP;
uint32_t curr_frame;
} stackseg_t;
+
+-----------------------------------------------------------------------------
+
+optional and keyword args:
+
+check nargs >= #required
+grow frame by ntotal-nargs ; ntotal = #req+#opt+#kw
+(sort keyword args into their places)
+branch if arg bound around initializer for each opt arg
+
+example: (lambda (a (b 0) (c b)))
+
+minargs 1
+framesize 3
+brbound 1 L1
+load0
+seta 0
+L1:
+brbound 2 L2
+loada 1
+seta 2
+L2: