Ile
- 13 Devlogs
- 58 Total hours
Ile is an Interpreted Language for Extensions. It's an embedded scripting language with a Rust API. Oh, and it has no 3rd-party dependencies!
Ile is an Interpreted Language for Extensions. It's an embedded scripting language with a Rust API. Oh, and it has no 3rd-party dependencies!
I’ve been working on getting everything ready to ship, and I think it’s almost time! I’ve fixed some bugs, added more tests, published to crates.io, and created a GitHub release! Now, I’ll make sure I have good instructions in my README, and I’ll be ready to go!
I’ve been working on getting Ile ready to ship, and I had a small, significant feature to implement: scoping. This is basically when a function is called and uses the scope that it was a part of when it was created instead of the scope it was called in. This was hard.
To implement this, my first thought was write yet another lookup function to find the correct module’s stack and walk the function in the stack. Unfortunately, the compiler didn’t like this. I couldn’t get it done without having 2 different mutable references to the stack at the same time, so it was off the table. What I ended up going for was when a function is called, it clones (memory-efficient, amirite?!) its entire scope and walks inside it. After the function executes, it then sets the value of its module’s scope to the current value of the scope it just walked in, so as to update it with any changes. Makes sense, right? RIGHT?!
Anyway, there isn’t really a picture to show, so here’s tests passing.
I’m hoping to ship tomorrow, so I’m fixing up the language to be usable. I’ve been writing some documentation, so I have a little starter guide now. I also learned that Ile can use as little as one thirtieth the ram of Node.js! That’s definitely going in the features section.
I’ve been trying to add a GUI system to the standard library. Because I don’t want any dependencies, I came up with the following harebrained scheme:
stdin in a Tkinter window to draw a GUIpipe
Unfortunately, this doesn’t work. The script works when run on its own, but when run by Ile it just doesn’t launch a window. I couldn’t figure this out, so the GUI system (VeBaGu, or Very Bad GUI) is staying, albeit in an unstable beta state.
On a side note, I’ve also decided to ditch the editor idea and just focus on the language; this Stardance project is now just Ile, not Crocodile.
If you couldn’t tell, that was a play on “we have liftoff!”. I didn’t add a rocket emoji, for obvious reasons.
Anyway, I have great news: Ile is almost a usable language! Today, I added loops and operators, so it can iterate and do math now! My for loop is a tad different than other languages, so here’s the gist: every for loop has a condition and a block. Every iteration, the condition runs. If it returns something, the block runs. Otherwise, the loop exits. Because I made let statements return the value they assign, you can have syntax that looks like this:
for let x = iterator.next() {}
I’m really proud of how my syntax is turning out overall. There’s still not much to screenshot; I haven’t written the logic to interface with Rust, so there’s no println yet. I do have some more test coverage, though.
There was some difficulty getting break to work, however. For some reason, the loop it was a part of would always keep going. Eventually, I figured out why: It was being removed from the stack at the end of the code block that generated it. To fix this, I added some logic to re-push it to the stack if it got popped.
I just spent a frustratingly long amount of time figuring out why Rust didn’t like my lifetimes. I don’t even remember what I did to make it compile. This was fun.
However, after figuring that out, I wrote the walk methods for a few NodeTypes. Here’s the stack after a simple program finishes, and the program that was run:
I started work on the AST (abstract syntax tree) walking algorithm today. I didn’t get very far, but one of the things I did do was I fixed operator parsing.
Before, if you were to parse something like 15 > 5 && 5 < 10, it would have been a greater-than operator with a boolean operator as a child, and that doesn’t work. Therefore, I had to write some code to convert that broken operator into a boolean operator with mathematical children. The algorithm didn’t make much sense in my head, so I drew it out on paper and that made it pretty easy to write.
Below is the illustration I made and the code it became.
I wrote the parser, which takes the tokenized code and converts it into a usable, in-memory representation. After fixing the bugs from yesterday, I wrote some logic to parse a function block and the rest of the syntax was easy. Running main.rs now prints out a representation of a parsed AST. Now all I have to do is:
The first image is some example Ile code, and the second is some of the AST that is generated from it.
I made a very basic AST parser! The AST (abstract syntax tree) is the in-memory representation of the code as a tree. This took a really long time. My machine froze and my interpreter produced incomprehensible errors about wanting a word token, but in the end cargo test passed, so I’m happy.
It also doesn’t support anything other than function calls, but this is a great first step in creating an actually walkable AST.
I started work on the AST builder. I decided that the algorithm will use delimiters to decide which tokens correspond to which AST node and I’m working on a method for Node that determines how to add a child based on the Node‘s type and the child’s type.
The screenshot is some of the code for Node.
I’ve been focusing on the scripting language, Ile, because to be honest the editor is the boring part. So far, I have project structure and some fundamentals–I’ve written the tokenizer and some stack-switching logic. For those who don’t know, the tokenizer is responsible for taking a blob of (hopefully) human-readable source code and converting it into tokens, which are used later on to build an abstract syntax tree. For now, all I’m concerned about is that cargo test passes!