From 515d6430c0298daf304e48b46e6b43802bbfdab4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 15 Jun 2021 14:08:57 -0700 Subject: AstGen: support `@export` with field access The Zig language specification will support identifiers and field access in order to refer to which declaration to export with `@export`. This commit implements the change in AstGen and updates the language reference. --- src/AstGen.zig | 29 ++++++++++++++++++++++------- src/Sema.zig | 3 +++ src/Zir.zig | 11 ++++++++--- 3 files changed, 33 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/AstGen.zig b/src/AstGen.zig index d7720e7678..54500675df 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -6706,18 +6706,33 @@ fn builtinCall( .@"export" => { const node_tags = tree.nodes.items(.tag); + const node_datas = tree.nodes.items(.data); // This function causes a Decl to be exported. The first parameter is not an expression, // but an identifier of the Decl to be exported. - if (node_tags[params[0]] != .identifier) { - return astgen.failNode(params[0], "the first @export parameter must be an identifier", .{}); + var namespace: Zir.Inst.Ref = .none; + var decl_name: u32 = 0; + switch (node_tags[params[0]]) { + .identifier => { + const ident_token = main_tokens[params[0]]; + decl_name = try astgen.identAsString(ident_token); + // TODO look for local variables in scope matching `decl_name` and emit a compile + // error. Only top-level declarations can be exported. Until this is done, the + // compile error will end up being "use of undeclared identifier" in Sema. + }, + .field_access => { + const namespace_node = node_datas[params[0]].lhs; + namespace = try typeExpr(gz, scope, namespace_node); + const dot_token = main_tokens[params[0]]; + const field_ident = dot_token + 1; + decl_name = try astgen.identAsString(field_ident); + }, + else => return astgen.failNode( + params[0], "the first @export parameter must be an identifier", .{}, + ), } - const ident_token = main_tokens[params[0]]; - const decl_name = try astgen.identAsString(ident_token); - // TODO look for local variables in scope matching `decl_name` and emit a compile - // error. Only top-level declarations can be exported. Until this is done, the - // compile error will end up being "use of undeclared identifier" in Sema. const options = try comptimeExpr(gz, scope, .{ .ty = .export_options_type }, params[1]); _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{ + .namespace = namespace, .decl_name = decl_name, .options = options, }); diff --git a/src/Sema.zig b/src/Sema.zig index c9a150202e..07c8c3fc26 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1985,6 +1985,9 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError! const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; const decl_name = sema.code.nullTerminatedString(extra.decl_name); + if (extra.namespace != .none) { + return sema.mod.fail(&block.base, src, "TODO: implement exporting with field access", .{}); + } const decl = try sema.lookupIdentifier(block, lhs_src, decl_name); const options = try sema.resolveInstConst(block, rhs_src, extra.options); const struct_obj = options.ty.castTag(.@"struct").?.data; diff --git a/src/Zir.zig b/src/Zir.zig index 8f40d95940..0c8855bbc9 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -347,8 +347,9 @@ pub const Inst = struct { error_union_type, /// `error.Foo` syntax. Uses the `str_tok` field of the Data union. error_value, - /// Implements the `@export` builtin function. - /// Uses the `pl_node` union field. Payload is `Bin`. + /// Implements the `@export` builtin function, based on either an identifier to a Decl, + /// or field access of a Decl. + /// Uses the `pl_node` union field. Payload is `Export`. @"export", /// Given a pointer to a struct or object that contains virtual fields, returns a pointer /// to the named field. The field name is stored in string_bytes. Used by a.b syntax. @@ -2738,6 +2739,9 @@ pub const Inst = struct { }; pub const Export = struct { + /// If present, this is referring to a Decl via field access, e.g. `a.b`. + /// If omitted, this is referring to a Decl via identifier, e.g. `a`. + namespace: Ref, /// Null-terminated string index. decl_name: u32, options: Ref, @@ -3284,7 +3288,8 @@ const Writer = struct { const extra = self.code.extraData(Inst.Export, inst_data.payload_index).data; const decl_name = self.code.nullTerminatedString(extra.decl_name); - try stream.print("{}, ", .{std.zig.fmtId(decl_name)}); + try self.writeInstRef(stream, extra.namespace); + try stream.print(", {}, ", .{std.zig.fmtId(decl_name)}); try self.writeInstRef(stream, extra.options); try stream.writeAll(") "); try self.writeSrc(stream, inst_data.src()); -- cgit v1.2.3