nativity/src/ir.zig
2023-09-03 20:44:18 -06:00

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);
}