commit before transpiling
This commit is contained in:
parent
20fe6c8f97
commit
df53762d92
@ -5,14 +5,18 @@ pub fn build(b: *std.Build) !void {
|
||||
all = b.option(bool, "all", "All") orelse false;
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimization = b.standardOptimizeOption(.{});
|
||||
const use_llvm = b.option(bool, "use_llvm", "Use LLVM as the backend for generate the compiler binary") orelse true;
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "nativity",
|
||||
.root_source_file = .{ .path = "src/main.zig" },
|
||||
.target = target,
|
||||
.optimize = optimization,
|
||||
.use_llvm = true,
|
||||
.use_llvm = use_llvm,
|
||||
.use_lld = false,
|
||||
});
|
||||
exe.unwind_tables = false;
|
||||
exe.omit_frame_pointer = false;
|
||||
|
||||
b.installArtifact(exe);
|
||||
b.installDirectory(.{
|
||||
.source_dir = std.Build.LazyPath.relative("lib"),
|
||||
@ -31,6 +35,8 @@ pub fn build(b: *std.Build) !void {
|
||||
const debug_command = switch (@import("builtin").os.tag) {
|
||||
.linux => blk: {
|
||||
const result = b.addSystemCommand(&.{"gf2"});
|
||||
result.addArg("-ex=r");
|
||||
result.addArgs(&.{ "-ex", "up" });
|
||||
result.addArg("--args");
|
||||
result.addArtifactArg(exe);
|
||||
break :blk result;
|
||||
|
5
ci.sh
5
ci.sh
@ -2,7 +2,8 @@
|
||||
|
||||
echo "Testing Nativity with Zig"
|
||||
echo "Compiling Nativity with Zig"
|
||||
zig build
|
||||
nativity_use_llvm=false
|
||||
zig build -Duse_llvm=$nativity_use_llvm
|
||||
failed_test_count=0
|
||||
passed_test_count=0
|
||||
test_directory_name=test
|
||||
@ -18,7 +19,7 @@ failed_tests=()
|
||||
for dir in $test_directory
|
||||
do
|
||||
MY_TESTNAME=${dir##*/}
|
||||
zig build run -- $dir/main.nat
|
||||
zig build run -Duse_llvm=$nativity_use_llvm -- $dir/main.nat -log ir
|
||||
if [[ "$?" == "0" ]]; then
|
||||
passed_compilation_count=$(($passed_compilation_count + 1))
|
||||
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
|
@ -53,6 +53,7 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
|
||||
var maybe_executable_path: ?[]const u8 = null;
|
||||
var maybe_main_package_path: ?[]const u8 = null;
|
||||
var target_triplet: []const u8 = "x86_64-linux-gnu";
|
||||
var transpile_to_c: ?bool = null;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < arguments.len) : (i += 1) {
|
||||
@ -112,6 +113,21 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
|
||||
} else {
|
||||
reportUnterminatedArgumentError(current_argument);
|
||||
}
|
||||
} else if (equal(u8, current_argument, "-transpile_to_c")) {
|
||||
if (i + 1 != arguments.len) {
|
||||
i += 1;
|
||||
|
||||
const arg = arguments[i];
|
||||
if (std.mem.eql(u8, arg, "true")) {
|
||||
transpile_to_c = true;
|
||||
} else if (std.mem.equal(u8, arg, "false")) {
|
||||
transpile_to_c = false;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
} else {
|
||||
reportUnterminatedArgumentError(current_argument);
|
||||
}
|
||||
} else {
|
||||
maybe_main_package_path = current_argument;
|
||||
}
|
||||
@ -133,6 +149,7 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
|
||||
.main_package_path = main_package_path,
|
||||
.executable_path = executable_path,
|
||||
.target = target,
|
||||
.transpile_to_c = transpile_to_c orelse true,
|
||||
};
|
||||
}
|
||||
|
||||
@ -236,7 +253,7 @@ pub const Type = union(enum) {
|
||||
pub fn getIndex(integer: Integer) Compilation.Type.Index {
|
||||
return .{
|
||||
.block = 0,
|
||||
.index = @ctz(integer.bit_count) - @ctz(@as(u8, 8)) + @as(u6, switch (integer.signedness) {
|
||||
.element = @ctz(integer.bit_count) - @ctz(@as(u8, 8)) + @as(u6, switch (integer.signedness) {
|
||||
.signed => Compilation.HardwareSignedIntegerType.offset,
|
||||
.unsigned => Compilation.HardwareUnsignedIntegerType.offset,
|
||||
}),
|
||||
@ -287,26 +304,6 @@ pub const Type = union(enum) {
|
||||
};
|
||||
|
||||
// Each time an enum is added here, a corresponding insertion in the initialization must be made
|
||||
pub const Values = enum {
|
||||
bool_false,
|
||||
bool_true,
|
||||
@"unreachable",
|
||||
|
||||
pub fn getIndex(value: Values) Value.Index {
|
||||
const absolute: u32 = @intFromEnum(value);
|
||||
const foo = @as(Value.Index, undefined);
|
||||
const ElementT = @TypeOf(@field(foo, "index"));
|
||||
const BlockT = @TypeOf(@field(foo, "block"));
|
||||
const divider = std.math.maxInt(ElementT);
|
||||
const element_index: ElementT = @intCast(absolute % divider);
|
||||
const block_index: BlockT = @intCast(absolute / divider);
|
||||
return .{
|
||||
.index = element_index,
|
||||
.block = block_index,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Intrinsic = enum {
|
||||
@"error",
|
||||
import,
|
||||
@ -556,6 +553,7 @@ pub const BinaryOperation = struct {
|
||||
divide,
|
||||
shift_left,
|
||||
shift_right,
|
||||
compare_equal,
|
||||
};
|
||||
};
|
||||
|
||||
@ -563,6 +561,17 @@ pub const CallingConvention = enum {
|
||||
system_v,
|
||||
};
|
||||
|
||||
pub const Branch = struct {
|
||||
condition: Value.Index,
|
||||
true_expression: Value.Index,
|
||||
false_expression: Value.Index,
|
||||
reaches_end: bool,
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
};
|
||||
|
||||
pub const Value = union(enum) {
|
||||
unresolved: Unresolved,
|
||||
declaration: Declaration.Index,
|
||||
@ -572,7 +581,8 @@ pub const Value = union(enum) {
|
||||
undefined,
|
||||
@"unreachable",
|
||||
loop: Loop.Index,
|
||||
function: Function.Index,
|
||||
function_definition: Function.Index,
|
||||
function_declaration: Function.Index,
|
||||
block: Block.Index,
|
||||
runtime: Runtime,
|
||||
assign: Assignment.Index,
|
||||
@ -589,6 +599,7 @@ pub const Value = union(enum) {
|
||||
sign_extend: Cast.Index,
|
||||
zero_extend: Cast.Index,
|
||||
binary_operation: BinaryOperation.Index,
|
||||
branch: Branch.Index,
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
@ -606,7 +617,7 @@ pub const Value = union(enum) {
|
||||
|
||||
pub fn isComptime(value: *Value, module: *Module) bool {
|
||||
return switch (value.*) {
|
||||
.bool, .void, .undefined, .function, .type, .enum_field => true,
|
||||
.bool, .void, .undefined, .function_definition, .type, .enum_field => true,
|
||||
.integer => |integer| integer.type.eq(Type.comptime_int),
|
||||
.call => false,
|
||||
.binary_operation => false,
|
||||
@ -623,8 +634,11 @@ pub const Value = union(enum) {
|
||||
.string_literal => |string_literal_hash| module.string_literal_types.get(@intCast(module.getStringLiteral(string_literal_hash).?.len)).?,
|
||||
.type => Type.type,
|
||||
.enum_field => |enum_field_index| module.enums.get(module.enum_fields.get(enum_field_index).parent).type,
|
||||
.function => |function_index| module.functions.get(function_index).prototype,
|
||||
.function_definition => |function_index| module.function_definitions.get(function_index).prototype,
|
||||
.function_declaration => |function_index| module.function_declarations.get(function_index).prototype,
|
||||
.binary_operation => |binary_operation| module.binary_operations.get(binary_operation).type,
|
||||
.bool => Type.boolean,
|
||||
.declaration => Type.void,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
@ -703,9 +717,10 @@ pub const Module = struct {
|
||||
scopes: BlockList(Scope) = .{},
|
||||
files: BlockList(File) = .{},
|
||||
values: BlockList(Value) = .{},
|
||||
functions: BlockList(Function) = .{},
|
||||
fields: BlockList(Field) = .{},
|
||||
function_definitions: BlockList(Function) = .{},
|
||||
function_declarations: BlockList(Function) = .{},
|
||||
function_prototypes: BlockList(Function.Prototype) = .{},
|
||||
fields: BlockList(Field) = .{},
|
||||
types: BlockList(Type) = .{},
|
||||
blocks: BlockList(Block) = .{},
|
||||
loops: BlockList(Loop) = .{},
|
||||
@ -721,6 +736,7 @@ pub const Module = struct {
|
||||
arrays: BlockList(Array) = .{},
|
||||
casts: BlockList(Cast) = .{},
|
||||
binary_operations: BlockList(BinaryOperation) = .{},
|
||||
branches: BlockList(Branch) = .{},
|
||||
string_literal_types: data_structures.AutoArrayHashMap(u32, Type.Index) = .{},
|
||||
array_types: data_structures.AutoArrayHashMap(Array, Type.Index) = .{},
|
||||
entry_point: Function.Index = Function.Index.invalid,
|
||||
@ -729,6 +745,7 @@ pub const Module = struct {
|
||||
main_package_path: []const u8,
|
||||
executable_path: []const u8,
|
||||
target: std.Target,
|
||||
transpile_to_c: bool,
|
||||
};
|
||||
|
||||
const ImportFileResult = struct {
|
||||
@ -1047,17 +1064,7 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) !
|
||||
_ = try module.types.append(compilation.base_allocator, type_data);
|
||||
}
|
||||
|
||||
_ = try module.values.append(compilation.base_allocator, .{
|
||||
.bool = false,
|
||||
});
|
||||
|
||||
_ = try module.values.append(compilation.base_allocator, .{
|
||||
.bool = true,
|
||||
});
|
||||
|
||||
_ = try module.values.append(compilation.base_allocator, .{
|
||||
.@"unreachable" = {},
|
||||
});
|
||||
semantic_analyzer.unreachable_index = (try module.values.append(compilation.base_allocator, .@"unreachable")).index;
|
||||
|
||||
const value_allocation = try module.values.append(compilation.base_allocator, .{
|
||||
.unresolved = .{
|
||||
@ -1196,13 +1203,14 @@ pub fn log(comptime logger_scope: LoggerScope, logger: getLoggerScopeType(logger
|
||||
}
|
||||
|
||||
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, return_address: ?usize) noreturn {
|
||||
const print_stack_trace = true;
|
||||
const print_stack_trace = false;
|
||||
switch (print_stack_trace) {
|
||||
true => @call(.always_inline, std.builtin.default_panic, .{ message, stack_trace, return_address }),
|
||||
false => {
|
||||
writer.writeAll("\nPANIC: ") catch {};
|
||||
writer.writeAll(message) catch {};
|
||||
writer.writeByte('\n') catch {};
|
||||
@breakpoint();
|
||||
std.os.abort();
|
||||
},
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ const expectEqual = std.testing.expectEqual;
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
|
||||
const ir = @import("intermediate_representation.zig");
|
||||
const IR = ir.IR;
|
||||
|
||||
const data_structures = @import("../data_structures.zig");
|
||||
const ArrayList = data_structures.ArrayList;
|
||||
@ -234,7 +235,7 @@ pub fn get(comptime arch: std.Target.Cpu.Arch) type {
|
||||
};
|
||||
|
||||
return struct {
|
||||
pub fn initialize(allocator: Allocator, intermediate: *ir.Result, descriptor: Compilation.Module.Descriptor) !void {
|
||||
pub fn initialize(allocator: Allocator, intermediate: *IR, descriptor: Compilation.Module.Descriptor) !void {
|
||||
switch (arch) {
|
||||
.x86_64 => {
|
||||
var mir = try backend.MIR.selectInstructions(allocator, intermediate, descriptor.target);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,7 @@ pub fn BlockList(comptime T: type) type {
|
||||
};
|
||||
|
||||
return struct {
|
||||
// TODO: make this not reallocate the whole block. Instead, use a pointer to the block as the ArrayList item
|
||||
blocks: ArrayList(Block) = .{},
|
||||
len: usize = 0,
|
||||
first_block: u32 = 0,
|
||||
@ -38,14 +39,14 @@ pub fn BlockList(comptime T: type) type {
|
||||
const List = @This();
|
||||
|
||||
pub const Index = packed struct(u32) {
|
||||
index: u6,
|
||||
element: u6,
|
||||
block: u24,
|
||||
_reserved: bool = false,
|
||||
invalid: bool = false,
|
||||
|
||||
pub const invalid = Index{
|
||||
.invalid = true,
|
||||
.index = 0,
|
||||
.element = 0,
|
||||
.block = 0,
|
||||
};
|
||||
|
||||
@ -63,42 +64,50 @@ pub fn BlockList(comptime T: type) type {
|
||||
const block: u24 = @intCast(index / item_count);
|
||||
const i: u6 = @intCast(index % item_count);
|
||||
return .{
|
||||
.index = i,
|
||||
.element = i,
|
||||
.block = block,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Iterator = struct {
|
||||
block_index: u24,
|
||||
element_index: u6,
|
||||
list: *const List,
|
||||
index: Index,
|
||||
list: *List,
|
||||
|
||||
pub fn getCurrentIndex(i: *const Iterator) Index {
|
||||
return .{
|
||||
.block = i.block_index,
|
||||
.index = @intCast(i.element_index),
|
||||
};
|
||||
}
|
||||
pub const Pair = struct {
|
||||
index: Index,
|
||||
};
|
||||
|
||||
pub fn next(i: *Iterator) ?T {
|
||||
return if (i.nextPointer()) |ptr| ptr.* else null;
|
||||
}
|
||||
pub fn nextIndex(i: *Iterator) ?Index {
|
||||
// TODO: optimize with ctz and masking out already iterated indices in the bitmask
|
||||
for (i.index.block..i.list.blocks.items.len) |block_index| {
|
||||
for (@as(u8, i.index.element)..item_count) |element_index| {
|
||||
if (i.list.blocks.items[block_index].bitset.isSet(element_index)) {
|
||||
const index = Index{
|
||||
.element = @intCast(element_index),
|
||||
.block = @intCast(block_index),
|
||||
};
|
||||
|
||||
pub fn nextPointer(i: *Iterator) ?*T {
|
||||
for (i.block_index..i.list.blocks.items.len) |block_index| {
|
||||
for (@as(u8, i.element_index)..item_count) |element_index| {
|
||||
if (i.list.blocks.items[i.block_index].bitset.isSet(element_index)) {
|
||||
i.element_index = @intCast(element_index);
|
||||
i.element_index +%= 1;
|
||||
i.block_index = @as(u24, @intCast(block_index)) + @intFromBool(i.element_index < element_index);
|
||||
return &i.list.blocks.items[block_index].items[element_index];
|
||||
i.index = index;
|
||||
i.index.element +%= 1;
|
||||
i.index.block = @as(u24, @intCast(block_index)) + @intFromBool(i.index.element < element_index);
|
||||
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn nextPointer(i: *Iterator) ?*T {
|
||||
if (i.nextIndex()) |index| {
|
||||
const result = i.list.get(index);
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const Allocation = struct {
|
||||
@ -106,17 +115,19 @@ pub fn BlockList(comptime T: type) type {
|
||||
index: Index,
|
||||
};
|
||||
|
||||
pub fn iterator(list: *const List) Iterator {
|
||||
pub fn iterator(list: *List) Iterator {
|
||||
return .{
|
||||
.block_index = 0,
|
||||
.element_index = 0,
|
||||
.index = Index{
|
||||
.element = 0,
|
||||
.block = 0,
|
||||
},
|
||||
.list = list,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get(list: *List, index: Index) *T {
|
||||
assert(!index.invalid);
|
||||
return &list.blocks.items[index.block].items[index.index];
|
||||
return &list.blocks.items[index.block].items[index.element];
|
||||
}
|
||||
|
||||
pub fn append(list: *List, allocator: Allocator, element: T) !Allocation {
|
||||
@ -131,12 +142,12 @@ pub fn BlockList(comptime T: type) type {
|
||||
const result = switch (list.len < max_allocation) {
|
||||
true => blk: {
|
||||
const block = &list.blocks.items[list.first_block];
|
||||
if (block.allocateIndex()) |index| {
|
||||
const ptr = &block.items[index];
|
||||
if (block.allocateIndex()) |element_index| {
|
||||
const ptr = &block.items[element_index];
|
||||
break :blk Allocation{
|
||||
.ptr = ptr,
|
||||
.index = .{
|
||||
.index = index,
|
||||
.element = element_index,
|
||||
.block = @intCast(list.first_block),
|
||||
},
|
||||
};
|
||||
@ -148,13 +159,13 @@ pub fn BlockList(comptime T: type) type {
|
||||
const block_index = list.blocks.items.len;
|
||||
const new_block = list.blocks.addOneAssumeCapacity();
|
||||
new_block.* = .{};
|
||||
const index = new_block.allocateIndex() catch unreachable;
|
||||
const ptr = &new_block.items[index];
|
||||
const element_index = new_block.allocateIndex() catch unreachable;
|
||||
const ptr = &new_block.items[element_index];
|
||||
list.first_block += @intFromBool(block_index != 0);
|
||||
break :blk Allocation{
|
||||
.ptr = ptr,
|
||||
.index = .{
|
||||
.index = index,
|
||||
.element = element_index,
|
||||
.block = @intCast(block_index),
|
||||
},
|
||||
};
|
||||
@ -174,7 +185,7 @@ pub fn BlockList(comptime T: type) type {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn indexOf(list: *const List, elem: *const T) Index {
|
||||
pub fn indexOf(list: *List, elem: *const T) Index {
|
||||
const address = @intFromPtr(elem);
|
||||
for (list.blocks.items, 0..) |*block, block_index| {
|
||||
const base = @intFromPtr(&block.items[0]);
|
||||
@ -182,7 +193,7 @@ pub fn BlockList(comptime T: type) type {
|
||||
if (address >= base and address < top) {
|
||||
return .{
|
||||
.block = @intCast(block_index),
|
||||
.index = @intCast(@divExact(address - base, @sizeOf(T))),
|
||||
.element = @intCast(@divExact(address - base, @sizeOf(T))),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -146,6 +146,7 @@ const Analyzer = struct {
|
||||
var reaches_end = true;
|
||||
const block_node = analyzer.getScopeNode(scope_index, node_index);
|
||||
var statement_nodes = ArrayList(Node.Index){};
|
||||
|
||||
switch (block_node.id) {
|
||||
.block_one, .comptime_block_one => {
|
||||
try statement_nodes.append(analyzer.allocator, block_node.left);
|
||||
@ -175,7 +176,7 @@ const Analyzer = struct {
|
||||
}
|
||||
|
||||
const statement_node = analyzer.getScopeNode(scope_index, statement_node_index);
|
||||
const statement_value = switch (statement_node.id) {
|
||||
const statement_value_index = switch (statement_node.id) {
|
||||
.assign => (try analyzer.module.values.append(analyzer.allocator, try analyzer.processAssignment(scope_index, statement_node_index))).index,
|
||||
.simple_while => blk: {
|
||||
const loop_allocation = try analyzer.module.loops.append(analyzer.allocator, .{
|
||||
@ -196,7 +197,7 @@ const Analyzer = struct {
|
||||
},
|
||||
.@"unreachable" => blk: {
|
||||
reaches_end = false;
|
||||
break :blk Compilation.Values.@"unreachable".getIndex();
|
||||
break :blk unreachable_index;
|
||||
},
|
||||
.simple_symbol_declaration => blk: {
|
||||
const declaration_index = try analyzer.symbolDeclaration(scope_index, statement_node_index, .local);
|
||||
@ -216,18 +217,43 @@ const Analyzer = struct {
|
||||
.@"return" => blk: {
|
||||
reaches_end = false;
|
||||
|
||||
const return_value_allocation = try analyzer.module.values.append(analyzer.allocator, try analyzer.processReturn(scope_index, expect_type, statement_node_index));
|
||||
const return_expresssion = try analyzer.processReturn(scope_index, expect_type, statement_node_index);
|
||||
const return_value_allocation = try analyzer.module.values.append(analyzer.allocator, return_expresssion);
|
||||
|
||||
break :blk return_value_allocation.index;
|
||||
},
|
||||
.call_two, .call => (try analyzer.module.values.append(analyzer.allocator, .{
|
||||
.call = try analyzer.processCall(scope_index, statement_node_index),
|
||||
})).index,
|
||||
.@"switch" => (try analyzer.module.values.append(analyzer.allocator, try analyzer.processSwitch(scope_index, statement_node_index))).index,
|
||||
.call_two, .call => blk: {
|
||||
const call_index = try analyzer.processCall(scope_index, statement_node_index);
|
||||
const call_statement = try analyzer.module.values.append(analyzer.allocator, .{
|
||||
.call = call_index,
|
||||
});
|
||||
if (call_statement.ptr.getType(analyzer.module).eq(Type.noreturn)) {
|
||||
reaches_end = false;
|
||||
}
|
||||
break :blk call_statement.index;
|
||||
},
|
||||
// TODO: reaches end switch statement
|
||||
.@"switch" => blk: {
|
||||
const switch_value = try analyzer.processSwitch(scope_index, expect_type, statement_node_index);
|
||||
switch (switch_value) {
|
||||
.@"return" => reaches_end = false,
|
||||
else => {},
|
||||
}
|
||||
const switch_value_allocation = try analyzer.module.values.append(analyzer.allocator, switch_value);
|
||||
|
||||
break :blk switch_value_allocation.index;
|
||||
},
|
||||
.if_else => blk: {
|
||||
const if_else_value = try analyzer.processIfElse(scope_index, expect_type, statement_node_index);
|
||||
const branch = analyzer.module.branches.get(if_else_value.branch);
|
||||
reaches_end = branch.reaches_end;
|
||||
const branch_statement = try analyzer.module.values.append(analyzer.allocator, if_else_value);
|
||||
break :blk branch_statement.index;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
try statements.append(analyzer.allocator, statement_value);
|
||||
try statements.append(analyzer.allocator, statement_value_index);
|
||||
}
|
||||
|
||||
const block_allocation = try analyzer.module.blocks.append(analyzer.allocator, .{
|
||||
@ -254,7 +280,7 @@ const Analyzer = struct {
|
||||
|
||||
const left_type = switch (left_value_index.invalid) {
|
||||
false => switch (analyzer.module.values.get(left_value_index).*) {
|
||||
.function => |function_index| analyzer.module.function_prototypes.get(analyzer.module.types.get(analyzer.module.functions.get(function_index).prototype).function).return_type,
|
||||
.function_definition => |function_index| analyzer.module.function_prototypes.get(analyzer.module.types.get(analyzer.module.function_definitions.get(function_index).prototype).function).return_type,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
true => Type.Index.invalid,
|
||||
@ -270,9 +296,9 @@ const Analyzer = struct {
|
||||
};
|
||||
|
||||
switch (analyzer.module.values.get(left_value_index).*) {
|
||||
.function => |function_index| {
|
||||
const function = analyzer.module.functions.get(function_index);
|
||||
const function_prototype = analyzer.module.function_prototypes.get(analyzer.module.types.get(function.prototype).function);
|
||||
.function_definition => |function_index| {
|
||||
const function_definition = analyzer.module.function_definitions.get(function_index);
|
||||
const function_prototype = analyzer.module.function_prototypes.get(analyzer.module.types.get(function_definition.prototype).function);
|
||||
const argument_declarations = function_prototype.arguments.?;
|
||||
logln(.sema, .call, "Argument declaration count: {}. Argument node list count: {}\n", .{ argument_declarations.len, call_argument_node_list.len });
|
||||
var argument_array = ArrayList(Value.Index){};
|
||||
@ -340,7 +366,8 @@ const Analyzer = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn processSwitch(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Value {
|
||||
fn processSwitch(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) !Value {
|
||||
_ = expect_type;
|
||||
const node = analyzer.getScopeNode(scope_index, node_index);
|
||||
assert(node.id == .@"switch");
|
||||
|
||||
@ -458,6 +485,44 @@ const Analyzer = struct {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
fn processIfElse(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) !Value {
|
||||
const node = analyzer.getScopeNode(scope_index, node_index);
|
||||
assert(node.id == .if_else);
|
||||
assert(!node.left.invalid);
|
||||
assert(!node.right.invalid);
|
||||
|
||||
const if_branch_node = analyzer.getScopeNode(scope_index, node.left);
|
||||
const if_condition = try analyzer.unresolvedAllocate(scope_index, ExpectType.boolean, if_branch_node.left);
|
||||
switch (if_condition.ptr.*) {
|
||||
.declaration_reference => {
|
||||
const true_expression = try analyzer.unresolvedAllocate(scope_index, expect_type, if_branch_node.right);
|
||||
const true_reaches_end = switch (true_expression.ptr.*) {
|
||||
.block => |block_index| analyzer.module.blocks.get(block_index).reaches_end,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
const false_expression = try analyzer.unresolvedAllocate(scope_index, expect_type, node.right);
|
||||
const false_reaches_end = switch (true_expression.ptr.*) {
|
||||
.block => |block_index| analyzer.module.blocks.get(block_index).reaches_end,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
const reaches_end = true_reaches_end and false_reaches_end;
|
||||
|
||||
const branch = try analyzer.module.branches.append(analyzer.allocator, .{
|
||||
.condition = if_condition.index,
|
||||
.true_expression = true_expression.index,
|
||||
.false_expression = false_expression.index,
|
||||
.reaches_end = reaches_end,
|
||||
});
|
||||
|
||||
return Value{
|
||||
.branch = branch.index,
|
||||
};
|
||||
},
|
||||
.bool => unreachable,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
}
|
||||
|
||||
fn processAssignment(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Value {
|
||||
const node = analyzer.getScopeNode(scope_index, node_index);
|
||||
assert(node.id == .assign);
|
||||
@ -536,9 +601,15 @@ const Analyzer = struct {
|
||||
.divide => .divide,
|
||||
.shift_left => .shift_left,
|
||||
.shift_right => .shift_right,
|
||||
.compare_equal => .compare_equal,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
const left_expect_type: ExpectType = switch (binary_operation_id) {
|
||||
.compare_equal => ExpectType.none,
|
||||
else => expect_type,
|
||||
};
|
||||
|
||||
const left_allocation = try analyzer.unresolvedAllocate(scope_index, left_expect_type, node.left);
|
||||
const right_expect_type: ExpectType = switch (binary_operation_id) {
|
||||
.add,
|
||||
.sub,
|
||||
@ -553,18 +624,26 @@ const Analyzer = struct {
|
||||
=> ExpectType{
|
||||
.type_index = Type.u8,
|
||||
},
|
||||
.compare_equal => ExpectType{
|
||||
.type_index = left_allocation.ptr.getType(analyzer.module),
|
||||
},
|
||||
};
|
||||
|
||||
const left_allocation = try analyzer.unresolvedAllocate(scope_index, expect_type, node.left);
|
||||
const right_allocation = try analyzer.unresolvedAllocate(scope_index, right_expect_type, node.right);
|
||||
const left_type = left_allocation.ptr.getType(analyzer.module);
|
||||
const right_type = right_allocation.ptr.getType(analyzer.module);
|
||||
_ = right_type;
|
||||
// const right_type = right_allocation.ptr.getType(analyzer.module);
|
||||
// _ = right_type;
|
||||
|
||||
const binary_operation = try analyzer.module.binary_operations.append(analyzer.allocator, .{
|
||||
.left = left_allocation.index,
|
||||
.right = right_allocation.index,
|
||||
.type = left_type,
|
||||
.type = switch (expect_type) {
|
||||
.none => switch (binary_operation_id) {
|
||||
.logical_and => left_type,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
.type_index => |type_index| type_index,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
.id = binary_operation_id,
|
||||
});
|
||||
|
||||
@ -615,7 +694,7 @@ const Analyzer = struct {
|
||||
try analyzer.resolveNode(init_value, lookup.scope, expect_type, init_value.unresolved.node_index);
|
||||
declaration.type = init_value.getType(analyzer.module);
|
||||
switch (init_value.*) {
|
||||
.function => |function_index| {
|
||||
.function_definition => |function_index| {
|
||||
try analyzer.module.function_name_map.put(analyzer.allocator, function_index, declaration.name);
|
||||
},
|
||||
else => {},
|
||||
@ -721,7 +800,7 @@ const Analyzer = struct {
|
||||
const value_ref = analyzer.module.values.get(value_index);
|
||||
break :blk value_ref.*;
|
||||
},
|
||||
.keyword_true => {
|
||||
.keyword_true, .keyword_false => blk: {
|
||||
switch (expect_type) {
|
||||
.none => {},
|
||||
.type_index => |expected_type| {
|
||||
@ -732,10 +811,13 @@ const Analyzer = struct {
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
// TODO
|
||||
unreachable;
|
||||
|
||||
// break :blk Values.getIndex(.bool_true);
|
||||
break :blk .{
|
||||
.bool = switch (node.id) {
|
||||
.keyword_true => true,
|
||||
.keyword_false => false,
|
||||
else => unreachable,
|
||||
},
|
||||
};
|
||||
},
|
||||
.compiler_intrinsic_one, .compiler_intrinsic_two, .compiler_intrinsic => blk: {
|
||||
const intrinsic_name = analyzer.tokenIdentifier(scope_index, node.token + 1);
|
||||
@ -826,6 +908,8 @@ const Analyzer = struct {
|
||||
});
|
||||
|
||||
const function_prototype_index = try analyzer.functionPrototype(function_scope_allocation.index, node.left);
|
||||
const function_prototype = analyzer.module.function_prototypes.get(function_prototype_index);
|
||||
assert(!function_prototype.attributes.@"extern");
|
||||
|
||||
const function_body = try analyzer.block(function_scope_allocation.index, .{
|
||||
.type_index = analyzer.functionPrototypeReturnType(function_prototype_index),
|
||||
@ -835,14 +919,14 @@ const Analyzer = struct {
|
||||
.function = function_prototype_index,
|
||||
});
|
||||
|
||||
const function_allocation = try analyzer.module.functions.append(analyzer.allocator, .{
|
||||
const function_allocation = try analyzer.module.function_definitions.append(analyzer.allocator, .{
|
||||
.prototype = prototype_type.index,
|
||||
.body = function_body,
|
||||
.scope = function_scope_allocation.index,
|
||||
});
|
||||
|
||||
break :blk .{
|
||||
.function = function_allocation.index,
|
||||
.function_definition = function_allocation.index,
|
||||
};
|
||||
},
|
||||
.function_prototype => blk: {
|
||||
@ -854,13 +938,13 @@ const Analyzer = struct {
|
||||
const prototype_type = try analyzer.module.types.append(analyzer.allocator, .{
|
||||
.function = function_prototype_index,
|
||||
});
|
||||
const function_allocation = try analyzer.module.functions.append(analyzer.allocator, .{
|
||||
const function_declaration = try analyzer.module.function_declarations.append(analyzer.allocator, .{
|
||||
.prototype = prototype_type.index,
|
||||
.body = Block.Index.invalid,
|
||||
.scope = Scope.Index.invalid,
|
||||
});
|
||||
break :b .{
|
||||
.function = function_allocation.index,
|
||||
.function_declaration = function_declaration.index,
|
||||
};
|
||||
},
|
||||
false => unreachable,
|
||||
@ -919,7 +1003,7 @@ const Analyzer = struct {
|
||||
const right_index = try analyzer.doIdentifier(struct_type.scope, ExpectType.none, node.right.value, scope_index);
|
||||
const right_value = analyzer.module.values.get(right_index);
|
||||
switch (right_value.*) {
|
||||
.function, .type, .enum_field => break :blk right_value.*,
|
||||
.function_definition, .type, .enum_field => break :blk right_value.*,
|
||||
.declaration_reference => |declaration_reference| {
|
||||
const declaration = analyzer.module.declarations.get(declaration_reference.value);
|
||||
const declaration_name = analyzer.module.getName(declaration.name).?;
|
||||
@ -983,7 +1067,7 @@ const Analyzer = struct {
|
||||
.string_literal => .{
|
||||
.string_literal = try analyzer.processStringLiteral(scope_index, node_index),
|
||||
},
|
||||
.@"switch" => try analyzer.processSwitch(scope_index, node_index),
|
||||
.@"switch" => try analyzer.processSwitch(scope_index, expect_type, node_index),
|
||||
.enum_type => blk: {
|
||||
const list_node = analyzer.getScopeNode(scope_index, node.left);
|
||||
const field_node_list = switch (list_node.id) {
|
||||
@ -1038,6 +1122,7 @@ const Analyzer = struct {
|
||||
.divide,
|
||||
.shift_left,
|
||||
.shift_right,
|
||||
.compare_equal,
|
||||
=> try analyzer.processBinaryOperation(scope_index, expect_type, node_index),
|
||||
.expression_group => return try analyzer.resolveNode(value, scope_index, expect_type, node.left), //unreachable,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
@ -1146,6 +1231,7 @@ const Analyzer = struct {
|
||||
.void_type => Type.void,
|
||||
.ssize_type => Type.ssize,
|
||||
.usize_type => Type.usize,
|
||||
.bool_type => Type.boolean,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
return type_index;
|
||||
@ -1525,6 +1611,9 @@ const Analyzer = struct {
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
.bool => switch (source_type.*) {
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
},
|
||||
@ -1584,6 +1673,8 @@ const ExpectType = union(enum) {
|
||||
};
|
||||
};
|
||||
|
||||
pub var unreachable_index = Value.Index.invalid;
|
||||
|
||||
pub fn initialize(compilation: *Compilation, module: *Module, package: *Package, main_value: *Value) !void {
|
||||
_ = try analyzeExistingPackage(main_value, compilation, module, package);
|
||||
|
||||
@ -1593,7 +1684,7 @@ pub fn initialize(compilation: *Compilation, module: *Module, package: *Package,
|
||||
if (equal(u8, declaration_name, "_start")) {
|
||||
const value = module.values.get(decl.init_value);
|
||||
module.entry_point = switch (value.*) {
|
||||
.function => |function_index| function_index,
|
||||
.function_definition => |function_index| function_index,
|
||||
.unresolved => panic("Unresolved declaration: {s}\n", .{declaration_name}),
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
@ -162,6 +162,7 @@ pub const Node = packed struct(u128) {
|
||||
divide = 68,
|
||||
shift_left = 69,
|
||||
shift_right = 70,
|
||||
bool_type = 71,
|
||||
};
|
||||
};
|
||||
|
||||
@ -611,7 +612,7 @@ const Analyzer = struct {
|
||||
analyzer.token_i += 1;
|
||||
|
||||
_ = try analyzer.expectToken(.left_parenthesis);
|
||||
const if_expression = try analyzer.expression();
|
||||
const if_condition = try analyzer.expression();
|
||||
_ = try analyzer.expectToken(.right_parenthesis);
|
||||
|
||||
const if_block = try analyzer.block(.{ .is_comptime = false });
|
||||
@ -619,7 +620,7 @@ const Analyzer = struct {
|
||||
const if_node = try analyzer.addNode(.{
|
||||
.id = .@"if",
|
||||
.token = if_token,
|
||||
.left = if_expression,
|
||||
.left = if_condition,
|
||||
.right = if_block,
|
||||
});
|
||||
|
||||
@ -782,7 +783,6 @@ const Analyzer = struct {
|
||||
const token = analyzer.tokens[analyzer.token_i];
|
||||
// logln("Looping in expression precedence with token {}\n", .{token});
|
||||
const operator: PrecedenceOperator = switch (token.id) {
|
||||
.equal,
|
||||
.semicolon,
|
||||
.right_parenthesis,
|
||||
.right_brace,
|
||||
@ -1180,6 +1180,15 @@ const Analyzer = struct {
|
||||
.right = Node.Index.invalid,
|
||||
}),
|
||||
.hash => analyzer.compilerIntrinsic(),
|
||||
.fixed_keyword_bool => analyzer.addNode(.{
|
||||
.id = .bool_type,
|
||||
.token = blk: {
|
||||
analyzer.token_i += 1;
|
||||
break :blk token_i;
|
||||
},
|
||||
.left = Node.Index.invalid,
|
||||
.right = Node.Index.invalid,
|
||||
}),
|
||||
.keyword_unsigned_integer, .keyword_signed_integer => |signedness| analyzer.addNode(.{
|
||||
.id = switch (signedness) {
|
||||
.keyword_unsigned_integer => .unsigned_integer_type,
|
||||
|
@ -6,6 +6,7 @@ pub const panic = Compilation.panic;
|
||||
|
||||
pub fn main() !void {
|
||||
const allocator = std.heap.page_allocator;
|
||||
|
||||
try Compilation.init(allocator);
|
||||
}
|
||||
|
||||
|
8
test/simple_bool/main.nat
Normal file
8
test/simple_bool/main.nat
Normal file
@ -0,0 +1,8 @@
|
||||
const main = fn () s32 {
|
||||
var false_boolean: bool = false;
|
||||
if (false_boolean) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user