Merge pull request #35 from birth-software/c-libraries
implement extern functionality
This commit is contained in:
commit
76332f5ad7
@ -563,7 +563,6 @@ pub const Declaration = struct {
|
||||
};
|
||||
|
||||
pub const Function = struct {
|
||||
scope: Scope.Index,
|
||||
body: Block.Index,
|
||||
prototype: Type.Index,
|
||||
|
||||
@ -571,11 +570,12 @@ pub const Function = struct {
|
||||
arguments: ArrayList(Declaration.Index),
|
||||
return_type: Type.Index,
|
||||
attributes: Attributes = .{},
|
||||
scope: Scope.Index,
|
||||
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = Prototype.List.Index;
|
||||
|
||||
pub const Attributes = packed struct {
|
||||
pub const Attributes = struct {
|
||||
@"extern": bool = false,
|
||||
@"export": bool = false,
|
||||
@"inline": Inline = .none,
|
||||
@ -885,7 +885,6 @@ pub const Value = union(enum) {
|
||||
indexed_access: IndexedAccess.Index,
|
||||
optional_check: OptionalCheck.Index,
|
||||
optional_unwrap: OptionalUnwrap.Index,
|
||||
// optional_cast: Cast.Index,
|
||||
array_coerce_to_slice: Cast.Index,
|
||||
slice: Slice.Index,
|
||||
assembly_block: Assembly.Block.Index,
|
||||
@ -908,9 +907,16 @@ pub const Value = union(enum) {
|
||||
_ = module;
|
||||
|
||||
return switch (value.*) {
|
||||
.bool,
|
||||
.void,
|
||||
.function_definition,
|
||||
.function_declaration,
|
||||
.type,
|
||||
.enum_field,
|
||||
.string_literal,
|
||||
=> true,
|
||||
.integer => |integer| integer.type.eq(Type.comptime_int),
|
||||
.declaration_reference => false,
|
||||
.bool, .void, .function_definition, .type, .enum_field => true,
|
||||
// TODO:
|
||||
.call,
|
||||
// .syscall,
|
||||
@ -1048,7 +1054,8 @@ pub const Module = struct {
|
||||
function_prototypes: BlockList(Function.Prototype) = .{},
|
||||
} = .{},
|
||||
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) = .{},
|
||||
imports: StringArrayHashMap(File.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) = .{},
|
||||
optionals: data_structures.AutoArrayHashMap(Type.Index, Type.Index) = .{},
|
||||
arrays: data_structures.AutoArrayHashMap(Type.Array, Type.Index) = .{},
|
||||
libraries: data_structures.StringArrayHashMap(void) = .{},
|
||||
} = .{},
|
||||
main_package: *Package,
|
||||
entry_point: Function.Index = Function.Index.invalid,
|
||||
|
@ -64,7 +64,8 @@ pub const TranslationUnit = struct {
|
||||
global_variable_declarations: ArrayList(u8) = .{},
|
||||
function_definitions: ArrayList(u8) = .{},
|
||||
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(),
|
||||
struct_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();
|
||||
while (function_definitions.nextIndex()) |function_definition_index| {
|
||||
@ -112,18 +120,33 @@ pub const TranslationUnit = struct {
|
||||
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 {
|
||||
if (unit.function_set.getIndex(function_definition_index)) |index| {
|
||||
return unit.function_set.values()[index];
|
||||
if (unit.function_definition_set.getIndex(function_definition_index)) |index| {
|
||||
return unit.function_definition_set.values()[index];
|
||||
} else {
|
||||
const function_definition = module.types.function_definitions.get(function_definition_index);
|
||||
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_name = try unit.writeFunctionHeader(module, &unit.function_declarations, allocator, function_definition_index);
|
||||
try unit.function_set.putNoClobber(allocator, function_definition_index, function_name);
|
||||
const function_name = try unit.renderFunctionDefinitionName(module, allocator, function_definition_index);
|
||||
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_definitions.append(allocator, ' ');
|
||||
@ -387,17 +410,28 @@ pub const TranslationUnit = struct {
|
||||
return result;
|
||||
}
|
||||
|
||||
fn renderFunctionName(unit: *TranslationUnit, module: *Module, allocator: Allocator, function_index: Compilation.Function.Index) ![]const u8 {
|
||||
const function_definition = module.types.function_definitions.get(function_index);
|
||||
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_definition_index);
|
||||
const function_prototype_type = module.types.array.get(function_definition.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 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);
|
||||
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 {
|
||||
if (unit.declaration_set.getIndex(declaration_index)) |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)");
|
||||
} else {
|
||||
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) {
|
||||
.system_v => {},
|
||||
.naked => try list.appendSlice(allocator, "[[gnu::naked]] "),
|
||||
@ -494,14 +533,12 @@ pub const TranslationUnit = struct {
|
||||
|
||||
try list.append(allocator, '(');
|
||||
|
||||
|
||||
if (function_prototype.arguments.items.len > 0) {
|
||||
for (function_prototype.arguments.items, 0..) |argument_index, index| {
|
||||
_ = index;
|
||||
|
||||
const arg_declaration = module.values.declarations.get(argument_index);
|
||||
if (is_main) {
|
||||
} else {
|
||||
if (is_main) {} else {
|
||||
try unit.writeType(module, list, allocator, arg_declaration.getType(), ' ');
|
||||
}
|
||||
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 {
|
||||
const name = try unit.renderFunctionName(module, allocator, function_index);
|
||||
const function_definition = module.types.function_definitions.get(function_index);
|
||||
const function_prototype_type = module.types.array.get(function_definition.prototype);
|
||||
fn writeFunctionHeader(unit: *TranslationUnit, module: *Module, list: *ArrayList(u8), allocator: Allocator, function: *const Compilation.Function, name: []const u8) !void {
|
||||
const function_prototype_type = module.types.array.get(function.prototype);
|
||||
const function_prototype_index = function_prototype_type.function;
|
||||
|
||||
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 {
|
||||
@ -1241,12 +1274,10 @@ pub const TranslationUnit = struct {
|
||||
const call = module.values.calls.get(call_index);
|
||||
const call_value = module.values.array.get(call.value);
|
||||
var argument_declarations = ArrayList(Compilation.Declaration.Index){};
|
||||
switch (call_value.*) {
|
||||
.function_definition => |function_definition_index| {
|
||||
const name = try unit.renderFunctionName(module, allocator, function_definition_index);
|
||||
// if (equal(u8, name, "os_execute")) {
|
||||
// @breakpoint();
|
||||
// }
|
||||
|
||||
const callable_name = switch (call_value.*) {
|
||||
.function_definition => |function_definition_index| blk: {
|
||||
const name = try unit.renderFunctionDefinitionName(module, allocator, 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 = module.types.function_prototypes.get(function_prototype_type.function);
|
||||
@ -1254,8 +1285,22 @@ pub const TranslationUnit = struct {
|
||||
|
||||
try list.appendSlice(allocator, name);
|
||||
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);
|
||||
try unit.writeValue(module, list, allocator, function_return_type, indentation, .{
|
||||
.value_index = field_access.declaration_reference,
|
||||
@ -1291,9 +1336,11 @@ pub const TranslationUnit = struct {
|
||||
const field_name = module.getName(field.name).?;
|
||||
try list.appendSlice(allocator, field_name);
|
||||
try list.append(allocator, '(');
|
||||
break :blk "field_access";
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
};
|
||||
_ = callable_name;
|
||||
|
||||
if (!call.arguments.invalid) {
|
||||
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");
|
||||
}
|
||||
|
||||
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: {
|
||||
std.fs.cwd().makeDir("nat/zig-cache") catch {};
|
||||
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, try std.mem.concat(allocator, u8, &.{ "-femit-bin=", module.descriptor.executable_path }));
|
||||
try zig_command_line.append(allocator, "-cflags");
|
||||
|
||||
|
@ -667,6 +667,7 @@ const Analyzer = struct {
|
||||
const left_type = switch (left_value_index.invalid) {
|
||||
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_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: {
|
||||
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);
|
||||
@ -723,6 +724,15 @@ const Analyzer = struct {
|
||||
};
|
||||
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| {
|
||||
const field_access = analyzer.module.values.field_accesses.get(field_access_index);
|
||||
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 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() });
|
||||
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| {
|
||||
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),
|
||||
.function_definition => blk: {
|
||||
const function_scope_index = try analyzer.module.values.scopes.append(analyzer.allocator, .{
|
||||
.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_index = try analyzer.functionPrototype(scope_index, node.left);
|
||||
const function_prototype = analyzer.module.types.function_prototypes.get(function_prototype_index);
|
||||
assert(!function_prototype.attributes.@"extern");
|
||||
const function_scope_index = function_prototype.scope;
|
||||
|
||||
const expected_type = ExpectType{
|
||||
.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, .{
|
||||
.prototype = prototype_type_index,
|
||||
.body = function_body,
|
||||
.scope = function_scope_index,
|
||||
});
|
||||
|
||||
const result = Value{
|
||||
@ -1924,7 +1929,6 @@ const Analyzer = struct {
|
||||
const function_declaration_index = try analyzer.module.types.function_declarations.append(analyzer.allocator, .{
|
||||
.prototype = prototype_type_index,
|
||||
.body = Block.Index.invalid,
|
||||
.scope = Scope.Index.invalid,
|
||||
});
|
||||
break :b Value{
|
||||
.function_declaration = function_declaration_index,
|
||||
@ -1933,7 +1937,6 @@ const Analyzer = struct {
|
||||
false => unreachable,
|
||||
};
|
||||
},
|
||||
.simple_while => unreachable,
|
||||
.block => blk: {
|
||||
const block_index = try analyzer.block(scope_index, expect_type, node_index);
|
||||
break :blk Value{
|
||||
@ -3077,12 +3080,18 @@ const Analyzer = struct {
|
||||
return type_index;
|
||||
}
|
||||
|
||||
fn processSimpleFunctionPrototype(analyzer: *Analyzer, 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);
|
||||
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(old_scope_index, simple_function_prototype_node_index);
|
||||
assert(simple_function_prototype_node.id == .simple_function_prototype);
|
||||
const arguments_node_index = simple_function_prototype_node.left;
|
||||
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){};
|
||||
switch (arguments_node_index.invalid) {
|
||||
true => {},
|
||||
@ -3128,6 +3137,7 @@ const Analyzer = struct {
|
||||
return .{
|
||||
.arguments = argument_declarations,
|
||||
.return_type = return_type,
|
||||
.scope = scope_index,
|
||||
};
|
||||
}
|
||||
|
||||
@ -3149,8 +3159,14 @@ const Analyzer = struct {
|
||||
const attribute_node = analyzer.getScopeNode(scope_index, attribute_node_index);
|
||||
|
||||
switch (attribute_node.id) {
|
||||
.extern_qualifier => function_prototype.attributes.@"extern" = 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 => {
|
||||
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).*) {
|
||||
|
@ -384,13 +384,22 @@ const Analyzer = struct {
|
||||
.left_brace,
|
||||
=> break,
|
||||
.fixed_keyword_extern => b: {
|
||||
const result = try analyzer.addNode(.{
|
||||
.id = .extern_qualifier,
|
||||
.token = attribute_token,
|
||||
analyzer.consumeToken();
|
||||
_ = try analyzer.expectToken(.left_parenthesis);
|
||||
const string_literal = try analyzer.addNode(.{
|
||||
.id = .string_literal,
|
||||
.token = try analyzer.expectToken(.string_literal),
|
||||
.left = 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;
|
||||
},
|
||||
.fixed_keyword_export => b: {
|
||||
@ -1391,6 +1400,7 @@ const Analyzer = struct {
|
||||
.right_parenthesis,
|
||||
.left_brace,
|
||||
.equal,
|
||||
.fixed_keyword_extern,
|
||||
=> return node_index,
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user