Merge pull request #35 from birth-software/c-libraries

implement extern functionality
This commit is contained in:
David 2023-12-19 19:18:51 +01:00 committed by GitHub
commit 76332f5ad7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 137 additions and 52 deletions

View File

@ -563,7 +563,6 @@ pub const Declaration = struct {
}; };
pub const Function = struct { pub const Function = struct {
scope: Scope.Index,
body: Block.Index, body: Block.Index,
prototype: Type.Index, prototype: Type.Index,
@ -571,11 +570,12 @@ pub const Function = struct {
arguments: ArrayList(Declaration.Index), arguments: ArrayList(Declaration.Index),
return_type: Type.Index, return_type: Type.Index,
attributes: Attributes = .{}, attributes: Attributes = .{},
scope: Scope.Index,
pub const List = BlockList(@This()); pub const List = BlockList(@This());
pub const Index = Prototype.List.Index; pub const Index = Prototype.List.Index;
pub const Attributes = packed struct { pub const Attributes = struct {
@"extern": bool = false, @"extern": bool = false,
@"export": bool = false, @"export": bool = false,
@"inline": Inline = .none, @"inline": Inline = .none,
@ -885,7 +885,6 @@ pub const Value = union(enum) {
indexed_access: IndexedAccess.Index, indexed_access: IndexedAccess.Index,
optional_check: OptionalCheck.Index, optional_check: OptionalCheck.Index,
optional_unwrap: OptionalUnwrap.Index, optional_unwrap: OptionalUnwrap.Index,
// optional_cast: Cast.Index,
array_coerce_to_slice: Cast.Index, array_coerce_to_slice: Cast.Index,
slice: Slice.Index, slice: Slice.Index,
assembly_block: Assembly.Block.Index, assembly_block: Assembly.Block.Index,
@ -908,9 +907,16 @@ pub const Value = union(enum) {
_ = module; _ = module;
return switch (value.*) { return switch (value.*) {
.bool,
.void,
.function_definition,
.function_declaration,
.type,
.enum_field,
.string_literal,
=> true,
.integer => |integer| integer.type.eq(Type.comptime_int), .integer => |integer| integer.type.eq(Type.comptime_int),
.declaration_reference => false, .declaration_reference => false,
.bool, .void, .function_definition, .type, .enum_field => true,
// TODO: // TODO:
.call, .call,
// .syscall, // .syscall,
@ -1048,7 +1054,8 @@ pub const Module = struct {
function_prototypes: BlockList(Function.Prototype) = .{}, function_prototypes: BlockList(Function.Prototype) = .{},
} = .{}, } = .{},
map: struct { map: struct {
functions: data_structures.AutoArrayHashMap(Function.Index, Declaration.Index) = .{}, function_definitions: data_structures.AutoArrayHashMap(Function.Index, Declaration.Index) = .{},
function_declarations: data_structures.AutoArrayHashMap(Function.Index, Declaration.Index) = .{},
strings: StringKeyMap([]const u8) = .{}, strings: StringKeyMap([]const u8) = .{},
imports: StringArrayHashMap(File.Index) = .{}, imports: StringArrayHashMap(File.Index) = .{},
types: data_structures.AutoArrayHashMap(Type.Index, Declaration.Index) = .{}, types: data_structures.AutoArrayHashMap(Type.Index, Declaration.Index) = .{},
@ -1057,6 +1064,7 @@ pub const Module = struct {
pointers: data_structures.AutoArrayHashMap(Type.Pointer, Type.Index) = .{}, pointers: data_structures.AutoArrayHashMap(Type.Pointer, Type.Index) = .{},
optionals: data_structures.AutoArrayHashMap(Type.Index, Type.Index) = .{}, optionals: data_structures.AutoArrayHashMap(Type.Index, Type.Index) = .{},
arrays: data_structures.AutoArrayHashMap(Type.Array, Type.Index) = .{}, arrays: data_structures.AutoArrayHashMap(Type.Array, Type.Index) = .{},
libraries: data_structures.StringArrayHashMap(void) = .{},
} = .{}, } = .{},
main_package: *Package, main_package: *Package,
entry_point: Function.Index = Function.Index.invalid, entry_point: Function.Index = Function.Index.invalid,

View File

@ -64,7 +64,8 @@ pub const TranslationUnit = struct {
global_variable_declarations: ArrayList(u8) = .{}, global_variable_declarations: ArrayList(u8) = .{},
function_definitions: ArrayList(u8) = .{}, function_definitions: ArrayList(u8) = .{},
syscall_bitset: SyscallBitset = SyscallBitset.initEmpty(), syscall_bitset: SyscallBitset = SyscallBitset.initEmpty(),
function_set: AutoArrayHashMap(Compilation.Function.Index, []const u8) = .{}, function_definition_set: AutoArrayHashMap(Compilation.Function.Index, []const u8) = .{},
function_declaration_set: AutoArrayHashMap(Compilation.Function.Index, []const u8) = .{},
macro_set: std.EnumSet(Macro) = std.EnumSet(Macro).initEmpty(), macro_set: std.EnumSet(Macro) = std.EnumSet(Macro).initEmpty(),
struct_type_set: TypeSet = .{}, struct_type_set: TypeSet = .{},
optional_type_set: TypeSet = .{}, optional_type_set: TypeSet = .{},
@ -102,6 +103,13 @@ pub const TranslationUnit = struct {
\\ \\
); );
{
var function_declarations = module.types.function_declarations.iterator();
while (function_declarations.nextIndex()) |function_declaration_index| {
_ = try unit.writeFunctionDeclaration(module, allocator, function_declaration_index);
}
}
{ {
var function_definitions = module.types.function_definitions.iterator(); var function_definitions = module.types.function_definitions.iterator();
while (function_definitions.nextIndex()) |function_definition_index| { while (function_definitions.nextIndex()) |function_definition_index| {
@ -112,18 +120,33 @@ pub const TranslationUnit = struct {
return unit; return unit;
} }
fn writeFunctionDeclaration(unit: *TranslationUnit, module: *Module, allocator: Allocator, function_declaration_index: Compilation.Function.Index) ![]const u8 {
if (unit.function_declaration_set.getIndex(function_declaration_index)) |index| {
return unit.function_declaration_set.values()[index];
} else {
const function_name = try unit.renderFunctionDeclarationName(module, allocator, function_declaration_index);
try unit.writeFunctionHeader(module, &unit.function_declarations, allocator, module.types.function_declarations.get(function_declaration_index), function_name);
try unit.function_declaration_set.putNoClobber(allocator, function_declaration_index, function_name);
try unit.function_declarations.appendSlice(allocator, ";\n\n");
return function_name;
}
}
fn writeFunctionDefinition(unit: *TranslationUnit, module: *Module, allocator: Allocator, function_definition_index: Compilation.Function.Index) ![]const u8 { fn writeFunctionDefinition(unit: *TranslationUnit, module: *Module, allocator: Allocator, function_definition_index: Compilation.Function.Index) ![]const u8 {
if (unit.function_set.getIndex(function_definition_index)) |index| { if (unit.function_definition_set.getIndex(function_definition_index)) |index| {
return unit.function_set.values()[index]; return unit.function_definition_set.values()[index];
} else { } else {
const function_definition = module.types.function_definitions.get(function_definition_index); const function_definition = module.types.function_definitions.get(function_definition_index);
const function_prototype_type = function_definition.prototype; const function_prototype_type = function_definition.prototype;
const function_prototype = module.types.function_prototypes.get(module.types.array.get(function_prototype_type).function); const function_prototype = module.types.function_prototypes.get(module.types.array.get(function_prototype_type).function);
const function_name = try unit.writeFunctionHeader(module, &unit.function_declarations, allocator, function_definition_index); const function_name = try unit.renderFunctionDefinitionName(module, allocator, function_definition_index);
try unit.function_set.putNoClobber(allocator, function_definition_index, function_name); try unit.writeFunctionHeader(module, &unit.function_declarations, allocator, function_definition, function_name);
try unit.function_definition_set.putNoClobber(allocator, function_definition_index, function_name);
_ = try unit.writeFunctionHeader(module, &unit.function_definitions, allocator, function_definition_index); try unit.writeFunctionHeader(module, &unit.function_definitions, allocator, function_definition, function_name);
try unit.function_declarations.appendSlice(allocator, ";\n\n"); try unit.function_declarations.appendSlice(allocator, ";\n\n");
try unit.function_definitions.append(allocator, ' '); try unit.function_definitions.append(allocator, ' ');
@ -387,17 +410,28 @@ pub const TranslationUnit = struct {
return result; return result;
} }
fn renderFunctionName(unit: *TranslationUnit, module: *Module, allocator: Allocator, function_index: Compilation.Function.Index) ![]const u8 { fn renderFunctionDefinitionName(unit: *TranslationUnit, module: *Module, allocator: Allocator, function_definition_index: Compilation.Function.Index) ![]const u8 {
const function_definition = module.types.function_definitions.get(function_index); const function_definition = module.types.function_definitions.get(function_definition_index);
const function_prototype_type = module.types.array.get(function_definition.prototype); const function_prototype_type = module.types.array.get(function_definition.prototype);
const function_prototype_index = function_prototype_type.function; const function_prototype_index = function_prototype_type.function;
const function_prototype = module.types.function_prototypes.get(function_prototype_index); const function_prototype = module.types.function_prototypes.get(function_prototype_index);
const mangle = !(function_prototype.attributes.@"export" or function_prototype.attributes.@"extern"); const mangle = !(function_prototype.attributes.@"export" or function_prototype.attributes.@"extern");
const function_declaration_index = module.map.functions.get(function_index).?; const function_declaration_index = module.map.function_definitions.get(function_definition_index).?;
const name = try unit.renderDeclarationName(module, allocator, function_declaration_index, mangle); const name = try unit.renderDeclarationName(module, allocator, function_declaration_index, mangle);
return name; return name;
} }
fn renderFunctionDeclarationName(unit: *TranslationUnit, module: *Module, allocator: Allocator, function_declaration_index: Compilation.Function.Index) ![]const u8 {
const function_declaration = module.types.function_declarations.get(function_declaration_index);
const function_prototype_type = module.types.array.get(function_declaration.prototype);
const function_prototype_index = function_prototype_type.function;
const function_prototype = module.types.function_prototypes.get(function_prototype_index);
const mangle = !(function_prototype.attributes.@"export" or function_prototype.attributes.@"extern");
const declaration_index = module.map.function_declarations.get(function_declaration_index).?;
const name = try unit.renderDeclarationName(module, allocator, declaration_index, mangle);
return name;
}
fn renderDeclarationName(unit: *TranslationUnit, module: *Module, allocator: Allocator, declaration_index: Compilation.Declaration.Index, mangle: bool) anyerror![]const u8 { fn renderDeclarationName(unit: *TranslationUnit, module: *Module, allocator: Allocator, declaration_index: Compilation.Declaration.Index, mangle: bool) anyerror![]const u8 {
if (unit.declaration_set.getIndex(declaration_index)) |index| { if (unit.declaration_set.getIndex(declaration_index)) |index| {
return unit.declaration_set.values()[index]; return unit.declaration_set.values()[index];
@ -481,6 +515,11 @@ pub const TranslationUnit = struct {
try list.appendSlice(allocator, "int main(int argc, char** argv, char** envp)"); try list.appendSlice(allocator, "int main(int argc, char** argv, char** envp)");
} else { } else {
const function_prototype = module.types.function_prototypes.get(function_prototype_index); const function_prototype = module.types.function_prototypes.get(function_prototype_index);
if (function_prototype.attributes.@"extern") {
try list.appendSlice(allocator, "extern ");
}
switch (function_prototype.attributes.calling_convention) { switch (function_prototype.attributes.calling_convention) {
.system_v => {}, .system_v => {},
.naked => try list.appendSlice(allocator, "[[gnu::naked]] "), .naked => try list.appendSlice(allocator, "[[gnu::naked]] "),
@ -494,14 +533,12 @@ pub const TranslationUnit = struct {
try list.append(allocator, '('); try list.append(allocator, '(');
if (function_prototype.arguments.items.len > 0) { if (function_prototype.arguments.items.len > 0) {
for (function_prototype.arguments.items, 0..) |argument_index, index| { for (function_prototype.arguments.items, 0..) |argument_index, index| {
_ = index; _ = index;
const arg_declaration = module.values.declarations.get(argument_index); const arg_declaration = module.values.declarations.get(argument_index);
if (is_main) { if (is_main) {} else {
} else {
try unit.writeType(module, list, allocator, arg_declaration.getType(), ' '); try unit.writeType(module, list, allocator, arg_declaration.getType(), ' ');
} }
try list.append(allocator, ' '); try list.append(allocator, ' ');
@ -517,15 +554,11 @@ pub const TranslationUnit = struct {
} }
} }
fn writeFunctionHeader(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, function_index: Compilation.Function.Index) ![]const u8 { fn writeFunctionHeader(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, function: *const Compilation.Function, name: []const u8) !void {
const name = try unit.renderFunctionName(module, allocator, function_index); const function_prototype_type = module.types.array.get(function.prototype);
const function_definition = module.types.function_definitions.get(function_index);
const function_prototype_type = module.types.array.get(function_definition.prototype);
const function_prototype_index = function_prototype_type.function; const function_prototype_index = function_prototype_type.function;
try unit.writeFunctionPrototype(module, list, allocator, function_prototype_index, name); try unit.writeFunctionPrototype(module, list, allocator, function_prototype_index, name);
return name;
} }
fn writeType(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, type_index: Type.Index, separation_character: u8) anyerror!void { fn writeType(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, type_index: Type.Index, separation_character: u8) anyerror!void {
@ -1241,12 +1274,10 @@ pub const TranslationUnit = struct {
const call = module.values.calls.get(call_index); const call = module.values.calls.get(call_index);
const call_value = module.values.array.get(call.value); const call_value = module.values.array.get(call.value);
var argument_declarations = ArrayList(Compilation.Declaration.Index){}; var argument_declarations = ArrayList(Compilation.Declaration.Index){};
switch (call_value.*) {
.function_definition => |function_definition_index| { const callable_name = switch (call_value.*) {
const name = try unit.renderFunctionName(module, allocator, function_definition_index); .function_definition => |function_definition_index| blk: {
// if (equal(u8, name, "os_execute")) { const name = try unit.renderFunctionDefinitionName(module, allocator, function_definition_index);
// @breakpoint();
// }
const function_definition = module.types.function_definitions.get(function_definition_index); const function_definition = module.types.function_definitions.get(function_definition_index);
const function_prototype_type = module.types.array.get(function_definition.prototype); const function_prototype_type = module.types.array.get(function_definition.prototype);
const function_prototype = module.types.function_prototypes.get(function_prototype_type.function); const function_prototype = module.types.function_prototypes.get(function_prototype_type.function);
@ -1254,8 +1285,22 @@ pub const TranslationUnit = struct {
try list.appendSlice(allocator, name); try list.appendSlice(allocator, name);
try list.append(allocator, '('); try list.append(allocator, '(');
break :blk name;
}, },
.field_access => |field_access_index| { .function_declaration => |function_declaration_index| blk: {
const name = try unit.renderFunctionDeclarationName(module, allocator, function_declaration_index);
const function_declaration = module.types.function_declarations.get(function_declaration_index);
const function_prototype_type = module.types.array.get(function_declaration.prototype);
const function_prototype = module.types.function_prototypes.get(function_prototype_type.function);
argument_declarations = function_prototype.arguments;
try list.appendSlice(allocator, name);
try list.append(allocator, '(');
break :blk name;
},
.field_access => |field_access_index| blk: {
const field_access = module.values.field_accesses.get(field_access_index); const field_access = module.values.field_accesses.get(field_access_index);
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{ try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
.value_index = field_access.declaration_reference, .value_index = field_access.declaration_reference,
@ -1291,9 +1336,11 @@ pub const TranslationUnit = struct {
const field_name = module.getName(field.name).?; const field_name = module.getName(field.name).?;
try list.appendSlice(allocator, field_name); try list.appendSlice(allocator, field_name);
try list.append(allocator, '('); try list.append(allocator, '(');
break :blk "field_access";
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} };
_ = callable_name;
if (!call.arguments.invalid) { if (!call.arguments.invalid) {
const argument_list = module.values.argument_lists.get(call.arguments); const argument_list = module.values.argument_lists.get(call.arguments);
@ -1961,6 +2008,11 @@ pub fn initialize(compilation: *Compilation, module: *Module) !void {
try zig_command_line.append(allocator, "-lc"); try zig_command_line.append(allocator, "-lc");
} }
for (module.map.libraries.keys()) |library_name| {
const library_argument = try std.mem.concat(allocator, u8, &.{ "-l", library_name });
try zig_command_line.append(allocator, library_argument);
}
const local_cache_dir = std.fs.cwd().realpathAlloc(allocator, "zig-cache") catch b: { const local_cache_dir = std.fs.cwd().realpathAlloc(allocator, "zig-cache") catch b: {
std.fs.cwd().makeDir("nat/zig-cache") catch {}; std.fs.cwd().makeDir("nat/zig-cache") catch {};
break :b try std.fs.cwd().realpathAlloc(allocator, "nat/zig-cache"); break :b try std.fs.cwd().realpathAlloc(allocator, "nat/zig-cache");
@ -1972,7 +2024,6 @@ pub fn initialize(compilation: *Compilation, module: *Module) !void {
try zig_command_line.append(allocator, "--global-cache-dir"); try zig_command_line.append(allocator, "--global-cache-dir");
try zig_command_line.append(allocator, global_cache_dir); try zig_command_line.append(allocator, global_cache_dir);
try zig_command_line.append(allocator, try std.mem.concat(allocator, u8, &.{ "-femit-bin=", module.descriptor.executable_path })); try zig_command_line.append(allocator, try std.mem.concat(allocator, u8, &.{ "-femit-bin=", module.descriptor.executable_path }));
try zig_command_line.append(allocator, "-cflags"); try zig_command_line.append(allocator, "-cflags");

View File

@ -667,6 +667,7 @@ const Analyzer = struct {
const left_type = switch (left_value_index.invalid) { const left_type = switch (left_value_index.invalid) {
false => switch (analyzer.module.values.array.get(left_value_index).*) { false => switch (analyzer.module.values.array.get(left_value_index).*) {
.function_definition => |function_index| analyzer.module.types.function_prototypes.get(analyzer.module.types.array.get(analyzer.module.types.function_definitions.get(function_index).prototype).function).return_type, .function_definition => |function_index| analyzer.module.types.function_prototypes.get(analyzer.module.types.array.get(analyzer.module.types.function_definitions.get(function_index).prototype).function).return_type,
.function_declaration => |function_index| analyzer.module.types.function_prototypes.get(analyzer.module.types.array.get(analyzer.module.types.function_declarations.get(function_index).prototype).function).return_type,
.field_access => |field_access_index| blk: { .field_access => |field_access_index| blk: {
const field_access_type_index = analyzer.module.types.container_fields.get(analyzer.module.values.field_accesses.get(field_access_index).field).type; const field_access_type_index = analyzer.module.types.container_fields.get(analyzer.module.values.field_accesses.get(field_access_index).field).type;
const field_access_type = analyzer.module.types.array.get(field_access_type_index); const field_access_type = analyzer.module.types.array.get(field_access_type_index);
@ -723,6 +724,15 @@ const Analyzer = struct {
}; };
break :b try analyzer.processCallToFunctionPrototype(scope_index, function_prototype_index, call_argument_node_list.items, method_object); break :b try analyzer.processCallToFunctionPrototype(scope_index, function_prototype_index, call_argument_node_list.items, method_object);
}, },
.function_declaration => |function_index| {
const function_declaration = analyzer.module.types.function_declarations.get(function_index);
const function_prototype_index = analyzer.module.types.array.get(function_declaration.prototype).function;
// TODO:
assert(!is_field_access);
const method_object = Value.Index.invalid;
break :b try analyzer.processCallToFunctionPrototype(scope_index, function_prototype_index, call_argument_node_list.items, method_object);
},
.field_access => |field_access_index| { .field_access => |field_access_index| {
const field_access = analyzer.module.values.field_accesses.get(field_access_index); const field_access = analyzer.module.values.field_accesses.get(field_access_index);
const container_field = analyzer.module.types.container_fields.get(field_access.field); const container_field = analyzer.module.types.container_fields.get(field_access.field);
@ -1693,7 +1703,10 @@ const Analyzer = struct {
const function_prototype = analyzer.module.types.array.get(function_definition.prototype); const function_prototype = analyzer.module.types.array.get(function_definition.prototype);
const return_type_index = analyzer.functionPrototypeReturnType(function_prototype.function); const return_type_index = analyzer.functionPrototypeReturnType(function_prototype.function);
logln(.sema, .fn_return_type, "Function {s} has return type #{}", .{ analyzer.module.getName(declaration.name).?, return_type_index.uniqueInteger() }); logln(.sema, .fn_return_type, "Function {s} has return type #{}", .{ analyzer.module.getName(declaration.name).?, return_type_index.uniqueInteger() });
try analyzer.module.map.functions.put(analyzer.allocator, function_index, declaration_index); try analyzer.module.map.function_definitions.put(analyzer.allocator, function_index, declaration_index);
},
.function_declaration => |function_index| {
try analyzer.module.map.function_declarations.put(analyzer.allocator, function_index, declaration_index);
}, },
.type => |type_index| { .type => |type_index| {
try analyzer.module.map.types.put(analyzer.allocator, type_index, declaration_index); try analyzer.module.map.types.put(analyzer.allocator, type_index, declaration_index);
@ -1880,17 +1893,10 @@ const Analyzer = struct {
}, },
.compiler_intrinsic => try analyzer.compilerIntrinsic(scope_index, expect_type, node_index), .compiler_intrinsic => try analyzer.compilerIntrinsic(scope_index, expect_type, node_index),
.function_definition => blk: { .function_definition => blk: {
const function_scope_index = try analyzer.module.values.scopes.append(analyzer.allocator, .{ const function_prototype_index = try analyzer.functionPrototype(scope_index, node.left);
.parent = scope_index,
.file = analyzer.module.values.scopes.get(scope_index).file,
.token = node.token,
});
logln(.sema, .type, "Creating function scope #{}. Parent #{}", .{ function_scope_index.uniqueInteger(), scope_index.uniqueInteger() });
const function_prototype_index = try analyzer.functionPrototype(function_scope_index, node.left);
const function_prototype = analyzer.module.types.function_prototypes.get(function_prototype_index); const function_prototype = analyzer.module.types.function_prototypes.get(function_prototype_index);
assert(!function_prototype.attributes.@"extern"); assert(!function_prototype.attributes.@"extern");
const function_scope_index = function_prototype.scope;
const expected_type = ExpectType{ const expected_type = ExpectType{
.type_index = analyzer.functionPrototypeReturnType(function_prototype_index), .type_index = analyzer.functionPrototypeReturnType(function_prototype_index),
@ -1904,7 +1910,6 @@ const Analyzer = struct {
const function_index = try analyzer.module.types.function_definitions.append(analyzer.allocator, .{ const function_index = try analyzer.module.types.function_definitions.append(analyzer.allocator, .{
.prototype = prototype_type_index, .prototype = prototype_type_index,
.body = function_body, .body = function_body,
.scope = function_scope_index,
}); });
const result = Value{ const result = Value{
@ -1924,7 +1929,6 @@ const Analyzer = struct {
const function_declaration_index = try analyzer.module.types.function_declarations.append(analyzer.allocator, .{ const function_declaration_index = try analyzer.module.types.function_declarations.append(analyzer.allocator, .{
.prototype = prototype_type_index, .prototype = prototype_type_index,
.body = Block.Index.invalid, .body = Block.Index.invalid,
.scope = Scope.Index.invalid,
}); });
break :b Value{ break :b Value{
.function_declaration = function_declaration_index, .function_declaration = function_declaration_index,
@ -1933,7 +1937,6 @@ const Analyzer = struct {
false => unreachable, false => unreachable,
}; };
}, },
.simple_while => unreachable,
.block => blk: { .block => blk: {
const block_index = try analyzer.block(scope_index, expect_type, node_index); const block_index = try analyzer.block(scope_index, expect_type, node_index);
break :blk Value{ break :blk Value{
@ -3077,12 +3080,18 @@ const Analyzer = struct {
return type_index; return type_index;
} }
fn processSimpleFunctionPrototype(analyzer: *Analyzer, scope_index: Scope.Index, simple_function_prototype_node_index: Node.Index) !Function.Prototype { fn processSimpleFunctionPrototype(analyzer: *Analyzer, old_scope_index: Scope.Index, simple_function_prototype_node_index: Node.Index) !Function.Prototype {
const simple_function_prototype_node = analyzer.getScopeNode(scope_index, simple_function_prototype_node_index); const simple_function_prototype_node = analyzer.getScopeNode(old_scope_index, simple_function_prototype_node_index);
assert(simple_function_prototype_node.id == .simple_function_prototype); assert(simple_function_prototype_node.id == .simple_function_prototype);
const arguments_node_index = simple_function_prototype_node.left; const arguments_node_index = simple_function_prototype_node.left;
const return_type_node_index = simple_function_prototype_node.right; const return_type_node_index = simple_function_prototype_node.right;
const scope_index = try analyzer.module.values.scopes.append(analyzer.allocator, .{
.parent = old_scope_index,
.file = analyzer.module.values.scopes.get(old_scope_index).file,
.token = simple_function_prototype_node.token,
});
var argument_declarations = ArrayList(Declaration.Index){}; var argument_declarations = ArrayList(Declaration.Index){};
switch (arguments_node_index.invalid) { switch (arguments_node_index.invalid) {
true => {}, true => {},
@ -3128,6 +3137,7 @@ const Analyzer = struct {
return .{ return .{
.arguments = argument_declarations, .arguments = argument_declarations,
.return_type = return_type, .return_type = return_type,
.scope = scope_index,
}; };
} }
@ -3149,8 +3159,14 @@ const Analyzer = struct {
const attribute_node = analyzer.getScopeNode(scope_index, attribute_node_index); const attribute_node = analyzer.getScopeNode(scope_index, attribute_node_index);
switch (attribute_node.id) { switch (attribute_node.id) {
.extern_qualifier => function_prototype.attributes.@"extern" = true,
.export_qualifier => function_prototype.attributes.@"export" = true, .export_qualifier => function_prototype.attributes.@"export" = true,
.extern_qualifier => {
const string_literal_node = analyzer.getScopeNode(scope_index, attribute_node.left);
const original_string_literal = analyzer.tokenStringLiteral(scope_index, string_literal_node.token);
const fixed_string_literal = try fixupStringLiteral(analyzer.allocator, original_string_literal);
_ = try analyzer.module.map.libraries.getOrPut(analyzer.allocator, fixed_string_literal);
function_prototype.attributes.@"extern" = true;
},
.calling_convention => { .calling_convention => {
const calling_convention_type_declaration = try analyzer.forceDeclarationAnalysis(scope_index, "std.builtin.CallingConvention"); const calling_convention_type_declaration = try analyzer.forceDeclarationAnalysis(scope_index, "std.builtin.CallingConvention");
const calling_convention_type = switch (analyzer.module.values.array.get(calling_convention_type_declaration).*) { const calling_convention_type = switch (analyzer.module.values.array.get(calling_convention_type_declaration).*) {

View File

@ -384,13 +384,22 @@ const Analyzer = struct {
.left_brace, .left_brace,
=> break, => break,
.fixed_keyword_extern => b: { .fixed_keyword_extern => b: {
const result = try analyzer.addNode(.{ analyzer.consumeToken();
.id = .extern_qualifier, _ = try analyzer.expectToken(.left_parenthesis);
.token = attribute_token, const string_literal = try analyzer.addNode(.{
.id = .string_literal,
.token = try analyzer.expectToken(.string_literal),
.left = Node.Index.invalid, .left = Node.Index.invalid,
.right = Node.Index.invalid, .right = Node.Index.invalid,
}); });
analyzer.consumeToken(); _ = try analyzer.expectToken(.right_parenthesis);
const result = try analyzer.addNode(.{
.id = .extern_qualifier,
.token = attribute_token,
.left = string_literal,
.right = Node.Index.invalid,
});
break :b result; break :b result;
}, },
.fixed_keyword_export => b: { .fixed_keyword_export => b: {
@ -1391,6 +1400,7 @@ const Analyzer = struct {
.right_parenthesis, .right_parenthesis,
.left_brace, .left_brace,
.equal, .equal,
.fixed_keyword_extern,
=> return node_index, => return node_index,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }