Forth is officially weird (multiple DOES> with CREATE)
Posted: Sun Jun 17, 2018 12:10 pm
SamCo has kindly ported the ANSI Forth test suite to Tali Forth 2, and apart from my "duh" stupid errors, there are also some really strange edge cases that are now covered. For instance, this test of DOES> is currently failing, as the log shows: (Yes, the "weird" part is from the official test code https://forth-standard.org/standard/core/DOES.) I did a double take when I first saw this: Yes, there are two DOES> after one CREATE. I didn't even know that was legal. As for what it, uh, does, the first call to w1 will run the first DOES>, and then all others will call the second one. You can do the same thing with three DOES> (here Gforth to be sure): I think I understand why this happens, but it does hurt my brain. More practically minded, what can it be used for? Well, a single initial code sequence for a created word, and then the same for every other call: (This leaves stuff on the stack, but gets the point across). It's tempting to use the word "constructor" here, but that would probably be a false analogy.
The really weird thing? This bizarre double DOES> code actually worked immediately with Tali Forth. The test is failing because of >BODY. That's a word that is the bane of my existence anyway, because with a STC Forth, there is no real difference between PFA and CFA. Tali gets around this with long, ugly code that checks to see if there is DOVAR, DOCONST etc subroutine jump at the beginning of the code area, and if yes, skips. But >BODY has no way of knowing that a word was created by a CREATE/DOES> construct, and so we're off by three bytes (the length of the subroutine jump instruction), which is why the ANSI test is failing while trying to match that address with HERE.
I currently have no idea how to fix this issue (formally https://github.com/scotws/TaliForth2/issues/61) at the moment -- ideally, it would slay the monster that is >BODY at the same time. We have three unused status bits, one of which would do the trick ("has CFA") -- clear by default, set for DODOES and friends, and words created by CREATE. But that's still ugly. At the moment, we'll document it and live with it.
Code: Select all
{ : weird: create does> 1 + does> 2 + ; -> } ok
{ weird: w1 -> } ok
{ ' w1 >body -> here } INCORRECT RESULT: { ' w1 >body -> here } ACTUAL RESULT: { 3938 } ok
{ w1 -> here 1 + } ok
{ w1 -> here 2 + } okCode: Select all
: weird3 create does> 1 + does> 2 + does> 3 + ; ok
weird3 w3 ok
w3 . 139906661999569 ok
w3 . 139906661999570 ok
w3 . 139906661999571 ok
w3 . 139906661999571 ok
Code: Select all
: hi_there create does> ." Nice to meet you!" does> ." We've already met." ; ok
hi_there ok
hi Nice to meet you! ok
hi We've already met. ok
hi We've already met. ok
The really weird thing? This bizarre double DOES> code actually worked immediately with Tali Forth. The test is failing because of >BODY. That's a word that is the bane of my existence anyway, because with a STC Forth, there is no real difference between PFA and CFA. Tali gets around this with long, ugly code that checks to see if there is DOVAR, DOCONST etc subroutine jump at the beginning of the code area, and if yes, skips. But >BODY has no way of knowing that a word was created by a CREATE/DOES> construct, and so we're off by three bytes (the length of the subroutine jump instruction), which is why the ANSI test is failing while trying to match that address with HERE.
I currently have no idea how to fix this issue (formally https://github.com/scotws/TaliForth2/issues/61) at the moment -- ideally, it would slay the monster that is >BODY at the same time. We have three unused status bits, one of which would do the trick ("has CFA") -- clear by default, set for DODOES and friends, and words created by CREATE. But that's still ugly. At the moment, we'll document it and live with it.