summaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
* eval: remove hack of macro deffers evaled on expansion.Kaz Kylheku2018-03-255-24/+28
| | | | | | | | | | | | | | | | | | * eval.c (do_expand): When a defmacro or defsymacro form is traversed, do not evaluate it, except in backward compatibility mode. Unfortunately, this breaks some code. * tests/011/macros-1.txr: A defmacro form has to be wrapped in macro-time. * tests/011/macros-2.txr: Likewise. * tests/011/mandel.txr: Likewise. * tests/012/man-or-boy.tl (defun-cbn): This macro generates a progn which which expects that a defmacro form will come into effect for the subsequent lambda in the same form. We must wrap it in macro-time to make this happen now.
* compiler: implement defun special op.Kaz Kylheku2018-03-251-0/+20
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle defun via expand-defun expander. (expand-defun): New function.
* eval/compiler: run-time support for compiled defun.Kaz Kylheku2018-03-251-8/+18
| | | | | | | * eval.c (rt_defun, rt_defmacro): New static functions. (op_defun): Use static functions. (eval_init): Register sys:rt-defun and sys:rt-defmacro intrinsics.
* compiler: implement defvarl special op.Kaz Kylheku2018-03-251-0/+9
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle defvarl via expand-defvarl expander. (expand-defvarl): New function.
* eval/compiler: run-time support for compact defvarl.Kaz Kylheku2018-03-251-5/+20
| | | | | | * eval.c (rt_defvarl): New static function. (op_defvarl): Simplified using rt_defvarl. (eval_init): Register sys:rt-defvarl.
* compiler: implement sys:setqf special op.Kaz Kylheku2018-03-241-0/+17
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle sys:setqf via comp-setqf. (compiler comp-setqf): New method.
* compiler: setq bug: wrong return for globals.Kaz Kylheku2018-03-251-2/+2
| | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-setq): The output register of the returned frag must be that of the value calculating frag, not vloc, because in the dynamic variable case, vloc holds the d-reg with the variable's name, not the v-reg that receives its value. (compiler compl-lisp1-setq): Fix same bug which got propagated by copy-and-paste coding.
* compiler: implement sys:lisp1-setq special op.Kaz Kylheku2018-03-241-0/+17
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle sys:lisp1-setq via comp-lisp1-setq. (compiler comp-lisp1-setq): New method.
* compiler: implement dwim special op.Kaz Kylheku2018-03-241-0/+7
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle dwim case via comp-dwim. (compiler comp-dwim): New method.
* compiler: implement sys:lisp1-value special formKaz Kylheku2018-03-241-3/+31
| | | | | | | | | | | | * share/txr/stdlib/compiler.tl (vbinding, fbinding): New structs subtyping binding. (sys:env lookup-lisp1): New method. (sys:env extend-var, sys:env extend-var*, sys:env extend-fun): Instantiate a vbinding or fbinding as appropriate. This lets us tell whether we have a function or variable binding after doing a successful lookup-lisp1. (compiler compile): Add sys:lisp1-value case. (compiler comp-lisp1-value): New method.
* compiler: specially compile (call ...) forms.Kaz Kylheku2018-03-241-1/+13
| | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-fun-form): Add a caseq form to handle certain top-level functions specially. Add a case for the call function, handled by comp-call. (compiler comp-call): New method.
* compiler: rename comp-call.Kaz Kylheku2018-03-241-2/+2
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Call comp-fun-form instead of comp-call. (compiler comp-call): Rename to comp-fun-form.
* compiler: implement fun special formKaz Kylheku2018-03-241-0/+8
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Route fun to comp-fun. (compiler comp-fun): New method.
* compiler: add fbind and lbind special formsKaz Kylheku2018-03-241-0/+32
| | | | | | | | This supports labels and flet. * share/txr/stdlib/compiler.tl (compiler compile): Route fbind and lbind to comp-fbind method. (compiler comp-fbind): New method.
* compiler: fix wrong frame level in lexical functions.Kaz Kylheku2018-03-241-1/+1
| | | | | | * share/txr/stdlib/compiler.tl (sys:env extend-fun): The v register's level is two less than the frame level. Add missing ppred call; extend-var has it already.
* compiler: fix lexical function call.Kaz Kylheku2018-03-241-2/+2
| | | | | * share/txr/stdlib/compiler.tl (compiler comp-call): Pass the location, not the binding itself, to comp-call-impl.
* compiler: implement unwind-protect.Kaz Kylheku2018-03-241-0/+25
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Wire in unwind-protect case via comp-unwind-protect method. (compiler comp-unwind-protect): New method.
* compiler: implement mac-param-bind.Kaz Kylheku2018-03-241-0/+12
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Wire in tree-bind case via comp-mac-param-bind method. (compiler comp-mac-param-bind): New method.
* compiler: hoist quoting out of bind expander.Kaz Kylheku2018-03-231-8/+12
| | | | | | | | | | | * share/txr/stdlib/compiler.tl (expand-bind-mac-params): Take the context form and error forms as separate arguments instead of calculating one from the other. Moreover, they are no longer assumed to be objects to be quoted and inserted but rather expressions to be substituted into the code directly. This gives the caller flexibility to make them calculated. (compiler comp-tree-bind, compiler comp-tree-case): Make the compensating adjustments to preserve the behavior.
* asm: report instruction count in disassembly.Kaz Kylheku2018-03-231-2/+7
| | | | | | * share/txr/stdlib/asm.tl (assembler dis-listing): Return the number of instructions that were traversed. (disassemble-c-d): Print count after instruction listing.
* tree-bind et al: don't retain full form for errors.Kaz Kylheku2018-03-231-2/+3
| | | | | | | | | * share/txr/stdlib/compiler.tl (expand-bind-mac-params): We don't need the full form for error reporting, because only the leading symbol is reported in diagnostics. We do need the full form if the :form parameter is used. If :form is not used, then a compiled function need not carry the entire form in its data table.
* compiler: avoid using var symbol.Kaz Kylheku2018-03-231-5/+5
| | | | | | | | | var is sys:var when we're working in the system package. This sometimes confuses the code walker, because (sys:var X) is the implementation of the @X notation. * share/txr/stdlib/compiler.tl (expand-bind-mac-params): Use sym instead of var.
* compiler: auto-load sys:bind-mac-error.Kaz Kylheku2018-03-231-1/+1
| | | | | | | This is run-time support needed by compiled tree-bind code. * lisplib.c (compiler_set_entries): Add bind-mac-error to sys package auto-load list.
* compiler: constant-optimize prog1Kaz Kylheku2018-03-231-1/+2
| | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-prog1): prog1 already uses progn. When using progn, though, it should append the nil form to the tail, otherwise progn will spare the last from from being eliminated, leaving an unused constant in the data table.
* compiler: basic optimization in progn.Kaz Kylheku2018-03-231-2/+6
| | | | | | * share/txr/stdlib/compiler.tl (compiler comp-progn): Eliminate any form which is a constant or a symbol, unless it appears in the last position.
* compiler: optimizations in cond and if.Kaz Kylheku2018-03-231-34/+58
| | | | | | | | | | | | We optimize based on test being constant expressions. * share/txr/stdlib/compiler.tl (compiler comp-cond): Whenever a test is a constant null, we need not evaluate the forms in that case; the entire case basically disappears so we compile it to nil. We also need not consider any cases after the first case whose test is a constant true. (compiler comp-if): Optimize all situations when the test is constant.
* compiler: last cond case: don't jmp to end.Kaz Kylheku2018-03-231-5/+11
| | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-cond): Don't generate the jmp instruction at the end of the last case. Why do I bother; a simple peephole optimizer will eliminate these. I want a little better code, now! That's why.
* vm: change encoding of getv, setv and related.Kaz Kylheku2018-03-232-12/+12
| | | | | | | | | | | | | | | | | | | | | | | In most compiler uses of bindv, getv and setv, the operand which names the dynamic symbol is the data table: a d0-dff register. The source or destination register of the transfer could be anything. Therefore, the existing encoding is suboptimal: the symbol is being put into the full sized operand field of the instruction, and the source or destination register into the small, ten-bit extra field in the upper half. This breaks on cases like (set x y) where x is a deeply nested lexical variable and y is a dynamic variable. Let's reverse the encoding. * share/txr/stdlib/asm.tl (op-getv, op-setv): Reverse the operands. All derived opcodes follow this since they reuse the code via inheritance. * vm.c (vm_get_binding): Fetch the symbol from the small operand field rather than the main operand field. (vm_getsym, vm_getbind, vm_setsym, vm_bindv): Pull the destination or source from the main operand of the instruction rather than the small opreand.
* compiler: streamline tree-caseKaz Kylheku2018-03-231-20/+9
| | | | | | | | | | | | | | | | | | | | | | | | | The setting of an error variable upon destructuring mismatch is not useful; it just takes extra instructions to check for a colon return out of the body or that variable being set. Let's have expand-bind-mac-params generate code which returns that symbol itself of assigning to it. The caller can then specify : for the strict parameter. A destructuring mismatch turns into a : return value, exactly the same as the value which indicates "fall through to next case". * share/txr/stdlib/compiler.tl (compiler comp-tree-case): Don't generate the err-var; remove all references to it. Pass : to expand-bind-mac-params as the strict parameter, rather than err-var.sym. Generate much simplified code after the cfrag: just test for a colon and continue through to the next case or else branch to the end. In the last case, the fall through path precipiates to the end, so we insert an instruction to clobber the : in the return register with a nil. (expand-bind-mac-params): Eliminate assignments to strict; it doesn't function as a variable any longer. Return that symbol in the return-from forms.
* compiler: bug: dynamic var assignment.Kaz Kylheku2018-03-231-1/+1
| | | | | * share/txr/stdlib/compiler.tl (compiler comp-setq): Fix reversed setv instruction operands.
* compiler: implement tree-case.Kaz Kylheku2018-03-221-0/+52
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Add tree-case case, handled via comp-tree-case method. (compiler comp-tree-case): New method.
* compiler: implement tree-bind special op.Kaz Kylheku2018-03-221-0/+134
| | | | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Wire in tree-bind case via comp-tree-bind method. (compiler comp-tree-bind): New method. (expand-bind-mac-parse-params, expand-bind-mac-params): New functions.
* vm: initialize vd->funvec to nil.Kaz Kylheku2018-03-221-0/+1
| | | | | | | | * vm.c (vm_make_desc): Initialize vd->funvec to nil so that when the object is created, it doesn't have a garbage field. However, there is no risk here that the field will be traversed by the garbage collector, since immediately after allocating the objct, we initialize the fields.
* vm: bugfix: cannot access vec during gc.Kaz Kylheku2018-03-221-6/+8
| | | | | | | | | | | | | | Let's have a field in struct vm_desc that keeps track of the ftab size. The problem is when we do length_vec(vd->funvec) in vm_desc_mark, we are in the middle of garbage collection. The object's tag has a reachable bit which blows up the type check. * vm.c (struct vm_desc): New member, ftsz. (vm_make_desc): Store the length of the function table into ftsz. (vm_desc_mark): Use the stored length as the loop bound; do not access vd->funvec.
* gc bugs: incorrect struct init function assignments.Kaz Kylheku2018-03-221-2/+2
| | | | | | | | | | * struct.c (struct_set_initfun, struct_set_postinitfun): Replace incorrect direct assignments with set macro. This manifested itself as corruption. I ran into a situation in which the postinitfun of a struct type was prematurely reclaimed and the heap object was re-used for something else wreaking havoc on the postinit call when the struct was instantiated.
* compiler: implement return-from and return.Kaz Kylheku2018-03-221-0/+18
| | | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle return and return-from special forms. (compiler comp-return-from, compiler comp-return): New methods.
* vm: ret instructions: throw error if block not found.Kaz Kylheku2018-03-221-0/+14
| | | | | | * vm.c (vm_no_block_err): New static function. (vm_retsr, vm_retrs, vm_retrr): Call vm_no_block_err if uw_block_return returns.
* compiler: sys:setq bug: wrong way mov.Kaz Kylheku2018-03-221-1/+1
| | | | | * share/txr/stdlib/compiler.tl (compiler comp-setq): Fix reversed mov instruction arguments in lexical case.
* new special op sys:upenvKaz Kylheku2018-03-212-0/+10
| | | | | | | | | | | | | | | | | | | | | | | This is something that will be useful in compiling some forms. At first I added it to the compiler only, but it seems wise to have it in the interpreter also. (sys:upenv form) causes form to be treated as if it were not in the immediately surrounding lexical environment but its parent. Thus (let ((a 1)) (let ((a 2)) (list a (sys:upenv a)))) yields (2 1). This operator needs no special treatment in the expander; it is expanded as a function call. This is not 100% correct in the face of all conceivable use. For instance given (symacrolet ((a 1)) (let ((a 2)) (sys:upenv a))), we probably want sys:upenv to skip the inner environment at expansion time too so that a is replaced by 1. However, it is not documented for application use, and will never be used in such a situation in the compiler. * eval.c (op_upenv): New static function. (eval_init): Register sys:upenv special operator. * compiler.tl (compiler compile): Implement compiled version of sys:upenv.
* compiler: append-each: bugfix for non-lists.Kaz Kylheku2018-03-211-1/+1
| | | | | | | | | * share/txr/stdlib/compiler.tl: If a non-list sequence like a string or vector is being accumulated, we must have an append call, because the accumulation cell is never extended with new cells. After we replace the cdr of ,accum with a string or vector atom, (last ,accum) just finds ,accum and so then the cdr will be clobbered on the next iteration.
* compiler: let* bugfix: not extending env.Kaz Kylheku2018-03-211-2/+8
| | | | | | | | | | * share/txr/stdlib/compiler.tl (sys:env extend-var*): New method. (compiler comp-let): When doing sequential bindings, we must still add the variable to the environment even if there is no init-form. Oops! Since we're not doing any gensym renaming trick in this case but binding the real symbol directly, we need a binding method that allows duplicates.
* compiler: disallow duplicate symbols in same env.Kaz Kylheku2018-03-211-3/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We want to diagnose (let (a a)) and (lambda (a a)), as well as the analogous situations for function bindings. This is certainly ambiguous: if the code accesses a, which one was intended? The choice is undocumented and so this is a likely programming error; nobody will write code this deliberately, investigate what the implementation actually does, and then rely on that. However, multiple bindings of special variables are allowed. Duplicates are also allowed in sequential binding. Handling duplicates in let* binding creates the following problem: (a a) means that a should be initialized from the previous a. We would like to compile the init form in the environment in which the second a doesn't exist, yet indicate the destination location of the new a. Since we are clobbering one environment as we go by adding bindings to it, this is not possible. The solution is a rename hack: we introduce the new a as a gensym, so that it is invisible. We indicate the gensym's location as the destination register for the init-form code fragment. Then immediately after compiling the init-form, we rename the gensym variable. * share/txr/stdlib/compiler.tl (sys:env extend-var, sys:env extend-fun): Diagnose duplicates. (sys:env rename-var): New methods. * share/txr/stdlib/compiler.tl (compile comp-let): Bind to a gensym instead of the real symbol when binding sequentially. Then rename the symbol.
* compiler: handle sys:each-op special form.Kaz Kylheku2018-03-211-0/+21
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle sys:each-op with help of expand-each. (expand-each): New function.
* compiler: handle special forms and or.Kaz Kylheku2018-03-201-0/+27
| | | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle and and or cases via comp-and-or method. (compiler comp-and-or): New method. This is based on comp-progn.
* expander: bugfix: sys:for-op init forms.Kaz Kylheku2018-03-201-5/+8
| | | | | | | * eval.c (do_expand): The first argument of the sys:for-op special operator isn't "vars" but a sequence of initialization forms. Name the variable appropriately. The neglected expansion of these forms is now performed.
* compiler: handle dohash special formKaz Kylheku2018-03-201-0/+12
| | | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle dohash by rewriting the form via expand-dohash, then compiling result. (expand-dohash): New function.
* vm: funcall wrappers need to check arg count.Kaz Kylheku2018-03-201-0/+16
| | | | | | | | | | | | | | There is the possibility that funcall1 through funcall3 will pass the wrong number of arguments to vm_execute_closure, which doesn't do any checks. This is only for the code paths which don't go through generic_funcall, when the function has no optional arguments. * lib.c (funcall1, funcall2, funcall3, funcall4): Check that the closure doesn't require more fixed parameters than we're giving it in the variadic case, or that it doesn't require a different number of fixed parameters we're giving it in the non-variadic case.
* gc: tail recurse on env rather than code.Kaz Kylheku2018-03-201-4/+5
| | | | | | | * gc.c (mark_obj): When marking functions, tail recurse on the environment. That's the pointer more likely to be a gateway to serious depth, rather than the vm description or interpreted function's source.
* vm: allocate display in same object as closure.Kaz Kylheku2018-03-201-14/+9
| | | | | | | | | | * vm.c (struct vm_closure): Redeclare display member as array of 1: old-fashioned version of C struct hack. (vm_make_closure): Make the necessary adjustments to the allocation code. (vm_closure_destroy): Static function removed. (vm_closure_mark): Wire in cobj_destroy_free_op once again, since there is just one object to free.
* compiler: lambda bug: wrong reg in defaulting.Kaz Kylheku2018-03-201-1/+1
| | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-lambda): To determine whether the argument is missing, we must test it for equivalence to the : symbol. What we're testing here is the wrong thing: the register which will hold the output of the default initform. That fragment would even be executed yet at this spot in the code, never mind being the wrong value to test.