9 files changed, 56 insertions(+), 25 deletions(-)
CHANGELOG.md+1| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | - fix: crash when analyzing an empty array without a result type | 16 | - fix: crash when analyzing an empty array without a result type |
| 17 | - fix: binary operands with float and float would not resolve | 17 | - fix: binary operands with float and float would not resolve |
| 18 | - fix: assertion false-positive when using an extern global more than once | 18 | - fix: assertion false-positive when using an extern global more than once |
| 19 | - fix: do not emit direct eval | ||
| 19 | 20 | ||
| 20 | ## 0.1.5 | 21 | ## 0.1.5 |
| 21 | 22 |
src/core/Air.Dump.zig+12| ... | @@ -249,6 +249,18 @@ pub const State = struct { | ... | @@ -249,6 +249,18 @@ pub const State = struct { |
| 249 | try w.writeAll(">"); | 249 | try w.writeAll(">"); |
| 250 | try tty.setColor(w, .reset); | 250 | try tty.setColor(w, .reset); |
| 251 | }, | 251 | }, |
| 252 | .opaque_value => |inner| { | ||
| 253 | try tty.setColor(w, .bright_black); | ||
| 254 | try w.writeAll("<"); | ||
| 255 | try tty.setColor(w, .blue); | ||
| 256 | try w.writeAll("opaque"); | ||
| 257 | try tty.setColor(w, .reset); | ||
| 258 | try tty.setColor(w, .bright_black); | ||
| 259 | try w.writeAll(", "); | ||
| 260 | try s.dumpValue(w, inner); | ||
| 261 | try w.writeAll(">"); | ||
| 262 | try tty.setColor(w, .reset); | ||
| 263 | }, | ||
| 252 | .string => |data| { | 264 | .string => |data| { |
| 253 | try w.writeAll("<"); | 265 | try w.writeAll("<"); |
| 254 | try tty.setColor(w, .blue); | 266 | try tty.setColor(w, .blue); |
src/core/InternPool.zig+10-1| ... | @@ -127,6 +127,8 @@ pub const Tag = enum(u8) { | ... | @@ -127,6 +127,8 @@ pub const Tag = enum(u8) { |
| 127 | array_value, | 127 | array_value, |
| 128 | /// An extern reference. For JS, this can be a property access | 128 | /// An extern reference. For JS, this can be a property access |
| 129 | external_value, | 129 | external_value, |
| 130 | /// A value masked as "opaque" type | ||
| 131 | opaque_value, | ||
| 130 | 132 | ||
| 131 | pub fn Data(comptime tag: Tag) type { | 133 | pub fn Data(comptime tag: Tag) type { |
| 132 | return switch (tag) { | 134 | return switch (tag) { |
| ... | @@ -135,6 +137,7 @@ pub const Tag = enum(u8) { | ... | @@ -135,6 +137,7 @@ pub const Tag = enum(u8) { |
| 135 | .simple_type => SimpleType, | 137 | .simple_type => SimpleType, |
| 136 | .simple_value => SimpleValue, | 138 | .simple_value => SimpleValue, |
| 137 | .int32 => i32, | 139 | .int32 => i32, |
| 140 | .opaque_value => Value, | ||
| 138 | 141 | ||
| 139 | else => ExtraIndex(tag.Payload()), | 142 | else => ExtraIndex(tag.Payload()), |
| 140 | }; | 143 | }; |
| ... | @@ -147,6 +150,7 @@ pub const Tag = enum(u8) { | ... | @@ -147,6 +150,7 @@ pub const Tag = enum(u8) { |
| 147 | .simple_type, | 150 | .simple_type, |
| 148 | .simple_value, | 151 | .simple_value, |
| 149 | .int32, | 152 | .int32, |
| 153 | .opaque_value, | ||
| 150 | => unreachable, // does not have a payload | 154 | => unreachable, // does not have a payload |
| 151 | .float, .comptime_float => Float, | 155 | .float, .comptime_float => Float, |
| 152 | .func => FuncDecl, | 156 | .func => FuncDecl, |
| ... | @@ -327,7 +331,7 @@ pub const Value = enum(u32) { | ... | @@ -327,7 +331,7 @@ pub const Value = enum(u32) { |
| 327 | .func => value.toKey(ip).func.ty, | 331 | .func => value.toKey(ip).func.ty, |
| 328 | .struct_value => value.toKey(ip).struct_value.ty, | 332 | .struct_value => value.toKey(ip).struct_value.ty, |
| 329 | .array_value => value.toKey(ip).array_value.type, | 333 | .array_value => value.toKey(ip).array_value.type, |
| 330 | .external_value => .@"opaque", | 334 | .external_value, .opaque_value => .@"opaque", |
| 331 | }; | 335 | }; |
| 332 | } | 336 | } |
| 333 | 337 | ||
| ... | @@ -871,6 +875,7 @@ pub const Key = union(enum) { | ... | @@ -871,6 +875,7 @@ pub const Key = union(enum) { |
| 871 | struct_value: StructValue, | 875 | struct_value: StructValue, |
| 872 | func: Func, | 876 | func: Func, |
| 873 | array_value: ArrayValue, | 877 | array_value: ArrayValue, |
| 878 | opaque_value: Value, | ||
| 874 | // Types | 879 | // Types |
| 875 | simple_type: SimpleType, | 880 | simple_type: SimpleType, |
| 876 | function_type: FunctionType, | 881 | function_type: FunctionType, |
| ... | @@ -991,6 +996,7 @@ pub const Key = union(enum) { | ... | @@ -991,6 +996,7 @@ pub const Key = union(enum) { |
| 991 | inline .int32, | 996 | inline .int32, |
| 992 | .simple_value, | 997 | .simple_value, |
| 993 | .simple_type, | 998 | .simple_type, |
| 999 | .opaque_value, | ||
| 994 | => |x| Hash.hash(seed, asBytes(&x)), | 1000 | => |x| Hash.hash(seed, asBytes(&x)), |
| 995 | .string, | 1001 | .string, |
| 996 | => |x| Hash.hash(seed, x), | 1002 | => |x| Hash.hash(seed, x), |
| ... | @@ -1023,6 +1029,7 @@ pub const Key = union(enum) { | ... | @@ -1023,6 +1029,7 @@ pub const Key = union(enum) { |
| 1023 | inline .int32, | 1029 | inline .int32, |
| 1024 | .simple_value, | 1030 | .simple_value, |
| 1025 | .simple_type, | 1031 | .simple_type, |
| 1032 | .opaque_value, | ||
| 1026 | => |x, tag| x == @field(b, @tagName(tag)), | 1033 | => |x, tag| x == @field(b, @tagName(tag)), |
| 1027 | .string, | 1034 | .string, |
| 1028 | => |x| std.mem.eql(u8, x, b.string), | 1035 | => |x| std.mem.eql(u8, x, b.string), |
| ... | @@ -1272,6 +1279,7 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key { | ... | @@ -1272,6 +1279,7 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key { |
| 1272 | 1279 | ||
| 1273 | .simple_type => .{ .simple_type = data.decode(.simple_type, item.tag) }, | 1280 | .simple_type => .{ .simple_type = data.decode(.simple_type, item.tag) }, |
| 1274 | .simple_value => .{ .simple_value = data.decode(.simple_value, item.tag) }, | 1281 | .simple_value => .{ .simple_value = data.decode(.simple_value, item.tag) }, |
| 1282 | .opaque_value => .{ .opaque_value = data.decode(.opaque_value, item.tag) }, | ||
| 1275 | .int32 => .{ .int32 = data.decode(.int32, item.tag) }, | 1283 | .int32 => .{ .int32 = data.decode(.int32, item.tag) }, |
| 1276 | .float => .{ .float = data.decode(.float, item.tag).get(ip).decode() }, | 1284 | .float => .{ .float = data.decode(.float, item.tag).get(ip).decode() }, |
| 1277 | .comptime_float => .{ | 1285 | .comptime_float => .{ |
| ... | @@ -1350,6 +1358,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value { | ... | @@ -1350,6 +1358,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value { |
| 1350 | inline .int32, | 1358 | inline .int32, |
| 1351 | .simple_type, | 1359 | .simple_type, |
| 1352 | .simple_value, | 1360 | .simple_value, |
| 1361 | .opaque_value, | ||
| 1353 | => |s, tag| Item.encode(@field(Tag, @tagName(tag)), s), | 1362 | => |s, tag| Item.encode(@field(Tag, @tagName(tag)), s), |
| 1354 | .string => |s| Item.encode( | 1363 | .string => |s| Item.encode( |
| 1355 | .string, | 1364 | .string, |
src/core/Report.zig+5-13| ... | @@ -1202,19 +1202,11 @@ pub const LazyNode = struct { | ... | @@ -1202,19 +1202,11 @@ pub const LazyNode = struct { |
| 1202 | else => {}, | 1202 | else => {}, |
| 1203 | } | 1203 | } |
| 1204 | 1204 | ||
| 1205 | if (builtin.mode == .Debug) { | 1205 | std.debug.print("TODO: operand lookup: .{s} + .{s} + {}\n", .{ |
| 1206 | std.debug.panic("TODO: operand lookup: .{s} + .{s} + {}", .{ | 1206 | @tagName(teg.instTag(lazy.inst)), |
| 1207 | @tagName(teg.instTag(lazy.inst)), | 1207 | @tagName(ctx.ast.nodeTag(base_node)), |
| 1208 | @tagName(ctx.ast.nodeTag(base_node)), | 1208 | lazy.operand, |
| 1209 | lazy.operand, | 1209 | }); |
| 1210 | }); | ||
| 1211 | } else { | ||
| 1212 | std.debug.print("TODO: operand lookup: .{s} + .{s} + {}", .{ | ||
| 1213 | @tagName(teg.instTag(lazy.inst)), | ||
| 1214 | @tagName(ctx.ast.nodeTag(base_node)), | ||
| 1215 | lazy.operand, | ||
| 1216 | }); | ||
| 1217 | } | ||
| 1218 | 1210 | ||
| 1219 | return base_node; | 1211 | return base_node; |
| 1220 | } | 1212 | } |
src/core/Sema.zig+1-1| ... | @@ -1548,7 +1548,7 @@ fn coerceValue(s: *Sema, src: LazyNode, value: Value, to: Type) Error!Value { | ... | @@ -1548,7 +1548,7 @@ fn coerceValue(s: *Sema, src: LazyNode, value: Value, to: Type) Error!Value { |
| 1548 | } | 1548 | } |
| 1549 | switch (to) { | 1549 | switch (to) { |
| 1550 | .@"opaque" => { | 1550 | .@"opaque" => { |
| 1551 | // TODO: | 1551 | return try s.makeValue(.{ .opaque_value = value }); |
| 1552 | }, | 1552 | }, |
| 1553 | .bool => { | 1553 | .bool => { |
| 1554 | // TODO: | 1554 | // TODO: |
src/core/Transform.zig+1| ... | @@ -366,6 +366,7 @@ const built_in_ids = std.StaticStringMap(Inst.Ref).initComptime(.{ | ... | @@ -366,6 +366,7 @@ const built_in_ids = std.StaticStringMap(Inst.Ref).initComptime(.{ |
| 366 | .{ "int", .int32_type }, | 366 | .{ "int", .int32_type }, |
| 367 | .{ "float", .float_type }, | 367 | .{ "float", .float_type }, |
| 368 | .{ "string", .string_type }, | 368 | .{ "string", .string_type }, |
| 369 | .{ "opaque", .opaque_type }, | ||
| 369 | // .{ "bigint", .bigint_type }, | 370 | // .{ "bigint", .bigint_type }, |
| 370 | .{ "bool", .bool_type }, | 371 | .{ "bool", .bool_type }, |
| 371 | .{ "never", .never_type }, | 372 | .{ "never", .never_type }, |
src/core/js/Link.zig+12-1| ... | @@ -482,7 +482,18 @@ fn printExprLevel( | ... | @@ -482,7 +482,18 @@ fn printExprLevel( |
| 482 | const call: Tree.Call = tree.nodeData(.call, node); | 482 | const call: Tree.Call = tree.nodeData(.call, node); |
| 483 | const args = call.args.get(tree); | 483 | const args = call.args.get(tree); |
| 484 | 484 | ||
| 485 | try link.printExpr(tree, call.base, writer); | 485 | if (tree.nodeTag(call.base) == .plain_value and brk: { |
| 486 | const k = tree.nodeData(.plain_value, call.base).value.toKey(&link.comp.intern_pool); | ||
| 487 | break :brk k == .external_value and | ||
| 488 | k.external_value.key.len == 1 and | ||
| 489 | std.mem.eql(u8, k.external_value.key[0].toSlice(&link.comp.intern_pool), "eval"); | ||
| 490 | }) { | ||
| 491 | @branchHint(.unlikely); | ||
| 492 | try writer.writeAll("(0, eval)"); | ||
| 493 | } else { | ||
| 494 | try link.printExpr(tree, call.base, writer); | ||
| 495 | } | ||
| 496 | |||
| 486 | try writer.writeAll("("); | 497 | try writer.writeAll("("); |
| 487 | 498 | ||
| 488 | for (args.slice(tree), 0..) |arg, i| { | 499 | for (args.slice(tree), 0..) |arg, i| { |
src/core/js/NodeGen.zig+8-9| ... | @@ -137,14 +137,6 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void { | ... | @@ -137,14 +137,6 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void { |
| 137 | 137 | ||
| 138 | .block => try c.codeGenBlock(inst), | 138 | .block => try c.codeGenBlock(inst), |
| 139 | 139 | ||
| 140 | // .js_global_ref => { | ||
| 141 | // const data: InternPool.String.WithLen = c.air.instData(.js_global_ref, inst); | ||
| 142 | // try c.extern_symbols.put(c.gpa, data, {}); | ||
| 143 | // c.air_node_map[@intFromEnum(inst)] = .{ | ||
| 144 | // .node = try c.add(.global, .{ .name = data }), | ||
| 145 | // }; | ||
| 146 | // }, | ||
| 147 | |||
| 148 | .memory => { | 140 | .memory => { |
| 149 | const i = @intFromEnum(inst); | 141 | const i = @intFromEnum(inst); |
| 150 | const data: Air.Memory = c.air.instData(.memory, inst); | 142 | const data: Air.Memory = c.air.instData(.memory, inst); |
| ... | @@ -574,9 +566,16 @@ fn valueToExpression(c: *NodeGen, v: Value) !Node.Index { | ... | @@ -574,9 +566,16 @@ fn valueToExpression(c: *NodeGen, v: Value) !Node.Index { |
| 574 | .simple_value, | 566 | .simple_value, |
| 575 | .struct_value, | 567 | .struct_value, |
| 576 | .array_value, | 568 | .array_value, |
| 577 | .external_value, | ||
| 578 | => return try c.add(.plain_value, .{ .value = v }), | 569 | => return try c.add(.plain_value, .{ .value = v }), |
| 579 | 570 | ||
| 571 | .external_value => { | ||
| 572 | const external = v.toKey(c.ip).external_value; | ||
| 573 | try c.extern_symbols.put(c.gpa, external.key[0].toString().withLen(external.key[0].length(c.ip)), {}); | ||
| 574 | return try c.add(.plain_value, .{ .value = v }); | ||
| 575 | }, | ||
| 576 | |||
| 577 | .opaque_value => return c.valueToExpression(v.toKey(c.ip).opaque_value), | ||
| 578 | |||
| 580 | // Hoist functions as top level values | 579 | // Hoist functions as top level values |
| 581 | // TODO: Consider hoisting large values too | 580 | // TODO: Consider hoisting large values too |
| 582 | .func => { | 581 | .func => { |
test/behavior/direct_eval created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | let eval = @extern("eval"); | ||
| 2 | |||
| 3 | fn main { | ||
| 4 | eval("var x = 1"); | ||
| 5 | eval("if (globalThis.x != 1) throw new Error('Emitted as direct eval');"); | ||
| 6 | } | ||