sema for main function
This commit is contained in:
parent
bf07777ff7
commit
611e611cab
@ -3,6 +3,7 @@ comptime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const _start = fn () noreturn {
|
const _start = fn () noreturn {
|
||||||
_ = #syscall(231, 0);
|
const result = #import("main").main();
|
||||||
|
_ = #syscall(231, result);
|
||||||
unreachable;
|
unreachable;
|
||||||
};
|
};
|
||||||
|
@ -64,6 +64,7 @@ pub const Struct = struct {
|
|||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Type = union(enum) {
|
pub const Type = union(enum) {
|
||||||
@ -74,6 +75,7 @@ pub const Type = union(enum) {
|
|||||||
@"struct": Struct.Index,
|
@"struct": Struct.Index,
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Integer = struct {
|
pub const Integer = struct {
|
||||||
@ -87,12 +89,14 @@ pub const Integer = struct {
|
|||||||
|
|
||||||
/// A scope contains a bunch of declarations
|
/// A scope contains a bunch of declarations
|
||||||
pub const Scope = struct {
|
pub const Scope = struct {
|
||||||
parent: Scope.Index,
|
|
||||||
type: Type.Index = Type.Index.invalid,
|
|
||||||
declarations: AutoHashMap(u32, Declaration.Index) = .{},
|
declarations: AutoHashMap(u32, Declaration.Index) = .{},
|
||||||
|
parent: Scope.Index,
|
||||||
|
file: File.Index,
|
||||||
|
type: Type.Index = Type.Index.invalid,
|
||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ScopeType = enum(u1) {
|
pub const ScopeType = enum(u1) {
|
||||||
@ -113,6 +117,7 @@ pub const Declaration = struct {
|
|||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Function = struct {
|
pub const Function = struct {
|
||||||
@ -133,6 +138,7 @@ pub const Function = struct {
|
|||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Block = struct {
|
pub const Block = struct {
|
||||||
@ -140,6 +146,7 @@ pub const Block = struct {
|
|||||||
reaches_end: bool,
|
reaches_end: bool,
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Field = struct {
|
pub const Field = struct {
|
||||||
@ -147,6 +154,7 @@ pub const Field = struct {
|
|||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Loop = struct {
|
pub const Loop = struct {
|
||||||
@ -156,6 +164,7 @@ pub const Loop = struct {
|
|||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Runtime = struct {
|
const Runtime = struct {
|
||||||
@ -172,6 +181,7 @@ pub const Assignment = struct {
|
|||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Syscall = struct {
|
pub const Syscall = struct {
|
||||||
@ -185,11 +195,35 @@ pub const Syscall = struct {
|
|||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Call = struct {
|
||||||
|
value: Value.Index,
|
||||||
|
arguments: ArgumentList.Index,
|
||||||
|
pub const List = BlockList(@This());
|
||||||
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ArgumentList = struct {
|
||||||
|
array: ArrayList(Value.Index),
|
||||||
|
pub const List = BlockList(@This());
|
||||||
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Return = struct {
|
||||||
|
value: Value.Index,
|
||||||
|
pub const List = BlockList(@This());
|
||||||
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Value = union(enum) {
|
pub const Value = union(enum) {
|
||||||
unresolved: Unresolved,
|
unresolved: Unresolved,
|
||||||
declaration: Declaration.Index,
|
declaration: Declaration.Index,
|
||||||
|
declaration_reference: Declaration.Index,
|
||||||
void,
|
void,
|
||||||
bool: bool,
|
bool: bool,
|
||||||
undefined,
|
undefined,
|
||||||
@ -202,9 +236,13 @@ pub const Value = union(enum) {
|
|||||||
type: Type.Index,
|
type: Type.Index,
|
||||||
integer: u64,
|
integer: u64,
|
||||||
syscall: Syscall.Index,
|
syscall: Syscall.Index,
|
||||||
|
call: Call.Index,
|
||||||
|
argument_list: ArgumentList,
|
||||||
|
@"return": Return.Index,
|
||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
|
pub const Allocation = List.Allocation;
|
||||||
|
|
||||||
pub fn isComptime(value: Value) bool {
|
pub fn isComptime(value: Value) bool {
|
||||||
return switch (value) {
|
return switch (value) {
|
||||||
@ -238,23 +276,26 @@ pub const Module = struct {
|
|||||||
loops: BlockList(Loop) = .{},
|
loops: BlockList(Loop) = .{},
|
||||||
assignments: BlockList(Assignment) = .{},
|
assignments: BlockList(Assignment) = .{},
|
||||||
syscalls: BlockList(Syscall) = .{},
|
syscalls: BlockList(Syscall) = .{},
|
||||||
|
calls: BlockList(Call) = .{},
|
||||||
|
argument_list: BlockList(ArgumentList) = .{},
|
||||||
|
returns: BlockList(Return) = .{},
|
||||||
|
|
||||||
pub const Descriptor = struct {
|
pub const Descriptor = struct {
|
||||||
main_package_path: []const u8,
|
main_package_path: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ImportFileResult = struct {
|
const ImportFileResult = struct {
|
||||||
file: *File,
|
ptr: *File,
|
||||||
|
index: File.Index,
|
||||||
is_new: bool,
|
is_new: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ImportPackageResult = struct {
|
const ImportPackageResult = struct {
|
||||||
file: *File,
|
file: ImportFileResult,
|
||||||
is_new: bool,
|
|
||||||
is_package: bool,
|
is_package: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn importFile(module: *Module, allocator: Allocator, current_file: *File, import_name: []const u8) !ImportPackageResult {
|
pub fn importFile(module: *Module, allocator: Allocator, current_file_index: File.Index, import_name: []const u8) !ImportPackageResult {
|
||||||
print("import: '{s}'\n", .{import_name});
|
print("import: '{s}'\n", .{import_name});
|
||||||
if (equal(u8, import_name, "std")) {
|
if (equal(u8, import_name, "std")) {
|
||||||
return module.importPackage(allocator, module.main_package.dependencies.get("std").?);
|
return module.importPackage(allocator, module.main_package.dependencies.get("std").?);
|
||||||
@ -268,6 +309,7 @@ pub const Module = struct {
|
|||||||
return module.importPackage(allocator, module.main_package);
|
return module.importPackage(allocator, module.main_package);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const current_file = module.files.get(current_file_index);
|
||||||
if (current_file.package.dependencies.get(import_name)) |package| {
|
if (current_file.package.dependencies.get(import_name)) |package| {
|
||||||
return module.importPackage(allocator, package);
|
return module.importPackage(allocator, package);
|
||||||
}
|
}
|
||||||
@ -279,55 +321,73 @@ pub const Module = struct {
|
|||||||
const full_path = try std.fs.path.join(allocator, &.{ current_file.package.directory.path, import_name });
|
const full_path = try std.fs.path.join(allocator, &.{ current_file.package.directory.path, import_name });
|
||||||
const file_relative_path = std.fs.path.basename(full_path);
|
const file_relative_path = std.fs.path.basename(full_path);
|
||||||
const package = current_file.package;
|
const package = current_file.package;
|
||||||
const import = try module.getFile(allocator, full_path, file_relative_path, package);
|
const import_file = try module.getFile(allocator, full_path, file_relative_path, package);
|
||||||
|
|
||||||
try import.file.addFileReference(allocator, current_file);
|
try import_file.ptr.addFileReference(allocator, current_file);
|
||||||
|
|
||||||
const result = ImportPackageResult{
|
const result = ImportPackageResult{
|
||||||
.file = import.file,
|
.file = import_file,
|
||||||
.is_new = import.is_new,
|
|
||||||
.is_package = false,
|
.is_package = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lookupDeclaration(module: *Module, hashed: u32) !noreturn {
|
||||||
|
_ = hashed;
|
||||||
|
_ = module;
|
||||||
|
while (true) {}
|
||||||
|
}
|
||||||
|
|
||||||
fn getFile(module: *Module, allocator: Allocator, full_path: []const u8, relative_path: []const u8, package: *Package) !ImportFileResult {
|
fn getFile(module: *Module, allocator: Allocator, full_path: []const u8, relative_path: []const u8, package: *Package) !ImportFileResult {
|
||||||
const path_lookup = try module.import_table.getOrPut(allocator, full_path);
|
const path_lookup = try module.import_table.getOrPut(allocator, full_path);
|
||||||
const file: *File = switch (path_lookup.found_existing) {
|
const file, const index = switch (path_lookup.found_existing) {
|
||||||
true => path_lookup.value_ptr.*,
|
true => blk: {
|
||||||
|
const result = path_lookup.value_ptr.*;
|
||||||
|
const index = module.files.indexOf(result);
|
||||||
|
break :blk .{
|
||||||
|
result,
|
||||||
|
index,
|
||||||
|
};
|
||||||
|
},
|
||||||
false => blk: {
|
false => blk: {
|
||||||
const new_file_index = try module.files.append(allocator, File{
|
const file_allocation = try module.files.append(allocator, File{
|
||||||
.relative_path = relative_path,
|
.relative_path = relative_path,
|
||||||
.package = package,
|
.package = package,
|
||||||
});
|
});
|
||||||
const file = module.files.get(new_file_index);
|
std.debug.print("Adding file #{}: {s}\n", .{ file_allocation.index.uniqueInteger(), full_path });
|
||||||
path_lookup.value_ptr.* = file;
|
path_lookup.value_ptr.* = file_allocation.ptr;
|
||||||
break :blk file;
|
// break :blk file;
|
||||||
|
break :blk .{
|
||||||
|
file_allocation.ptr,
|
||||||
|
file_allocation.index,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.file = file,
|
.ptr = file,
|
||||||
|
.index = index,
|
||||||
.is_new = !path_lookup.found_existing,
|
.is_new = !path_lookup.found_existing,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn importPackage(module: *Module, allocator: Allocator, package: *Package) !ImportPackageResult {
|
pub fn importPackage(module: *Module, allocator: Allocator, package: *Package) !ImportPackageResult {
|
||||||
const full_path = try std.fs.path.resolve(allocator, &.{ package.directory.path, package.source_path });
|
const full_path = try std.fs.path.resolve(allocator, &.{ package.directory.path, package.source_path });
|
||||||
const import = try module.getFile(allocator, full_path, package.source_path, package);
|
const import_file = try module.getFile(allocator, full_path, package.source_path, package);
|
||||||
try import.file.addPackageReference(allocator, package);
|
try import_file.ptr.addPackageReference(allocator, package);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.file = import.file,
|
.file = import_file,
|
||||||
.is_new = import.is_new,
|
|
||||||
.is_package = true,
|
.is_package = true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generateAbstractSyntaxTreeForFile(module: *Module, allocator: Allocator, file: *File) !void {
|
pub fn generateAbstractSyntaxTreeForFile(module: *Module, allocator: Allocator, file: *File) !void {
|
||||||
_ = module;
|
_ = module;
|
||||||
const source_file = try file.package.directory.handle.openFile(file.relative_path, .{});
|
const source_file = file.package.directory.handle.openFile(file.relative_path, .{}) catch |err| {
|
||||||
|
std.debug.panic("Can't find file {s} in directory {s} for error {s}", .{ file.relative_path, file.package.directory.path, @errorName(err) });
|
||||||
|
};
|
||||||
|
|
||||||
const file_size = try source_file.getEndPos();
|
const file_size = try source_file.getEndPos();
|
||||||
var file_buffer = try allocator.alloc(u8, file_size);
|
var file_buffer = try allocator.alloc(u8, file_size);
|
||||||
@ -426,7 +486,7 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) !
|
|||||||
try module.generateAbstractSyntaxTreeForFile(compilation.base_allocator, import);
|
try module.generateAbstractSyntaxTreeForFile(compilation.base_allocator, import);
|
||||||
}
|
}
|
||||||
|
|
||||||
const main_declaration = try semantic_analyzer.initialize(compilation, module, packages[0]);
|
const main_declaration = try semantic_analyzer.initialize(compilation, module, packages[0], .{ .block = 0, .index = 0 });
|
||||||
|
|
||||||
var ir = try intermediate_representation.initialize(compilation, module, packages[0], main_declaration);
|
var ir = try intermediate_representation.initialize(compilation, module, packages[0], main_declaration);
|
||||||
|
|
||||||
@ -465,6 +525,9 @@ pub const File = struct {
|
|||||||
relative_path: []const u8,
|
relative_path: []const u8,
|
||||||
package: *Package,
|
package: *Package,
|
||||||
|
|
||||||
|
pub const List = BlockList(@This());
|
||||||
|
pub const Index = List.Index;
|
||||||
|
|
||||||
const Status = enum {
|
const Status = enum {
|
||||||
not_loaded,
|
not_loaded,
|
||||||
loaded_into_memory,
|
loaded_into_memory,
|
||||||
@ -484,15 +547,6 @@ pub const File = struct {
|
|||||||
try file.file_references.append(allocator, affected);
|
try file.file_references.append(allocator, affected);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fromRelativePath(allocator: Allocator, file_relative_path: []const u8) *File {
|
|
||||||
const file_content = try std.fs.cwd().readFileAlloc(allocator, file_relative_path, std.math.maxInt(usize));
|
|
||||||
_ = file_content;
|
|
||||||
const file = try allocator.create(File);
|
|
||||||
file.* = File{};
|
|
||||||
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lex(file: *File, allocator: Allocator) !void {
|
fn lex(file: *File, allocator: Allocator) !void {
|
||||||
assert(file.status == .loaded_into_memory);
|
assert(file.status == .loaded_into_memory);
|
||||||
file.lexical_analyzer_result = try lexical_analyzer.analyze(allocator, file.source_code);
|
file.lexical_analyzer_result = try lexical_analyzer.analyze(allocator, file.source_code);
|
||||||
|
@ -19,6 +19,7 @@ pub const Result = struct {
|
|||||||
values: BlockList(Value) = .{},
|
values: BlockList(Value) = .{},
|
||||||
syscalls: BlockList(Syscall) = .{},
|
syscalls: BlockList(Syscall) = .{},
|
||||||
loads: BlockList(Load) = .{},
|
loads: BlockList(Load) = .{},
|
||||||
|
phis: BlockList(Phi) = .{},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn initialize(compilation: *Compilation, module: *Module, package: *Package, main_file: Compilation.Type.Index) !Result {
|
pub fn initialize(compilation: *Compilation, module: *Module, package: *Package, main_file: Compilation.Type.Index) !Result {
|
||||||
@ -73,7 +74,10 @@ pub const Instruction = union(enum) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Phi = struct {
|
const Phi = struct {
|
||||||
foo: u32 = 0,
|
value: Value.Index,
|
||||||
|
jump: Jump.Index,
|
||||||
|
block: BasicBlock.Index,
|
||||||
|
next: Phi.Index,
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
};
|
};
|
||||||
@ -133,9 +137,10 @@ pub const Builder = struct {
|
|||||||
module: *Module,
|
module: *Module,
|
||||||
current_basic_block: BasicBlock.Index = BasicBlock.Index.invalid,
|
current_basic_block: BasicBlock.Index = BasicBlock.Index.invalid,
|
||||||
current_function_index: Function.Index = Function.Index.invalid,
|
current_function_index: Function.Index = Function.Index.invalid,
|
||||||
|
return_phi_node: Instruction.Index = Instruction.Index.invalid,
|
||||||
|
|
||||||
fn function(builder: *Builder, sema_function: Compilation.Function) !void {
|
fn function(builder: *Builder, sema_function: Compilation.Function) !void {
|
||||||
builder.current_function_index = try builder.ir.functions.append(builder.allocator, .{});
|
builder.current_function_index = (try builder.ir.functions.append(builder.allocator, .{})).index;
|
||||||
// TODO: arguments
|
// TODO: arguments
|
||||||
builder.current_basic_block = try builder.newBlock();
|
builder.current_basic_block = try builder.newBlock();
|
||||||
|
|
||||||
@ -143,15 +148,23 @@ pub const Builder = struct {
|
|||||||
const is_noreturn = return_type.* == .noreturn;
|
const is_noreturn = return_type.* == .noreturn;
|
||||||
if (!is_noreturn) {
|
if (!is_noreturn) {
|
||||||
const exit_block = try builder.newBlock();
|
const exit_block = try builder.newBlock();
|
||||||
const phi = try builder.appendToBlock(exit_block, .{
|
const phi = try builder.ir.phis.addOne(builder.allocator);
|
||||||
.phi = Phi.Index.invalid,
|
const phi_instruction = try builder.appendToBlock(exit_block, .{
|
||||||
|
.phi = phi.index,
|
||||||
});
|
});
|
||||||
|
phi.ptr.* = .{
|
||||||
|
.value = Value.Index.invalid,
|
||||||
|
.jump = Jump.Index.invalid,
|
||||||
|
.block = exit_block,
|
||||||
|
.next = Phi.Index.invalid,
|
||||||
|
};
|
||||||
const ret = try builder.appendToBlock(exit_block, .{
|
const ret = try builder.appendToBlock(exit_block, .{
|
||||||
.ret = .{
|
.ret = .{
|
||||||
.value = phi,
|
.value = phi_instruction,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
_ = ret;
|
_ = ret;
|
||||||
|
builder.return_phi_node = phi_instruction;
|
||||||
}
|
}
|
||||||
const sema_block = sema_function.getBodyBlock(builder.module);
|
const sema_block = sema_function.getBodyBlock(builder.module);
|
||||||
try builder.block(sema_block, .{ .emit_exit_block = !is_noreturn });
|
try builder.block(sema_block, .{ .emit_exit_block = !is_noreturn });
|
||||||
@ -262,14 +275,35 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ = try builder.append(.{
|
_ = try builder.append(.{
|
||||||
.syscall = try builder.ir.syscalls.append(builder.allocator, .{
|
.syscall = (try builder.ir.syscalls.append(builder.allocator, .{
|
||||||
.arguments = arguments,
|
.arguments = arguments,
|
||||||
}),
|
})).index,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.@"unreachable" => _ = try builder.append(.{
|
.@"unreachable" => _ = try builder.append(.{
|
||||||
.@"unreachable" = {},
|
.@"unreachable" = {},
|
||||||
}),
|
}),
|
||||||
|
.@"return" => |sema_ret_index| {
|
||||||
|
const sema_ret = builder.module.returns.get(sema_ret_index);
|
||||||
|
const return_value = try builder.emitValue(sema_ret.value);
|
||||||
|
const phi_instruction = builder.ir.instructions.get(builder.return_phi_node);
|
||||||
|
const phi = builder.ir.phis.get(phi_instruction.phi);
|
||||||
|
const exit_jump = try builder.jump(.{ .source = builder.current_basic_block, .destination = phi.block });
|
||||||
|
phi_instruction.phi = (try builder.ir.phis.append(builder.allocator, .{
|
||||||
|
.value = return_value,
|
||||||
|
.jump = exit_jump,
|
||||||
|
.next = phi_instruction.phi,
|
||||||
|
.block = phi.block,
|
||||||
|
})).index;
|
||||||
|
|
||||||
|
_ = try builder.append(.{
|
||||||
|
.jump = exit_jump,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.declaration => |sema_declaration_index| {
|
||||||
|
_ = sema_declaration_index;
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,12 +329,12 @@ pub const Builder = struct {
|
|||||||
const sema_value = builder.module.values.get(sema_value_index).*;
|
const sema_value = builder.module.values.get(sema_value_index).*;
|
||||||
return switch (sema_value) {
|
return switch (sema_value) {
|
||||||
// TODO
|
// TODO
|
||||||
.integer => |integer| try builder.ir.values.append(builder.allocator, .{
|
.integer => |integer| (try builder.ir.values.append(builder.allocator, .{
|
||||||
.integer = .{
|
.integer = .{
|
||||||
.value = integer,
|
.value = integer,
|
||||||
.sign = false,
|
.sign = false,
|
||||||
},
|
},
|
||||||
}),
|
})).index,
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -308,7 +342,8 @@ pub const Builder = struct {
|
|||||||
fn jump(builder: *Builder, jump_descriptor: Jump) !Jump.Index {
|
fn jump(builder: *Builder, jump_descriptor: Jump) !Jump.Index {
|
||||||
const destination_block = builder.ir.blocks.get(jump_descriptor.destination);
|
const destination_block = builder.ir.blocks.get(jump_descriptor.destination);
|
||||||
assert(!destination_block.sealed);
|
assert(!destination_block.sealed);
|
||||||
return try builder.ir.jumps.append(builder.allocator, jump_descriptor);
|
const jump_allocation = try builder.ir.jumps.append(builder.allocator, jump_descriptor);
|
||||||
|
return jump_allocation.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append(builder: *Builder, instruction: Instruction) !Instruction.Index {
|
fn append(builder: *Builder, instruction: Instruction) !Instruction.Index {
|
||||||
@ -317,20 +352,20 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn appendToBlock(builder: *Builder, block_index: BasicBlock.Index, instruction: Instruction) !Instruction.Index {
|
fn appendToBlock(builder: *Builder, block_index: BasicBlock.Index, instruction: Instruction) !Instruction.Index {
|
||||||
const instruction_index = try builder.ir.instructions.append(builder.allocator, instruction);
|
const instruction_allocation = try builder.ir.instructions.append(builder.allocator, instruction);
|
||||||
try builder.ir.blocks.get(block_index).instructions.append(builder.allocator, instruction_index);
|
try builder.ir.blocks.get(block_index).instructions.append(builder.allocator, instruction_allocation.index);
|
||||||
|
|
||||||
return instruction_index;
|
return instruction_allocation.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn newBlock(builder: *Builder) !BasicBlock.Index {
|
fn newBlock(builder: *Builder) !BasicBlock.Index {
|
||||||
const new_block_index = try builder.ir.blocks.append(builder.allocator, .{});
|
const new_block_allocation = try builder.ir.blocks.append(builder.allocator, .{});
|
||||||
const current_function = builder.ir.functions.get(builder.current_function_index);
|
const current_function = builder.ir.functions.get(builder.current_function_index);
|
||||||
const function_block_index = current_function.blocks.items.len;
|
const function_block_index = current_function.blocks.items.len;
|
||||||
try current_function.blocks.append(builder.allocator, new_block_index);
|
try current_function.blocks.append(builder.allocator, new_block_allocation.index);
|
||||||
|
|
||||||
print("Adding block: {}\n", .{function_block_index});
|
print("Adding block: {}\n", .{function_block_index});
|
||||||
|
|
||||||
return new_block_index;
|
return new_block_allocation.index;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -36,8 +36,8 @@ pub fn BlockList(comptime T: type) type {
|
|||||||
const List = @This();
|
const List = @This();
|
||||||
|
|
||||||
pub const Index = packed struct(u32) {
|
pub const Index = packed struct(u32) {
|
||||||
block: u24,
|
|
||||||
index: u6,
|
index: u6,
|
||||||
|
block: u24,
|
||||||
_reserved: bool = false,
|
_reserved: bool = false,
|
||||||
valid: bool = true,
|
valid: bool = true,
|
||||||
|
|
||||||
@ -50,6 +50,11 @@ pub fn BlockList(comptime T: type) type {
|
|||||||
pub fn eq(index: Index, other: Index) bool {
|
pub fn eq(index: Index, other: Index) bool {
|
||||||
return @as(u32, @bitCast(index)) == @as(u32, @bitCast(other));
|
return @as(u32, @bitCast(index)) == @as(u32, @bitCast(other));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn uniqueInteger(index: Index) u32 {
|
||||||
|
assert(index.valid);
|
||||||
|
return @as(u30, @truncate(@as(u32, @bitCast(index))));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Iterator = struct {
|
pub const Iterator = struct {
|
||||||
@ -81,6 +86,11 @@ pub fn BlockList(comptime T: type) type {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Allocation = struct {
|
||||||
|
ptr: *T,
|
||||||
|
index: Index,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn iterator(list: *const List) Iterator {
|
pub fn iterator(list: *const List) Iterator {
|
||||||
return .{
|
return .{
|
||||||
.block_index = 0,
|
.block_index = 0,
|
||||||
@ -94,33 +104,50 @@ pub fn BlockList(comptime T: type) type {
|
|||||||
return &list.blocks.items[index.block].items[index.index];
|
return &list.blocks.items[index.block].items[index.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append(list: *List, allocator: Allocator, element: T) !Index {
|
pub fn append(list: *List, allocator: Allocator, element: T) !Allocation {
|
||||||
|
const result = try list.addOne(allocator);
|
||||||
|
result.ptr.* = element;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addOne(list: *List, allocator: Allocator) !Allocation {
|
||||||
try list.ensureCapacity(allocator, list.len + 1);
|
try list.ensureCapacity(allocator, list.len + 1);
|
||||||
const max_allocation = list.blocks.items.len * item_count;
|
const max_allocation = list.blocks.items.len * item_count;
|
||||||
if (list.len < max_allocation) {
|
const result = switch (list.len < max_allocation) {
|
||||||
// Follow the guess
|
true => blk: {
|
||||||
if (list.blocks.items[list.first_block].allocateIndex()) |index| {
|
const block = &list.blocks.items[list.first_block];
|
||||||
list.blocks.items[list.first_block].items[index] = element;
|
if (block.allocateIndex()) |index| {
|
||||||
list.len += 1;
|
const ptr = &block.items[index];
|
||||||
return .{
|
break :blk Allocation{
|
||||||
|
.ptr = ptr,
|
||||||
|
.index = .{
|
||||||
.index = index,
|
.index = index,
|
||||||
.block = @intCast(list.first_block),
|
.block = @intCast(list.first_block),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
} else |_| {
|
} else |_| {
|
||||||
@panic("TODO");
|
@panic("TODO");
|
||||||
}
|
}
|
||||||
} else {
|
},
|
||||||
|
false => blk: {
|
||||||
const block_index = list.blocks.items.len;
|
const block_index = list.blocks.items.len;
|
||||||
const new_block = list.blocks.addOneAssumeCapacity();
|
const new_block = list.blocks.addOneAssumeCapacity();
|
||||||
new_block.* = .{};
|
new_block.* = .{};
|
||||||
const index = new_block.allocateIndex() catch unreachable;
|
const index = new_block.allocateIndex() catch unreachable;
|
||||||
new_block.items[index] = element;
|
const ptr = &new_block.items[index];
|
||||||
list.len += 1;
|
break :blk Allocation{
|
||||||
return .{
|
.ptr = ptr,
|
||||||
|
.index = .{
|
||||||
.index = index,
|
.index = index,
|
||||||
.block = @intCast(block_index),
|
.block = @intCast(block_index),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
list.len += 1;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensureCapacity(list: *List, allocator: Allocator, new_capacity: usize) !void {
|
pub fn ensureCapacity(list: *List, allocator: Allocator, new_capacity: usize) !void {
|
||||||
@ -131,6 +158,24 @@ pub fn BlockList(comptime T: type) type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn indexOf(list: *List, elem: *T) Index {
|
||||||
|
const address = @intFromPtr(elem);
|
||||||
|
std.debug.print("Items: {}. Block count: {}\n", .{ list.len, list.blocks.items.len });
|
||||||
|
for (list.blocks.items, 0..) |*block, block_index| {
|
||||||
|
const base = @intFromPtr(&block.items[0]);
|
||||||
|
const top = base + @sizeOf(T) * item_count;
|
||||||
|
std.debug.print("Bitset: {}. address: 0x{x}. Base: 0x{x}. Top: 0x{x}\n", .{ block.bitset, address, base, top });
|
||||||
|
if (address >= base and address < top) {
|
||||||
|
return .{
|
||||||
|
.block = @intCast(block_index),
|
||||||
|
.index = @intCast(@divExact(address - base, @sizeOf(T))),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@panic("not found");
|
||||||
|
}
|
||||||
|
|
||||||
test "Bitset index allocation" {
|
test "Bitset index allocation" {
|
||||||
const expect = std.testing.expect;
|
const expect = std.testing.expect;
|
||||||
var block = Block{};
|
var block = Block{};
|
||||||
|
@ -34,6 +34,9 @@ pub const Token = packed struct(u64) {
|
|||||||
fixed_keyword_false = 0x0d,
|
fixed_keyword_false = 0x0d,
|
||||||
fixed_keyword_fn = 0x0e,
|
fixed_keyword_fn = 0x0e,
|
||||||
fixed_keyword_unreachable = 0x0f,
|
fixed_keyword_unreachable = 0x0f,
|
||||||
|
fixed_keyword_return = 0x10,
|
||||||
|
keyword_unsigned_integer = 0x1f,
|
||||||
|
keyword_signed_integer = 0x20,
|
||||||
bang = '!', // 0x21
|
bang = '!', // 0x21
|
||||||
hash = '#', // 0x23
|
hash = '#', // 0x23
|
||||||
dollar_sign = '$', // 0x24
|
dollar_sign = '$', // 0x24
|
||||||
@ -82,6 +85,7 @@ pub const FixedKeyword = enum {
|
|||||||
false,
|
false,
|
||||||
@"fn",
|
@"fn",
|
||||||
@"unreachable",
|
@"unreachable",
|
||||||
|
@"return",
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Result = struct {
|
pub const Result = struct {
|
||||||
@ -109,8 +113,9 @@ pub fn analyze(allocator: Allocator, text: []const u8) !Result {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const identifier = text[start_index..][0 .. index - start_index];
|
// const identifier = text[start_index..][0 .. index - start_index];
|
||||||
std.debug.print("Identifier: {s}\n", .{identifier});
|
// _ = identifier;
|
||||||
|
// std.debug.print("Identifier: {s}\n", .{identifier});
|
||||||
|
|
||||||
if (start_character == 'u' or start_character == 's') {
|
if (start_character == 'u' or start_character == 's') {
|
||||||
var index_integer = start_index + 1;
|
var index_integer = start_index + 1;
|
||||||
@ -119,7 +124,13 @@ pub fn analyze(allocator: Allocator, text: []const u8) !Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (index_integer == index) {
|
if (index_integer == index) {
|
||||||
unreachable;
|
const id: Token.Id = switch (start_character) {
|
||||||
|
'u' => .keyword_unsigned_integer,
|
||||||
|
's' => .keyword_signed_integer,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
|
break :blk id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +138,7 @@ pub fn analyze(allocator: Allocator, text: []const u8) !Result {
|
|||||||
inline else => |comptime_fixed_keyword| @field(Token.Id, "fixed_keyword_" ++ @tagName(comptime_fixed_keyword)),
|
inline else => |comptime_fixed_keyword| @field(Token.Id, "fixed_keyword_" ++ @tagName(comptime_fixed_keyword)),
|
||||||
} else .identifier;
|
} else .identifier;
|
||||||
},
|
},
|
||||||
'(', ')', '{', '}', '-', '=', ';', '#', '@', ',' => |operator| blk: {
|
'(', ')', '{', '}', '-', '=', ';', '#', '@', ',', '.' => |operator| blk: {
|
||||||
index += 1;
|
index += 1;
|
||||||
break :blk @enumFromInt(operator);
|
break :blk @enumFromInt(operator);
|
||||||
},
|
},
|
||||||
|
@ -7,6 +7,7 @@ const File = Compilation.File;
|
|||||||
const Module = Compilation.Module;
|
const Module = Compilation.Module;
|
||||||
const Package = Compilation.Package;
|
const Package = Compilation.Package;
|
||||||
|
|
||||||
|
const ArgumentList = Compilation.ArgumentList;
|
||||||
const Assignment = Compilation.Assignment;
|
const Assignment = Compilation.Assignment;
|
||||||
const Block = Compilation.Block;
|
const Block = Compilation.Block;
|
||||||
const Declaration = Compilation.Declaration;
|
const Declaration = Compilation.Declaration;
|
||||||
@ -14,6 +15,7 @@ const Field = Compilation.Field;
|
|||||||
const Function = Compilation.Function;
|
const Function = Compilation.Function;
|
||||||
const Loop = Compilation.Loop;
|
const Loop = Compilation.Loop;
|
||||||
const Scope = Compilation.Scope;
|
const Scope = Compilation.Scope;
|
||||||
|
const ScopeType = Compilation.ScopeType;
|
||||||
const Struct = Compilation.Struct;
|
const Struct = Compilation.Struct;
|
||||||
const Type = Compilation.Type;
|
const Type = Compilation.Type;
|
||||||
const Value = Compilation.Value;
|
const Value = Compilation.Value;
|
||||||
@ -33,35 +35,68 @@ const HashMap = data_structures.AutoHashMap;
|
|||||||
const print = std.debug.print;
|
const print = std.debug.print;
|
||||||
|
|
||||||
const Analyzer = struct {
|
const Analyzer = struct {
|
||||||
source_code: []const u8,
|
|
||||||
nodes: []const Node,
|
|
||||||
tokens: []const Token,
|
|
||||||
file: *File,
|
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
module: *Module,
|
module: *Module,
|
||||||
|
current_file: File.Index,
|
||||||
|
|
||||||
fn lazyGlobalDeclaration(analyzer: *Analyzer, node_index: Node.Index) void {
|
fn getSourceFile(analyzer: *Analyzer, scope_index: Scope.Index) []const u8 {
|
||||||
print("Global: {}", .{analyzer.nodes[node_index.unwrap()]});
|
const scope = analyzer.module.scopes.get(scope_index);
|
||||||
|
const file = analyzer.module.files.get(scope.file);
|
||||||
|
return file.source_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn comptimeBlock(analyzer: *Analyzer, scope: *Scope, node_index: Node.Index) !Value.Index {
|
fn getNode(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) Node {
|
||||||
const comptime_node = analyzer.nodes[node_index.unwrap()];
|
const scope = analyzer.module.scopes.get(scope_index);
|
||||||
|
const file = analyzer.module.files.get(scope.file);
|
||||||
|
const result = file.syntactic_analyzer_result.nodes.items[node_index.unwrap()];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
const comptime_block = try analyzer.block(scope, .{ .none = {} }, comptime_node.left);
|
fn getToken(analyzer: *Analyzer, scope_index: Scope.Index, token_index: Token.Index) Token {
|
||||||
return try analyzer.module.values.append(analyzer.allocator, .{
|
const scope = analyzer.module.scopes.get(scope_index);
|
||||||
|
const file = analyzer.module.files.get(scope.file);
|
||||||
|
const result = file.lexical_analyzer_result.tokens.items[token_index];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getNodeList(analyzer: *Analyzer, scope_index: Scope.Index, list_index: u32) ArrayList(Node.Index) {
|
||||||
|
const scope = analyzer.module.scopes.get(scope_index);
|
||||||
|
const file = analyzer.module.files.get(scope.file);
|
||||||
|
return file.syntactic_analyzer_result.node_lists.items[list_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comptimeBlock(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Value.Index {
|
||||||
|
const comptime_node = analyzer.getNode(scope_index, node_index);
|
||||||
|
|
||||||
|
const comptime_block = try analyzer.block(scope_index, .{ .none = {} }, comptime_node.left);
|
||||||
|
const value_allocation = try analyzer.module.values.append(analyzer.allocator, .{
|
||||||
.block = comptime_block,
|
.block = comptime_block,
|
||||||
});
|
});
|
||||||
|
return value_allocation.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign(analyzer: *Analyzer, scope: *Scope, node_index: Node.Index) !Assignment.Index {
|
fn unresolved(analyzer: *Analyzer, node_index: Node.Index) !Value.Allocation {
|
||||||
_ = node_index;
|
const value_allocation = try analyzer.module.values.addOne(analyzer.allocator);
|
||||||
_ = scope;
|
value_allocation.ptr.* = .{
|
||||||
_ = analyzer;
|
.unresolved = .{
|
||||||
|
.node_index = node_index,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return value_allocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(analyzer: *Analyzer, scope: *Scope, expect_type: ExpectType, node_index: Node.Index) anyerror!Block.Index {
|
fn unresolvedAllocate(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) !Value.Allocation {
|
||||||
|
const new = try analyzer.unresolved(node_index);
|
||||||
|
try analyzer.resolveNode(new.ptr, scope_index, expect_type, node_index);
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) anyerror!Block.Index {
|
||||||
|
_ = expect_type;
|
||||||
var reaches_end = true;
|
var reaches_end = true;
|
||||||
const block_node = analyzer.nodes[node_index.unwrap()];
|
const block_node = analyzer.getNode(scope_index, node_index);
|
||||||
var statement_nodes = ArrayList(Node.Index){};
|
var statement_nodes = ArrayList(Node.Index){};
|
||||||
switch (block_node.id) {
|
switch (block_node.id) {
|
||||||
.block_one, .comptime_block_one => {
|
.block_one, .comptime_block_one => {
|
||||||
@ -72,12 +107,13 @@ const Analyzer = struct {
|
|||||||
try statement_nodes.append(analyzer.allocator, block_node.left);
|
try statement_nodes.append(analyzer.allocator, block_node.left);
|
||||||
try statement_nodes.append(analyzer.allocator, block_node.right);
|
try statement_nodes.append(analyzer.allocator, block_node.right);
|
||||||
},
|
},
|
||||||
|
.block, .comptime_block => statement_nodes = analyzer.getNodeList(scope_index, block_node.left.unwrap()),
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
|
|
||||||
const is_comptime = switch (block_node.id) {
|
const is_comptime = switch (block_node.id) {
|
||||||
.comptime_block_zero, .comptime_block_one, .comptime_block_two => true,
|
.comptime_block, .comptime_block_zero, .comptime_block_one, .comptime_block_two => true,
|
||||||
.block_zero, .block_one, .block_two => false,
|
.block, .block_zero, .block_one, .block_two => false,
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
print("Is comptime: {}\n", .{is_comptime});
|
print("Is comptime: {}\n", .{is_comptime});
|
||||||
@ -89,7 +125,7 @@ const Analyzer = struct {
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
const statement_node = analyzer.nodes[statement_node_index.unwrap()];
|
const statement_node = analyzer.getNode(scope_index, statement_node_index);
|
||||||
const statement_value = switch (statement_node.id) {
|
const statement_value = switch (statement_node.id) {
|
||||||
inline .assign, .simple_while => |statement_id| blk: {
|
inline .assign, .simple_while => |statement_id| blk: {
|
||||||
const specific_value_index = switch (statement_id) {
|
const specific_value_index = switch (statement_id) {
|
||||||
@ -99,17 +135,23 @@ const Analyzer = struct {
|
|||||||
switch (statement_node.left.valid) {
|
switch (statement_node.left.valid) {
|
||||||
// In an assignment, the node being invalid means a discarding underscore, like this: ```_ = result```
|
// In an assignment, the node being invalid means a discarding underscore, like this: ```_ = result```
|
||||||
false => {
|
false => {
|
||||||
const right = try analyzer.expression(scope, ExpectType.none, statement_node.right);
|
const right_value_allocation = try analyzer.module.values.addOne(analyzer.allocator);
|
||||||
try statements.append(analyzer.allocator, right);
|
right_value_allocation.ptr.* = .{
|
||||||
|
.unresolved = .{
|
||||||
|
.node_index = statement_node.right,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
try analyzer.resolveNode(right_value_allocation.ptr, scope_index, ExpectType.none, statement_node.right);
|
||||||
|
switch (right_value_allocation.ptr.*) {
|
||||||
|
else => |t| std.debug.print("\n\n\n\n\nASSIGN RIGHT: {s}\n\n\n\n", .{@tagName(t)}),
|
||||||
|
}
|
||||||
|
try statements.append(analyzer.allocator, right_value_allocation.index);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
true => {
|
true => {
|
||||||
const left_node = analyzer.nodes[statement_node.left.unwrap()];
|
|
||||||
print("left node index: {}. Left node: {}\n", .{ statement_node.left, left_node });
|
|
||||||
// const id = analyzer.tokenIdentifier(.token);
|
// const id = analyzer.tokenIdentifier(.token);
|
||||||
// print("id: {s}\n", .{id});
|
// print("id: {s}\n", .{id});
|
||||||
const left = try analyzer.expression(scope, ExpectType.none, statement_node.left);
|
// const left = try analyzer.expression(scope_index, ExpectType.none, statement_node.left);
|
||||||
_ = left;
|
|
||||||
|
|
||||||
// if (analyzer.module.values.get(left).isComptime() and analyzer.module.values.get(right).isComptime()) {
|
// if (analyzer.module.values.get(left).isComptime() and analyzer.module.values.get(right).isComptime()) {
|
||||||
// unreachable;
|
// unreachable;
|
||||||
@ -125,20 +167,18 @@ const Analyzer = struct {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.simple_while => statement: {
|
.simple_while => statement: {
|
||||||
const loop_index = try analyzer.module.loops.append(analyzer.allocator, .{
|
const loop_allocation = try analyzer.module.loops.append(analyzer.allocator, .{
|
||||||
.condition = Value.Index.invalid,
|
.condition = Value.Index.invalid,
|
||||||
.body = Value.Index.invalid,
|
.body = Value.Index.invalid,
|
||||||
.breaks = false,
|
.breaks = false,
|
||||||
});
|
});
|
||||||
const loop_structure = analyzer.module.loops.get(loop_index);
|
loop_allocation.ptr.condition = (try analyzer.unresolvedAllocate(scope_index, ExpectType.boolean, statement_node.left)).index;
|
||||||
const while_condition = try analyzer.expression(scope, ExpectType.boolean, statement_node.left);
|
loop_allocation.ptr.body = (try analyzer.unresolvedAllocate(scope_index, ExpectType.none, statement_node.right)).index;
|
||||||
const while_body = try analyzer.expression(scope, expect_type, statement_node.right);
|
|
||||||
loop_structure.condition = while_condition;
|
|
||||||
loop_structure.body = while_body;
|
|
||||||
|
|
||||||
reaches_end = loop_structure.breaks or while_condition.valid;
|
// TODO: bool true
|
||||||
|
reaches_end = loop_allocation.ptr.breaks or unreachable;
|
||||||
|
|
||||||
break :statement loop_index;
|
break :statement loop_allocation.index;
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
@ -147,62 +187,87 @@ const Analyzer = struct {
|
|||||||
.simple_while => "loop",
|
.simple_while => "loop",
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}, specific_value_index);
|
}, specific_value_index);
|
||||||
const value_index = try analyzer.module.values.append(analyzer.allocator, value);
|
const value_allocation = try analyzer.module.values.append(analyzer.allocator, value);
|
||||||
break :blk value_index;
|
break :blk value_allocation.index;
|
||||||
},
|
},
|
||||||
.@"unreachable" => blk: {
|
.@"unreachable" => blk: {
|
||||||
reaches_end = false;
|
reaches_end = false;
|
||||||
break :blk Values.@"unreachable".getIndex();
|
break :blk Values.@"unreachable".getIndex();
|
||||||
},
|
},
|
||||||
|
.simple_variable_declaration => (try analyzer.module.values.append(analyzer.allocator, .{
|
||||||
|
.declaration = try analyzer.symbolDeclaration(scope_index, statement_node_index, .local),
|
||||||
|
})).index,
|
||||||
|
.@"return" => blk: {
|
||||||
|
reaches_end = false;
|
||||||
|
const return_expression: Value.Index = switch (statement_node_index.valid) {
|
||||||
|
// TODO: expect type
|
||||||
|
true => ret: {
|
||||||
|
const return_value_allocation = try analyzer.module.values.addOne(analyzer.allocator);
|
||||||
|
return_value_allocation.ptr.* = .{
|
||||||
|
.unresolved = .{
|
||||||
|
.node_index = statement_node.left,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
try analyzer.resolveNode(return_value_allocation.ptr, scope_index, ExpectType.none, statement_node.left);
|
||||||
|
break :ret return_value_allocation.index;
|
||||||
|
},
|
||||||
|
false => @panic("TODO: ret void"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const return_value_allocation = try analyzer.module.returns.append(analyzer.allocator, .{
|
||||||
|
.value = return_expression,
|
||||||
|
});
|
||||||
|
|
||||||
|
const return_expression_value_allocation = try analyzer.module.values.append(analyzer.allocator, .{
|
||||||
|
.@"return" = return_value_allocation.index,
|
||||||
|
});
|
||||||
|
|
||||||
|
break :blk return_expression_value_allocation.index;
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
|
|
||||||
try statements.append(analyzer.allocator, statement_value);
|
try statements.append(analyzer.allocator, statement_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return try analyzer.module.blocks.append(analyzer.allocator, .{
|
const block_allocation = try analyzer.module.blocks.append(analyzer.allocator, .{
|
||||||
.statements = statements,
|
.statements = statements,
|
||||||
.reaches_end = reaches_end,
|
.reaches_end = reaches_end,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return block_allocation.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn whileExpression(analyzer: *Analyzer, scope: *Scope, expect_type: ExpectType, node: Node) !Loop.Index {
|
fn doIdentifier(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_token: Token.Index, node_scope_index: Scope.Index) !Value.Index {
|
||||||
_ = node;
|
const identifier_hash = try analyzer.identifierFromToken(node_scope_index, node_token);
|
||||||
_ = expect_type;
|
const scope = analyzer.module.scopes.get(scope_index);
|
||||||
_ = scope;
|
|
||||||
_ = analyzer;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve(analyzer: *Analyzer, scope: *Scope, expect_type: ExpectType, value: *Value) !void {
|
|
||||||
const node_index = switch (value.*) {
|
|
||||||
.unresolved => |unresolved| unresolved.node_index,
|
|
||||||
else => |t| @panic(@tagName(t)),
|
|
||||||
};
|
|
||||||
value.* = try analyzer.resolveNode(scope, expect_type, node_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn doIdentifier(analyzer: *Analyzer, scope: *Scope, expect_type: ExpectType, node: Node) !Value.Index {
|
|
||||||
assert(node.id == .identifier);
|
|
||||||
const identifier_hash = try analyzer.identifierFromToken(node.token);
|
|
||||||
// TODO: search in upper scopes too
|
// TODO: search in upper scopes too
|
||||||
const identifier_scope_lookup = try scope.declarations.getOrPut(analyzer.allocator, identifier_hash);
|
const identifier_scope_lookup = try scope.declarations.getOrPut(analyzer.allocator, identifier_hash);
|
||||||
if (identifier_scope_lookup.found_existing) {
|
if (identifier_scope_lookup.found_existing) {
|
||||||
const declaration_index = identifier_scope_lookup.value_ptr.*;
|
const declaration_index = identifier_scope_lookup.value_ptr.*;
|
||||||
const declaration = analyzer.module.declarations.get(declaration_index);
|
const declaration = analyzer.module.declarations.get(declaration_index);
|
||||||
const init_value = analyzer.module.values.get(declaration.init_value);
|
const init_value = analyzer.module.values.get(declaration.init_value);
|
||||||
try analyzer.resolve(scope, expect_type, init_value);
|
print("Declaration found: {}\n", .{init_value});
|
||||||
if (init_value.* != .runtime and declaration.mutability == .@"const") {
|
switch (init_value.*) {
|
||||||
|
.unresolved => |ur| try analyzer.resolveNode(init_value, scope_index, expect_type, ur.node_index),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
if (init_value.isComptime() and declaration.mutability == .@"const") {
|
||||||
return declaration.init_value;
|
return declaration.init_value;
|
||||||
} else {
|
} else {
|
||||||
unreachable;
|
const ref_allocation = try analyzer.module.values.append(analyzer.allocator, .{
|
||||||
|
.declaration_reference = declaration_index,
|
||||||
|
});
|
||||||
|
return ref_allocation.index;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@panic("TODO: not found");
|
std.debug.panic("Identifier not found in scope #{} of file #{} referenced by scope #{} of file #{}: {s}", .{ scope_index.uniqueInteger(), scope.file.uniqueInteger(), node_scope_index.uniqueInteger(), analyzer.module.scopes.get(node_scope_index).file.uniqueInteger(), tokenBytes(analyzer.getToken(scope_index, node_token), analyzer.getSourceFile(scope_index)) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getArguments(analyzer: *Analyzer, node_index: Node.Index) !ArrayList(Node.Index) {
|
fn getArguments(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !ArrayList(Node.Index) {
|
||||||
var arguments = ArrayList(Node.Index){};
|
var arguments = ArrayList(Node.Index){};
|
||||||
const node = analyzer.nodes[node_index.unwrap()];
|
const node = analyzer.getNode(scope_index, node_index);
|
||||||
switch (node.id) {
|
switch (node.id) {
|
||||||
.compiler_intrinsic_two => {
|
.compiler_intrinsic_two => {
|
||||||
try arguments.append(analyzer.allocator, node.left);
|
try arguments.append(analyzer.allocator, node.left);
|
||||||
@ -214,107 +279,19 @@ const Analyzer = struct {
|
|||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolveNode(analyzer: *Analyzer, scope: *Scope, expect_type: ExpectType, node_index: Node.Index) anyerror!Value {
|
fn resolveNode(analyzer: *Analyzer, value: *Value, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) anyerror!void {
|
||||||
const node = analyzer.nodes[node_index.unwrap()];
|
const node = analyzer.getNode(scope_index, node_index);
|
||||||
return switch (node.id) {
|
print("Resolving node #{}: {}\n", .{ node_index.uniqueInteger(), node });
|
||||||
.identifier => unreachable,
|
|
||||||
.compiler_intrinsic_one, .compiler_intrinsic_two => blk: {
|
|
||||||
const intrinsic_name = analyzer.tokenIdentifier(node.token + 1);
|
|
||||||
const intrinsic = data_structures.enumFromString(Intrinsic, intrinsic_name) orelse unreachable;
|
|
||||||
print("Intrinsic: {s}\n", .{@tagName(intrinsic)});
|
|
||||||
switch (intrinsic) {
|
|
||||||
.import => {
|
|
||||||
assert(node.id == .compiler_intrinsic_one);
|
|
||||||
const import_argument = analyzer.nodes[node.left.unwrap()];
|
|
||||||
switch (import_argument.id) {
|
|
||||||
.string_literal => {
|
|
||||||
const import_name = analyzer.tokenStringLiteral(import_argument.token);
|
|
||||||
const imported_file = try analyzer.module.importFile(analyzer.allocator, analyzer.file, import_name);
|
|
||||||
|
|
||||||
if (imported_file.is_new) {
|
assert(value.* == .unresolved);
|
||||||
// TODO: fix error
|
|
||||||
try analyzer.module.generateAbstractSyntaxTreeForFile(analyzer.allocator, imported_file.file);
|
|
||||||
} else {
|
|
||||||
unreachable;
|
|
||||||
}
|
|
||||||
|
|
||||||
break :blk .{
|
value.* = switch (node.id) {
|
||||||
.type = try analyzeFile(analyzer.allocator, analyzer.module, imported_file.file),
|
.identifier => blk: {
|
||||||
};
|
const value_index = try analyzer.doIdentifier(scope_index, expect_type, node.token, scope_index);
|
||||||
|
const value_ref = analyzer.module.values.get(value_index);
|
||||||
|
break :blk value_ref.*;
|
||||||
},
|
},
|
||||||
else => unreachable,
|
.keyword_true => {
|
||||||
}
|
|
||||||
},
|
|
||||||
.syscall => {
|
|
||||||
var argument_nodes = try analyzer.getArguments(node_index);
|
|
||||||
print("Argument count: {}\n", .{argument_nodes.items.len});
|
|
||||||
if (argument_nodes.items.len > 0 and argument_nodes.items.len <= 6 + 1) {
|
|
||||||
const number = try analyzer.expression(scope, ExpectType.none, argument_nodes.items[0]);
|
|
||||||
assert(number.valid);
|
|
||||||
var arguments = std.mem.zeroes([6]Value.Index);
|
|
||||||
for (argument_nodes.items[1..], 0..) |argument_node_index, argument_index| {
|
|
||||||
const argument = try analyzer.expression(scope, ExpectType.none, argument_node_index);
|
|
||||||
print("Index: {}. Argument: {}\n", .{ argument_index, argument });
|
|
||||||
arguments[argument_index] = argument;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: typecheck for usize
|
|
||||||
for (arguments[0..argument_nodes.items.len]) |argument| {
|
|
||||||
_ = argument;
|
|
||||||
}
|
|
||||||
|
|
||||||
break :blk .{
|
|
||||||
.syscall = try analyzer.module.syscalls.append(analyzer.allocator, .{
|
|
||||||
.number = number,
|
|
||||||
.arguments = arguments,
|
|
||||||
.argument_count = @intCast(argument_nodes.items.len - 1),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
unreachable;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
unreachable;
|
|
||||||
},
|
|
||||||
.function_definition => blk: {
|
|
||||||
const function_prototype_index = try analyzer.functionPrototype(node.left);
|
|
||||||
|
|
||||||
const function_body = try analyzer.block(scope, .{
|
|
||||||
.type_index = analyzer.functionPrototypeReturnType(function_prototype_index),
|
|
||||||
}, node.right);
|
|
||||||
|
|
||||||
const function_index = try analyzer.module.functions.append(analyzer.allocator, .{
|
|
||||||
.prototype = function_prototype_index,
|
|
||||||
.body = function_body,
|
|
||||||
});
|
|
||||||
break :blk .{
|
|
||||||
.function = function_index,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
.keyword_true => unreachable,
|
|
||||||
.simple_while => unreachable,
|
|
||||||
.block_zero, .block_one => blk: {
|
|
||||||
const block_index = try analyzer.block(scope, expect_type, node_index);
|
|
||||||
break :blk .{
|
|
||||||
.block = block_index,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
.number_literal => switch (std.zig.parseNumberLiteral(analyzer.tokenBytes(analyzer.tokens[node.token]))) {
|
|
||||||
.int => |integer| .{
|
|
||||||
.integer = integer,
|
|
||||||
},
|
|
||||||
else => |t| @panic(@tagName(t)),
|
|
||||||
},
|
|
||||||
else => |t| @panic(@tagName(t)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expression(analyzer: *Analyzer, scope: *Scope, expect_type: ExpectType, node_index: Node.Index) !Value.Index {
|
|
||||||
const node = analyzer.nodes[node_index.unwrap()];
|
|
||||||
return switch (node.id) {
|
|
||||||
.identifier => analyzer.doIdentifier(scope, expect_type, node),
|
|
||||||
.keyword_true => blk: {
|
|
||||||
switch (expect_type) {
|
switch (expect_type) {
|
||||||
.none => {},
|
.none => {},
|
||||||
.type_index => |expected_type| {
|
.type_index => |expected_type| {
|
||||||
@ -324,9 +301,140 @@ const Analyzer = struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
break :blk Values.getIndex(.bool_true);
|
// TODO
|
||||||
|
unreachable;
|
||||||
|
|
||||||
|
// break :blk Values.getIndex(.bool_true);
|
||||||
},
|
},
|
||||||
else => try analyzer.module.values.append(analyzer.allocator, try analyzer.resolveNode(scope, expect_type, node_index)),
|
.compiler_intrinsic_one, .compiler_intrinsic_two => blk: {
|
||||||
|
const intrinsic_name = analyzer.tokenIdentifier(scope_index, node.token + 1);
|
||||||
|
const intrinsic = data_structures.enumFromString(Intrinsic, intrinsic_name) orelse unreachable;
|
||||||
|
print("Intrinsic: {s}\n", .{@tagName(intrinsic)});
|
||||||
|
switch (intrinsic) {
|
||||||
|
.import => {
|
||||||
|
assert(node.id == .compiler_intrinsic_one);
|
||||||
|
const import_argument = analyzer.getNode(scope_index, node.left);
|
||||||
|
switch (import_argument.id) {
|
||||||
|
.string_literal => {
|
||||||
|
const import_name = analyzer.tokenStringLiteral(scope_index, import_argument.token);
|
||||||
|
const import_file = try analyzer.module.importFile(analyzer.allocator, analyzer.current_file, import_name);
|
||||||
|
|
||||||
|
if (import_file.file.is_new) {
|
||||||
|
// TODO: fix error
|
||||||
|
try analyzer.module.generateAbstractSyntaxTreeForFile(analyzer.allocator, import_file.file.ptr);
|
||||||
|
} else {
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
break :blk .{
|
||||||
|
.type = try analyzeFile(value, analyzer.allocator, analyzer.module, import_file.file.ptr, import_file.file.index),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.syscall => {
|
||||||
|
var argument_nodes = try analyzer.getArguments(scope_index, node_index);
|
||||||
|
print("Argument count: {}\n", .{argument_nodes.items.len});
|
||||||
|
if (argument_nodes.items.len > 0 and argument_nodes.items.len <= 6 + 1) {
|
||||||
|
const number_allocation = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, argument_nodes.items[0]);
|
||||||
|
const number = number_allocation.index;
|
||||||
|
assert(number.valid);
|
||||||
|
var arguments = std.mem.zeroes([6]Value.Index);
|
||||||
|
for (argument_nodes.items[1..], 0..) |argument_node_index, argument_index| {
|
||||||
|
const argument_allocation = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, argument_node_index);
|
||||||
|
arguments[argument_index] = argument_allocation.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: typecheck for usize
|
||||||
|
for (arguments[0..argument_nodes.items.len]) |argument| {
|
||||||
|
_ = argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
break :blk .{
|
||||||
|
.syscall = (try analyzer.module.syscalls.append(analyzer.allocator, .{
|
||||||
|
.number = number,
|
||||||
|
.arguments = arguments,
|
||||||
|
.argument_count = @intCast(argument_nodes.items.len - 1),
|
||||||
|
})).index,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
.function_definition => blk: {
|
||||||
|
const function_prototype_index = try analyzer.functionPrototype(scope_index, node.left);
|
||||||
|
|
||||||
|
const function_body = try analyzer.block(scope_index, .{
|
||||||
|
.type_index = analyzer.functionPrototypeReturnType(function_prototype_index),
|
||||||
|
}, node.right);
|
||||||
|
|
||||||
|
const function_allocation = try analyzer.module.functions.append(analyzer.allocator, .{
|
||||||
|
.prototype = function_prototype_index,
|
||||||
|
.body = function_body,
|
||||||
|
});
|
||||||
|
break :blk .{
|
||||||
|
.function = function_allocation.index,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.simple_while => unreachable,
|
||||||
|
.block_zero, .block_one => blk: {
|
||||||
|
const block_index = try analyzer.block(scope_index, expect_type, node_index);
|
||||||
|
break :blk .{
|
||||||
|
.block = block_index,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.number_literal => switch (std.zig.parseNumberLiteral(analyzer.numberBytes(scope_index, node.token))) {
|
||||||
|
.int => |integer| .{
|
||||||
|
.integer = integer,
|
||||||
|
},
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
},
|
||||||
|
.call_one => blk: {
|
||||||
|
const this_value_node_index = node.left;
|
||||||
|
const this_value_allocation = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, this_value_node_index);
|
||||||
|
|
||||||
|
const call_allocation = try analyzer.module.calls.append(analyzer.allocator, .{
|
||||||
|
.value = this_value_allocation.index,
|
||||||
|
.arguments = ArgumentList.Index.invalid,
|
||||||
|
});
|
||||||
|
break :blk .{
|
||||||
|
.call = call_allocation.index,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.field_access => blk: {
|
||||||
|
const left_allocation = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, node.left);
|
||||||
|
const identifier = analyzer.tokenIdentifier(scope_index, node.right.value);
|
||||||
|
_ = identifier;
|
||||||
|
switch (left_allocation.ptr.*) {
|
||||||
|
.type => |type_index| {
|
||||||
|
const left_type = analyzer.module.types.get(type_index);
|
||||||
|
switch (left_type.*) {
|
||||||
|
.@"struct" => |struct_index| {
|
||||||
|
const struct_type = analyzer.module.structs.get(struct_index);
|
||||||
|
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 => break :blk right_value.*,
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
print("Right: {}\n", .{right_value});
|
||||||
|
// struct_scope.declarations.get(identifier);
|
||||||
|
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
}
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
}
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,37 +443,55 @@ const Analyzer = struct {
|
|||||||
return function_prototype.return_type;
|
return function_prototype.return_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn functionPrototype(analyzer: *Analyzer, node_index: Node.Index) !Function.Prototype.Index {
|
fn functionPrototype(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Function.Prototype.Index {
|
||||||
const node = analyzer.nodes[node_index.unwrap()];
|
const node = analyzer.getNode(scope_index, node_index);
|
||||||
switch (node.id) {
|
switch (node.id) {
|
||||||
.simple_function_prototype => {
|
.simple_function_prototype => {
|
||||||
const arguments: ?[]const Field.Index = blk: {
|
const arguments: ?[]const Field.Index = blk: {
|
||||||
const argument_node = analyzer.nodes[node.left.get() orelse break :blk null];
|
if (node.left.get() == null) break :blk null;
|
||||||
|
const argument_node = analyzer.getNode(scope_index, node.left);
|
||||||
switch (argument_node.id) {
|
switch (argument_node.id) {
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const return_type_node = analyzer.nodes[node.right.unwrap()];
|
const return_type_node = analyzer.getNode(scope_index, node.right);
|
||||||
const return_type: Type.Index = switch (return_type_node.id) {
|
const return_type: Type.Index = switch (return_type_node.id) {
|
||||||
.identifier => {
|
.identifier => {
|
||||||
unreachable;
|
unreachable;
|
||||||
},
|
},
|
||||||
.keyword_noreturn => .{ .block = 0, .index = FixedTypeKeyword.offset + @intFromEnum(FixedTypeKeyword.noreturn) },
|
.keyword_noreturn => .{ .block = 0, .index = FixedTypeKeyword.offset + @intFromEnum(FixedTypeKeyword.noreturn) },
|
||||||
|
inline .signed_integer_type, .unsigned_integer_type => |int_type_signedness| blk: {
|
||||||
|
const bit_count: u16 = @intCast(return_type_node.left.value);
|
||||||
|
print("Bit count: {}\n", .{bit_count});
|
||||||
|
break :blk switch (bit_count) {
|
||||||
|
inline 8, 16, 32, 64 => |hardware_bit_count| Type.Index{
|
||||||
|
.block = 0,
|
||||||
|
.index = @ctz(hardware_bit_count) - @ctz(@as(u8, 8)) + switch (int_type_signedness) {
|
||||||
|
.signed_integer_type => HardwareSignedIntegerType,
|
||||||
|
.unsigned_integer_type => HardwareUnsignedIntegerType,
|
||||||
|
else => unreachable,
|
||||||
|
}.offset,
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
|
|
||||||
return try analyzer.module.function_prototypes.append(analyzer.allocator, .{
|
const function_prototype_allocation = try analyzer.module.function_prototypes.append(analyzer.allocator, .{
|
||||||
.arguments = arguments,
|
.arguments = arguments,
|
||||||
.return_type = return_type,
|
.return_type = return_type,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return function_prototype_allocation.index;
|
||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyzeDeclaration(analyzer: *Analyzer, scope: *Scope, declaration: *Declaration) !Value.Index {
|
fn analyzeDeclaration(analyzer: *Analyzer, scope_index: Scope.Index, declaration: *Declaration) !Value.Index {
|
||||||
|
_ = scope_index;
|
||||||
_ = declaration;
|
_ = declaration;
|
||||||
_ = scope;
|
|
||||||
_ = analyzer;
|
_ = analyzer;
|
||||||
// switch (declaration.*) {
|
// switch (declaration.*) {
|
||||||
// .unresolved => |node_index| {
|
// .unresolved => |node_index| {
|
||||||
@ -394,33 +520,53 @@ const Analyzer = struct {
|
|||||||
@panic("TODO: analyzeDeclaration");
|
@panic("TODO: analyzeDeclaration");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn structType(analyzer: *Analyzer, parent_scope: Scope.Index, container_declaration: syntactic_analyzer.ContainerDeclaration, index: Node.Index) !Type.Index {
|
fn structType(analyzer: *Analyzer, value: *Value, parent_scope_index: Scope.Index, index: Node.Index, file_index: File.Index) !Type.Index {
|
||||||
_ = index;
|
var node_buffer: [2]Node.Index = undefined;
|
||||||
const new_scope = try analyzer.allocateScope(.{ .parent = parent_scope });
|
// We have the file because this might be the first file
|
||||||
const scope = new_scope.ptr;
|
const file = analyzer.module.files.get(file_index);
|
||||||
|
const node = file.syntactic_analyzer_result.nodes.items[index.unwrap()];
|
||||||
|
const nodes = switch (node.id) {
|
||||||
|
.main_one => blk: {
|
||||||
|
node_buffer[0] = node.left;
|
||||||
|
break :blk node_buffer[0..1];
|
||||||
|
},
|
||||||
|
.main_two => blk: {
|
||||||
|
node_buffer[0] = node.left;
|
||||||
|
node_buffer[1] = node.right;
|
||||||
|
break :blk &node_buffer;
|
||||||
|
},
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
};
|
||||||
|
|
||||||
const is_file = !parent_scope.valid;
|
if (nodes.len > 0) {
|
||||||
|
const new_scope = try analyzer.allocateScope(.{
|
||||||
|
.parent = parent_scope_index,
|
||||||
|
.file = file_index,
|
||||||
|
});
|
||||||
|
const scope = new_scope.ptr;
|
||||||
|
const scope_index = new_scope.index;
|
||||||
|
|
||||||
|
const is_file = !parent_scope_index.valid;
|
||||||
assert(is_file);
|
assert(is_file);
|
||||||
|
|
||||||
const struct_index = try analyzer.module.structs.append(analyzer.allocator, .{
|
const struct_allocation = try analyzer.module.structs.append(analyzer.allocator, .{
|
||||||
.scope = new_scope.index,
|
.scope = new_scope.index,
|
||||||
});
|
});
|
||||||
const struct_type = analyzer.module.structs.get(struct_index);
|
const type_allocation = try analyzer.module.types.append(analyzer.allocator, .{
|
||||||
const type_index = try analyzer.module.types.append(analyzer.allocator, .{
|
.@"struct" = struct_allocation.index,
|
||||||
.@"struct" = struct_index,
|
|
||||||
});
|
});
|
||||||
scope.type = type_index;
|
scope.type = type_allocation.index;
|
||||||
|
value.* = .{
|
||||||
_ = struct_type;
|
.type = type_allocation.index,
|
||||||
assert(container_declaration.members.len > 0);
|
};
|
||||||
|
|
||||||
const count = blk: {
|
const count = blk: {
|
||||||
var result: struct {
|
var result: struct {
|
||||||
fields: u32 = 0,
|
fields: u32 = 0,
|
||||||
declarations: u32 = 0,
|
declarations: u32 = 0,
|
||||||
} = .{};
|
} = .{};
|
||||||
for (container_declaration.members) |member_index| {
|
for (nodes) |member_index| {
|
||||||
const member = analyzer.nodes[member_index.unwrap()];
|
const member = analyzer.getNode(scope_index, member_index);
|
||||||
const member_type = getContainerMemberType(member.id);
|
const member_type = getContainerMemberType(member.id);
|
||||||
|
|
||||||
switch (member_type) {
|
switch (member_type) {
|
||||||
@ -434,8 +580,8 @@ const Analyzer = struct {
|
|||||||
var declaration_nodes = try ArrayList(Node.Index).initCapacity(analyzer.allocator, count.declarations);
|
var declaration_nodes = try ArrayList(Node.Index).initCapacity(analyzer.allocator, count.declarations);
|
||||||
var field_nodes = try ArrayList(Node.Index).initCapacity(analyzer.allocator, count.fields);
|
var field_nodes = try ArrayList(Node.Index).initCapacity(analyzer.allocator, count.fields);
|
||||||
|
|
||||||
for (container_declaration.members) |member_index| {
|
for (nodes) |member_index| {
|
||||||
const member = analyzer.nodes[member_index.unwrap()];
|
const member = analyzer.getNode(scope_index, member_index);
|
||||||
const member_type = getContainerMemberType(member.id);
|
const member_type = getContainerMemberType(member.id);
|
||||||
const array_list = switch (member_type) {
|
const array_list = switch (member_type) {
|
||||||
.declaration => &declaration_nodes,
|
.declaration => &declaration_nodes,
|
||||||
@ -445,27 +591,59 @@ const Analyzer = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (declaration_nodes.items) |declaration_node_index| {
|
for (declaration_nodes.items) |declaration_node_index| {
|
||||||
const declaration_node = analyzer.nodes[declaration_node_index.unwrap()];
|
const declaration_node = analyzer.getNode(scope_index, declaration_node_index);
|
||||||
switch (declaration_node.id) {
|
switch (declaration_node.id) {
|
||||||
.@"comptime" => {},
|
.@"comptime" => {},
|
||||||
.simple_variable_declaration => {
|
.simple_variable_declaration => _ = try analyzer.symbolDeclaration(scope_index, declaration_node_index, .global),
|
||||||
const mutability: Compilation.Mutability = switch (analyzer.tokens[declaration_node.token].id) {
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: consider iterating over scope declarations instead?
|
||||||
|
for (declaration_nodes.items) |declaration_node_index| {
|
||||||
|
const declaration_node = analyzer.getNode(scope_index, declaration_node_index);
|
||||||
|
switch (declaration_node.id) {
|
||||||
|
.@"comptime" => _ = try analyzer.comptimeBlock(scope_index, declaration_node_index),
|
||||||
|
.simple_variable_declaration => {},
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (field_nodes.items) |field_index| {
|
||||||
|
const field_node = analyzer.getNode(scope_index, field_index);
|
||||||
|
_ = field_node;
|
||||||
|
|
||||||
|
@panic("TODO: fields");
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_allocation.index;
|
||||||
|
} else {
|
||||||
|
return Type.Index.invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn symbolDeclaration(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index, scope_type: ScopeType) !Declaration.Index {
|
||||||
|
const declaration_node = analyzer.getNode(scope_index, node_index);
|
||||||
|
assert(declaration_node.id == .simple_variable_declaration);
|
||||||
|
assert(!declaration_node.left.valid);
|
||||||
|
const mutability: Compilation.Mutability = switch (analyzer.getToken(scope_index, declaration_node.token).id) {
|
||||||
.fixed_keyword_const => .@"const",
|
.fixed_keyword_const => .@"const",
|
||||||
.fixed_keyword_var => .@"var",
|
.fixed_keyword_var => .@"var",
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
const expected_identifier_token_index = declaration_node.token + 1;
|
const expected_identifier_token_index = declaration_node.token + 1;
|
||||||
const expected_identifier_token = analyzer.tokens[expected_identifier_token_index];
|
const expected_identifier_token = analyzer.getToken(scope_index, expected_identifier_token_index);
|
||||||
if (expected_identifier_token.id != .identifier) {
|
if (expected_identifier_token.id != .identifier) {
|
||||||
print("Error: found: {}", .{expected_identifier_token.id});
|
print("Error: found: {}", .{expected_identifier_token.id});
|
||||||
@panic("Expected identifier");
|
@panic("Expected identifier");
|
||||||
}
|
}
|
||||||
// TODO: Check if it is a keyword
|
// TODO: Check if it is a keyword
|
||||||
|
|
||||||
const identifier_index = try analyzer.identifierFromToken(expected_identifier_token_index);
|
const identifier_index = try analyzer.identifierFromToken(scope_index, expected_identifier_token_index);
|
||||||
|
|
||||||
const declaration_name = analyzer.tokenIdentifier(expected_identifier_token_index);
|
const declaration_name = analyzer.tokenIdentifier(scope_index, expected_identifier_token_index);
|
||||||
// Check if the symbol name is already occupied in the same scope
|
// Check if the symbol name is already occupied in the same scope
|
||||||
|
const scope = analyzer.module.scopes.get(scope_index);
|
||||||
const scope_lookup = try scope.declarations.getOrPut(analyzer.allocator, identifier_index);
|
const scope_lookup = try scope.declarations.getOrPut(analyzer.allocator, identifier_index);
|
||||||
if (scope_lookup.found_existing) {
|
if (scope_lookup.found_existing) {
|
||||||
std.debug.panic("Existing name in lookup: {s}", .{declaration_name});
|
std.debug.panic("Existing name in lookup: {s}", .{declaration_name});
|
||||||
@ -477,42 +655,22 @@ const Analyzer = struct {
|
|||||||
while (upper_scope_index.valid) {
|
while (upper_scope_index.valid) {
|
||||||
@panic("TODO: upper scope");
|
@panic("TODO: upper scope");
|
||||||
}
|
}
|
||||||
|
assert(declaration_node.right.valid);
|
||||||
|
|
||||||
const container_declaration_index = try analyzer.module.declarations.append(analyzer.allocator, .{
|
const declaration_allocation = try analyzer.module.declarations.append(analyzer.allocator, .{
|
||||||
.name = declaration_name,
|
.name = declaration_name,
|
||||||
.scope_type = .global,
|
.scope_type = scope_type,
|
||||||
.mutability = mutability,
|
.mutability = mutability,
|
||||||
.init_value = try analyzer.module.values.append(analyzer.allocator, .{
|
.init_value = (try analyzer.module.values.append(analyzer.allocator, .{
|
||||||
.unresolved = .{
|
.unresolved = .{
|
||||||
.node_index = declaration_node.right,
|
.node_index = declaration_node.right,
|
||||||
},
|
},
|
||||||
}),
|
})).index,
|
||||||
});
|
});
|
||||||
|
|
||||||
scope_lookup.value_ptr.* = container_declaration_index;
|
scope_lookup.value_ptr.* = declaration_allocation.index;
|
||||||
},
|
|
||||||
else => unreachable,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: consider iterating over scope declarations instead?
|
return declaration_allocation.index;
|
||||||
for (declaration_nodes.items) |declaration_node_index| {
|
|
||||||
const declaration_node = analyzer.nodes[declaration_node_index.unwrap()];
|
|
||||||
switch (declaration_node.id) {
|
|
||||||
.@"comptime" => _ = try analyzer.comptimeBlock(scope, declaration_node_index),
|
|
||||||
.simple_variable_declaration => {},
|
|
||||||
else => |t| @panic(@tagName(t)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (field_nodes.items) |field_index| {
|
|
||||||
const field_node = analyzer.nodes[field_index.unwrap()];
|
|
||||||
_ = field_node;
|
|
||||||
|
|
||||||
@panic("TODO: fields");
|
|
||||||
}
|
|
||||||
|
|
||||||
return type_index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MemberType = enum {
|
const MemberType = enum {
|
||||||
@ -528,8 +686,8 @@ const Analyzer = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn identifierFromToken(analyzer: *Analyzer, token_index: Token.Index) !u32 {
|
fn identifierFromToken(analyzer: *Analyzer, scope_index: Scope.Index, token_index: Token.Index) !u32 {
|
||||||
const identifier = analyzer.tokenIdentifier(token_index);
|
const identifier = analyzer.tokenIdentifier(scope_index, token_index);
|
||||||
const key: u32 = @truncate(std.hash.Wyhash.hash(0, identifier));
|
const key: u32 = @truncate(std.hash.Wyhash.hash(0, identifier));
|
||||||
|
|
||||||
const lookup_result = try analyzer.module.string_table.getOrPut(analyzer.allocator, key);
|
const lookup_result = try analyzer.module.string_table.getOrPut(analyzer.allocator, key);
|
||||||
@ -541,40 +699,40 @@ const Analyzer = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tokenIdentifier(analyzer: *Analyzer, token_index: Token.Index) []const u8 {
|
fn tokenIdentifier(analyzer: *Analyzer, scope_index: Scope.Index, token_index: Token.Index) []const u8 {
|
||||||
const token = analyzer.tokens[token_index];
|
const token = analyzer.getToken(scope_index, token_index);
|
||||||
assert(token.id == .identifier);
|
assert(token.id == .identifier);
|
||||||
const identifier = analyzer.tokenBytes(token);
|
const source_file = analyzer.getSourceFile(scope_index);
|
||||||
|
const identifier = tokenBytes(token, source_file);
|
||||||
|
|
||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tokenBytes(analyzer: *Analyzer, token: Token) []const u8 {
|
fn tokenBytes(token: Token, source_code: []const u8) []const u8 {
|
||||||
return analyzer.source_code[token.start..][0..token.len];
|
return source_code[token.start..][0..token.len];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tokenStringLiteral(analyzer: *Analyzer, token_index: Token.Index) []const u8 {
|
fn numberBytes(analyzer: *Analyzer, scope_index: Scope.Index, token_index: Token.Index) []const u8 {
|
||||||
const token = analyzer.tokens[token_index];
|
const token = analyzer.getToken(scope_index, token_index);
|
||||||
|
assert(token.id == .number_literal);
|
||||||
|
const source_file = analyzer.getSourceFile(scope_index);
|
||||||
|
const bytes = tokenBytes(token, source_file);
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tokenStringLiteral(analyzer: *Analyzer, scope_index: Scope.Index, token_index: Token.Index) []const u8 {
|
||||||
|
const token = analyzer.getToken(scope_index, token_index);
|
||||||
assert(token.id == .string_literal);
|
assert(token.id == .string_literal);
|
||||||
|
const source_file = analyzer.getSourceFile(scope_index);
|
||||||
// Eat double quotes
|
// Eat double quotes
|
||||||
const string_literal = analyzer.tokenBytes(token)[1..][0 .. token.len - 2];
|
const string_literal = tokenBytes(token, source_file)[1..][0 .. token.len - 2];
|
||||||
|
|
||||||
return string_literal;
|
return string_literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ScopeAllocation = struct {
|
fn allocateScope(analyzer: *Analyzer, scope_value: Scope) !Scope.Allocation {
|
||||||
ptr: *Scope,
|
return analyzer.module.scopes.append(analyzer.allocator, scope_value);
|
||||||
index: Scope.Index,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn allocateScope(analyzer: *Analyzer, scope_value: Scope) !ScopeAllocation {
|
|
||||||
const scope_index = try analyzer.module.scopes.append(analyzer.allocator, scope_value);
|
|
||||||
const scope = analyzer.module.scopes.get(scope_index);
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.ptr = scope,
|
|
||||||
.index = scope_index,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -647,7 +805,8 @@ const HardwareSignedIntegerType = enum {
|
|||||||
const offset = HardwareUnsignedIntegerType.offset + @typeInfo(HardwareUnsignedIntegerType).Enum.fields.len;
|
const offset = HardwareUnsignedIntegerType.offset + @typeInfo(HardwareUnsignedIntegerType).Enum.fields.len;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn initialize(compilation: *Compilation, module: *Module, package: *Package) !Type.Index {
|
pub fn initialize(compilation: *Compilation, module: *Module, package: *Package, file_index: File.Index) !Type.Index {
|
||||||
|
_ = file_index;
|
||||||
inline for (@typeInfo(FixedTypeKeyword).Enum.fields) |enum_field| {
|
inline for (@typeInfo(FixedTypeKeyword).Enum.fields) |enum_field| {
|
||||||
_ = try module.types.append(compilation.base_allocator, @unionInit(Type, enum_field.name, {}));
|
_ = try module.types.append(compilation.base_allocator, @unionInit(Type, enum_field.name, {}));
|
||||||
}
|
}
|
||||||
@ -692,58 +851,40 @@ pub fn initialize(compilation: *Compilation, module: *Module, package: *Package)
|
|||||||
.@"unreachable" = {},
|
.@"unreachable" = {},
|
||||||
});
|
});
|
||||||
|
|
||||||
return analyzeExistingPackage(compilation, module, package);
|
const value_allocation = try module.values.append(compilation.base_allocator, .{
|
||||||
|
.unresolved = .{
|
||||||
|
.node_index = .{ .value = 0 },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return analyzeExistingPackage(value_allocation.ptr, compilation, module, package);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analyzeExistingPackage(compilation: *Compilation, module: *Module, package: *Package) !Type.Index {
|
pub fn analyzeExistingPackage(value: *Value, compilation: *Compilation, module: *Module, package: *Package) !Type.Index {
|
||||||
const package_import = try module.importPackage(compilation.base_allocator, package);
|
const package_import = try module.importPackage(compilation.base_allocator, package);
|
||||||
assert(!package_import.is_new);
|
assert(!package_import.file.is_new);
|
||||||
const package_file = package_import.file;
|
const package_file = package_import.file.ptr;
|
||||||
|
const file_index = package_import.file.index;
|
||||||
|
|
||||||
return try analyzeFile(compilation.base_allocator, module, package_file);
|
return try analyzeFile(value, compilation.base_allocator, module, package_file, file_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analyzeFile(allocator: Allocator, module: *Module, file: *File) !Type.Index {
|
pub fn analyzeFile(value: *Value, allocator: Allocator, module: *Module, file: *File, file_index: File.Index) !Type.Index {
|
||||||
|
assert(value.* == .unresolved);
|
||||||
assert(file.status == .parsed);
|
assert(file.status == .parsed);
|
||||||
|
|
||||||
var analyzer = Analyzer{
|
var analyzer = Analyzer{
|
||||||
.source_code = file.source_code,
|
.current_file = file_index,
|
||||||
.nodes = file.syntactic_analyzer_result.nodes.items,
|
|
||||||
.tokens = file.lexical_analyzer_result.tokens.items,
|
|
||||||
.file = file,
|
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.module = module,
|
.module = module,
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = try analyzer.structType(Scope.Index.invalid, try mainNodeToContainerDeclaration(allocator, file), .{ .value = 0 });
|
var buffer = [2]Node.Index{
|
||||||
|
Node.Index.invalid,
|
||||||
|
Node.Index.invalid,
|
||||||
|
};
|
||||||
|
_ = buffer;
|
||||||
|
|
||||||
|
const result = try analyzer.structType(value, Scope.Index.invalid, .{ .value = 0 }, file_index);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mainNodeToContainerDeclaration(allocator: Allocator, file: *File) !ContainerDeclaration {
|
|
||||||
const main_node = getNode(file, 0);
|
|
||||||
var list_buffer: [2]Node.Index = undefined;
|
|
||||||
const left_node = getNode(file, main_node.left.value);
|
|
||||||
const node_list: []const Node.Index = blk: {
|
|
||||||
if (left_node.id != .node_list) {
|
|
||||||
const len = @as(u2, @intFromBool(main_node.left.valid)) + @as(u2, @intFromBool(main_node.right.valid)) - @as(u2, @intFromBool(main_node.left.valid and main_node.right.valid and main_node.left.value == main_node.right.value));
|
|
||||||
assert(len > 0);
|
|
||||||
list_buffer[0] = main_node.left;
|
|
||||||
list_buffer[1] = main_node.right;
|
|
||||||
break :blk list_buffer[0..len];
|
|
||||||
} else {
|
|
||||||
@panic("TODO: get list");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const owned_node_list = try allocator.alloc(Node.Index, node_list.len);
|
|
||||||
@memcpy(owned_node_list, node_list);
|
|
||||||
|
|
||||||
// Deal properly with this allocation
|
|
||||||
return .{
|
|
||||||
.members = owned_node_list,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn getNode(file: *const File, index: u32) *Node {
|
|
||||||
return &file.syntactic_analyzer_result.nodes.items[index];
|
|
||||||
}
|
|
||||||
|
@ -14,6 +14,7 @@ const Token = lexical_analyzer.Token;
|
|||||||
|
|
||||||
pub const Result = struct {
|
pub const Result = struct {
|
||||||
nodes: ArrayList(Node),
|
nodes: ArrayList(Node),
|
||||||
|
node_lists: ArrayList(Node.List),
|
||||||
time: u64,
|
time: u64,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -47,6 +48,11 @@ pub const Node = packed struct(u128) {
|
|||||||
assert(index.valid);
|
assert(index.valid);
|
||||||
return index.value;
|
return index.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn uniqueInteger(index: Index) u32 {
|
||||||
|
assert(index.valid);
|
||||||
|
return index.value;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Range = struct {
|
pub const Range = struct {
|
||||||
@ -81,6 +87,15 @@ pub const Node = packed struct(u128) {
|
|||||||
comptime_block_two = 23,
|
comptime_block_two = 23,
|
||||||
block_two = 24,
|
block_two = 24,
|
||||||
@"unreachable" = 25,
|
@"unreachable" = 25,
|
||||||
|
field_access = 26,
|
||||||
|
call_one = 27,
|
||||||
|
comptime_block = 28,
|
||||||
|
block = 29,
|
||||||
|
unsigned_integer_type = 30,
|
||||||
|
signed_integer_type = 31,
|
||||||
|
main_one = 32,
|
||||||
|
main_two = 33,
|
||||||
|
main_zero = 34,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -109,10 +124,37 @@ const Analyzer = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getIdentifier(analyzer: *const Analyzer, token: Token) []const u8 {
|
fn bytes(analyzer: *const Analyzer, token_index: Token.Index) []const u8 {
|
||||||
assert(token.id == .identifier);
|
const token = analyzer.tokens[token_index];
|
||||||
const identifier = analyzer.file[token.start..][0..token.len];
|
return analyzer.file[token.start..][0..token.len];
|
||||||
return identifier;
|
}
|
||||||
|
|
||||||
|
fn symbolDeclaration(analyzer: *Analyzer) !Node.Index {
|
||||||
|
const first = analyzer.token_i;
|
||||||
|
assert(analyzer.tokens[first].id == .fixed_keyword_var or analyzer.tokens[first].id == .fixed_keyword_const);
|
||||||
|
analyzer.token_i += 1;
|
||||||
|
_ = try analyzer.expectToken(.identifier);
|
||||||
|
|
||||||
|
// TODO: type
|
||||||
|
_ = try analyzer.expectToken(.equal);
|
||||||
|
|
||||||
|
const init_node = try analyzer.expression();
|
||||||
|
|
||||||
|
_ = try analyzer.expectToken(.semicolon);
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
const type_node = Node.Index.invalid;
|
||||||
|
const declaration = Node{
|
||||||
|
.id = .simple_variable_declaration,
|
||||||
|
.token = first,
|
||||||
|
.left = type_node,
|
||||||
|
.right = init_node,
|
||||||
|
};
|
||||||
|
|
||||||
|
const declaration_init_node = analyzer.nodes.items[init_node.unwrap()];
|
||||||
|
std.debug.print("Declaration init node: {}\n", .{declaration_init_node});
|
||||||
|
|
||||||
|
return analyzer.addNode(declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn containerMembers(analyzer: *Analyzer) !Members {
|
fn containerMembers(analyzer: *Analyzer) !Members {
|
||||||
@ -121,58 +163,26 @@ const Analyzer = struct {
|
|||||||
|
|
||||||
while (analyzer.token_i < analyzer.tokens.len) {
|
while (analyzer.token_i < analyzer.tokens.len) {
|
||||||
const first = analyzer.token_i;
|
const first = analyzer.token_i;
|
||||||
const member_node: Node = switch (analyzer.tokens[first].id) {
|
const member_node_index: Node.Index = switch (analyzer.tokens[first].id) {
|
||||||
.fixed_keyword_comptime => switch (analyzer.tokens[analyzer.token_i + 1].id) {
|
.fixed_keyword_comptime => switch (analyzer.tokens[analyzer.token_i + 1].id) {
|
||||||
.left_brace => blk: {
|
.left_brace => blk: {
|
||||||
analyzer.token_i += 1;
|
analyzer.token_i += 1;
|
||||||
const comptime_block = try analyzer.block(.{ .is_comptime = true });
|
const comptime_block = try analyzer.block(.{ .is_comptime = true });
|
||||||
|
|
||||||
break :blk .{
|
break :blk try analyzer.addNode(.{
|
||||||
.id = .@"comptime",
|
.id = .@"comptime",
|
||||||
.token = first,
|
.token = first,
|
||||||
.left = comptime_block,
|
.left = comptime_block,
|
||||||
.right = Node.Index.invalid,
|
.right = Node.Index.invalid,
|
||||||
};
|
});
|
||||||
},
|
},
|
||||||
else => |foo| std.debug.panic("NI: {s}", .{@tagName(foo)}),
|
else => |foo| @panic(@tagName(foo)),
|
||||||
},
|
},
|
||||||
.fixed_keyword_const, .fixed_keyword_var => blk: {
|
.fixed_keyword_const, .fixed_keyword_var => try analyzer.symbolDeclaration(),
|
||||||
analyzer.token_i += 1;
|
else => |t| @panic(@tagName(t)),
|
||||||
_ = try analyzer.expectToken(.identifier);
|
|
||||||
|
|
||||||
// TODO: type
|
|
||||||
_ = try analyzer.expectToken(.equal);
|
|
||||||
|
|
||||||
// TODO: do this in a function
|
|
||||||
const init_node = try analyzer.expression();
|
|
||||||
// const init_node = switch (analyzer.tokens[analyzer.token_i].id) {
|
|
||||||
// .identifier => unreachable,
|
|
||||||
// .hash => try analyzer.compilerIntrinsic(),
|
|
||||||
// .left_parenthesis => try analyzer.function(),
|
|
||||||
// else => |t| std.debug.panic("NI: {s}", .{@tagName(t)}),
|
|
||||||
// };
|
|
||||||
|
|
||||||
_ = try analyzer.expectToken(.semicolon);
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
const type_node = Node.Index.invalid;
|
|
||||||
const top_level_decl = .{
|
|
||||||
.id = .simple_variable_declaration,
|
|
||||||
.token = first,
|
|
||||||
.left = type_node,
|
|
||||||
.right = init_node,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
break :blk top_level_decl;
|
try analyzer.temporal_node_heap.append(analyzer.allocator, member_node_index);
|
||||||
},
|
|
||||||
.identifier => {
|
|
||||||
unreachable;
|
|
||||||
},
|
|
||||||
else => |t| std.debug.panic("NI: {s}", .{@tagName(t)}),
|
|
||||||
};
|
|
||||||
|
|
||||||
const member_index = try analyzer.addNode(member_node);
|
|
||||||
try analyzer.temporal_node_heap.append(analyzer.allocator, member_index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const members_array = analyzer.temporal_node_heap.items[node_heap_top..];
|
const members_array = analyzer.temporal_node_heap.items[node_heap_top..];
|
||||||
@ -263,10 +273,12 @@ const Analyzer = struct {
|
|||||||
},
|
},
|
||||||
else => try analyzer.assignExpressionStatement(),
|
else => try analyzer.assignExpressionStatement(),
|
||||||
},
|
},
|
||||||
.fixed_keyword_unreachable => try analyzer.assignExpressionStatement(),
|
.fixed_keyword_unreachable, .fixed_keyword_return => try analyzer.assignExpressionStatement(),
|
||||||
.fixed_keyword_while => try analyzer.whileStatement(options),
|
.fixed_keyword_while => try analyzer.whileStatement(options),
|
||||||
else => unreachable,
|
.fixed_keyword_const, .fixed_keyword_var => try analyzer.symbolDeclaration(),
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
|
|
||||||
try analyzer.temporal_node_heap.append(analyzer.allocator, statement_index);
|
try analyzer.temporal_node_heap.append(analyzer.allocator, statement_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +313,15 @@ const Analyzer = struct {
|
|||||||
.left = statement_array[0],
|
.left = statement_array[0],
|
||||||
.right = statement_array[1],
|
.right = statement_array[1],
|
||||||
},
|
},
|
||||||
else => |len| std.debug.panic("len: {}", .{len}),
|
else => .{
|
||||||
|
.id = switch (options.is_comptime) {
|
||||||
|
true => .comptime_block,
|
||||||
|
false => .block,
|
||||||
|
},
|
||||||
|
.token = left_brace,
|
||||||
|
.left = try analyzer.nodeList(statement_array),
|
||||||
|
.right = Node.Index.invalid,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
return analyzer.addNode(node);
|
return analyzer.addNode(node);
|
||||||
}
|
}
|
||||||
@ -329,7 +349,7 @@ const Analyzer = struct {
|
|||||||
const expression_id: Node.Id = switch (analyzer.tokens[analyzer.token_i].id) {
|
const expression_id: Node.Id = switch (analyzer.tokens[analyzer.token_i].id) {
|
||||||
.semicolon => return expr,
|
.semicolon => return expr,
|
||||||
.equal => .assign,
|
.equal => .assign,
|
||||||
else => unreachable,
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
|
|
||||||
const node = Node{
|
const node = Node{
|
||||||
@ -398,8 +418,8 @@ const Analyzer = struct {
|
|||||||
|
|
||||||
while (analyzer.token_i < analyzer.tokens.len) {
|
while (analyzer.token_i < analyzer.tokens.len) {
|
||||||
const precedence: i32 = switch (analyzer.tokens[analyzer.token_i].id) {
|
const precedence: i32 = switch (analyzer.tokens[analyzer.token_i].id) {
|
||||||
.equal, .semicolon, .right_parenthesis, .right_brace, .comma => -1,
|
.equal, .semicolon, .right_parenthesis, .right_brace, .comma, .period => -1,
|
||||||
else => |foo| std.debug.panic("Foo: ({s}) {}", .{ @tagName(foo), foo }),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (precedence < minimum_precedence) {
|
if (precedence < minimum_precedence) {
|
||||||
@ -446,6 +466,16 @@ const Analyzer = struct {
|
|||||||
},
|
},
|
||||||
.string_literal, .number_literal, .fixed_keyword_true, .fixed_keyword_false, .hash, .fixed_keyword_unreachable => try analyzer.curlySuffixExpression(),
|
.string_literal, .number_literal, .fixed_keyword_true, .fixed_keyword_false, .hash, .fixed_keyword_unreachable => try analyzer.curlySuffixExpression(),
|
||||||
.fixed_keyword_fn => analyzer.function(),
|
.fixed_keyword_fn => analyzer.function(),
|
||||||
|
.fixed_keyword_return => try analyzer.addNode(.{
|
||||||
|
.id = .@"return",
|
||||||
|
.token = blk: {
|
||||||
|
const token = analyzer.token_i;
|
||||||
|
analyzer.token_i += 1;
|
||||||
|
break :blk token;
|
||||||
|
},
|
||||||
|
.left = try analyzer.expression(),
|
||||||
|
.right = Node.Index.invalid,
|
||||||
|
}),
|
||||||
// todo:?
|
// todo:?
|
||||||
// .left_brace => try analyzer.block(),
|
// .left_brace => try analyzer.block(),
|
||||||
else => |id| {
|
else => |id| {
|
||||||
@ -492,14 +522,8 @@ const Analyzer = struct {
|
|||||||
|
|
||||||
fn typeExpression(analyzer: *Analyzer) !Node.Index {
|
fn typeExpression(analyzer: *Analyzer) !Node.Index {
|
||||||
return switch (analyzer.tokens[analyzer.token_i].id) {
|
return switch (analyzer.tokens[analyzer.token_i].id) {
|
||||||
.identifier, .fixed_keyword_noreturn, .fixed_keyword_true, .fixed_keyword_false, .hash => try analyzer.errorUnionExpression(),
|
.identifier, .fixed_keyword_noreturn, .fixed_keyword_true, .fixed_keyword_false, .hash, .string_literal, .number_literal, .fixed_keyword_unreachable, .keyword_unsigned_integer, .keyword_signed_integer => try analyzer.errorUnionExpression(),
|
||||||
else => |id| blk: {
|
else => |id| @panic(@tagName(id)),
|
||||||
log.warn("By default, calling errorUnionExpression with {s}", .{@tagName(id)});
|
|
||||||
|
|
||||||
const result = try analyzer.errorUnionExpression();
|
|
||||||
|
|
||||||
break :blk result;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,14 +540,17 @@ const Analyzer = struct {
|
|||||||
var result = try analyzer.primaryTypeExpression();
|
var result = try analyzer.primaryTypeExpression();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (analyzer.suffixOperator()) |_| {
|
const suffix_operator = try analyzer.suffixOperator(result);
|
||||||
unreachable;
|
if (suffix_operator.valid) {
|
||||||
|
result = suffix_operator;
|
||||||
} else {
|
} else {
|
||||||
if (analyzer.tokens[analyzer.token_i].id == .left_parenthesis) {
|
if (analyzer.tokens[analyzer.token_i].id == .left_parenthesis) {
|
||||||
|
const left_parenthesis = analyzer.token_i;
|
||||||
analyzer.token_i += 1;
|
analyzer.token_i += 1;
|
||||||
|
|
||||||
var expression_list = ArrayList(Node.Index){};
|
var expression_list = ArrayList(Node.Index){};
|
||||||
while (analyzer.tokens[analyzer.token_i].id != .right_parenthesis) {
|
while (analyzer.tokens[analyzer.token_i].id != .right_parenthesis) {
|
||||||
|
std.debug.print("Loop\n", .{});
|
||||||
const parameter = try analyzer.expression();
|
const parameter = try analyzer.expression();
|
||||||
try expression_list.append(analyzer.allocator, parameter);
|
try expression_list.append(analyzer.allocator, parameter);
|
||||||
analyzer.token_i += @intFromBool(switch (analyzer.tokens[analyzer.token_i].id) {
|
analyzer.token_i += @intFromBool(switch (analyzer.tokens[analyzer.token_i].id) {
|
||||||
@ -534,7 +561,16 @@ const Analyzer = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ = try analyzer.expectToken(.right_parenthesis);
|
_ = try analyzer.expectToken(.right_parenthesis);
|
||||||
@panic("TODO");
|
// const is_comma = analyzer.tokens[analyzer.token_i].id == .comma;
|
||||||
|
return analyzer.addNode(switch (expression_list.items.len) {
|
||||||
|
0 => .{
|
||||||
|
.id = .call_one,
|
||||||
|
.token = left_parenthesis,
|
||||||
|
.left = result,
|
||||||
|
.right = Node.Index.invalid,
|
||||||
|
},
|
||||||
|
else => |len| std.debug.panic("len: {}", .{len}),
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -569,8 +605,8 @@ const Analyzer = struct {
|
|||||||
.identifier => switch (analyzer.tokens[token_i + 1].id) {
|
.identifier => switch (analyzer.tokens[token_i + 1].id) {
|
||||||
.colon => unreachable,
|
.colon => unreachable,
|
||||||
else => blk: {
|
else => blk: {
|
||||||
const identifier = analyzer.getIdentifier(token);
|
const identifier = analyzer.bytes(token_i);
|
||||||
std.debug.print("identifier: {s}\n", .{identifier});
|
// std.debug.print("identifier: {s}\n", .{identifier});
|
||||||
analyzer.token_i += 1;
|
analyzer.token_i += 1;
|
||||||
if (equal(u8, identifier, "_")) {
|
if (equal(u8, identifier, "_")) {
|
||||||
break :blk Node.Index.invalid;
|
break :blk Node.Index.invalid;
|
||||||
@ -594,20 +630,55 @@ const Analyzer = struct {
|
|||||||
.right = Node.Index.invalid,
|
.right = Node.Index.invalid,
|
||||||
}),
|
}),
|
||||||
.hash => analyzer.compilerIntrinsic(),
|
.hash => analyzer.compilerIntrinsic(),
|
||||||
|
.keyword_unsigned_integer, .keyword_signed_integer => |signedness| try analyzer.addNode(.{
|
||||||
|
.id = switch (signedness) {
|
||||||
|
.keyword_unsigned_integer => .unsigned_integer_type,
|
||||||
|
.keyword_signed_integer => .signed_integer_type,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.token = blk: {
|
||||||
|
analyzer.token_i += 1;
|
||||||
|
break :blk token_i;
|
||||||
|
},
|
||||||
|
.left = @bitCast(@as(u32, std.fmt.parseInt(u16, analyzer.bytes(token_i)[1..], 10) catch unreachable)),
|
||||||
|
.right = Node.Index.invalid,
|
||||||
|
}),
|
||||||
else => |foo| {
|
else => |foo| {
|
||||||
switch (foo) {
|
switch (foo) {
|
||||||
.identifier => std.debug.panic("{s}: {s}", .{ @tagName(foo), analyzer.getIdentifier(analyzer.tokens[token_i]) }),
|
.identifier => std.debug.panic("{s}: {s}", .{ @tagName(foo), analyzer.bytes(token_i) }),
|
||||||
else => std.debug.panic("{s}", .{@tagName(foo)}),
|
else => @panic(@tagName(foo)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
fn suffixOperator(analyzer: *Analyzer) ?bool {
|
fn suffixOperator(analyzer: *Analyzer, left: Node.Index) !Node.Index {
|
||||||
_ = analyzer;
|
const token = analyzer.tokens[analyzer.token_i];
|
||||||
|
return switch (token.id) {
|
||||||
return null;
|
.left_bracket => unreachable,
|
||||||
|
.period => switch (analyzer.tokens[analyzer.token_i + 1].id) {
|
||||||
|
.identifier => analyzer.addNode(.{
|
||||||
|
.id = .field_access,
|
||||||
|
.token = blk: {
|
||||||
|
const main_token = analyzer.token_i;
|
||||||
|
analyzer.token_i += 1;
|
||||||
|
break :blk main_token;
|
||||||
|
},
|
||||||
|
.left = left,
|
||||||
|
.right = blk: {
|
||||||
|
//TODO ???
|
||||||
|
const right_token = analyzer.token_i;
|
||||||
|
analyzer.token_i += 1;
|
||||||
|
const result: Node.Index = @bitCast(right_token);
|
||||||
|
std.debug.print("WARNING: rhs has node index {} but it's token #{}\n", .{ result, right_token });
|
||||||
|
break :blk result;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
},
|
||||||
|
else => Node.Index.invalid,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addNode(analyzer: *Analyzer, node: Node) !Node.Index {
|
fn addNode(analyzer: *Analyzer, node: Node) !Node.Index {
|
||||||
@ -618,27 +689,23 @@ const Analyzer = struct {
|
|||||||
.value = @intCast(index),
|
.value = @intCast(index),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn nodeList(analyzer: *Analyzer, input: []const Node.Index) !Node.Index {
|
||||||
|
const index = analyzer.node_lists.items.len;
|
||||||
|
var new_node_list = try ArrayList(Node.Index).initCapacity(analyzer.allocator, input.len);
|
||||||
|
try new_node_list.appendSlice(analyzer.allocator, input);
|
||||||
|
try analyzer.node_lists.append(analyzer.allocator, new_node_list);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.value = @intCast(index),
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Members = struct {
|
const Members = struct {
|
||||||
len: usize,
|
len: usize,
|
||||||
left: Node.Index,
|
left: Node.Index,
|
||||||
right: Node.Index,
|
right: Node.Index,
|
||||||
|
|
||||||
pub fn toRange(members: Members) Node.Range {
|
|
||||||
return switch (members.len) {
|
|
||||||
0 => unreachable,
|
|
||||||
1 => .{
|
|
||||||
.start = members.left.value,
|
|
||||||
.end = members.left.value,
|
|
||||||
},
|
|
||||||
2 => .{
|
|
||||||
.start = members.left.value,
|
|
||||||
.end = members.right.value,
|
|
||||||
},
|
|
||||||
else => unreachable,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn analyze(allocator: Allocator, tokens: []const Token, file: []const u8) !Result {
|
pub fn analyze(allocator: Allocator, tokens: []const Token, file: []const u8) !Result {
|
||||||
@ -657,10 +724,22 @@ pub fn analyze(allocator: Allocator, tokens: []const Token, file: []const u8) !R
|
|||||||
|
|
||||||
assert(node_index.value == 0);
|
assert(node_index.value == 0);
|
||||||
assert(node_index.valid);
|
assert(node_index.valid);
|
||||||
|
|
||||||
const members = try analyzer.containerMembers();
|
const members = try analyzer.containerMembers();
|
||||||
const member_range = members.toRange();
|
|
||||||
analyzer.nodes.items[0].left = .{ .value = @intCast(member_range.start) };
|
switch (members.len) {
|
||||||
analyzer.nodes.items[0].right = .{ .value = @intCast(member_range.end) };
|
0 => unreachable,
|
||||||
|
1 => {
|
||||||
|
analyzer.nodes.items[0].id = .main_one;
|
||||||
|
analyzer.nodes.items[0].left = members.left;
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
analyzer.nodes.items[0].id = .main_two;
|
||||||
|
analyzer.nodes.items[0].left = members.left;
|
||||||
|
analyzer.nodes.items[0].right = members.right;
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
|
||||||
const end = std.time.Instant.now() catch unreachable;
|
const end = std.time.Instant.now() catch unreachable;
|
||||||
|
|
||||||
@ -668,6 +747,7 @@ pub fn analyze(allocator: Allocator, tokens: []const Token, file: []const u8) !R
|
|||||||
|
|
||||||
return .{
|
return .{
|
||||||
.nodes = analyzer.nodes,
|
.nodes = analyzer.nodes,
|
||||||
|
.node_lists = analyzer.node_lists,
|
||||||
.time = end.since(start),
|
.time = end.since(start),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
pub const first = "src/test/main.b";
|
|
||||||
|
|
||||||
pub fn readFile(allocator: Allocator, file_relative_path: []const u8) ![]const u8 {
|
pub fn readFile(allocator: Allocator, file_relative_path: []const u8) ![]const u8 {
|
||||||
const file = try std.fs.cwd().readFileAlloc(allocator, file_relative_path, std.math.maxInt(usize));
|
const file = try std.fs.cwd().readFileAlloc(allocator, file_relative_path, std.math.maxInt(usize));
|
||||||
return file;
|
return file;
|
||||||
|
@ -5,7 +5,7 @@ const assert = std.debug.assert;
|
|||||||
const Compilation = @import("Compilation.zig");
|
const Compilation = @import("Compilation.zig");
|
||||||
|
|
||||||
pub const seed = std.math.maxInt(u64);
|
pub const seed = std.math.maxInt(u64);
|
||||||
const default_src_file = "src/test/main.b";
|
const default_src_file = "src/test/main.nat";
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
try singleCompilation(default_src_file);
|
try singleCompilation(default_src_file);
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
const main = fn() i32 {
|
const main = fn() s32 {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user