authorchloe caruso <git@paperclover.net> 2024-05-25 17:53:36-07:00
committerchloe caruso <git@paperclover.net> 2024-05-25 17:53:36-07:00
log91ee439c7b9f751d6bceaa26282cfdd0b3cdc6ca
treecb69168284b422a4d88568479c0b8898b5e096b3
parent974964a59da977061f958f51c142256ece5f30ea

introduce InstOp, making it possible to point report items at Teg.Inst


10 files changed, 342 insertions(+), 106 deletions(-)

demo.ix created+1
...@@ -0,0 +1 @@
1let x: int = 1.5;
demo.wl deleted-1
...@@ -1 +0,0 @@
1let x: int = 1.5;
src/compiler/Air.Dump.zig+2-2
...@@ -157,14 +157,14 @@ pub const State = struct {...@@ -157,14 +157,14 @@ pub const State = struct {
157157
158 fn dumpRef(s: *State, w: anytype, ref: Inst.Ref) !void {158 fn dumpRef(s: *State, w: anytype, ref: Inst.Ref) !void {
159 switch (ref.decode()) {159 switch (ref.decode()) {
160 .inst => |i| try s.dumpInstRef(w, i),160 .index => |i| try s.dumpInstRef(w, i),
161 .value => |v| try s.dumpValue(w, v),161 .value => |v| try s.dumpValue(w, v),
162 }162 }
163 }163 }
164164
165 fn dumpRefRecurse(s: *State, w: anytype, ref: Inst.Ref) !void {165 fn dumpRefRecurse(s: *State, w: anytype, ref: Inst.Ref) !void {
166 switch (ref.decode()) {166 switch (ref.decode()) {
167 .inst => |i| try s.dumpInst(w, i),167 .index => |i| try s.dumpInst(w, i),
168 .value => |v| try s.dumpValue(w, v),168 .value => |v| try s.dumpValue(w, v),
169 }169 }
170 }170 }
src/compiler/Air.zig+5-5
...@@ -68,17 +68,17 @@ pub const Inst = struct {...@@ -68,17 +68,17 @@ pub const Inst = struct {
68 kind: Kind,68 kind: Kind,
69 data: u31,69 data: u31,
7070
71 pub const Kind = enum(u1) { value, inst };71 pub const Kind = enum(u1) { value, index };
7272
73 pub const Decoded = union(enum) {73 pub const Decoded = union(enum) {
74 value: Value,74 value: Value,
75 inst: Index,75 index: Index,
76 };76 };
7777
78 pub fn decode(ref: Ref) Decoded {78 pub fn decode(ref: Ref) Decoded {
79 return switch (ref.kind) {79 return switch (ref.kind) {
80 .value => .{ .value = @enumFromInt(ref.data) },80 .value => .{ .value = @enumFromInt(ref.data) },
81 .inst => .{ .inst = @enumFromInt(ref.data) },81 .index => .{ .index = @enumFromInt(ref.data) },
82 };82 };
83 }83 }
8484
...@@ -113,7 +113,7 @@ pub const Inst = struct {...@@ -113,7 +113,7 @@ pub const Inst = struct {
113113
114 pub fn toRef(index: Index) Ref {114 pub fn toRef(index: Index) Ref {
115 return .{115 return .{
116 .kind = .inst,116 .kind = .index,
117 .data = @intCast(@intFromEnum(index)),117 .data = @intCast(@intFromEnum(index)),
118 };118 };
119 }119 }
...@@ -252,7 +252,7 @@ pub fn instPayload(air: *const Air, comptime tag: Inst.Tag, index: Inst.Index) t...@@ -252,7 +252,7 @@ pub fn instPayload(air: *const Air, comptime tag: Inst.Tag, index: Inst.Index) t
252pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *InternPool) InternPool.Type {252pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *InternPool) InternPool.Type {
253 return switch (ref.decode()) {253 return switch (ref.decode()) {
254 .value => |v| v.typeOf(ip),254 .value => |v| v.typeOf(ip),
255 .inst => |i| air.typeOfIndex(i, ip),255 .index => |i| air.typeOfIndex(i, ip),
256 };256 };
257}257}
258258
src/compiler/Ast.zig+85
...@@ -520,6 +520,91 @@ pub fn nodeToken(ast: Ast, node: NodeIndex) TokenIndex {...@@ -520,6 +520,91 @@ pub fn nodeToken(ast: Ast, node: NodeIndex) TokenIndex {
520 return ast.nodes.items(.main_token)[node];520 return ast.nodes.items(.main_token)[node];
521}521}
522522
523// pub fn operandNode(ast: Ast, node: NodeIndex, operand: OperandId) NodeIndex {
524// if (operand == .main_node) return node;
525
526// switch (ast.nodeTag(node)) {
527// .root => unreachable,
528// .block_void => unreachable,
529// .block_implicit_return => unreachable,
530// .var_decl,
531// => return switch (operand) {
532// .type => ast.nodeData(node).var_decl.type.unwrap().?,
533// .initializer => ast.nodeData(node).var_decl.init,
534// else => unreachable,
535// },
536
537// .label,
538// .group,
539// .negate,
540// .bit_not,
541// .bool_not,
542// .@"comptime",
543// => return switch (operand) {
544// .base => ast.nodeData(node).un.expr,
545// else => unreachable, // Invalid unary operand
546// },
547
548// .add,
549// .sub,
550// .mul,
551// .div,
552// .rem,
553// .pow,
554// .@"and",
555// .@"or",
556// .bit_and,
557// .bit_or,
558// .bit_xor,
559// .shl,
560// .shr,
561// .eq,
562// .ne,
563// .lt,
564// .le,
565// .gt,
566// .ge,
567// .assign,
568// .add_assign,
569// .sub_assign,
570// .mul_assign,
571// .div_assign,
572// .rem_assign,
573// .pow_assign,
574// .and_assign,
575// .or_assign,
576// .bit_and_assign,
577// .bit_or_assign,
578// .bit_xor_assign,
579// .shl_assign,
580// .shr_assign,
581// => {
582// const bin = ast.nodeData(node).bin;
583// return switch (operand) {
584// .lhs => bin.lhs,
585// .rhs => bin.rhs,
586// else => unreachable, // Not a valid operand for binary node
587// };
588// },
589
590// .fn_decl,
591// .param_decl,
592// .id,
593// .number_int,
594// .number_float,
595// .string,
596// .multiline_string,
597// .call,
598// .builtin_call,
599// .@"if",
600// .field,
601// .index,
602// .@"return",
603// .@"break",
604// => |tag| std.debug.panic("TODO: operandNode .{s}", .{@tagName(tag)}),
605// }
606// }
607
523pub fn fullFnDecl(ast: Ast, node: NodeIndex) full.FnDecl {608pub fn fullFnDecl(ast: Ast, node: NodeIndex) full.FnDecl {
524 const tok_tags = ast.tokens.items(.tag);609 const tok_tags = ast.tokens.items(.tag);
525610
src/compiler/JsNodeGen.zig+6-6
...@@ -185,8 +185,8 @@ fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void {...@@ -185,8 +185,8 @@ fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void {
185185
186 const target = try c.fetchInstExpression(data.memory);186 const target = try c.fetchInstExpression(data.memory);
187187
188 if (data.operand.kind == .inst) {188 if (data.operand.kind == .index) {
189 const index = data.operand.decode().inst;189 const index = data.operand.decode().index;
190 switch (c.air.instTag(index)) {190 switch (c.air.instTag(index)) {
191 inline .add,191 inline .add,
192 .sub,192 .sub,
...@@ -418,7 +418,7 @@ fn fetchExpression(c: *JsNodeGen, ref: Air.Inst.Ref) !Node.Index {...@@ -418,7 +418,7 @@ fn fetchExpression(c: *JsNodeGen, ref: Air.Inst.Ref) !Node.Index {
418418
419 return switch (ref.decode()) {419 return switch (ref.decode()) {
420 .value => |v| c.valueToExpression(v),420 .value => |v| c.valueToExpression(v),
421 .inst => |index| fetchInstExpression(c, index),421 .index => |index| fetchInstExpression(c, index),
422 };422 };
423}423}
424424
...@@ -509,7 +509,7 @@ fn codeGenBranch(c: *JsNodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Br...@@ -509,7 +509,7 @@ fn codeGenBranch(c: *JsNodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Br
509 }509 }
510 break :items c.scratch.items[scratch_top..];510 break :items c.scratch.items[scratch_top..];
511 },511 },
512 .inst => |i| items: {512 .index => |i| items: {
513 assert(c.air.instTag(i) == .block);513 assert(c.air.instTag(i) == .block);
514 c.air_node_map[@intFromEnum(i)] = .{514 c.air_node_map[@intFromEnum(i)] = .{
515 .block = .{ .index = @intCast(scratch_top) },515 .block = .{ .index = @intCast(scratch_top) },
...@@ -600,7 +600,7 @@ fn canLowerToExpression(c: *const JsNodeGen, inst: Air.Inst.Ref) bool {...@@ -600,7 +600,7 @@ fn canLowerToExpression(c: *const JsNodeGen, inst: Air.Inst.Ref) bool {
600600
601 return switch (inst.decode()) {601 return switch (inst.decode()) {
602 .value => true,602 .value => true,
603 .inst => |index| switch (c.air.instTag(index)) {603 .index => |index| switch (c.air.instTag(index)) {
604 .js_global_ref,604 .js_global_ref,
605 .call,605 .call,
606 .arg,606 .arg,
...@@ -651,7 +651,7 @@ fn lowerToExpression(c: *JsNodeGen, ref: Air.Inst.Ref) !Node.Index {...@@ -651,7 +651,7 @@ fn lowerToExpression(c: *JsNodeGen, ref: Air.Inst.Ref) !Node.Index {
651 assert(c.canLowerToExpression(ref));651 assert(c.canLowerToExpression(ref));
652 return switch (ref.decode()) {652 return switch (ref.decode()) {
653 .value => |v| try c.valueToExpression(v),653 .value => |v| try c.valueToExpression(v),
654 .inst => |index| {654 .index => |index| {
655 try c.codeGenInst(index);655 try c.codeGenInst(index);
656 return c.fetchExpression(ref);656 return c.fetchExpression(ref);
657 },657 },
src/compiler/Report.zig+62-2
...@@ -142,6 +142,16 @@ pub const Err = union(enum) {...@@ -142,6 +142,16 @@ pub const Err = union(enum) {
142 try ctx.msgNode(node, "numeric literal \"{d}\" cannot be coerced to \"int\"", .{data.val});142 try ctx.msgNode(node, "numeric literal \"{d}\" cannot be coerced to \"int\"", .{data.val});
143 }143 }
144 },144 },
145 coersion: struct {
146 from: Type,
147 to: Type,
148 src: LazyNode,
149
150 fn build(data: @This(), ctx: *MsgContext) !void {
151 const node = try data.src.get(ctx);
152 try ctx.msgNode(node, "stinky", .{});
153 }
154 },
145};155};
146156
147pub const Warn = union(enum) {157pub const Warn = union(enum) {
...@@ -614,7 +624,8 @@ pub const MsgContext = struct {...@@ -614,7 +624,8 @@ pub const MsgContext = struct {
614624
615pub const LazyNode = struct {625pub const LazyNode = struct {
616 decl: Comp.Decl.Index,626 decl: Comp.Decl.Index,
617 node_offset: i32,627 inst: Teg.Inst.Index,
628 operand: Operand,
618629
619 pub fn get(lazy: LazyNode, ctx: *MsgContext) !NodeIndex {630 pub fn get(lazy: LazyNode, ctx: *MsgContext) !NodeIndex {
620 const decl = ctx.comp.intern_pool.declPtrConst(lazy.decl);631 const decl = ctx.comp.intern_pool.declPtrConst(lazy.decl);
...@@ -640,7 +651,50 @@ pub const LazyNode = struct {...@@ -640,7 +651,50 @@ pub const LazyNode = struct {
640651
641 const teg_decl = teg.instData(.declaration, decl_inst.resolve(&ctx.comp.intern_pool));652 const teg_decl = teg.instData(.declaration, decl_inst.resolve(&ctx.comp.intern_pool));
642653
643 return @intCast(teg_decl.src_node - lazy.node_offset);654 const node_offset = teg.instNodeOffset(lazy.inst);
655
656 const base_node: NodeIndex = @intCast(node_offset - teg_decl.src_node);
657 if (lazy.operand == .main_node)
658 return base_node;
659
660 const data = ctx.ast.nodeData(base_node);
661
662 switch (teg.instTag(lazy.inst)) {
663 .as => switch (ctx.ast.nodeTag(base_node)) {
664 .var_decl => {
665 switch (lazy.operand) {
666 .rhs => return data.var_decl.init,
667 else => {},
668 }
669 },
670 else => {},
671 },
672 else => {},
673 }
674
675 if (!std.debug.runtime_safety) unreachable;
676
677 std.debug.panic("TODO: operand lookup: .{s} + .{s} + {}", .{
678 @tagName(teg.instTag(lazy.inst)),
679 @tagName(ctx.ast.nodeTag(base_node)),
680 lazy.operand,
681 });
682 }
683};
684
685pub const Operand = enum(u32) {
686 /// Point to the main node of an instruction
687 main_node = 0,
688 /// Base of a call, field, or operand to a unary instruction
689 operand = 1,
690 /// Left hand side of a binary instruction
691 lhs,
692 /// Right hand side of a binary instruction
693 rhs,
694
695 /// An argument of a call node
696 pub fn argument(id: u32) Operand {
697 return @enumFromInt(id + 2);
644 }698 }
645};699};
646700
...@@ -660,7 +714,13 @@ const TokenIndex = Ast.TokenIndex;...@@ -660,7 +714,13 @@ const TokenIndex = Ast.TokenIndex;
660const NodeIndex = Ast.NodeIndex;714const NodeIndex = Ast.NodeIndex;
661const Location = Ast.Location;715const Location = Ast.Location;
662716
717const Teg = @import("Teg.zig");
718
663const Comp = @import("Comp.zig");719const Comp = @import("Comp.zig");
664const File = Comp.File;720const File = Comp.File;
665721
722const InternPool = @import("InternPool.zig");
723const Value = InternPool.Value;
724const Type = InternPool.Type;
725
666const util = @import("util.zig");726const util = @import("util.zig");
src/compiler/Sema.zig+155-77
...@@ -64,7 +64,7 @@ const InstMap = struct {...@@ -64,7 +64,7 @@ const InstMap = struct {
64 if (assertWithMessage(map.get(from) == null)) {64 if (assertWithMessage(map.get(from) == null)) {
65 std.debug.panic("%{d} is already mapped (to #{d})", .{65 std.debug.panic("%{d} is already mapped (to #{d})", .{
66 @intFromEnum(from),66 @intFromEnum(from),
67 @intFromEnum(map.get(from).?.decode().inst),67 @intFromEnum(map.get(from).?.decode().index),
68 });68 });
69 }69 }
70 const source_i = @intFromEnum(from);70 const source_i = @intFromEnum(from);
...@@ -330,7 +330,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -330,7 +330,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
330 .@"break" => {330 .@"break" => {
331 const brk: Teg.Inst.Break = s.code.instPayload(.@"break", in);331 const brk: Teg.Inst.Break = s.code.instPayload(.@"break", in);
332 const operand = try s.resolveRefRuntime(brk.operand);332 const operand = try s.resolveRefRuntime(brk.operand);
333 const block_ref = s.inst_map.get(brk.block).?.decode().inst; // block ref is resolved by teg333 const block_ref = s.inst_map.get(brk.block).?.decode().index; // block ref is resolved by teg
334 return s.addInstRef(.@"break", .{334 return s.addInstRef(.@"break", .{
335 .block_ref = block_ref,335 .block_ref = block_ref,
336 .value = operand,336 .value = operand,
...@@ -439,7 +439,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -439,7 +439,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
439 .block => {439 .block => {
440 const block = try s.analyzeBlock(in);440 const block = try s.analyzeBlock(in);
441 switch (block.decode()) {441 switch (block.decode()) {
442 .inst => |t| if (s.tempAir().instTag(t) == .block) {442 .index => |t| if (s.tempAir().instTag(t) == .block) {
443 try s.scratch.append(s.gpa, @intFromEnum(t));443 try s.scratch.append(s.gpa, @intFromEnum(t));
444 },444 },
445 else => {},445 else => {},
...@@ -455,7 +455,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -455,7 +455,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
455 .value => |v| switch (v.toKey(s.ip)) {455 .value => |v| switch (v.toKey(s.ip)) {
456 .comptime_float => |val| {456 .comptime_float => |val| {
457 try s.report.warn(.numeric_int_var_ambiguity, .{457 try s.report.warn(.numeric_int_var_ambiguity, .{
458 .node = s.nodeLoc(in),458 .node = s.nodeLoc(in, .operand),
459 });459 });
460 initial_value = (try s.makeValue(.{ .float = val })).toAir();460 initial_value = (try s.makeValue(.{ .float = val })).toAir();
461 },461 },
...@@ -473,7 +473,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -473,7 +473,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
473 const data: Teg.Inst.Store = s.code.instPayload(.store, in);473 const data: Teg.Inst.Store = s.code.instPayload(.store, in);
474 assert(s.code.instTag(data.memory) == .memory); // corrupt store instruction474 assert(s.code.instTag(data.memory) == .memory); // corrupt store instruction
475475
476 const location = s.mapTeg(data.memory.toRef()).decode().inst;476 const location = s.mapTeg(data.memory.toRef()).decode().index;
477 const operand = try s.resolveRefRuntime(data.operand);477 const operand = try s.resolveRefRuntime(data.operand);
478478
479 // try s.validateType(479 // try s.validateType(
...@@ -488,9 +488,9 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -488,9 +488,9 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
488 },488 },
489 .as => {489 .as => {
490 const as: Teg.Inst.As = s.code.instPayload(.as, in);490 const as: Teg.Inst.As = s.code.instPayload(.as, in);
491 const coerce_to = try s.resolveRefComptime(as.type);491 const coerce_to = try s.resolveRefComptimeType(in.op(.lhs) ,as.type, .type);
492 const operand = try s.resolveRefRuntime(as.operand);492 const operand = try s.resolveRefRuntime(as.operand);
493 return try s.coerceRef(in, operand, coerce_to.toType(s.ip).?);493 return try s.coerceRef(in.op(.rhs), operand, coerce_to.toType(s.ip).?);
494 },494 },
495 else => |tag| std.debug.panic("TODO: analyze of .{s}", .{@tagName(tag)}),495 else => |tag| std.debug.panic("TODO: analyze of .{s}", .{@tagName(tag)}),
496 }496 }
...@@ -516,8 +516,8 @@ fn analyzeRefToBlock(s: *Sema, in: Teg.Inst.Ref) anyerror!Air.Inst.Ref {...@@ -516,8 +516,8 @@ fn analyzeRefToBlock(s: *Sema, in: Teg.Inst.Ref) anyerror!Air.Inst.Ref {
516 return visited;516 return visited;
517 }517 }
518518
519 if (visited.kind == .inst and519 if (visited.kind == .index and
520 s.air_instructions.items(.tag)[@intFromEnum(visited.decode().inst)] == .block)520 s.air_instructions.items(.tag)[@intFromEnum(visited.decode().index)] == .block)
521 {521 {
522 return visited;522 return visited;
523 }523 }
...@@ -538,7 +538,7 @@ fn resolveRefRuntimeExtra(s: *Sema, ref: Teg.Inst.Ref, mark: bool) anyerror!Air....@@ -538,7 +538,7 @@ fn resolveRefRuntimeExtra(s: *Sema, ref: Teg.Inst.Ref, mark: bool) anyerror!Air.
538 if (s.inst_map.get(index)) |air| {538 if (s.inst_map.get(index)) |air| {
539 if (mark) {539 if (mark) {
540 switch (air.decode()) {540 switch (air.decode()) {
541 .inst => |i| s.markInst(i),541 .index => |i| s.markInst(i),
542 else => {},542 else => {},
543 }543 }
544 }544 }
...@@ -576,67 +576,130 @@ fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value {...@@ -576,67 +576,130 @@ fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value {
576}576}
577577
578/// Coerce `value` runtime ref to `coerce_type`, and emit an error at `teg_ref`'s location578/// Coerce `value` runtime ref to `coerce_type`, and emit an error at `teg_ref`'s location
579fn coerceRef(579fn coerceRef(s: *Sema, src: InstOp, value: Air.Inst.Ref, to: Type) !Air.Inst.Ref {
580 s: *Sema,580 const from = s.typeOfRef(value);
581 teg_ref: Teg.Inst.Index,581 if (from == to) {
582 value: Air.Inst.Ref,582 return value;
583 coerce_to: Type,583 }
584) !Air.Inst.Ref {584 const index = switch (value.decode()) {
585 _ = teg_ref;585 .value => |v| return (try s.coerceValue(src, v, to)).toAir(),
586 _ = s;586 .index => |index| index,
587 _ = value;587 };
588 _ = coerce_to;588 switch (to) {
589 // const value_type = s.typeOfRef(value);589 .@"opaque" => {
590 // switch (coerce_type.toKey(s.ip)) {590 //
591 // .simple_type => |simple_type| switch (simple_type) {591 },
592 // // .@"opaque",592 .bool => {
593 // .int32 => {593 //
594 // switch (value_type.toKey(s.ip)) {594 },
595 // .simple_type => switch (simple_type) {595 .int32 => switch (from) {
596 // // .int32 => return value,596 .int32 => unreachable, // same type handled
597 // // .numeric_literal => {597 .numeric_literal => unreachable, // must should comptime known
598 // // const val = value.decode().value.toKey(s.ip).comptime_float;598 else => {},
599 // // std.debug.print("buh {d}\n", .{val});599 },
600 // // if (!math.isFinite(val) or600 .float => switch (from) {
601 // // val < math.minInt(i32) or601 .float => unreachable, // same type handled
602 // // val > math.maxInt(i32))602 .int32 => return index.toRef(),
603 // // {603 else => {},
604 // // try s.fail(.comptime_float_to_int, .{604 },
605 // // .val = val,605 .string => {
606 // // .src = s.nodeLoc(teg_ref),606 //
607 // // });607 },
608 // // }608 .noreturn => {
609 // // return (try s.makeValue(.{ .int32 = @intFromFloat(val) })).toAir();609 //
610 // // },610 },
611 // else => |tag| std.debug.panic("TODO: coerceTo value_type simple_type .{s}", .{@tagName(tag)}),611 .type => {
612 // },612 //
613 // else => |tag| std.debug.panic("TODO: coerceTo value_type .{s}", .{@tagName(tag)}),613 },
614 // }614 .numeric_literal => {
615 // },615 @panic("TODO: error message for not known at compile time");
616 // // .float,616 },
617 // // .string,617 .void => {
618 // // .bool,618 //
619 // // .noreturn,619 },
620 // // .type,620 else => {},
621 // // .numeric_literal,621 }
622 // else => |tag| std.debug.panic("TODO: coerceTo coerce_type .simple_type = .{s}", .{@tagName(tag)}),622 return s.coersionError(src, from, to);
623 // },623}
624 // else => |tag| std.debug.panic("TODO: coerceTo coerce_type .{s}", .{@tagName(tag)}),624
625 // }625fn coerceValue(s: *Sema, src: InstOp, value: Value, to: Type) !Value {
626 @panic("TODO");626 const from = value.typeOf(s.ip);
627}627 if (from == to) {
628628 return value;
629fn coerceValue(629 }
630 s: *Sema,630 switch (to) {
631 teg_ref: Teg.Inst.Index,631 // .simple_type => |simple_type| switch (simple_type) {
632 value: Value,632 // // .@"opaque",
633 coerce_to: Type,633 // .int32 => {
634) !Value {634 // switch (value_type.toKey(s.ip)) {
635 _ = s;635 // .simple_type => switch (simple_type) {
636 _ = teg_ref;636 // // .int32 => return value,
637 _ = value;637 // // .numeric_literal => {
638 _ = coerce_to;638 // // const val = value.decode().value.toKey(s.ip).comptime_float;
639 @panic("TODO");639 // // },
640 // else => |tag| std.debug.panic("TODO: coerceTo value_type simple_type .{s}", .{@tagName(tag)}),
641 // },
642 // else => |tag| std.debug.panic("TODO: coerceTo value_type .{s}", .{@tagName(tag)}),
643 // }
644 // },
645 // // .float,
646 // // .string,
647 // // .bool,
648 // // .noreturn,
649 // // .type,
650 // // .numeric_literal,
651 // else => |tag| std.debug.panic("TODO: coerceTo coerce_type .simple_type = .{s}", .{@tagName(tag)}),
652 // },
653 // else => |tag| std.debug.panic("TODO: coerceTo coerce_type .{s}", .{@tagName(tag)}),
654 // }
655 .@"opaque" => {
656 //
657 },
658 .bool => {
659 //
660 },
661 .int32 => switch (from) {
662 .int32 => unreachable, // same type handled
663 .numeric_literal, .float => switch (value.toKey(s.ip)) {
664 .comptime_float, .float => |val| {
665 if (!math.isFinite(val) or
666 val < math.minInt(i32) or
667 val > math.maxInt(i32) or
668 (@rem(val, 1) != 0))
669 {
670 return s.fail(.comptime_float_to_int, .{
671 .val = val,
672 .src = s.lazyNode(src),
673 });
674 }
675
676 return try s.makeValue(.{
677 .int32 = @intFromFloat(val),
678 });
679 },
680 else => unreachable, // not a numeric literal
681 },
682 else => return s.coersionError(src, from, to),
683 },
684 .float => {
685 //
686 },
687 .string => {
688 //
689 },
690 .noreturn => {
691 //
692 },
693 .type => {
694 //
695 },
696 .numeric_literal => {},
697 .void => {
698 //
699 },
700 else => {},
701 }
702 return s.coersionError(src, from, to);
640}703}
641704
642fn resolveDecl(s: *Sema, decl_index: Decl.Index) !Value {705fn resolveDecl(s: *Sema, decl_index: Decl.Index) !Value {
...@@ -856,23 +919,35 @@ fn lookupDecl(s: *Sema, name: NullTerminatedString) ?InternPool.DeclIndex {...@@ -856,23 +919,35 @@ fn lookupDecl(s: *Sema, name: NullTerminatedString) ?InternPool.DeclIndex {
856 }919 }
857}920}
858921
859fn nodeLoc(s: *const Sema, in: Teg.Inst.Index) Report.LazyNode {922fn nodeLoc(s: *const Sema, in: Teg.Inst.Index, op: Report.Operand) Report.LazyNode {
860 return s.code.instSrcLoc(in, s.decl_index);923 return s.lazyNode(in.op(op));
861}924}
862925
863pub fn addWarn(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) !void {926fn addWarn(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) !void {
864 try s.report.warn(kind, data);927 try s.report.warn(kind, data);
865}928}
866929
867pub fn addError(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) !void {930fn addError(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) !void {
868 try s.report.err(kind, data);931 try s.report.err(kind, data);
869}932}
870933
871pub fn fail(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) Error!void {934fn fail(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) Error {
872 try s.report.err(kind, data);935 try s.report.err(kind, data);
873 return Error.AnalysisFail;936 return Error.AnalysisFail;
874}937}
875938
939fn coersionError(s: *Sema, src: InstOp, from: Type, to: Type) Error {
940 return s.fail(.coersion, .{
941 .from = from,
942 .to = to,
943 .src = s.lazyNode(src),
944 });
945}
946
947fn lazyNode(s: *const Sema, src: InstOp) Report.LazyNode {
948 return src.lazyNode( s.decl_index);
949}
950
876const Sema = @This();951const Sema = @This();
877952
878const std = @import("std");953const std = @import("std");
...@@ -895,9 +970,12 @@ const File = Comp.File;...@@ -895,9 +970,12 @@ const File = Comp.File;
895const Decl = Comp.Decl;970const Decl = Comp.Decl;
896const Namespace = Comp.Namespace;971const Namespace = Comp.Namespace;
897972
898const Air = @import("Air.zig");
899const Teg = @import("Teg.zig");973const Teg = @import("Teg.zig");
974const InstOp = Teg.InstOp;
975
976const Air = @import("Air.zig");
900const Report = @import("Report.zig");977const Report = @import("Report.zig");
978const Ast = @import("Ast.zig");
901const dod = @import("dod.zig");979const dod = @import("dod.zig");
902const tracer = @import("tracer");980const tracer = @import("tracer");
903981
src/compiler/Teg.Dump.zig+1-1
...@@ -23,7 +23,7 @@ const State = struct {...@@ -23,7 +23,7 @@ const State = struct {
23 const tag = s.teg.instTag(inst);23 const tag = s.teg.instTag(inst);
2424
25 try tty.setColor(writer, .bright_black);25 try tty.setColor(writer, .bright_black);
26 const node_offset = teg.instSrcLoc(inst, @enumFromInt(0)).node_offset;26 const node_offset = teg.instNodeOffset(inst);
27 try writer.print("{c}{d} ", .{27 try writer.print("{c}{d} ", .{
28 @as(u8, if (node_offset >= 0) '+' else '-'),28 @as(u8, if (node_offset >= 0) '+' else '-'),
29 @abs(node_offset),29 @abs(node_offset),
src/compiler/Teg.zig+25-12
...@@ -180,6 +180,10 @@ pub const Inst = struct {...@@ -180,6 +180,10 @@ pub const Inst = struct {
180 pub fn toOptional(i: Index) OptionalIndex {180 pub fn toOptional(i: Index) OptionalIndex {
181 return @enumFromInt(@intFromEnum(i));181 return @enumFromInt(@intFromEnum(i));
182 }182 }
183
184 pub fn op(i: Index, operand: Report.Operand) InstOp {
185 return .{ .index = i, .op = operand };
186 }
183 };187 };
184188
185 pub const OptionalIndex = enum(u32) {189 pub const OptionalIndex = enum(u32) {
...@@ -318,6 +322,19 @@ pub const Inst = struct {...@@ -318,6 +322,19 @@ pub const Inst = struct {
318 };322 };
319};323};
320324
325pub const InstOp = struct {
326 index: Inst.Index,
327 op: Report.Operand,
328
329 pub fn lazyNode(inst: InstOp, decl: Comp.Decl.Index) LazyNode {
330 return .{
331 .inst = inst.index,
332 .operand = inst.op,
333 .decl = decl,
334 };
335 }
336};
337
321pub const NullTerminatedString = enum(u32) {338pub const NullTerminatedString = enum(u32) {
322 empty = 0,339 empty = 0,
323 _,340 _,
...@@ -382,6 +399,14 @@ pub fn instPayload(teg: *const Teg, comptime tag: Inst.Tag, index: Inst.Index) t...@@ -382,6 +399,14 @@ pub fn instPayload(teg: *const Teg, comptime tag: Inst.Tag, index: Inst.Index) t
382 return teg.instData(tag, index).extra_index.get(teg);399 return teg.instData(tag, index).extra_index.get(teg);
383}400}
384401
402pub fn instNodeOffset(teg: *const Teg, index: Inst.Index) i32 {
403 switch (teg.instTag(index)) {
404 inline else => |tag| {
405 return teg.instData(tag, index).src_node;
406 },
407 }
408}
409
385pub fn blockInstructions(teg: *const Teg, index: Inst.Index) []const Inst.Index {410pub fn blockInstructions(teg: *const Teg, index: Inst.Index) []const Inst.Index {
386 return teg.instData(.block, index).extra_index.get(teg).slice(teg);411 return teg.instData(.block, index).extra_index.get(teg).slice(teg);
387}412}
...@@ -396,18 +421,6 @@ pub fn declData(teg: *const Teg, index: Inst.Index) Inst.Decl {...@@ -396,18 +421,6 @@ pub fn declData(teg: *const Teg, index: Inst.Index) Inst.Decl {
396 return teg.instData(.declaration, index).extra_index.get(teg);421 return teg.instData(.declaration, index).extra_index.get(teg);
397}422}
398423
399pub fn instSrcLoc(teg: *const Teg, inst: Inst.Index, decl: Comp.Decl.Index) LazyNode {
400 switch (teg.instTag(inst)) {
401 inline else => |tag| {
402 const data = teg.instData(tag, inst);
403 return .{
404 .node_offset = data.src_node,
405 .decl = decl,
406 };
407 },
408 }
409}
410
411pub fn moduleDeclarations(teg: *const Teg, module_index: Inst.Index) []const Inst.Index {424pub fn moduleDeclarations(teg: *const Teg, module_index: Inst.Index) []const Inst.Index {
412 const module = teg.instData(.module, module_index);425 const module = teg.instData(.module, module_index);
413 const module_data: IndexList = module.extra_index.get(teg);426 const module_data: IndexList = module.extra_index.get(teg);