rework semantic analysis

This commit is contained in:
David Gonzalez Martin 2024-01-29 21:09:52 +01:00
parent b1ec34232f
commit c75b8db371
8 changed files with 2394 additions and 2518 deletions

File diff suppressed because it is too large Load Diff

View File

@ -324,6 +324,11 @@ extern "C" DISubprogram* NativityLLVMFunctionGetSubprogram(Function& function)
return subprogram; return subprogram;
} }
extern "C" void NativityLLVMGlobalVariableSetInitializer(GlobalVariable& global_variable, Constant* constant_initializer)
{
global_variable.setInitializer(constant_initializer);
}
extern "C" Constant* NativityLLVMConstantStruct(StructType* struct_type, Constant** constant_ptr, size_t constant_count) extern "C" Constant* NativityLLVMConstantStruct(StructType* struct_type, Constant** constant_ptr, size_t constant_count)
{ {
auto constants = ArrayRef<Constant*>(constant_ptr, constant_count); auto constants = ArrayRef<Constant*>(constant_ptr, constant_count);

File diff suppressed because it is too large Load Diff

View File

@ -116,3 +116,4 @@ pub extern fn NativityLLVMCreatePhiNode(type: *LLVM.Type, reserved_value_count:
pub extern fn NativityLLVMAllocatGetAllocatedType(alloca: *LLVM.Value.Instruction.Alloca) *LLVM.Type; pub extern fn NativityLLVMAllocatGetAllocatedType(alloca: *LLVM.Value.Instruction.Alloca) *LLVM.Type;
pub extern fn NativityLLVMValueToAlloca(value: *LLVM.Value) ?*LLVM.Value.Instruction.Alloca; pub extern fn NativityLLVMValueToAlloca(value: *LLVM.Value) ?*LLVM.Value.Instruction.Alloca;
pub extern fn NativityLLVMGlobalVariableSetInitializer(global_variable: *LLVM.Value.Constant.GlobalVariable, constant_initializer: *LLVM.Value.Constant) void;

View File

@ -13,7 +13,6 @@ const HashMap = data_structures.HashMap;
const lexer = @import("lexer.zig"); const lexer = @import("lexer.zig");
const Compilation = @import("../Compilation.zig"); const Compilation = @import("../Compilation.zig");
const File = Compilation.File;
const log = Compilation.log; const log = Compilation.log;
const logln = Compilation.logln; const logln = Compilation.logln;
const Token = Compilation.Token; const Token = Compilation.Token;
@ -179,10 +178,12 @@ pub const Node = struct {
empty_container_literal_guess, empty_container_literal_guess,
break_expression, break_expression,
character_literal, character_literal,
attribute_naked, function_attribute_naked,
attribute_export, function_attribute_cc,
attribute_extern, symbol_attribute_extern,
attribute_cc, symbol_attribute_export,
symbol_attributes,
metadata,
}; };
}; };
@ -199,7 +200,6 @@ const Analyzer = struct {
nodes: *Node.List, nodes: *Node.List,
node_lists: *ArrayList(ArrayList(Node.Index)), node_lists: *ArrayList(ArrayList(Node.Index)),
source_file: []const u8, source_file: []const u8,
file_index: File.Index,
allocator: Allocator, allocator: Allocator,
suffix_depth: usize = 0, suffix_depth: usize = 0,
@ -288,10 +288,50 @@ const Analyzer = struct {
logln(.parser, .symbol_declaration, "Current token: {}", .{analyzer.peekToken()}); logln(.parser, .symbol_declaration, "Current token: {}", .{analyzer.peekToken()});
const type_node_index = switch (analyzer.peekToken()) { const metadata_node_index = switch (analyzer.peekToken()) {
.operator_colon => blk: { .operator_colon => blk: {
analyzer.consumeToken(); const colon = try analyzer.expectToken(.operator_colon);
break :blk try analyzer.typeExpression(); const type_node_index = if (analyzer.peekToken() != .operator_colon) try analyzer.typeExpression() else .null;
const attribute_node_index: Node.Index = if (analyzer.peekToken() == .operator_colon) b: {
analyzer.consumeToken();
var list = ArrayList(Node.Index){};
while (analyzer.peekToken() != .operator_assign) {
const identifier = try analyzer.expectToken(.identifier);
const identifier_name = analyzer.bytes(identifier);
const attribute_node = inline for (@typeInfo(Compilation.Debug.Declaration.Global.Attribute).Enum.fields) |enum_field| {
if (equal(u8, identifier_name, enum_field.name)) {
const attribute = @field(Compilation.Debug.Declaration.Global.Attribute, enum_field.name);
const attribute_node = switch (attribute) {
.@"export" => try analyzer.addNode(.{
.id = @field(Node.Id, "symbol_attribute_" ++ @tagName(attribute)),
.token = identifier,
.left = .null,
.right = .null,
}),
};
break attribute_node;
}
} else @panic("Not known attribute");
try list.append(analyzer.allocator, attribute_node);
switch (analyzer.peekToken()) {
.operator_assign => {},
.operator_comma => analyzer.consumeToken(),
else => |t| @panic(@tagName(t)),
}
}
break :b try analyzer.nodeList(list);
} else .null;
break :blk try analyzer.addNode(.{
.id = .metadata,
.token = colon,
.left = type_node_index,
.right = attribute_node_index,
});
}, },
else => Node.Index.null, else => Node.Index.null,
}; };
@ -310,7 +350,7 @@ const Analyzer = struct {
const declaration = Node{ const declaration = Node{
.id = mutability_node_id, .id = mutability_node_id,
.token = first, .token = first,
.left = type_node_index, .left = metadata_node_index,
.right = init_node_index, .right = init_node_index,
}; };
@ -350,8 +390,8 @@ const Analyzer = struct {
if (equal(u8, identifier_name, enum_field.name)) { if (equal(u8, identifier_name, enum_field.name)) {
const attribute = @field(Compilation.Function.Attribute, enum_field.name); const attribute = @field(Compilation.Function.Attribute, enum_field.name);
const attribute_node = switch (attribute) { const attribute_node = switch (attribute) {
.naked, .@"export", => try analyzer.addNode(.{ .naked, => try analyzer.addNode(.{
.id = @field(Node.Id, "attribute_" ++ @tagName(attribute)), .id = @field(Node.Id, "function_attribute_" ++ @tagName(attribute)),
.token = identifier, .token = identifier,
.left = .null, .left = .null,
.right = .null, .right = .null,
@ -826,9 +866,9 @@ const Analyzer = struct {
_ = try analyzer.expectToken(.operator_left_parenthesis); _ = try analyzer.expectToken(.operator_left_parenthesis);
const intrinsic_name = analyzer.bytes(intrinsic_token)[1..]; const intrinsic_name = analyzer.bytes(intrinsic_token)[1..];
const intrinsic_id = inline for (@typeInfo(Compilation.Intrinsic.Id).Enum.fields) |enum_field| { const intrinsic_id = inline for (@typeInfo(Compilation.IntrinsicId).Enum.fields) |enum_field| {
if (equal(u8, enum_field.name, intrinsic_name)) { if (equal(u8, enum_field.name, intrinsic_name)) {
break @field(Compilation.Intrinsic.Id, enum_field.name); break @field(Compilation.IntrinsicId, enum_field.name);
} }
} else @panic(intrinsic_name); } else @panic(intrinsic_name);
@ -1902,13 +1942,13 @@ const Analyzer = struct {
fn addNode(analyzer: *Analyzer, node: Node) !Node.Index { fn addNode(analyzer: *Analyzer, node: Node) !Node.Index {
const node_index = try analyzer.nodes.append(analyzer.allocator, node); const node_index = try analyzer.nodes.append(analyzer.allocator, node);
logln(.parser, .node_creation, "Adding node #{} {s} to file #{} (left: {}, right: {})", .{ Node.unwrap(node_index), @tagName(node.id), File.unwrap(analyzer.file_index), switch (node.left) { // logln(.parser, .node_creation, "Adding node #{} {s} to file #{} (left: {}, right: {})", .{ Node.unwrap(node_index), @tagName(node.id), File.unwrap(analyzer.file_index), switch (node.left) {
.null => 0xffff_ffff, // .null => 0xffff_ffff,
else => Node.unwrap(node.left), // else => Node.unwrap(node.left),
}, switch (node.right) { // }, switch (node.right) {
.null => 0xffff_ffff, // .null => 0xffff_ffff,
else => Node.unwrap(node.right), // else => Node.unwrap(node.right),
}}); // }});
// if (Logger.bitset.contains(.node_creation_detailed)) { // if (Logger.bitset.contains(.node_creation_detailed)) {
// const chunk_start = analyzer.lexer.offsets.items[node.token]; // const chunk_start = analyzer.lexer.offsets.items[node.token];
// const chunk_end = analyzer.lexer.offsets.items[node.token + 1]; // const chunk_end = analyzer.lexer.offsets.items[node.token + 1];
@ -1950,13 +1990,13 @@ const Analyzer = struct {
// Here it is assumed that left brace is consumed // Here it is assumed that left brace is consumed
pub fn analyze(allocator: Allocator, lexer_result: lexer.Result, source_file: []const u8, file_index: File.Index, token_buffer: *Token.Buffer, node_list: *Node.List, node_lists: *ArrayList(ArrayList(Node.Index))) !Result { pub fn analyze(allocator: Allocator, lexer_result: lexer.Result, source_file: []const u8, token_buffer: *Token.Buffer, node_list: *Node.List, node_lists: *ArrayList(ArrayList(Node.Index))) !Result {
const start = std.time.Instant.now() catch unreachable; const start = std.time.Instant.now() catch unreachable;
var analyzer = Analyzer{ var analyzer = Analyzer{
.lexer = lexer_result, .lexer = lexer_result,
.token_buffer = token_buffer, .token_buffer = token_buffer,
.source_file = source_file, .source_file = source_file,
.file_index = file_index, // .file_index = file_index,
.token_i = lexer_result.offset, .token_i = lexer_result.offset,
.allocator = allocator, .allocator = allocator,
.nodes = node_list, .nodes = node_list,

View File

@ -5,7 +5,6 @@ pub fn build(b: *std.Build) !void {
const self_hosted_ci = b.option(bool, "self_hosted_ci", "This option enables the self-hosted CI behavior") orelse false; const self_hosted_ci = b.option(bool, "self_hosted_ci", "This option enables the self-hosted CI behavior") orelse false;
const third_party_ci = b.option(bool, "third_party_ci", "This option enables the third-party CI behavior") orelse false; const third_party_ci = b.option(bool, "third_party_ci", "This option enables the third-party CI behavior") orelse false;
const is_ci = self_hosted_ci or third_party_ci; const is_ci = self_hosted_ci or third_party_ci;
_ = is_ci; // autofix
const native_target = b.resolveTargetQuery(.{}); const native_target = b.resolveTargetQuery(.{});
const optimization = b.standardOptimizeOption(.{}); const optimization = b.standardOptimizeOption(.{});
var target_query = b.standardTargetOptionsQueryOnly(.{}); var target_query = b.standardTargetOptionsQueryOnly(.{});
@ -76,9 +75,9 @@ pub fn build(b: *std.Build) !void {
.target = target, .target = target,
.optimize = optimization, .optimize = optimization,
}); });
// compiler.formatted_panics = false; compiler.formatted_panics = is_ci;
// compiler.root_module.unwind_tables = false; compiler.root_module.unwind_tables = is_ci;
// compiler.root_module.omit_frame_pointer = false; compiler.root_module.omit_frame_pointer = false;
compiler.want_lto = false; compiler.want_lto = false;
compiler.linkLibC(); compiler.linkLibC();

View File

@ -8,7 +8,7 @@ comptime {
} }
} }
const _start = fn naked, export () noreturn { const _start:: export = fn naked() noreturn {
#asm({ #asm({
xor ebp, ebp; xor ebp, ebp;
mov rdi, rsp; mov rdi, rsp;
@ -21,7 +21,7 @@ var argument_count: usize = 0;
var argument_values: [&]const [&:0]const u8 = undefined; var argument_values: [&]const [&:0]const u8 = undefined;
var environment_values: [&:null]const ?[&:null]const u8 = undefined; var environment_values: [&:null]const ?[&:null]const u8 = undefined;
const start = fn export (argc_argv_address: usize) noreturn { const start:: export = fn (argc_argv_address: usize) noreturn {
var argument_address_iterator = argc_argv_address; var argument_address_iterator = argc_argv_address;
const argument_count_ptr: &usize = #cast(argument_address_iterator); const argument_count_ptr: &usize = #cast(argument_address_iterator);
argument_count = argument_count_ptr.@; argument_count = argument_count_ptr.@;
@ -33,6 +33,6 @@ const start = fn export (argc_argv_address: usize) noreturn {
std.os.exit(exit_code = result); std.os.exit(exit_code = result);
} }
const main = fn export (argc: s32, argv: [&:null]?[&:null]u8, env: [&:null]?[&:null]u8) s32 { const main:: export = fn (argc: s32, argv: [&:null]?[&:null]u8, env: [&:null]?[&:null]u8) s32 {
return #import("main").main(); return #import("main").main();
} }