POSTPONE
drom opened this issue · 17 comments
The following code:
T{ : GT1 123 ; -> }T
T{ : GT4 POSTPONE GT1 ; IMMEDIATE -> }T
T{ : GT5 GT4 ; -> }T
T{ GT5 -> 123 }T
Lead to the core test failure:
Error: in line: 647 T{ : GT5 GT4 ; -> }T expected [ 291 ] to deeply equal [].
Error: in line: 648 T{ GT5 -> 123 }T expected [] to deeply equal [ 291 ].
Other parts of the test with POSTPONE
are passing.
T{ : GT6 345 ; IMMEDIATE -> }T
T{ : GT7 POSTPONE GT6 ; -> }T
T{ GT7 -> 345 }T
and
T{ : NOP : POSTPONE ; ; -> }T
T{ NOP NOP1 NOP NOP2 -> }T
T{ NOP1 -> }T
T{ NOP2 -> }T
If you have a traditional Forth with just default and immediate words, POSTPONE FOO
should be the same as COMPILE FOO
if FOO
has default compilation semantics, and the same as [COMPILE] FOO
if FOO
is immediate.
It seems your problem is with POSTPONE
ing non-immediate words. If bar
is not immediate
: foo postpone bar ;
should have the same effect at run time as
: foo ['] bar postpone literal ['] compile, compile, ;
I.e. when foo
runs, it compiles bar
into the definition that is being compiled that time. (If bar
were immediate, it would be compiled into foo
instead.)
Is your head spinning yet? ;-)
Note: COMPILE,
is just the same as ,
in a traditional (indirect or direct) threaded Forth.
Yes, that is my issue. I have JS-Threaded Forth 😏
Looks like I need to detect if the word is immediate
or not.
Current code is too simple:
https://github.com/drom/forth/blob/master/lib/cfg.js#L65-L74
def('postpone', function () {
var w = this.io.word('\\s');
var wordLink = this.O[w.toLowerCase()];
if (wordLink) {
this.pos.push(ast.callword(wordLink.index));
} else {
cxt.log('word: ' + w + ' is not defined');
throw new Error;
}
}, cxt, { immediate: true });
I see your compiler is building JavaScript code at run time. So COMPILE,
should take an xt and generate code to call that xt.
POSTPONE IF
should generate code to call IF
.
POSTPONE +
should generate code to generate code to call +
. Simple!
That is what I am doing. But as you can see in the failing case:
HEX
T{ : GT1 123 ; -> }T
T{ : GT4 POSTPONE GT1 ; IMMEDIATE -> }T
T{ : GT5 GT4 ; -> }T
T{ GT5 -> 123 }T
SEE GT4
will be:
gt4: function () {
this[152]();
}
Lead to the core test failure:
Error: in line: 647 T{ : GT5 GT4 ; -> }T expected [ 291 ] to deeply equal [].
Error: in line: 648 T{ GT5 -> 123 }T expected [] to deeply equal [ 291 ].
You ca run it by yourself:
http://drom.io/forth
The comp.lang.forth
link: https://groups.google.com/forum/#!topic/comp.lang.forth/BlA-81dmWow
What does your GT5
do? It seems it doesn't leave 123
on the stack. Why doesn't it do that?
GT4
is an immediate word. When GT4
runs it should compile GT1
into the current definition. So : GT5 GT4 ;
should have the same effect as : GT5 GT1 ;
.
Also, where does 291
come from?
123
HEX = 291
DEC
Well, I tried http://drom.io/forth, and typed in the test code.
see GT4
clearly shows the generated JavaScript code is wrong.
Looks like POSTPONE
has to check if the WORD
, it is POSTPONing is immediate
or not.
if (immediate) {
compile the WORD into the current definition.
} else {
compile the code that will compile the WORD into current definition when being executed.
}
Yes!
Thanks, fixing. 7 more issue to go ;)
T{ : GT1 123 ; -> }T
T{ : GT4 POSTPONE GT1 ; IMMEDIATE -> }T
T{ : GT5 GT4 ; -> }T
T{ GT5 -> 123 }T
GT1
is a word with default compilation semantics (i.e., you get them from Section 3.4.3.3 cited above. POSTPONE GT1
appends the compilation semantics of GT1
to GT4
, whereas just writing GT1
would append the execution semantics of GT1 to GT4. Or, in other words, POSTPONE GT1
appends the appending of the execution semantics of GT1
to GT4
. When GT4
is performed in the next line, it appends the execution semantics of GT1
to GT5
. And when GT5
is performed in the next line, it performs the execution semantics of GT1
and pushes 123
on the stack.
--- anton
from here: https://groups.google.com/d/msg/comp.lang.forth/BlA-81dmWow/j81maLLaAAAJ
T{ : GT6 345 ; IMMEDIATE -> }T
T{ : GT7 POSTPONE GT6 ; -> }T
T{ GT7 -> 345 }T
GT6
is an immediate
word with the following compilation semantic == execution semantic is to push 345
to the stack.
POSTPONE GT6
appends this compilation / execution semantic of GT6
to GT7
by just compiling call to GT6
.
GT7
just executes this call.
T{ : NOP : POSTPONE ; ; -> }T
T{ NOP NOP1 NOP NOP2 -> }T
T{ NOP1 -> }T
T{ NOP2 -> }T
;
is an immediate
word with the following compilation semantic == execution semantic of finishing the colon definition.
POSTPONE ;
appends this compilation / execution semantic of ;
to NOP
by just compiling call to ;
.
NOP NOP1
just executes this call.