From 1225049f76568edb76e2abd98a8149d31b7bfaa8 Mon Sep 17 00:00:00 2001 From: Fernando Araoz Date: Sat, 14 Dec 2024 06:24:13 -0500 Subject: [PATCH] feat: minimal parsing of statements --- CHANGELOG.md | 6 ++-- build.zig | 1 + src/02_syntax/statement.zig | 56 +++++++++++++++++++++++++++++++++++++ src/02_syntax/variable.zig | 10 +++---- 4 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 src/02_syntax/statement.zig diff --git a/CHANGELOG.md b/CHANGELOG.md index e3e6abf..b9983b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,8 +31,8 @@ Now in Zig! - [x] Lex single line comments - [x] Lex strings - [x] Lex grouping signs -- [ ] - - +- [x] Parse minimal expression +- [x] Parse minimal variable binding +- [x] Parse minimal statement diff --git a/build.zig b/build.zig index 1205135..32db097 100644 --- a/build.zig +++ b/build.zig @@ -94,6 +94,7 @@ pub fn build(b: *std.Build) void { "src/02_syntax/root.zig", "src/02_syntax/variable.zig", "src/02_syntax/expression.zig", + "src/02_syntax/statement.zig", }; for (files) |file| { const file_unit_test = b.addTest(.{ diff --git a/src/02_syntax/statement.zig b/src/02_syntax/statement.zig new file mode 100644 index 0000000..ecb5a3a --- /dev/null +++ b/src/02_syntax/statement.zig @@ -0,0 +1,56 @@ +const std = @import("std"); +const lexic = @import("lexic"); +const expression = @import("expression.zig"); +const types = @import("./types.zig"); +const utils = @import("./utils.zig"); +const variable = @import("./variable.zig"); + +const TokenStream = types.TokenStream; +const ParseError = types.ParseError; + +pub const Statement = union(enum) { + VariableBinding: *variable.VariableBinding, + + fn init(target: *Statement, tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!void { + // try to parse a variable definition + + var vardef: variable.VariableBinding = undefined; + var parse_failed = false; + vardef.init(tokens, pos, allocator) catch |err| switch (err) { + error.Unmatched => { + parse_failed = true; + }, + else => { + return err; + }, + }; + if (!parse_failed) { + // return the parsed variable definition + target.* = .{ + .VariableBinding = &vardef, + }; + return; + } + + // fail + return ParseError.Unmatched; + } + + fn deinit(self: @This()) void { + switch (self) { + .VariableBinding => |v| v.deinit(), + } + } +}; + +test "should parse a variable declaration statement" { + const input = "var my_variable = 322"; + const tokens = try lexic.tokenize(input, std.testing.allocator); + defer tokens.deinit(); + + var statement: Statement = undefined; + try statement.init(&tokens, 0, std.testing.allocator); + defer statement.deinit(); + + // try std.testing.expectEqual(true, statement.is_mutable); +} diff --git a/src/02_syntax/variable.zig b/src/02_syntax/variable.zig index 74f2bca..e4d9cbf 100644 --- a/src/02_syntax/variable.zig +++ b/src/02_syntax/variable.zig @@ -7,7 +7,7 @@ const utils = @import("./utils.zig"); const TokenStream = types.TokenStream; const ParseError = types.ParseError; -const VariableBinding = struct { +pub const VariableBinding = struct { is_mutable: bool, datatype: ?*lexic.Token, identifier: *lexic.Token, @@ -15,7 +15,7 @@ const VariableBinding = struct { alloc: std.mem.Allocator, /// Parses a variable binding - fn init(target: *VariableBinding, tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!void { + pub fn init(target: *VariableBinding, tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!void { std.debug.assert(pos < tokens.items.len); // try to parse a var keyword @@ -42,9 +42,7 @@ const VariableBinding = struct { // parse expression if (pos + 3 >= tokens.items.len) return ParseError.Error; - var exp = allocator.create(expression.Expression) catch { - return ParseError.Error; - }; + var exp = try allocator.create(expression.Expression); errdefer allocator.destroy(exp); exp.init(tokens, pos + 3) catch { return ParseError.Error; @@ -60,7 +58,7 @@ const VariableBinding = struct { }; } - fn deinit(self: *VariableBinding) void { + pub fn deinit(self: *VariableBinding) void { self.alloc.destroy(self.expression); } };