aboutsummaryrefslogtreecommitdiff
path: root/src/parse.zig
diff options
context:
space:
mode:
authorMathias Magnusson <mathias@magnusson.space>2025-07-24 22:15:03 +0200
committerMathias Magnusson <mathias@magnusson.space>2025-07-24 22:17:19 +0200
commit0fa2f445eb7140214471074fc544adfd0f8a524f (patch)
treecb3bca4a9604df71cfe0cfcdb0c0f1e3590923ea /src/parse.zig
parentb3909efb3a6bf76870b686b5062f9a4282fbdd66 (diff)
downloadhuginn-0fa2f445eb7140214471074fc544adfd0f8a524f.tar.gz
continue implementing procedure calls
multiple procedures can now exist, but you cannot call them, the first one is the "main" procedure since it happens to be placed first in the binary, and all procedures end with an exit system call
Diffstat (limited to 'src/parse.zig')
-rw-r--r--src/parse.zig73
1 files changed, 60 insertions, 13 deletions
diff --git a/src/parse.zig b/src/parse.zig
index bd6b000..bd0ca46 100644
--- a/src/parse.zig
+++ b/src/parse.zig
@@ -23,6 +23,25 @@ pub fn fmt(tree: anytype, source: []const u8, indent: usize) Fmt(@TypeOf(tree))
return .{ .data = .{ tree, source, indent } };
}
+pub const File = struct {
+ decls: []Decl,
+
+ const Decl = struct {
+ loc: Lexer.Location,
+ inner: Stmt.Type.AssignVar,
+ };
+
+ fn format(self: File, writer: anytype, source: []const u8, indent: usize) !void {
+ for (self.decls) |decl| {
+ try writer.print("{s} {s} {}", .{
+ decl.inner.ident.getIdent(source),
+ ":=",
+ fmt(decl.inner.value, source, indent),
+ });
+ }
+ }
+};
+
pub const Block = struct {
loc: Lexer.Location,
stmts: []Stmt,
@@ -87,6 +106,7 @@ pub const Expr = struct {
call: Call,
identifier,
@"if": If,
+ proc: Proc,
pub const BinOp = struct {
lhs: *const Expr,
@@ -124,6 +144,10 @@ pub const Expr = struct {
then: Block,
@"else": ?Block,
};
+
+ pub const Proc = struct {
+ body: Block,
+ };
};
fn format(self: Expr, writer: anytype, source: []const u8, indent: usize) !void {
@@ -145,6 +169,9 @@ pub const Expr = struct {
try writer.print(" else {}", .{fmt(@"else", source, indent)});
}
},
+ .proc => |proc| {
+ try writer.print("proc() {}", .{fmt(proc.body, source, indent)});
+ },
}
}
};
@@ -157,22 +184,28 @@ const ParseError = error{
ExprStatementMustBeCall,
};
-pub fn file(allocator: Allocator, lexer: *Lexer) !Block {
- var stmts: std.ArrayList(Stmt) = .init(allocator);
+pub fn file(allocator: Allocator, lexer: *Lexer) !File {
+ var decls: std.ArrayList(File.Decl) = .init(allocator);
while (lexer.peek().type != .eof) {
- try stmts.append(try statement(allocator, lexer));
+ const stmt = try parseStatement(allocator, lexer);
+ if (stmt.type != .assign_var or !stmt.type.assign_var.is_decl) {
+ return error.ExpectedProcedureDeclaration;
+ }
+ try decls.append(.{
+ .loc = stmt.loc,
+ .inner = stmt.type.assign_var,
+ });
}
return .{
- .loc = stmts.items[0].loc.combine(stmts.getLast().loc),
- .stmts = try stmts.toOwnedSlice(),
+ .decls = try decls.toOwnedSlice(),
};
}
-fn block(allocator: Allocator, lexer: *Lexer) !Block {
+fn parseBlock(allocator: Allocator, lexer: *Lexer) !Block {
const left_curly = try mustEat(lexer, .left_curly);
var stmts: std.ArrayList(Stmt) = .init(allocator);
while (lexer.peek().type != .right_curly) {
- try stmts.append(try statement(allocator, lexer));
+ try stmts.append(try parseStatement(allocator, lexer));
}
const right_curly = try mustEat(lexer, .right_curly);
return .{
@@ -181,10 +214,10 @@ fn block(allocator: Allocator, lexer: *Lexer) !Block {
};
}
-fn statement(allocator: Allocator, lexer: *Lexer) ParseError!Stmt {
+fn parseStatement(allocator: Allocator, lexer: *Lexer) ParseError!Stmt {
switch (lexer.peek().type) {
.left_curly => {
- const b = try block(allocator, lexer);
+ const b = try parseBlock(allocator, lexer);
return .{
.loc = b.loc,
.type = .{ .block = b },
@@ -193,7 +226,7 @@ fn statement(allocator: Allocator, lexer: *Lexer) ParseError!Stmt {
.@"while" => {
const @"while" = lexer.next();
const cond = try expression(allocator, lexer);
- const do = try block(allocator, lexer);
+ const do = try parseBlock(allocator, lexer);
return .{
.loc = @"while".loc.combine(do.loc),
.type = .{ .@"while" = .{
@@ -232,7 +265,21 @@ fn statement(allocator: Allocator, lexer: *Lexer) ParseError!Stmt {
}
fn expression(allocator: Allocator, lexer: *Lexer) ParseError!*Expr {
- return parseComparisons(allocator, lexer);
+ return parseProc(allocator, lexer);
+}
+
+fn parseProc(allocator: Allocator, lexer: *Lexer) ParseError!*Expr {
+ if (lexer.peek().type != .proc) return parseComparisons(allocator, lexer);
+ const proc = try mustEat(lexer, .proc);
+ _ = try mustEat(lexer, .left_paren);
+ // TODO: parameters
+ _ = try mustEat(lexer, .right_paren);
+ const body = try parseBlock(allocator, lexer);
+
+ return allocate(Expr, allocator, .{
+ .loc = proc.loc.combine(body.loc),
+ .type = .{ .proc = .{ .body = body } },
+ });
}
fn parseComparisons(allocator: Allocator, lexer: *Lexer) ParseError!*Expr {
@@ -278,10 +325,10 @@ fn parseIf(allocator: Allocator, lexer: *Lexer) !*Expr {
.@"if" => {
const @"if" = lexer.next();
const cond = try expression(allocator, lexer);
- const then = try block(allocator, lexer);
+ const then = try parseBlock(allocator, lexer);
const @"else" = if (lexer.peek().type == .@"else") blk: {
_ = lexer.next();
- break :blk try block(allocator, lexer);
+ break :blk try parseBlock(allocator, lexer);
} else null;
return try allocate(Expr, allocator, .{
.loc = @"if".loc.combine((@"else" orelse then).loc),