The language is named 'oh' and is a stack rpn lang written in js. It has some sort of compilation method that transforms source code into a bunch of js functions that will perform the actions of the code when evaluated. It has two dictionaries, the normal dictionary and a temporary one to aid compilation. The interpreter and compiler procedures will prefer a temporary word if it exists than a dictionary word, so temporary words shadow normal ones, but their life span is short. They get removed from the temporary dictionary once a top level colon word definition ends compilation, but they get retained in the code where they are used. After the temporary dictionary has been reset you cannot access those words unless you appended them into the compilation of some definition. Temporary words are available outside compilation (at runtime) as long as they do not get removed. Normal words can be immediate, which means that they exeecute at compile time and if they want or need, they can append code into the current compilation. words like: bind, if, :, {, object, list, etc. Are immediate words. Any word that evaluates at compile time is an immediate word. To push a number on the stack or evaluate a word you just type it. ```oh 1 2 + ``` You know that stuff already. ```oh 1 2 dup swap over ``` If you precede a word with a single quote "'" then the word gets pushed on the stack as a string. ```oh 'oh print 'meh print ``` Note that is only ONE single quote, not two like in other languages. It's somewhat similar to lisp's quote operator, but it just quotes a string and pushes it on the stack. The language even if written in js will not allow you to use + with strings. ```oh 'oh 'meh + ``` This is an error, the operator to concatenate two strings is .. like in perl, but it's two dots instead of one ```oh 'oh 'meh .. ``` This merges both strings and returns ohmeh on the stack To define a word we use the colon word : ```oh : oh 1 2 3 ; ``` ```oh : meh oh + + print ; ``` Colon definitions can be nested ```oh : oh : meh 1 2 ; meh + ; ``` There is no lexical scope, but the nested definitions are temporary. I call them temporary words and they will disappear when the top colon definition ends compilation. They are meant to be helpers inside a definition, to create little blocks. They shadow normal words and can be used at runtime, but remember that when a top level colon word definition ends, they will get removed. So in this case, the word meh gets removed from the temporary dictionary when the definition of the oh word reaches its end at the last semicolon. trying to evaluate meh from now on will trigger an error saying that the word does not exist, yet the code of meh was compiled in the code of oh, because oh used it. Only top level : colon definitions will reset temporary words, any other word that triggers compilation will not remove them. Temporary words are available both at compile time and at runtime, just remember that they will disappeear once a top level colon definition ends. Any word that compiles code will allow the creation and usage of temporary words. One example of such a word is the curly bracket { When executed it reads the source code and starts compiling until a terminating } is found, then it pushes a js function on the stack that when evaluated will evaluate that code. ```oh { 1 2 3 } eval ``` That would create the function and eval will evaluate it, making it push those numbers on the stack. Temporary words can be defined inside { ```oh { : oh 1 2 3 ; oh } ``` Note that we are not evaluating the function returned by { but the oh temporary word has been created already at the compile time of { This temporary word is available outside the { code because only top level colon definitions reset temporary words. So now we could: ```oh oh ``` At the top level or anywhere and it will work fine. Only when the next top level definition ends compilation will oh cease to exist. ```oh : meh oh + + print ; ``` The temporary word oh was compiled into the code of meh and after meh ends compilation oh does not exist in the temporary dictionary anymore, yet it will be retained on the code of any word that compiled it when it existed This is mainly due to js garbage collector, the word oh does not really cease to exist because meh has a reference to it, but is not available because is not in the dictionary anymore. Okay, now let's create a binding for a value. ```oh 24 bind oh ``` The word bind reads a word from the source code, in this case oh, and at runtime it will take an element from the stack and associate it with the word oh. The word bind creates a js lexical variable named 'value' inside a lexical scope. Then inside this scope it creates two closures that capture the variable value. One closure will set the value and the other push it on the stack. The bind word in this case created the word oh in the dictionary and it's code was the closure that pushes value on the stack. Since we were not compiling, it evaluated the other closure that updates the value variable by taking an element from the stack. Note that bind is not a real variable, just a binding associated with another word. Now if we were compiling bind would do the same a bit differently. ```oh : oh bind meh ; ``` In this case bind is being evaluated at compile time, when oh was compiling. It then creates the two closures associated with a variable in js, then creates the word meh and associates meh with the closure that pushes the value. The difference here is that when bind is inside a compilation unit, it creates a temporary word in the temporary dictionary instead of the persistent one. Also, it attaches the setter closure to the compilation of oh. We did not evaluate oh yet, but the word meh was defined which will push the associated value on the stack when executed. If we were to evaluate oh like: ```oh 24 oh ``` Then oh will execute the setter closure and set this value. The problem here is that meh was a temporary word and temporary words die when a top level colon definition ends compilation, so meh is not available anymore. Let's try with a { block which does not remove temporary words. ```oh { bind meh } ``` Now bind does the same. It evaluates at { compilation time, it reads the word meh from the source code, creates the two closures and creates a temporary word named meh that when evaluated will push the associated value on the stack. Then it appends the setter closure to the code of { so if we were to evaluate the function that { returns on the stack, it will take a value from the stack and update the associated variable. Let's save the function returned by { into a binding ```oh { bind meh } bind set-meh ``` Note that we are using bind twice, one at the compilation time of { and other at the top level and at runtime. You know what the bind inside { does, it creates the temporary word meh associated with a js variable and appends the setter closure to the code of { Then the { finds a } and finishes compilation, returning the function on the stack. Now the bind outside reads the word set-meh and creates a binding with the two closures, creates the set-meh word in the persistent dictionary, because bind creates temporary words only when it executes at compiling time, if it executes at runtime creates a normal word instead. Then takes an element from the stack which is the function { generated and sets the associated variable to retain that function. This means that when we evaluate the word set-meh it will push that function on the stack. Now we can use it to set the value of meh. if we first execute meh, it will return an undefined value. because the setter closure appended in the function { created was not evaluated it. ```oh meh ``` Returns undefined on the stack. ```oh 24 set-meh eval ``` Now set-meh pushes the function { created on the stack and eval executes it, evaluating the setter closure that was appended to it which will take the 24 value on the stack nd set it to the associated variable so now. ```oh meh ``` Will return 24 We can reuse the setter to keep modifying the value of meh. ```oh 3 set-meh meh ``` Now returns 3 Remember top level colon : definitions reset the temporary dictionary Any other word that compiles does not reset the temporary dictionary. So at the top level ```oh : oh ; ``` Will reset the temporary words after compilation (even if it's an empty word) ```oh { } ``` Will never reset the temporary words, neither any other word that compiles code. Now let's play with strings. You have seen the word print, which is obvious. The forth word ." exists in this language, which prints a string. ```oh ." Hello, World!" cr ``` You know what it does. There is a way to push a string on the stack with the " word ```oh " Hello, World!" print cr ``` Notice that there is a space between ." and " because the reader reads words separated by spaces so if you were doing something like: ```oh "Hello, World!" ``` The interpreter will read that as two words: "Hello. and World!" Which is likely to be an error. Just remember to use spaces, everything in this language is a word delimited by spaces or newlines. Strings have interpolation of values at runtime. ```oh 1 2 + ." The sum of one and two is: ~a" cr ``` The ~a directive inserts an element from the stack into the string. The ~{ }~ directive will evaluate arbitrary code and insert an element from the stack. ```oh ." The sum of one and two is: ~{1 2 +}~" ``` An empty ~{}~ directive will have the same effect of the ~a directive since it will evaluate empty code and then get an element from the stack. Both " and ." support such string interpolation. That interpolation will be compiled as some sort of template and produced at runtime if " or ." are inside a definition. ```oh : oh ." The value is: ~a" cr ; 24 oh ``` prints The value is: 24 ```oh 3 oh ``` prints The value is: 3 Same with the ~{}~ directive. ```oh : oh dup ." The sum of ~a with 3 is: ~{3 +}~" cr ; 24 oh ``` prints The sum of 24 with 3 is: 27 ```oh 3 oh ``` prints The sum of 24 with 3 is: 6 Now for creating lists we have to ways. One is actually perl's qw// operator. It just reads words until a delimiter and pushes a list on the stack. ```oh qw / oh my cat / ``` pushes ['oh', 'my', 'cat'] on the stack. qw allows you to choose the delimiter. ```oh qw ( 1 2 3 ) qw [ 1 2 3 ] qw a 1 2 3 a qw AaAa aaaa Aaaa AaaA AaAa ``` The delimiter is case sensitive and it can be any word. The qw word reads a word from the source code and takes it as the delimiter. Then it keeps reading until it finds that delimiter. If the delimiter is: [ { ( or < it will look for the closing symbol instead: ] } ) or > Note that qw quotes words into strings, so numbers inside it will be taken as strings. If you try to do something like: ```oh qw ( 1 2 3 ) bind oh oh.0 oh.1 + ``` Will trigger an error because the contents of oh all are strings and + refuses to sum strings because it likes sanity or something. And yes, the dot notation is like in js, oh.0 means evaluate oh, then get an element frorm the stack (the list oh pushes) and access the 0th value of that element. To set the elements of the array we append ! to the dot notation. ```oh 24 oh.0! ``` Now the first element is 24 The dot notation can also work with existing objects on the stack. ```oh qw ( 1 2 3 ) .0 ``` Will push the first element of the object that was on the stack (which was the list created by qw) The dot notation allows for nested chains, just like in js. We could do: ```oh oh.0.1.0.0 ``` If oh had such a number of nested lists. The dot notation works with objects too. Now qw is not for creating lists, but for quoting words, it creates a list of strings and that's it. For creating lists we have the word list, which also allows us to choose the delimiter in the same way qw does. ```oh list ( 1 2 3 ) ``` This time the numbers of the list will be js numbers, not strings, so we can sum them. ```oh list ( 1 2 3 ) bind oh oh.0 oh.1 + ``` This will work fine. The word list has some value interpolation: ```oh 1 2 3 list ( , , , ) ``` This will return [3,2,1] The comma is a special syntax for list that will insert one element from the stack into the list. The comma can also be together with a word name, then this word will be evaluated and one element will be inserted from the stack. ```oh : oh 1 ; list ( ,oh ) ``` returns [1] note that strings inside list are strings, just that if the element is a number it will get it's proper number type unlike with qw lists since qw only quotes words. If a list is compiled, the list interpolation will happen at runtime. ```oh : oh list ( , ) ; ``` The word list when executed at compile time it will generate some sort of template like " and ." do with string interpolation. ```oh 1 oh ``` returns [1] ```oh 3 oh ``` returns [3] If a string with string interpolation is inside a list, list will defer that interpolation for runtime too. Note that list only accepts " but not ." ```oh : oh list ( " The value is: ~a" ) ; 24 oh ``` returns ['The value is: 24'] ```oh 3 oh ``` returns ['The value is: 3'] It will also work with ~{}~ string interpolation for arbitrary code. ```oh : oh dup list ( " The value ~a plus 3 is: ~{3 +}~" ) ; 24 oh ``` returns ['The value 24 plus 3 is: 27'] Lists can be nested: ```oh list ( 1 2 3 list { 4 5 6 } ) ``` returns [1, 2, 3, [4, 5, 6]] Now if they have interpolation, the innermost lists will be interpolated first. ```oh 1 2 list ( outer , list [ inner , ] ) ``` returns ['outer', 1, ['inner', 2]] There is also the object word, which creates js objects It also allows you to choose the delimiter. ```oh object { oh 1 meh 2 } object < oh 1 meh 2 > ``` They can also be inside lists. ```oh list ( object { oh 1 meh 2 } ) ``` The word object does not have interpolation, but can execute { blocks and insert a value into the property. ```oh object { oh { 1 2 + } meh { 5 3 - } } object [ oh { 1 2 + } meh { 5 3 - } ] ``` Note that the { blocks are not tied with the delimiter you chose, they will always be { since they are actually the { word being evaluated. The objects also accept " like list does ```oh object { str " oh my cat" } ``` It also allows them to interpolate values and will also defer the interpolation to runtime. ```oh : oh object { str " The value is: ~a" } ; 24 oh ``` returns { str: 'The value is: 24' } Lists can also be inside objects. ```oh object { numbers list ( 1 2 3 ) } ``` returns { numbers: [1, 2, 3] } It allows for list interpolation, and will also defer it. ```oh : oh object { numbers list ( 1 , 3 ) } ; 2 oh ``` returns { numbers: [1, 2, 3] } The { blocks inside object will also be deferred. ```oh : oh object [ oh { 1 + } ] ; 2 oh ``` returns { oh: 3 } Now let's see the if word :D ```oh 1 2 + if 3 equal then ." It is tree" else ." It is not three" endif cr ``` The if word is an immediate word that compiles 3 chunks of code. The first part is the condition or test part, which is between if and then. The second is the code that will be executed if the condition is true. The third is the code that will be executed if the condition is false. At runtime the if word will evaluate the first part, the condition or test code. Then it will take an element from the stack, which will be what is tested to be true or false and depending on that the true or the false code will be evaluated. The condition or test part and the false or else part are optional. ```oh 1 if then ." Is true" endif ``` Since the if word evaluates the condition part and takes an element from the stack, if the conditionn part is empty it evaluates an empty block of code and takes an element from the stack anyways. This behavior allows the user to decide whether to encode logic into the condition or not. ```oh : is-three if 3 equal then ." Is three" else ." It is not three" endif cr ; 3 is-three 1 is-three ``` Due to the concatenative aspect of a stack based language, we can add the condition code partially and get the rest from the stack. Just note that since if compiles code, temporary words are available and could also be defined there. ```oh : i-like-three : is-three? 3 equal ; : i-like-it ." oh..." cr ; : i'm-disappointed ." meh" cr ; if is-three? then i-like-it else i'm-disappointed endif ; ``` This example also shows the real purpose of temporary words. To help with creating very small units that get composed later. Now for simple and limited loops we have the words times and times* Those words are not immediate and instead take code and a number from the stack. ```oh { ." Hi" cr } 3 times ``` This will execute the function { returns 3 times The word times* does the same, but also pushes the loop index on the stack before evaluating the code at every iteration. ```oh { print } 3 times* ``` Will print: 0 1 2 Obviously they are quite limited, but they might prove useful several times. Now I think you are prepared to learn how to use variables. Variables are global and meant to store state for the program. The word bind is not meant to store values for a long time, although you could. The word bind is meant to help binding values from the stack to avoid stack juggling. This is why it creates temporary variables when inside a definition. To set a variable we have the words set and is. ```oh 24 set oh ``` This sets a variable named oh with the value 24 To get the value we can use get ```oh get oh ``` This pushes the value of the variable oh on the stack The word 'is' is similar to set, but also creates a word that will push the value on the stack with the same name as the variable ```oh 24 is oh ``` Now instead of using get oh we can just ```oh oh ``` And it will push the variable on the stack. Variables have hooks, whenever a variable is set using is or set, if the variable has hooks they will execute in reverse order. The last hooks created will run first. Hooks are just code attached to a variable that will trigger when it is set. They will receive the value of the variable on the stack. ```oh { ." The value is: ~a" } hook oh ``` Now we have registered a hook on the variable oh (the variable does not need to exist). Whenever the variable executes the code we have associated will run. ```oh 24 set oh ``` The variable oh is set to 24, the hook code executes and prints: ```oh The value is: 24 ``` We need to be able to remove a hook at any time. The word remove-hook takes a number from the stack and reads a name from the source code. The name is the variable name and the number the id of the hook. The id of the hook is it's index position in the list of hooks for that variable. If we know for sure the id of the hook, for example the first hook will have an id of 0, the second id of 1, etc. Then we can just give that number. ```oh 0 remove-hook oh ``` That will remove the first hook on the variable oh If we do not want to keep track of the ids, we can use the word hook* for setting a hook, is the same as the hook word, but returns the id on the stack. ```oh { ." The value is: ~a" } hook* oh ``` That will push the index of the hook on the stack, which we can save to give to remove-hook later.