Forest "Hello world" tutorial

Apr 5, 2020 21:10 · 2384 words · 12 minute read object last time empty statement

Hi, I’m Philippe. I’m going to show you how to write “Hello world” in Forest, which is a tree editor for TypeScript. First head over to the Forest GitHub page and open the “Play with Forest” link. So what you’ll see is this big box on the screen, with these 2 little grey boxes in it. One of them is an empty folder, and the other one is an empty TypeScript file, which is a child of that folder. To navigate around this tree in Forest you use your arrow keys.

00:36 - So you press left to go up one level and right to go down to the next child. So lets first take a look at the program we want to write as text. As I said, we’re going to write “Hello world”. Specifically, console.log(“Hello world”). Writing this in a text editor is something you’ve done a million times before. You’re used to it. Writing this in a tree editor is a little different. I’m going to write out console.

log(“Hello world”) here first so you can get an idea 01:11 - of what it will look like, and then we’ll go through it step by step. So let me just write it out without explaining anything. Ok. So, here we have “console.log” “Hello world”. Let’s look at the structure in a little more detail. So maybe it’s a little clearer now how the tree is stacked up. On the left we have nodes which are higher up in the tree, and on the right we have stuff which is deeper and deeper into the tree.

01:47 - For example this node which says call is a child of the one which says “ExpressionStatement”. The call node has 4 children of its own. In the grey, these names describe what the child is relative to the parent. The rest of the text is just describing the child itself. At the bottom here we have the arguments to the function, and there could be multiple children under this, so multiple arguments. Here we have just one argument, which is this red string literal node.

02:24 - Red nodes in Forest are always literals (things like numbers, constant strings, stuff like that). If we go back up the tree, up to here, this thing labelled “expression” is the function that we’re going to call. Sometimes these labels aren’t very clear, because this is all pretty close to the TypeScript AST (the syntax tree of TypeScript). But you get the general idea, were calling “console log” here. So let’s take a look at the text version of this program in Forest.

02:56 - For that you need to open up your developer console (when you have an actual program written) and press 0 to see the code. So that’s something we’re going to use as we’re writing this code up step by step. Let me just reset the window here and start with an empty program, and we can write “console log” step by step. To start, navigate over to this “main.ts” node by pressing “right”. So now it’s highlighted in this grey - that’s the focused node. And down here you see different stuff you can do with this focused node.

03:37 - What we’re going to use is this action called “append”. Append adds a new child of some type to a node. Since this is a TypeScript file, it will add some kind of child that you could have in a TypeScript file. Let’s press “control-right” for append, and we’ll see it adds this thing called “EmptyStatement”. So what is that? If we look at a text version of this program, that would just be generated as a semicolon by itself on its own line, which is not really a program you usually write, but still a valid TypeScript program.

04:15 - So this is a default, and all the default is Forest currently are pretty unhelpful, but technically valid in terms of the type of node that they are. Usually you just want to switch them out straight away. The way we switch out this empty statement for something else is with the “setVariant” action. With your cursor focused on this empty statement, like this, press “v” to pull up the “setVariant” menu. It starts out with this prompt, which says something about shortcut keys. We don’t need those at the moment, so just press space to go to the search view. This is the search view, and you get this list of stuff, and these things are all things that you could put here instead of this empty statement. You have things like imports, for loops, if statements, things like that. What we want is a call. We want to call “console.log”. So if I search for “call” here I get no results, and there’s a reason for that. The reason is in the difference between statements and expressions.

05:35 - If you’ve never heard of statements vs expressions before, the difference is roughly just kind of a grouping. For example this is an import statement, as we usually say. And for example this is a string literal, which is an expression. This is a binary expression. And this function declaration here is a statement. So syntax is kind of grouped into these groups of expressions vs statements.

06:16 - And I said that this was an expression, but we can actually put it at the top level of a file and use it like a statement (the things at the top level of a file are statements). The reason we can do that is because TypeScript has this kind of adapter node called an “ExpressionStatement”. If you search for “ExpressionStatement” in this “setVariant” menu here, you’ll find it. Let’s press “enter” and place it into our tree to see how it looks. So the empty statement node has been replaced with an expression statement, and this expression statement now has a child of its own, which is the expression over here, which is specifically an empty string literal.

07:07 - Open up your developer console and press zero (down here) to print this program as a text program in the console. This thing over here is our whole program. It’s an empty string on its own line, which is a valid TypeScript program, but not a very useful one. The point of this is just to show you that you can print your program to the console (with zero) to take a look at it and better understand what you’ve made in the tree. We don’t need this string on its own line - we need a function call.

07:49 - Last time we tried to do that we pressed “setVariant” and we couldn’t find the function call in the list (over here), because the things we write under a TypeScript file are always statements. If you go over here though, in this position we have an expression, and if you press “v”to go into the “setVariant” menu, and space to go through to the search view, you’ll see that the list here is a little bit different. Now we have stuff we didn’t have before, like “ThisExpression”, “StringLiteral”, “BooleanLiteral”, stuff like that. These are all expressions, whereas stuff we had in this “setVariant” menu were all statements. Now we can find what we need, which is a function call. Press “enter” to select it.

