this ends up regressing a lot of the compiler's ability to work,
but i have found many many many cases where a comptime value
should have only ever been a type, but we previously allowed
any value. also a revelation that `validateType` is not going
to cut it- we need to have a Teg ref for any type validation,
and it should be a *coersion*. the difference is these new
coersion functions return !Value or !Air.Inst.Ref instead of
just a !void (error being a coersion error)20 files changed, 683 insertions(+), 416 deletions(-)
README.md+6-6| ... | @@ -46,7 +46,7 @@ let hello = hello * world; | ... | @@ -46,7 +46,7 @@ let hello = hello * world; |
| 46 | @js("console").log(hello); | 46 | @js("console").log(hello); |
| 47 | ``` | 47 | ``` |
| 48 | 48 | ||
| 49 | `var` bindings create mutable memory locations at runtime. This means they can be re-assigned to in arbitrary ways. | 49 | `var` bindings create mutable memory locations at runtime. This means they can be re-assigned to: |
| 50 | 50 | ||
| 51 | ``` | 51 | ``` |
| 52 | var message = "first message"; | 52 | var message = "first message"; |
| ... | @@ -58,7 +58,7 @@ if @js("Math").random() > 0.5 { | ... | @@ -58,7 +58,7 @@ if @js("Math").random() > 0.5 { |
| 58 | @js("console").log(message); | 58 | @js("console").log(message); |
| 59 | ``` | 59 | ``` |
| 60 | 60 | ||
| 61 | `let` is preferred whenever possible, as it will lead to more readable code, and the compiler is able to optimize it better. The above can be rewritten as: | 61 | Using `let` is preferred whenever possible, as it will lead to more readable code, and the compiler is able to optimize it better. The above can be rewritten as: |
| 62 | 62 | ||
| 63 | ``` | 63 | ``` |
| 64 | let message = if @js("Math").random() > 0.5 { | 64 | let message = if @js("Math").random() > 0.5 { |
| ... | @@ -70,10 +70,10 @@ let message = if @js("Math").random() > 0.5 { | ... | @@ -70,10 +70,10 @@ let message = if @js("Math").random() > 0.5 { |
| 70 | @js("console").log(message); | 70 | @js("console").log(message); |
| 71 | ``` | 71 | ``` |
| 72 | 72 | ||
| 73 | The initializer for a `let` and `var` are always required, but the type annotations can be omitted when the data type can be inferred. For `let`, this is always the case. `var`, being runtime-mutable memory, only supports runtime representable data types. This means for numerical literals, an explicit type annotation is needed to determine weather to store an integer or a floating point number. | 73 | It should be noted that numeric literals are a comptime-only data type, meaning it cannot be assigned to a `var` without an explicit type annotation. Since `int` is a strict subset of valid `float`s, the coersion will implicitly be a float, but a compiler warning will be emitted. |
| 74 | 74 | ||
| 75 | ``` | 75 | ``` |
| 76 | var a = 5; // error | 76 | var number = 0; // `number` is a `float`, but not explicit |
| 77 | var b: int = 5; // ok | 77 | var number: int = 0; // `number` is `int` |
| 78 | var c: float = 5; // ok | 78 | var number: float = 0; // `number` is `float` |
| 79 | ``` | 79 | ``` |
demo.wl created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | let x: int = 1.5; | ||
notes created+19| ... | @@ -0,0 +1,19 @@ | ||
| 1 | 0.1.2 | ||
| 2 | - teg: useless discard | ||
| 3 | - teg: dangling identifier | ||
| 4 | - teg: remove `let _ = ` error | ||
| 5 | - sema: .as instruction | ||
| 6 | - sema: binary op type resolution (float + num_literal -> float) | ||
| 7 | 0.1.3 | ||
| 8 | - parse/teg/sema: implement the comptime keyword | ||
| 9 | - implement all the binary operators | ||
| 10 | - implement all the unary operators | ||
| 11 | - implement string escapes | ||
| 12 | - implement proper float printing | ||
| 13 | - js/link: add parenthesis when needed | ||
| 14 | 0.1.4 | ||
| 15 | - parse: impl module, struct define, struct init, defer, and optionals | ||
| 16 | - teg: impl the above, except anonymous struct initializers | ||
| 17 | - sema: implement some built-in functions on floats | ||
| 18 | - float.intTruncate() to perform lossy int conversion | ||
| 19 | |||
src/compiler/Air.Dump.zig+9-10| ... | @@ -2,7 +2,7 @@ | ... | @@ -2,7 +2,7 @@ |
| 2 | air: Air, | 2 | air: Air, |
| 3 | ip: *const InternPool, | 3 | ip: *const InternPool, |
| 4 | 4 | ||
| 5 | const State = struct { | 5 | pub const State = struct { |
| 6 | arena: std.mem.Allocator, | 6 | arena: std.mem.Allocator, |
| 7 | air: *const Air, | 7 | air: *const Air, |
| 8 | ip: *const InternPool, | 8 | ip: *const InternPool, |
| ... | @@ -67,7 +67,7 @@ const State = struct { | ... | @@ -67,7 +67,7 @@ const State = struct { |
| 67 | try w.print("{d}", .{arg.arg_number}); | 67 | try w.print("{d}", .{arg.arg_number}); |
| 68 | try tty.setColor(w, .reset); | 68 | try tty.setColor(w, .reset); |
| 69 | try w.writeAll(": "); | 69 | try w.writeAll(": "); |
| 70 | try s.dumpValue(w, arg.type); | 70 | try s.dumpValue(w, arg.type.value()); |
| 71 | }, | 71 | }, |
| 72 | .@"break" => { | 72 | .@"break" => { |
| 73 | const brk: Air.Break = air.instData(.@"break", inst); | 73 | const brk: Air.Break = air.instData(.@"break", inst); |
| ... | @@ -113,7 +113,7 @@ const State = struct { | ... | @@ -113,7 +113,7 @@ const State = struct { |
| 113 | try w.writeAll("("); | 113 | try w.writeAll("("); |
| 114 | try s.dumpRef(w, memory.init); | 114 | try s.dumpRef(w, memory.init); |
| 115 | try w.writeAll(", type: "); | 115 | try w.writeAll(", type: "); |
| 116 | try s.dumpValue(w, memory.ty); | 116 | try s.dumpValue(w, memory.ty.value()); |
| 117 | try w.writeAll(")"); | 117 | try w.writeAll(")"); |
| 118 | }, | 118 | }, |
| 119 | .field => { | 119 | .field => { |
| ... | @@ -175,7 +175,7 @@ const State = struct { | ... | @@ -175,7 +175,7 @@ const State = struct { |
| 175 | try s.tty.setColor(w, .reset); | 175 | try s.tty.setColor(w, .reset); |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | fn dumpValue(s: *State, w: anytype, val: Value) !void { | 178 | pub fn dumpValue(s: *State, w: anytype, val: Value) !void { |
| 179 | const tty = s.tty; | 179 | const tty = s.tty; |
| 180 | switch (val.toKey(s.ip)) { | 180 | switch (val.toKey(s.ip)) { |
| 181 | .simple_type => |t| { | 181 | .simple_type => |t| { |
| ... | @@ -198,14 +198,14 @@ const State = struct { | ... | @@ -198,14 +198,14 @@ const State = struct { |
| 198 | try w.writeAll(","); | 198 | try w.writeAll(","); |
| 199 | try tty.setColor(w, .reset); | 199 | try tty.setColor(w, .reset); |
| 200 | } | 200 | } |
| 201 | try s.dumpValue(w, Value.fromInterned(param)); | 201 | try s.dumpValue(w, param.value()); |
| 202 | } | 202 | } |
| 203 | try tty.setColor(w, .blue); | 203 | try tty.setColor(w, .blue); |
| 204 | try w.writeAll(") -> "); | 204 | try w.writeAll(") -> "); |
| 205 | try tty.setColor(w, .reset); | 205 | try tty.setColor(w, .reset); |
| 206 | try s.dumpValue(w, Value.fromInterned(ty.return_type)); | 206 | try s.dumpValue(w, ty.return_type.value()); |
| 207 | }, | 207 | }, |
| 208 | inline .float, .int32 => |data, tag| { | 208 | inline .float, .int32, .comptime_float => |data, tag| { |
| 209 | try tty.setColor(w, .bright_black); | 209 | try tty.setColor(w, .bright_black); |
| 210 | try w.writeAll("<"); | 210 | try w.writeAll("<"); |
| 211 | try tty.setColor(w, .blue); | 211 | try tty.setColor(w, .blue); |
| ... | @@ -235,7 +235,7 @@ const State = struct { | ... | @@ -235,7 +235,7 @@ const State = struct { |
| 235 | .func => |func| { | 235 | .func => |func| { |
| 236 | try tty.setColor(w, .bright_black); | 236 | try tty.setColor(w, .bright_black); |
| 237 | try w.writeAll("<"); | 237 | try w.writeAll("<"); |
| 238 | try s.dumpValue(w, Value.fromInterned(func.ty)); | 238 | try s.dumpValue(w, func.ty); |
| 239 | try tty.setColor(w, .bright_black); | 239 | try tty.setColor(w, .bright_black); |
| 240 | try w.writeAll(", "); | 240 | try w.writeAll(", "); |
| 241 | const decl_name = s.ip.declPtrConst(func.owner_decl).name.toSlice(s.ip); | 241 | const decl_name = s.ip.declPtrConst(func.owner_decl).name.toSlice(s.ip); |
| ... | @@ -310,8 +310,7 @@ const assert = std.debug.assert; | ... | @@ -310,8 +310,7 @@ const assert = std.debug.assert; |
| 310 | const Air = @import("Air.zig"); | 310 | const Air = @import("Air.zig"); |
| 311 | const Inst = Air.Inst; | 311 | const Inst = Air.Inst; |
| 312 | 312 | ||
| 313 | const Value = @import("Value.zig"); | ||
| 314 | |||
| 315 | const InternPool = @import("InternPool.zig"); | 313 | const InternPool = @import("InternPool.zig"); |
| 314 | const Value = InternPool.Value; | ||
| 316 | 315 | ||
| 317 | const detectTTYFromWriter = @import("util.zig").detectTTYFromWriter; | 316 | const detectTTYFromWriter = @import("util.zig").detectTTYFromWriter; |
src/compiler/Air.zig+22-21| ... | @@ -77,7 +77,7 @@ pub const Inst = struct { | ... | @@ -77,7 +77,7 @@ pub const Inst = struct { |
| 77 | 77 | ||
| 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 = Value.fromInterned(@enumFromInt(ref.data)) }, | 80 | .value => .{ .value = @enumFromInt(ref.data) }, |
| 81 | .inst => .{ .inst = @enumFromInt(ref.data) }, | 81 | .inst => .{ .inst = @enumFromInt(ref.data) }, |
| 82 | }; | 82 | }; |
| 83 | } | 83 | } |
| ... | @@ -97,7 +97,7 @@ pub const Inst = struct { | ... | @@ -97,7 +97,7 @@ pub const Inst = struct { |
| 97 | 97 | ||
| 98 | pub fn isVoid(ref: Ref) bool { | 98 | pub fn isVoid(ref: Ref) bool { |
| 99 | return ref.kind == .value and | 99 | return ref.kind == .value and |
| 100 | ref.decode().value.toIntern() == .void_value; | 100 | ref.decode().value == .void; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | pub fn eql(ref: Ref, other: Ref) bool { | 103 | pub fn eql(ref: Ref, other: Ref) bool { |
| ... | @@ -203,7 +203,7 @@ pub const Call = struct { | ... | @@ -203,7 +203,7 @@ pub const Call = struct { |
| 203 | }; | 203 | }; |
| 204 | 204 | ||
| 205 | pub const Arg = struct { | 205 | pub const Arg = struct { |
| 206 | type: Value, | 206 | type: Type, |
| 207 | arg_number: u32, | 207 | arg_number: u32, |
| 208 | }; | 208 | }; |
| 209 | 209 | ||
| ... | @@ -214,13 +214,13 @@ pub const If = struct { | ... | @@ -214,13 +214,13 @@ pub const If = struct { |
| 214 | pub const Data = struct { | 214 | pub const Data = struct { |
| 215 | yes: Inst.Ref, | 215 | yes: Inst.Ref, |
| 216 | no: Inst.Ref, | 216 | no: Inst.Ref, |
| 217 | union_ty: Value, | 217 | union_ty: Type, |
| 218 | }; | 218 | }; |
| 219 | }; | 219 | }; |
| 220 | 220 | ||
| 221 | pub const Memory = struct { | 221 | pub const Memory = struct { |
| 222 | init: Inst.Ref, | 222 | init: Inst.Ref, |
| 223 | ty: Value, | 223 | ty: Type, |
| 224 | }; | 224 | }; |
| 225 | 225 | ||
| 226 | pub fn deinit(air: *Air, gpa: std.mem.Allocator) void { | 226 | pub fn deinit(air: *Air, gpa: std.mem.Allocator) void { |
| ... | @@ -249,16 +249,16 @@ pub fn instPayload(air: *const Air, comptime tag: Inst.Tag, index: Inst.Index) t | ... | @@ -249,16 +249,16 @@ pub fn instPayload(air: *const Air, comptime tag: Inst.Tag, index: Inst.Index) t |
| 249 | return air.instData(tag, index).extra_index.get(air); | 249 | return air.instData(tag, index).extra_index.get(air); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *InternPool) InternPool.Index { | 252 | pub 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.type(ip).toIntern(), | 254 | .value => |v| v.typeOf(ip), |
| 255 | .inst => |i| air.typeOfIndex(i, ip), | 255 | .inst => |i| air.typeOfIndex(i, ip), |
| 256 | }; | 256 | }; |
| 257 | } | 257 | } |
| 258 | 258 | ||
| 259 | pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *InternPool) InternPool.Index { | 259 | pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *InternPool) InternPool.Type { |
| 260 | return switch (air.instTag(index)) { | 260 | return switch (air.instTag(index)) { |
| 261 | .js_global_ref => .opaque_type, | 261 | .js_global_ref => .@"opaque", |
| 262 | 262 | ||
| 263 | .block => { | 263 | .block => { |
| 264 | const items = air.instData(.block, index).slice(air); | 264 | const items = air.instData(.block, index).slice(air); |
| ... | @@ -267,28 +267,28 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *InternPool) InternPo | ... | @@ -267,28 +267,28 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *InternPool) InternPo |
| 267 | 267 | ||
| 268 | inline .add, .sub, .mul, .div => |t| air.typeOf(air.instData(t, index).lhs, ip), | 268 | inline .add, .sub, .mul, .div => |t| air.typeOf(air.instData(t, index).lhs, ip), |
| 269 | 269 | ||
| 270 | .lt, .gt, .eq, .bool_not => .bool_type, | 270 | .lt, .gt, .eq, .bool_not => .bool, |
| 271 | 271 | ||
| 272 | .arg => air.instData(.arg, index).type.toIntern(), | 272 | .arg => air.instData(.arg, index).type, |
| 273 | 273 | ||
| 274 | .negate => air.typeOf(air.instData(.negate, index).operand, ip), | 274 | .negate => air.typeOf(air.instData(.negate, index).operand, ip), |
| 275 | 275 | ||
| 276 | .@"break" => .noreturn_type, | 276 | .@"break" => .noreturn, |
| 277 | 277 | ||
| 278 | // todo: | 278 | // todo: |
| 279 | .field => .opaque_type, | 279 | .field => .@"opaque", |
| 280 | 280 | ||
| 281 | .call => { | 281 | .call => { |
| 282 | const base_type = air.typeOf(air.instData(.call, index).base, ip); | 282 | const base_type = air.typeOf(air.instData(.call, index).base, ip); |
| 283 | if (base_type == .opaque_type) return .opaque_type; | 283 | if (base_type == .@"opaque") return .@"opaque"; |
| 284 | return base_type.toKey(ip).type_function.return_type; | 284 | return base_type.value().toKey(ip).type_function.return_type; |
| 285 | }, | 285 | }, |
| 286 | 286 | ||
| 287 | .memory => air.instData(.memory, index).ty.toIntern(), | 287 | .memory => air.instData(.memory, index).ty, |
| 288 | 288 | ||
| 289 | .store => air.instData(.memory, air.instData(.store, index).memory).ty.toIntern(), | 289 | .store => air.instData(.memory, air.instData(.store, index).memory).ty, |
| 290 | 290 | ||
| 291 | .@"if" => air.instData(.@"if", index).data.get(air).union_ty.toIntern(), | 291 | .@"if" => air.instData(.@"if", index).data.get(air).union_ty, |
| 292 | }; | 292 | }; |
| 293 | } | 293 | } |
| 294 | 294 | ||
| ... | @@ -310,10 +310,11 @@ const std = @import("std"); | ... | @@ -310,10 +310,11 @@ const std = @import("std"); |
| 310 | const mem = std.mem; | 310 | const mem = std.mem; |
| 311 | const assert = std.debug.assert; | 311 | const assert = std.debug.assert; |
| 312 | 312 | ||
| 313 | const Teg = @import("Teg.zig"); | ||
| 314 | const InternPool = @import("InternPool.zig"); | 313 | const InternPool = @import("InternPool.zig"); |
| 314 | const Value = InternPool.Value; | ||
| 315 | const Type = InternPool.Type; | ||
| 316 | |||
| 317 | const Teg = @import("Teg.zig"); | ||
| 315 | const dod = @import("dod.zig"); | 318 | const dod = @import("dod.zig"); |
| 316 | 319 | ||
| 317 | const Unused = enum(u32) { zero = 0 }; | 320 | const Unused = enum(u32) { zero = 0 }; |
| 318 | |||
| 319 | const Value = @import("Value.zig"); |
src/compiler/Comp.zig+1-2| ... | @@ -214,7 +214,7 @@ pub const File = struct { | ... | @@ -214,7 +214,7 @@ pub const File = struct { |
| 214 | 214 | ||
| 215 | pub const Decl = struct { | 215 | pub const Decl = struct { |
| 216 | name: InternPool.NullTerminatedString, | 216 | name: InternPool.NullTerminatedString, |
| 217 | val: Value, | 217 | val: InternPool.Value, |
| 218 | /// The direct parent namespace of the Decl. In the case of the Decl | 218 | /// The direct parent namespace of the Decl. In the case of the Decl |
| 219 | /// corresponding to a file, this is the namespace of the struct, since | 219 | /// corresponding to a file, this is the namespace of the struct, since |
| 220 | /// there is no parent. | 220 | /// there is no parent. |
| ... | @@ -432,7 +432,6 @@ const Ast = @import("Ast.zig"); | ... | @@ -432,7 +432,6 @@ const Ast = @import("Ast.zig"); |
| 432 | const Air = @import("Air.zig"); | 432 | const Air = @import("Air.zig"); |
| 433 | const Teg = @import("Teg.zig"); | 433 | const Teg = @import("Teg.zig"); |
| 434 | const Cache = @import("Cache.zig"); | 434 | const Cache = @import("Cache.zig"); |
| 435 | const Value = @import("Value.zig"); | ||
| 436 | const Sema = @import("Sema.zig"); | 435 | const Sema = @import("Sema.zig"); |
| 437 | const Transform = @import("Transform.zig"); | 436 | const Transform = @import("Transform.zig"); |
| 438 | const JsNodeGen = @import("JsNodeGen.zig"); | 437 | const JsNodeGen = @import("JsNodeGen.zig"); |
src/compiler/InternPool.zig+156-41| ... | @@ -78,21 +78,25 @@ pub const Tag = enum(u8) { | ... | @@ -78,21 +78,25 @@ pub const Tag = enum(u8) { |
| 78 | /// A function type | 78 | /// A function type |
| 79 | /// data is an extra index into a `FuncType` | 79 | /// data is an extra index into a `FuncType` |
| 80 | type_function, | 80 | type_function, |
| 81 | /// A type that can be represented with only an enum tag. | ||
| 82 | /// data is SimpleType enum value. | ||
| 83 | simple_type, | ||
| 81 | 84 | ||
| 82 | // --- before this are types --- | 85 | // --- before this are types --- |
| 83 | // --- past this are values --- | 86 | // --- past this are values --- |
| 84 | 87 | ||
| 85 | /// A type that can be represented with only an enum tag. | ||
| 86 | /// data is SimpleType enum value. | ||
| 87 | simple_type, | ||
| 88 | /// A value that can be represented with only an enum tag. | 88 | /// A value that can be represented with only an enum tag. |
| 89 | /// data is SimpleValue enum value. | 89 | /// data is SimpleValue enum value. |
| 90 | simple_value, | 90 | simple_value, |
| 91 | /// A numeric literal that can be represented as a float. | ||
| 92 | /// Integers greater than 2^53 known at compile time are currently not supported. | ||
| 93 | /// data is an extra index into a `Float` | ||
| 94 | comptime_float, | ||
| 91 | /// An int32 value | 95 | /// An int32 value |
| 92 | /// data is i32 | 96 | /// data is i32 |
| 93 | int32, | 97 | int32, |
| 94 | /// A float value | 98 | /// A float value |
| 95 | /// data is an extra index into an `Float` | 99 | /// data is an extra index into a `Float` |
| 96 | float, | 100 | float, |
| 97 | /// A function | 101 | /// A function |
| 98 | /// data is an extra index into a `FuncDecl` | 102 | /// data is an extra index into a `FuncDecl` |
| ... | @@ -122,7 +126,7 @@ pub const Tag = enum(u8) { | ... | @@ -122,7 +126,7 @@ pub const Tag = enum(u8) { |
| 122 | .simple_value, | 126 | .simple_value, |
| 123 | .int32, | 127 | .int32, |
| 124 | => unreachable, // does not have a payload | 128 | => unreachable, // does not have a payload |
| 125 | .float => Float, | 129 | .float, .comptime_float => Float, |
| 126 | .func => FuncDecl, | 130 | .func => FuncDecl, |
| 127 | .type_function => TypeFunction, | 131 | .type_function => TypeFunction, |
| 128 | .string => String.WithLen, | 132 | .string => String.WithLen, |
| ... | @@ -133,7 +137,7 @@ pub const Tag = enum(u8) { | ... | @@ -133,7 +137,7 @@ pub const Tag = enum(u8) { |
| 133 | pub const FuncDecl = struct { | 137 | pub const FuncDecl = struct { |
| 134 | analysis: FuncAnalysis, | 138 | analysis: FuncAnalysis, |
| 135 | owner_decl: DeclIndex, | 139 | owner_decl: DeclIndex, |
| 136 | ty: Index, | 140 | ty: Value, |
| 137 | teg_body_inst: TrackedInst.Index, | 141 | teg_body_inst: TrackedInst.Index, |
| 138 | }; | 142 | }; |
| 139 | 143 | ||
| ... | @@ -141,26 +145,26 @@ pub const Tag = enum(u8) { | ... | @@ -141,26 +145,26 @@ pub const Tag = enum(u8) { |
| 141 | /// 0. param_type: Index for each params_len | 145 | /// 0. param_type: Index for each params_len |
| 142 | pub const TypeFunction = struct { | 146 | pub const TypeFunction = struct { |
| 143 | params_len: u32, | 147 | params_len: u32, |
| 144 | return_type: Index, | 148 | return_type: Type, |
| 145 | }; | 149 | }; |
| 146 | }; | 150 | }; |
| 147 | 151 | ||
| 148 | pub const Index = enum(u32) { | 152 | pub const Value = enum(u32) { |
| 149 | pub const first_type: Index = .opaque_type; | 153 | pub const first_type: Value = .opaque_type; |
| 150 | pub const last_type: Index = .noreturn_type; | 154 | pub const last_type: Value = .noreturn_type; |
| 151 | pub const first_value: Index = .void_value; | 155 | pub const first_value: Value = .void; |
| 152 | pub const last_value: Index = .empty_string; | 156 | pub const last_value: Value = .empty_string; |
| 153 | 157 | ||
| 154 | opaque_type, | 158 | opaque_type, |
| 155 | bool_type, | 159 | bool_type, |
| 156 | int32_type, | 160 | int32_type, |
| 157 | float_type, | 161 | float_type, |
| 158 | string_type, | 162 | string_type, |
| 159 | void_type, | ||
| 160 | noreturn_type, | 163 | noreturn_type, |
| 161 | type_type, | 164 | type_type, |
| 165 | numeric_literal_type, | ||
| 162 | 166 | ||
| 163 | void_value, | 167 | void, |
| 164 | bool_true, | 168 | bool_true, |
| 165 | bool_false, | 169 | bool_false, |
| 166 | int32_zero, | 170 | int32_zero, |
| ... | @@ -178,36 +182,140 @@ pub const Index = enum(u32) { | ... | @@ -178,36 +182,140 @@ pub const Index = enum(u32) { |
| 178 | start: u32, | 182 | start: u32, |
| 179 | len: u32, | 183 | len: u32, |
| 180 | 184 | ||
| 181 | pub fn get(slice: Slice, ip: *const InternPool) []Index { | 185 | pub fn get(slice: Slice, ip: *const InternPool) []Value { |
| 182 | return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]); | 186 | return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]); |
| 183 | } | 187 | } |
| 184 | }; | 188 | }; |
| 185 | 189 | ||
| 186 | /// Used for a map of `Index` values to the index within a list of `Index` values. | 190 | /// Used for a map of `Index` values to the index within a list of `Index` values. |
| 187 | const Adapter = struct { | 191 | const Adapter = struct { |
| 188 | indexes: []const Index, | 192 | indexes: []const Value, |
| 189 | 193 | ||
| 190 | pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool { | 194 | pub fn eql(ctx: @This(), a: Value, b_void: void, b_map_index: usize) bool { |
| 191 | _ = b_void; | 195 | _ = b_void; |
| 192 | return a == ctx.indexes[b_map_index]; | 196 | return a == ctx.indexes[b_map_index]; |
| 193 | } | 197 | } |
| 194 | 198 | ||
| 195 | pub fn hash(ctx: @This(), a: Index) u32 { | 199 | pub fn hash(ctx: @This(), a: Value) u32 { |
| 196 | _ = ctx; | 200 | _ = ctx; |
| 197 | return std.hash.uint32(@intFromEnum(a)); | 201 | return std.hash.uint32(@intFromEnum(a)); |
| 198 | } | 202 | } |
| 199 | }; | 203 | }; |
| 200 | 204 | ||
| 201 | pub fn toAir(index: Index) Air.Inst.Ref { | 205 | pub fn valueTag(value: Value, ip: *const InternPool) Tag { |
| 202 | return .{ .kind = .value, .data = @intCast(@intFromEnum(index)) }; | 206 | return ip.items.items(.tag)[@intFromEnum(value)]; |
| 207 | } | ||
| 208 | |||
| 209 | pub fn valueData(value: Value, ip: *const InternPool, comptime tag: Tag) tag.Data() { | ||
| 210 | return ip.items.items(.data)[@intFromEnum(value)].decode(tag, value.valueTag(ip)); | ||
| 211 | } | ||
| 212 | |||
| 213 | pub fn toAir(value: Value) Air.Inst.Ref { | ||
| 214 | return .{ .kind = .value, .data = @intCast(@intFromEnum(value)) }; | ||
| 215 | } | ||
| 216 | |||
| 217 | pub fn toKey(value: Value, ip: *const InternPool) Key { | ||
| 218 | return ip.indexToKey(value); | ||
| 219 | } | ||
| 220 | |||
| 221 | pub fn dump(value: Value, ip: *const InternPool) std.fmt.Formatter(Value.formatValue) { | ||
| 222 | return .{ .data = .{ .val = value, .ip = ip } }; | ||
| 223 | } | ||
| 224 | |||
| 225 | fn formatValue( | ||
| 226 | ctx: struct { val: Value, ip: *const InternPool }, | ||
| 227 | comptime _: []const u8, | ||
| 228 | _: std.fmt.FormatOptions, | ||
| 229 | writer: anytype, | ||
| 230 | ) !void { | ||
| 231 | // TODO: move the formatter out of Air.Dump | ||
| 232 | var state: Air.Dump.State = undefined; | ||
| 233 | state.ip = ctx.ip; | ||
| 234 | state.tty = @import("util.zig").detectTTYFromWriter(writer); | ||
| 235 | try Air.Dump.State.dumpValue(&state, writer, ctx.val); | ||
| 236 | } | ||
| 237 | |||
| 238 | pub fn typeOf(value: Value, ip: *const InternPool) Type { | ||
| 239 | return switch (value.valueTag(ip)) { | ||
| 240 | .removed => unreachable, // UAF | ||
| 241 | |||
| 242 | .type_function => .type, | ||
| 243 | .simple_type => .type, | ||
| 244 | |||
| 245 | .simple_value => switch (value.valueData(ip, .simple_value)) { | ||
| 246 | .true => .bool, | ||
| 247 | .false => .bool, | ||
| 248 | .void => .void, | ||
| 249 | }, | ||
| 250 | |||
| 251 | .comptime_float => .numeric_literal, | ||
| 252 | .int32 => .int32, | ||
| 253 | .float => .float, | ||
| 254 | .string => .string, | ||
| 255 | |||
| 256 | .func => @panic("TODO"), | ||
| 257 | }; | ||
| 258 | } | ||
| 259 | |||
| 260 | /// Try to re-interpret this `Value` as a `Type`. | ||
| 261 | /// Returns `null` if the value is not a type. | ||
| 262 | pub fn toType(value: Value, ip: *const InternPool) ?Type { | ||
| 263 | return switch (value.valueTag(ip)) { | ||
| 264 | .removed => unreachable, // UAF | ||
| 265 | |||
| 266 | .type_function, | ||
| 267 | .simple_type, | ||
| 268 | => @enumFromInt(@intFromEnum(value)), | ||
| 269 | |||
| 270 | // exception: void is a value AND a type | ||
| 271 | .simple_value => if (value == .void) .void else null, | ||
| 272 | |||
| 273 | else => null, | ||
| 274 | }; | ||
| 275 | } | ||
| 276 | |||
| 277 | pub fn asString(val: Value, ip: *const InternPool) InternPool.String.WithLen { | ||
| 278 | return val.valueData(ip, .string).get(ip); | ||
| 279 | } | ||
| 280 | |||
| 281 | pub fn toFloat(val: Value, ip: *const InternPool) ?f64 { | ||
| 282 | return switch (val.valueTag(ip)) { | ||
| 283 | inline .comptime_float, .float => |tag| val.valueData(ip, tag).get(ip).decode(), | ||
| 284 | else => null, | ||
| 285 | }; | ||
| 203 | } | 286 | } |
| 287 | }; | ||
| 288 | |||
| 289 | pub const Type = enum(u32) { | ||
| 290 | @"opaque" = @intFromEnum(Value.opaque_type), | ||
| 291 | bool = @intFromEnum(Value.bool_type), | ||
| 292 | int32 = @intFromEnum(Value.int32_type), | ||
| 293 | float = @intFromEnum(Value.float_type), | ||
| 294 | string = @intFromEnum(Value.string_type), | ||
| 295 | noreturn = @intFromEnum(Value.noreturn_type), | ||
| 296 | type = @intFromEnum(Value.type_type), | ||
| 297 | numeric_literal = @intFromEnum(Value.numeric_literal_type), | ||
| 298 | void = @intFromEnum(Value.void), | ||
| 299 | _, | ||
| 204 | 300 | ||
| 205 | pub fn toValue(index: Index) @import("Value.zig") { | 301 | /// An array of `Index` existing within the `extra` array. |
| 206 | return .{ .ip_index = index }; | 302 | /// This type exists to provide a struct with lifetime that is |
| 303 | /// not invalidated when items are added to the `InternPool`. | ||
| 304 | pub const Slice = struct { | ||
| 305 | start: u32, | ||
| 306 | len: u32, | ||
| 307 | |||
| 308 | pub fn get(slice: Slice, ip: *const InternPool) []Type { | ||
| 309 | return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]); | ||
| 310 | } | ||
| 311 | }; | ||
| 312 | |||
| 313 | pub fn value(ty: Type) Value { | ||
| 314 | return @enumFromInt(@intFromEnum(ty)); | ||
| 207 | } | 315 | } |
| 208 | 316 | ||
| 209 | pub fn toKey(index: Index, ip: *const InternPool) Key { | 317 | pub fn dump(ty: Type, ip: *const InternPool) std.fmt.Formatter(Value.formatValue) { |
| 210 | return ip.indexToKey(index); | 318 | return ty.value().dump(ip); |
| 211 | } | 319 | } |
| 212 | }; | 320 | }; |
| 213 | 321 | ||
| ... | @@ -217,9 +325,9 @@ pub const static_keys = [_]Key{ | ... | @@ -217,9 +325,9 @@ pub const static_keys = [_]Key{ |
| 217 | SimpleType.int32.key(), | 325 | SimpleType.int32.key(), |
| 218 | SimpleType.float.key(), | 326 | SimpleType.float.key(), |
| 219 | SimpleType.string.key(), | 327 | SimpleType.string.key(), |
| 220 | SimpleType.void.key(), | ||
| 221 | SimpleType.noreturn.key(), | 328 | SimpleType.noreturn.key(), |
| 222 | SimpleType.type.key(), | 329 | SimpleType.type.key(), |
| 330 | SimpleType.numeric_literal.key(), | ||
| 223 | 331 | ||
| 224 | SimpleValue.void.key(), | 332 | SimpleValue.void.key(), |
| 225 | SimpleValue.true.key(), | 333 | SimpleValue.true.key(), |
| ... | @@ -461,11 +569,11 @@ pub const NamespaceIndex = enum(u32) { | ... | @@ -461,11 +569,11 @@ pub const NamespaceIndex = enum(u32) { |
| 461 | /// * comptime-known value (where we store the value) | 569 | /// * comptime-known value (where we store the value) |
| 462 | /// * decl val (so that we can analyze the value lazily) | 570 | /// * decl val (so that we can analyze the value lazily) |
| 463 | /// * decl ref (so that we can analyze the reference lazily) | 571 | /// * decl ref (so that we can analyze the reference lazily) |
| 464 | pub const CaptureValue = packed struct(u32) { | 572 | pub const Capture = packed struct(u32) { |
| 465 | tag: enum(u2) { @"comptime", runtime, decl_val, decl_ref }, | 573 | tag: enum(u2) { @"comptime", runtime, decl_val, decl_ref }, |
| 466 | idx: u30, | 574 | idx: u30, |
| 467 | 575 | ||
| 468 | pub fn wrap(val: Unwrapped) CaptureValue { | 576 | pub fn wrap(val: Unwrapped) Capture { |
| 469 | return switch (val) { | 577 | return switch (val) { |
| 470 | .@"comptime" => |i| .{ .tag = .@"comptime", .idx = @intCast(@intFromEnum(i)) }, | 578 | .@"comptime" => |i| .{ .tag = .@"comptime", .idx = @intCast(@intFromEnum(i)) }, |
| 471 | .runtime => |i| .{ .tag = .runtime, .idx = @intCast(@intFromEnum(i)) }, | 579 | .runtime => |i| .{ .tag = .runtime, .idx = @intCast(@intFromEnum(i)) }, |
| ... | @@ -473,7 +581,7 @@ pub const CaptureValue = packed struct(u32) { | ... | @@ -473,7 +581,7 @@ pub const CaptureValue = packed struct(u32) { |
| 473 | .decl_ref => |i| .{ .tag = .decl_ref, .idx = @intCast(@intFromEnum(i)) }, | 581 | .decl_ref => |i| .{ .tag = .decl_ref, .idx = @intCast(@intFromEnum(i)) }, |
| 474 | }; | 582 | }; |
| 475 | } | 583 | } |
| 476 | pub fn unwrap(val: CaptureValue) Unwrapped { | 584 | pub fn unwrap(val: Capture) Unwrapped { |
| 477 | return switch (val.tag) { | 585 | return switch (val.tag) { |
| 478 | .@"comptime" => .{ .@"comptime" = @enumFromInt(val.idx) }, | 586 | .@"comptime" => .{ .@"comptime" = @enumFromInt(val.idx) }, |
| 479 | .runtime => .{ .runtime = @enumFromInt(val.idx) }, | 587 | .runtime => .{ .runtime = @enumFromInt(val.idx) }, |
| ... | @@ -484,9 +592,9 @@ pub const CaptureValue = packed struct(u32) { | ... | @@ -484,9 +592,9 @@ pub const CaptureValue = packed struct(u32) { |
| 484 | 592 | ||
| 485 | pub const Unwrapped = union(enum) { | 593 | pub const Unwrapped = union(enum) { |
| 486 | /// Index refers to the value. | 594 | /// Index refers to the value. |
| 487 | @"comptime": Index, | 595 | @"comptime": Value, |
| 488 | /// Index refers to the type. | 596 | /// Index refers to the type. |
| 489 | runtime: Index, | 597 | runtime: Value, |
| 490 | decl_val: DeclIndex, | 598 | decl_val: DeclIndex, |
| 491 | decl_ref: DeclIndex, | 599 | decl_ref: DeclIndex, |
| 492 | }; | 600 | }; |
| ... | @@ -494,7 +602,7 @@ pub const CaptureValue = packed struct(u32) { | ... | @@ -494,7 +602,7 @@ pub const CaptureValue = packed struct(u32) { |
| 494 | pub const Slice = struct { | 602 | pub const Slice = struct { |
| 495 | start: u32, | 603 | start: u32, |
| 496 | len: u32, | 604 | len: u32, |
| 497 | pub fn get(slice: Slice, ip: *const InternPool) []CaptureValue { | 605 | pub fn get(slice: Slice, ip: *const InternPool) []Capture { |
| 498 | return @ptrCast(ip.extra.items[slice.start..][0..slice.len]); | 606 | return @ptrCast(ip.extra.items[slice.start..][0..slice.len]); |
| 499 | } | 607 | } |
| 500 | }; | 608 | }; |
| ... | @@ -516,9 +624,9 @@ const SimpleType = enum { | ... | @@ -516,9 +624,9 @@ const SimpleType = enum { |
| 516 | float, | 624 | float, |
| 517 | string, | 625 | string, |
| 518 | bool, | 626 | bool, |
| 519 | void, | ||
| 520 | noreturn, | 627 | noreturn, |
| 521 | type, | 628 | type, |
| 629 | numeric_literal, | ||
| 522 | 630 | ||
| 523 | pub fn key(self: SimpleType) Key { | 631 | pub fn key(self: SimpleType) Key { |
| 524 | return .{ .simple_type = self }; | 632 | return .{ .simple_type = self }; |
| ... | @@ -526,6 +634,7 @@ const SimpleType = enum { | ... | @@ -526,6 +634,7 @@ const SimpleType = enum { |
| 526 | }; | 634 | }; |
| 527 | 635 | ||
| 528 | pub const Key = union(enum) { | 636 | pub const Key = union(enum) { |
| 637 | comptime_float: f64, | ||
| 529 | int32: i32, | 638 | int32: i32, |
| 530 | float: f64, | 639 | float: f64, |
| 531 | string: []const u8, | 640 | string: []const u8, |
| ... | @@ -549,8 +658,8 @@ pub const Key = union(enum) { | ... | @@ -549,8 +658,8 @@ pub const Key = union(enum) { |
| 549 | }; | 658 | }; |
| 550 | 659 | ||
| 551 | pub const TypeFunction = struct { | 660 | pub const TypeFunction = struct { |
| 552 | param_types: []Index, | 661 | param_types: []Type, |
| 553 | return_type: Index, | 662 | return_type: Type, |
| 554 | 663 | ||
| 555 | pub fn hash(self: TypeFunction, hasher: *Hash) void { | 664 | pub fn hash(self: TypeFunction, hasher: *Hash) void { |
| 556 | const t = tracer.trace(@src()); | 665 | const t = tracer.trace(@src()); |
| ... | @@ -563,13 +672,13 @@ pub const Key = union(enum) { | ... | @@ -563,13 +672,13 @@ pub const Key = union(enum) { |
| 563 | } | 672 | } |
| 564 | 673 | ||
| 565 | pub fn eql(a: TypeFunction, b: TypeFunction) bool { | 674 | pub fn eql(a: TypeFunction, b: TypeFunction) bool { |
| 566 | return std.mem.eql(Index, a.param_types, b.param_types) and | 675 | return std.mem.eql(Type, a.param_types, b.param_types) and |
| 567 | a.return_type == b.return_type; | 676 | a.return_type == b.return_type; |
| 568 | } | 677 | } |
| 569 | }; | 678 | }; |
| 570 | 679 | ||
| 571 | pub const Func = struct { | 680 | pub const Func = struct { |
| 572 | ty: Index, | 681 | ty: Value, |
| 573 | owner_decl: DeclIndex, | 682 | owner_decl: DeclIndex, |
| 574 | teg_body_inst: TrackedInst.Index, | 683 | teg_body_inst: TrackedInst.Index, |
| 575 | 684 | ||
| ... | @@ -600,7 +709,7 @@ pub const Key = union(enum) { | ... | @@ -600,7 +709,7 @@ pub const Key = union(enum) { |
| 600 | => |x| Hash.hash(seed, asBytes(&x)), | 709 | => |x| Hash.hash(seed, asBytes(&x)), |
| 601 | .string, | 710 | .string, |
| 602 | => |x| Hash.hash(seed, x), | 711 | => |x| Hash.hash(seed, x), |
| 603 | .float => |x| Hash.hash(seed, asBytes(&Float.assertPure(x))), | 712 | .float, .comptime_float => |x| Hash.hash(seed, asBytes(&Float.assertPure(x))), |
| 604 | .type_function => |x| { | 713 | .type_function => |x| { |
| 605 | var hasher = Hash.init(seed); | 714 | var hasher = Hash.init(seed); |
| 606 | x.hash(&hasher); | 715 | x.hash(&hasher); |
| ... | @@ -631,6 +740,7 @@ pub const Key = union(enum) { | ... | @@ -631,6 +740,7 @@ pub const Key = union(enum) { |
| 631 | .string, | 740 | .string, |
| 632 | => |x| std.mem.eql(u8, x, b.string), | 741 | => |x| std.mem.eql(u8, x, b.string), |
| 633 | .float => |x| Float.assertPure(x) == Float.assertPure(b.float), | 742 | .float => |x| Float.assertPure(x) == Float.assertPure(b.float), |
| 743 | .comptime_float => |x| Float.assertPure(x) == Float.assertPure(b.comptime_float), | ||
| 634 | .type_function => |x| x.eql(b.type_function), | 744 | .type_function => |x| x.eql(b.type_function), |
| 635 | .func => |a_info| { | 745 | .func => |a_info| { |
| 636 | const b_info = b.func; | 746 | const b_info = b.func; |
| ... | @@ -747,7 +857,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { | ... | @@ -747,7 +857,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 747 | ip.* = undefined; | 857 | ip.* = undefined; |
| 748 | } | 858 | } |
| 749 | 859 | ||
| 750 | pub fn indexToKey(ip: *const InternPool, index: Index) Key { | 860 | pub fn indexToKey(ip: *const InternPool, index: Value) Key { |
| 751 | assert(index != .none); | 861 | assert(index != .none); |
| 752 | const item: Item = ip.items.get(@intFromEnum(index)); | 862 | const item: Item = ip.items.get(@intFromEnum(index)); |
| 753 | const data = item.data; | 863 | const data = item.data; |
| ... | @@ -762,6 +872,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -762,6 +872,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 762 | .simple_value => .{ .simple_value = data.decode(.simple_value, item.tag) }, | 872 | .simple_value => .{ .simple_value = data.decode(.simple_value, item.tag) }, |
| 763 | .int32 => .{ .int32 = data.decode(.int32, item.tag) }, | 873 | .int32 => .{ .int32 = data.decode(.int32, item.tag) }, |
| 764 | .float => .{ .float = data.decode(.float, item.tag).get(ip).decode() }, | 874 | .float => .{ .float = data.decode(.float, item.tag).get(ip).decode() }, |
| 875 | .comptime_float => .{ .comptime_float = data.decode(.comptime_float, item.tag).get(ip).decode() }, | ||
| 765 | .string => .{ .string = data.decode(.string, item.tag).get(ip).toSlice(ip) }, | 876 | .string => .{ .string = data.decode(.string, item.tag).get(ip).toSlice(ip) }, |
| 766 | .func => { | 877 | .func => { |
| 767 | const func = data.decode(.func, item.tag).get(ip); | 878 | const func = data.decode(.func, item.tag).get(ip); |
| ... | @@ -774,7 +885,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -774,7 +885,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 774 | }; | 885 | }; |
| 775 | } | 886 | } |
| 776 | 887 | ||
| 777 | pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Index { | 888 | pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value { |
| 778 | const t = tracer.traceFmt(@src(), "{s}", .{@tagName(key)}); | 889 | const t = tracer.traceFmt(@src(), "{s}", .{@tagName(key)}); |
| 779 | defer t.end(); | 890 | defer t.end(); |
| 780 | 891 | ||
| ... | @@ -806,6 +917,10 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Index { | ... | @@ -806,6 +917,10 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Index { |
| 806 | .float, | 917 | .float, |
| 807 | try ip.extra.append(gpa, Float, Float.encode(f)), | 918 | try ip.extra.append(gpa, Float, Float.encode(f)), |
| 808 | ), | 919 | ), |
| 920 | .comptime_float => |f| Item.encode( | ||
| 921 | .comptime_float, | ||
| 922 | try ip.extra.append(gpa, Float, Float.encode(f)), | ||
| 923 | ), | ||
| 809 | .func => |f| brk: { | 924 | .func => |f| brk: { |
| 810 | const extra = try ip.extra.append(gpa, Tag.FuncDecl, .{ | 925 | const extra = try ip.extra.append(gpa, Tag.FuncDecl, .{ |
| 811 | .analysis = .{ | 926 | .analysis = .{ |
| ... | @@ -829,7 +944,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Index { | ... | @@ -829,7 +944,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Index { |
| 829 | }, | 944 | }, |
| 830 | }; | 945 | }; |
| 831 | ip.items.appendAssumeCapacity(item); | 946 | ip.items.appendAssumeCapacity(item); |
| 832 | const index: Index = @enumFromInt(ip.items.len - 1); | 947 | const index: Value = @enumFromInt(ip.items.len - 1); |
| 833 | if (std.debug.runtime_safety) { | 948 | if (std.debug.runtime_safety) { |
| 834 | assert(ip.indexToKey(index).eql(key, ip)); | 949 | assert(ip.indexToKey(index).eql(key, ip)); |
| 835 | } | 950 | } |
| ... | @@ -841,7 +956,7 @@ fn extraTypeFunction( | ... | @@ -841,7 +956,7 @@ fn extraTypeFunction( |
| 841 | extra_index: ExtraIndex(Tag.TypeFunction), | 956 | extra_index: ExtraIndex(Tag.TypeFunction), |
| 842 | ) Key.TypeFunction { | 957 | ) Key.TypeFunction { |
| 843 | const type_function, var trail = extra_index.getTrail(ip); | 958 | const type_function, var trail = extra_index.getTrail(ip); |
| 844 | const param_types = trail.readInternPoolIndexSlice(type_function.params_len); | 959 | const param_types = trail.readTypeSlice(type_function.params_len); |
| 845 | const result: Key.TypeFunction = .{ | 960 | const result: Key.TypeFunction = .{ |
| 846 | .return_type = type_function.return_type, | 961 | .return_type = type_function.return_type, |
| 847 | .param_types = param_types.get(ip), | 962 | .param_types = param_types.get(ip), |
src/compiler/JsLink.zig+2| ... | @@ -221,6 +221,8 @@ fn printExpr(link: *JsLink, tree: *const JsTree, node: Node.Index, writer: anyty | ... | @@ -221,6 +221,8 @@ fn printExpr(link: *JsLink, tree: *const JsTree, node: Node.Index, writer: anyty |
| 221 | // TODO: escapes | 221 | // TODO: escapes |
| 222 | .string => |val| try writer.print("\"{s}\"", .{val}), | 222 | .string => |val| try writer.print("\"{s}\"", .{val}), |
| 223 | 223 | ||
| 224 | .comptime_float => unreachable, // was not lowered to float | ||
| 225 | |||
| 224 | else => unreachable, // this value is not a plain_value | 226 | else => unreachable, // this value is not a plain_value |
| 225 | } | 227 | } |
| 226 | }, | 228 | }, |
src/compiler/JsNodeGen.zig+29-25| ... | @@ -198,23 +198,23 @@ fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void { | ... | @@ -198,23 +198,23 @@ fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void { |
| 198 | if ((tag == .add or tag == .sub) and | 198 | if ((tag == .add or tag == .sub) and |
| 199 | inner_data.rhs.kind == .value) | 199 | inner_data.rhs.kind == .value) |
| 200 | { | 200 | { |
| 201 | if (inner_data.rhs.decode().value.toFloat(c.ip)) |f| { | 201 | // if (inner_data.rhs.decode().value.toFloat(c.ip)) |f| { |
| 202 | if (f == 1) { | 202 | // if (f == 1) { |
| 203 | // convert this into ++ or -- | 203 | // // convert this into ++ or -- |
| 204 | const node = try c.add( | 204 | // const node = try c.add( |
| 205 | if (tag == .add) | 205 | // if (tag == .add) |
| 206 | .pre_inc | 206 | // .pre_inc |
| 207 | else | 207 | // else |
| 208 | .pre_dec, | 208 | // .pre_dec, |
| 209 | .{ | 209 | // .{ |
| 210 | .operand = target, | 210 | // .operand = target, |
| 211 | }, | 211 | // }, |
| 212 | ); | 212 | // ); |
| 213 | try c.markExpression(inst, node); | 213 | // try c.markExpression(inst, node); |
| 214 | 214 | ||
| 215 | return; | 215 | // return; |
| 216 | } | 216 | // } |
| 217 | } | 217 | // } |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | // convert into a compound assignment | 220 | // convert into a compound assignment |
| ... | @@ -442,15 +442,20 @@ fn valueToExpression(c: *JsNodeGen, v: Value) !Node.Index { | ... | @@ -442,15 +442,20 @@ fn valueToExpression(c: *JsNodeGen, v: Value) !Node.Index { |
| 442 | const t = tracer.trace(@src()); | 442 | const t = tracer.trace(@src()); |
| 443 | defer t.end(); | 443 | defer t.end(); |
| 444 | 444 | ||
| 445 | const intern_tag = c.ip.items.items(.tag)[@intFromEnum(v.toIntern())]; | 445 | const intern_tag = v.valueTag(c.ip); |
| 446 | switch (intern_tag) { | 446 | switch (intern_tag) { |
| 447 | .removed => unreachable, // UAF | 447 | .removed => unreachable, // UAF |
| 448 | 448 | ||
| 449 | .type_function, .simple_type => unreachable, // Type values are not allowed here | 449 | .type_function, |
| 450 | .simple_type, | ||
| 451 | => unreachable, // Type values are not allowed here | ||
| 450 | 452 | ||
| 451 | .int32, .float, .string, .simple_value => { | 453 | .int32, |
| 452 | return try c.add(.plain_value, .{ .value = v }); | 454 | .float, |
| 453 | }, | 455 | .comptime_float, |
| 456 | .string, | ||
| 457 | .simple_value, | ||
| 458 | => return try c.add(.plain_value, .{ .value = v }), | ||
| 454 | 459 | ||
| 455 | // funcs always point to decls | 460 | // funcs always point to decls |
| 456 | .func => { | 461 | .func => { |
| ... | @@ -493,7 +498,7 @@ fn codeGenBranch(c: *JsNodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Br | ... | @@ -493,7 +498,7 @@ fn codeGenBranch(c: *JsNodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Br |
| 493 | var requires_label = false; | 498 | var requires_label = false; |
| 494 | var items = switch (inst.decode()) { | 499 | var items = switch (inst.decode()) { |
| 495 | .value => |v| items: { | 500 | .value => |v| items: { |
| 496 | if (v.ip_index == .void_value) | 501 | if (v == .void) |
| 497 | return null; | 502 | return null; |
| 498 | if (temporary) |temp| { | 503 | if (temporary) |temp| { |
| 499 | const node = try c.valueToExpression(v); | 504 | const node = try c.valueToExpression(v); |
| ... | @@ -678,6 +683,7 @@ const assert = std.debug.assert; | ... | @@ -678,6 +683,7 @@ const assert = std.debug.assert; |
| 678 | const Allocator = std.mem.Allocator; | 683 | const Allocator = std.mem.Allocator; |
| 679 | 684 | ||
| 680 | const InternPool = @import("InternPool.zig"); | 685 | const InternPool = @import("InternPool.zig"); |
| 686 | const Value = InternPool.Value; | ||
| 681 | const NullTerminatedString = InternPool.NullTerminatedString; | 687 | const NullTerminatedString = InternPool.NullTerminatedString; |
| 682 | 688 | ||
| 683 | const Comp = @import("Comp.zig"); | 689 | const Comp = @import("Comp.zig"); |
| ... | @@ -690,7 +696,5 @@ const LocalIndex = JsTree.LocalIndex; | ... | @@ -690,7 +696,5 @@ const LocalIndex = JsTree.LocalIndex; |
| 690 | 696 | ||
| 691 | const Air = @import("Air.zig"); | 697 | const Air = @import("Air.zig"); |
| 692 | 698 | ||
| 693 | const Value = @import("Value.zig"); | ||
| 694 | |||
| 695 | const dod = @import("dod.zig"); | 699 | const dod = @import("dod.zig"); |
| 696 | const tracer = @import("tracer"); | 700 | const tracer = @import("tracer"); |
src/compiler/JsTree.zig+2-2| ... | @@ -244,6 +244,8 @@ const std = @import("std"); | ... | @@ -244,6 +244,8 @@ const std = @import("std"); |
| 244 | const assert = std.debug.assert; | 244 | const assert = std.debug.assert; |
| 245 | 245 | ||
| 246 | const InternPool = @import("InternPool.zig"); | 246 | const InternPool = @import("InternPool.zig"); |
| 247 | const Value = InternPool.Value; | ||
| 248 | |||
| 247 | const NullTerminatedString = InternPool.NullTerminatedString; | 249 | const NullTerminatedString = InternPool.NullTerminatedString; |
| 248 | const String = InternPool.String; | 250 | const String = InternPool.String; |
| 249 | 251 | ||
| ... | @@ -252,6 +254,4 @@ const Decl = Comp.Decl; | ... | @@ -252,6 +254,4 @@ const Decl = Comp.Decl; |
| 252 | 254 | ||
| 253 | const dod = @import("dod.zig"); | 255 | const dod = @import("dod.zig"); |
| 254 | 256 | ||
| 255 | const Value = @import("Value.zig"); | ||
| 256 | |||
| 257 | const Unused = @import("Ast.zig").Unused; | 257 | const Unused = @import("Ast.zig").Unused; |
src/compiler/Parse.zig+4-1| ... | @@ -265,7 +265,10 @@ fn parseFnDecl(p: *Parse) Error!NodeIndex { | ... | @@ -265,7 +265,10 @@ fn parseFnDecl(p: *Parse) Error!NodeIndex { |
| 265 | const params = try p.parseParamList(); | 265 | const params = try p.parseParamList(); |
| 266 | 266 | ||
| 267 | const return_type = if (p.eatToken(.minus_lt)) |_| | 267 | const return_type = if (p.eatToken(.minus_lt)) |_| |
| 268 | try p.parseExpression(false) | 268 | if (!p.isExpressionStart()) |
| 269 | return p.failUnexpectedToken(.expression) | ||
| 270 | else | ||
| 271 | try p.parseExpression(false) | ||
| 269 | else | 272 | else |
| 270 | null; | 273 | null; |
| 271 | 274 |
src/compiler/Report.zig+108-56| ... | @@ -24,62 +24,6 @@ pub const Item = struct { | ... | @@ -24,62 +24,6 @@ pub const Item = struct { |
| 24 | pub const Type = enum { @"error", warn }; | 24 | pub const Type = enum { @"error", warn }; |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | /// A variant of std.builtin.StackTrace that stores it's data within itself | ||
| 28 | /// instead of being a pointer. This allows capturing the stack trace and | ||
| 29 | /// saving it for later printing. | ||
| 30 | pub const StoredTrace = struct { | ||
| 31 | data: [32]usize, | ||
| 32 | index: usize, | ||
| 33 | |||
| 34 | pub const empty = .{ | ||
| 35 | .data = .{0} ** 32, | ||
| 36 | .index = 0, | ||
| 37 | }; | ||
| 38 | |||
| 39 | fn trace(stored: *StoredTrace) std.builtin.StackTrace { | ||
| 40 | return .{ | ||
| 41 | .index = stored.index, | ||
| 42 | .instruction_addresses = &stored.data, | ||
| 43 | }; | ||
| 44 | } | ||
| 45 | |||
| 46 | pub fn capture(begin: ?usize) StoredTrace { | ||
| 47 | var stored: StoredTrace = undefined; | ||
| 48 | var frame = stored.trace(); | ||
| 49 | std.debug.captureStackTrace(begin orelse @returnAddress(), &frame); | ||
| 50 | stored.index = frame.index; | ||
| 51 | return stored; | ||
| 52 | } | ||
| 53 | |||
| 54 | pub fn from(stack_trace: ?*std.builtin.StackTrace) StoredTrace { | ||
| 55 | if (stack_trace) |stack| { | ||
| 56 | var data: [32]usize = undefined; | ||
| 57 | @memset(&data, 0); | ||
| 58 | const items = @min(stack.instruction_addresses.len, 32); | ||
| 59 | @memcpy(data[0..items], stack.instruction_addresses[0..items]); | ||
| 60 | return .{ | ||
| 61 | .data = data, | ||
| 62 | .index = @min(items, stack.index), | ||
| 63 | }; | ||
| 64 | } else { | ||
| 65 | return empty; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | }; | ||
| 69 | |||
| 70 | pub const DebugStoredTrace = if (builtin.mode == .Debug) | ||
| 71 | StoredTrace | ||
| 72 | else | ||
| 73 | struct { | ||
| 74 | pub fn capture() @This() { | ||
| 75 | return .{}; | ||
| 76 | } | ||
| 77 | |||
| 78 | pub fn from(_: ?*std.builtin.StackTrace) @This() { | ||
| 79 | return .{}; | ||
| 80 | } | ||
| 81 | }; | ||
| 82 | |||
| 83 | pub const Err = union(enum) { | 27 | pub const Err = union(enum) { |
| 84 | pub const FieldEnum = std.meta.FieldEnum(Err); | 28 | pub const FieldEnum = std.meta.FieldEnum(Err); |
| 85 | 29 | ||
| ... | @@ -189,6 +133,15 @@ pub const Err = union(enum) { | ... | @@ -189,6 +133,15 @@ pub const Err = union(enum) { |
| 189 | ); | 133 | ); |
| 190 | } | 134 | } |
| 191 | }, | 135 | }, |
| 136 | comptime_float_to_int: struct { | ||
| 137 | val: f64, | ||
| 138 | src: LazyNode, | ||
| 139 | |||
| 140 | fn build(data: @This(), ctx: *MsgContext) !void { | ||
| 141 | const node = try data.src.get(ctx); | ||
| 142 | try ctx.msgNode(node, "numeric literal \"{d}\" cannot be coerced to \"int\"", .{data.val}); | ||
| 143 | } | ||
| 144 | }, | ||
| 192 | }; | 145 | }; |
| 193 | 146 | ||
| 194 | pub const Warn = union(enum) { | 147 | pub const Warn = union(enum) { |
| ... | @@ -221,8 +174,74 @@ pub const Warn = union(enum) { | ... | @@ -221,8 +174,74 @@ pub const Warn = union(enum) { |
| 221 | try ctx.msgAlone("if this was intentional, discard it with \"_ = {s};\"", .{id}); | 174 | try ctx.msgAlone("if this was intentional, discard it with \"_ = {s};\"", .{id}); |
| 222 | } | 175 | } |
| 223 | }, | 176 | }, |
| 177 | numeric_int_var_ambiguity: struct { | ||
| 178 | node: LazyNode, | ||
| 179 | |||
| 180 | fn build(data: @This(), ctx: *MsgContext) !void { | ||
| 181 | const var_decl_node = try data.node.get(ctx); | ||
| 182 | const init_node = ctx.ast.nodeData(var_decl_node).var_decl.init; | ||
| 183 | try ctx.msgNode(init_node, "constant integer in a \"var\" has an unknown type, assuming \"float\"", .{}); | ||
| 184 | try ctx.msgAlone("add \": float\" or \": int\" after the variable name to set the type", .{}); | ||
| 185 | } | ||
| 186 | }, | ||
| 224 | }; | 187 | }; |
| 225 | 188 | ||
| 189 | /// A variant of std.builtin.StackTrace that stores it's data within itself | ||
| 190 | /// instead of being a pointer. This allows capturing the stack trace and | ||
| 191 | /// saving it for later printing. | ||
| 192 | pub const StoredTrace = struct { | ||
| 193 | data: [32]usize, | ||
| 194 | index: usize, | ||
| 195 | |||
| 196 | pub const empty = .{ | ||
| 197 | .data = .{0} ** 32, | ||
| 198 | .index = 0, | ||
| 199 | }; | ||
| 200 | |||
| 201 | fn trace(stored: *StoredTrace) std.builtin.StackTrace { | ||
| 202 | return .{ | ||
| 203 | .index = stored.index, | ||
| 204 | .instruction_addresses = &stored.data, | ||
| 205 | }; | ||
| 206 | } | ||
| 207 | |||
| 208 | pub fn capture(begin: ?usize) StoredTrace { | ||
| 209 | var stored: StoredTrace = undefined; | ||
| 210 | var frame = stored.trace(); | ||
| 211 | std.debug.captureStackTrace(begin orelse @returnAddress(), &frame); | ||
| 212 | stored.index = frame.index; | ||
| 213 | return stored; | ||
| 214 | } | ||
| 215 | |||
| 216 | pub fn from(stack_trace: ?*std.builtin.StackTrace) StoredTrace { | ||
| 217 | if (stack_trace) |stack| { | ||
| 218 | var data: [32]usize = undefined; | ||
| 219 | @memset(&data, 0); | ||
| 220 | const items = @min(stack.instruction_addresses.len, 32); | ||
| 221 | @memcpy(data[0..items], stack.instruction_addresses[0..items]); | ||
| 222 | return .{ | ||
| 223 | .data = data, | ||
| 224 | .index = @min(items, stack.index), | ||
| 225 | }; | ||
| 226 | } else { | ||
| 227 | return empty; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | }; | ||
| 231 | |||
| 232 | pub const DebugStoredTrace = if (builtin.mode == .Debug) | ||
| 233 | StoredTrace | ||
| 234 | else | ||
| 235 | struct { | ||
| 236 | pub fn capture() @This() { | ||
| 237 | return .{}; | ||
| 238 | } | ||
| 239 | |||
| 240 | pub fn from(_: ?*std.builtin.StackTrace) @This() { | ||
| 241 | return .{}; | ||
| 242 | } | ||
| 243 | }; | ||
| 244 | |||
| 226 | pub const UnusedKind = enum { | 245 | pub const UnusedKind = enum { |
| 227 | param, | 246 | param, |
| 228 | constant, | 247 | constant, |
| ... | @@ -509,6 +528,7 @@ pub const Builder = struct { | ... | @@ -509,6 +528,7 @@ pub const Builder = struct { |
| 509 | pub fn deinit(b: *Builder) void { | 528 | pub fn deinit(b: *Builder) void { |
| 510 | b.errors.deinit(b.gpa); | 529 | b.errors.deinit(b.gpa); |
| 511 | b.warnings.deinit(b.gpa); | 530 | b.warnings.deinit(b.gpa); |
| 531 | b.string_bytes.deinit(b.gpa); | ||
| 512 | } | 532 | } |
| 513 | 533 | ||
| 514 | pub fn finalize(b: *Builder) !Report { | 534 | pub fn finalize(b: *Builder) !Report { |
| ... | @@ -592,6 +612,38 @@ pub const MsgContext = struct { | ... | @@ -592,6 +612,38 @@ pub const MsgContext = struct { |
| 592 | } | 612 | } |
| 593 | }; | 613 | }; |
| 594 | 614 | ||
| 615 | pub const LazyNode = struct { | ||
| 616 | decl: Comp.Decl.Index, | ||
| 617 | node_offset: i32, | ||
| 618 | |||
| 619 | pub fn get(lazy: LazyNode, ctx: *MsgContext) !NodeIndex { | ||
| 620 | const decl = ctx.comp.intern_pool.declPtrConst(lazy.decl); | ||
| 621 | const ns = ctx.comp.intern_pool.namespacePtr(decl.src_namespace); | ||
| 622 | |||
| 623 | // TODO: This might change if we have errors like | ||
| 624 | // - function arguments not matching at <callsite> | ||
| 625 | // - function declared <definition> | ||
| 626 | // And they are both in different files. | ||
| 627 | // To resolve this, `Component` needs to store which file it is in. | ||
| 628 | assert(ns.file_scope == ctx.file); | ||
| 629 | |||
| 630 | if (ns.parent.unwrap() != null) { | ||
| 631 | @panic("TODO: LazyNode.get when the decl is in a nested namespace"); | ||
| 632 | } | ||
| 633 | |||
| 634 | const teg = &(ctx.file.teg orelse | ||
| 635 | // this will be required once incremental compilation hits | ||
| 636 | @panic("TODO: teg was unloaded")); | ||
| 637 | |||
| 638 | const decl_inst = decl.teg_decl_index.unwrap() orelse | ||
| 639 | unreachable; // file was not analyzed, yet teg loaded? | ||
| 640 | |||
| 641 | const teg_decl = teg.instData(.declaration, decl_inst.resolve(&ctx.comp.intern_pool)); | ||
| 642 | |||
| 643 | return @intCast(teg_decl.src_node - lazy.node_offset); | ||
| 644 | } | ||
| 645 | }; | ||
| 646 | |||
| 595 | const Report = @This(); | 647 | const Report = @This(); |
| 596 | const std = @import("std"); | 648 | const std = @import("std"); |
| 597 | const ArrayListUnmanaged = std.ArrayListUnmanaged; | 649 | const ArrayListUnmanaged = std.ArrayListUnmanaged; |
src/compiler/Sema.zig+224-121| ... | @@ -16,9 +16,10 @@ inst_map: InstMap = undefined, | ... | @@ -16,9 +16,10 @@ inst_map: InstMap = undefined, |
| 16 | /// scratch memory. can be used in any place you might temporarily allocate an arraylist | 16 | /// scratch memory. can be used in any place you might temporarily allocate an arraylist |
| 17 | /// this is most notably used to store block contents before the block is finalized | 17 | /// this is most notably used to store block contents before the block is finalized |
| 18 | scratch: std.ArrayListUnmanaged(u32) = .{}, | 18 | scratch: std.ArrayListUnmanaged(u32) = .{}, |
| 19 | params: []InternPool.Index = undefined, | 19 | params: []Type = undefined, |
| 20 | 20 | ||
| 21 | // outputs | 21 | // outputs |
| 22 | report: Report.Builder = undefined, | ||
| 22 | air_instructions: std.MultiArrayList(Air.Inst) = .{}, | 23 | air_instructions: std.MultiArrayList(Air.Inst) = .{}, |
| 23 | air_extra: dod.ExtraStore(.air, .@"var") = .{}, | 24 | air_extra: dod.ExtraStore(.air, .@"var") = .{}, |
| 24 | 25 | ||
| ... | @@ -27,6 +28,8 @@ pub const Error = error{ | ... | @@ -27,6 +28,8 @@ pub const Error = error{ |
| 27 | AnalysisFail, | 28 | AnalysisFail, |
| 28 | /// This analysis is waiting on other dependencies to finish | 29 | /// This analysis is waiting on other dependencies to finish |
| 29 | Interrupt, | 30 | Interrupt, |
| 31 | |||
| 32 | OutOfMemory, | ||
| 30 | }; | 33 | }; |
| 31 | 34 | ||
| 32 | /// Instead of using a hash map for this, just pre-allocate a list long enough to hold everything. | 35 | /// Instead of using a hash map for this, just pre-allocate a list long enough to hold everything. |
| ... | @@ -74,6 +77,11 @@ pub fn init(s: *Sema) !void { | ... | @@ -74,6 +77,11 @@ pub fn init(s: *Sema) !void { |
| 74 | const t = tracer.trace(@src()); | 77 | const t = tracer.trace(@src()); |
| 75 | defer t.end(); | 78 | defer t.end(); |
| 76 | 79 | ||
| 80 | s.report = .{ | ||
| 81 | .gpa = s.gpa, | ||
| 82 | .current_file = s.ip.namespacePtr(s.namespace_index).file_scope, | ||
| 83 | }; | ||
| 84 | |||
| 77 | try s.comp.current_compile_decls.append(s.gpa, s.decl_index); | 85 | try s.comp.current_compile_decls.append(s.gpa, s.decl_index); |
| 78 | 86 | ||
| 79 | s.inst_map = try InstMap.init( | 87 | s.inst_map = try InstMap.init( |
| ... | @@ -87,6 +95,10 @@ pub fn deinit(s: *Sema) void { | ... | @@ -87,6 +95,10 @@ pub fn deinit(s: *Sema) void { |
| 87 | const t = tracer.trace(@src()); | 95 | const t = tracer.trace(@src()); |
| 88 | defer t.end(); | 96 | defer t.end(); |
| 89 | 97 | ||
| 98 | const report = s.report.finalize() catch @panic("OOM"); | ||
| 99 | report.dumpToStdErr(s.comp) catch @panic("Error"); | ||
| 100 | report.deinit(s.gpa); | ||
| 101 | |||
| 90 | defer s.* = undefined; | 102 | defer s.* = undefined; |
| 91 | s.inst_map.deinit(s.arena); | 103 | s.inst_map.deinit(s.arena); |
| 92 | s.scratch.deinit(s.arena); | 104 | s.scratch.deinit(s.arena); |
| ... | @@ -121,14 +133,14 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value { | ... | @@ -121,14 +133,14 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value { |
| 121 | const decl, const fn_decl = s.code.fullFuncDecl(s.inst_map.start); | 133 | const decl, const fn_decl = s.code.fullFuncDecl(s.inst_map.start); |
| 122 | assert(decl.kind == .function); | 134 | assert(decl.kind == .function); |
| 123 | 135 | ||
| 124 | s.params = try s.gpa.alloc(InternPool.Index, fn_decl.params.len); | 136 | s.params = try s.gpa.alloc(Type, fn_decl.params.len); |
| 125 | defer s.gpa.free(s.params); | 137 | defer s.gpa.free(s.params); |
| 126 | 138 | ||
| 127 | for (fn_decl.params.slice(&s.code), 0..) |param, i| { | 139 | for (fn_decl.params.slice(&s.code), 0..) |param, i| { |
| 128 | s.params[i] = (try s.resolveRefComptime(param)).toIntern(); | 140 | s.params[i] = (try s.resolveRefComptime(param)).toType(s.ip).?; |
| 129 | } | 141 | } |
| 130 | 142 | ||
| 131 | const return_type = try s.resolveRefComptime(fn_decl.return_type); | 143 | const return_type = (try s.resolveRefComptime(fn_decl.return_type)).toType(s.ip).?; |
| 132 | 144 | ||
| 133 | const root_block = fn_decl.body.toIndex() orelse | 145 | const root_block = fn_decl.body.toIndex() orelse |
| 134 | @panic("TODO: please change this to Index. Ref is not allowed here anymore"); | 146 | @panic("TODO: please change this to Index. Ref is not allowed here anymore"); |
| ... | @@ -143,17 +155,16 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value { | ... | @@ -143,17 +155,16 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value { |
| 143 | const func_prototype = try s.ip.get(s.gpa, .{ | 155 | const func_prototype = try s.ip.get(s.gpa, .{ |
| 144 | .type_function = .{ | 156 | .type_function = .{ |
| 145 | .param_types = s.params, | 157 | .param_types = s.params, |
| 146 | .return_type = return_type.toIntern(), | 158 | .return_type = return_type, |
| 147 | }, | 159 | }, |
| 148 | }); | 160 | }); |
| 149 | const func_value = try s.ip.get(s.gpa, .{ | 161 | const value = try s.ip.get(s.gpa, .{ |
| 150 | .func = .{ | 162 | .func = .{ |
| 151 | .ty = func_prototype, | 163 | .ty = func_prototype, |
| 152 | .owner_decl = s.decl_index, | 164 | .owner_decl = s.decl_index, |
| 153 | .teg_body_inst = s.decl.teg_decl_index.unwrap().?, | 165 | .teg_body_inst = s.decl.teg_decl_index.unwrap().?, |
| 154 | }, | 166 | }, |
| 155 | }); | 167 | }); |
| 156 | const value = Value.fromInterned(func_value); | ||
| 157 | s.decl.val = value; | 168 | s.decl.val = value; |
| 158 | return value; | 169 | return value; |
| 159 | } | 170 | } |
| ... | @@ -221,11 +232,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | ... | @@ -221,11 +232,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { |
| 221 | }, | 232 | }, |
| 222 | .number => { | 233 | .number => { |
| 223 | const number: dod.Float = s.code.instPayload(.number, in); | 234 | const number: dod.Float = s.code.instPayload(.number, in); |
| 224 | return s.makeValueAir(.{ .float = number.decode() }); | 235 | return s.makeValueAir(.{ .comptime_float = number.decode() }); |
| 225 | }, | 236 | }, |
| 226 | .js => { | 237 | .js => { |
| 227 | const operand = try s.resolveRefComptime(s.code.instData(.js, in).operand); | 238 | const operand_ref = s.code.instData(.js, in).operand; |
| 228 | try s.validateType(operand.type(s.ip), .string_type); | 239 | const operand = try s.resolveRefComptime(operand_ref); |
| 240 | // const operand_str = try s.coerceValue(operand_ref.toIndex().?, operand, .string); | ||
| 229 | return s.addInstRef(.js_global_ref, operand.asString(s.ip)); | 241 | return s.addInstRef(.js_global_ref, operand.asString(s.ip)); |
| 230 | }, | 242 | }, |
| 231 | .field => { | 243 | .field => { |
| ... | @@ -233,12 +245,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | ... | @@ -233,12 +245,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { |
| 233 | const base = try s.resolveRefRuntime(field.lhs); | 245 | const base = try s.resolveRefRuntime(field.lhs); |
| 234 | const rhs = try s.resolveRefComptime(field.rhs); | 246 | const rhs = try s.resolveRefComptime(field.rhs); |
| 235 | 247 | ||
| 236 | try s.validateType(rhs.type(s.ip), .string_type); | 248 | // try s.validateType(rhs.type(s.ip), .string_type); |
| 237 | const string = rhs.asString(s.ip); | 249 | const string = rhs.asString(s.ip); |
| 238 | 250 | ||
| 239 | const base_type = s.typeOfRef(base); | 251 | const base_type = s.typeOfRef(base); |
| 240 | switch (base_type) { | 252 | switch (base_type) { |
| 241 | .opaque_type => { | 253 | .@"opaque" => { |
| 242 | return s.addInstRef(.field, .{ | 254 | return s.addInstRef(.field, .{ |
| 243 | .base = base, | 255 | .base = base, |
| 244 | .field = try string.tryToNullTerminatedString(s.ip, s.gpa), | 256 | .field = try string.tryToNullTerminatedString(s.ip, s.gpa), |
| ... | @@ -259,12 +271,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | ... | @@ -259,12 +271,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { |
| 259 | return error.AnalysisFail; | 271 | return error.AnalysisFail; |
| 260 | }; | 272 | }; |
| 261 | const resolved = try s.resolveDecl(decl_index); | 273 | const resolved = try s.resolveDecl(decl_index); |
| 262 | return resolved.toIntern().toAir(); | 274 | return resolved.toAir(); |
| 263 | }, | 275 | }, |
| 264 | .param => { | 276 | .param => { |
| 265 | const param: Teg.Inst.DataNode = s.code.instData(.param, in); | 277 | const param: Teg.Inst.DataNode = s.code.instData(.param, in); |
| 266 | return s.addInstRef(.arg, .{ | 278 | return s.addInstRef(.arg, .{ |
| 267 | .type = Value.fromInterned(s.params[param.data]), | 279 | .type = s.params[param.data], |
| 268 | .arg_number = param.data, | 280 | .arg_number = param.data, |
| 269 | }); | 281 | }); |
| 270 | }, | 282 | }, |
| ... | @@ -325,83 +337,86 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | ... | @@ -325,83 +337,86 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { |
| 325 | }); | 337 | }); |
| 326 | }, | 338 | }, |
| 327 | .call => { | 339 | .call => { |
| 328 | const call: Teg.Inst.Call = s.code.instPayload(.call, in); | 340 | @panic("TODO: re-implement .call"); |
| 329 | const base = try s.resolveRefRuntime(call.base); | 341 | // const call: Teg.Inst.Call = s.code.instPayload(.call, in); |
| 330 | const base_type = s.typeOfRef(base).toKey(s.ip); | 342 | // const base = try s.resolveRefRuntime(call.base); |
| 331 | 343 | // const base_type = s.typeOfRef(base).toKey(s.ip); | |
| 332 | const is_opaque = base_type == .simple_type and base_type.simple_type == .@"opaque"; | 344 | |
| 333 | 345 | // const is_opaque = base_type == .simple_type and base_type.simple_type == .@"opaque"; | |
| 334 | const scratch = try s.arena.alloc(Air.Inst.Ref, call.args.len); | 346 | |
| 335 | defer s.arena.free(scratch); | 347 | // const scratch = try s.arena.alloc(Air.Inst.Ref, call.args.len); |
| 336 | if (!is_opaque) { | 348 | // defer s.arena.free(scratch); |
| 337 | if (base_type != .type_function) { | 349 | // if (!is_opaque) { |
| 338 | std.debug.print("Attempt to call non-function {}", .{base_type}); | 350 | // if (base_type != .type_function) { |
| 339 | return error.AnalysisFail; | 351 | // std.debug.print("Attempt to call non-function {}", .{base_type}); |
| 340 | } | 352 | // return error.AnalysisFail; |
| 341 | 353 | // } | |
| 342 | const proto = base_type.type_function; | 354 | |
| 343 | if (proto.param_types.len != call.args.len) { | 355 | // const proto = base_type.type_function; |
| 344 | std.debug.print("Incorrect args. Expect {d}, Got {d}", .{ | 356 | // if (proto.param_types.len != call.args.len) { |
| 345 | proto.param_types.len, | 357 | // std.debug.print("Incorrect args. Expect {d}, Got {d}", .{ |
| 346 | call.args.len, | 358 | // proto.param_types.len, |
| 347 | }); | 359 | // call.args.len, |
| 348 | return error.AnalysisFail; | 360 | // }); |
| 349 | } | 361 | // return error.AnalysisFail; |
| 350 | 362 | // } | |
| 351 | // validate function args | 363 | |
| 352 | for (proto.param_types, call.args.slice(&s.code), 0..) |param, arg, i| { | 364 | // // validate function args |
| 353 | const ref = try s.resolveRefRuntime(arg); | 365 | // for (proto.param_types, call.args.slice(&s.code), 0..) |param, arg, i| { |
| 354 | scratch[i] = ref; | 366 | // const ref = try s.resolveRefRuntime(arg); |
| 355 | try s.validateType( | 367 | // scratch[i] = ref; |
| 356 | Value.fromInterned(s.typeOfRef(ref)), | 368 | // _ = param; |
| 357 | param, | 369 | // // try s.validateType( |
| 358 | ); | 370 | // // Value.fromInterned(s.typeOfRef(ref)), |
| 359 | } | 371 | // // param, |
| 360 | } else { | 372 | // // ); |
| 361 | // just copy the args in without checking | 373 | // } |
| 362 | for (call.args.slice(&s.code), 0..) |arg, i| { | 374 | // } else { |
| 363 | const ref = try s.resolveRefRuntime(arg); | 375 | // // just copy the args in without checking |
| 364 | scratch[i] = ref; | 376 | // for (call.args.slice(&s.code), 0..) |arg, i| { |
| 365 | } | 377 | // const ref = try s.resolveRefRuntime(arg); |
| 366 | } | 378 | // scratch[i] = ref; |
| 367 | 379 | // } | |
| 368 | const start = s.air_extra.list.items.len; | 380 | // } |
| 369 | try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch)); | 381 | |
| 370 | 382 | // const start = s.air_extra.list.items.len; | |
| 371 | return s.addInstRef(.call, .{ | 383 | // try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch)); |
| 372 | .base = base, | 384 | |
| 373 | .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{ | 385 | // return s.addInstRef(.call, .{ |
| 374 | .args = .{ | 386 | // .base = base, |
| 375 | .start = @intCast(start), | 387 | // .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{ |
| 376 | .len = @intCast(scratch.len), | 388 | // .args = .{ |
| 377 | }, | 389 | // .start = @intCast(start), |
| 378 | }), | 390 | // .len = @intCast(scratch.len), |
| 379 | }); | 391 | // }, |
| 392 | // }), | ||
| 393 | // }); | ||
| 380 | }, | 394 | }, |
| 381 | .ensure_void => { | 395 | .ensure_void => { |
| 382 | const operand = try s.resolveRefRuntimeExtra(s.code.instData(.ensure_void, in).operand, false); | 396 | const operand = try s.resolveRefRuntimeExtra(s.code.instData(.ensure_void, in).operand, false); |
| 383 | const t = Value.fromInterned(s.typeOfRef(operand)); | 397 | const t = s.typeOfRef(operand); |
| 384 | if (!t.isEnsureVoid(s.ip)) { | 398 | _ = t; |
| 385 | std.debug.print("oh no, we are discarding {} on accident\n", .{ | 399 | // if (!t.isEnsureVoid(s.ip)) { |
| 386 | t.fmt(s.ip), | 400 | // std.debug.print("oh no, we are discarding {} on accident\n", .{ |
| 387 | }); | 401 | // t.fmt(s.ip), |
| 388 | } | 402 | // }); |
| 389 | return InternPool.Index.void_value.toAir(); | 403 | // } |
| 404 | return InternPool.Value.void.toAir(); | ||
| 390 | }, | 405 | }, |
| 391 | .discard => { | 406 | .discard => { |
| 392 | const operand = try s.resolveRefRuntimeExtra(s.code.instData(.discard, in).operand, false); | 407 | const operand = try s.resolveRefRuntimeExtra(s.code.instData(.discard, in).operand, false); |
| 393 | const t = Value.fromInterned(s.typeOfRef(operand)); | 408 | const t = s.typeOfRef(operand); |
| 394 | if (t.ip_index == .void_value) { | 409 | if (t == .void) { |
| 395 | std.debug.print("oh no, we have a useless _ = void;\n", .{}); | 410 | std.debug.print("oh no, we have a useless _ = void;\n", .{}); |
| 396 | } | 411 | } |
| 397 | return InternPool.Index.void_value.toAir(); | 412 | return InternPool.Value.void.toAir(); |
| 398 | }, | 413 | }, |
| 399 | .@"if" => { | 414 | .@"if" => { |
| 400 | const data: Teg.Inst.If = s.code.instData(.@"if", in).extra_index.get(&s.code); | 415 | const data: Teg.Inst.If = s.code.instData(.@"if", in).extra_index.get(&s.code); |
| 401 | 416 | ||
| 402 | const cond = try s.resolveRefRuntime(data.cond); | 417 | const cond = try s.resolveRefRuntime(data.cond); |
| 403 | 418 | ||
| 404 | try s.validateType(Value.fromInterned(s.typeOfRef(cond)), .bool_type); | 419 | // try s.validateType(s.typeOfRef(cond), .bool_type); |
| 405 | 420 | ||
| 406 | // If known at comptime, only analyze the taken path | 421 | // If known at comptime, only analyze the taken path |
| 407 | if (cond.kind == .value) { | 422 | if (cond.kind == .value) { |
| ... | @@ -417,7 +432,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | ... | @@ -417,7 +432,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { |
| 417 | .data = try s.air_extra.append(s.gpa, Air.If.Data, .{ | 432 | .data = try s.air_extra.append(s.gpa, Air.If.Data, .{ |
| 418 | .yes = yes_block, | 433 | .yes = yes_block, |
| 419 | .no = no_block, | 434 | .no = no_block, |
| 420 | .union_ty = s.unionType(Value.fromInterned(s.typeOfRef(yes_block)), Value.fromInterned(s.typeOfRef(no_block))), | 435 | .union_ty = s.unionType(s.typeOfRef(yes_block), s.typeOfRef(no_block)), |
| 421 | }), | 436 | }), |
| 422 | }); | 437 | }); |
| 423 | }, | 438 | }, |
| ... | @@ -434,11 +449,24 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | ... | @@ -434,11 +449,24 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { |
| 434 | .memory => { | 449 | .memory => { |
| 435 | const data = s.code.instData(.memory, in); | 450 | const data = s.code.instData(.memory, in); |
| 436 | 451 | ||
| 437 | const initial_value = try s.resolveRefRuntime(data.operand); | 452 | var initial_value = try s.resolveRefRuntime(data.operand); |
| 453 | |||
| 454 | switch (initial_value.decode()) { | ||
| 455 | .value => |v| switch (v.toKey(s.ip)) { | ||
| 456 | .comptime_float => |val| { | ||
| 457 | try s.report.warn(.numeric_int_var_ambiguity, .{ | ||
| 458 | .node = s.nodeLoc(in), | ||
| 459 | }); | ||
| 460 | initial_value = (try s.makeValue(.{ .float = val })).toAir(); | ||
| 461 | }, | ||
| 462 | else => {}, | ||
| 463 | }, | ||
| 464 | else => {}, | ||
| 465 | } | ||
| 438 | 466 | ||
| 439 | return try s.addInstRef(.memory, .{ | 467 | return try s.addInstRef(.memory, .{ |
| 440 | .init = initial_value, | 468 | .init = initial_value, |
| 441 | .ty = s.typeOfRef(initial_value).toValue(), | 469 | .ty = s.typeOfRef(initial_value), |
| 442 | }); | 470 | }); |
| 443 | }, | 471 | }, |
| 444 | .store => { | 472 | .store => { |
| ... | @@ -448,16 +476,22 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | ... | @@ -448,16 +476,22 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { |
| 448 | const location = s.mapTeg(data.memory.toRef()).decode().inst; | 476 | const location = s.mapTeg(data.memory.toRef()).decode().inst; |
| 449 | const operand = try s.resolveRefRuntime(data.operand); | 477 | const operand = try s.resolveRefRuntime(data.operand); |
| 450 | 478 | ||
| 451 | try s.validateType( | 479 | // try s.validateType( |
| 452 | s.typeOfRef(operand).toValue(), | 480 | // s.typeOfRef(operand).toValue(), |
| 453 | s.tempAir().instData(.memory, location).ty.ip_index, | 481 | // s.tempAir().instData(.memory, location).ty.ip_index, |
| 454 | ); | 482 | // ); |
| 455 | 483 | ||
| 456 | return try s.addInstRef(.store, .{ | 484 | return try s.addInstRef(.store, .{ |
| 457 | .memory = location, | 485 | .memory = location, |
| 458 | .operand = operand, | 486 | .operand = operand, |
| 459 | }); | 487 | }); |
| 460 | }, | 488 | }, |
| 489 | .as => { | ||
| 490 | const as: Teg.Inst.As = s.code.instPayload(.as, in); | ||
| 491 | const coerce_to = try s.resolveRefComptime(as.type); | ||
| 492 | const operand = try s.resolveRefRuntime(as.operand); | ||
| 493 | return try s.coerceRef(in, operand, coerce_to.toType(s.ip).?); | ||
| 494 | }, | ||
| 461 | else => |tag| std.debug.panic("TODO: analyze of .{s}", .{@tagName(tag)}), | 495 | else => |tag| std.debug.panic("TODO: analyze of .{s}", .{@tagName(tag)}), |
| 462 | } | 496 | } |
| 463 | } | 497 | } |
| ... | @@ -498,7 +532,7 @@ fn analyzeRefToBlock(s: *Sema, in: Teg.Inst.Ref) anyerror!Air.Inst.Ref { | ... | @@ -498,7 +532,7 @@ fn analyzeRefToBlock(s: *Sema, in: Teg.Inst.Ref) anyerror!Air.Inst.Ref { |
| 498 | 532 | ||
| 499 | fn resolveRefRuntimeExtra(s: *Sema, ref: Teg.Inst.Ref, mark: bool) anyerror!Air.Inst.Ref { | 533 | fn resolveRefRuntimeExtra(s: *Sema, ref: Teg.Inst.Ref, mark: bool) anyerror!Air.Inst.Ref { |
| 500 | const index = ref.toIndex() orelse { | 534 | const index = ref.toIndex() orelse { |
| 501 | return ref.toInterned().?.toAir(); | 535 | return ref.toValue().?.toAir(); |
| 502 | }; | 536 | }; |
| 503 | 537 | ||
| 504 | if (s.inst_map.get(index)) |air| { | 538 | if (s.inst_map.get(index)) |air| { |
| ... | @@ -519,20 +553,21 @@ fn resolveRefRuntime(s: *Sema, ref: Teg.Inst.Ref) anyerror!Air.Inst.Ref { | ... | @@ -519,20 +553,21 @@ fn resolveRefRuntime(s: *Sema, ref: Teg.Inst.Ref) anyerror!Air.Inst.Ref { |
| 519 | } | 553 | } |
| 520 | 554 | ||
| 521 | fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value { | 555 | fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value { |
| 522 | const in = ref.toIndex() orelse { | 556 | const index = switch (ref.decode()) { |
| 523 | return Value{ .ip_index = ref.toInterned().? }; | 557 | .value => |value| return value, |
| 558 | .index => |index| index, | ||
| 524 | }; | 559 | }; |
| 525 | 560 | ||
| 526 | if (s.inst_map.get(in)) |air| { | 561 | if (s.inst_map.get(index)) |air| { |
| 527 | switch (air.decode()) { | 562 | switch (air.decode()) { |
| 528 | .value => |value| return value, | 563 | .value => |value| return value, |
| 529 | else => {}, | 564 | else => {}, |
| 530 | } | 565 | } |
| 531 | } | 566 | } |
| 532 | 567 | ||
| 533 | switch (s.code.instTag(in)) { | 568 | switch (s.code.instTag(index)) { |
| 534 | .string => { | 569 | .string => { |
| 535 | const string: Teg.SlicedString = s.code.instPayload(.string, in); | 570 | const string: Teg.SlicedString = s.code.instPayload(.string, index); |
| 536 | return s.makeValue(.{ .string = string.slice(s.code.string_bytes) }); | 571 | return s.makeValue(.{ .string = string.slice(s.code.string_bytes) }); |
| 537 | }, | 572 | }, |
| 538 | 573 | ||
| ... | @@ -540,6 +575,70 @@ fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value { | ... | @@ -540,6 +575,70 @@ fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value { |
| 540 | } | 575 | } |
| 541 | } | 576 | } |
| 542 | 577 | ||
| 578 | /// Coerce `value` runtime ref to `coerce_type`, and emit an error at `teg_ref`'s location | ||
| 579 | fn coerceRef( | ||
| 580 | s: *Sema, | ||
| 581 | teg_ref: Teg.Inst.Index, | ||
| 582 | value: Air.Inst.Ref, | ||
| 583 | coerce_to: Type, | ||
| 584 | ) !Air.Inst.Ref { | ||
| 585 | _ = teg_ref; | ||
| 586 | _ = s; | ||
| 587 | _ = value; | ||
| 588 | _ = coerce_to; | ||
| 589 | // const value_type = s.typeOfRef(value); | ||
| 590 | // switch (coerce_type.toKey(s.ip)) { | ||
| 591 | // .simple_type => |simple_type| switch (simple_type) { | ||
| 592 | // // .@"opaque", | ||
| 593 | // .int32 => { | ||
| 594 | // switch (value_type.toKey(s.ip)) { | ||
| 595 | // .simple_type => switch (simple_type) { | ||
| 596 | // // .int32 => return value, | ||
| 597 | // // .numeric_literal => { | ||
| 598 | // // const val = value.decode().value.toKey(s.ip).comptime_float; | ||
| 599 | // // std.debug.print("buh {d}\n", .{val}); | ||
| 600 | // // if (!math.isFinite(val) or | ||
| 601 | // // val < math.minInt(i32) or | ||
| 602 | // // val > math.maxInt(i32)) | ||
| 603 | // // { | ||
| 604 | // // try s.fail(.comptime_float_to_int, .{ | ||
| 605 | // // .val = val, | ||
| 606 | // // .src = s.nodeLoc(teg_ref), | ||
| 607 | // // }); | ||
| 608 | // // } | ||
| 609 | // // return (try s.makeValue(.{ .int32 = @intFromFloat(val) })).toAir(); | ||
| 610 | // // }, | ||
| 611 | // else => |tag| std.debug.panic("TODO: coerceTo value_type simple_type .{s}", .{@tagName(tag)}), | ||
| 612 | // }, | ||
| 613 | // else => |tag| std.debug.panic("TODO: coerceTo value_type .{s}", .{@tagName(tag)}), | ||
| 614 | // } | ||
| 615 | // }, | ||
| 616 | // // .float, | ||
| 617 | // // .string, | ||
| 618 | // // .bool, | ||
| 619 | // // .noreturn, | ||
| 620 | // // .type, | ||
| 621 | // // .numeric_literal, | ||
| 622 | // else => |tag| std.debug.panic("TODO: coerceTo coerce_type .simple_type = .{s}", .{@tagName(tag)}), | ||
| 623 | // }, | ||
| 624 | // else => |tag| std.debug.panic("TODO: coerceTo coerce_type .{s}", .{@tagName(tag)}), | ||
| 625 | // } | ||
| 626 | @panic("TODO"); | ||
| 627 | } | ||
| 628 | |||
| 629 | fn coerceValue( | ||
| 630 | s: *Sema, | ||
| 631 | teg_ref: Teg.Inst.Index, | ||
| 632 | value: Value, | ||
| 633 | coerce_to: Type, | ||
| 634 | ) !Value { | ||
| 635 | _ = s; | ||
| 636 | _ = teg_ref; | ||
| 637 | _ = value; | ||
| 638 | _ = coerce_to; | ||
| 639 | @panic("TODO"); | ||
| 640 | } | ||
| 641 | |||
| 543 | fn resolveDecl(s: *Sema, decl_index: Decl.Index) !Value { | 642 | fn resolveDecl(s: *Sema, decl_index: Decl.Index) !Value { |
| 544 | const decl = s.ip.declPtr(decl_index); | 643 | const decl = s.ip.declPtr(decl_index); |
| 545 | switch (decl.analysis) { | 644 | switch (decl.analysis) { |
| ... | @@ -579,27 +678,22 @@ fn resolveDecl(s: *Sema, decl_index: Decl.Index) !Value { | ... | @@ -579,27 +678,22 @@ fn resolveDecl(s: *Sema, decl_index: Decl.Index) !Value { |
| 579 | } | 678 | } |
| 580 | } | 679 | } |
| 581 | 680 | ||
| 582 | fn unionType(s: *Sema, a: Value, b: Value) Value { | 681 | fn unionType(s: *Sema, a: Type, b: Type) Type { |
| 583 | if (std.debug.runtime_safety) { | 682 | if (a == b) { |
| 584 | assert(a.type(s.ip).toIntern() == .type_type); | ||
| 585 | assert(b.type(s.ip).toIntern() == .type_type); | ||
| 586 | } | ||
| 587 | |||
| 588 | if (a.ip_index == b.ip_index) { | ||
| 589 | return a; | 683 | return a; |
| 590 | } | 684 | } |
| 591 | 685 | ||
| 592 | if (a.ip_index == .noreturn_type) | 686 | if (a == .noreturn) |
| 593 | return b; | 687 | return b; |
| 594 | 688 | ||
| 595 | if (b.ip_index == .noreturn_type) | 689 | if (b == .noreturn) |
| 596 | return a; | 690 | return a; |
| 597 | 691 | ||
| 598 | std.debug.panic( | 692 | std.debug.panic( |
| 599 | "TODO: when two non-equal types implicitly merge (if/match), this should generate a union type.\na: {}\nb: {}", | 693 | "TODO: when two non-equal types implicitly merge (if/match), this should generate a union type.\na: {}\nb: {}", |
| 600 | .{ | 694 | .{ |
| 601 | a.fmt(s.ip), | 695 | a.dump(s.ip), |
| 602 | b.fmt(s.ip), | 696 | b.dump(s.ip), |
| 603 | }, | 697 | }, |
| 604 | ); | 698 | ); |
| 605 | // return s.ip.get(s.gpa, .{ .@"union" = &.{ a, b } }); | 699 | // return s.ip.get(s.gpa, .{ .@"union" = &.{ a, b } }); |
| ... | @@ -650,7 +744,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Air.Inst.Ref { | ... | @@ -650,7 +744,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Air.Inst.Ref { |
| 650 | else => comptime unreachable, | 744 | else => comptime unreachable, |
| 651 | }; | 745 | }; |
| 652 | return @as( | 746 | return @as( |
| 653 | InternPool.Index, | 747 | InternPool.Value, |
| 654 | if (result) .bool_true else .bool_false, | 748 | if (result) .bool_true else .bool_false, |
| 655 | ).toAir(); | 749 | ).toAir(); |
| 656 | }, | 750 | }, |
| ... | @@ -660,7 +754,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Air.Inst.Ref { | ... | @@ -660,7 +754,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Air.Inst.Ref { |
| 660 | const r = rhs.toFloat(s.ip) orelse @panic("TODO: typecheck / non-numeric eq"); | 754 | const r = rhs.toFloat(s.ip) orelse @panic("TODO: typecheck / non-numeric eq"); |
| 661 | const result = l == r; | 755 | const result = l == r; |
| 662 | return @as( | 756 | return @as( |
| 663 | InternPool.Index, | 757 | InternPool.Value, |
| 664 | if (result) .bool_true else .bool_false, | 758 | if (result) .bool_true else .bool_false, |
| 665 | ).toAir(); | 759 | ).toAir(); |
| 666 | }, | 760 | }, |
| ... | @@ -709,15 +803,15 @@ fn setInstData( | ... | @@ -709,15 +803,15 @@ fn setInstData( |
| 709 | } | 803 | } |
| 710 | 804 | ||
| 711 | fn makeValue(s: *Sema, key: InternPool.Key) !Value { | 805 | fn makeValue(s: *Sema, key: InternPool.Key) !Value { |
| 712 | return .{ .ip_index = try s.ip.get(s.gpa, key) }; | 806 | return try s.ip.get(s.gpa, key); |
| 713 | } | 807 | } |
| 714 | 808 | ||
| 715 | fn makeValueAir(s: *Sema, key: InternPool.Key) !Air.Inst.Ref { | 809 | fn makeValueAir(s: *Sema, key: InternPool.Key) !Air.Inst.Ref { |
| 716 | return (try s.makeValue(key)).ip_index.toAir(); | 810 | return (try s.makeValue(key)).toAir(); |
| 717 | } | 811 | } |
| 718 | 812 | ||
| 719 | fn mapTeg(s: *Sema, inst: Teg.Inst.Ref) Air.Inst.Ref { | 813 | fn mapTeg(s: *Sema, inst: Teg.Inst.Ref) Air.Inst.Ref { |
| 720 | if (inst.toInterned()) |interned| { | 814 | if (inst.toValue()) |interned| { |
| 721 | return interned.toAir(); | 815 | return interned.toAir(); |
| 722 | } | 816 | } |
| 723 | const index = inst.toIndex().?; | 817 | const index = inst.toIndex().?; |
| ... | @@ -729,13 +823,6 @@ fn mapTeg(s: *Sema, inst: Teg.Inst.Ref) Air.Inst.Ref { | ... | @@ -729,13 +823,6 @@ fn mapTeg(s: *Sema, inst: Teg.Inst.Ref) Air.Inst.Ref { |
| 729 | }; | 823 | }; |
| 730 | } | 824 | } |
| 731 | 825 | ||
| 732 | fn validateType(s: *Sema, checked_type: Value, wanted_type: InternPool.Index) !void { | ||
| 733 | _ = s; // autofix | ||
| 734 | if (checked_type.toIntern() != wanted_type) { | ||
| 735 | return error.TypeCheckFailed; | ||
| 736 | } | ||
| 737 | } | ||
| 738 | |||
| 739 | fn scratchToIndexList(s: *Sema, scratch_top: usize) !Air.IndexList { | 826 | fn scratchToIndexList(s: *Sema, scratch_top: usize) !Air.IndexList { |
| 740 | const items = s.scratch.items[scratch_top..]; | 827 | const items = s.scratch.items[scratch_top..]; |
| 741 | const extra_top = s.air_extra.list.items.len; | 828 | const extra_top = s.air_extra.list.items.len; |
| ... | @@ -753,7 +840,7 @@ fn tempAir(s: *const Sema) Air { | ... | @@ -753,7 +840,7 @@ fn tempAir(s: *const Sema) Air { |
| 753 | }; | 840 | }; |
| 754 | } | 841 | } |
| 755 | 842 | ||
| 756 | fn typeOfRef(s: *Sema, ref: Air.Inst.Ref) InternPool.Index { | 843 | fn typeOfRef(s: *Sema, ref: Air.Inst.Ref) InternPool.Type { |
| 757 | return s.tempAir().typeOf(ref, s.ip); | 844 | return s.tempAir().typeOf(ref, s.ip); |
| 758 | } | 845 | } |
| 759 | 846 | ||
| ... | @@ -769,10 +856,28 @@ fn lookupDecl(s: *Sema, name: NullTerminatedString) ?InternPool.DeclIndex { | ... | @@ -769,10 +856,28 @@ fn lookupDecl(s: *Sema, name: NullTerminatedString) ?InternPool.DeclIndex { |
| 769 | } | 856 | } |
| 770 | } | 857 | } |
| 771 | 858 | ||
| 859 | fn nodeLoc(s: *const Sema, in: Teg.Inst.Index) Report.LazyNode { | ||
| 860 | return s.code.instSrcLoc(in, s.decl_index); | ||
| 861 | } | ||
| 862 | |||
| 863 | pub fn addWarn(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) !void { | ||
| 864 | try s.report.warn(kind, data); | ||
| 865 | } | ||
| 866 | |||
| 867 | pub fn addError(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) !void { | ||
| 868 | try s.report.err(kind, data); | ||
| 869 | } | ||
| 870 | |||
| 871 | pub fn fail(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) Error!void { | ||
| 872 | try s.report.err(kind, data); | ||
| 873 | return Error.AnalysisFail; | ||
| 874 | } | ||
| 875 | |||
| 772 | const Sema = @This(); | 876 | const Sema = @This(); |
| 773 | 877 | ||
| 774 | const std = @import("std"); | 878 | const std = @import("std"); |
| 775 | const mem = std.mem; | 879 | const mem = std.mem; |
| 880 | const math = std.math; | ||
| 776 | const Allocator = std.mem.Allocator; | 881 | const Allocator = std.mem.Allocator; |
| 777 | const assert = std.debug.assert; | 882 | const assert = std.debug.assert; |
| 778 | const log = std.log.scoped(.sema); | 883 | const log = std.log.scoped(.sema); |
| ... | @@ -791,14 +896,12 @@ const Decl = Comp.Decl; | ... | @@ -791,14 +896,12 @@ const Decl = Comp.Decl; |
| 791 | const Namespace = Comp.Namespace; | 896 | const Namespace = Comp.Namespace; |
| 792 | 897 | ||
| 793 | const Air = @import("Air.zig"); | 898 | const Air = @import("Air.zig"); |
| 794 | |||
| 795 | const Teg = @import("Teg.zig"); | 899 | const Teg = @import("Teg.zig"); |
| 900 | const Report = @import("Report.zig"); | ||
| 901 | const dod = @import("dod.zig"); | ||
| 902 | const tracer = @import("tracer"); | ||
| 796 | 903 | ||
| 797 | const Value = @import("Value.zig"); | ||
| 798 | const InternPool = @import("InternPool.zig"); | 904 | const InternPool = @import("InternPool.zig"); |
| 905 | const Value = InternPool.Value; | ||
| 906 | const Type = InternPool.Type; | ||
| 799 | const NullTerminatedString = InternPool.NullTerminatedString; | 907 | const NullTerminatedString = InternPool.NullTerminatedString; |
| 800 | const dod = @import("dod.zig"); | ||
| 801 | |||
| 802 | const Report = @import("Report.zig"); | ||
| 803 | |||
| 804 | const tracer = @import("tracer"); |
src/compiler/Teg.Dump.zig+8| ... | @@ -22,6 +22,14 @@ const State = struct { | ... | @@ -22,6 +22,14 @@ const State = struct { |
| 22 | 22 | ||
| 23 | const tag = s.teg.instTag(inst); | 23 | const tag = s.teg.instTag(inst); |
| 24 | 24 | ||
| 25 | try tty.setColor(writer, .bright_black); | ||
| 26 | const node_offset = teg.instSrcLoc(inst, @enumFromInt(0)).node_offset; | ||
| 27 | try writer.print("{c}{d} ", .{ | ||
| 28 | @as(u8, if (node_offset >= 0) '+' else '-'), | ||
| 29 | @abs(node_offset), | ||
| 30 | }); | ||
| 31 | try tty.setColor(writer, .reset); | ||
| 32 | |||
| 25 | try tty.setColor(writer, .cyan); | 33 | try tty.setColor(writer, .cyan); |
| 26 | try writer.print("{s}", .{@tagName(tag)}); | 34 | try writer.print("{s}", .{@tagName(tag)}); |
| 27 | try tty.setColor(writer, .reset); | 35 | try tty.setColor(writer, .reset); |
src/compiler/Teg.zig+42-14| ... | @@ -209,11 +209,11 @@ pub const Inst = struct { | ... | @@ -209,11 +209,11 @@ pub const Inst = struct { |
| 209 | int32_type, | 209 | int32_type, |
| 210 | float_type, | 210 | float_type, |
| 211 | string_type, | 211 | string_type, |
| 212 | void_type, | ||
| 213 | noreturn_type, | 212 | noreturn_type, |
| 214 | type_type, | 213 | type_type, |
| 214 | numeric_literal_type, | ||
| 215 | 215 | ||
| 216 | void_value, | 216 | void, |
| 217 | bool_true, | 217 | bool_true, |
| 218 | bool_false, | 218 | bool_false, |
| 219 | int32_zero, | 219 | int32_zero, |
| ... | @@ -227,9 +227,22 @@ pub const Inst = struct { | ... | @@ -227,9 +227,22 @@ pub const Inst = struct { |
| 227 | 227 | ||
| 228 | _, | 228 | _, |
| 229 | 229 | ||
| 230 | pub fn toIndex(inst: Ref) ?Index { | 230 | pub const Decoded = union(enum) { |
| 231 | assert(inst != .none); | 231 | value: InternPool.Value, |
| 232 | const ref_int = @intFromEnum(inst); | 232 | index: Teg.Inst.Index, |
| 233 | }; | ||
| 234 | |||
| 235 | pub fn decode(ref: Ref) Decoded { | ||
| 236 | const ref_int = @intFromEnum(ref); | ||
| 237 | return if (ref_int >= Index.static_len) | ||
| 238 | .{ .index = @enumFromInt(ref_int - Index.static_len) } | ||
| 239 | else | ||
| 240 | .{ .value = @enumFromInt(ref_int) }; | ||
| 241 | } | ||
| 242 | |||
| 243 | pub fn toIndex(ref: Ref) ?Index { | ||
| 244 | assert(ref != .none); | ||
| 245 | const ref_int = @intFromEnum(ref); | ||
| 233 | if (ref_int >= Index.static_len) { | 246 | if (ref_int >= Index.static_len) { |
| 234 | return @enumFromInt(ref_int - Index.static_len); | 247 | return @enumFromInt(ref_int - Index.static_len); |
| 235 | } else { | 248 | } else { |
| ... | @@ -242,7 +255,7 @@ pub const Inst = struct { | ... | @@ -242,7 +255,7 @@ pub const Inst = struct { |
| 242 | return toIndex(inst); | 255 | return toIndex(inst); |
| 243 | } | 256 | } |
| 244 | 257 | ||
| 245 | pub fn toInterned(inst: Ref) ?InternPool.Index { | 258 | pub fn toValue(inst: Ref) ?InternPool.Value { |
| 246 | const ref_int = @intFromEnum(inst); | 259 | const ref_int = @intFromEnum(inst); |
| 247 | 260 | ||
| 248 | // todo: is this > or >= | 261 | // todo: is this > or >= |
| ... | @@ -383,18 +396,30 @@ pub fn declData(teg: *const Teg, index: Inst.Index) Inst.Decl { | ... | @@ -383,18 +396,30 @@ pub fn declData(teg: *const Teg, index: Inst.Index) Inst.Decl { |
| 383 | return teg.instData(.declaration, index).extra_index.get(teg); | 396 | return teg.instData(.declaration, index).extra_index.get(teg); |
| 384 | } | 397 | } |
| 385 | 398 | ||
| 399 | pub 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 | |||
| 386 | pub fn moduleDeclarations(teg: *const Teg, module_index: Inst.Index) []const Inst.Index { | 411 | pub fn moduleDeclarations(teg: *const Teg, module_index: Inst.Index) []const Inst.Index { |
| 387 | const module = teg.instData(.module, module_index); | 412 | const module = teg.instData(.module, module_index); |
| 388 | const module_data: IndexList = module.extra_index.get(teg); | 413 | const module_data: IndexList = module.extra_index.get(teg); |
| 389 | const slice = module_data.slice(teg); | 414 | const slice = module_data.slice(teg); |
| 390 | // if (std.debug.runtime_safety) { | 415 | if (std.debug.runtime_safety) { |
| 391 | // for (slice) |item| { | 416 | for (slice) |item| { |
| 392 | // if (teg.instTag(item) != .declaration) { | 417 | if (teg.instTag(item) != .declaration) { |
| 393 | // std.debug.print("\ngot unknown tag {s}\n", .{@tagName(teg.instTag(item))}); | 418 | std.debug.print("\ngot unknown tag {s}\n", .{@tagName(teg.instTag(item))}); |
| 394 | // unreachable; | 419 | unreachable; |
| 395 | // } | 420 | } |
| 396 | // } | 421 | } |
| 397 | // } | 422 | } |
| 398 | return slice; | 423 | return slice; |
| 399 | } | 424 | } |
| 400 | 425 | ||
| ... | @@ -441,4 +466,7 @@ const InternPool = @import("InternPool.zig"); | ... | @@ -441,4 +466,7 @@ const InternPool = @import("InternPool.zig"); |
| 441 | 466 | ||
| 442 | const Air = @import("Air.zig"); | 467 | const Air = @import("Air.zig"); |
| 443 | 468 | ||
| 469 | const Comp = @import("Comp.zig"); | ||
| 470 | |||
| 444 | const Report = @import("Report.zig"); | 471 | const Report = @import("Report.zig"); |
| 472 | const LazyNode = Report.LazyNode; |
src/compiler/Tokenizer.zig+1-1| ... | @@ -192,7 +192,7 @@ pub const Token = struct { | ... | @@ -192,7 +192,7 @@ pub const Token = struct { |
| 192 | .pipe_pipe => "||", | 192 | .pipe_pipe => "||", |
| 193 | .percent => "%", | 193 | .percent => "%", |
| 194 | .plus => "+", | 194 | .plus => "+", |
| 195 | .minus_lt => "<", | 195 | .minus_lt => "->", |
| 196 | .semi => ";", | 196 | .semi => ";", |
| 197 | .slash => "/", | 197 | .slash => "/", |
| 198 | .star => "*", | 198 | .star => "*", |
src/compiler/Transform.zig+18-18| ... | @@ -202,7 +202,7 @@ const BlockContext = struct { | ... | @@ -202,7 +202,7 @@ const BlockContext = struct { |
| 202 | const Liveness = enum { alive, dead }; | 202 | const Liveness = enum { alive, dead }; |
| 203 | 203 | ||
| 204 | const BuiltInIds = std.ComptimeStringMap(Inst.Ref, .{ | 204 | const BuiltInIds = std.ComptimeStringMap(Inst.Ref, .{ |
| 205 | .{ "void", .void_value }, | 205 | .{ "void", .void }, |
| 206 | .{ "true", .bool_true }, | 206 | .{ "true", .bool_true }, |
| 207 | .{ "false", .bool_false }, | 207 | .{ "false", .bool_false }, |
| 208 | .{ "int", .int32_type }, | 208 | .{ "int", .int32_type }, |
| ... | @@ -289,7 +289,7 @@ fn transformModule(t: *Transform, module_node: NodeIndex) Allocator.Error!Inst.I | ... | @@ -289,7 +289,7 @@ fn transformModule(t: *Transform, module_node: NodeIndex) Allocator.Error!Inst.I |
| 289 | 289 | ||
| 290 | trail.writeStruct(Inst.DeclFn, .{ | 290 | trail.writeStruct(Inst.DeclFn, .{ |
| 291 | .params = .{ .start = 0, .len = 0 }, | 291 | .params = .{ .start = 0, .len = 0 }, |
| 292 | .return_type = Inst.Ref.void_type, | 292 | .return_type = Inst.Ref.void, |
| 293 | .body = block.toRef(), | 293 | .body = block.toRef(), |
| 294 | }); | 294 | }); |
| 295 | 295 | ||
| ... | @@ -378,7 +378,7 @@ fn transformFunction(t: *Transform, outer_decl: BlockContext, node: NodeIndex) A | ... | @@ -378,7 +378,7 @@ fn transformFunction(t: *Transform, outer_decl: BlockContext, node: NodeIndex) A |
| 378 | const return_type = if (fn_decl.return_type) |return_type_node| | 378 | const return_type = if (fn_decl.return_type) |return_type_node| |
| 379 | try t.transformExpressionToBlock(decl, return_type_node, false) | 379 | try t.transformExpressionToBlock(decl, return_type_node, false) |
| 380 | else | 380 | else |
| 381 | Inst.Ref.void_type; | 381 | Inst.Ref.void; |
| 382 | 382 | ||
| 383 | const body = try t.transformExpressionToBlock(decl, fn_decl.body, true); | 383 | const body = try t.transformExpressionToBlock(decl, fn_decl.body, true); |
| 384 | 384 | ||
| ... | @@ -528,7 +528,7 @@ fn transformParamDecl(t: *Transform, decl: BlockContext, param: NodeIndex) Alloc | ... | @@ -528,7 +528,7 @@ fn transformParamDecl(t: *Transform, decl: BlockContext, param: NodeIndex) Alloc |
| 528 | .node = param, | 528 | .node = param, |
| 529 | .prev = sym.value_ptr.node, | 529 | .prev = sym.value_ptr.node, |
| 530 | }); | 530 | }); |
| 531 | return .void_value; | 531 | return .void; |
| 532 | } | 532 | } |
| 533 | 533 | ||
| 534 | sym.value_ptr.* = .{ | 534 | sym.value_ptr.* = .{ |
| ... | @@ -558,7 +558,7 @@ const Builtin = enum { | ... | @@ -558,7 +558,7 @@ const Builtin = enum { |
| 558 | 558 | ||
| 559 | if (args.len != 1) { | 559 | if (args.len != 1) { |
| 560 | // try t.report.err(.invalid_builtin_args, .{ .id = "js" }); | 560 | // try t.report.err(.invalid_builtin_args, .{ .id = "js" }); |
| 561 | return .void_value; | 561 | return .void; |
| 562 | } | 562 | } |
| 563 | 563 | ||
| 564 | const source = try t.transformExpression(decl, args[0]) orelse return null; | 564 | const source = try t.transformExpression(decl, args[0]) orelse return null; |
| ... | @@ -600,7 +600,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc | ... | @@ -600,7 +600,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc |
| 600 | 600 | ||
| 601 | const lookup = t.lookupId(id) orelse { | 601 | const lookup = t.lookupId(id) orelse { |
| 602 | try t.report.err(.unknown_identifier, .{ .node = node }); | 602 | try t.report.err(.unknown_identifier, .{ .node = node }); |
| 603 | return .void_value; | 603 | return .void; |
| 604 | }; | 604 | }; |
| 605 | 605 | ||
| 606 | lookup.used = true; | 606 | lookup.used = true; |
| ... | @@ -815,7 +815,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc | ... | @@ -815,7 +815,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc |
| 815 | => |tag| { | 815 | => |tag| { |
| 816 | const statements = t.ast.nodeStatements(node); | 816 | const statements = t.ast.nodeStatements(node); |
| 817 | 817 | ||
| 818 | var last: Inst.Ref = .void_value; | 818 | var last: Inst.Ref = .void; |
| 819 | for (statements, 1..) |statement, i| { | 819 | for (statements, 1..) |statement, i| { |
| 820 | const is_last = i == statements.len; | 820 | const is_last = i == statements.len; |
| 821 | last = try t.transformBlockStatement( | 821 | last = try t.transformBlockStatement( |
| ... | @@ -827,14 +827,14 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc | ... | @@ -827,14 +827,14 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc |
| 827 | }; | 827 | }; |
| 828 | } | 828 | } |
| 829 | 829 | ||
| 830 | return if (tag == .block_implicit_return) last else .void_value; | 830 | return if (tag == .block_implicit_return) last else .void; |
| 831 | }, | 831 | }, |
| 832 | 832 | ||
| 833 | .builtin_call, | 833 | .builtin_call, |
| 834 | => { | 834 | => { |
| 835 | const builtin = Builtin.map.get(t.ast.basicNodeSlice(node)[1..]) orelse { | 835 | const builtin = Builtin.map.get(t.ast.basicNodeSlice(node)[1..]) orelse { |
| 836 | try t.report.err(.invalid_builtin, .{ .node = node }); | 836 | try t.report.err(.invalid_builtin, .{ .node = node }); |
| 837 | return .void_value; | 837 | return .void; |
| 838 | }; | 838 | }; |
| 839 | 839 | ||
| 840 | const base = t.ast.nodeData(node).list; | 840 | const base = t.ast.nodeData(node).list; |
| ... | @@ -939,9 +939,9 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc | ... | @@ -939,9 +939,9 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc |
| 939 | false, | 939 | false, |
| 940 | ) | 940 | ) |
| 941 | else | 941 | else |
| 942 | Inst.Ref.void_value; | 942 | Inst.Ref.void; |
| 943 | 943 | ||
| 944 | if (yes == .void_value and no == .void_value) { | 944 | if (yes == .void and no == .void) { |
| 945 | // when both branches do nothing, we can omit the branch, | 945 | // when both branches do nothing, we can omit the branch, |
| 946 | // however we still need to type-check the condition operand | 946 | // however we still need to type-check the condition operand |
| 947 | _ = try t.addInstRef(.{ | 947 | _ = try t.addInstRef(.{ |
| ... | @@ -951,7 +951,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc | ... | @@ -951,7 +951,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc |
| 951 | .operand = cond, | 951 | .operand = cond, |
| 952 | }), | 952 | }), |
| 953 | }); | 953 | }); |
| 954 | return .void_value; | 954 | return .void; |
| 955 | } | 955 | } |
| 956 | 956 | ||
| 957 | return try t.addInstRef(.{ | 957 | return try t.addInstRef(.{ |
| ... | @@ -990,7 +990,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc | ... | @@ -990,7 +990,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc |
| 990 | try t.transformExpression(decl.withReturn(null), expr) orelse | 990 | try t.transformExpression(decl.withReturn(null), expr) orelse |
| 991 | return null | 991 | return null |
| 992 | else | 992 | else |
| 993 | .void_value; | 993 | .void; |
| 994 | 994 | ||
| 995 | _ = try t.addInstRef(.{ | 995 | _ = try t.addInstRef(.{ |
| 996 | .tag = .@"break", | 996 | .tag = .@"break", |
| ... | @@ -1022,7 +1022,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc | ... | @@ -1022,7 +1022,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc |
| 1022 | try t.transformExpression(decl.withReturn(null), expr) orelse | 1022 | try t.transformExpression(decl.withReturn(null), expr) orelse |
| 1023 | return null | 1023 | return null |
| 1024 | else | 1024 | else |
| 1025 | .void_value; | 1025 | .void; |
| 1026 | 1026 | ||
| 1027 | _ = try t.addInstRef(.{ | 1027 | _ = try t.addInstRef(.{ |
| 1028 | .tag = .@"break", | 1028 | .tag = .@"break", |
| ... | @@ -1063,12 +1063,12 @@ fn transformBlockStatement( | ... | @@ -1063,12 +1063,12 @@ fn transformBlockStatement( |
| 1063 | if (mem.eql(u8, var_decl.id, "_")) { | 1063 | if (mem.eql(u8, var_decl.id, "_")) { |
| 1064 | // TODO: relax this restriction into just creating a discard node | 1064 | // TODO: relax this restriction into just creating a discard node |
| 1065 | try t.report.err(.invalid_discard, .{ .node = node }); | 1065 | try t.report.err(.invalid_discard, .{ .node = node }); |
| 1066 | return .void_value; | 1066 | return .void; |
| 1067 | } | 1067 | } |
| 1068 | 1068 | ||
| 1069 | if (BuiltInIds.has(var_decl.id)) { | 1069 | if (BuiltInIds.has(var_decl.id)) { |
| 1070 | try t.report.err(.shadow_builtin_variable, .{ .node = node }); | 1070 | try t.report.err(.shadow_builtin_variable, .{ .node = node }); |
| 1071 | return .void_value; | 1071 | return .void; |
| 1072 | } | 1072 | } |
| 1073 | 1073 | ||
| 1074 | const type_ref = if (var_decl.type) |data_type| | 1074 | const type_ref = if (var_decl.type) |data_type| |
| ... | @@ -1132,7 +1132,7 @@ fn transformBlockStatement( | ... | @@ -1132,7 +1132,7 @@ fn transformBlockStatement( |
| 1132 | }, | 1132 | }, |
| 1133 | }; | 1133 | }; |
| 1134 | 1134 | ||
| 1135 | return .void_value; | 1135 | return .void; |
| 1136 | }, | 1136 | }, |
| 1137 | 1137 | ||
| 1138 | .fn_decl, | 1138 | .fn_decl, |
| ... | @@ -1188,7 +1188,7 @@ fn transformBlockStatement( | ... | @@ -1188,7 +1188,7 @@ fn transformBlockStatement( |
| 1188 | const result = try t.transformExpression(decl, node) orelse | 1188 | const result = try t.transformExpression(decl, node) orelse |
| 1189 | return null; | 1189 | return null; |
| 1190 | 1190 | ||
| 1191 | if (!is_implicit_return_expression and result != .void_value) { | 1191 | if (!is_implicit_return_expression and result != .void) { |
| 1192 | return try t.addInstRef(.{ | 1192 | return try t.addInstRef(.{ |
| 1193 | .tag = .ensure_void, | 1193 | .tag = .ensure_void, |
| 1194 | .data = EncodedData.encode(.ensure_void, .{ | 1194 | .data = EncodedData.encode(.ensure_void, .{ |
src/compiler/Value.zig deleted-96| ... | @@ -1,96 +0,0 @@ | ||
| 1 | ip_index: InternPool.Index, | ||
| 2 | |||
| 3 | pub fn fromInterned(i: InternPool.Index) Value { | ||
| 4 | assert(i != .none); | ||
| 5 | return .{ .ip_index = i }; | ||
| 6 | } | ||
| 7 | |||
| 8 | pub fn toIntern(val: Value) InternPool.Index { | ||
| 9 | assert(val.ip_index != .none); | ||
| 10 | return val.ip_index; | ||
| 11 | } | ||
| 12 | |||
| 13 | pub fn toKey(val: Value, ip: *const InternPool) InternPool.Key { | ||
| 14 | return val.toIntern().toKey(ip); | ||
| 15 | } | ||
| 16 | |||
| 17 | pub fn asBool(val: Value) i32 { | ||
| 18 | return switch (val.toIntern()) { | ||
| 19 | .bool_true => true, | ||
| 20 | .bool_false => false, | ||
| 21 | else => unreachable, | ||
| 22 | }; | ||
| 23 | } | ||
| 24 | |||
| 25 | pub fn asString(val: Value, ip: *const InternPool) InternPool.String.WithLen { | ||
| 26 | const index = val.toIntern(); | ||
| 27 | return ip.items.items(.data)[@intFromEnum(index)].decode( | ||
| 28 | .string, | ||
| 29 | ip.items.items(.tag)[@intFromEnum(index)], | ||
| 30 | ) | ||
| 31 | .get(ip); | ||
| 32 | } | ||
| 33 | |||
| 34 | pub fn @"type"(val: Value, ip: *const InternPool) Value { | ||
| 35 | const v: InternPool.Index = switch (val.toKey(ip)) { | ||
| 36 | .simple_type, .type_function => .type_type, | ||
| 37 | |||
| 38 | .int32 => .int32_type, | ||
| 39 | .float => .float_type, | ||
| 40 | .string => .string_type, | ||
| 41 | .simple_value => |v| switch (v) { | ||
| 42 | .true, .false => .bool_type, | ||
| 43 | .void => .void_type, | ||
| 44 | }, | ||
| 45 | .func => |f| f.ty, | ||
| 46 | }; | ||
| 47 | return Value.fromInterned(v); | ||
| 48 | } | ||
| 49 | |||
| 50 | pub fn toFloat(val: Value, ip: *const InternPool) ?f64 { | ||
| 51 | return switch (val.toKey(ip)) { | ||
| 52 | .int32 => |i| @floatFromInt(i), | ||
| 53 | .float => |f| f, | ||
| 54 | else => null, | ||
| 55 | }; | ||
| 56 | } | ||
| 57 | |||
| 58 | /// used for validating ensure_void instructions | ||
| 59 | pub fn isEnsureVoid(val: Value, ip: *const InternPool) bool { | ||
| 60 | const intern = val.toIntern(); | ||
| 61 | const i = @intFromEnum(intern); | ||
| 62 | |||
| 63 | return switch (ip.items.items(.tag)[i]) { | ||
| 64 | .simple_type => switch (ip.items.items(.data)[i].decode(.simple_type, .simple_type)) { | ||
| 65 | .@"opaque", .void => true, | ||
| 66 | else => true, | ||
| 67 | }, | ||
| 68 | else => false, | ||
| 69 | }; | ||
| 70 | } | ||
| 71 | |||
| 72 | const Value = @This(); | ||
| 73 | |||
| 74 | const std = @import("std"); | ||
| 75 | const assert = std.debug.assert; | ||
| 76 | |||
| 77 | pub const InternPool = @import("InternPool.zig"); | ||
| 78 | |||
| 79 | pub fn fmt(v: Value, ip: *InternPool) Format { | ||
| 80 | return .{ .value = v, .ip = ip }; | ||
| 81 | } | ||
| 82 | |||
| 83 | pub const Format = struct { | ||
| 84 | value: Value, | ||
| 85 | ip: *InternPool, | ||
| 86 | |||
| 87 | pub fn format( | ||
| 88 | self: Format, | ||
| 89 | comptime unused_fmt_str: []const u8, | ||
| 90 | _: std.fmt.FormatOptions, | ||
| 91 | writer: anytype, | ||
| 92 | ) !void { | ||
| 93 | comptime assert(unused_fmt_str.len == 0); | ||
| 94 | try writer.print("{any}", .{self.value.toKey(self.ip)}); | ||
| 95 | } | ||
| 96 | }; | ||
src/compiler/dod.zig+9-1| ... | @@ -240,7 +240,15 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil | ... | @@ -240,7 +240,15 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil |
| 240 | return ip.get(T, trail.index); | 240 | return ip.get(T, trail.index); |
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | pub fn readInternPoolIndexSlice(trail: *TrailReader, len: u32) @import("InternPool.zig").Index.Slice { | 243 | pub fn readValueSlice(trail: *TrailReader, len: u32) @import("InternPool.zig").Value.Slice { |
| 244 | defer trail.index += len; | ||
| 245 | return .{ | ||
| 246 | .start = @intCast(trail.index), | ||
| 247 | .len = len, | ||
| 248 | }; | ||
| 249 | } | ||
| 250 | |||
| 251 | pub fn readTypeSlice(trail: *TrailReader, len: u32) @import("InternPool.zig").Type.Slice { | ||
| 244 | defer trail.index += len; | 252 | defer trail.index += len; |
| 245 | return .{ | 253 | return .{ |
| 246 | .start = @intCast(trail.index), | 254 | .start = @intCast(trail.index), |
src/compiler/util.zig+22-1| ... | @@ -1,4 +1,3 @@ | ... | @@ -1,4 +1,3 @@ |
| 1 | /// TODO: move to io utility file | ||
| 2 | pub fn detectTTYFromWriter(writer: anytype) std.io.tty.Config { | 1 | pub fn detectTTYFromWriter(writer: anytype) std.io.tty.Config { |
| 3 | if (@hasField(@TypeOf(writer), "unbuffered_writer")) { | 2 | if (@hasField(@TypeOf(writer), "unbuffered_writer")) { |
| 4 | return detectTTYFromWriter(writer.unbuffered_writer); | 3 | return detectTTYFromWriter(writer.unbuffered_writer); |
| ... | @@ -17,4 +16,26 @@ pub fn detectTTYFromWriter(writer: anytype) std.io.tty.Config { | ... | @@ -17,4 +16,26 @@ pub fn detectTTYFromWriter(writer: anytype) std.io.tty.Config { |
| 17 | return .no_color; | 16 | return .no_color; |
| 18 | } | 17 | } |
| 19 | 18 | ||
| 19 | pub fn Ordinal(Int: type) type { | ||
| 20 | comptime assert(@typeInfo(Int).Int.signedness == .unsigned); | ||
| 21 | return enum(Int) { | ||
| 22 | _, | ||
| 23 | pub fn fromZeroBased(int: Int) @This() { | ||
| 24 | assert(int != std.math.maxInt(Int)); | ||
| 25 | return @enumFromInt(int); | ||
| 26 | } | ||
| 27 | pub fn fromOneBased(int: Int) @This() { | ||
| 28 | assert(int > 0); | ||
| 29 | return @enumFromInt(int - 1); | ||
| 30 | } | ||
| 31 | pub fn zeroBased(ord: @This()) Int { | ||
| 32 | return @intFromEnum(ord); | ||
| 33 | } | ||
| 34 | pub fn oneBased(ord: @This()) Int { | ||
| 35 | return @intFromEnum(ord) + 1; | ||
| 36 | } | ||
| 37 | }; | ||
| 38 | } | ||
| 39 | |||
| 20 | const std = @import("std"); | 40 | const std = @import("std"); |
| 41 | const assert = std.debug.assert; |