It has been a while since I visited this thread. The as-of-right-now commit of
http://github.com/chitselb/pettil is pretty stable, after spending way too much time rewriting BLOCK and UPDATE and a foray into +LOOP , but those are stable too, as is the editor. Yes, even the editor which has been broken for about a month. Time to revisit <BUILDS ... DOES> ...
There are two separate dictionary spaces, "core" and "transient" with a symbol table "symtab". Once all the editing, assembling, interpreting, compiling (in short, anything that touches the symbol table) are done with, only "core" will remain, currently residing from $0400-$1B1F. Virtual memory (BLOCK / UPDATE / LOAD-BUFFERS / SAVE-BUFFERS) will stick around in "core" and everything above that will become room for application code and data.
Without a symbol table, CREATE is pretty worthless, so it lives in the transient dictionary. I'd like for all the code in between <BUILDS and DOES> to also go up in transient, something like
Code:
USER TDP ( transient dictionary pointer, was initialized at cold start )
: @SWAP! ( var1 var2 -- )
2DUP 2>R @ SWAP @ R> ! R> ! ;
: NEW-PARENT-WORD ( address value == ) ( -- )
<BUILDS , , DOES> DUP @ SWAP 2+ @ EXECUTE ; ( or something similar )
: DRAW ( value -- ) ... code to draw something ;
' DRAW 42 NEW-PARENT-WORD CHILD-WORD
"<BUILDS" is immediate and performs a DP TDP @SWAP! to target the transient dictionary.
the " , ,XT " code is then compiled in the transient dictionary
"DOES>" is also immediate, switches the dictionaries again, the rest of the code compiles to core dictionary
the " DUP @ SWAP 2+ @ EXECUTE " runtime behavior of all child words is compiled once in the core dictionary at newparentwordruntime
The top of core would now look something like:
Code:
newparentwordruntime
.word dup ( jsr enter is not required or compiled for DOES> blocks. dodoes points IP to here )
.word fetch
.word swap
.word twoplus
...etc...
.word execute
.word exit ( exits the child word )
child-word
jsr dodoes ( CFA )
.word newparentwordruntime ( PFA+0 )
.word 42 ( PFA + 2 )
.word draw ( PFA + 4)
This means <BUILDS and DOES> would both be immediate, to switch dictionaries when NEW-PARENT-WORD is compiled. This feels messy. I also don't like using PFA+0 to store the address of the child word's runtime behavior, because that is something that probably belongs in the child word CFA.
It would be nice if CREATE ... DOES> also worked, but in a more vanilla way, without the target dictionary swapping. These behave the same, with the difference being where the " , , " is compiled. For 2KONSTA it goes in TDICT, at TDP, and for 2KONSTB it goes in core, at HERE .
Code:
: 2KONSTA <BUILDS , , DOES> 2@ ;
: 2KONSTB CREATE , , DOES> 2@ ;
DOES> would only swap dictionaries when DP @ is greater than TDICT @ (pointer to the base of the transient dictionary, presently $6C00 on a 32K PET). I suppose it would be possible to associate a list of behaviors (like Java's class methods) with a parent/defining word and have each child word's PFA+0 point to the base of that list, with the remainder of the child's PFA behaving like Java's instance fields.
That's where the design is for now, tormenting me in my dreams and waking hours. All feedback (even "what a stupid idea! and here's why...") will be welcome