commit before transpiling

This commit is contained in:
David Gonzalez Martin 2023-11-19 09:22:39 -06:00
parent 20fe6c8f97
commit df53762d92
11 changed files with 1774 additions and 1618 deletions

View File

@ -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
View File

@ -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

View File

@ -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();
},
}

View File

@ -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

View File

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

View File

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

View File

@ -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,

View File

@ -6,6 +6,7 @@ pub const panic = Compilation.panic;
pub fn main() !void {
const allocator = std.heap.page_allocator;
try Compilation.init(allocator);
}

View File

@ -0,0 +1,8 @@
const main = fn () s32 {
var false_boolean: bool = false;
if (false_boolean) {
return 1;
} else {
return 0;
}
}