feat: minimal parse of variable binding

This commit is contained in:
Fernando Araoz 2024-12-12 06:47:20 -05:00
parent 44bd9fc5ad
commit 55231e986e
3 changed files with 33 additions and 19 deletions

View File

@ -8,15 +8,17 @@ pub const Expression = union(enum) {
number: *const Token,
/// Attempts to parse an expression from a token stream.
fn parse(tokens: *const std.ArrayList(Token), pos: usize) ParseError!@This() {
///
/// Receives a pointer to the memory for initialization
pub fn init(target: *Expression, tokens: *const std.ArrayList(Token), pos: usize) error{Unmatched}!void {
std.debug.assert(pos < tokens.items.len);
const t = tokens.items[pos];
if (t.token_type != TokenType.Int) {
return ParseError.Unmatched;
return error.Unmatched;
}
return .{
target.* = .{
.number = &t,
};
}
@ -27,7 +29,8 @@ test "should parse expression" {
const tokens = try lexic.tokenize(input, std.testing.allocator);
defer tokens.deinit();
const expr = try Expression.parse(&tokens, 0);
var expr: Expression = undefined;
try expr.init(&tokens, 0);
try std.testing.expectEqualDeep("322", expr.number.value);
try std.testing.expectEqualDeep(TokenType.Int, expr.number.token_type);
}
@ -37,7 +40,8 @@ test "should fail on non expression" {
const tokens = try lexic.tokenize(input, std.testing.allocator);
defer tokens.deinit();
const expr = Expression.parse(&tokens, 0) catch |err| {
var expr: Expression = undefined;
expr.init(&tokens, 0) catch |err| {
try std.testing.expectEqual(ParseError.Unmatched, err);
return;
};

View File

@ -10,6 +10,8 @@ pub const ParseError = error{
/// For example, a `var` keyword was found, but then no identifier
/// The parsing should stop
Error,
/// OOM. Fatal error, blows up everything
OutOfMemory,
};
pub const TokenStream = std.ArrayList(lexic.Token);

View File

@ -11,14 +11,12 @@ const VariableBinding = struct {
is_mutable: bool,
datatype: ?*lexic.Token,
identifier: *lexic.Token,
expression: expression.Expression,
expression: *expression.Expression,
alloc: std.mem.Allocator,
fn init(tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!@This() {
fn init(target: *VariableBinding, tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!void {
std.debug.assert(pos < tokens.items.len);
_ = allocator;
// try to parse a var keyword
const var_keyword = try utils.expect_token_type(lexic.TokenType.K_Var, &tokens.items[pos]);
_ = var_keyword;
@ -33,7 +31,6 @@ const VariableBinding = struct {
const identifier = utils.expect_token_type(lexic.TokenType.Identifier, &tokens.items[pos + 1]) catch {
return ParseError.Error;
};
_ = identifier;
// parse equal sign
if (pos + 2 >= tokens.items.len) return ParseError.Error;
@ -43,25 +40,36 @@ const VariableBinding = struct {
_ = equal_sign;
// parse expression
if (pos + 3 >= tokens.items.len) return ParseError.Error;
var exp = allocator.create(expression.Expression) catch {
return ParseError.Error;
};
errdefer allocator.destroy(exp);
try exp.init(tokens, pos + 3);
// provisional good return value
return ParseError.Unmatched;
// return
target.* = .{
.is_mutable = true,
.datatype = null,
.identifier = identifier,
.expression = exp,
.alloc = allocator,
};
}
fn deinit(self: *@This()) void {
_ = self;
self.alloc.destroy(self.expression);
}
};
test "should parse a minimal var" {
const input = "var my_variable =";
const input = "var my_variable = 322";
const tokens = try lexic.tokenize(input, std.testing.allocator);
defer tokens.deinit();
const binding = VariableBinding.init(&tokens, 0, std.testing.allocator) catch |err| {
try std.testing.expectEqual(ParseError.Unmatched, err);
return;
};
var binding: VariableBinding = undefined;
try binding.init(&tokens, 0, std.testing.allocator);
defer binding.deinit();
try std.testing.expectEqual(false, binding.is_mutable);
try std.testing.expectEqual(true, binding.is_mutable);
}