authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-29 19:44:51-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-29 19:44:51-07:00
log86d564eed8b9eacd0447598dd364ab04c5b1b04d
treed4fff51821459dd9ae181a31c667cac1bd2b3bbc
parentba9b9cb38dbd66c7a600606c5599c80b115e0f85

AstGen: implement extern variables


4 files changed, 139 insertions(+), 16 deletions(-)

src/AstGen.zig+13-7
...@@ -2961,7 +2961,7 @@ fn globalVarDecl(...@@ -2961,7 +2961,7 @@ fn globalVarDecl(
29612961
2962 assert(var_decl.comptime_token == null); // handled by parser2962 assert(var_decl.comptime_token == null); // handled by parser
29632963
2964 const var_inst: Zir.Inst.Index = if (var_decl.ast.init_node != 0) vi: {2964 if (var_decl.ast.init_node != 0) {
2965 if (is_extern) {2965 if (is_extern) {
2966 return astgen.failNode(2966 return astgen.failNode(
2967 var_decl.ast.init_node,2967 var_decl.ast.init_node,
...@@ -2989,19 +2989,25 @@ fn globalVarDecl(...@@ -2989,19 +2989,25 @@ fn globalVarDecl(
2989 // We do this at the end so that the instruction index marks the end2989 // We do this at the end so that the instruction index marks the end
2990 // range of a top level declaration.2990 // range of a top level declaration.
2991 _ = try block_scope.addBreak(.break_inline, block_inst, init_inst);2991 _ = try block_scope.addBreak(.break_inline, block_inst, init_inst);
2992 try block_scope.setBlockBody(block_inst);
2993 break :vi block_inst;
2994 } else if (!is_extern) {2992 } else if (!is_extern) {
2995 return astgen.failNode(node, "variables must be initialized", .{});2993 return astgen.failNode(node, "variables must be initialized", .{});
2996 } else if (var_decl.ast.type_node != 0) {2994 } else if (var_decl.ast.type_node != 0) {
2997 // Extern variable which has an explicit type.2995 // Extern variable which has an explicit type.
2998
2999 const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node);2996 const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node);
30002997
3001 return astgen.failNode(node, "TODO AstGen extern global variable", .{});2998 const var_inst = try block_scope.addVar(.{
2999 .var_type = type_inst,
3000 .lib_name = lib_name,
3001 .align_inst = .none, // passed in the decls data
3002 .init = .none,
3003 .is_extern = true,
3004 });
3005
3006 _ = try block_scope.addBreak(.break_inline, block_inst, var_inst);
3002 } else {3007 } else {
3003 return astgen.failNode(node, "unable to infer variable type", .{});3008 return astgen.failNode(node, "unable to infer variable type", .{});
3004 };3009 }
3010 try block_scope.setBlockBody(block_inst);
30053011
3006 const name_token = var_decl.ast.mut_token + 1;3012 const name_token = var_decl.ast.mut_token + 1;
3007 const name_str_index = try gz.identAsString(name_token);3013 const name_str_index = try gz.identAsString(name_token);
...@@ -3013,7 +3019,7 @@ fn globalVarDecl(...@@ -3013,7 +3019,7 @@ fn globalVarDecl(
3013 wip_decls.payload.appendSliceAssumeCapacity(&casted);3019 wip_decls.payload.appendSliceAssumeCapacity(&casted);
3014 }3020 }
3015 wip_decls.payload.appendAssumeCapacity(name_str_index);3021 wip_decls.payload.appendAssumeCapacity(name_str_index);
3016 wip_decls.payload.appendAssumeCapacity(var_inst);3022 wip_decls.payload.appendAssumeCapacity(block_inst);
3017 if (align_inst != .none) {3023 if (align_inst != .none) {
3018 wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst));3024 wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst));
3019 }3025 }
src/Module.zig+51
...@@ -1462,6 +1462,57 @@ pub const Scope = struct {...@@ -1462,6 +1462,57 @@ pub const Scope = struct {
1462 }1462 }
1463 }1463 }
14641464
1465 pub fn addVar(gz: *GenZir, args: struct {
1466 align_inst: Zir.Inst.Ref,
1467 lib_name: u32,
1468 var_type: Zir.Inst.Ref,
1469 init: Zir.Inst.Ref,
1470 is_extern: bool,
1471 }) !Zir.Inst.Ref {
1472 const astgen = gz.astgen;
1473 const gpa = astgen.gpa;
1474
1475 try gz.instructions.ensureUnusedCapacity(gpa, 1);
1476 try astgen.instructions.ensureUnusedCapacity(gpa, 1);
1477
1478 try astgen.extra.ensureUnusedCapacity(
1479 gpa,
1480 @typeInfo(Zir.Inst.ExtendedVar).Struct.fields.len +
1481 @boolToInt(args.lib_name != 0) +
1482 @boolToInt(args.align_inst != .none) +
1483 @boolToInt(args.init != .none),
1484 );
1485 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{
1486 .var_type = args.var_type,
1487 });
1488 if (args.lib_name != 0) {
1489 astgen.extra.appendAssumeCapacity(args.lib_name);
1490 }
1491 if (args.align_inst != .none) {
1492 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
1493 }
1494 if (args.init != .none) {
1495 astgen.extra.appendAssumeCapacity(@enumToInt(args.init));
1496 }
1497
1498 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
1499 astgen.instructions.appendAssumeCapacity(.{
1500 .tag = .extended,
1501 .data = .{ .extended = .{
1502 .opcode = .variable,
1503 .small = @bitCast(u16, Zir.Inst.ExtendedVar.Small{
1504 .has_lib_name = args.lib_name != 0,
1505 .has_align = args.align_inst != .none,
1506 .has_init = args.init != .none,
1507 .is_extern = args.is_extern,
1508 }),
1509 .operand = payload_index,
1510 } },
1511 });
1512 gz.instructions.appendAssumeCapacity(new_index);
1513 return gz.indexToRef(new_index);
1514 }
1515
1465 pub fn addCall(1516 pub fn addCall(
1466 gz: *GenZir,1517 gz: *GenZir,
1467 tag: Zir.Inst.Tag,1518 tag: Zir.Inst.Tag,
src/Sema.zig+12
...@@ -479,6 +479,7 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro...@@ -479,6 +479,7 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
479 switch (extended.opcode) {479 switch (extended.opcode) {
480 // zig fmt: off480 // zig fmt: off
481 .func => return sema.zirFuncExtended( block, extended),481 .func => return sema.zirFuncExtended( block, extended),
482 .variable => return sema.zirVarExtended( block, extended),
482 .ret_ptr => return sema.zirRetPtr( block, extended),483 .ret_ptr => return sema.zirRetPtr( block, extended),
483 .ret_type => return sema.zirRetType( block, extended),484 .ret_type => return sema.zirRetType( block, extended),
484 .this => return sema.zirThis( block, extended),485 .this => return sema.zirThis( block, extended),
...@@ -5427,6 +5428,17 @@ fn zirAwait(...@@ -5427,6 +5428,17 @@ fn zirAwait(
5427 return sema.mod.fail(&block.base, src, "TODO: Sema.zirAwait", .{});5428 return sema.mod.fail(&block.base, src, "TODO: Sema.zirAwait", .{});
5428}5429}
54295430
5431fn zirVarExtended(
5432 sema: *Sema,
5433 block: *Scope.Block,
5434 extended: Zir.Inst.Extended.InstData,
5435) InnerError!*Inst {
5436 const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand);
5437 const src = sema.src;
5438
5439 return sema.mod.fail(&block.base, src, "TODO implement Sema.zirVarExtended", .{});
5440}
5441
5430fn zirFuncExtended(5442fn zirFuncExtended(
5431 sema: *Sema,5443 sema: *Sema,
5432 block: *Scope.Block,5444 block: *Scope.Block,
src/Zir.zig+63-9
...@@ -1496,6 +1496,10 @@ pub const Inst = struct {...@@ -1496,6 +1496,10 @@ pub const Inst = struct {
1496 /// `operand` is payload index to `ExtendedFunc`.1496 /// `operand` is payload index to `ExtendedFunc`.
1497 /// `small` is `ExtendedFunc.Small`.1497 /// `small` is `ExtendedFunc.Small`.
1498 func,1498 func,
1499 /// Declares a global variable.
1500 /// `operand` is payload index to `ExtendedVar`.
1501 /// `small` is `ExtendedVar.Small`.
1502 variable,
1499 /// Obtains a pointer to the return value.1503 /// Obtains a pointer to the return value.
1500 /// `operand` is `src_node: i32`.1504 /// `operand` is `src_node: i32`.
1501 ret_ptr,1505 ret_ptr,
...@@ -2209,6 +2213,23 @@ pub const Inst = struct {...@@ -2209,6 +2213,23 @@ pub const Inst = struct {
2209 };2213 };
2210 };2214 };
22112215
2216 /// Trailing:
2217 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
2218 /// 1. align: Ref, // if has_align is set
2219 /// 2. init: Ref // if has_init is set
2220 /// The source node is obtained from the containing `block_inline`.
2221 pub const ExtendedVar = struct {
2222 var_type: Ref,
2223
2224 pub const Small = packed struct {
2225 has_lib_name: bool,
2226 has_align: bool,
2227 has_init: bool,
2228 is_extern: bool,
2229 _: u12 = undefined,
2230 };
2231 };
2232
2212 /// Trailing:2233 /// Trailing:
2213 /// 0. param_type: Ref // for each param_types_len2234 /// 0. param_type: Ref // for each param_types_len
2214 /// - `none` indicates that the param type is `anytype`.2235 /// - `none` indicates that the param type is `anytype`.
...@@ -3010,6 +3031,7 @@ const Writer = struct {...@@ -3010,6 +3031,7 @@ const Writer = struct {
30103031
3011 .@"asm" => try self.writeAsm(stream, extended),3032 .@"asm" => try self.writeAsm(stream, extended),
3012 .func => try self.writeFuncExtended(stream, extended),3033 .func => try self.writeFuncExtended(stream, extended),
3034 .variable => try self.writeVarExtended(stream, extended),
30133035
3014 .compile_log,3036 .compile_log,
3015 .typeof_peer,3037 .typeof_peer,
...@@ -4015,6 +4037,34 @@ const Writer = struct {...@@ -4015,6 +4037,34 @@ const Writer = struct {
4015 );4037 );
4016 }4038 }
40174039
4040 fn writeVarExtended(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void {
4041 const extra = self.code.extraData(Inst.ExtendedVar, extended.operand);
4042 const small = @bitCast(Inst.ExtendedVar.Small, extended.small);
4043
4044 try self.writeInstRef(stream, extra.data.var_type);
4045
4046 var extra_index: usize = extra.end;
4047 if (small.has_lib_name) {
4048 const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
4049 extra_index += 1;
4050 try stream.print(", lib_name=\"{}\"", .{std.zig.fmtEscapes(lib_name)});
4051 }
4052 const align_inst: Inst.Ref = if (!small.has_align) .none else blk: {
4053 const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
4054 extra_index += 1;
4055 break :blk align_inst;
4056 };
4057 const init_inst: Inst.Ref = if (!small.has_init) .none else blk: {
4058 const init_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
4059 extra_index += 1;
4060 break :blk init_inst;
4061 };
4062 try self.writeFlag(stream, ", is_extern", small.is_extern);
4063 try self.writeOptionalInstRef(stream, ", align=", align_inst);
4064 try self.writeOptionalInstRef(stream, ", init=", init_inst);
4065 try stream.writeAll("))");
4066 }
4067
4018 fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {4068 fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
4019 const inst_data = self.code.instructions.items(.data)[inst].bool_br;4069 const inst_data = self.code.instructions.items(.data)[inst].bool_br;
4020 const extra = self.code.extraData(Inst.Block, inst_data.payload_index);4070 const extra = self.code.extraData(Inst.Block, inst_data.payload_index);
...@@ -4078,15 +4128,19 @@ const Writer = struct {...@@ -4078,15 +4128,19 @@ const Writer = struct {
4078 try self.writeFlag(stream, ", vargs", var_args);4128 try self.writeFlag(stream, ", vargs", var_args);
4079 try self.writeFlag(stream, ", inferror", inferred_error_set);4129 try self.writeFlag(stream, ", inferror", inferred_error_set);
40804130
4081 try stream.writeAll(", {\n");4131 if (body.len == 0) {
4082 self.indent += 2;4132 try stream.writeAll(", {}) ");
4083 const prev_param_count = self.param_count;4133 } else {
4084 self.param_count = param_types.len;4134 try stream.writeAll(", {\n");
4085 try self.writeBody(stream, body);4135 self.indent += 2;
4086 self.param_count = prev_param_count;4136 const prev_param_count = self.param_count;
4087 self.indent -= 2;4137 self.param_count = param_types.len;
4088 try stream.writeByteNTimes(' ', self.indent);4138 try self.writeBody(stream, body);
4089 try stream.writeAll("}) ");4139 self.param_count = prev_param_count;
4140 self.indent -= 2;
4141 try stream.writeByteNTimes(' ', self.indent);
4142 try stream.writeAll("}) ");
4143 }
4090 try self.writeSrc(stream, src);4144 try self.writeSrc(stream, src);
4091 }4145 }
40924146