Compare commits

...

2 Commits

Author SHA1 Message Date
374a221e94 remove funcs for now
All checks were successful
Run unit tests / zig build test (push) Successful in 33s
2026-01-23 20:16:19 +01:00
a42770f4cc fix test
All checks were successful
Run unit tests / zig build test (push) Successful in 31s
2026-01-23 20:07:24 +01:00
4 changed files with 31 additions and 75 deletions

View File

@@ -1,3 +1 @@
(func main [] { (print_int (+ 1 (* 2 34)))
(print_int (+ 1 (* 2 34)))
})

View File

@@ -6,17 +6,9 @@ pub const Interpreter = struct {
stdout: *std.Io.Writer, stdout: *std.Io.Writer,
pub fn interpret(self: @This(), program: parser.Program) !void { pub fn interpret(self: @This(), program: parser.Program) !void {
const main = for (program.funcs) |func| { for (program.stmts) |stmt| {
if (std.mem.eql(u8, func.name, "main")) break func;
} else return error.NoMain;
try self.run_func(main);
try self.stdout.flush();
}
fn run_func(self: @This(), func: parser.Func) !void {
for (func.body) |stmt| {
try self.run_stmt(stmt); try self.run_stmt(stmt);
try self.stdout.flush();
} }
} }

View File

@@ -81,40 +81,7 @@ fn parse_sexprs(gpa: std.mem.Allocator, tokens: []const lexer.Token) ![]const SE
} }
pub const Program = struct { pub const Program = struct {
funcs: []const Func, stmts: []const Stmt,
};
pub const Func = struct {
name: []const u8,
args: []const []const u8,
body: []const Stmt,
fn from(gpa: std.mem.Allocator, sexpr: SExpr) !Func {
if (sexpr != .call or sexpr.call.len != 4) {
return error.InvalidFunc;
}
const call = sexpr.call;
if (call[0] != .identifier or !std.mem.eql(u8, call[0].identifier, "func") or call[1] != .identifier) {
return error.InvalidFunc;
}
if (call[2] != .list or call[3] != .block) {
return error.InvalidFunc;
}
var args = std.ArrayList([]const u8).empty;
for (call[2].list) |arg| {
if (arg != .identifier) return error.InvalidFuncArg;
try args.append(gpa, arg.identifier);
}
var body = std.ArrayList(Stmt).empty;
for (call[3].block) |inner| {
try body.append(gpa, try Stmt.from(gpa, inner));
}
return Func{
.name = call[1].identifier,
.args = try args.toOwnedSlice(gpa),
.body = try body.toOwnedSlice(gpa),
};
}
}; };
pub const Stmt = union(enum) { pub const Stmt = union(enum) {
@@ -218,12 +185,12 @@ pub const Expr = union(enum) {
pub fn parse(gpa: std.mem.Allocator, tokens: []const lexer.Token) !Program { pub fn parse(gpa: std.mem.Allocator, tokens: []const lexer.Token) !Program {
const sexprs = try parse_sexprs(gpa, tokens); const sexprs = try parse_sexprs(gpa, tokens);
var funcs = std.ArrayList(Func).empty; var stmts = std.ArrayList(Stmt).empty;
for (sexprs) |sexpr| { for (sexprs) |sexpr| {
const func = try Func.from(gpa, sexpr); const stmt = try Stmt.from(gpa, sexpr);
try funcs.append(gpa, func); try stmts.append(gpa, stmt);
} }
return Program{ return Program{
.funcs = try funcs.toOwnedSlice(gpa), .stmts = try stmts.toOwnedSlice(gpa),
}; };
} }

View File

@@ -3,50 +3,49 @@ const t = std.testing;
const lib = @import("libneon"); const lib = @import("libneon");
test "large tree" { test "program" {
var arena = std.heap.ArenaAllocator.init(t.allocator); var arena = std.heap.ArenaAllocator.init(t.allocator);
defer arena.deinit(); defer arena.deinit();
const gpa = arena.allocator(); const gpa = arena.allocator();
try t.expectEqualDeep( try t.expectEqualDeep(
&[_]lib.parser.SExpr{ lib.parser.Program{
.{ .call = &.{ .stmts = &.{
.{ .identifier = "foo" }, .{ .expr = .{ .func_call = .{ .name = "foo", .args = &.{
.{ .identifier = "bar" }, .{ .variable = "bar" },
.{ .string = "baz" }, .{ .string = "baz" },
.{ .list = &.{ .{ .func_call = .{ .name = "+", .args = &.{
.{ .integer = 1 }, .{ .integer = 1 },
.{ .integer = 2 }, .{ .integer = 2 },
.{ .integer = 3 }, } } },
} }, } } } },
.{ .block = &.{} },
} },
}, },
try lib.parser.parse_sexprs(gpa, &.{ },
try lib.parser.parse(gpa, &.{
.lparen, .lparen,
.{ .identifier = "foo" }, .{ .identifier = "foo" },
.{ .identifier = "bar" }, .{ .identifier = "bar" },
.{ .string = "baz" }, .{ .string = "baz" },
.lbracket, .lparen,
.{ .identifier = "+" },
.{ .integer = 1 }, .{ .integer = 1 },
.{ .integer = 2 }, .{ .integer = 2 },
.{ .integer = 3 }, .rparen,
.rbracket,
.lbrace,
.rbrace,
.rparen, .rparen,
}), }),
); );
} }
test "empty" { test "empty program" {
var arena = std.heap.ArenaAllocator.init(t.allocator); var arena = std.heap.ArenaAllocator.init(t.allocator);
defer arena.deinit(); defer arena.deinit();
const gpa = arena.allocator(); const gpa = arena.allocator();
try t.expectEqualDeep( try t.expectEqualDeep(
&.{}, lib.parser.Program{
lib.parser.parse_sexprs(gpa, &.{}), .stmts = &.{},
},
lib.parser.parse(gpa, &.{}),
); );
} }
@@ -57,7 +56,7 @@ test "unmatched delimiters" {
try t.expectError( try t.expectError(
error.UnmatchedParen, error.UnmatchedParen,
lib.parser.parse_sexprs(gpa, &.{ lib.parser.parse(gpa, &.{
.lbracket, .lbracket,
.{ .integer = 34 }, .{ .integer = 34 },
.lparen, .lparen,
@@ -67,7 +66,7 @@ test "unmatched delimiters" {
try t.expectError( try t.expectError(
error.UnmatchedBracket, error.UnmatchedBracket,
lib.parser.parse_sexprs(gpa, &.{ lib.parser.parse(gpa, &.{
.lparen, .lparen,
.{ .integer = 34 }, .{ .integer = 34 },
.lbracket, .lbracket,