fix: memory issues
This commit is contained in:
parent
6edb533f3d
commit
81e38ab8a8
@ -10,7 +10,7 @@ pub const Expression = union(enum) {
|
|||||||
/// Attempts to parse an expression from a token stream.
|
/// Attempts to parse an expression from a token stream.
|
||||||
///
|
///
|
||||||
/// Receives a pointer to the memory for initialization
|
/// Receives a pointer to the memory for initialization
|
||||||
pub fn init(tokens: *const std.ArrayList(Token), pos: usize) error{Unmatched}!Expression {
|
pub fn init(self: *@This(), tokens: *const std.ArrayList(Token), pos: usize) error{Unmatched}!void {
|
||||||
std.debug.assert(pos < tokens.items.len);
|
std.debug.assert(pos < tokens.items.len);
|
||||||
|
|
||||||
const t = tokens.items[pos];
|
const t = tokens.items[pos];
|
||||||
@ -18,7 +18,7 @@ pub const Expression = union(enum) {
|
|||||||
return error.Unmatched;
|
return error.Unmatched;
|
||||||
}
|
}
|
||||||
|
|
||||||
return .{
|
self.* = .{
|
||||||
.number = &t,
|
.number = &t,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -29,7 +29,8 @@ test "should parse expression" {
|
|||||||
const tokens = try lexic.tokenize(input, std.testing.allocator);
|
const tokens = try lexic.tokenize(input, std.testing.allocator);
|
||||||
defer tokens.deinit();
|
defer tokens.deinit();
|
||||||
|
|
||||||
const expr = try Expression.init(&tokens, 0);
|
var expr: Expression = undefined;
|
||||||
|
try expr.init(&tokens, 0);
|
||||||
try std.testing.expectEqualDeep("322", expr.number.value);
|
try std.testing.expectEqualDeep("322", expr.number.value);
|
||||||
try std.testing.expectEqualDeep(TokenType.Int, expr.number.token_type);
|
try std.testing.expectEqualDeep(TokenType.Int, expr.number.token_type);
|
||||||
}
|
}
|
||||||
@ -39,7 +40,8 @@ test "should fail on non expression" {
|
|||||||
const tokens = try lexic.tokenize(input, std.testing.allocator);
|
const tokens = try lexic.tokenize(input, std.testing.allocator);
|
||||||
defer tokens.deinit();
|
defer tokens.deinit();
|
||||||
|
|
||||||
const expr = Expression.init(&tokens, 0) catch |err| {
|
var expr: Expression = undefined;
|
||||||
|
expr.init(&tokens, 0) catch |err| {
|
||||||
try std.testing.expectEqual(ParseError.Unmatched, err);
|
try std.testing.expectEqual(ParseError.Unmatched, err);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -23,8 +23,6 @@ pub const Module = struct {
|
|||||||
|
|
||||||
// parse many statements
|
// parse many statements
|
||||||
while (current_pos < input_len) {
|
while (current_pos < input_len) {
|
||||||
std.debug.print("running on pos {d} \n", .{current_pos});
|
|
||||||
|
|
||||||
// FIXME: if a statement was added to the array list,
|
// FIXME: if a statement was added to the array list,
|
||||||
// and then one of these fails,
|
// and then one of these fails,
|
||||||
// will all previous statements leak memory?
|
// will all previous statements leak memory?
|
||||||
@ -34,6 +32,7 @@ pub const Module = struct {
|
|||||||
current_pos = next_pos;
|
current_pos = next_pos;
|
||||||
|
|
||||||
arrl.append(stmt) catch {
|
arrl.append(stmt) catch {
|
||||||
|
// TODO: free stmt if this fails
|
||||||
return ParseError.Error;
|
return ParseError.Error;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -68,6 +67,5 @@ test "should parse a single statement" {
|
|||||||
var module: Module = undefined;
|
var module: Module = undefined;
|
||||||
_ = try module.init(&tokens, 0, std.testing.allocator);
|
_ = try module.init(&tokens, 0, std.testing.allocator);
|
||||||
|
|
||||||
std.debug.print("len: {d} \n", .{module.statements.items.len});
|
|
||||||
defer module.deinit();
|
defer module.deinit();
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,21 @@ const variable = @import("./variable.zig");
|
|||||||
const TokenStream = types.TokenStream;
|
const TokenStream = types.TokenStream;
|
||||||
const ParseError = types.ParseError;
|
const ParseError = types.ParseError;
|
||||||
|
|
||||||
pub const Statement = union(enum) {
|
pub const Statement = struct {
|
||||||
VariableBinding: *variable.VariableBinding,
|
alloc: std.mem.Allocator,
|
||||||
|
value: union(enum) {
|
||||||
|
variableBinding: *variable.VariableBinding,
|
||||||
|
},
|
||||||
|
|
||||||
/// Parses a Statement and return the position of the next token
|
/// Parses a Statement and return the position of the next token
|
||||||
pub fn init(target: *Statement, tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!usize {
|
pub fn init(target: *Statement, tokens: *const TokenStream, pos: usize, allocator: std.mem.Allocator) ParseError!usize {
|
||||||
// try to parse a variable definition
|
// try to parse a variable definition
|
||||||
|
|
||||||
var vardef: variable.VariableBinding = undefined;
|
var vardef = allocator.create(variable.VariableBinding) catch {
|
||||||
|
return ParseError.OutOfMemory;
|
||||||
|
};
|
||||||
|
errdefer allocator.destroy(vardef);
|
||||||
|
|
||||||
var parse_failed = false;
|
var parse_failed = false;
|
||||||
const vardef_end = vardef.init(tokens, pos, allocator) catch |err| switch (err) {
|
const vardef_end = vardef.init(tokens, pos, allocator) catch |err| switch (err) {
|
||||||
error.Unmatched => blk: {
|
error.Unmatched => blk: {
|
||||||
@ -29,7 +36,8 @@ pub const Statement = union(enum) {
|
|||||||
if (!parse_failed) {
|
if (!parse_failed) {
|
||||||
// return the parsed variable definition
|
// return the parsed variable definition
|
||||||
target.* = .{
|
target.* = .{
|
||||||
.VariableBinding = &vardef,
|
.alloc = allocator,
|
||||||
|
.value = .{ .variableBinding = vardef },
|
||||||
};
|
};
|
||||||
return vardef_end;
|
return vardef_end;
|
||||||
}
|
}
|
||||||
@ -39,8 +47,11 @@ pub const Statement = union(enum) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: @This()) void {
|
pub fn deinit(self: @This()) void {
|
||||||
switch (self) {
|
switch (self.value) {
|
||||||
.VariableBinding => |v| v.deinit(),
|
.variableBinding => |v| {
|
||||||
|
v.deinit();
|
||||||
|
self.alloc.destroy(v);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -54,8 +65,8 @@ test "should parse a variable declaration statement" {
|
|||||||
_ = try statement.init(&tokens, 0, std.testing.allocator);
|
_ = try statement.init(&tokens, 0, std.testing.allocator);
|
||||||
defer statement.deinit();
|
defer statement.deinit();
|
||||||
|
|
||||||
switch (statement) {
|
switch (statement.value) {
|
||||||
.VariableBinding => |v| {
|
.variableBinding => |v| {
|
||||||
try std.testing.expectEqual(true, v.is_mutable);
|
try std.testing.expectEqual(true, v.is_mutable);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ pub const VariableBinding = struct {
|
|||||||
is_mutable: bool,
|
is_mutable: bool,
|
||||||
datatype: ?*lexic.Token,
|
datatype: ?*lexic.Token,
|
||||||
identifier: *lexic.Token,
|
identifier: *lexic.Token,
|
||||||
expression: *const expression.Expression,
|
expression: *expression.Expression,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
/// Parses a variable binding and returns the position of the next token
|
/// Parses a variable binding and returns the position of the next token
|
||||||
@ -43,7 +43,12 @@ pub const VariableBinding = struct {
|
|||||||
// parse expression
|
// parse expression
|
||||||
if (pos + 3 >= tokens.items.len) return ParseError.Error;
|
if (pos + 3 >= tokens.items.len) return ParseError.Error;
|
||||||
|
|
||||||
const exp = expression.Expression.init(tokens, pos + 3) catch {
|
// TODO: allocate on the stack
|
||||||
|
const exp = allocator.create(expression.Expression) catch {
|
||||||
|
return ParseError.OutOfMemory;
|
||||||
|
};
|
||||||
|
errdefer allocator.destroy(exp);
|
||||||
|
exp.init(tokens, pos + 3) catch {
|
||||||
return ParseError.Error;
|
return ParseError.Error;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,15 +57,15 @@ pub const VariableBinding = struct {
|
|||||||
.is_mutable = true,
|
.is_mutable = true,
|
||||||
.datatype = null,
|
.datatype = null,
|
||||||
.identifier = identifier,
|
.identifier = identifier,
|
||||||
.expression = &exp,
|
.expression = exp,
|
||||||
.alloc = allocator,
|
.alloc = allocator,
|
||||||
};
|
};
|
||||||
// TODO: when expression parses more than one token this will break.
|
// TODO: when expression parses more than one token this will break.
|
||||||
return pos + 4;
|
return pos + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *VariableBinding) void {
|
pub fn deinit(self: @This()) void {
|
||||||
_ = self;
|
self.alloc.destroy(self.expression);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -74,6 +79,14 @@ test "should parse a minimal var" {
|
|||||||
defer binding.deinit();
|
defer binding.deinit();
|
||||||
|
|
||||||
try std.testing.expectEqual(true, binding.is_mutable);
|
try std.testing.expectEqual(true, binding.is_mutable);
|
||||||
|
try std.testing.expect(binding.datatype == null);
|
||||||
|
try std.testing.expectEqualDeep("my_variable", binding.identifier.value);
|
||||||
|
const expr = binding.expression;
|
||||||
|
switch (expr.*) {
|
||||||
|
.number => |n| {
|
||||||
|
try std.testing.expectEqualDeep("322", n.value);
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "should fail is it doesnt start with var" {
|
test "should fail is it doesnt start with var" {
|
||||||
|
Loading…
Reference in New Issue
Block a user