08:33 - So again, you go to “setVariant”, you search for “CallExpression” and you press “enter”. Now we have a function call. I’m going to press zero to print this program. This is what we get as a printout. This is actually not a valid TypeScript program syntactically, because this tree doesn’t generate to a valid program at the moment. That usually happens when you’re using empty values in places where you aren’t really allowed to have them, but it’s still sometimes useful to understand what you’ve got in your tree, even if it’s not valid. These brackets here are actually the call brackets of a function call.

09:15 - So let’s start writing our “Hello world” call, and let’s start with the arguments, because it’s a little easier to explain that way. Use your arrow keys to navigate down to the arguments node. This is the parent of all the arguments to the function call. You see it has only one possible action - the “append”. Just like we did with the TypeScript file (we wanted to add something new to it), we pressed “control-right”. We do the same to this arguments list. Press “control-right” on the “arguments” node to get a new argument. This argument, at the moment, is an empty string. If you press zero you’ll see our function call with the single empty string being passed. We don’t want an empty string - we want the string “Hello world”. To get that, we can use this new action over here - “setFromString”.

10:04 - “setFromString” you can use on numbers, strings, names of stuff, to give them a value. Press “s” and you’ll get the prompt for a value down here. Type in “Hello world” and press “enter” to set the value. Now if you press zero you’ll see we have a function call without the name of the function we’re calling, but we’re passing the argument “Hello world” like we should be (as a string). Now lets go to the “console.log”. I’m going to do an in-between step here, and instead of doing a “console.

log” we’ll first 10:44 - do a “prompt”, and you’ll see why in a minute. Move up here to this node labelled “expression”. This is the name of the function we want to call, effectively (in this particular configuration). You’ll see it also has a “setFromString”, so let’s use that. Set from string using “s”, type “prompt” and press “enter”. Now if you press zero, you’ll see prompt(“Hello world”) in your console. So that’s actually a valid program, and it’s pretty close to console.log(“Hello world”), but not quite. So why did I show you a “prompt” first, instead of going straight to “console.log”? The reason is, they are syntactically a bit different. So whereas the “prompt” here is only highlighted with one color (it’s kind of one thing), and the “console.

log” is actually two sections (highlighted 11:47 - in two separate colors, with a dot in between). So it has a bit more structure than just a flat piece of text, and to generate a valid program in Forest we need to replicate that structure. You could actually “setFromString” on this and type “console.log”, and that will actually generate the right program, but that’s really just coincidence that it does. It’s not really valid to do it that way. So we have to actually replicate the correct tree structure in Forest.

12:22 - So I’m going to set this back to a “prompt”, and we’re going to change it (the whole expression over here) to be a property access, with the object “console” and the property “log”. Focus this expression node and press “setVariant” (“v”). Press “space” to get to the search menu, and in here you’ll see we have the list of stuff we had when we were choosing an expression for the call expression. One of these things is going to be a “PropertyAccessExpression”, so search for “property” until you find that, and select it. The tree will change to show something like this. This is another one of Forest’s weird defaults. Again it’s technically correct, even though it won’t generate a valid program, because we haven’t filled it out. I’m going to press zero and see what we have. We have these curly braces here, and then a dot, and then these kind of “call brackets” for the function call. This pair of curly brackets over here corresponds to this node - it’s an object literal.

13:37 - And the thing that’s missing between this dot and these call brackets corresponds to the name of the property we would have (but the name of this property is currently empty - that’s represented by this string over here). Let’s go set the name of the property first. Move over to this string and see we can use the “setFromString” on it? Press “s” and type “log” here. Now if you press zero, you’ll see the program is calling “log”on this empty object literal here, which syntactically is valid. Now we need to write “console.log”, so instead of using this empty object literal here, we want to reference an existing object (an existing value).

14:23 - The type of node you use to do that is an “Identifier”. Press “setVariant” when focused on this object literal to replace it with something else, press space to go into the search menu, and find an “Identifier”. An identifier is like a reference to a variable. So when you type a variable name (without quotes, without anything else, not after a dot, just by itself), that’s usually an identifier, syntactically. Press enter to choose the identifier, and you’ll get this blue box.

14:52 - Notice it’s the same blue that we had when we had the “prompt” back there, because the “prompt” was syntactically an identifier. This box is totally empty, because our identifier is empty at the moment. If you get the program you’ll get this - that’s actually where the identifier should go (before this dot). So press “s” when focused on this identifier (the blue one) to fill it out. Type “console”. That looks ok. Now press zero, and there we have it! “console.log” printed as text, written as a tree in Forest.

15:35 - So I know that was quite a lot, and I know it took a while to write (and explain how to write) this “console.log”. Writing stuff in a tree is pretty different from writing it in text, and Forest is also just a prototype, so a lot if this stuff isn’t working yet. But I’d really enjoy it if people tried Forest. Take a look at the other videos, try writing a simple thing in it, see what you think, and get a feel for this whole “tree editing” thing. Ok, so that’s it. See you! .