From: Sam S. <sd...@gn...> - 2005-01-12 21:45:28
|
Hi Bruno, why isn't active_bit_o flag do its job in make_variable_frame and C_let? symbol_env_search appears to respect it! -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> Linux: Telling Microsoft where to go since 1991. |
From: Bruno H. <br...@cl...> - 2005-01-12 22:08:28
|
Sam wrote: > why isn't active_bit_o flag do its job in make_variable_frame and C_let? > symbol_env_search appears to respect it! The code is optimized for lexical bindings. I'm not looking at this now: contorted examples are low priority for me. If you want to tackle this long-standing bug, I suggest that you write an exhaustive test suite FIRST that covers - LET, LET* and LAMBDA, - the variable being declared special is bound / is not bound / the variable is bound without being declared special - compiled and interpreted THEN you can see what is wrong and what is correct and must not be changed. Bruno |
From: Sam S. <sd...@gn...> - 2005-01-12 23:13:22
|
> * Bruno Haible <oe...@py...t> [2005-01-12 23:05:36 +0100]: > > Sam wrote: >> why isn't active_bit_o flag do its job in make_variable_frame and C_let? >> symbol_env_search appears to respect it! > > The code is optimized for lexical bindings. but it appears that the code is supposed to support inactive dynamic bindings. so why isn't it working? -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> MS: our tomorrow's software will run on your tomorrow's HW at today's speed. |
From: Bruno H. <br...@cl...> - 2005-01-13 14:08:53
|
Sam wrote: > but it appears that the code is supposed to support inactive dynamic > bindings. so why isn't it working? The "why" and the "it" are not clear. You can not understand it just by looking at the code. (I couldn't either.) We're in the same situation as when Kaz and you started to modify the backquote macro: a complex piece of code, and in _some_ cases it doesn't work. The backquote macro you changed without having a test suite, and in the result several of the 16 possible doubly-nested-backquote combinations were broken. To avoid the same phenomenon this time with the bindings, I'd like you to have a test suite covering all the 24 combinations of - LET, LET*, LAMBDA, MULTIPLE-VALUE-BIND, - the variable being declared special is bound / is not bound / the variable is bound without being declared special - compiled and interpreted You need the test suite anyway, in order to check afterwards that all is fine. And in the beginning it will tell you _what_ is broken. Bruno |
From: Sam S. <sd...@gn...> - 2005-01-13 16:22:19
|
> * Bruno Haible <oe...@py...t> [2005-01-13 14:43:56 +0100]: > > To avoid the same phenomenon this time with the bindings, I'd like you > to have a test suite covering all the 24 combinations of > > - LET, LET*, LAMBDA, MULTIPLE-VALUE-BIND, > - the variable being declared special is bound / is not bound / the variable > is bound without being declared special > - compiled and interpreted > > You need the test suite anyway, in order to check afterwards that all is > fine. And in the beginning it will tell you _what_ is broken. $ ./clisp -K boot -q -norc -C -i tests/tests.lisp -x '(run-test "tests/bind" :eval-method :both)' ;; Loading file tests/tests.lisp ... 0 errors, 0 warnings ;; Loaded file tests/tests.lisp RUN-TEST: started #<INPUT BUFFERED FILE-STREAM CHARACTER #P"tests/bind.tst" @1> (DEFUN PRINT-COND (C) (FRESH-LINE) (PRINC C) (ELASTIC-NEWLINE)) EQL-OK: PRINT-COND (LET ((X 5)) (LET ((X (1+ X))) (DECLARE (SPECIAL X)) X)) EVAL: variable X has no value ERROR!! ERROR should be 6 ! (LET ((X 5)) (LET* ((X (1+ X))) (DECLARE (SPECIAL X)) X)) EVAL: variable X has no value ERROR!! ERROR should be 6 ! (LET ((X 5)) (MULTIPLE-VALUE-BIND (X) (1+ X) (DECLARE (SPECIAL X)) X)) EVAL: variable X has no value ERROR!! ERROR should be 6 ! (LET ((X 5)) ((LAMBDA (X) (DECLARE (SPECIAL X)) X) (1+ X))) EQL-OK: 6 (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINT-COND C) (RETURN-F ROM FOO 'GOOD)))) (LET ((X (1+ X))) (DECLARE (SPECIAL X)) X))) EVAL: variable X has no value NIL: symbol X has no value EQL-OK: GOOD (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINT-COND C) (RETURN-F ROM FOO 'GOOD)))) (LET* ((X (1+ X))) (DECLARE (SPECIAL X)) X))) EVAL: variable X has no value NIL: symbol X has no value EQL-OK: GOOD (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINT-COND C) (RETURN-F ROM FOO 'GOOD)))) (MULTIPLE-VALUE-BIND (X) (1+ X) (DECLARE (SPECIAL X)) X))) EVAL: variable X has no value NIL: symbol X has no value EQL-OK: GOOD (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINT-COND C) (RETURN-F ROM FOO 'GOOD)))) ((LAMBDA (X) (DECLARE (SPECIAL X)) X) (1+ X)))) EVAL: variable X has no value WARNING : X is neither declared nor bound, it will be treated as if it were declared SPECIAL.NIL: symbol X has no value EQL-OK: GOOD (LET ((X 5)) (LET ((X (1+ X))) X)) EQL-OK: 6 (LET ((X 5)) (LET* ((X (1+ X))) X)) EQL-OK: 6 (LET ((X 5)) (MULTIPLE-VALUE-BIND (X) (1+ X) X)) EQL-OK: 6 (LET ((X 5)) ((LAMBDA (X) X) (1+ X))) EQL-OK: 6 RUN-TEST: finished "tests/bind" (3 errors out of 13 tests) 13 ; 3 -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> I'd give my right arm to be ambidextrous. |
From: Bruno H. <br...@cl...> - 2005-01-13 18:28:55
|
Sam wrote: > (LET ((X 5)) (LET ((X (1+ X))) (DECLARE (SPECIAL X)) X)) > EVAL: variable X has no value > > ERROR!! ERROR should be 6 ! > (LET ((X 5)) (LET* ((X (1+ X))) (DECLARE (SPECIAL X)) X)) > EVAL: variable X has no value > > ERROR!! ERROR should be 6 ! > (LET ((X 5)) (MULTIPLE-VALUE-BIND (X) (1+ X) (DECLARE (SPECIAL X)) X)) > EVAL: variable X has no value > > ERROR!! ERROR should be 6 ! > (LET ((X 5)) ((LAMBDA (X) (DECLARE (SPECIAL X)) X) (1+ X))) > EQL-OK: 6 Good. So the bug is really only with SPECIAL bindings, and affects all of LET, LET*, MULTIPLE-VALUE-BIND, but not LAMBDA. Which means, the bug is in make_variable_frame, and the code which does it right is in funcall_iclosure. One more test case (after reading CLHS 3.3.4): (LET ((X 5)) (PROGV '(X) '(20) (LET* ((X (1+ X)) (Z (1+ X))) (DECLARE (SPECIAL X)) Z))) => 7 (LET ((X 5)) (PROGV '(X) '(20) (LET* ((Y (1+ X)) (Z (1+ X))) (DECLARE (SPECIAL X)) Z))) => 21 OK, now how to fix make_variable_frame? Bruno |
From: Sam S. <sd...@gn...> - 2005-01-13 20:17:42
|
> * Bruno Haible <oe...@py...t> [2005-01-13 19:25:52 +0100]: > > the bug is in make_variable_frame, and the code which does it right is > in funcall_iclosure. how come there are two functions doing almost the same?! -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> Beliefs divide, doubts unite. |
From: Bruno H. <br...@cl...> - 2005-01-13 20:41:03
|
Sam wrote: > > the bug is in make_variable_frame, and the code which does it right is > > in funcall_iclosure. > > how come there are two functions doing almost the same?! "Almost" the same?! funcall_iclosure handles the LAMBDA case with optional, rest, key and aux arguments and is therefore more complicated. make_variable_frame OTOH has to eval() the initforms in the right order, with the right parts of the binding list already active, and is therefore more complicated regarding the management of the var_env and of the active_bit. Bruno |
From: Sam S. <sd...@gn...> - 2005-01-18 17:04:29
|
> * Bruno Haible <oe...@py...t> [2005-01-13 19:25:52 +0100]: > > Which means, the bug is in make_variable_frame, and the code which > does it right is in funcall_iclosure. nope. funcall_iclosure() is called when the values of the bindings are already known (arguments are evaluated before the function is called) while make_variable_frame() is called _before_ the values are known and must create _inactive_ bindings, which it does not: control.d:make_variable_frame(): 460: pushSTACK_symbolwithflags(declsym,wbit(active_bit_o)); /* Symbol active */ why doesn't deactivation of the bindings: --- control.d 17 Jan 2005 22:24:12 -0500 1.117 +++ control.d 18 Jan 2005 11:55:42 -0500 @@ -560,9 +560,9 @@ if (specdecled || special_var_p(TheSymbol(symbol))) { /* bind dynamically */ #if (varframe_binding_mark == varframe_binding_sym) - STACK_(varframe_binding_mark) = as_object(as_oint(symbol) | wbit(dynam_bit_o)); + STACK_(varframe_binding_mark) = as_object((as_oint(symbol) | wbit(dynam_bit_o)) & ~wbit(active_bit_o)); #else - STACK_(varframe_binding_mark) = as_object(as_oint(Fixnum_0) | wbit(dynam_bit_o)); + STACK_(varframe_binding_mark) = as_object((as_oint(Fixnum_0) | wbit(dynam_bit_o)) & ~wbit(active_bit_o)); #endif } else { /* bind statically */ fix the problem? -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> The only intuitive interface is the nipple. The rest has to be learned. |
From: Bruno H. <br...@cl...> - 2005-01-18 19:08:50
|
I wrote: > One more test case (after reading CLHS 3.3.4): > > (LET ((X 5)) > (PROGV '(X) '(20) > (LET* ((X (1+ X)) (Z (1+ X))) (DECLARE (SPECIAL X)) Z))) => 7 > (LET ((X 5)) > (PROGV '(X) '(20) > (LET* ((Y (1+ X)) (Z (1+ X))) (DECLARE (SPECIAL X)) Z))) => 21 Oops, after reading CLHS 3.3.4 and SPECIAL once again, I think the second test case is wrong: the (SPECIAL X) is a _free_ declaration here, and therefore does not apply to the initforms of Y and Z. So (LET ((X 5)) (PROGV '(X) '(20) (LET* ((Y (1+ X)) (Z (1+ X))) (DECLARE (SPECIAL X)) Z))) => 6 ACL 6.2 gets it right, SBCL and CLISP have a bug here. Bruno |
From: Bruno H. <br...@cl...> - 2005-01-18 18:50:32
|
Sam wrote: > funcall_iclosure() is called when the values of the bindings are already > known (arguments are evaluated before the function is called) > while make_variable_frame() is called _before_ the values are known and > must create _inactive_ bindings, which it does not: Yes. I think you're on the right track. Recall the general work pattern of make_variable_frame: - A pre-pass to collect the SPECIAL declarations, - A loop through the binding list that for each variable, tests whether it is among the SPECIAL declared ones, and prepare the binding in the stack. Whereas the evaluation of the initforms happens later, in a caller's loop. Looking at these examples: (LET ((X 5)) (PROGV '(X) '(20) (LET* ((X (1+ X)) (Z (1+ X))) (DECLARE (SPECIAL X)) Z))) => 7 (LET ((X 5)) (PROGV '(X) '(20) (LET* ((Y (1+ X)) (Z (1+ X))) (DECLARE (SPECIAL X)) Z))) => 6 it is clear that - If X is bound but neither specdecled nor a globally special variable, the binding of X must be activated in the caller's loop, after its initform has been evaluated. - If X is bound and is specdecled or a globally special variable, the X <--> #<SPECDECL> binding must be activated in the loop, not before. - If X is not bound, just specdecled, the X <--> #<SPECDECL> binding must be activated after the loop. So I think > control.d:make_variable_frame(): > > 460: pushSTACK_symbolwithflags(declsym,wbit(active_bit_o)); /* Symbol active */ here the binding should not be made active. > why doesn't deactivation of the bindings: > > --- control.d 17 Jan 2005 22:24:12 -0500 1.117 > +++ control.d 18 Jan 2005 11:55:42 -0500 > @@ -560,9 +560,9 @@ > if (specdecled || special_var_p(TheSymbol(symbol))) { > /* bind dynamically */ > #if (varframe_binding_mark == varframe_binding_sym) > ... & ~wbit(active_bit_o)); > #endif > } else { > /* bind statically */ > > fix the problem? That's because (as_oint(symbol) | wbit(dynam_bit_o) has the active_bit_o bit set to 0, therefore masking it out has no effect. Also here you are operating on the part of the stack frame that corresponds to the bindinglist, and this part is correct. So 1) before the loop, collect the SPECDECL bindings but don't make them active, 2) outside make_variable_frame, in LET, LET*, MULTIPLE-VALUE-BIND, after the loop that evaluates the initforms but before the implicit_progn, add a small loop that activates the SPECDECL bindings. Bruno |
From: Sam S. <sd...@gn...> - 2005-01-19 00:15:46
|
> * Bruno Haible <oe...@py...t> [2005-01-18 19:46:59 +0100]: > > So 1) before the loop, collect the SPECDECL bindings but don't make them > active, > 2) outside make_variable_frame, in LET, LET*, MULTIPLE-VALUE-BIND, > after the loop that evaluates the initforms but before the > implicit_progn, add a small loop that activates the SPECDECL bindings. this won't fix compiled code... -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> When you are arguing with an idiot, your opponent is doing the same. |
From: Bruno H. <br...@cl...> - 2005-01-19 17:56:11
|
Sam wrote: > this won't fix compiled code... I take over the compiler.lisp part. I have a partial fix already... You can concentrate on control.d. Bruno |
From: Sam S. <sd...@gn...> - 2005-01-19 19:03:31
|
> * Bruno Haible <oe...@py...t> [2005-01-19 18:52:59 +0100]: > > Sam wrote: >> this won't fix compiled code... > > I take over the compiler.lisp part. I have a partial fix already... > You can concentrate on control.d. the appended patch fixes 12 out of the 14 eval failures. the remaining 2 bugs are in funcall_iclosure(): Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (X (1+ X)) (Z (1+ X))) (DECLARE (SPECIAL X)) Z)))) CORRECT: 7 CLISP : 22 Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (Y (1+ X)) (Z (1+ X))) (DECLARE (SPECIAL X)) Z)))) CORRECT: 6 CLISP : 21 the amusing thing is that this patch: --- eval.d 19 Jan 2005 11:40:04 -0500 1.183 +++ eval.d 19 Jan 2005 14:01:33 -0500 @@ -2387,7 +2387,7 @@ /* the special-references first: */ dotimesC(count,spec_count, { pushSTACK(specdecl); /* preliminary "binding value" */ - pushSTACK_symbolwithflags(*varptr++,wbit(active_bit_o)); /* make a note of binding as being active */ + pushSTACK_symbolwithflags(*varptr++,wbit(dynam_bit_o)); /* inactive */ }); frame_pointer = args_end_pointer; if (var_count-spec_count > 0) { fixes one test and breaks another: Form: (LET ((X 5)) ((LAMBDA (X) (DECLARE (SPECIAL X)) X) (1+ X))) CORRECT: 6 CLISP : 5 Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (X (1+ X)) (Z (1+ X))) (DECLARE (SPECIAL X)) Z)))) CORRECT: 7 CLISP : 6 -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> XFM: Exit file manager? [Continue] [Cancel] [Abort] --- control.d 17 Jan 2005 22:24:12 -0500 1.117 +++ control.d 19 Jan 2005 10:05:41 -0500 @@ -457,7 +457,7 @@ } /* store special-declared symbol in stack: */ pushSTACK(specdecl); /* SPECDECL as "value" */ - pushSTACK_symbolwithflags(declsym,wbit(active_bit_o)); /* Symbol active */ + pushSTACK_symbolwithflags(declsym,wbit(dynam_bit_o)); /* Symbol inactive */ check_STACK(); spec_anz++; } @@ -520,7 +520,7 @@ } } while (--count); #else - var object to_compare = as_object(as_oint(symbol) | wbit(active_bit_o)); + var object to_compare = as_object(as_oint(symbol) | wbit(dynam_bit_o)); var gcv_object_t* ptr = spec_pointer; var uintL count = spec_anz; do { @@ -557,16 +557,6 @@ ASSERT(!constant_var_p(TheSymbol(symbol))); STACK_(varframe_binding_sym) = symbol; } - if (specdecled || special_var_p(TheSymbol(symbol))) { - /* bind dynamically */ - #if (varframe_binding_mark == varframe_binding_sym) - STACK_(varframe_binding_mark) = as_object(as_oint(symbol) | wbit(dynam_bit_o)); - #else - STACK_(varframe_binding_mark) = as_object(as_oint(Fixnum_0) | wbit(dynam_bit_o)); - #endif - } else { - /* bind statically */ - } } varspecs = Cdr(varspecs); var_anz++; |
From: Bruno H. <br...@cl...> - 2005-01-19 19:41:10
|
Sam wrote: > > You can concentrate on control.d. > > the appended patch fixes 12 out of the 14 eval failures. It is not good nevertheless: 1) You have not understood what dynam_bit means. 2) The patch removes the only relevant test for special_var_p. To understand what active_bit means, look at symbol_env_search(). Then, to understand what dynam_bit means, look at unwind(), around line 442. Can you add test cases that exhibit the bugs in your patch? > the remaining 2 bugs are in funcall_iclosure(): > > Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (X (1+ X)) (Z (1+ > X))) (DECLARE (SPECIAL X)) Z)))) > CORRECT: 7 > CLISP : 22 > > Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (Y (1+ X)) (Z (1+ > X))) (DECLARE (SPECIAL X)) Z)))) > CORRECT: 6 > CLISP : 21 Uuh, this one is a little more complicated to fix, because it probably requires a modification of get_closure() as well. Fixing control.d is the easier first step. > the amusing thing is that this patch: > ... > fixes one test and breaks another: Programs and testsuites behave like elements of a vector space and its dual space, respectively. Given enough elements of the dual space, you can distinguish any two different elements of the original space. In program speak: Given sufficient test cases, any wrong modification of the program will lead to a testsuite failure. Bruno |
From: Sam S. <sd...@gn...> - 2005-01-19 20:31:02
|
> * Bruno Haible <oe...@py...t> [2005-01-19 20:37:56 +0100]: > > Sam wrote: >> > You can concentrate on control.d. >> >> the appended patch fixes 12 out of the 14 eval failures. > > It is not good nevertheless this one should be better: --- control.d 17 Jan 2005 22:24:12 -0500 1.117 +++ control.d 19 Jan 2005 15:20:05 -0500 @@ -457,7 +457,7 @@ } /* store special-declared symbol in stack: */ pushSTACK(specdecl); /* SPECDECL as "value" */ - pushSTACK_symbolwithflags(declsym,wbit(active_bit_o)); /* Symbol active */ + pushSTACK_symbolwithflags(declsym,0); /* Symbol inactive */ check_STACK(); spec_anz++; } > Can you add test cases that exhibit the bugs in your patch? done. >> the remaining 2 bugs are in funcall_iclosure(): >> >> Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (X (1+ X)) (Z (1+ >> X))) (DECLARE (SPECIAL X)) Z)))) >> CORRECT: 7 >> CLISP : 22 >> >> Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (Y (1+ X)) (Z (1+ >> X))) (DECLARE (SPECIAL X)) Z)))) >> CORRECT: 6 >> CLISP : 21 > > Uuh, this one is a little more complicated to fix, because it probably > requires a modification of get_closure() as well. yeah... I think the order of variables in clos_vars should be reversed: now specials come first, actually, the formal arguments should be first. (so that they will be bound first). > Fixing control.d is the easier first step. done, I hope. > Programs and testsuites behave like elements of a vector space and > its dual space, respectively. Actually, the other way around. Programs are functions on test cases (not testsuites), so test cases are elements of the "base space", and programs belong to the "dual space". There are many more functions on programs than test cases. (i.e., Gelfand's map is not surjective). -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> Why use Windows, when there are Doors? |
From: Bruno H. <br...@cl...> - 2005-01-19 21:28:06
|
Sam wrote: > this one should be better: > > --- control.d 17 Jan 2005 22:24:12 -0500 1.117 > +++ control.d 19 Jan 2005 15:20:05 -0500 > @@ -457,7 +457,7 @@ > } > /* store special-declared symbol in stack: */ > pushSTACK(specdecl); /* SPECDECL as "value" */ > - pushSTACK_symbolwithflags(declsym,wbit(active_bit_o)); /* > Symbol active */ + pushSTACK_symbolwithflags(declsym,0); /* > Symbol inactive */ check_STACK(); > spec_anz++; > } Yes, this one is part of the solution. > > Can you add test cases that exhibit the bugs in your patch? > > done. Good. I extended the tests by checking the variable's value after unwind() and by testing also without SPECIAL declaration. > >> the remaining 2 bugs are in funcall_iclosure(): > >> > >> Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (X (1+ X)) (Z > >> (1+ X))) (DECLARE (SPECIAL X)) Z)))) > >> CORRECT: 7 > >> CLISP : 22 > >> > >> Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (Y (1+ X)) (Z > >> (1+ X))) (DECLARE (SPECIAL X)) Z)))) > >> CORRECT: 6 > >> CLISP : 21 > > > > Uuh, this one is a little more complicated to fix, because it probably > > requires a modification of get_closure() as well. > > yeah... > I think the order of variables in clos_vars should be reversed: now > specials come first, actually, the formal arguments should be first. > (so that they will be bound first). The order in the frame is normally not relevant; what is relevant is the moment at which the active_bit gets set. The order is only relevant for the case when an X is both declared SPECIAL and bound: (LET (... (X ...) ...) (DECLARE (SPECIAL X)) ...) Here X will be twice in the frame: once for the binding, with dynam_bit and - after the binding is activated - active_bit, and once for the SPECIAL-declaration, with first 0 and then just active_bit. Looking at symbol_env_search, we see that it looks only for elements with active_bit and without dynam_bit. Therefore you can indeed reverse the order. Whether you want to actually reverse the order, depends on whether it simplifies the code. Having at the beginning a loop with puts the variables into the frame with flags 0 and at the end a loop which adds active_bit to each element, is not so efficient. > > Programs and testsuites behave like elements of a vector space and > > its dual space, respectively. > > Actually, the other way around. > Programs are functions on test cases (not testsuites), > so test cases are elements of the "base space", > and programs belong to the "dual space". You lost me here a bit. I thought the thing that's easiest to define is a program (e.g. the Turing definition). -> Vector space P. Then you can make statements / test cases about the program. -> Vector space P*. A test suite would then be a set of elements of P*. And a specification like ANSI CL, which describes the set of valid programs, is an element of P**. > (i.e., Gelfand's map is not surjective). Oops, I have no idea whether the theory about vector spaces, the theory about Banach spaces, and the theory about complex algebras have the same kinds of theorems regarding P, P*, and P**. Bruno |
From: Sam S. <sd...@gn...> - 2005-01-19 22:06:01
|
> * Bruno Haible <oe...@py...t> [2005-01-19 22:24:52 +0100]: > >> I think the order of variables in clos_vars should be reversed: now >> specials come first, actually, the formal arguments should be first. >> (so that they will be bound first). what I was trying to say is that the first set of variables in the clos_vars vector (the special variables) should be bound special only around the implicit_progn() at the end of funcall_iclosure(), not in the early beginning. >> > Programs and testsuites behave like elements of a vector space and >> > its dual space, respectively. >> >> Actually, the other way around. >> Programs are functions on test cases (not testsuites), >> so test cases are elements of the "base space", >> and programs belong to the "dual space". > > You lost me here a bit. data (bit streams or S-exprs) is fundamental. programs operate on data. -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> Linux: Telling Microsoft where to go since 1991. |
From: Bruno H. <br...@cl...> - 2005-01-20 11:57:50
|
Sam wrote: > > * Bruno Haible <oe...@py...t> [2005-01-19 22:24:52 +0100]: > >> I think the order of variables in clos_vars should be reversed: now > >> specials come first, actually, the formal arguments should be first. > >> (so that they will be bound first). > > what I was trying to say is that the first set of variables in the > clos_vars vector (the special variables) should be bound special only > around the implicit_progn() at the end of funcall_iclosure(), not in the > early beginning. Yes, that's correct in any case. > data (bit streams or S-exprs) is fundamental. > programs operate on data. Ah, yes. You're right. Bruno |
From: Sam S. <sd...@gn...> - 2005-01-20 14:15:56
|
> * Bruno Haible <oe...@py...t> [2005-01-20 12:54:28 +0100]: > > Sam wrote: >> > * Bruno Haible <oe...@py...t> [2005-01-19 22:24:52 +0100]: >> >> I think the order of variables in clos_vars should be reversed: now >> >> specials come first, actually, the formal arguments should be first. >> >> (so that they will be bound first). >> >> what I was trying to say is that the first set of variables in the >> clos_vars vector (the special variables) should be bound special only >> around the implicit_progn() at the end of funcall_iclosure(), not in the >> early beginning. > > Yes, that's correct in any case. unfortunately, when I de-activate the initial special bindings and re-activate them at the end right before the implicit_progn(), I get some additional test failures instead. I wonder if keeping two separate vectors of special vars and args and binding the specials only after argument processing right before the implicit_progn() is a cleaner solution. -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> "A pint of sweat will save a gallon of blood." -- George S. Patton |
From: Bruno H. <br...@cl...> - 2005-01-20 16:35:41
|
Sam wrote: > unfortunately, when I de-activate the initial special bindings and > re-activate them at the end right before the implicit_progn(), > I get some additional test failures instead. But at least this modification handles the "free SPECIAL declarations" correctly. For the "bound SPECIAL declarations", i.e. those symbols with occur in both variable lists, you need to set the active_bit already when the corresponding binding is activated. When I look at funcall_iclosure / bind_next_var, it looks like the code should already do this. Which bind-eval tests exactly are still failing? > I wonder if keeping two separate vectors of special vars and args > and binding the specials only after argument processing right before the > implicit_progn() is a cleaner solution. It would consume more memory - gratuitously. Bruno |
From: Sam S. <sd...@gn...> - 2005-01-20 17:12:30
|
> * Bruno Haible <oe...@py...t> [2005-01-20 17:29:49 +0100]: > > Sam wrote: >> unfortunately, when I de-activate the initial special bindings and >> re-activate them at the end right before the implicit_progn(), >> I get some additional test failures instead. > > But at least this modification handles the "free SPECIAL declarations" > correctly. > > For the "bound SPECIAL declarations", i.e. those symbols with occur in > both variable lists, you need to set the active_bit already when the > corresponding binding is activated. When I look at funcall_iclosure / > bind_next_var, it looks like the code should already do this. it activates just the next binding, not the special binding done before. > Which bind-eval tests exactly are still failing? with this patch: --- eval.d 19 Jan 2005 15:50:06 -0500 1.184 +++ eval.d 20 Jan 2005 12:05:52 -0500 @@ -2375,6 +2375,8 @@ } var gcv_object_t* closure_ = &STACK_(frame_closure); /* &closure */ var gcv_object_t* frame_pointer; /* pointer to the frame */ + var gcv_object_t* bind_ptr; + var uintC bind_count; { /* 2nd step: build variable-binding-frame: */ var gcv_object_t* top_of_frame = STACK; /* Pointer to Frame */ var object vars = TheIclosure(closure)->clos_vars; /* Vector of variable-names */ @@ -2387,8 +2389,9 @@ /* the special-references first: */ dotimesC(count,spec_count, { pushSTACK(specdecl); /* SPECDECL as "value" */ - pushSTACK_symbolwithflags(*varptr++,wbit(active_bit_o)); /* active */ + pushSTACK_symbolwithflags(*varptr++,0); /* INactive */ }); + bind_ptr = args_end_pointer; bind_count = spec_count; frame_pointer = args_end_pointer; if (var_count-spec_count > 0) { var uintB* varflagsptr = &TheSbvector(TheIclosure(closure)->clos_varflags)->data[0]; @@ -2635,6 +2638,15 @@ } #undef bind_next_var } + /* activate the bindings: */ + for (;bind_count--;bind_ptr skipSTACKop varframe_binding_size) { + var gcv_object_t* markptr = &Before(bind_ptr); + var object symbol = *(markptr STACKop varframe_binding_sym); /* variable */ + var object newval = *(markptr STACKop varframe_binding_value); /* new value */ + *(markptr STACKop varframe_binding_value) = TheSymbolflagged(symbol)->symvalue; /* save old value in frame */ + *markptr = as_object(as_oint(*markptr) | wbit(active_bit_o)); /* activate binding */ + TheSymbolflagged(symbol)->symvalue = newval; /* new value */ + } /* 5th step: evaluate Body: */ implicit_progn(TheIclosure(closure)->clos_body,NIL); unwind(); /* unwind ENV-frame */ 2 tests fail: RUN-TEST: finished "tests/bind" (2 errors out of 32 tests) 32 ; 2 Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (X (1+ X)) (Z (1+ X)))(DECLARE (SPECIAL X)) Z)))) CORRECT: 7 CLISP : 6 Form: (PROGN (DEFPARAMETER *GLOBAL-VAR-FOR-BIND.TST* 123) (LET ((*GLOBAL-VAR-FOR-BIND.TST* 5)) (LIST ((LAMBDA (*GLOBAL-VAR-FOR-BIND.TST*) (DECLARE (SPECIAL *GLOBAL-VAR-FOR-BIND.TST*)) *GLOBAL-VAR-FOR-BIND.TST*) (1+ *GLOBAL-VAR-FOR-BIND.TST*)) *GLOBAL-VAR-FOR-BIND.TST*))) CORRECT: (6 5) CLISP : (#<SPECIAL REFERENCE> 5) Differ at position 0: 6 vs #<SPECIAL REFERENCE> CORRECT: (6 5) CLISP : (#<SPECIAL REFERENCE> 5) if I put wbit(dynam_bit_o) instead of 0 in the second hunk, I get: RUN-TEST: finished "tests/bind" (7 errors out of 32 tests) 32 ; 7 Form: (LET ((X 5)) ((LAMBDA (X) (DECLARE (SPECIAL X)) X) (1+ X))) CORRECT: 6 CLISP : 5 Form: (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINC-ERROR C) (RETURN-FROM FOO 'GOOD)))) (LET ((X (1+ X))) (DECLARE (SPECIAL X)) X))) CORRECT: GOOD CLISP : 7 Form: (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINC-ERROR C) (RETURN-FROM FOO 'GOOD)))) (LET* ((X (1+ X))) (DECLARE (SPECIAL X)) X))) CORRECT: GOOD CLISP : 7 Form: (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINC-ERROR C) (RETURN-FROM FOO 'GOOD)))) (MULTIPLE-VALUE-BIND (X) (1+ X) (DECLARE (SPECIAL X)) X))) CORRECT: GOOD CLISP : 7 Form: (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINC-ERROR C) (RETURN-FROM FOO 'GOOD)))) ((LAMBDA (X) (DECLARE (SPECIAL X)) X) (1+ X)))) CORRECT: GOOD CLISP : #<SPECIAL REFERENCE> Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (X (1+ X)) (Z (1+ X)))(DECLARE (SPECIAL X)) Z)))) CORRECT: 7 CLISP : 6 Form: (PROGN (DEFPARAMETER *GLOBAL-VAR-FOR-BIND.TST* 123) (LET ((*GLOBAL-VAR-FOR-BIND.TST* 5)) (LIST ((LAMBDA (*GLOBAL-VAR-FOR-BIND.TST*) (DECLARE (SPECIAL *GLOBAL-VAR-FOR-BIND.TST*)) *GLOBAL-VAR-FOR-BIND.TST*) (1+ *GLOBAL-VAR-FOR-BIND.TST*)) *GLOBAL-VAR-FOR-BIND.TST*))) CORRECT: (6 5) CLISP : (#<SPECIAL REFERENCE> 6) Differ at position 0: 6 vs #<SPECIAL REFERENCE> CORRECT: (6 5) CLISP : (#<SPECIAL REFERENCE> 6) if instead I add wbit(dynam_bit_o) to wbit(active_bit_o) in the last hunk, I get: RUN-TEST: finished "tests/bind" (7 errors out of 32 tests) 32 ; 7 Form: (LET ((X 5)) ((LAMBDA (X) (DECLARE (SPECIAL X)) X) (1+ X))) CORRECT: 6 CLISP : 5 Form: (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINC-ERROR C) (RETURN-FROM FOO 'GOOD)))) (LET ((X (1+ X))) (DECLARE (SPECIAL X)) X))) CORRECT: GOOD CLISP : 7 Form: (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINC-ERROR C) (RETURN-FROM FOO 'GOOD)))) (LET* ((X (1+ X))) (DECLARE (SPECIAL X)) X))) CORRECT: GOOD CLISP : 7 Form: (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINC-ERROR C) (RETURN-FROM FOO 'GOOD)))) (MULTIPLE-VALUE-BIND (X) (1+ X) (DECLARE (SPECIAL X)) X))) CORRECT: GOOD CLISP : 7 Form: (BLOCK FOO (HANDLER-BIND ((UNBOUND-VARIABLE (LAMBDA (C) (PRINC-ERROR C) (RETURN-FROM FOO 'GOOD)))) ((LAMBDA (X) (DECLARE (SPECIAL X)) X) (1+ X)))) CORRECT: GOOD CLISP : #<SPECIAL REFERENCE> Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (X (1+ X)) (Z (1+ X)))(DECLARE (SPECIAL X)) Z)))) CORRECT: 7 CLISP : 6 Form: (PROGN (DEFPARAMETER *GLOBAL-VAR-FOR-BIND.TST* 123) (LET ((*GLOBAL-VAR-FOR-BIND.TST* 5)) (LIST ((LAMBDA (*GLOBAL-VAR-FOR-BIND.TST*) (DECLARE (SPECIAL *GLOBAL-VAR-FOR-BIND.TST*)) *GLOBAL-VAR-FOR-BIND.TST*) (1+ *GLOBAL-VAR-FOR-BIND.TST*)) *GLOBAL-VAR-FOR-BIND.TST*))) CORRECT: (6 5) CLISP : (#<SPECIAL REFERENCE> 6) Differ at position 0: 6 vs #<SPECIAL REFERENCE> CORRECT: (6 5) CLISP : (#<SPECIAL REFERENCE> 6) >> I wonder if keeping two separate vectors of special vars and args >> and binding the specials only after argument processing right before the >> implicit_progn() is a cleaner solution. > > It would consume more memory - gratuitously. an interpreted closure is a rare beast, I wouldn't worry about this too much -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> Bill Gates is not god and Microsoft is not heaven. |
From: Bruno H. <br...@cl...> - 2005-01-20 19:04:57
|
Sam wrote: > 2 tests fail: > > RUN-TEST: finished "tests/bind" (2 errors out of 32 tests) > 32 ; > 2 > Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (X (1+ X)) (Z (1+ X)))(DECLARE (SPECIAL X)) Z)))) > CORRECT: 7 > CLISP : 6 Yes, for this test to work, the first (1+ X) has to refer to the lexical binding and the second (1+ X) has to refer to the global binding. Either, as you say, the activation of the of X |here (X (1+ X)) | (Z (1+ X)) must also the the active_bit in the (X, SPECDECL) pair, or symbol_env_search must be changed to also look at dynam | active pairs. For the latter to be consistent with the way it works after an environment is nested (:= moved into the heap), we need to verify how nest_var works: (defvar x 5) (setq func (let ((x 10)) (declare (special x)) #'(lambda () x))) func must refer to the special variable x (value 5) although the binding of x as a special variable has already been undone. It looks like you also need to read the code of nest_var() in order to understand how things are meant to work... > >> I wonder if keeping two separate vectors of special vars and args > >> and binding the specials only after argument processing right before the > >> implicit_progn() is a cleaner solution. > > > > It would consume more memory - gratuitously. > > an interpreted closure is a rare beast, I wouldn't worry about this too much Huh? An interpreted closure is very frequent when you load a program in interpreted form. Bruno |
From: Sam S. <sd...@gn...> - 2005-01-20 20:06:39
|
> * Bruno Haible <oe...@py...t> [2005-01-20 19:59:01 +0100]: > > Sam wrote: >> 2 tests fail: >> >> RUN-TEST: finished "tests/bind" (2 errors out of 32 tests) >> 32 ; >> 2 >> Form: (LET ((X 5)) (PROGV '(X) '(20) ((LAMBDA (&OPTIONAL (X (1+ X)) (Z (1+ X)))(DECLARE (SPECIAL X)) Z)))) >> CORRECT: 7 >> CLISP : 6 > > Yes, for this test to work, the first (1+ X) has to refer to the lexical > binding and the second (1+ X) has to refer to the global binding. Either, > as you say, the activation of the of X > |here > (X (1+ X)) | (Z (1+ X)) > must also the the active_bit in the (X, SPECDECL) pair, to do that easily, the information that X should be special should be carried not via the extra X in clos_vars, but via an annotation on the only X in clos_vars that this binding is special. this will also save some STACK... >> >> I wonder if keeping two separate vectors of special vars and args >> >> and binding the specials only after argument processing right before the >> >> implicit_progn() is a cleaner solution. >> > >> > It would consume more memory - gratuitously. >> >> an interpreted closure is a rare beast, I wouldn't worry about this too much > > Huh? An interpreted closure is very frequent when you load a program > in interpreted form. What I am trying to say is that when you are using interpreted closures, you are probably not concerned about performance as much because you are doing development, not production (cf. many C compilers refuse to combine -g with -O). Thus, 1% (or even 10% - although Iclosure size cannot do that) performance impact in interpreted closures does not matter. -- Sam Steingold (http://www.podval.org/~sds) running w2k <http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/> <http://www.mideasttruth.com/> <http://www.honestreporting.com> Don't use force -- get a bigger hammer. |
From: Bruno H. <br...@cl...> - 2005-01-20 21:14:36
|
Sam wrote: > to do that easily, the information that X should be special should be > carried not via the extra X in clos_vars, but via an annotation on the > only X in clos_vars that this binding is special. > this will also save some STACK... Maybe... Don't forget to think about the nesting that happens while the frame is being built. Explained around lispbibl.d:9950. An example is (let ((x (progn (setq *func1* #'(lambda () x)) ...)) (y (progn (setq *func2* #'(lambda () x)) ...))) (declare (special x z)) (setq *func3* #'(lambda () z)) ...) When the closure for *func1* is created, a nest_var is used, that should not move anything to the heap. When the closure for *func2* is created, a nest_var is used, that should move the (x SPECDECL) association to the heap, so that the x in *func2* refers to the global variable. When the closure for *func3* is created, then only the (z SPECDECL) association is also moved to the heap. Assuming we don't want to change symbol_env_search - I think it's more often used than funcall_iclosure and therefore should not be made slower -, the frame for the above example should be reordered from x 0 SPECDECL z 0 SPECDECL x dynam_bit value y 0 value (where the active_bits are added top-down) to x dynam_bit value x 0 SPECDECL y 0 value z 0 SPECDECL (where the active_bits are added top-down again). Then we can also remove the inconsistency between nest_var and symbol_env_search: [1]> (let ((x 5)) (declare (special x)) #'(lambda () x)) #<FUNCTION :LAMBDA NIL X> [2]> (dotimes (i 22) (print (sys::%record-ref * i))) :LAMBDA (NIL X) NIL (X) #(X #<SPECIAL REFERENCE> X #<SPECIAL REFERENCE> NIL) NIL NIL NIL ((DECLARATION OPTIMIZE DECLARATION)) #() #() 0 0 0 NIL 0 0 NIL NIL NIL 0 NIL As you can see here, the variable environment contains the information that X is SPECDECL twice! Once from the binding with dynam_bit, once from the SPECIAL declaration. OK, this is not so important... Bruno |