diff options
author | Mathias Magnusson <mathias@magnusson.space> | 2025-07-24 22:15:03 +0200 |
---|---|---|
committer | Mathias Magnusson <mathias@magnusson.space> | 2025-07-24 22:17:19 +0200 |
commit | 0fa2f445eb7140214471074fc544adfd0f8a524f (patch) | |
tree | cb3bca4a9604df71cfe0cfcdb0c0f1e3590923ea /src/parse.zig | |
parent | b3909efb3a6bf76870b686b5062f9a4282fbdd66 (diff) | |
download | huginn-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.zig | 73 |
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), |