101
lib/std/zig.zig
101
lib/std/zig.zig
@@ -80,6 +80,107 @@ pub fn binNameAlloc(
|
||||
}
|
||||
}
|
||||
|
||||
/// Only validates escape sequence characters.
|
||||
/// Slice must be valid utf8 starting and ending with "'" and exactly one codepoint in between.
|
||||
pub fn parseCharLiteral(
|
||||
slice: []const u8,
|
||||
bad_index: *usize, // populated if error.InvalidCharacter is returned)
|
||||
) error{InvalidCharacter}!u32 {
|
||||
std.debug.assert(slice.len >= 3 and slice[0] == '\'' and slice[slice.len - 1] == '\'');
|
||||
|
||||
if (slice[1] == '\\') {
|
||||
switch (slice[2]) {
|
||||
'n' => return '\n',
|
||||
'r' => return '\r',
|
||||
'\\' => return '\\',
|
||||
't' => return '\t',
|
||||
'\'' => return '\'',
|
||||
'"' => return '"',
|
||||
'x' => {
|
||||
if (slice.len != 6) {
|
||||
bad_index.* = slice.len - 2;
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
|
||||
var value: u32 = 0;
|
||||
for (slice[3..5]) |c, i| {
|
||||
switch (slice[3]) {
|
||||
'0'...'9' => {
|
||||
value *= 16;
|
||||
value += c - '0';
|
||||
},
|
||||
'a'...'f' => {
|
||||
value *= 16;
|
||||
value += c - 'a';
|
||||
},
|
||||
'A'...'F' => {
|
||||
value *= 16;
|
||||
value += c - 'a';
|
||||
},
|
||||
else => {
|
||||
bad_index.* = i;
|
||||
return error.InvalidCharacter;
|
||||
},
|
||||
}
|
||||
}
|
||||
return value;
|
||||
},
|
||||
'u' => {
|
||||
if (slice.len < 6 or slice[3] != '{') {
|
||||
bad_index.* = 2;
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
var value: u32 = 0;
|
||||
for (slice[4..]) |c, i| {
|
||||
if (value > 0x10ffff) {
|
||||
bad_index.* = i;
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
switch (c) {
|
||||
'0'...'9' => {
|
||||
value *= 16;
|
||||
value += c - '0';
|
||||
},
|
||||
'a'...'f' => {
|
||||
value *= 16;
|
||||
value += c - 'a';
|
||||
},
|
||||
'A'...'F' => {
|
||||
value *= 16;
|
||||
value += c - 'A';
|
||||
},
|
||||
'}' => break,
|
||||
else => {
|
||||
bad_index.* = i;
|
||||
return error.InvalidCharacter;
|
||||
},
|
||||
}
|
||||
}
|
||||
return value;
|
||||
},
|
||||
else => {
|
||||
bad_index.* = 2;
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std.unicode.utf8Decode(slice[1 .. slice.len - 1]) catch unreachable;
|
||||
}
|
||||
|
||||
test "parseCharLiteral" {
|
||||
var bad_index: usize = undefined;
|
||||
std.testing.expectEqual(try parseCharLiteral("'a'", &bad_index), 'a');
|
||||
std.testing.expectEqual(try parseCharLiteral("'ä'", &bad_index), 'ä');
|
||||
std.testing.expectEqual(try parseCharLiteral("'\\x00'", &bad_index), 0);
|
||||
std.testing.expectEqual(try parseCharLiteral("'ぁ'", &bad_index), 0x3041);
|
||||
std.testing.expectEqual(try parseCharLiteral("'\\u{3041}'", &bad_index), 0x3041);
|
||||
|
||||
std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\x0'", &bad_index));
|
||||
std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\y'", &bad_index));
|
||||
std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u'", &bad_index));
|
||||
std.testing.expectError(error.InvalidCharacter, parseCharLiteral("'\\u{FFFFFF}'", &bad_index));
|
||||
}
|
||||
|
||||
test "" {
|
||||
@import("std").meta.refAllDecls(@This());
|
||||
}
|
||||
|
||||
@@ -2902,7 +2902,7 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
|
||||
return Value.initPayload(val_payload);
|
||||
}
|
||||
|
||||
pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) error{OutOfMemory}!Type {
|
||||
pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) Allocator.Error!Type {
|
||||
const type_payload = try scope.arena().create(Type.Payload.Pointer);
|
||||
type_payload.* = .{
|
||||
.base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer },
|
||||
@@ -2911,6 +2911,71 @@ pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, el
|
||||
return Type.initPayload(&type_payload.base);
|
||||
}
|
||||
|
||||
pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type {
|
||||
return Type.initPayload(switch (child_type.tag()) {
|
||||
.single_const_pointer => blk: {
|
||||
const payload = try scope.arena().create(Type.Payload.Pointer);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .optional_single_const_pointer },
|
||||
.pointee_type = child_type.elemType(),
|
||||
};
|
||||
break :blk &payload.base;
|
||||
},
|
||||
.single_mut_pointer => blk: {
|
||||
const payload = try scope.arena().create(Type.Payload.Pointer);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .optional_single_mut_pointer },
|
||||
.pointee_type = child_type.elemType(),
|
||||
};
|
||||
break :blk &payload.base;
|
||||
},
|
||||
else => blk: {
|
||||
const payload = try scope.arena().create(Type.Payload.Optional);
|
||||
payload.* = .{
|
||||
.child_type = child_type,
|
||||
};
|
||||
break :blk &payload.base;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
pub fn arrayType(self: *Module, scope: *Scope, len: u64, sentinel: ?Value, elem_type: Type) Allocator.Error!Type {
|
||||
if (elem_type.eql(Type.initTag(.u8))) {
|
||||
if (sentinel) |some| {
|
||||
if (some.eql(Value.initTag(.zero))) {
|
||||
const payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
|
||||
payload.* = .{
|
||||
.len = len,
|
||||
};
|
||||
return Type.initPayload(&payload.base);
|
||||
}
|
||||
} else {
|
||||
const payload = try scope.arena().create(Type.Payload.Array_u8);
|
||||
payload.* = .{
|
||||
.len = len,
|
||||
};
|
||||
return Type.initPayload(&payload.base);
|
||||
}
|
||||
}
|
||||
|
||||
if (sentinel) |some| {
|
||||
const payload = try scope.arena().create(Type.Payload.ArraySentinel);
|
||||
payload.* = .{
|
||||
.len = len,
|
||||
.sentinel = some,
|
||||
.elem_type = elem_type,
|
||||
};
|
||||
return Type.initPayload(&payload.base);
|
||||
}
|
||||
|
||||
const payload = try scope.arena().create(Type.Payload.Array);
|
||||
payload.* = .{
|
||||
.len = len,
|
||||
.elem_type = elem_type,
|
||||
};
|
||||
return Type.initPayload(&payload.base);
|
||||
}
|
||||
|
||||
pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {
|
||||
const zir_module = scope.namespace();
|
||||
const source = zir_module.getSource(self) catch @panic("dumpInst failed to get source");
|
||||
|
||||
@@ -20,6 +20,8 @@ pub const ResultLoc = union(enum) {
|
||||
/// The expression must generate a pointer rather than a value. For example, the left hand side
|
||||
/// of an assignment uses an "LValue" result location.
|
||||
lvalue,
|
||||
/// The expression must generate a pointer
|
||||
ref,
|
||||
/// The expression will be type coerced into this type, but it will be evaluated as an rvalue.
|
||||
ty: *zir.Inst,
|
||||
/// The expression must store its result into this typed pointer.
|
||||
@@ -46,6 +48,132 @@ pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*z
|
||||
|
||||
/// Turn Zig AST into untyped ZIR istructions.
|
||||
pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst {
|
||||
if (rl == .lvalue) {
|
||||
switch (node.tag) {
|
||||
.Root => unreachable,
|
||||
.Use => unreachable,
|
||||
.TestDecl => unreachable,
|
||||
.DocComment => unreachable,
|
||||
.VarDecl => unreachable,
|
||||
.SwitchCase => unreachable,
|
||||
.SwitchElse => unreachable,
|
||||
.Else => unreachable,
|
||||
.Payload => unreachable,
|
||||
.PointerPayload => unreachable,
|
||||
.PointerIndexPayload => unreachable,
|
||||
.ErrorTag => unreachable,
|
||||
.FieldInitializer => unreachable,
|
||||
.ContainerField => unreachable,
|
||||
|
||||
.Assign,
|
||||
.AssignBitAnd,
|
||||
.AssignBitOr,
|
||||
.AssignBitShiftLeft,
|
||||
.AssignBitShiftRight,
|
||||
.AssignBitXor,
|
||||
.AssignDiv,
|
||||
.AssignSub,
|
||||
.AssignSubWrap,
|
||||
.AssignMod,
|
||||
.AssignAdd,
|
||||
.AssignAddWrap,
|
||||
.AssignMul,
|
||||
.AssignMulWrap,
|
||||
.Add,
|
||||
.AddWrap,
|
||||
.Sub,
|
||||
.SubWrap,
|
||||
.Mul,
|
||||
.MulWrap,
|
||||
.Div,
|
||||
.Mod,
|
||||
.BitAnd,
|
||||
.BitOr,
|
||||
.BitShiftLeft,
|
||||
.BitShiftRight,
|
||||
.BitXor,
|
||||
.BangEqual,
|
||||
.EqualEqual,
|
||||
.GreaterThan,
|
||||
.GreaterOrEqual,
|
||||
.LessThan,
|
||||
.LessOrEqual,
|
||||
.ArrayCat,
|
||||
.ArrayMult,
|
||||
.BoolAnd,
|
||||
.BoolOr,
|
||||
.Asm,
|
||||
.StringLiteral,
|
||||
.IntegerLiteral,
|
||||
.Call,
|
||||
.Unreachable,
|
||||
.Return,
|
||||
.If,
|
||||
.While,
|
||||
.BoolNot,
|
||||
.AddressOf,
|
||||
.FloatLiteral,
|
||||
.UndefinedLiteral,
|
||||
.BoolLiteral,
|
||||
.NullLiteral,
|
||||
.OptionalType,
|
||||
.Block,
|
||||
.LabeledBlock,
|
||||
.Break,
|
||||
.PtrType,
|
||||
.GroupedExpression,
|
||||
.ArrayType,
|
||||
.ArrayTypeSentinel,
|
||||
.EnumLiteral,
|
||||
.MultilineStringLiteral,
|
||||
.CharLiteral,
|
||||
.Defer,
|
||||
.Catch,
|
||||
.ErrorUnion,
|
||||
.MergeErrorSets,
|
||||
.Range,
|
||||
.OrElse,
|
||||
.Await,
|
||||
.BitNot,
|
||||
.Negation,
|
||||
.NegationWrap,
|
||||
.Resume,
|
||||
.Try,
|
||||
.SliceType,
|
||||
.Slice,
|
||||
.ArrayInitializer,
|
||||
.ArrayInitializerDot,
|
||||
.StructInitializer,
|
||||
.StructInitializerDot,
|
||||
.Switch,
|
||||
.For,
|
||||
.Suspend,
|
||||
.Continue,
|
||||
.AnyType,
|
||||
.ErrorType,
|
||||
.FnProto,
|
||||
.AnyFrameType,
|
||||
.ErrorSetDecl,
|
||||
.ContainerDecl,
|
||||
.Comptime,
|
||||
.Nosuspend,
|
||||
=> return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}),
|
||||
|
||||
// @field can be assigned to
|
||||
.BuiltinCall => {
|
||||
const call = node.castTag(.BuiltinCall).?;
|
||||
const tree = scope.tree();
|
||||
const builtin_name = tree.tokenSlice(call.builtin_token);
|
||||
|
||||
if (!mem.eql(u8, builtin_name, "@field")) {
|
||||
return mod.failNode(scope, node, "invalid left-hand side to assignment", .{});
|
||||
}
|
||||
},
|
||||
|
||||
// can be assigned to
|
||||
.UnwrapOptional, .Deref, .Period, .ArrayAccess, .Identifier => {},
|
||||
}
|
||||
}
|
||||
switch (node.tag) {
|
||||
.Root => unreachable, // Top-level declaration.
|
||||
.Use => unreachable, // Top-level declaration.
|
||||
@@ -60,6 +188,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
||||
.PointerIndexPayload => unreachable, // Handled explicitly.
|
||||
.ErrorTag => unreachable, // Handled explicitly.
|
||||
.FieldInitializer => unreachable, // Handled explicitly.
|
||||
.ContainerField => unreachable, // Handled explicitly.
|
||||
|
||||
.Assign => return rlWrapVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)),
|
||||
.AssignBitAnd => return rlWrapVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bitand)),
|
||||
@@ -100,6 +229,9 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
||||
.ArrayCat => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayCat).?, .array_cat),
|
||||
.ArrayMult => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayMult).?, .array_mul),
|
||||
|
||||
.BoolAnd => return boolBinOp(mod, scope, rl, node.castTag(.BoolAnd).?),
|
||||
.BoolOr => return boolBinOp(mod, scope, rl, node.castTag(.BoolOr).?),
|
||||
|
||||
.Identifier => return try identifier(mod, scope, rl, node.castTag(.Identifier).?),
|
||||
.Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)),
|
||||
.StringLiteral => return rlWrap(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)),
|
||||
@@ -124,11 +256,15 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
||||
.LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?),
|
||||
.Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)),
|
||||
.PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)),
|
||||
.GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr),
|
||||
.ArrayType => return rlWrap(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)),
|
||||
.ArrayTypeSentinel => return rlWrap(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)),
|
||||
.EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)),
|
||||
.MultilineStringLiteral => return rlWrap(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)),
|
||||
.CharLiteral => return rlWrap(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)),
|
||||
|
||||
.Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
|
||||
.Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),
|
||||
.BoolAnd => return mod.failNode(scope, node, "TODO implement astgen.expr for .BoolAnd", .{}),
|
||||
.BoolOr => return mod.failNode(scope, node, "TODO implement astgen.expr for .BoolOr", .{}),
|
||||
.ErrorUnion => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorUnion", .{}),
|
||||
.MergeErrorSets => return mod.failNode(scope, node, "TODO implement astgen.expr for .MergeErrorSets", .{}),
|
||||
.Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),
|
||||
@@ -139,8 +275,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
||||
.NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}),
|
||||
.Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
|
||||
.Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
|
||||
.ArrayType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayType", .{}),
|
||||
.ArrayTypeSentinel => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayTypeSentinel", .{}),
|
||||
.SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}),
|
||||
.Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),
|
||||
.ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}),
|
||||
@@ -156,15 +290,10 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
||||
.ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}),
|
||||
.FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),
|
||||
.AnyFrameType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyFrameType", .{}),
|
||||
.EnumLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .EnumLiteral", .{}),
|
||||
.MultilineStringLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .MultilineStringLiteral", .{}),
|
||||
.CharLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .CharLiteral", .{}),
|
||||
.GroupedExpression => return mod.failNode(scope, node, "TODO implement astgen.expr for .GroupedExpression", .{}),
|
||||
.ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}),
|
||||
.ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),
|
||||
.Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}),
|
||||
.Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}),
|
||||
.ContainerField => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerField", .{}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +316,7 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr
|
||||
// proper type inference requires peer type resolution on the block's
|
||||
// break operand expressions.
|
||||
const branch_rl: ResultLoc = switch (label.result_loc) {
|
||||
.discard, .none, .ty, .ptr, .lvalue => label.result_loc,
|
||||
.discard, .none, .ty, .ptr, .lvalue, .ref => label.result_loc,
|
||||
.inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = label.block_inst },
|
||||
};
|
||||
const operand = try expr(mod, parent_scope, branch_rl, rhs);
|
||||
@@ -426,7 +555,7 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr
|
||||
}
|
||||
|
||||
fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
|
||||
return expr(mod, scope, .lvalue, node.rhs);
|
||||
return expr(mod, scope, .ref, node.rhs);
|
||||
}
|
||||
|
||||
fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
|
||||
@@ -484,13 +613,65 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir
|
||||
return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);
|
||||
}
|
||||
|
||||
fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.op_token].start;
|
||||
const meta_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.type_type),
|
||||
});
|
||||
const usize_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.usize_type),
|
||||
});
|
||||
|
||||
// TODO check for [_]T
|
||||
const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
|
||||
const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
|
||||
|
||||
return addZIRBinOp(mod, scope, src, .array_type, len, child_type);
|
||||
}
|
||||
|
||||
fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSentinel) !*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.op_token].start;
|
||||
const meta_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.type_type),
|
||||
});
|
||||
const usize_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.usize_type),
|
||||
});
|
||||
|
||||
// TODO check for [_]T
|
||||
const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
|
||||
const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel);
|
||||
const elem_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
|
||||
const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted);
|
||||
|
||||
return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{
|
||||
.len = len,
|
||||
.sentinel = sentinel,
|
||||
.elem_type = elem_type,
|
||||
}, .{});
|
||||
}
|
||||
|
||||
fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.EnumLiteral) !*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.name].start;
|
||||
const name = try identifierTokenString(mod, scope, node.name);
|
||||
|
||||
return addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{});
|
||||
}
|
||||
|
||||
fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.rtoken].start;
|
||||
|
||||
const operand = try expr(mod, scope, .lvalue, node.lhs);
|
||||
const operand = try expr(mod, scope, .ref, node.lhs);
|
||||
const unwrapped_ptr = try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand);
|
||||
if (rl == .lvalue) return unwrapped_ptr;
|
||||
if (rl == .lvalue or rl == .ref) return unwrapped_ptr;
|
||||
|
||||
return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));
|
||||
}
|
||||
@@ -568,6 +749,88 @@ fn simpleBinOp(
|
||||
return rlWrap(mod, scope, rl, result);
|
||||
}
|
||||
|
||||
fn boolBinOp(
|
||||
mod: *Module,
|
||||
scope: *Scope,
|
||||
rl: ResultLoc,
|
||||
infix_node: *ast.Node.SimpleInfixOp,
|
||||
) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[infix_node.op_token].start;
|
||||
const bool_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.bool_type),
|
||||
});
|
||||
|
||||
var block_scope: Scope.GenZIR = .{
|
||||
.parent = scope,
|
||||
.decl = scope.decl().?,
|
||||
.arena = scope.arena(),
|
||||
.instructions = .{},
|
||||
};
|
||||
defer block_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
const lhs = try expr(mod, scope, .{ .ty = bool_type }, infix_node.lhs);
|
||||
const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{
|
||||
.condition = lhs,
|
||||
.then_body = undefined, // populated below
|
||||
.else_body = undefined, // populated below
|
||||
}, .{});
|
||||
|
||||
const block = try addZIRInstBlock(mod, scope, src, .{
|
||||
.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
|
||||
});
|
||||
|
||||
var rhs_scope: Scope.GenZIR = .{
|
||||
.parent = scope,
|
||||
.decl = block_scope.decl,
|
||||
.arena = block_scope.arena,
|
||||
.instructions = .{},
|
||||
};
|
||||
defer rhs_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
const rhs = try expr(mod, &rhs_scope.base, .{ .ty = bool_type }, infix_node.rhs);
|
||||
_ = try addZIRInst(mod, &rhs_scope.base, src, zir.Inst.Break, .{
|
||||
.block = block,
|
||||
.operand = rhs,
|
||||
}, .{});
|
||||
|
||||
var const_scope: Scope.GenZIR = .{
|
||||
.parent = scope,
|
||||
.decl = block_scope.decl,
|
||||
.arena = block_scope.arena,
|
||||
.instructions = .{},
|
||||
};
|
||||
defer const_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
const is_bool_and = infix_node.base.tag == .BoolAnd;
|
||||
_ = try addZIRInst(mod, &const_scope.base, src, zir.Inst.Break, .{
|
||||
.block = block,
|
||||
.operand = try addZIRInstConst(mod, &const_scope.base, src, .{
|
||||
.ty = Type.initTag(.bool),
|
||||
.val = if (is_bool_and) Value.initTag(.bool_false) else Value.initTag(.bool_true),
|
||||
}),
|
||||
}, .{});
|
||||
|
||||
if (is_bool_and) {
|
||||
// if lhs // AND
|
||||
// break rhs
|
||||
// else
|
||||
// break false
|
||||
condbr.positionals.then_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) };
|
||||
condbr.positionals.else_body = .{ .instructions = try const_scope.arena.dupe(*zir.Inst, const_scope.instructions.items) };
|
||||
} else {
|
||||
// if lhs // OR
|
||||
// break true
|
||||
// else
|
||||
// break rhs
|
||||
condbr.positionals.then_body = .{ .instructions = try const_scope.arena.dupe(*zir.Inst, const_scope.instructions.items) };
|
||||
condbr.positionals.else_body = .{ .instructions = try rhs_scope.arena.dupe(*zir.Inst, rhs_scope.instructions.items) };
|
||||
}
|
||||
|
||||
return rlWrap(mod, scope, rl, &block.base);
|
||||
}
|
||||
|
||||
const CondKind = union(enum) {
|
||||
bool,
|
||||
optional: ?*zir.Inst,
|
||||
@@ -583,13 +846,13 @@ const CondKind = union(enum) {
|
||||
return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node);
|
||||
},
|
||||
.optional => {
|
||||
const cond_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node);
|
||||
const cond_ptr = try expr(mod, &block_scope.base, .ref, cond_node);
|
||||
self.* = .{ .optional = cond_ptr };
|
||||
const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr);
|
||||
return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result);
|
||||
},
|
||||
.err_union => {
|
||||
const err_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node);
|
||||
const err_ptr = try expr(mod, &block_scope.base, .ref, cond_node);
|
||||
self.* = .{ .err_union = err_ptr };
|
||||
const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr);
|
||||
return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result);
|
||||
@@ -600,7 +863,11 @@ const CondKind = union(enum) {
|
||||
fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope {
|
||||
if (self == .bool) return &then_scope.base;
|
||||
|
||||
const payload = payload_node.?.castTag(.PointerPayload).?;
|
||||
const payload = payload_node.?.castTag(.PointerPayload) orelse {
|
||||
// condition is error union and payload is not explicitly ignored
|
||||
_ = try addZIRUnOp(mod, &then_scope.base, src, .ensure_err_payload_void, self.err_union.?);
|
||||
return &then_scope.base;
|
||||
};
|
||||
const is_ptr = payload.ptr_token != null;
|
||||
const ident_node = payload.value_symbol.castTag(.Identifier).?;
|
||||
|
||||
@@ -680,7 +947,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
|
||||
// proper type inference requires peer type resolution on the if's
|
||||
// branches.
|
||||
const branch_rl: ResultLoc = switch (rl) {
|
||||
.discard, .none, .ty, .ptr, .lvalue => rl,
|
||||
.discard, .none, .ty, .ptr, .lvalue, .ref => rl,
|
||||
.inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
|
||||
};
|
||||
|
||||
@@ -810,7 +1077,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
|
||||
// proper type inference requires peer type resolution on the while's
|
||||
// branches.
|
||||
const branch_rl: ResultLoc = switch (rl) {
|
||||
.discard, .none, .ty, .ptr, .lvalue => rl,
|
||||
.discard, .none, .ty, .ptr, .lvalue, .ref => rl,
|
||||
.inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block },
|
||||
};
|
||||
|
||||
@@ -941,7 +1208,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
|
||||
.local_ptr => {
|
||||
const local_ptr = s.cast(Scope.LocalPtr).?;
|
||||
if (mem.eql(u8, local_ptr.name, ident_name)) {
|
||||
if (rl == .lvalue) {
|
||||
if (rl == .lvalue or rl == .ref) {
|
||||
return local_ptr.ptr;
|
||||
} else {
|
||||
const result = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr);
|
||||
@@ -983,6 +1250,53 @@ fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.OneToken) Inner
|
||||
return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
|
||||
}
|
||||
|
||||
fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStringLiteral) !*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const lines = node.linesConst();
|
||||
const src = tree.token_locs[lines[0]].start;
|
||||
|
||||
// line lengths and new lines
|
||||
var len = lines.len - 1;
|
||||
for (lines) |line| {
|
||||
len += tree.tokenSlice(line).len - 2;
|
||||
}
|
||||
|
||||
const bytes = try scope.arena().alloc(u8, len);
|
||||
var i: usize = 0;
|
||||
for (lines) |line, line_i| {
|
||||
if (line_i != 0) {
|
||||
bytes[i] = '\n';
|
||||
i += 1;
|
||||
}
|
||||
const slice = tree.tokenSlice(line)[2..];
|
||||
mem.copy(u8, bytes[i..], slice);
|
||||
i += slice.len;
|
||||
}
|
||||
|
||||
return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
|
||||
}
|
||||
|
||||
fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.token].start;
|
||||
const slice = tree.tokenSlice(node.token);
|
||||
|
||||
var bad_index: usize = undefined;
|
||||
const value = std.zig.parseCharLiteral(slice, &bad_index) catch |err| switch (err) {
|
||||
error.InvalidCharacter => {
|
||||
const bad_byte = slice[bad_index];
|
||||
return mod.fail(scope, src + bad_index, "invalid character: '{c}'\n", .{bad_byte});
|
||||
},
|
||||
};
|
||||
|
||||
const int_payload = try scope.arena().create(Value.Payload.Int_u64);
|
||||
int_payload.* = .{ .int = value };
|
||||
return addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.comptime_int),
|
||||
.val = Value.initPayload(&int_payload.base),
|
||||
});
|
||||
}
|
||||
|
||||
fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) InnerError!*zir.Inst {
|
||||
const arena = scope.arena();
|
||||
const tree = scope.tree();
|
||||
@@ -1158,7 +1472,8 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I
|
||||
_ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
|
||||
return result;
|
||||
},
|
||||
.lvalue => {
|
||||
.lvalue => unreachable,
|
||||
.ref => {
|
||||
const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);
|
||||
return addZIRUnOp(mod, scope, result.src, .ref, result);
|
||||
},
|
||||
@@ -1209,9 +1524,10 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa
|
||||
_ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
|
||||
return result;
|
||||
},
|
||||
.lvalue => {
|
||||
const operand = try expr(mod, scope, .lvalue, params[1]);
|
||||
const result = try addZIRBinOp(mod, scope, src, .bitcast_lvalue, dest_type, operand);
|
||||
.lvalue => unreachable,
|
||||
.ref => {
|
||||
const operand = try expr(mod, scope, .ref, params[1]);
|
||||
const result = try addZIRBinOp(mod, scope, src, .bitcast_ref, dest_type, operand);
|
||||
return result;
|
||||
},
|
||||
.ty => |result_ty| {
|
||||
@@ -1476,7 +1792,7 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr
|
||||
_ = try addZIRUnOp(mod, scope, result.src, .ensure_result_non_error, result);
|
||||
return result;
|
||||
},
|
||||
.lvalue => {
|
||||
.lvalue, .ref => {
|
||||
// We need a pointer but we have a value.
|
||||
return addZIRUnOp(mod, scope, result.src, .ref, result);
|
||||
},
|
||||
|
||||
@@ -65,7 +65,7 @@ pub const Type = extern union {
|
||||
.fn_ccc_void_no_args => return .Fn,
|
||||
.function => return .Fn,
|
||||
|
||||
.array, .array_u8_sentinel_0 => return .Array,
|
||||
.array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array,
|
||||
.single_const_pointer => return .Pointer,
|
||||
.single_mut_pointer => return .Pointer,
|
||||
.single_const_pointer_to_comptime_int => return .Pointer,
|
||||
@@ -75,6 +75,7 @@ pub const Type = extern union {
|
||||
.optional_single_const_pointer,
|
||||
.optional_single_mut_pointer,
|
||||
=> return .Optional,
|
||||
.enum_literal => return .EnumLiteral,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +128,7 @@ pub const Type = extern union {
|
||||
if (zig_tag_a != zig_tag_b)
|
||||
return false;
|
||||
switch (zig_tag_a) {
|
||||
.EnumLiteral => return true,
|
||||
.Type => return true,
|
||||
.Void => return true,
|
||||
.Bool => return true,
|
||||
@@ -211,7 +213,6 @@ pub const Type = extern union {
|
||||
.Frame,
|
||||
.AnyFrame,
|
||||
.Vector,
|
||||
.EnumLiteral,
|
||||
=> std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
|
||||
}
|
||||
}
|
||||
@@ -327,9 +328,11 @@ pub const Type = extern union {
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.const_slice_u8,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0),
|
||||
.array_u8 => return self.copyPayloadShallow(allocator, Payload.Array_u8),
|
||||
.array => {
|
||||
const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.Array);
|
||||
@@ -340,6 +343,17 @@ pub const Type = extern union {
|
||||
};
|
||||
return Type{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.array_sentinel => {
|
||||
const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.ArraySentinel);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.len = payload.len,
|
||||
.sentinel = try payload.sentinel.copy(allocator),
|
||||
.elem_type = try payload.elem_type.copy(allocator),
|
||||
};
|
||||
return Type{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
|
||||
.int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
|
||||
.function => {
|
||||
@@ -425,6 +439,7 @@ pub const Type = extern union {
|
||||
.noreturn,
|
||||
=> return out_stream.writeAll(@tagName(t)),
|
||||
|
||||
.enum_literal => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),
|
||||
.@"null" => return out_stream.writeAll("@TypeOf(null)"),
|
||||
.@"undefined" => return out_stream.writeAll("@TypeOf(undefined)"),
|
||||
|
||||
@@ -445,6 +460,10 @@ pub const Type = extern union {
|
||||
try payload.return_type.format("", .{}, out_stream);
|
||||
},
|
||||
|
||||
.array_u8 => {
|
||||
const payload = @fieldParentPtr(Payload.Array_u8, "base", ty.ptr_otherwise);
|
||||
return out_stream.print("[{}]u8", .{payload.len});
|
||||
},
|
||||
.array_u8_sentinel_0 => {
|
||||
const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
|
||||
return out_stream.print("[{}:0]u8", .{payload.len});
|
||||
@@ -455,6 +474,12 @@ pub const Type = extern union {
|
||||
ty = payload.elem_type;
|
||||
continue;
|
||||
},
|
||||
.array_sentinel => {
|
||||
const payload = @fieldParentPtr(Payload.ArraySentinel, "base", ty.ptr_otherwise);
|
||||
try out_stream.print("[{}:{}]", .{ payload.len, payload.sentinel });
|
||||
ty = payload.elem_type;
|
||||
continue;
|
||||
},
|
||||
.single_const_pointer => {
|
||||
const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
|
||||
try out_stream.writeAll("*const ");
|
||||
@@ -539,6 +564,7 @@ pub const Type = extern union {
|
||||
.fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
|
||||
.single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
|
||||
.const_slice_u8 => return Value.initTag(.const_slice_u8_type),
|
||||
.enum_literal => return Value.initTag(.enum_literal_type),
|
||||
else => {
|
||||
const ty_payload = try allocator.create(Value.Payload.Ty);
|
||||
ty_payload.* = .{ .ty = self };
|
||||
@@ -588,6 +614,8 @@ pub const Type = extern union {
|
||||
=> true,
|
||||
// TODO lazy types
|
||||
.array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
|
||||
.array_u8 => self.arrayLen() != 0,
|
||||
.array_sentinel => self.elemType().hasCodeGenBits(),
|
||||
.single_const_pointer => self.elemType().hasCodeGenBits(),
|
||||
.single_mut_pointer => self.elemType().hasCodeGenBits(),
|
||||
.int_signed => self.cast(Payload.IntSigned).?.bits == 0,
|
||||
@@ -601,6 +629,7 @@ pub const Type = extern union {
|
||||
.noreturn,
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.enum_literal,
|
||||
=> false,
|
||||
};
|
||||
}
|
||||
@@ -616,6 +645,7 @@ pub const Type = extern union {
|
||||
.i8,
|
||||
.bool,
|
||||
.array_u8_sentinel_0,
|
||||
.array_u8,
|
||||
=> return 1,
|
||||
|
||||
.fn_noreturn_no_args, // represents machine code; not a pointer
|
||||
@@ -659,7 +689,7 @@ pub const Type = extern union {
|
||||
|
||||
.anyerror => return 2, // TODO revisit this when we have the concept of the error tag type
|
||||
|
||||
.array => return self.cast(Payload.Array).?.elem_type.abiAlignment(target),
|
||||
.array, .array_sentinel => return self.elemType().abiAlignment(target),
|
||||
|
||||
.int_signed, .int_unsigned => {
|
||||
const bits: u16 = if (self.cast(Payload.IntSigned)) |pl|
|
||||
@@ -691,6 +721,7 @@ pub const Type = extern union {
|
||||
.noreturn,
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@@ -711,18 +742,25 @@ pub const Type = extern union {
|
||||
.noreturn => unreachable,
|
||||
.@"null" => unreachable,
|
||||
.@"undefined" => unreachable,
|
||||
.enum_literal => unreachable,
|
||||
|
||||
.u8,
|
||||
.i8,
|
||||
.bool,
|
||||
=> return 1,
|
||||
|
||||
.array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len,
|
||||
.array_u8 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len,
|
||||
.array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len + 1,
|
||||
.array => {
|
||||
const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
|
||||
const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
|
||||
return payload.len * elem_size;
|
||||
},
|
||||
.array_sentinel => {
|
||||
const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise);
|
||||
const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
|
||||
return (payload.len + 1) * elem_size;
|
||||
},
|
||||
.i16, .u16 => return 2,
|
||||
.i32, .u32 => return 4,
|
||||
.i64, .u64 => return 8,
|
||||
@@ -818,6 +856,8 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.fn_noreturn_no_args,
|
||||
@@ -830,6 +870,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> false,
|
||||
|
||||
.single_const_pointer,
|
||||
@@ -875,6 +916,8 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
@@ -889,6 +932,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> false,
|
||||
|
||||
.const_slice_u8 => true,
|
||||
@@ -931,6 +975,8 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
@@ -943,6 +989,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> false,
|
||||
|
||||
.single_const_pointer,
|
||||
@@ -988,6 +1035,8 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
@@ -1003,6 +1052,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> false,
|
||||
};
|
||||
}
|
||||
@@ -1023,6 +1073,45 @@ pub const Type = extern union {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns if type can be used for a runtime variable
|
||||
pub fn isValidVarType(self: Type) bool {
|
||||
var ty = self;
|
||||
while (true) switch (ty.zigTypeTag()) {
|
||||
.Bool,
|
||||
.Int,
|
||||
.Float,
|
||||
.ErrorSet,
|
||||
.Enum,
|
||||
.Frame,
|
||||
.AnyFrame,
|
||||
.Vector,
|
||||
=> return true,
|
||||
|
||||
.BoundFn,
|
||||
.ComptimeFloat,
|
||||
.ComptimeInt,
|
||||
.EnumLiteral,
|
||||
.NoReturn,
|
||||
.Type,
|
||||
.Void,
|
||||
.Undefined,
|
||||
.Null,
|
||||
.Opaque,
|
||||
=> return false,
|
||||
|
||||
.Optional => {
|
||||
var buf: Payload.Pointer = undefined;
|
||||
return ty.optionalChild(&buf).isValidVarType();
|
||||
},
|
||||
.Pointer, .Array => ty = ty.elemType(),
|
||||
|
||||
.ErrorUnion => @panic("TODO fn isValidVarType"),
|
||||
.Fn => @panic("TODO fn isValidVarType"),
|
||||
.Struct => @panic("TODO struct isValidVarType"),
|
||||
.Union => @panic("TODO union isValidVarType"),
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the type is a pointer or array type.
|
||||
pub fn elemType(self: Type) Type {
|
||||
return switch (self.tag()) {
|
||||
@@ -1069,12 +1158,14 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_const_pointer,
|
||||
.optional_single_mut_pointer,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.array => self.cast(Payload.Array).?.elem_type,
|
||||
.array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type,
|
||||
.single_const_pointer => self.castPointer().?.pointee_type,
|
||||
.single_mut_pointer => self.castPointer().?.pointee_type,
|
||||
.array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
|
||||
.array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
|
||||
.single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
|
||||
};
|
||||
}
|
||||
@@ -1173,9 +1264,12 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.array => self.cast(Payload.Array).?.len,
|
||||
.array_sentinel => self.cast(Payload.ArraySentinel).?.len,
|
||||
.array_u8 => self.cast(Payload.Array_u8).?.len,
|
||||
.array_u8_sentinel_0 => self.cast(Payload.Array_u8_Sentinel0).?.len,
|
||||
};
|
||||
}
|
||||
@@ -1230,9 +1324,11 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.array => return null,
|
||||
.array, .array_u8 => return null,
|
||||
.array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel,
|
||||
.array_u8_sentinel_0 => return Value.initTag(.zero),
|
||||
};
|
||||
}
|
||||
@@ -1266,10 +1362,12 @@ pub const Type = extern union {
|
||||
.fn_ccc_void_no_args,
|
||||
.function,
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.int_unsigned,
|
||||
.u8,
|
||||
@@ -1284,6 +1382,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> false,
|
||||
|
||||
.int_signed,
|
||||
@@ -1324,10 +1423,12 @@ pub const Type = extern union {
|
||||
.fn_ccc_void_no_args,
|
||||
.function,
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.int_signed,
|
||||
.i8,
|
||||
@@ -1342,6 +1443,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> false,
|
||||
|
||||
.int_unsigned,
|
||||
@@ -1382,14 +1484,17 @@ pub const Type = extern union {
|
||||
.fn_ccc_void_no_args,
|
||||
.function,
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits },
|
||||
@@ -1438,10 +1543,12 @@ pub const Type = extern union {
|
||||
.fn_ccc_void_no_args,
|
||||
.function,
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.int_unsigned,
|
||||
.int_signed,
|
||||
@@ -1456,6 +1563,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> false,
|
||||
|
||||
.usize,
|
||||
@@ -1523,10 +1631,12 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.u8,
|
||||
.i8,
|
||||
@@ -1551,6 +1661,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@@ -1584,10 +1695,12 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.u8,
|
||||
.i8,
|
||||
@@ -1612,6 +1725,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
}
|
||||
}
|
||||
@@ -1644,10 +1758,12 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.u8,
|
||||
.i8,
|
||||
@@ -1672,6 +1788,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
}
|
||||
}
|
||||
@@ -1704,10 +1821,12 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.u8,
|
||||
.i8,
|
||||
@@ -1732,6 +1851,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@@ -1761,10 +1881,12 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.u8,
|
||||
.i8,
|
||||
@@ -1789,6 +1911,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@@ -1818,10 +1941,12 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.u8,
|
||||
.i8,
|
||||
@@ -1846,6 +1971,7 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@@ -1895,14 +2021,17 @@ pub const Type = extern union {
|
||||
.fn_ccc_void_no_args,
|
||||
.function,
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> false,
|
||||
};
|
||||
}
|
||||
@@ -1944,12 +2073,14 @@ pub const Type = extern union {
|
||||
.fn_ccc_void_no_args,
|
||||
.function,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_sentinel,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.c_void,
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> return null,
|
||||
|
||||
.void => return Value.initTag(.void_value),
|
||||
@@ -1971,11 +2102,10 @@ pub const Type = extern union {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
.array => {
|
||||
const array = ty.cast(Payload.Array).?;
|
||||
if (array.len == 0)
|
||||
.array, .array_u8 => {
|
||||
if (ty.arrayLen() == 0)
|
||||
return Value.initTag(.empty_array);
|
||||
ty = array.elem_type;
|
||||
ty = ty.elemType();
|
||||
continue;
|
||||
},
|
||||
.single_const_pointer, .single_mut_pointer => {
|
||||
@@ -2022,7 +2152,6 @@ pub const Type = extern union {
|
||||
.fn_ccc_void_no_args,
|
||||
.function,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.c_void,
|
||||
.void,
|
||||
@@ -2032,11 +2161,15 @@ pub const Type = extern union {
|
||||
.int_unsigned,
|
||||
.int_signed,
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
=> return false,
|
||||
};
|
||||
}
|
||||
@@ -2080,6 +2213,7 @@ pub const Type = extern union {
|
||||
comptime_int,
|
||||
comptime_float,
|
||||
noreturn,
|
||||
enum_literal,
|
||||
@"null",
|
||||
@"undefined",
|
||||
fn_noreturn_no_args,
|
||||
@@ -2090,8 +2224,10 @@ pub const Type = extern union {
|
||||
const_slice_u8, // See last_no_payload_tag below.
|
||||
// After this, the tag requires a payload.
|
||||
|
||||
array_u8,
|
||||
array_u8_sentinel_0,
|
||||
array,
|
||||
array_sentinel,
|
||||
single_const_pointer,
|
||||
single_mut_pointer,
|
||||
int_signed,
|
||||
@@ -2114,11 +2250,25 @@ pub const Type = extern union {
|
||||
len: u64,
|
||||
};
|
||||
|
||||
pub const Array_u8 = struct {
|
||||
base: Payload = Payload{ .tag = .array_u8 },
|
||||
|
||||
len: u64,
|
||||
};
|
||||
|
||||
pub const Array = struct {
|
||||
base: Payload = Payload{ .tag = .array },
|
||||
|
||||
elem_type: Type,
|
||||
len: u64,
|
||||
elem_type: Type,
|
||||
};
|
||||
|
||||
pub const ArraySentinel = struct {
|
||||
base: Payload = Payload{ .tag = .array_sentinel },
|
||||
|
||||
len: u64,
|
||||
sentinel: Value,
|
||||
elem_type: Type,
|
||||
};
|
||||
|
||||
pub const Pointer = struct {
|
||||
|
||||
@@ -60,6 +60,7 @@ pub const Value = extern union {
|
||||
fn_ccc_void_no_args_type,
|
||||
single_const_pointer_to_comptime_int_type,
|
||||
const_slice_u8_type,
|
||||
enum_literal_type,
|
||||
|
||||
undef,
|
||||
zero,
|
||||
@@ -87,6 +88,7 @@ pub const Value = extern union {
|
||||
float_32,
|
||||
float_64,
|
||||
float_128,
|
||||
enum_literal,
|
||||
|
||||
pub const last_no_payload_tag = Tag.bool_false;
|
||||
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
||||
@@ -164,6 +166,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.undef,
|
||||
.zero,
|
||||
.void_value,
|
||||
@@ -213,7 +216,7 @@ pub const Value = extern union {
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
|
||||
.enum_literal, .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
|
||||
.repeated => {
|
||||
const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.Repeated);
|
||||
@@ -285,6 +288,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
|
||||
.single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
|
||||
.const_slice_u8_type => return out_stream.writeAll("[]const u8"),
|
||||
.enum_literal_type => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),
|
||||
|
||||
.null_value => return out_stream.writeAll("null"),
|
||||
.undef => return out_stream.writeAll("undefined"),
|
||||
@@ -318,7 +322,7 @@ pub const Value = extern union {
|
||||
val = elem_ptr.array_ptr;
|
||||
},
|
||||
.empty_array => return out_stream.writeAll(".{}"),
|
||||
.bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream),
|
||||
.enum_literal, .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream),
|
||||
.repeated => {
|
||||
try out_stream.writeAll("(repeated) ");
|
||||
val = val.cast(Payload.Repeated).?.val;
|
||||
@@ -391,6 +395,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
|
||||
.single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
|
||||
.const_slice_u8_type => Type.initTag(.const_slice_u8),
|
||||
.enum_literal_type => Type.initTag(.enum_literal),
|
||||
|
||||
.undef,
|
||||
.zero,
|
||||
@@ -414,6 +419,7 @@ pub const Value = extern union {
|
||||
.float_32,
|
||||
.float_64,
|
||||
.float_128,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@@ -462,6 +468,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.ref_val,
|
||||
@@ -476,6 +483,7 @@ pub const Value = extern union {
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@@ -537,6 +545,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.ref_val,
|
||||
@@ -551,6 +560,7 @@ pub const Value = extern union {
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@@ -612,6 +622,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.ref_val,
|
||||
@@ -626,6 +637,7 @@ pub const Value = extern union {
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@@ -713,6 +725,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.ref_val,
|
||||
@@ -728,6 +741,7 @@ pub const Value = extern union {
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@@ -793,6 +807,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.ref_val,
|
||||
@@ -807,6 +822,7 @@ pub const Value = extern union {
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@@ -953,6 +969,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.bool_true,
|
||||
.bool_false,
|
||||
.null_value,
|
||||
@@ -970,6 +987,7 @@ pub const Value = extern union {
|
||||
.empty_array,
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.zero => false,
|
||||
@@ -1025,6 +1043,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.ref_val,
|
||||
@@ -1036,6 +1055,7 @@ pub const Value = extern union {
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@@ -1102,6 +1122,11 @@ pub const Value = extern union {
|
||||
}
|
||||
|
||||
pub fn eql(a: Value, b: Value) bool {
|
||||
if (a.tag() == b.tag() and a.tag() == .enum_literal) {
|
||||
const a_name = @fieldParentPtr(Payload.Bytes, "base", a.ptr_otherwise).data;
|
||||
const b_name = @fieldParentPtr(Payload.Bytes, "base", b.ptr_otherwise).data;
|
||||
return std.mem.eql(u8, a_name, b_name);
|
||||
}
|
||||
// TODO non numerical comparisons
|
||||
return compare(a, .eq, b);
|
||||
}
|
||||
@@ -1151,6 +1176,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.zero,
|
||||
.bool_true,
|
||||
.bool_false,
|
||||
@@ -1170,6 +1196,7 @@ pub const Value = extern union {
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.ref_val => self.cast(Payload.RefVal).?.val,
|
||||
@@ -1227,6 +1254,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.zero,
|
||||
.bool_true,
|
||||
.bool_false,
|
||||
@@ -1246,6 +1274,7 @@ pub const Value = extern union {
|
||||
.float_128,
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.enum_literal,
|
||||
=> unreachable,
|
||||
|
||||
.empty_array => unreachable, // out of bounds array index
|
||||
@@ -1320,6 +1349,7 @@ pub const Value = extern union {
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.zero,
|
||||
.empty_array,
|
||||
.bool_true,
|
||||
@@ -1339,6 +1369,7 @@ pub const Value = extern union {
|
||||
.float_64,
|
||||
.float_128,
|
||||
.void_value,
|
||||
.enum_literal,
|
||||
=> false,
|
||||
|
||||
.undef => unreachable,
|
||||
|
||||
@@ -47,6 +47,10 @@ pub const Inst = struct {
|
||||
array_cat,
|
||||
/// Array multiplication `a ** b`
|
||||
array_mul,
|
||||
/// Create an array type
|
||||
array_type,
|
||||
/// Create an array type with sentinel
|
||||
array_type_sentinel,
|
||||
/// Function parameter value. These must be first in a function's main block,
|
||||
/// in respective order with the parameters.
|
||||
arg,
|
||||
@@ -58,11 +62,11 @@ pub const Inst = struct {
|
||||
bitand,
|
||||
/// TODO delete this instruction, it has no purpose.
|
||||
bitcast,
|
||||
/// An arbitrary typed pointer, which is to be used as an L-Value, is pointer-casted
|
||||
/// to a new L-Value. The destination type is given by LHS. The cast is to be evaluated
|
||||
/// An arbitrary typed pointer is pointer-casted to a new Pointer.
|
||||
/// The destination type is given by LHS. The cast is to be evaluated
|
||||
/// as if it were a bit-cast operation from the operand pointer element type to the
|
||||
/// provided destination type.
|
||||
bitcast_lvalue,
|
||||
bitcast_ref,
|
||||
/// A typed result location pointer is bitcasted to a new result location pointer.
|
||||
/// The new result location pointer has an inferred type.
|
||||
bitcast_result_ptr,
|
||||
@@ -225,6 +229,10 @@ pub const Inst = struct {
|
||||
unwrap_err_safe,
|
||||
/// Same as previous, but without safety checks. Used for orelse, if and while
|
||||
unwrap_err_unsafe,
|
||||
/// Takes a *E!T and raises a compiler error if T != void
|
||||
ensure_err_payload_void,
|
||||
/// Enum literal
|
||||
enum_literal,
|
||||
|
||||
pub fn Type(tag: Tag) type {
|
||||
return switch (tag) {
|
||||
@@ -250,7 +258,7 @@ pub const Inst = struct {
|
||||
.ensure_result_non_error,
|
||||
.bitcast_result_ptr,
|
||||
.ref,
|
||||
.bitcast_lvalue,
|
||||
.bitcast_ref,
|
||||
.typeof,
|
||||
.single_const_ptr_type,
|
||||
.single_mut_ptr_type,
|
||||
@@ -259,12 +267,14 @@ pub const Inst = struct {
|
||||
.unwrap_optional_unsafe,
|
||||
.unwrap_err_safe,
|
||||
.unwrap_err_unsafe,
|
||||
.ensure_err_payload_void,
|
||||
=> UnOp,
|
||||
|
||||
.add,
|
||||
.addwrap,
|
||||
.array_cat,
|
||||
.array_mul,
|
||||
.array_type,
|
||||
.bitand,
|
||||
.bitor,
|
||||
.div,
|
||||
@@ -291,6 +301,7 @@ pub const Inst = struct {
|
||||
=> BinOp,
|
||||
|
||||
.arg => Arg,
|
||||
.array_type_sentinel => ArrayTypeSentinel,
|
||||
.block => Block,
|
||||
.@"break" => Break,
|
||||
.breakvoid => BreakVoid,
|
||||
@@ -317,6 +328,7 @@ pub const Inst = struct {
|
||||
.elemptr => ElemPtr,
|
||||
.condbr => CondBr,
|
||||
.ptr_type => PtrType,
|
||||
.enum_literal => EnumLiteral,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -330,12 +342,14 @@ pub const Inst = struct {
|
||||
.alloc_inferred,
|
||||
.array_cat,
|
||||
.array_mul,
|
||||
.array_type,
|
||||
.array_type_sentinel,
|
||||
.arg,
|
||||
.as,
|
||||
.@"asm",
|
||||
.bitand,
|
||||
.bitcast,
|
||||
.bitcast_lvalue,
|
||||
.bitcast_ref,
|
||||
.bitcast_result_ptr,
|
||||
.bitor,
|
||||
.block,
|
||||
@@ -398,6 +412,8 @@ pub const Inst = struct {
|
||||
.unwrap_err_safe,
|
||||
.unwrap_err_unsafe,
|
||||
.ptr_type,
|
||||
.ensure_err_payload_void,
|
||||
.enum_literal,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
@@ -845,6 +861,28 @@ pub const Inst = struct {
|
||||
sentinel: ?*Inst = null,
|
||||
},
|
||||
};
|
||||
|
||||
pub const ArrayTypeSentinel = struct {
|
||||
pub const base_tag = Tag.array_type_sentinel;
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
len: *Inst,
|
||||
sentinel: *Inst,
|
||||
elem_type: *Inst,
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const EnumLiteral = struct {
|
||||
pub const base_tag = Tag.enum_literal;
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
name: []const u8,
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
};
|
||||
|
||||
pub const ErrorMsg = struct {
|
||||
@@ -1922,6 +1960,10 @@ const EmitZIR = struct {
|
||||
return self.emitUnnamedDecl(&str_inst.base);
|
||||
},
|
||||
.Void => return self.emitPrimitive(src, .void_value),
|
||||
.Bool => if (typed_value.val.toBool())
|
||||
return self.emitPrimitive(src, .@"true")
|
||||
else
|
||||
return self.emitPrimitive(src, .@"false"),
|
||||
else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
||||
.alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?),
|
||||
.alloc_inferred => return analyzeInstAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?),
|
||||
.arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?),
|
||||
.bitcast_lvalue => return analyzeInstBitCastLValue(mod, scope, old_inst.castTag(.bitcast_lvalue).?),
|
||||
.bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),
|
||||
.bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),
|
||||
.block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?),
|
||||
.@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?),
|
||||
@@ -112,6 +112,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
||||
.unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),
|
||||
.unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),
|
||||
.unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false),
|
||||
.ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?),
|
||||
.array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?),
|
||||
.array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?),
|
||||
.enum_literal => return analyzeInstEnumLiteral(mod, scope, old_inst.castTag(.enum_literal).?),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,8 +299,8 @@ fn analyzeInstCoerceResultBlockPtr(
|
||||
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{});
|
||||
}
|
||||
|
||||
fn analyzeInstBitCastLValue(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastLValue", .{});
|
||||
fn analyzeInstBitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastRef", .{});
|
||||
}
|
||||
|
||||
fn analyzeInstBitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
@@ -361,6 +365,10 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.
|
||||
|
||||
fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
const var_type = try resolveType(mod, scope, inst.positionals.operand);
|
||||
// TODO this should happen only for var allocs
|
||||
if (!var_type.isValidVarType()) {
|
||||
return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type});
|
||||
}
|
||||
const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type);
|
||||
const b = try mod.requireRuntimeBlock(scope, inst.base.src);
|
||||
return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
|
||||
@@ -675,31 +683,36 @@ fn analyzeInstIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) I
|
||||
fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
const child_type = try resolveType(mod, scope, optional.positionals.operand);
|
||||
|
||||
return mod.constType(scope, optional.base.src, Type.initPayload(switch (child_type.tag()) {
|
||||
.single_const_pointer => blk: {
|
||||
const payload = try scope.arena().create(Type.Payload.Pointer);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .optional_single_const_pointer },
|
||||
.pointee_type = child_type.elemType(),
|
||||
};
|
||||
break :blk &payload.base;
|
||||
},
|
||||
.single_mut_pointer => blk: {
|
||||
const payload = try scope.arena().create(Type.Payload.Pointer);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .optional_single_mut_pointer },
|
||||
.pointee_type = child_type.elemType(),
|
||||
};
|
||||
break :blk &payload.base;
|
||||
},
|
||||
else => blk: {
|
||||
const payload = try scope.arena().create(Type.Payload.Optional);
|
||||
payload.* = .{
|
||||
.child_type = child_type,
|
||||
};
|
||||
break :blk &payload.base;
|
||||
},
|
||||
}));
|
||||
return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type));
|
||||
}
|
||||
|
||||
fn analyzeInstArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst {
|
||||
// TODO these should be lazily evaluated
|
||||
const len = try resolveInstConst(mod, scope, array.positionals.lhs);
|
||||
const elem_type = try resolveType(mod, scope, array.positionals.rhs);
|
||||
|
||||
return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type));
|
||||
}
|
||||
|
||||
fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.ArrayTypeSentinel) InnerError!*Inst {
|
||||
// TODO these should be lazily evaluated
|
||||
const len = try resolveInstConst(mod, scope, array.positionals.len);
|
||||
const sentinel = try resolveInstConst(mod, scope, array.positionals.sentinel);
|
||||
const elem_type = try resolveType(mod, scope, array.positionals.elem_type);
|
||||
|
||||
return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type));
|
||||
}
|
||||
|
||||
fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst {
|
||||
const payload = try scope.arena().create(Value.Payload.Bytes);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .enum_literal },
|
||||
.data = try scope.arena().dupe(u8, inst.positionals.name),
|
||||
};
|
||||
return mod.constInst(scope, inst.base.src, .{
|
||||
.ty = Type.initTag(.enum_literal),
|
||||
.val = Value.initPayload(&payload.base),
|
||||
});
|
||||
}
|
||||
|
||||
fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {
|
||||
@@ -735,6 +748,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf
|
||||
return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{});
|
||||
}
|
||||
|
||||
fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstEnsureErrPayloadVoid", .{});
|
||||
}
|
||||
|
||||
fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
|
||||
const return_type = try resolveType(mod, scope, fntype.positionals.return_type);
|
||||
|
||||
@@ -760,7 +777,12 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne
|
||||
const arena = scope.arena();
|
||||
const param_types = try arena.alloc(Type, fntype.positionals.param_types.len);
|
||||
for (fntype.positionals.param_types) |param_type, i| {
|
||||
param_types[i] = try resolveType(mod, scope, param_type);
|
||||
const resolved = try resolveType(mod, scope, param_type);
|
||||
// TODO skip for comptime params
|
||||
if (!resolved.isValidVarType()) {
|
||||
return mod.fail(scope, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved});
|
||||
}
|
||||
param_types[i] = resolved;
|
||||
}
|
||||
|
||||
const payload = try arena.create(Type.Payload.Function);
|
||||
|
||||
@@ -543,6 +543,38 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
,
|
||||
"",
|
||||
);
|
||||
|
||||
case.addCompareOutput(
|
||||
\\export fn _start() noreturn {
|
||||
\\ const ignore =
|
||||
\\ \\ cool thx
|
||||
\\ \\
|
||||
\\ ;
|
||||
\\ add('ぁ', '\x03');
|
||||
\\
|
||||
\\ exit();
|
||||
\\}
|
||||
\\
|
||||
\\fn add(a: u32, b: u32) void {
|
||||
\\ assert(a + b == 12356);
|
||||
\\}
|
||||
\\
|
||||
\\pub fn assert(ok: bool) void {
|
||||
\\ if (!ok) unreachable; // assertion failure
|
||||
\\}
|
||||
\\
|
||||
\\fn exit() noreturn {
|
||||
\\ asm volatile ("syscall"
|
||||
\\ :
|
||||
\\ : [number] "{rax}" (231),
|
||||
\\ [arg1] "{rdi}" (0)
|
||||
\\ : "rcx", "r11", "memory"
|
||||
\\ );
|
||||
\\ unreachable;
|
||||
\\}
|
||||
,
|
||||
"",
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user