lang
- 3 Devlogs
- 12 Total hours
creating a compiled language
creating a compiled language
Basic types, generics, function calls, and nested identifiers
Function calls are now parsed, and identifiers can be nested via dots and indices via brackets. I think I’ll have to reuse the same AST node used for function calls for enum fields carrying tuples when used in an expression other than enum itself.
I got a headache thinking about the type system with generics. It probably would’ve been easier if I drew a diagram before trying to implement them into the AST and parser. I got there eventually.
I have yet to add support for tuple and array types outside the AST interface/type definitions. Basic named types and generics are supported and parsed properly.
I should probably move all my type definitions for the AST to a new file so I don’t have to keep scrolling past a couple hundred lines every time I need to reference them.
Started AST and parser
I’ve been referencing the parser guide for Easel. It’s been quite useful.
I started working on this last night, but I got tired and paused without writing a journal. I made a git commit with the broken changes this morning.
So far, I’ve implemented basic parsing for variable and function declarations, literals, tuples, and expressions.
I spent quite a while trying to settle on values for operator precedence. I lost track of time testing things in the JS console and on the Rust playground website to see what made sense for precedence. Apparently 1..5==1..5 evaluates to 1..(5==1)..5, and 1&1+1 evaluates to 1&(1+1).
Like JS, Rust treats += as an expression instead of a statement, but it evaluates to () every time. Looking at Go, it supports the ++ operator, but doesn’t allow it to be used inside an expression. Language design is odd, but I like how everything fits together.
Initial blueprint, and a lexer.
Before I wrote any code, I spent a while brainstorming features I wanted in this language.
I wanted something with simple syntax and few keywords. There are currently 18 keywords. No keyword has more than four letters.
I have yet to reserve names for types. I might stick with something similar to Rust for naming types.
Declarations
val Value (immutable).
var Variable (mutable).
fn
enum I intend to support storing values inside, like Rust.
obj Equivalent to a struct in Rust.
type Type alias or an interface.
ext Like an impl block in Rust.
Conditional
if
else
cmp Similar to Rust’s match statement.
Flow
ret Return.
loop Overloaded loop operator. Go uses for, this uses loop.
jmp Depending on context, this replaces continue and goto (though I intend to add constraints like Go for memory safety).
drop Acts as a break statement, dropping out of a labeled loop or scope. May take a return value.
Misc
in Used for iteration.
use Import.
pub Export.
del Manually delete a variable (free memory).
I’m considering two more keywords for a macro system later on, but I’m not going to invest energy into that quite yet.
:: operator. It will all be ..-> instead of adding another keyword... prefixing a parameter name.I wrote a lexer for this with a bit of hacky TypeScript and RegExp. Don’t ask why it’s in TypeScript. I’m pretty sure I was half-asleep when I started this the other day, and it shouldn’t matter in the long run. If I can get this to transpile to C or something, I’ll bootstrap it.
For memory management, I don’t want a garbage collector. I don’t want Rust’s ownership system either. It would defeat the point of a simple language if you need to wrestle with the compiler so often. The current plan is to use RAII and manual freeing where needed. I’m considering an ARC hybrid with RAII or something later on, so memory management won’t be manual forever.