changing optional args to allow default values to be computed from
preceding arguments tidying some stuff with keywords
This commit is contained in:
		
							parent
							
								
									eceeddf6d2
								
							
						
					
					
						commit
						ecfd81148f
					
				| 
						 | 
				
			
			@ -135,8 +135,7 @@ static value_t fl_keywordp(value_t *args, u_int32_t nargs)
 | 
			
		|||
{
 | 
			
		||||
    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 @@ static value_t fl_set_top_level_value(value_t *args, u_int32_t nargs)
 | 
			
		|||
{
 | 
			
		||||
    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 @@ static value_t fl_constantp(value_t *args, u_int32_t nargs)
 | 
			
		|||
{
 | 
			
		||||
    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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,14 +277,14 @@
 | 
			
		|||
	 (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)
 | 
			
		||||
  (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,14 +430,14 @@
 | 
			
		|||
		     (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))
 | 
			
		||||
		  (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,41 +448,41 @@
 | 
			
		|||
(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)))
 | 
			
		||||
		     (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,31 +563,33 @@
 | 
			
		|||
      
 | 
			
		||||
      (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
 | 
			
		||||
		      (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)))
 | 
			
		||||
		 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -237,13 +237,14 @@ static symbol_t *mk_symbol(char *str)
 | 
			
		|||
    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,28 +933,41 @@ static value_t apply_cl(uint32_t nargs)
 | 
			
		|||
            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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1525,7 +1539,7 @@ static value_t apply_cl(uint32_t nargs)
 | 
			
		|||
            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 @@ static value_t apply_cl(uint32_t nargs)
 | 
			
		|||
#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,10 +1727,12 @@ static uint32_t compute_maxstack(uint8_t *code, size_t len, value_t vals)
 | 
			
		|||
            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:
 | 
			
		||||
| 
						 | 
				
			
			@ -1848,13 +1864,13 @@ static value_t fl_function(value_t *args, uint32_t nargs)
 | 
			
		|||
    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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ typedef struct {
 | 
			
		|||
} 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 @@ typedef struct _symbol_t {
 | 
			
		|||
#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))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ enum {
 | 
			
		|||
    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 @@ enum {
 | 
			
		|||
    &&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                                                 \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -424,7 +424,7 @@ void fl_print_child(ios_t *f, value_t v)
 | 
			
		|||
        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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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))))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1128,3 +1128,25 @@ typedef struct {
 | 
			
		|||
    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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue