ona/src/coral/script/tree/Stmt.zig
kayomn 8fe734f9b7
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reintroduce integrated scripting language
2024-06-04 23:51:00 +01:00

243 lines
5.6 KiB
Zig

const Expr = @import("./Expr.zig");
const coral = @import("coral");
const tokens = @import("../tokens.zig");
const tree = @import("../tree.zig");
next: ?*const Self = null,
line: tokens.Line,
kind: union (enum) {
top_expression: *const Expr,
@"return": Return,
declare: Declare,
@"if": If,
@"while": While,
},
pub const Declare = struct {
declaration: *const tree.Declaration,
initial_expression: *const Expr,
};
pub const If = struct {
then_expression: *const Expr,
@"then": *const Self,
@"else": ?*const Self,
};
pub const Return = struct {
returned_expression: ?*const Expr,
};
const Self = @This();
pub const While = struct {
loop_expression: *const Expr,
loop: *const Self,
};
pub fn parse(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Environment) tree.ParseError!*Self {
switch (stream.token) {
.keyword_return => {
stream.step();
if (stream.token != .end and stream.token != .newline) {
return root.create_node(Self{
.line = stream.line,
.kind = .{.@"return" = .{.returned_expression = try Expr.parse(root, stream, environment)}},
});
}
if (stream.token != .end and stream.token != .newline) {
return root.report_error(stream.line, "expected end or newline after return statement", .{});
}
return root.create_node(Self{
.line = stream.line,
.kind = .{.@"return" = .{.returned_expression = null}},
});
},
.keyword_while => {
defer stream.skip_newlines();
stream.step();
const condition_expression = try Expr.parse(root, stream, environment);
if (stream.token != .symbol_colon) {
return root.report_error(stream.line, "expected `:` after `while` statement", .{});
}
stream.skip_newlines();
const first_statement = try parse(root, stream, environment);
{
var current_statement = first_statement;
while (stream.token != .keyword_end) {
const next_statement = try parse(root, stream, environment);
current_statement.next = next_statement;
current_statement = next_statement;
}
}
return root.create_node(Self{
.line = stream.line,
.kind = .{
.@"while" = .{
.loop = first_statement,
.loop_expression = condition_expression,
},
},
});
},
.keyword_var, .keyword_let => {
const is_constant = stream.token == .keyword_let;
stream.skip_newlines();
const identifier = switch (stream.token) {
.identifier => |identifier| identifier,
else => return root.report_error(stream.line, "expected identifier after declaration", .{}),
};
stream.skip_newlines();
if (stream.token != .symbol_equals) {
return root.report_error(stream.line, "expected `=` after declaration `{identifier}`", .{
.identifier = identifier,
});
}
stream.skip_newlines();
return root.create_node(Self{
.line = stream.line,
.kind = .{
.declare = .{
.initial_expression = try Expr.parse(root, stream, environment),
.declaration = declare: {
if (is_constant) {
break: declare environment.declare_constant(identifier) catch |declaration_error| {
return root.report_declare_error(stream.line, identifier, declaration_error);
};
}
break: declare environment.declare_variable(identifier) catch |declaration_error| {
return root.report_declare_error(stream.line, identifier, declaration_error);
};
},
},
},
});
},
.keyword_if => return parse_branch(root, stream, environment),
else => return root.create_node(Self{
.line = stream.line,
.kind = .{.top_expression = try Expr.parse(root, stream, environment)},
}),
}
}
fn parse_branch(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Environment) tree.ParseError!*Self {
stream.step();
const expression = try Expr.parse(root, stream, environment);
if (stream.token != .symbol_colon) {
return root.report_error(stream.line, "expected `:` after `{token}`", .{.token = stream.token.text()});
}
stream.skip_newlines();
const first_then_statement = try parse(root, stream, environment);
var current_then_statement = first_then_statement;
while (true) {
switch (stream.token) {
.keyword_end => {
stream.skip_newlines();
return root.create_node(Self{
.line = stream.line,
.kind = .{
.@"if" = .{
.then_expression = expression,
.@"then" = first_then_statement,
.@"else" = null,
},
},
});
},
.keyword_else => {
stream.step();
if (stream.token != .symbol_colon) {
return root.report_error(stream.line, "expected `:` after `if` statement condition", .{});
}
stream.skip_newlines();
const first_else_statement = try parse(root, stream, environment);
var current_else_statement = first_else_statement;
while (stream.token != .keyword_end) {
const next_statement = try parse(root, stream, environment);
current_else_statement.next = next_statement;
current_else_statement = next_statement;
}
stream.skip_newlines();
return root.create_node(Self{
.line = stream.line,
.kind = .{
.@"if" = .{
.@"else" = first_else_statement,
.@"then" = first_then_statement,
.then_expression = expression,
},
}
});
},
.keyword_elif => {
return root.create_node(Self{
.line = stream.line,
.kind = .{
.@"if" = .{
.@"else" = try parse_branch(root, stream, environment),
.@"then" = first_then_statement,
.then_expression = expression,
},
},
});
},
else => {
const next_statement = try parse(root, stream, environment);
current_then_statement.next = next_statement;
current_then_statement = next_statement;
},
}
}
}