2024-01-10 17:02:58 in writing my own Forth, i found myself in 2 rooms: one is the repl Forth, e.g. the classic repl when you type words and they get executed immediately, the second room is the compiled Forth.. when i define a new word i save the microcode (this is a VM) in a vector of instructions, which is basically different than the repl.. here i can optimize things, having some more instructions that are impossible to have in repl, and so on -- do you think is it n 2024-01-10 17:02:58 this dichotomy? 2024-01-10 17:05:03 rendar: i have been grappling with this over the past few weeks, too. i think the answer is yes, it is normal, and you have some word to switch between "rooms". i'm not very happy with this, though, so at the moment i'm working toward something to try to unify them 2024-01-10 17:05:33 zelgomer, no, i don't think we have to unify these 2 rooms 2024-01-10 17:05:37 they are 2 different things 2024-01-10 17:06:07 i was also thinking to add more features on words defined by hand, that repl shouldn't have 2024-01-10 17:06:28 Traditional Forth compiling appends each word to the current definition but there's no reason you couldn't add them to some equivalent of an AST and have ; generate the code from that 2024-01-10 17:07:11 GeDaMo, well, i don't have an AST, i have a simply vector of OpCodes 2024-01-10 17:07:19 the thing is, those OpCodes are not 1:1 with words 2024-01-10 17:07:44 well, it's confusing to me to have two independent contexts with similar vocabularies. so i'm moving toward something approaching what GeDaMo just described. repl interpretation is not going to be as performant, but it is laid out in such a way and with metadata so that when you want to produce a binary, it can crawl words and compile them on-demand into the target image 2024-01-10 17:07:51 i have almost ~600 words in my Forth, while OpCodes are like 5/6 now 2024-01-10 17:09:14 zelgomer, yeah, but the basic difference is that in definition of a new word, you have `;` delmiter, which says you can stop, and it gives you a whole chunk of code, in REPL you don't have any temination, it will read forever, literally 2024-01-10 17:09:19 that's an important difference 2024-01-10 17:10:31 It doesn't specifically have to be an AST, just some intermediate structure which you can apply optimizations to 2024-01-10 17:11:37 rendar: not following 2024-01-10 17:11:50 rendar: i am able to write : ... ; in my repl 2024-01-10 17:14:49 zelgomer, what i want to say is: 2024-01-10 17:17:01 when you write `2 dropn a b` in your repl, the repl will get words by words and will WAIT until the next word, e.g. you can type "2" then return then "dropn", when you type "2" and you press return, the REPL will add 2 into the stack, then when you type "dropn" it will pop 2 and drop 2 elements from the stack.. but the REPL can't tell if you after 2 will type 'dropn', otherwise when the compiler gets `: hello 2 dropn a b ;` it has a "complete vision" 2024-01-10 17:17:01 whole word you're defining, and can optimized `2 dropn` into `2drop` 2024-01-10 17:18:55 colorforth had an interesting technique which I've seen referred to as pinhole optimization 2024-01-10 17:18:55 + was an immediate word, it ran at compile time and looked at the previous thing compiled; if it was pushing a literal value to the stack, that would be de-compiled then add would compile an add immediate machine code instruction 2024-01-10 17:19:35 Otherwise it would ocmpile a standard add top two elements on the stack 2024-01-10 17:26:29 GeDaMo: I think you're right - you could do something other than the conventional dictionary structure, like an AST, and that would give you various optimization opportunities. 2024-01-10 17:26:49 The normal dictionary is just the standard and "simplest" thing to do. 2024-01-10 17:27:30 Yeah 2024-01-10 17:29:07 I think in Chuck's very earliest system he didn't actually have definitions as we know them - he just stored the text of each "definition" and then things got expanded macro style. 2024-01-10 17:29:15 Compiled definitions came later. 2024-01-10 17:29:46 So maybe that is the "simplest" thing you could do. 2024-01-10 17:31:02 Apropos of nothing, I was reminded of a paper by Wirth "Good Ideas, Through the Looking Glass" https://people.inf.ethz.ch/wirth/Articles/GoodIdeas_origFig.pdf 2024-01-10 17:56:54 KipIngram, i guess so 2024-01-10 17:57:17 KipIngram, but my inquiry was about that repl and compiled functions are basically 2 different worlds, with different rules 2024-01-10 17:58:28 The REPL executes functions immediately, the compiler defers execution until later 2024-01-10 18:13:50 rendar: rather than thinking of it as two different worlds, the ANS texts that i've read seems to prefer to describe it as "execution semantics" versus "compilation semantics". every word has both, for some words they are the same (like comments, for example) 2024-01-10 18:19:29 zelgomer, hmm, i can't follow you here, can you define better execution and compilation semantics? 2024-01-10 18:20:21 execution semantics are a word's behavior when it's encountered during execution, compilation semantics are a word's behavior when it's encountered during compilation 2024-01-10 18:21:07 for example, ('s execution semantics are that it consumes the input stream until a matching ) is encountered. its compilation semantics are the same 2024-01-10 18:21:42 "+" has different execution semantics and compilation semantics, though 2024-01-10 18:22:08 execution adds two values together, compilation appends its execution token to the current definition 2024-01-10 18:22:59 "if"'s execution semantics are undefined, and its compilation semantics are that it appends a conditional branch to the current definition, and so on 2024-01-10 18:30:31 zelgomer, yes! that's exactly what i mean 2024-01-10 18:30:44 zelgomer, basically you can't use 'if' in repl, right? 2024-01-10 18:31:04 usually you cannot, yes 2024-01-10 18:32:05 i see, right 2024-01-10 19:35:41 rendar: That's because if compiles something (a conditional jump). If it doesn't have anywhere to compile it to, it doesn't know what to do. 2024-01-10 19:35:56 KipIngram, indeed 2024-01-10 19:36:59 in my forth implementation i have this: `true #if-true 1 #else 2 #fi` with this, you can implement this in REPL, because #if-true and #else can switch on/off REPL reading based on what true/false is in the stack 2024-01-10 19:38:39 yeah, there are a number of games you can play in the interpreter. 2024-01-10 19:38:56 I've used a looping method at interpreter level to time compilation in my system. 2024-01-10 19:39:04 yeah 2024-01-10 19:39:07 I wrote a word that conditionally resets >in to zero. 2024-01-10 19:39:23 Which sends the interpreter back to start of line - eventually it fails to reset it and I finish. 2024-01-10 19:39:25 that's is a different world from compiling words for obvious reasons 2024-01-10 19:39:34 oh..interesting 2024-01-10 19:40:36 I wasn't too happy with the results. Insofar as execution speed of compiled code went, my system compared very favorably with GForth. But on compile speed GForth totally kicked my system's butt. 2024-01-10 19:41:06 I figured right then it had to be hasing instead of doing a linked list lookup - it was TOO fast to be doing anything other than hashing. And we later confirmed that to be true in their docs. 2024-01-10 19:41:46 i see 2024-01-10 19:43:07 That word was pretty simple - it was just : stop? 1- .0=; >in off ; 2024-01-10 19:43:29 .0=; returns if the TOS is zero, and does not consume the TOS. 2024-01-10 19:44:24 so all I had to do was make sure that a counter was on the stack at start of line and the code I was timing the compile of didn't disturb it. 2024-01-10 19:46:29 Top of stack? 2024-01-10 19:46:42 TOS == Top Of Stack? 2024-01-10 19:49:06 Yes. 2024-01-10 19:51:37 as opposed to DS9 or TNG 2024-01-10 19:57:00 tos is the best one 2024-01-10 20:04:17 haahahaha