Obsidian v1 updates Devlog
What’s new?
Finally got basic lambda style return functions working.
Right now these both compile all the way through the tokenizer, IR, NASM generation, and actually run correctly:
func test() -> int {2 + 2};
func anothertest() -> int {2 - 2};
test currently spits out:
mov eax, 2
mov ebx, 2
add eax, ebx
ret
So the entire pipeline is finally working end to end.
Syntax change
I ended up changing the function syntax halfway through development.
Originally it looked like this:
func test() -> { 2 + 2 }
The problem is -> was basically trying to do two different jobs at once. It was acting like “here comes the function body” instead of what it should actually mean: “here comes the return type.”
That would’ve forced the parser to guess whether the next token was a type or the start of a block, which is just unnecessary pain when the fix is simple.
Now it’s:
func name() -> type { body }
Way cleaner, no ambiguity, and honestly it reads a lot better too.
Under the hood
Parentheses are now their own tokens (_OPEN_PAREN / _CLOSE_PAREN) instead of getting lumped together with braces.
Expressions are currently evaluated by folding left-to-right through (operator, operand) pairs.
+, -, *, and / all work with integer literals.
One limitation right now is there’s no operator precedence yet.
So:
2 + 3 * 4
currently evaluates as:
((2 + 3) * 4) = 20
instead of:
2 + (3 * 4) = 14
Not really a bug, just something I haven’t implemented yet. The real fix is building an expression tree instead of another parser hack.
Right now everything also assumes the operands are integer literals. Variables aren’t hooked into expression evaluation yet, so identifiers basically don’t work inside expressions.
Function bodies are also limited to a single expression for now no multiple statements or nested expressions yet.
Next up
- Proper operator precedence (expression trees)
- Variables inside expressions
- Multi-statement function bodies
- Saving/restoring non-volatile registers once functions start calling other functions. Right now I’m using ebx as a scratch register, which is perfectly fine for leaf functions but won’t fly forever once function calls exist.
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.