From 7531b352fe3683bc2e720133bff396d5216090bb Mon Sep 17 00:00:00 2001 From: Sublime Tshimpangila Date: Fri, 10 Jul 2026 13:48:13 -0400 Subject: [PATCH 01/10] add example for a simple if statement --- examples/if.sub | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 examples/if.sub diff --git a/examples/if.sub b/examples/if.sub new file mode 100644 index 0000000..b684910 --- /dev/null +++ b/examples/if.sub @@ -0,0 +1,13 @@ +fn main() void { + print("Helloworld", "maman", "Harold", "Reese",); + fn_call("I like to play with people"); + var sub: i32 = "Bonjour"; + if "bonjour" { + print("in if statement"); + foo("in foo statement"); + if "maman" { + bar("foo", "bar", "baz",); + bar("abc", "cde", "fgh",); + } + } +} From e57807b4cbaef8741314a938c815db26f4a8ec6f Mon Sep 17 00:00:00 2001 From: Sublime Tshimpangila Date: Fri, 10 Jul 2026 13:48:44 -0400 Subject: [PATCH 02/10] add parsing and printing of simple if statements --- src/ast.zig | 57 ++++++++++++++++++++++++++++++++++++++------------ src/main.zig | 12 +++++++---- src/parser.zig | 31 +++++++++++++++++++++------ 3 files changed, 77 insertions(+), 23 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index 61ec513..2569544 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -13,7 +13,7 @@ pub const Ast = struct { pub fn print(ast: Ast) void { for (ast.decls.items) |decl| { - decl.print(); + decl.print(0); std.debug.print("\n\n", .{}); } } @@ -43,9 +43,9 @@ pub const ProgramDecl = union(ProgramDeclTag) { } }; } - pub fn print(self: Self) void { + pub fn print(self: Self, nindent: usize) void { switch (self) { - .fn_decl => |fn_decl| fn_decl.print(), + .fn_decl => |fn_decl| fn_decl.print(nindent), } } }; @@ -58,20 +58,20 @@ const FnDecl = struct { body: std.ArrayList(Stmt), return_type: []const u8, - pub fn print(self: Self) void { + pub fn print(self: Self, indent: usize) void { + print_nindent(indent); std.debug.print("fn {s}(", .{self.name}); for (self.args.items) |arg| { std.debug.print("{s}, ", .{arg}); } std.debug.print(") {s} {{\n", .{self.return_type}); - const indent = 1; for (self.body.items) |stmt| { - print_nindent(indent); - stmt.print(); + stmt.print(indent + 1); } + print_nindent(indent); std.debug.print("}}", .{}); } }; @@ -147,6 +147,7 @@ const VarDeclExpr = struct { const StmtTag = enum { assign, no_assign, + if_, }; //////////// Stmt structs @@ -155,6 +156,7 @@ pub const Stmt = union(StmtTag) { assign: AssignStmt, no_assign: NoAssignStmt, + if_: IfStmt, pub fn create_assign(var_: ?[]const u8, value: Expr) Stmt { return .{ .assign = .{ @@ -163,10 +165,18 @@ pub const Stmt = union(StmtTag) { } }; } - pub fn print(self: Self) void { + pub fn create_if(if_eval: Expr, if_body: std.ArrayList(Stmt)) Stmt { + return .{ .if_ = .{ + .if_eval = if_eval, + .if_body = if_body, + }}; + } + + pub fn print(self: Self, indent: usize) void { switch (self) { - .assign => |assign| assign.print(), - .no_assign => |no_assign| no_assign.print(), + .assign => |assign| assign.print(indent), + .no_assign => |no_assign| no_assign.print(indent), + .if_ => |if_| if_.print(indent), } std.debug.print(";\n", .{}); } @@ -179,7 +189,8 @@ const AssignStmt = struct { type_: []const u8, value: Expr, - pub fn print(self: Self) void { + pub fn print(self: Self, indent: usize) void { + print_nindent(indent); std.debug.print("var {s}: {s} = ", .{ self.var_, self.type_ }); self.value.print(); } @@ -189,13 +200,33 @@ const NoAssignStmt = struct { const Self = @This(); value: Expr, - pub fn print(self: Self) void { + pub fn print(self: Self, indent: usize) void { + print_nindent(indent); self.value.print(); } }; +const IfStmt = struct { + const Self = @This(); + + if_eval: Expr, + if_body: std.ArrayList(Stmt), + + pub fn print(self: Self, indent: usize) void { + print_nindent(indent); + std.debug.print("if ", .{}); + self.if_eval.print(); + std.debug.print(" {{\n", .{}); + for (self.if_body.items) |stmt| { + stmt.print(indent + 1); + } + print_nindent(indent); + std.debug.print("}}", .{}); + } +}; + fn print_nindent(n: usize) void { for (0..n) |_| { - std.debug.print(" ", .{}); + std.debug.print(" ", .{}); } } diff --git a/src/main.zig b/src/main.zig index 734ccfb..af46282 100644 --- a/src/main.zig +++ b/src/main.zig @@ -9,13 +9,17 @@ const Parser = parser_pkg.Parser; const LIMIT = 1024 * 10; +const assert = std.debug.assert; + pub fn main(init: std.process.Init) !void { - _ = ast_pkg; - const io = init.io; const alloc = std.heap.page_allocator; + const args = try init.minimal.args.toSlice(alloc); + assert(args.len == 2); + const io = init.io; + const current_dir = std.Io.Dir.cwd(); - const file_path = "examples/helloworld.sub"; + const file_path = args[1]; const content: []const u8 = try current_dir.readFileAlloc( io, file_path, @@ -25,7 +29,7 @@ pub fn main(init: std.process.Init) !void { var l = Lexer.init( content, - "main.sub", + file_path, ); var parser = Parser.init(&l, alloc); const ast = try parser.parse(); diff --git a/src/parser.zig b/src/parser.zig index 6bcea42..21dd4c0 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -80,19 +80,25 @@ pub const Parser = struct { while (l.token != .cbrace) { const stmt = try parse_stmt(l, alloc); try body.append(alloc, stmt); - l.eat(.semicolon); + // l.eat(.semicolon); } l.eat(.cbrace); return ProgramDecl.create_fn(id, args, body, return_type); } - fn parse_stmt(l: *Lexer, alloc: Allocator) !Stmt { + fn parse_stmt(l: *Lexer, alloc: Allocator) error{OutOfMemory}!Stmt { if (l.token == .var_) { // var declaration - return parse_var_decl_stmt(l, alloc); + const stmt = parse_var_decl_stmt(l, alloc); + l.eat(.semicolon); + return stmt; + } else if (l.token == .if_) { + return parse_if_stmt(l, alloc); } else { - return parse_no_var_decl_stmt(l, alloc); + const stmt = parse_no_var_decl_stmt(l, alloc); + l.eat(.semicolon); + return stmt; } } @@ -119,6 +125,20 @@ pub const Parser = struct { } }; } + fn parse_if_stmt(l: *Lexer, alloc: Allocator) !Stmt { + l.eat(.if_); + const if_eval = try parse_expr(l, alloc); + l.eat(.obrace); + var if_body: std.ArrayList(Stmt) = .empty; + while (l.token != .cbrace) { + const stmt = try parse_stmt(l, alloc); + try if_body.append(alloc, stmt); + // l.eat(.semicolon); + } + l.eat(.cbrace); + return Stmt.create_if(if_eval, if_body); + } + fn parse_expr(l: *Lexer, alloc: Allocator) error{OutOfMemory}!Expr { if (l.token == .id) { const next_l = l.nextl(); @@ -128,8 +148,7 @@ pub const Parser = struct { } } else if (l.token == .str) { return parse_str(l); - } - + } panic("parse_expr panics with {}, name: {s}", .{ l.token, l.name.as_str(l.content) }); } From cba2f4c34d74e40d06b307b391075e5e8dc680c4 Mon Sep 17 00:00:00 2001 From: Sublime Tshimpangila Date: Fri, 10 Jul 2026 13:49:26 -0400 Subject: [PATCH 03/10] zig fmt . --- src/ast.zig | 2 +- src/parser.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index 2569544..440889e 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -169,7 +169,7 @@ pub const Stmt = union(StmtTag) { return .{ .if_ = .{ .if_eval = if_eval, .if_body = if_body, - }}; + } }; } pub fn print(self: Self, indent: usize) void { diff --git a/src/parser.zig b/src/parser.zig index 21dd4c0..4cca3e6 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -148,7 +148,7 @@ pub const Parser = struct { } } else if (l.token == .str) { return parse_str(l); - } + } panic("parse_expr panics with {}, name: {s}", .{ l.token, l.name.as_str(l.content) }); } From b214bba24178f86cc191a5da80dd7fa98a918a81 Mon Sep 17 00:00:00 2001 From: Sublime Tshimpangila Date: Fri, 10 Jul 2026 14:24:26 -0400 Subject: [PATCH 04/10] update if.sub example --- examples/if.sub | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/examples/if.sub b/examples/if.sub index b684910..5b0a848 100644 --- a/examples/if.sub +++ b/examples/if.sub @@ -1,13 +1,17 @@ fn main() void { - print("Helloworld", "maman", "Harold", "Reese",); - fn_call("I like to play with people"); - var sub: i32 = "Bonjour"; - if "bonjour" { - print("in if statement"); - foo("in foo statement"); - if "maman" { - bar("foo", "bar", "baz",); - bar("abc", "cde", "fgh",); + print("Helloworld", "maman", "Harold", "Reese",); + fn_call("I like to play with people"); + var sub: i32 = "Bonjour"; + if "bonjour" { + print("in if statement"); + foo("in foo statement"); + if "maman" { + bar("foo", "bar", "baz",); + var inner_var: Foo = "bonsoir"; + } elseif "else_expr" { + fn_else("in_fn_else",); + } + } elseif "else_if_expr" { + bazz("in bazz"); } - } } From c766b6e9a35686bed5c7fb5ee1cd7e5d4704cc12 Mon Sep 17 00:00:00 2001 From: Sublime Tshimpangila Date: Fri, 10 Jul 2026 14:29:12 -0400 Subject: [PATCH 05/10] add parsing of elseif in if statements --- src/ast.zig | 19 ++++++++++++++++++- src/parser.zig | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index 440889e..5d61f0f 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -165,10 +165,21 @@ pub const Stmt = union(StmtTag) { } }; } - pub fn create_if(if_eval: Expr, if_body: std.ArrayList(Stmt)) Stmt { + pub fn create_if( + if_eval: Expr, + if_body: std.ArrayList(Stmt), + elseif_evals: std.ArrayList(Expr), + elseif_thens: std.ArrayList(std.ArrayList(Stmt)), + else_eval: ?Expr, + else_then: ?std.ArrayList(Stmt), + ) Stmt { return .{ .if_ = .{ .if_eval = if_eval, .if_body = if_body, + .elseif_evals = elseif_evals, + .elseif_thens = elseif_thens, + .else_eval = else_eval, + .else_then = else_then, } }; } @@ -212,6 +223,12 @@ const IfStmt = struct { if_eval: Expr, if_body: std.ArrayList(Stmt), + elseif_evals: std.ArrayList(Expr), + elseif_thens: std.ArrayList(std.ArrayList(Stmt)), + + else_eval: ?Expr, + else_then: ?std.ArrayList(Stmt), + pub fn print(self: Self, indent: usize) void { print_nindent(indent); std.debug.print("if ", .{}); diff --git a/src/parser.zig b/src/parser.zig index 4cca3e6..82759ef 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -128,15 +128,44 @@ pub const Parser = struct { fn parse_if_stmt(l: *Lexer, alloc: Allocator) !Stmt { l.eat(.if_); const if_eval = try parse_expr(l, alloc); - l.eat(.obrace); var if_body: std.ArrayList(Stmt) = .empty; + l.eat(.obrace); while (l.token != .cbrace) { const stmt = try parse_stmt(l, alloc); try if_body.append(alloc, stmt); - // l.eat(.semicolon); } l.eat(.cbrace); - return Stmt.create_if(if_eval, if_body); + var elseif_evals: std.ArrayList(Expr) = .empty; + var elseif_thens: std.ArrayList(std.ArrayList(Stmt)) = .empty; + + std.debug.print("token is {}\n", .{l.token}); + while (l.token == .elseif) { + // std.debug.print("In while {}\n", .{l.token}); + l.eat(.elseif); + const eval = try parse_expr(l, alloc); + + // std.debug.print("else if cond: \n", .{}); + // eval.print(); + var then: std.ArrayList(Stmt) = .empty; + l.eat(.obrace); + while (l.token != .cbrace) { + const stmt = try parse_stmt(l, alloc); + try then.append(alloc, stmt); + } + l.eat(.cbrace); + try elseif_evals.append(alloc, eval); + try elseif_thens.append(alloc, then); + } + // std.debug.print("token AFTER is {}\n", .{l.token}); + + return Stmt.create_if( + if_eval, + if_body, + elseif_evals, + elseif_thens, + null, + null, + ); } fn parse_expr(l: *Lexer, alloc: Allocator) error{OutOfMemory}!Expr { From 4614ce700b7e0fbaf9df7eeba44dce13e7ce768e Mon Sep 17 00:00:00 2001 From: Sublime Tshimpangila Date: Fri, 10 Jul 2026 14:41:03 -0400 Subject: [PATCH 06/10] add print for elseif statements --- src/ast.zig | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/ast.zig b/src/ast.zig index 5d61f0f..e05ed73 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -1,6 +1,7 @@ const std = @import("std"); const panic = std.debug.panic; +const assert = std.debug.assert; //////////// Program Block @@ -239,6 +240,23 @@ const IfStmt = struct { } print_nindent(indent); std.debug.print("}}", .{}); + + assert(self.elseif_evals.items.len == self.elseif_thens.items.len); + for (0..self.elseif_evals.items.len) |i| { + const eval = self.elseif_evals.items[i]; + const then = self.elseif_thens.items[i]; + + // print_nindent(indent); + std.debug.print(" elseif ", .{}); + eval.print(); + std.debug.print(" {{\n", .{}); + + for (then.items) |then_stmt| { + then_stmt.print(indent + 1); + } + print_nindent(indent); + std.debug.print("}}", .{}); + } } }; From 5fa225ae12f5e67368b6c7a56a291439f448342e Mon Sep 17 00:00:00 2001 From: Sublime Tshimpangila Date: Fri, 10 Jul 2026 14:57:32 -0400 Subject: [PATCH 07/10] update if.sub example --- examples/if.sub | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/if.sub b/examples/if.sub index 5b0a848..256b7e0 100644 --- a/examples/if.sub +++ b/examples/if.sub @@ -11,7 +11,10 @@ fn main() void { } elseif "else_expr" { fn_else("in_fn_else",); } - } elseif "else_if_expr" { + } elseif best("else_if_expr") { bazz("in bazz"); + fuzz("in bazz"); + } else cond("else_expr") { + var else_inner: f32 = "for now, expr can just be strings"; } } From 7bdc6ca9810770612d3019a7fe278abbb18716ad Mon Sep 17 00:00:00 2001 From: Sublime Tshimpangila Date: Fri, 10 Jul 2026 14:57:57 -0400 Subject: [PATCH 08/10] add else in parser.zig --- src/ast.zig | 3 +-- src/parser.zig | 29 ++++++++++++++++++++--------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index e05ed73..639d8a8 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -246,11 +246,10 @@ const IfStmt = struct { const eval = self.elseif_evals.items[i]; const then = self.elseif_thens.items[i]; - // print_nindent(indent); std.debug.print(" elseif ", .{}); eval.print(); std.debug.print(" {{\n", .{}); - + for (then.items) |then_stmt| { then_stmt.print(indent + 1); } diff --git a/src/parser.zig b/src/parser.zig index 82759ef..7786f6a 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -137,15 +137,11 @@ pub const Parser = struct { l.eat(.cbrace); var elseif_evals: std.ArrayList(Expr) = .empty; var elseif_thens: std.ArrayList(std.ArrayList(Stmt)) = .empty; - - std.debug.print("token is {}\n", .{l.token}); + while (l.token == .elseif) { - // std.debug.print("In while {}\n", .{l.token}); l.eat(.elseif); const eval = try parse_expr(l, alloc); - - // std.debug.print("else if cond: \n", .{}); - // eval.print(); + var then: std.ArrayList(Stmt) = .empty; l.eat(.obrace); while (l.token != .cbrace) { @@ -156,15 +152,30 @@ pub const Parser = struct { try elseif_evals.append(alloc, eval); try elseif_thens.append(alloc, then); } - // std.debug.print("token AFTER is {}\n", .{l.token}); + + var else_eval: ?Expr = null; + var else_then: ?std.ArrayList(Stmt) = null; + + std.debug.print("HERE : {}\n", .{l.token}); + if (l.token == .else_) { + l.eat(.else_); + else_eval = try parse_expr(l, alloc); + l.eat(.obrace); + else_then = .empty; + while (l.token != .cbrace) { + const stmt = try parse_stmt(l, alloc); + try else_then.?.append(alloc, stmt); + } + l.eat(.cbrace); + } return Stmt.create_if( if_eval, if_body, elseif_evals, elseif_thens, - null, - null, + else_eval, + else_then, ); } From 3b2bf030b92d9fd28771af07ac34e67904e5a0f8 Mon Sep 17 00:00:00 2001 From: Sublime Tshimpangila Date: Fri, 10 Jul 2026 15:07:12 -0400 Subject: [PATCH 09/10] update parsing of else stmts --- examples/if.sub | 4 +++- src/ast.zig | 14 +++++++++++--- src/parser.zig | 4 ---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/examples/if.sub b/examples/if.sub index 256b7e0..01d3d48 100644 --- a/examples/if.sub +++ b/examples/if.sub @@ -10,11 +10,13 @@ fn main() void { var inner_var: Foo = "bonsoir"; } elseif "else_expr" { fn_else("in_fn_else",); + } else { + print("without condition"); } } elseif best("else_if_expr") { bazz("in bazz"); fuzz("in bazz"); - } else cond("else_expr") { + } else { var else_inner: f32 = "for now, expr can just be strings"; } } diff --git a/src/ast.zig b/src/ast.zig index 639d8a8..9dbba55 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -171,7 +171,6 @@ pub const Stmt = union(StmtTag) { if_body: std.ArrayList(Stmt), elseif_evals: std.ArrayList(Expr), elseif_thens: std.ArrayList(std.ArrayList(Stmt)), - else_eval: ?Expr, else_then: ?std.ArrayList(Stmt), ) Stmt { return .{ .if_ = .{ @@ -179,7 +178,6 @@ pub const Stmt = union(StmtTag) { .if_body = if_body, .elseif_evals = elseif_evals, .elseif_thens = elseif_thens, - .else_eval = else_eval, .else_then = else_then, } }; } @@ -227,7 +225,6 @@ const IfStmt = struct { elseif_evals: std.ArrayList(Expr), elseif_thens: std.ArrayList(std.ArrayList(Stmt)), - else_eval: ?Expr, else_then: ?std.ArrayList(Stmt), pub fn print(self: Self, indent: usize) void { @@ -256,6 +253,17 @@ const IfStmt = struct { print_nindent(indent); std.debug.print("}}", .{}); } + + if (self.else_then != null) { + const else_then = self.else_then.?; + + std.debug.print(" else {{\n", .{}); + for (else_then.items) |then_stmt| { + then_stmt.print(indent + 1); + } + print_nindent(indent); + std.debug.print("}}", .{}); + } } }; diff --git a/src/parser.zig b/src/parser.zig index 7786f6a..b2bc2b8 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -153,13 +153,10 @@ pub const Parser = struct { try elseif_thens.append(alloc, then); } - var else_eval: ?Expr = null; var else_then: ?std.ArrayList(Stmt) = null; - std.debug.print("HERE : {}\n", .{l.token}); if (l.token == .else_) { l.eat(.else_); - else_eval = try parse_expr(l, alloc); l.eat(.obrace); else_then = .empty; while (l.token != .cbrace) { @@ -174,7 +171,6 @@ pub const Parser = struct { if_body, elseif_evals, elseif_thens, - else_eval, else_then, ); } From 22077b44b543211d40a367d3fb24dac487fd316c Mon Sep 17 00:00:00 2001 From: Sublime Tshimpangila Date: Fri, 10 Jul 2026 15:12:05 -0400 Subject: [PATCH 10/10] fix trailing comma after if statements --- src/ast.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ast.zig b/src/ast.zig index 9dbba55..6d8834b 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -188,7 +188,7 @@ pub const Stmt = union(StmtTag) { .no_assign => |no_assign| no_assign.print(indent), .if_ => |if_| if_.print(indent), } - std.debug.print(";\n", .{}); + std.debug.print("\n", .{}); } }; @@ -203,6 +203,7 @@ const AssignStmt = struct { print_nindent(indent); std.debug.print("var {s}: {s} = ", .{ self.var_, self.type_ }); self.value.print(); + std.debug.print(";", .{}); } }; @@ -213,6 +214,7 @@ const NoAssignStmt = struct { pub fn print(self: Self, indent: usize) void { print_nindent(indent); self.value.print(); + std.debug.print(";", .{}); } };