adding support for optional arguments
error checking formal argument lists making filter preserve the order of elements in the input list
This commit is contained in:
parent
c61dc10002
commit
eceeddf6d2
File diff suppressed because it is too large
Load Diff
|
@ -26,6 +26,7 @@
|
|||
:add2 :sub2 :neg :largc :lvargc
|
||||
:loada0 :loada1 :loadc00 :loadc01 :call.l :tcall.l
|
||||
:brne :brne.l :cadr :brnn :brnn.l :brn :brn.l
|
||||
:optargs
|
||||
|
||||
dummy_t dummy_f dummy_nil]))
|
||||
(for 0 (1- (length keys))
|
||||
|
@ -171,7 +172,7 @@
|
|||
((number? nxt)
|
||||
(case vi
|
||||
((:loadv.l :loadg.l :setg.l :loada.l :seta.l
|
||||
:largc :lvargc :call.l :tcall.l)
|
||||
:largc :lvargc :call.l :tcall.l :optargs)
|
||||
(io.write bcode (int32 nxt))
|
||||
(set! i (+ i 1)))
|
||||
|
||||
|
@ -346,6 +347,7 @@
|
|||
(if (and (pair? head)
|
||||
(eq? (car head) 'lambda)
|
||||
(list? (cadr head))
|
||||
(every symbol? (cadr head))
|
||||
(not (length> (cadr head) 255)))
|
||||
(compile-let g env tail? x)
|
||||
(compile-call g env tail? x))))
|
||||
|
@ -505,6 +507,28 @@
|
|||
(else ())))))
|
||||
(lambda (expr) (delete-duplicates (get-defined-vars- expr)))))
|
||||
|
||||
(define (lambda-vars l)
|
||||
(define (check-formals l o)
|
||||
(or
|
||||
(null? l) (symbol? l)
|
||||
(and
|
||||
(pair? l)
|
||||
(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)))
|
||||
(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)))))
|
||||
(check-formals l l)
|
||||
(map (lambda (s) (if (pair? s) (car s) s))
|
||||
(to-proper l)))
|
||||
|
||||
(define compile-f-
|
||||
(let ((*defines-processed-token* (gensym)))
|
||||
; to eval a top-level expression we need to avoid internal define
|
||||
|
@ -529,23 +553,34 @@
|
|||
|
||||
(let ((g (make-code-emitter))
|
||||
(args (cadr f))
|
||||
(vars (lambda-vars (cadr f)))
|
||||
(opta (filter pair? (cadr f)))
|
||||
(name (if (eq? (lastcdr f) *defines-processed-token*)
|
||||
'lambda
|
||||
(lastcdr f))))
|
||||
(cond ((not (null? let?)) (emit g :let))
|
||||
((length> args 255) (emit g (if (null? (lastcdr args))
|
||||
:largc :lvargc)
|
||||
(length args)))
|
||||
((null? (lastcdr args)) (emit g :argc (length args)))
|
||||
(else (emit g :vargc (if (atom? args) 0 (length args)))))
|
||||
(compile-in g (cons (to-proper args) env) #t
|
||||
(if (eq? (lastcdr f) *defines-processed-token*)
|
||||
(caddr f)
|
||||
(lambda-body f)))
|
||||
(emit g :ret)
|
||||
(values (function (encode-byte-code (bcode:code g))
|
||||
(const-to-idx-vec g) name)
|
||||
(aref g 3))))))
|
||||
(let ((nargs (if (atom? args) 0 (length args))))
|
||||
|
||||
; emit argument checking prologue
|
||||
(if (not (null? opta))
|
||||
(begin (bcode:indexfor g (list->vector (map cadr opta)))
|
||||
(emit g :optargs (- nargs (length opta)))))
|
||||
|
||||
(cond ((not (null? let?)) (emit g :let))
|
||||
((> nargs 255) (emit g (if (null? (lastcdr args))
|
||||
:largc :lvargc)
|
||||
nargs))
|
||||
((null? (lastcdr args)) (emit g :argc nargs))
|
||||
(else (emit g :vargc 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)
|
||||
(values (function (encode-byte-code (bcode:code g))
|
||||
(const-to-idx-vec g) name)
|
||||
(aref g 3)))))))
|
||||
|
||||
(define (compile f) (compile-f () f))
|
||||
|
||||
|
@ -604,7 +639,7 @@
|
|||
(princ (number->string (aref code i)))
|
||||
(set! i (+ i 1)))
|
||||
|
||||
((:loada.l :seta.l :largc :lvargc :call.l :tcall.l)
|
||||
((:loada.l :seta.l :largc :lvargc :call.l :tcall.l :optargs)
|
||||
(princ (number->string (ref-int32-LE code i)))
|
||||
(set! i (+ i 4)))
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -931,6 +931,30 @@ static value_t apply_cl(uint32_t nargs)
|
|||
Stack[SP-1] = 0;
|
||||
curr_frame = SP;
|
||||
NEXT_OP;
|
||||
OP(OP_OPTARGS)
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
@ -1662,7 +1686,7 @@ static value_t apply_cl(uint32_t nargs)
|
|||
#endif
|
||||
}
|
||||
|
||||
static uint32_t compute_maxstack(uint8_t *code, size_t len)
|
||||
static uint32_t compute_maxstack(uint8_t *code, size_t len, value_t vals)
|
||||
{
|
||||
uint8_t *ip = code+4, *end = code+len;
|
||||
uint8_t op;
|
||||
|
@ -1688,6 +1712,12 @@ static uint32_t compute_maxstack(uint8_t *code, size_t len)
|
|||
sp += (n+2);
|
||||
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));
|
||||
break;
|
||||
|
||||
case OP_TCALL: case OP_CALL:
|
||||
n = *ip++; // nargs
|
||||
|
@ -1824,7 +1854,7 @@ static value_t fl_function(value_t *args, uint32_t nargs)
|
|||
for(i=0; i < sz; i++)
|
||||
data[i] -= 48;
|
||||
}
|
||||
uint32_t ms = compute_maxstack((uint8_t*)data, cv_len(arr));
|
||||
uint32_t ms = compute_maxstack((uint8_t*)data, cv_len(arr), args[1]);
|
||||
PUT_INT32(data, ms);
|
||||
function_t *fn = (function_t*)alloc_words(4);
|
||||
value_t fv = tagptr(fn, TAG_FUNCTION);
|
||||
|
|
|
@ -27,6 +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_BOOL_CONST_T, OP_BOOL_CONST_F, OP_THE_EMPTY_LIST,
|
||||
|
||||
|
@ -69,7 +70,7 @@ 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_BRNN, &&L_OP_BRNNL, &&L_OP_BRN, &&L_OP_BRNL, &&L_OP_OPTARGS \
|
||||
}
|
||||
|
||||
#define VM_APPLY_LABELS \
|
||||
|
|
|
@ -224,15 +224,16 @@
|
|||
(set-car! lst (f (car lst)))
|
||||
(set! lst (cdr lst)))))
|
||||
|
||||
(define filter
|
||||
(letrec ((filter-
|
||||
(lambda (pred lst accum)
|
||||
(cond ((null? lst) accum)
|
||||
((pred (car lst))
|
||||
(filter- pred (cdr lst) (cons (car lst) accum)))
|
||||
(#t
|
||||
(filter- pred (cdr lst) accum))))))
|
||||
(lambda (pred lst) (filter- pred lst ()))))
|
||||
(define (filter pred lst)
|
||||
(define (filter- f lst acc)
|
||||
(cdr
|
||||
(prog1 acc
|
||||
(while (pair? lst)
|
||||
(begin (if (pred (car lst))
|
||||
(set! acc
|
||||
(cdr (set-cdr! acc (cons (car lst) ())))))
|
||||
(set! lst (cdr lst)))))))
|
||||
(filter- pred lst (list ())))
|
||||
|
||||
(define separate
|
||||
(letrec ((separate-
|
||||
|
|
|
@ -159,7 +159,7 @@ bugs:
|
|||
. write a function to evaluate directly from list to list, use it for
|
||||
Nth arg and for user function rest args
|
||||
. modify vararg builtins accordingly
|
||||
- filter should be stable. right now it reverses.
|
||||
* filter should be stable. right now it reverses.
|
||||
|
||||
|
||||
femtoLisp3...with symbolic C interface
|
||||
|
@ -975,7 +975,8 @@ consolidated todo list as of 7/8:
|
|||
- remaining c types
|
||||
- remaining cvalues functions
|
||||
- finish ios
|
||||
- optional and keyword arguments
|
||||
* optional arguments
|
||||
- keyword arguments
|
||||
- some kind of record, struct, or object system
|
||||
|
||||
- special efficient reader for #array
|
||||
|
@ -1042,6 +1043,8 @@ new evaluator todo:
|
|||
* try removing MAX_ARGS trickery
|
||||
- apply optimization, avoid redundant list copying calling vararg fns
|
||||
- let eversion
|
||||
- variable analysis - avoid holding references to values in frames
|
||||
captured by closures but not used inside them
|
||||
* lambda lifting
|
||||
* let optimization
|
||||
* fix equal? on functions
|
||||
|
|
|
@ -116,6 +116,14 @@
|
|||
(assert (equal? (apply f (iota 995)) '(994)))
|
||||
(assert (equal? (apply f (iota 1000)) '(994 995 996 997 998 999)))
|
||||
|
||||
; optional arguments
|
||||
(assert (equal? ((lambda ((b 0)) b)) 0))
|
||||
(assert (equal? ((lambda (a (b 2)) (list a b)) 1) '(1 2)))
|
||||
(assert (equal? ((lambda (a (b 2)) (list a b)) 1 3) '(1 3)))
|
||||
(assert (equal? ((lambda (a (b 2) (c 3)) (list a b c)) 1) '(1 2 3)))
|
||||
(assert (equal? ((lambda (a (b 2) (c 3)) (list a b c)) 1 8) '(1 8 3)))
|
||||
(assert (equal? ((lambda (a (b 2) (c 3)) (list a b c)) 1 8 9) '(1 8 9)))
|
||||
|
||||
; ok, a couple end-to-end tests as well
|
||||
(define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
|
||||
(assert (equal? (fib 20) 6765))
|
||||
|
|
Loading…
Reference in New Issue