144 lines
3.8 KiB
Zig
144 lines
3.8 KiB
Zig
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|
|
const assert = std.debug.assert;
|
|
const equal = std.mem.eql;
|
|
|
|
const data_structures = @import("data_structures.zig");
|
|
const ArrayList = data_structures.ArrayList;
|
|
const parser = @import("parser.zig");
|
|
|
|
const void_type = Type{
|
|
.id = .void,
|
|
};
|
|
|
|
const Type = struct {
|
|
id: Id,
|
|
|
|
fn isPrimitive(T: Type) bool {
|
|
return switch (T.id) {
|
|
.void => true,
|
|
};
|
|
}
|
|
const Id = enum {
|
|
void,
|
|
};
|
|
};
|
|
|
|
const Error = error{
|
|
type_mismatch,
|
|
internal,
|
|
arguments_not_used,
|
|
};
|
|
|
|
const TopLevelDeclaration = struct {
|
|
type: Id,
|
|
index: u31,
|
|
|
|
const Id = enum {
|
|
function,
|
|
expression,
|
|
};
|
|
};
|
|
|
|
const Instruction = struct {
|
|
id: Id,
|
|
index: u16,
|
|
|
|
const Id = enum {
|
|
ret_void,
|
|
};
|
|
};
|
|
|
|
const ret_void = Instruction{
|
|
.id = .ret_void,
|
|
.index = 0,
|
|
};
|
|
|
|
const ret = struct {
|
|
is_type: bool,
|
|
};
|
|
|
|
const Function = struct {
|
|
instructions: ArrayList(Instruction),
|
|
return_type: Type,
|
|
};
|
|
|
|
pub const Result = struct {
|
|
top_level_declarations: ArrayList(TopLevelDeclaration),
|
|
functions: ArrayList(Function),
|
|
instructions: struct {} = .{},
|
|
|
|
pub fn free(result: *Result, allocator: Allocator) void {
|
|
for (result.functions.items) |*function| {
|
|
function.instructions.clearAndFree(allocator);
|
|
}
|
|
result.functions.clearAndFree(allocator);
|
|
result.top_level_declarations.clearAndFree(allocator);
|
|
}
|
|
};
|
|
|
|
const Analyzer = struct {
|
|
parser: *const parser.Result,
|
|
top_level_declarations: ArrayList(TopLevelDeclaration),
|
|
functions: ArrayList(Function),
|
|
allocator: Allocator,
|
|
|
|
fn analyze(allocator: Allocator, parser_result: *const parser.Result) Error!Result {
|
|
var analyzer = Analyzer{
|
|
.parser = parser_result,
|
|
.top_level_declarations = ArrayList(TopLevelDeclaration){},
|
|
.allocator = allocator,
|
|
.functions = ArrayList(Function){},
|
|
};
|
|
|
|
for (parser_result.functions.items) |ast_function| {
|
|
if (ast_function.statements.items.len != 0) {
|
|
for (ast_function.statements.items) |statement| {
|
|
_ = statement;
|
|
@panic("TODO: statement");
|
|
}
|
|
} else {
|
|
if (ast_function.arguments.items.len != 0) {
|
|
return Error.arguments_not_used;
|
|
}
|
|
|
|
try analyzer.expectPrimitiveType(void_type, ast_function.return_type);
|
|
|
|
const function_index = analyzer.functions.items.len;
|
|
|
|
var function = Function{
|
|
.instructions = ArrayList(Instruction){},
|
|
.return_type = void_type,
|
|
};
|
|
|
|
function.instructions.append(allocator, ret_void) catch return Error.internal;
|
|
|
|
analyzer.top_level_declarations.append(allocator, TopLevelDeclaration{
|
|
.type = .function,
|
|
.index = @intCast(function_index),
|
|
}) catch return Error.internal;
|
|
|
|
analyzer.functions.append(allocator, function) catch return Error.internal;
|
|
}
|
|
}
|
|
|
|
return .{
|
|
.top_level_declarations = analyzer.top_level_declarations,
|
|
.functions = analyzer.functions,
|
|
};
|
|
}
|
|
|
|
fn expectPrimitiveType(analyzer: *Analyzer, comptime type_value: Type, type_identifier_id: u32) Error!void {
|
|
assert(type_value.isPrimitive());
|
|
const type_identifier = analyzer.parser.strings.get(type_identifier_id) orelse return Error.internal;
|
|
|
|
if (!equal(u8, @tagName(type_value.id), type_identifier)) {
|
|
return Error.type_mismatch;
|
|
}
|
|
}
|
|
};
|
|
|
|
pub fn runTest(allocator: Allocator, parser_result: *const parser.Result) !Result {
|
|
return Analyzer.analyze(allocator, parser_result);
|
|
}
|