| author | |
| committer | |
| log | 74ce0c381324aeb3b73bb9928bcf433ee7e0e687 |
| tree | 50c429271ba632c4d9a6a3bda649ed95e5b9c147 |
| parent | 84de5f3373a98b314e681e6e7d5ac259071c50c4 |
| signature | Commit is signed but in an unrecognized format. |
13 files changed, 347 insertions(+), 371 deletions(-)
CHANGELOG.md+9-2| ... | @@ -1,7 +1,14 @@ | ... | @@ -1,7 +1,14 @@ |
| 1 | ## 0.1.2 | 1 | ## 0.1.2 |
| 2 | 2 | ||
| 3 | - feat: semantic analysis can return formatted errors to the user | ||
| 4 | - feat: implement basic type coersions | ||
| 5 | - feat: type-check call parameters | ||
| 6 | - feat: type-check function return types | ||
| 3 | - feat: parsing of assignments within expressions is disallowed now | 7 | - feat: parsing of assignments within expressions is disallowed now |
| 4 | - feat: debug builds have `--report-trace` to print stack traces | 8 | - feat: limit parsing to 4096 nested expressions / modules |
| 9 | - feat: added error for return outside of function | ||
| 10 | - feat: debug builds have `--report-trace` to print a stack trace per error | ||
| 11 | - fix: function arguments were not validated | ||
| 5 | - fix: unused warnings now properly work | 12 | - fix: unused warnings now properly work |
| 6 | - fix: empty files and functions no longer crash | 13 | - fix: empty files and functions no longer crash |
| 7 | 14 | ||
| ... | @@ -16,4 +23,4 @@ | ... | @@ -16,4 +23,4 @@ |
| 16 | 23 | ||
| 17 | ## 0.1.0 | 24 | ## 0.1.0 |
| 18 | 25 | ||
| 19 | initial demo of compiler pipeline in zig. | 26 | initial demo of compiler pipeline |
README.md+5-2| ... | @@ -1,4 +1,4 @@ | ... | @@ -1,4 +1,4 @@ |
| 1 | # Compiler | 1 | # New Language Project |
| 2 | 2 | ||
| 3 | This language is a mix of features from JavaScript, Rust, and Zig. Some notable features carried over from each include: | 3 | This language is a mix of features from JavaScript, Rust, and Zig. Some notable features carried over from each include: |
| 4 | 4 | ||
| ... | @@ -8,7 +8,7 @@ This language is a mix of features from JavaScript, Rust, and Zig. Some notable | ... | @@ -8,7 +8,7 @@ This language is a mix of features from JavaScript, Rust, and Zig. Some notable |
| 8 | 8 | ||
| 9 | ## Standard Library | 9 | ## Standard Library |
| 10 | 10 | ||
| 11 | Currently, there is no standard library. One will be added later. | 11 | Currently, there is no standard library. One will be introduced later. |
| 12 | 12 | ||
| 13 | ## Hello World | 13 | ## Hello World |
| 14 | 14 | ||
| ... | @@ -77,3 +77,6 @@ var number = 0; // `number` is a `float`, but not explicit | ... | @@ -77,3 +77,6 @@ var number = 0; // `number` is a `float`, but not explicit |
| 77 | var number: int = 0; // `number` is `int` | 77 | var number: int = 0; // `number` is `int` |
| 78 | var number: float = 0; // `number` is `float` | 78 | var number: float = 0; // `number` is `float` |
| 79 | ``` | 79 | ``` |
| 80 | |||
| 81 | ## Functions | ||
| 82 |
demo.ix deleted-1| ... | @@ -1 +0,0 @@ | ||
| 1 | let x: int = 1.5; | ||
notes deleted-19| ... | @@ -1,19 +0,0 @@ | ||
| 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+1-1| ... | @@ -235,7 +235,7 @@ pub const State = struct { | ... | @@ -235,7 +235,7 @@ pub 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, func.ty); | 238 | try s.dumpValue(w, func.ty.value()); |
| 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); |
src/compiler/Ast.zig-85| ... | @@ -520,91 +520,6 @@ pub fn nodeToken(ast: Ast, node: NodeIndex) TokenIndex { | ... | @@ -520,91 +520,6 @@ pub fn nodeToken(ast: Ast, node: NodeIndex) TokenIndex { |
| 520 | return ast.nodes.items(.main_token)[node]; | 520 | return ast.nodes.items(.main_token)[node]; |
| 521 | } | 521 | } |
| 522 | 522 | ||
| 523 | // pub fn operandNode(ast: Ast, node: NodeIndex, operand: OperandId) NodeIndex { | ||
| 524 | // if (operand == .main_node) return node; | ||
| 525 | |||
| 526 | // switch (ast.nodeTag(node)) { | ||
| 527 | // .root => unreachable, | ||
| 528 | // .block_void => unreachable, | ||
| 529 | // .block_implicit_return => unreachable, | ||
| 530 | // .var_decl, | ||
| 531 | // => return switch (operand) { | ||
| 532 | // .type => ast.nodeData(node).var_decl.type.unwrap().?, | ||
| 533 | // .initializer => ast.nodeData(node).var_decl.init, | ||
| 534 | // else => unreachable, | ||
| 535 | // }, | ||
| 536 | |||
| 537 | // .label, | ||
| 538 | // .group, | ||
| 539 | // .negate, | ||
| 540 | // .bit_not, | ||
| 541 | // .bool_not, | ||
| 542 | // .@"comptime", | ||
| 543 | // => return switch (operand) { | ||
| 544 | // .base => ast.nodeData(node).un.expr, | ||
| 545 | // else => unreachable, // Invalid unary operand | ||
| 546 | // }, | ||
| 547 | |||
| 548 | // .add, | ||
| 549 | // .sub, | ||
| 550 | // .mul, | ||
| 551 | // .div, | ||
| 552 | // .rem, | ||
| 553 | // .pow, | ||
| 554 | // .@"and", | ||
| 555 | // .@"or", | ||
| 556 | // .bit_and, | ||
| 557 | // .bit_or, | ||
| 558 | // .bit_xor, | ||
| 559 | // .shl, | ||
| 560 | // .shr, | ||
| 561 | // .eq, | ||
| 562 | // .ne, | ||
| 563 | // .lt, | ||
| 564 | // .le, | ||
| 565 | // .gt, | ||
| 566 | // .ge, | ||
| 567 | // .assign, | ||
| 568 | // .add_assign, | ||
| 569 | // .sub_assign, | ||
| 570 | // .mul_assign, | ||
| 571 | // .div_assign, | ||
| 572 | // .rem_assign, | ||
| 573 | // .pow_assign, | ||
| 574 | // .and_assign, | ||
| 575 | // .or_assign, | ||
| 576 | // .bit_and_assign, | ||
| 577 | // .bit_or_assign, | ||
| 578 | // .bit_xor_assign, | ||
| 579 | // .shl_assign, | ||
| 580 | // .shr_assign, | ||
| 581 | // => { | ||
| 582 | // const bin = ast.nodeData(node).bin; | ||
| 583 | // return switch (operand) { | ||
| 584 | // .lhs => bin.lhs, | ||
| 585 | // .rhs => bin.rhs, | ||
| 586 | // else => unreachable, // Not a valid operand for binary node | ||
| 587 | // }; | ||
| 588 | // }, | ||
| 589 | |||
| 590 | // .fn_decl, | ||
| 591 | // .param_decl, | ||
| 592 | // .id, | ||
| 593 | // .number_int, | ||
| 594 | // .number_float, | ||
| 595 | // .string, | ||
| 596 | // .multiline_string, | ||
| 597 | // .call, | ||
| 598 | // .builtin_call, | ||
| 599 | // .@"if", | ||
| 600 | // .field, | ||
| 601 | // .index, | ||
| 602 | // .@"return", | ||
| 603 | // .@"break", | ||
| 604 | // => |tag| std.debug.panic("TODO: operandNode .{s}", .{@tagName(tag)}), | ||
| 605 | // } | ||
| 606 | // } | ||
| 607 | |||
| 608 | pub fn fullFnDecl(ast: Ast, node: NodeIndex) full.FnDecl { | 523 | pub fn fullFnDecl(ast: Ast, node: NodeIndex) full.FnDecl { |
| 609 | const tok_tags = ast.tokens.items(.tag); | 524 | const tok_tags = ast.tokens.items(.tag); |
| 610 | 525 |
src/compiler/Comp.zig+2-2| ... | @@ -122,7 +122,7 @@ pub const File = struct { | ... | @@ -122,7 +122,7 @@ pub const File = struct { |
| 122 | return loaded_source; | 122 | return loaded_source; |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | const GetAstError = GetSourceError || Parse.Error; | 125 | pub const GetAstError = GetSourceError || Parse.Error; |
| 126 | 126 | ||
| 127 | pub fn getAst(file: *File, comp: *Comp) GetAstError!Ast { | 127 | pub fn getAst(file: *File, comp: *Comp) GetAstError!Ast { |
| 128 | if (file.ast) |ast| { | 128 | if (file.ast) |ast| { |
| ... | @@ -155,7 +155,7 @@ pub const File = struct { | ... | @@ -155,7 +155,7 @@ pub const File = struct { |
| 155 | return ast; | 155 | return ast; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | const GetTegError = GetAstError || Transform.Error; | 158 | pub const GetTegError = GetAstError || Transform.Error; |
| 159 | 159 | ||
| 160 | pub fn getTeg(file: *File, comp: *Comp, fail_report: *Report) GetTegError!Teg { | 160 | pub fn getTeg(file: *File, comp: *Comp, fail_report: *Report) GetTegError!Teg { |
| 161 | if (file.teg) |teg| { | 161 | if (file.teg) |teg| { |
src/compiler/InternPool.zig+66-8| ... | @@ -137,7 +137,7 @@ pub const Tag = enum(u8) { | ... | @@ -137,7 +137,7 @@ pub const Tag = enum(u8) { |
| 137 | pub const FuncDecl = struct { | 137 | pub const FuncDecl = struct { |
| 138 | analysis: FuncAnalysis, | 138 | analysis: FuncAnalysis, |
| 139 | owner_decl: DeclIndex, | 139 | owner_decl: DeclIndex, |
| 140 | ty: Value, | 140 | ty: Type, |
| 141 | teg_body_inst: TrackedInst.Index, | 141 | teg_body_inst: TrackedInst.Index, |
| 142 | }; | 142 | }; |
| 143 | 143 | ||
| ... | @@ -252,8 +252,7 @@ pub const Value = enum(u32) { | ... | @@ -252,8 +252,7 @@ pub const Value = enum(u32) { |
| 252 | .int32 => .int32, | 252 | .int32 => .int32, |
| 253 | .float => .float, | 253 | .float => .float, |
| 254 | .string => .string, | 254 | .string => .string, |
| 255 | 255 | .func => value.toKey(ip).func.ty, | |
| 256 | .func => @panic("TODO"), | ||
| 257 | }; | 256 | }; |
| 258 | } | 257 | } |
| 259 | 258 | ||
| ... | @@ -274,6 +273,13 @@ pub const Value = enum(u32) { | ... | @@ -274,6 +273,13 @@ pub const Value = enum(u32) { |
| 274 | }; | 273 | }; |
| 275 | } | 274 | } |
| 276 | 275 | ||
| 276 | pub fn toTypeUnsafe(value: Value, proof_ip: *const InternPool) Type { | ||
| 277 | if (std.debug.runtime_safety) { | ||
| 278 | return value.toType(proof_ip).?; | ||
| 279 | } | ||
| 280 | return @enumFromInt(@intFromEnum(value)); | ||
| 281 | } | ||
| 282 | |||
| 277 | pub fn asString(val: Value, ip: *const InternPool) InternPool.String.WithLen { | 283 | pub fn asString(val: Value, ip: *const InternPool) InternPool.String.WithLen { |
| 278 | return val.valueData(ip, .string).get(ip); | 284 | return val.valueData(ip, .string).get(ip); |
| 279 | } | 285 | } |
| ... | @@ -298,6 +304,12 @@ pub const Type = enum(u32) { | ... | @@ -298,6 +304,12 @@ pub const Type = enum(u32) { |
| 298 | void = @intFromEnum(Value.void), | 304 | void = @intFromEnum(Value.void), |
| 299 | _, | 305 | _, |
| 300 | 306 | ||
| 307 | // Restricted version of `InternPool.Tag` | ||
| 308 | pub const Tag = enum(u32) { | ||
| 309 | type_function = @intFromEnum(InternPool.Tag.type_function), | ||
| 310 | simple_type = @intFromEnum(InternPool.Tag.simple_type), | ||
| 311 | }; | ||
| 312 | |||
| 301 | /// An array of `Index` existing within the `extra` array. | 313 | /// An array of `Index` existing within the `extra` array. |
| 302 | /// This type exists to provide a struct with lifetime that is | 314 | /// This type exists to provide a struct with lifetime that is |
| 303 | /// not invalidated when items are added to the `InternPool`. | 315 | /// not invalidated when items are added to the `InternPool`. |
| ... | @@ -314,9 +326,59 @@ pub const Type = enum(u32) { | ... | @@ -314,9 +326,59 @@ pub const Type = enum(u32) { |
| 314 | return @enumFromInt(@intFromEnum(ty)); | 326 | return @enumFromInt(@intFromEnum(ty)); |
| 315 | } | 327 | } |
| 316 | 328 | ||
| 329 | pub fn tag(ty: Type, ip: *const InternPool) Type.Tag { | ||
| 330 | return @enumFromInt(@intFromEnum(ty.value().valueTag(ip))); | ||
| 331 | } | ||
| 332 | |||
| 333 | pub fn toFunctionPrototype(ty: Type, ip: *const InternPool) ?Key.TypeFunction { | ||
| 334 | if (ty.tag(ip) != .type_function) return null; | ||
| 335 | return ip.indexToKey(ty.value()).type_function; | ||
| 336 | } | ||
| 337 | |||
| 338 | pub fn displayName(ty: Type, ip: *const InternPool) std.fmt.Formatter(formatDisplayName) { | ||
| 339 | return .{ .data = .{ .type = ty, .ip = ip } }; | ||
| 340 | } | ||
| 341 | |||
| 317 | pub fn dump(ty: Type, ip: *const InternPool) std.fmt.Formatter(Value.formatValue) { | 342 | pub fn dump(ty: Type, ip: *const InternPool) std.fmt.Formatter(Value.formatValue) { |
| 318 | return ty.value().dump(ip); | 343 | return ty.value().dump(ip); |
| 319 | } | 344 | } |
| 345 | |||
| 346 | fn formatDisplayName( | ||
| 347 | ctx: struct { type: Type, ip: *const InternPool }, | ||
| 348 | comptime _: []const u8, | ||
| 349 | _: std.fmt.FormatOptions, | ||
| 350 | writer: anytype, | ||
| 351 | ) !void { | ||
| 352 | const ty = ctx.type; | ||
| 353 | const ip = ctx.ip; | ||
| 354 | |||
| 355 | switch (ty) { | ||
| 356 | .@"opaque" => return try writer.writeAll("opaque"), | ||
| 357 | .bool => return try writer.writeAll("bool"), | ||
| 358 | .int32 => return try writer.writeAll("int"), | ||
| 359 | .float => return try writer.writeAll("float"), | ||
| 360 | .string => return try writer.writeAll("string"), | ||
| 361 | .noreturn => return try writer.writeAll("noreturn"), | ||
| 362 | .type => return try writer.writeAll("type"), | ||
| 363 | .numeric_literal => return try writer.writeAll("numeric literal"), | ||
| 364 | .void => return try writer.writeAll("void"), | ||
| 365 | else => {}, | ||
| 366 | } | ||
| 367 | |||
| 368 | switch (ty.tag(ip)) { | ||
| 369 | .simple_type => unreachable, // all simple types are already printed | ||
| 370 | .type_function => { | ||
| 371 | const type_function = ty.toFunctionPrototype(ip).?; | ||
| 372 | try writer.writeAll("fn("); | ||
| 373 | for (type_function.param_types, 0..) |param, i| { | ||
| 374 | if (i != 0) try writer.writeAll(", "); | ||
| 375 | try writer.print("{}", .{param.displayName(ip)}); | ||
| 376 | } | ||
| 377 | try writer.writeAll(") -> "); | ||
| 378 | try writer.print("{}", .{type_function.return_type.displayName(ip)}); | ||
| 379 | }, | ||
| 380 | } | ||
| 381 | } | ||
| 320 | }; | 382 | }; |
| 321 | 383 | ||
| 322 | pub const static_keys = [_]Key{ | 384 | pub const static_keys = [_]Key{ |
| ... | @@ -386,10 +448,6 @@ pub const String = enum(u32) { | ... | @@ -386,10 +448,6 @@ pub const String = enum(u32) { |
| 386 | pub fn tryToNullTerminatedString(string: WithLen, ip: *InternPool, gpa: Allocator) !NullTerminatedString { | 448 | pub fn tryToNullTerminatedString(string: WithLen, ip: *InternPool, gpa: Allocator) !NullTerminatedString { |
| 387 | return string.string.tryToNullTerminatedString(string.len, ip, gpa); | 449 | return string.string.tryToNullTerminatedString(string.len, ip, gpa); |
| 388 | } | 450 | } |
| 389 | |||
| 390 | pub fn toNullTerminatedString(string: WithLen, ip: *const InternPool) NullTerminatedString { | ||
| 391 | return string.string.tryToNullTerminatedString(string.len, ip); | ||
| 392 | } | ||
| 393 | }; | 451 | }; |
| 394 | 452 | ||
| 395 | pub fn toSlice(string: String, len: u64, ip: *const InternPool) []const u8 { | 453 | pub fn toSlice(string: String, len: u64, ip: *const InternPool) []const u8 { |
| ... | @@ -678,7 +736,7 @@ pub const Key = union(enum) { | ... | @@ -678,7 +736,7 @@ pub const Key = union(enum) { |
| 678 | }; | 736 | }; |
| 679 | 737 | ||
| 680 | pub const Func = struct { | 738 | pub const Func = struct { |
| 681 | ty: Value, | 739 | ty: Type, |
| 682 | owner_decl: DeclIndex, | 740 | owner_decl: DeclIndex, |
| 683 | teg_body_inst: TrackedInst.Index, | 741 | teg_body_inst: TrackedInst.Index, |
| 684 | 742 |
src/compiler/Parse.zig+40-1| ... | @@ -12,6 +12,11 @@ scratch: ArrayListUnmanaged(NodeIndex) = .{}, | ... | @@ -12,6 +12,11 @@ scratch: ArrayListUnmanaged(NodeIndex) = .{}, |
| 12 | 12 | ||
| 13 | ast_error: ?AstError.WithTrace = null, | 13 | ast_error: ?AstError.WithTrace = null, |
| 14 | 14 | ||
| 15 | depth: u32 = 0, | ||
| 16 | |||
| 17 | /// Instead of implementing a non-recursive parser, the stack size is limited by this constant. | ||
| 18 | const depth_limit = 4096; | ||
| 19 | |||
| 15 | pub fn parse(gpa: std.mem.Allocator, source: [:0]const u8, ast_error: *AstError.WithTrace) Parse.Error!Ast { | 20 | pub fn parse(gpa: std.mem.Allocator, source: [:0]const u8, ast_error: *AstError.WithTrace) Parse.Error!Ast { |
| 16 | var err_byte: ByteOffset = 0; | 21 | var err_byte: ByteOffset = 0; |
| 17 | var tokens = Tokenizer.tokenize( | 22 | var tokens = Tokenizer.tokenize( |
| ... | @@ -129,6 +134,8 @@ pub const AstError = union(enum) { | ... | @@ -129,6 +134,8 @@ pub const AstError = union(enum) { |
| 129 | expected: ExpectedContext, | 134 | expected: ExpectedContext, |
| 130 | got: Token, | 135 | got: Token, |
| 131 | }, | 136 | }, |
| 137 | /// Went past depth maximum | ||
| 138 | depth_limit: Token, | ||
| 132 | 139 | ||
| 133 | pub fn toReport(err: AstError, comp: *Comp, file: *Comp.File, trace: Report.DebugStoredTrace) !Report { | 140 | pub fn toReport(err: AstError, comp: *Comp, file: *Comp.File, trace: Report.DebugStoredTrace) !Report { |
| 134 | return (Report.Err{ .ast = err }).toReport(comp, file, trace); | 141 | return (Report.Err{ .ast = err }).toReport(comp, file, trace); |
| ... | @@ -165,6 +172,9 @@ pub const AstError = union(enum) { | ... | @@ -165,6 +172,9 @@ pub const AstError = union(enum) { |
| 165 | data.got.tag.description(), | 172 | data.got.tag.description(), |
| 166 | }); | 173 | }); |
| 167 | }, | 174 | }, |
| 175 | .depth_limit => |data| { | ||
| 176 | try ctx.msg(.{ .token_stored = data }, "syntax tree is nested too deeply (limit: {d})", .{depth_limit}); | ||
| 177 | }, | ||
| 168 | } | 178 | } |
| 169 | } | 179 | } |
| 170 | 180 | ||
| ... | @@ -200,6 +210,12 @@ pub fn parseRoot(p: *Parse) Error!void { | ... | @@ -200,6 +210,12 @@ pub fn parseRoot(p: *Parse) Error!void { |
| 200 | } | 210 | } |
| 201 | 211 | ||
| 202 | fn parseModuleMembers(p: *Parse) Error!SubList { | 212 | fn parseModuleMembers(p: *Parse) Error!SubList { |
| 213 | p.depth += 1; | ||
| 214 | defer p.depth -= 1; | ||
| 215 | if (p.depth > depth_limit) { | ||
| 216 | return p.fail(.{ .depth_limit = p.fullToken(p.pos) }); | ||
| 217 | } | ||
| 218 | |||
| 203 | const trace = t.trace(@src()); | 219 | const trace = t.trace(@src()); |
| 204 | defer trace.end(); | 220 | defer trace.end(); |
| 205 | 221 | ||
| ... | @@ -642,7 +658,24 @@ const Operator = enum(u8) { | ... | @@ -642,7 +658,24 @@ const Operator = enum(u8) { |
| 642 | } | 658 | } |
| 643 | 659 | ||
| 644 | pub fn isAssign(op: Operator) bool { | 660 | pub fn isAssign(op: Operator) bool { |
| 645 | return @intFromEnum(op) >= @intFromEnum(Operator.assign); | 661 | return switch (op) { |
| 662 | .assign, | ||
| 663 | .add_assign, | ||
| 664 | .sub_assign, | ||
| 665 | .mul_assign, | ||
| 666 | .div_assign, | ||
| 667 | .rem_assign, | ||
| 668 | .pow_assign, | ||
| 669 | .and_assign, | ||
| 670 | .or_assign, | ||
| 671 | .bit_and_assign, | ||
| 672 | .bit_or_assign, | ||
| 673 | .bit_xor_assign, | ||
| 674 | .shl_assign, | ||
| 675 | .shr_assign, | ||
| 676 | => true, | ||
| 677 | else => false, | ||
| 678 | }; | ||
| 646 | } | 679 | } |
| 647 | }; | 680 | }; |
| 648 | 681 | ||
| ... | @@ -650,6 +683,12 @@ fn parseExpression(p: *Parse, allow_assign_operators: bool) Error!NodeIndex { | ... | @@ -650,6 +683,12 @@ fn parseExpression(p: *Parse, allow_assign_operators: bool) Error!NodeIndex { |
| 650 | const trace = t.trace(@src()); | 683 | const trace = t.trace(@src()); |
| 651 | defer trace.end(); | 684 | defer trace.end(); |
| 652 | 685 | ||
| 686 | p.depth += 1; | ||
| 687 | defer p.depth -= 1; | ||
| 688 | if (p.depth > depth_limit) { | ||
| 689 | return p.fail(.{ .depth_limit = p.fullToken(p.pos) }); | ||
| 690 | } | ||
| 691 | |||
| 653 | assert(p.isExpressionStart()); | 692 | assert(p.isExpressionStart()); |
| 654 | 693 | ||
| 655 | // These unary operators are greedy, so handle them first. | 694 | // These unary operators are greedy, so handle them first. |
src/compiler/Report.zig+78-20| ... | @@ -64,16 +64,6 @@ pub const Err = union(enum) { | ... | @@ -64,16 +64,6 @@ pub const Err = union(enum) { |
| 64 | ); | 64 | ); |
| 65 | } | 65 | } |
| 66 | }, | 66 | }, |
| 67 | invalid_discard: struct { | ||
| 68 | node: NodeIndex, | ||
| 69 | |||
| 70 | fn build(data: @This(), ctx: *MsgContext) !void { | ||
| 71 | try ctx.msgToken(ctx.ast.idToken(data.node), "local cannot be named \"_\"", .{}); | ||
| 72 | try ctx.msgAlone("to discard this value, remove '{s}'", .{ | ||
| 73 | ctx.ast.tokenSlice(ctx.ast.nodeToken(data.node)), | ||
| 74 | }); | ||
| 75 | } | ||
| 76 | }, | ||
| 77 | duplicate_function: struct { | 67 | duplicate_function: struct { |
| 78 | node: NodeIndex, | 68 | node: NodeIndex, |
| 79 | prev: NodeIndex, | 69 | prev: NodeIndex, |
| ... | @@ -106,7 +96,7 @@ pub const Err = union(enum) { | ... | @@ -106,7 +96,7 @@ pub const Err = union(enum) { |
| 106 | fn build(data: @This(), ctx: *MsgContext) !void { | 96 | fn build(data: @This(), ctx: *MsgContext) !void { |
| 107 | try ctx.msgNode( | 97 | try ctx.msgNode( |
| 108 | data.node, | 98 | data.node, |
| 109 | "return cannot be used here", | 99 | "return cannot be used outside of a function body", |
| 110 | .{}, | 100 | .{}, |
| 111 | ); | 101 | ); |
| 112 | } | 102 | } |
| ... | @@ -149,7 +139,34 @@ pub const Err = union(enum) { | ... | @@ -149,7 +139,34 @@ pub const Err = union(enum) { |
| 149 | 139 | ||
| 150 | fn build(data: @This(), ctx: *MsgContext) !void { | 140 | fn build(data: @This(), ctx: *MsgContext) !void { |
| 151 | const node = try data.src.get(ctx); | 141 | const node = try data.src.get(ctx); |
| 152 | try ctx.msgNode(node, "stinky", .{}); | 142 | try ctx.msgNode(node, "expected \"{s}\", got \"{s}\"", .{ |
| 143 | data.to.displayName(&ctx.comp.intern_pool), | ||
| 144 | data.from.displayName(&ctx.comp.intern_pool), | ||
| 145 | }); | ||
| 146 | } | ||
| 147 | }, | ||
| 148 | call_non_function: struct { | ||
| 149 | call: LazyNode, | ||
| 150 | ty: Type, | ||
| 151 | |||
| 152 | fn build(data: @This(), ctx: *MsgContext) !void { | ||
| 153 | const node = try data.call.get(ctx); | ||
| 154 | try ctx.msgNode(node, "\"{s}\" is not callable", .{ | ||
| 155 | data.ty.displayName(&ctx.comp.intern_pool), | ||
| 156 | }); | ||
| 157 | } | ||
| 158 | }, | ||
| 159 | call_mismatch_args: struct { | ||
| 160 | call: LazyNode, | ||
| 161 | actual: u32, | ||
| 162 | expected: u32, | ||
| 163 | |||
| 164 | fn build(data: @This(), ctx: *MsgContext) !void { | ||
| 165 | const node = try data.call.get(ctx); | ||
| 166 | try ctx.msgNode(node, "function expected {d} arguments, recieved {d}", .{ | ||
| 167 | data.expected, | ||
| 168 | data.actual, | ||
| 169 | }); | ||
| 153 | } | 170 | } |
| 154 | }, | 171 | }, |
| 155 | }; | 172 | }; |
| ... | @@ -184,6 +201,20 @@ pub const Warn = union(enum) { | ... | @@ -184,6 +201,20 @@ pub const Warn = union(enum) { |
| 184 | try ctx.msgAlone("if this was intentional, discard it with \"_ = {s};\"", .{id}); | 201 | try ctx.msgAlone("if this was intentional, discard it with \"_ = {s};\"", .{id}); |
| 185 | } | 202 | } |
| 186 | }, | 203 | }, |
| 204 | invalid_discard: struct { | ||
| 205 | node: NodeIndex, | ||
| 206 | |||
| 207 | fn build(data: @This(), ctx: *MsgContext) !void { | ||
| 208 | try ctx.msgToken(ctx.ast.nodeToken(data.node), "\"let\" is not required for a discard", .{}); | ||
| 209 | } | ||
| 210 | }, | ||
| 211 | dangling_identifier: struct { | ||
| 212 | node: NodeIndex, | ||
| 213 | |||
| 214 | fn build(data: @This(), ctx: *MsgContext) !void { | ||
| 215 | try ctx.msgToken(ctx.ast.nodeToken(data.node), "dangling identifier does nothing", .{}); | ||
| 216 | } | ||
| 217 | }, | ||
| 187 | numeric_int_var_ambiguity: struct { | 218 | numeric_int_var_ambiguity: struct { |
| 188 | node: LazyNode, | 219 | node: LazyNode, |
| 189 | 220 | ||
| ... | @@ -243,7 +274,7 @@ pub const DebugStoredTrace = if (builtin.mode == .Debug) | ... | @@ -243,7 +274,7 @@ pub const DebugStoredTrace = if (builtin.mode == .Debug) |
| 243 | StoredTrace | 274 | StoredTrace |
| 244 | else | 275 | else |
| 245 | struct { | 276 | struct { |
| 246 | pub fn capture() @This() { | 277 | pub fn capture(_: ?usize) @This() { |
| 247 | return .{}; | 278 | return .{}; |
| 248 | } | 279 | } |
| 249 | 280 | ||
| ... | @@ -289,7 +320,7 @@ pub fn deinit(report: Report, gpa: Allocator) void { | ... | @@ -289,7 +320,7 @@ pub fn deinit(report: Report, gpa: Allocator) void { |
| 289 | } | 320 | } |
| 290 | 321 | ||
| 291 | pub fn dumpToWriter(report: Report, comp: *Comp, writer: anytype, tty: std.io.tty.Config) !void { | 322 | pub fn dumpToWriter(report: Report, comp: *Comp, writer: anytype, tty: std.io.tty.Config) !void { |
| 292 | try writer.print("{d} errors, {d} warnings\n", .{ report.errors.len, report.warnings.len }); | 323 | // try writer.print("{d} errors, {d} warnings\n", .{ report.errors.len, report.warnings.len }); |
| 293 | for (report.errors) |item| { | 324 | for (report.errors) |item| { |
| 294 | try report.formatItem(item, .@"error", comp, writer, tty); | 325 | try report.formatItem(item, .@"error", comp, writer, tty); |
| 295 | } | 326 | } |
| ... | @@ -653,14 +684,16 @@ pub const LazyNode = struct { | ... | @@ -653,14 +684,16 @@ pub const LazyNode = struct { |
| 653 | 684 | ||
| 654 | const node_offset = teg.instNodeOffset(lazy.inst); | 685 | const node_offset = teg.instNodeOffset(lazy.inst); |
| 655 | 686 | ||
| 656 | const base_node: NodeIndex = @intCast(node_offset - teg_decl.src_node); | 687 | const base_node: NodeIndex = @intCast(teg_decl.src_node + node_offset); |
| 657 | if (lazy.operand == .main_node) | 688 | if (lazy.operand == .main_node) |
| 658 | return base_node; | 689 | return base_node; |
| 659 | 690 | ||
| 660 | const data = ctx.ast.nodeData(base_node); | 691 | const data = ctx.ast.nodeData(base_node); |
| 661 | 692 | ||
| 693 | const node_tag = ctx.ast.nodeTag(base_node); | ||
| 694 | |||
| 662 | switch (teg.instTag(lazy.inst)) { | 695 | switch (teg.instTag(lazy.inst)) { |
| 663 | .as => switch (ctx.ast.nodeTag(base_node)) { | 696 | .as => switch (node_tag) { |
| 664 | .var_decl => { | 697 | .var_decl => { |
| 665 | switch (lazy.operand) { | 698 | switch (lazy.operand) { |
| 666 | .rhs => return data.var_decl.init, | 699 | .rhs => return data.var_decl.init, |
| ... | @@ -669,6 +702,23 @@ pub const LazyNode = struct { | ... | @@ -669,6 +702,23 @@ pub const LazyNode = struct { |
| 669 | }, | 702 | }, |
| 670 | else => {}, | 703 | else => {}, |
| 671 | }, | 704 | }, |
| 705 | .call => switch (node_tag) { | ||
| 706 | .call => switch (lazy.operand) { | ||
| 707 | .operand => return data.call.base, | ||
| 708 | else => |op| return ctx.ast.extraData(data.call.extra, Ast.Call) | ||
| 709 | .args.slice(ctx.ast)[op.getArgId()], | ||
| 710 | }, | ||
| 711 | else => {}, | ||
| 712 | }, | ||
| 713 | .@"break" => switch (node_tag) { | ||
| 714 | .@"return" => return data.@"return".expr.unwrap().?, | ||
| 715 | .@"break" => return data.@"break".value.unwrap().?, | ||
| 716 | .block_implicit_return => { | ||
| 717 | const statements = ctx.ast.nodeStatements(base_node); | ||
| 718 | return statements[statements.len - 1]; | ||
| 719 | }, | ||
| 720 | else => return base_node, | ||
| 721 | }, | ||
| 672 | else => {}, | 722 | else => {}, |
| 673 | } | 723 | } |
| 674 | 724 | ||
| ... | @@ -687,14 +737,22 @@ pub const Operand = enum(u32) { | ... | @@ -687,14 +737,22 @@ pub const Operand = enum(u32) { |
| 687 | main_node = 0, | 737 | main_node = 0, |
| 688 | /// Base of a call, field, or operand to a unary instruction | 738 | /// Base of a call, field, or operand to a unary instruction |
| 689 | operand = 1, | 739 | operand = 1, |
| 740 | /// Return type of a function declaration or lambda node | ||
| 741 | return_type = 2, | ||
| 690 | /// Left hand side of a binary instruction | 742 | /// Left hand side of a binary instruction |
| 691 | lhs, | 743 | lhs = 4, |
| 692 | /// Right hand side of a binary instruction | 744 | /// Right hand side of a binary instruction |
| 693 | rhs, | 745 | rhs = 5, |
| 694 | 746 | ||
| 695 | /// An argument of a call node | 747 | /// One of: |
| 748 | /// - An argument of a .call node | ||
| 749 | /// - A parameter of a .fn_decl node | ||
| 696 | pub fn argument(id: u32) Operand { | 750 | pub fn argument(id: u32) Operand { |
| 697 | return @enumFromInt(id + 2); | 751 | return @enumFromInt(id + 5); |
| 752 | } | ||
| 753 | |||
| 754 | fn getArgId(op: Operand) u32 { | ||
| 755 | return @intFromEnum(op) - 5; | ||
| 698 | } | 756 | } |
| 699 | }; | 757 | }; |
| 700 | 758 |
src/compiler/Sema.zig+120-111| ... | @@ -23,14 +23,20 @@ report: Report.Builder = undefined, | ... | @@ -23,14 +23,20 @@ report: Report.Builder = undefined, |
| 23 | air_instructions: std.MultiArrayList(Air.Inst) = .{}, | 23 | air_instructions: std.MultiArrayList(Air.Inst) = .{}, |
| 24 | air_extra: dod.ExtraStore(.air, .@"var") = .{}, | 24 | air_extra: dod.ExtraStore(.air, .@"var") = .{}, |
| 25 | 25 | ||
| 26 | temp_result_map: std.AutoArrayHashMapUnmanaged(Teg.Inst.Index, Type) = .{}, | ||
| 27 | |||
| 26 | pub const Error = error{ | 28 | pub const Error = error{ |
| 27 | /// Analysis has failed, see error list | 29 | /// Analysis has failed, see error list |
| 28 | AnalysisFail, | 30 | AnalysisFail, |
| 29 | /// This analysis is waiting on other dependencies to finish | 31 | // This analysis is waiting on other dependencies to finish |
| 30 | Interrupt, | 32 | // Interrupt, |
| 33 | |||
| 34 | // TODO: add handling of this | ||
| 35 | TooManyValues, | ||
| 36 | HasNulls, | ||
| 31 | 37 | ||
| 32 | OutOfMemory, | 38 | OutOfMemory, |
| 33 | }; | 39 | } || Comp.File.GetTegError; |
| 34 | 40 | ||
| 35 | /// Instead of using a hash map for this, just pre-allocate a list long enough to hold everything. | 41 | /// Instead of using a hash map for this, just pre-allocate a list long enough to hold everything. |
| 36 | /// This is fine because all instructions are going to be adacent in a single declaration. | 42 | /// This is fine because all instructions are going to be adacent in a single declaration. |
| ... | @@ -104,6 +110,7 @@ pub fn deinit(s: *Sema) void { | ... | @@ -104,6 +110,7 @@ pub fn deinit(s: *Sema) void { |
| 104 | s.scratch.deinit(s.arena); | 110 | s.scratch.deinit(s.arena); |
| 105 | s.air_extra.deinit(s.gpa); | 111 | s.air_extra.deinit(s.gpa); |
| 106 | s.air_instructions.deinit(s.gpa); | 112 | s.air_instructions.deinit(s.gpa); |
| 113 | s.temp_result_map.deinit(s.arena); | ||
| 107 | } | 114 | } |
| 108 | 115 | ||
| 109 | pub fn finalize(s: *Sema) !void { | 116 | pub fn finalize(s: *Sema) !void { |
| ... | @@ -121,7 +128,7 @@ pub fn finalize(s: *Sema) !void { | ... | @@ -121,7 +128,7 @@ pub fn finalize(s: *Sema) !void { |
| 121 | // --- analyze functions --- | 128 | // --- analyze functions --- |
| 122 | 129 | ||
| 123 | /// This is the entrypoint to semantic analysis: It all starts at a declaration. | 130 | /// This is the entrypoint to semantic analysis: It all starts at a declaration. |
| 124 | pub fn analyzeDeclaration(s: *Sema) anyerror!Value { | 131 | pub fn analyzeDeclaration(s: *Sema) Error!Value { |
| 125 | const t = tracer.trace(@src()); | 132 | const t = tracer.trace(@src()); |
| 126 | defer t.end(); | 133 | defer t.end(); |
| 127 | 134 | ||
| ... | @@ -137,27 +144,43 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value { | ... | @@ -137,27 +144,43 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value { |
| 137 | defer s.gpa.free(s.params); | 144 | defer s.gpa.free(s.params); |
| 138 | 145 | ||
| 139 | for (fn_decl.params.slice(&s.code), 0..) |param, i| { | 146 | for (fn_decl.params.slice(&s.code), 0..) |param, i| { |
| 140 | s.params[i] = (try s.resolveRefComptime(param)).toType(s.ip).?; | 147 | s.params[i] = try s.resolveType( |
| 148 | s.inst_map.start.op(Report.Operand.argument(@intCast(i))), | ||
| 149 | param, | ||
| 150 | ); | ||
| 141 | } | 151 | } |
| 142 | 152 | ||
| 143 | const return_type = (try s.resolveRefComptime(fn_decl.return_type)).toType(s.ip).?; | 153 | const return_type = try s.resolveType( |
| 144 | 154 | s.inst_map.start.op(.return_type), | |
| 145 | const root_block = fn_decl.body.toIndex() orelse | 155 | fn_decl.return_type, |
| 146 | @panic("TODO: please change this to Index. Ref is not allowed here anymore"); | 156 | ); |
| 147 | 157 | ||
| 148 | _ = if (s.code.instPayload(.block, root_block).len > 0) | 158 | const root_block = fn_decl.body; |
| 149 | try s.analyzeBlock(root_block) | 159 | switch (root_block.decode()) { |
| 150 | else empty_block: { | 160 | .value => |value| { |
| 151 | var root = try s.addBlock(); | 161 | const coerced = try s.coerceValue( |
| 152 | break :empty_block (try root.finish(s, s.air_instructions.len - 1)); | 162 | s.inst_map.start.op(.operand), |
| 153 | }; | 163 | value, |
| 164 | return_type, | ||
| 165 | ); | ||
| 166 | const block = try s.addBlock(); | ||
| 167 | _ = try s.addInstRef(.@"break", .{ | ||
| 168 | .block_ref = block.block_index, | ||
| 169 | .value = coerced.toAir(), | ||
| 170 | }); | ||
| 171 | }, | ||
| 172 | .index => |index| { | ||
| 173 | try s.temp_result_map.putNoClobber(s.arena, index, return_type); | ||
| 174 | _ = try s.analyzeBlock(index); | ||
| 175 | }, | ||
| 176 | } | ||
| 154 | 177 | ||
| 155 | const func_prototype = try s.ip.get(s.gpa, .{ | 178 | const func_prototype = (try s.ip.get(s.gpa, .{ |
| 156 | .type_function = .{ | 179 | .type_function = .{ |
| 157 | .param_types = s.params, | 180 | .param_types = s.params, |
| 158 | .return_type = return_type, | 181 | .return_type = return_type, |
| 159 | }, | 182 | }, |
| 160 | }); | 183 | })).toTypeUnsafe(s.ip); |
| 161 | const value = try s.ip.get(s.gpa, .{ | 184 | const value = try s.ip.get(s.gpa, .{ |
| 162 | .func = .{ | 185 | .func = .{ |
| 163 | .ty = func_prototype, | 186 | .ty = func_prototype, |
| ... | @@ -169,7 +192,7 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value { | ... | @@ -169,7 +192,7 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value { |
| 169 | return value; | 192 | return value; |
| 170 | } | 193 | } |
| 171 | 194 | ||
| 172 | pub fn analyzeBlock(s: *Sema, in: Teg.Inst.Index) anyerror!Air.Inst.Ref { | 195 | pub fn analyzeBlock(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 173 | const t = tracer.trace(@src()); | 196 | const t = tracer.trace(@src()); |
| 174 | defer t.end(); | 197 | defer t.end(); |
| 175 | 198 | ||
| ... | @@ -224,7 +247,7 @@ fn analyzeCode(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | ... | @@ -224,7 +247,7 @@ fn analyzeCode(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { |
| 224 | return out; | 247 | return out; |
| 225 | } | 248 | } |
| 226 | 249 | ||
| 227 | fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | 250 | fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 228 | switch (s.code.instTag(in)) { | 251 | switch (s.code.instTag(in)) { |
| 229 | .string => { | 252 | .string => { |
| 230 | const string: Teg.SlicedString = s.code.instPayload(.string, in); | 253 | const string: Teg.SlicedString = s.code.instPayload(.string, in); |
| ... | @@ -236,16 +259,14 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | ... | @@ -236,16 +259,14 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { |
| 236 | }, | 259 | }, |
| 237 | .js => { | 260 | .js => { |
| 238 | const operand_ref = s.code.instData(.js, in).operand; | 261 | const operand_ref = s.code.instData(.js, in).operand; |
| 239 | const operand = try s.resolveRefComptime(operand_ref); | 262 | const operand = try s.resolveRefComptimeType(in.op(.operand), operand_ref, .string); |
| 240 | // const operand_str = try s.coerceValue(operand_ref.toIndex().?, operand, .string); | ||
| 241 | return s.addInstRef(.js_global_ref, operand.asString(s.ip)); | 263 | return s.addInstRef(.js_global_ref, operand.asString(s.ip)); |
| 242 | }, | 264 | }, |
| 243 | .field => { | 265 | .field => { |
| 244 | const field: Teg.Inst.Bin = s.code.instPayload(.field, in); | 266 | const field: Teg.Inst.Bin = s.code.instPayload(.field, in); |
| 245 | const base = try s.resolveRefRuntime(field.lhs); | 267 | const base = try s.resolveRefRuntime(field.lhs); |
| 246 | const rhs = try s.resolveRefComptime(field.rhs); | ||
| 247 | 268 | ||
| 248 | // try s.validateType(rhs.type(s.ip), .string_type); | 269 | const rhs = try s.resolveRefComptimeType(in.op(.rhs), field.rhs, .string); |
| 249 | const string = rhs.asString(s.ip); | 270 | const string = rhs.asString(s.ip); |
| 250 | 271 | ||
| 251 | const base_type = s.typeOfRef(base); | 272 | const base_type = s.typeOfRef(base); |
| ... | @@ -331,66 +352,71 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | ... | @@ -331,66 +352,71 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { |
| 331 | const brk: Teg.Inst.Break = s.code.instPayload(.@"break", in); | 352 | const brk: Teg.Inst.Break = s.code.instPayload(.@"break", in); |
| 332 | const operand = try s.resolveRefRuntime(brk.operand); | 353 | const operand = try s.resolveRefRuntime(brk.operand); |
| 333 | const block_ref = s.inst_map.get(brk.block).?.decode().index; // block ref is resolved by teg | 354 | const block_ref = s.inst_map.get(brk.block).?.decode().index; // block ref is resolved by teg |
| 355 | |||
| 356 | const coerced = if (s.temp_result_map.get(brk.block)) |ty| | ||
| 357 | try s.coerceRef(in.op(.operand), operand, ty) | ||
| 358 | else | ||
| 359 | operand; | ||
| 360 | |||
| 334 | return s.addInstRef(.@"break", .{ | 361 | return s.addInstRef(.@"break", .{ |
| 335 | .block_ref = block_ref, | 362 | .block_ref = block_ref, |
| 336 | .value = operand, | 363 | .value = coerced, |
| 337 | }); | 364 | }); |
| 338 | }, | 365 | }, |
| 339 | .call => { | 366 | .call => { |
| 340 | @panic("TODO: re-implement .call"); | 367 | const call: Teg.Inst.Call = s.code.instPayload(.call, in); |
| 341 | // const call: Teg.Inst.Call = s.code.instPayload(.call, in); | 368 | const base = try s.resolveRefRuntime(call.base); |
| 342 | // const base = try s.resolveRefRuntime(call.base); | 369 | const base_type = s.typeOfRef(base); |
| 343 | // const base_type = s.typeOfRef(base).toKey(s.ip); | ||
| 344 | |||
| 345 | // const is_opaque = base_type == .simple_type and base_type.simple_type == .@"opaque"; | ||
| 346 | |||
| 347 | // const scratch = try s.arena.alloc(Air.Inst.Ref, call.args.len); | ||
| 348 | // defer s.arena.free(scratch); | ||
| 349 | // if (!is_opaque) { | ||
| 350 | // if (base_type != .type_function) { | ||
| 351 | // std.debug.print("Attempt to call non-function {}", .{base_type}); | ||
| 352 | // return error.AnalysisFail; | ||
| 353 | // } | ||
| 354 | |||
| 355 | // const proto = base_type.type_function; | ||
| 356 | // if (proto.param_types.len != call.args.len) { | ||
| 357 | // std.debug.print("Incorrect args. Expect {d}, Got {d}", .{ | ||
| 358 | // proto.param_types.len, | ||
| 359 | // call.args.len, | ||
| 360 | // }); | ||
| 361 | // return error.AnalysisFail; | ||
| 362 | // } | ||
| 363 | |||
| 364 | // // validate function args | ||
| 365 | // for (proto.param_types, call.args.slice(&s.code), 0..) |param, arg, i| { | ||
| 366 | // const ref = try s.resolveRefRuntime(arg); | ||
| 367 | // scratch[i] = ref; | ||
| 368 | // _ = param; | ||
| 369 | // // try s.validateType( | ||
| 370 | // // Value.fromInterned(s.typeOfRef(ref)), | ||
| 371 | // // param, | ||
| 372 | // // ); | ||
| 373 | // } | ||
| 374 | // } else { | ||
| 375 | // // just copy the args in without checking | ||
| 376 | // for (call.args.slice(&s.code), 0..) |arg, i| { | ||
| 377 | // const ref = try s.resolveRefRuntime(arg); | ||
| 378 | // scratch[i] = ref; | ||
| 379 | // } | ||
| 380 | // } | ||
| 381 | 370 | ||
| 382 | // const start = s.air_extra.list.items.len; | 371 | const scratch = try s.arena.alloc(Air.Inst.Ref, call.args.len); |
| 383 | // try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch)); | 372 | defer s.arena.free(scratch); |
| 373 | if (base_type != .@"opaque") { | ||
| 374 | const proto = base_type.toFunctionPrototype(s.ip) orelse { | ||
| 375 | return s.fail(.call_non_function, .{ | ||
| 376 | .call = s.nodeLoc(in, .operand), | ||
| 377 | .ty = base_type, | ||
| 378 | }); | ||
| 379 | }; | ||
| 380 | |||
| 381 | if (proto.param_types.len != call.args.len) { | ||
| 382 | // TODO: also attempt to coerce some of the params to reveal more errors. | ||
| 383 | return s.fail(.call_mismatch_args, .{ | ||
| 384 | .call = s.nodeLoc(in, .operand), | ||
| 385 | .actual = @intCast(call.args.len), | ||
| 386 | .expected = @intCast(proto.param_types.len), | ||
| 387 | }); | ||
| 388 | } | ||
| 389 | |||
| 390 | // validate function args | ||
| 391 | for (proto.param_types, call.args.slice(&s.code), 0..) |param, arg, i| { | ||
| 392 | const ref = try s.resolveRefRuntime(arg); | ||
| 393 | const coerced = try s.coerceRef( | ||
| 394 | in.op(Report.Operand.argument(@intCast(i))), | ||
| 395 | ref, | ||
| 396 | param, | ||
| 397 | ); | ||
| 398 | scratch[i] = coerced; | ||
| 399 | } | ||
| 400 | } else { | ||
| 401 | // just copy the args in without checking | ||
| 402 | for (call.args.slice(&s.code), 0..) |arg, i| { | ||
| 403 | const ref = try s.resolveRefRuntime(arg); | ||
| 404 | scratch[i] = ref; | ||
| 405 | } | ||
| 406 | } | ||
| 384 | 407 | ||
| 385 | // return s.addInstRef(.call, .{ | 408 | const start = s.air_extra.list.items.len; |
| 386 | // .base = base, | 409 | try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch)); |
| 387 | // .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{ | 410 | |
| 388 | // .args = .{ | 411 | return s.addInstRef(.call, .{ |
| 389 | // .start = @intCast(start), | 412 | .base = base, |
| 390 | // .len = @intCast(scratch.len), | 413 | .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{ |
| 391 | // }, | 414 | .args = .{ |
| 392 | // }), | 415 | .start = @intCast(start), |
| 393 | // }); | 416 | .len = @intCast(scratch.len), |
| 417 | }, | ||
| 418 | }), | ||
| 419 | }); | ||
| 394 | }, | 420 | }, |
| 395 | .ensure_void => { | 421 | .ensure_void => { |
| 396 | const operand = try s.resolveRefRuntimeExtra(s.code.instData(.ensure_void, in).operand, false); | 422 | const operand = try s.resolveRefRuntimeExtra(s.code.instData(.ensure_void, in).operand, false); |
| ... | @@ -488,7 +514,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { | ... | @@ -488,7 +514,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref { |
| 488 | }, | 514 | }, |
| 489 | .as => { | 515 | .as => { |
| 490 | const as: Teg.Inst.As = s.code.instPayload(.as, in); | 516 | const as: Teg.Inst.As = s.code.instPayload(.as, in); |
| 491 | const coerce_to = try s.resolveRefComptimeType(in.op(.lhs) ,as.type, .type); | 517 | const coerce_to = try s.resolveRefComptimeType(in.op(.lhs), as.type, .type); |
| 492 | const operand = try s.resolveRefRuntime(as.operand); | 518 | const operand = try s.resolveRefRuntime(as.operand); |
| 493 | return try s.coerceRef(in.op(.rhs), operand, coerce_to.toType(s.ip).?); | 519 | return try s.coerceRef(in.op(.rhs), operand, coerce_to.toType(s.ip).?); |
| 494 | }, | 520 | }, |
| ... | @@ -501,16 +527,14 @@ fn markInst(s: *Sema, inst: Air.Inst.Index) void { | ... | @@ -501,16 +527,14 @@ fn markInst(s: *Sema, inst: Air.Inst.Index) void { |
| 501 | flags.uses = flags.uses.increment(); | 527 | flags.uses = flags.uses.increment(); |
| 502 | } | 528 | } |
| 503 | 529 | ||
| 504 | fn analyzeRefToBlock(s: *Sema, in: Teg.Inst.Ref) anyerror!Air.Inst.Ref { | 530 | fn analyzeRefToBlock(s: *Sema, in: Teg.Inst.Ref) Error!Air.Inst.Ref { |
| 505 | const t = tracer.trace(@src()); | 531 | const t = tracer.trace(@src()); |
| 506 | defer t.end(); | 532 | defer t.end(); |
| 507 | 533 | ||
| 508 | const scratch_top = s.scratch.items.len; | 534 | const scratch_top = s.scratch.items.len; |
| 509 | defer s.scratch.shrinkRetainingCapacity(scratch_top); | 535 | defer s.scratch.shrinkRetainingCapacity(scratch_top); |
| 510 | 536 | ||
| 511 | std.debug.print("{d} {d}\n", .{ scratch_top, s.scratch.items.len }); | ||
| 512 | const visited = try s.resolveRefRuntime(in); | 537 | const visited = try s.resolveRefRuntime(in); |
| 513 | std.debug.print("{d} {d}\n", .{ scratch_top, s.scratch.items.len }); | ||
| 514 | 538 | ||
| 515 | if (scratch_top == s.scratch.items.len and visited.kind == .value) { | 539 | if (scratch_top == s.scratch.items.len and visited.kind == .value) { |
| 516 | return visited; | 540 | return visited; |
| ... | @@ -530,7 +554,7 @@ fn analyzeRefToBlock(s: *Sema, in: Teg.Inst.Ref) anyerror!Air.Inst.Ref { | ... | @@ -530,7 +554,7 @@ fn analyzeRefToBlock(s: *Sema, in: Teg.Inst.Ref) anyerror!Air.Inst.Ref { |
| 530 | return (try block.finish(s, scratch_top)).toRef(); | 554 | return (try block.finish(s, scratch_top)).toRef(); |
| 531 | } | 555 | } |
| 532 | 556 | ||
| 533 | fn resolveRefRuntimeExtra(s: *Sema, ref: Teg.Inst.Ref, mark: bool) anyerror!Air.Inst.Ref { | 557 | fn resolveRefRuntimeExtra(s: *Sema, ref: Teg.Inst.Ref, mark: bool) Error!Air.Inst.Ref { |
| 534 | const index = ref.toIndex() orelse { | 558 | const index = ref.toIndex() orelse { |
| 535 | return ref.toValue().?.toAir(); | 559 | return ref.toValue().?.toAir(); |
| 536 | }; | 560 | }; |
| ... | @@ -548,11 +572,11 @@ fn resolveRefRuntimeExtra(s: *Sema, ref: Teg.Inst.Ref, mark: bool) anyerror!Air. | ... | @@ -548,11 +572,11 @@ fn resolveRefRuntimeExtra(s: *Sema, ref: Teg.Inst.Ref, mark: bool) anyerror!Air. |
| 548 | return s.analyzeCode(index); | 572 | return s.analyzeCode(index); |
| 549 | } | 573 | } |
| 550 | 574 | ||
| 551 | fn resolveRefRuntime(s: *Sema, ref: Teg.Inst.Ref) anyerror!Air.Inst.Ref { | 575 | fn resolveRefRuntime(s: *Sema, ref: Teg.Inst.Ref) Error!Air.Inst.Ref { |
| 552 | return resolveRefRuntimeExtra(s, ref, true); | 576 | return resolveRefRuntimeExtra(s, ref, true); |
| 553 | } | 577 | } |
| 554 | 578 | ||
| 555 | fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value { | 579 | fn resolveRefComptimeAny(s: *Sema, ref: Teg.Inst.Ref) !Value { |
| 556 | const index = switch (ref.decode()) { | 580 | const index = switch (ref.decode()) { |
| 557 | .value => |value| return value, | 581 | .value => |value| return value, |
| 558 | .index => |index| index, | 582 | .index => |index| index, |
| ... | @@ -575,6 +599,15 @@ fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value { | ... | @@ -575,6 +599,15 @@ fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value { |
| 575 | } | 599 | } |
| 576 | } | 600 | } |
| 577 | 601 | ||
| 602 | fn resolveRefComptimeType(s: *Sema, src: Teg.InstOp, ref: Teg.Inst.Ref, ty: Type) !Value { | ||
| 603 | const any = try s.resolveRefComptimeAny(ref); | ||
| 604 | return try s.coerceValue(src, any, ty); | ||
| 605 | } | ||
| 606 | |||
| 607 | fn resolveType(s: *Sema, src: Teg.InstOp, ref: Teg.Inst.Ref) !Type { | ||
| 608 | return (try s.resolveRefComptimeType(src, ref, .type)).toTypeUnsafe(s.ip); | ||
| 609 | } | ||
| 610 | |||
| 578 | /// Coerce `value` runtime ref to `coerce_type`, and emit an error at `teg_ref`'s location | 611 | /// Coerce `value` runtime ref to `coerce_type`, and emit an error at `teg_ref`'s location |
| 579 | fn coerceRef(s: *Sema, src: InstOp, value: Air.Inst.Ref, to: Type) !Air.Inst.Ref { | 612 | fn coerceRef(s: *Sema, src: InstOp, value: Air.Inst.Ref, to: Type) !Air.Inst.Ref { |
| 580 | const from = s.typeOfRef(value); | 613 | const from = s.typeOfRef(value); |
| ... | @@ -628,30 +661,6 @@ fn coerceValue(s: *Sema, src: InstOp, value: Value, to: Type) !Value { | ... | @@ -628,30 +661,6 @@ fn coerceValue(s: *Sema, src: InstOp, value: Value, to: Type) !Value { |
| 628 | return value; | 661 | return value; |
| 629 | } | 662 | } |
| 630 | switch (to) { | 663 | switch (to) { |
| 631 | // .simple_type => |simple_type| switch (simple_type) { | ||
| 632 | // // .@"opaque", | ||
| 633 | // .int32 => { | ||
| 634 | // switch (value_type.toKey(s.ip)) { | ||
| 635 | // .simple_type => switch (simple_type) { | ||
| 636 | // // .int32 => return value, | ||
| 637 | // // .numeric_literal => { | ||
| 638 | // // const val = value.decode().value.toKey(s.ip).comptime_float; | ||
| 639 | // // }, | ||
| 640 | // else => |tag| std.debug.panic("TODO: coerceTo value_type simple_type .{s}", .{@tagName(tag)}), | ||
| 641 | // }, | ||
| 642 | // else => |tag| std.debug.panic("TODO: coerceTo value_type .{s}", .{@tagName(tag)}), | ||
| 643 | // } | ||
| 644 | // }, | ||
| 645 | // // .float, | ||
| 646 | // // .string, | ||
| 647 | // // .bool, | ||
| 648 | // // .noreturn, | ||
| 649 | // // .type, | ||
| 650 | // // .numeric_literal, | ||
| 651 | // else => |tag| std.debug.panic("TODO: coerceTo coerce_type .simple_type = .{s}", .{@tagName(tag)}), | ||
| 652 | // }, | ||
| 653 | // else => |tag| std.debug.panic("TODO: coerceTo coerce_type .{s}", .{@tagName(tag)}), | ||
| 654 | // } | ||
| 655 | .@"opaque" => { | 664 | .@"opaque" => { |
| 656 | // | 665 | // |
| 657 | }, | 666 | }, |
| ... | @@ -691,18 +700,18 @@ fn coerceValue(s: *Sema, src: InstOp, value: Value, to: Type) !Value { | ... | @@ -691,18 +700,18 @@ fn coerceValue(s: *Sema, src: InstOp, value: Value, to: Type) !Value { |
| 691 | // | 700 | // |
| 692 | }, | 701 | }, |
| 693 | .type => { | 702 | .type => { |
| 694 | // | 703 | if (value == .void) return .void; |
| 695 | }, | 704 | }, |
| 696 | .numeric_literal => {}, | 705 | .numeric_literal => {}, |
| 697 | .void => { | 706 | .void => { |
| 698 | // | 707 | if (value == .void) return .void; |
| 699 | }, | 708 | }, |
| 700 | else => {}, | 709 | else => {}, |
| 701 | } | 710 | } |
| 702 | return s.coersionError(src, from, to); | 711 | return s.coersionError(src, from, to); |
| 703 | } | 712 | } |
| 704 | 713 | ||
| 705 | fn resolveDecl(s: *Sema, decl_index: Decl.Index) !Value { | 714 | fn resolveDecl(s: *Sema, decl_index: Decl.Index) Error!Value { |
| 706 | const decl = s.ip.declPtr(decl_index); | 715 | const decl = s.ip.declPtr(decl_index); |
| 707 | switch (decl.analysis) { | 716 | switch (decl.analysis) { |
| 708 | .unreferenced => { | 717 | .unreferenced => { |
| ... | @@ -945,7 +954,7 @@ fn coersionError(s: *Sema, src: InstOp, from: Type, to: Type) Error { | ... | @@ -945,7 +954,7 @@ fn coersionError(s: *Sema, src: InstOp, from: Type, to: Type) Error { |
| 945 | } | 954 | } |
| 946 | 955 | ||
| 947 | fn lazyNode(s: *const Sema, src: InstOp) Report.LazyNode { | 956 | fn lazyNode(s: *const Sema, src: InstOp) Report.LazyNode { |
| 948 | return src.lazyNode( s.decl_index); | 957 | return src.lazyNode(s.decl_index); |
| 949 | } | 958 | } |
| 950 | 959 | ||
| 951 | const Sema = @This(); | 960 | const Sema = @This(); |
src/compiler/Transform.zig+22-8| ... | @@ -396,7 +396,7 @@ fn transformFunction(t: *Transform, outer_decl: BlockContext, node: NodeIndex) A | ... | @@ -396,7 +396,7 @@ fn transformFunction(t: *Transform, outer_decl: BlockContext, node: NodeIndex) A |
| 396 | }); | 396 | }); |
| 397 | 397 | ||
| 398 | t.getInstData(func).* = EncodedData.encode(.declaration, .{ | 398 | t.getInstData(func).* = EncodedData.encode(.declaration, .{ |
| 399 | .src_node = 0, | 399 | .src_node = outer_decl.nodeOffset(node), |
| 400 | .extra_index = decl_extra, | 400 | .extra_index = decl_extra, |
| 401 | }); | 401 | }); |
| 402 | 402 | ||
| ... | @@ -971,8 +971,8 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc | ... | @@ -971,8 +971,8 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc |
| 971 | const ret_node = t.ast.nodeData(node).@"return"; | 971 | const ret_node = t.ast.nodeData(node).@"return"; |
| 972 | 972 | ||
| 973 | const ret_block_ptr = decl.return_target orelse { | 973 | const ret_block_ptr = decl.return_target orelse { |
| 974 | // return error.InvalidReturn; | 974 | try t.report.err(.invalid_return, .{ .node = node }); |
| 975 | @panic("TODO"); | 975 | return .void; |
| 976 | }; | 976 | }; |
| 977 | 977 | ||
| 978 | const ret_block = if (ret_block_ptr.*) |block| | 978 | const ret_block = if (ret_block_ptr.*) |block| |
| ... | @@ -1061,9 +1061,18 @@ fn transformBlockStatement( | ... | @@ -1061,9 +1061,18 @@ fn transformBlockStatement( |
| 1061 | const var_decl = t.ast.fullVarDecl(node); | 1061 | const var_decl = t.ast.fullVarDecl(node); |
| 1062 | 1062 | ||
| 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 | try t.report.warn(.invalid_discard, .{ .node = node }); |
| 1065 | try t.report.err(.invalid_discard, .{ .node = node }); | 1065 | |
| 1066 | return .void; | 1066 | const ref = try t.transformExpression(decl, var_decl.init) orelse |
| 1067 | return null; | ||
| 1068 | |||
| 1069 | return try t.addInstRef(.{ | ||
| 1070 | .tag = .discard, | ||
| 1071 | .data = EncodedData.encode(.discard, .{ | ||
| 1072 | .src_node = decl.nodeOffset(node), | ||
| 1073 | .operand = ref, | ||
| 1074 | }), | ||
| 1075 | }); | ||
| 1067 | } | 1076 | } |
| 1068 | 1077 | ||
| 1069 | if (BuiltInIds.has(var_decl.id)) { | 1078 | if (BuiltInIds.has(var_decl.id)) { |
| ... | @@ -1189,6 +1198,13 @@ fn transformBlockStatement( | ... | @@ -1189,6 +1198,13 @@ fn transformBlockStatement( |
| 1189 | return null; | 1198 | return null; |
| 1190 | 1199 | ||
| 1191 | if (!is_implicit_return_expression and result != .void) { | 1200 | if (!is_implicit_return_expression and result != .void) { |
| 1201 | if (t.ast.nodeTag(node) == .id) { | ||
| 1202 | try t.report.warn(.dangling_identifier, .{ | ||
| 1203 | .node = node, | ||
| 1204 | }); | ||
| 1205 | return result; | ||
| 1206 | } | ||
| 1207 | |||
| 1192 | return try t.addInstRef(.{ | 1208 | return try t.addInstRef(.{ |
| 1193 | .tag = .ensure_void, | 1209 | .tag = .ensure_void, |
| 1194 | .data = EncodedData.encode(.ensure_void, .{ | 1210 | .data = EncodedData.encode(.ensure_void, .{ |
| ... | @@ -1203,8 +1219,6 @@ fn transformBlockStatement( | ... | @@ -1203,8 +1219,6 @@ fn transformBlockStatement( |
| 1203 | } | 1219 | } |
| 1204 | } | 1220 | } |
| 1205 | 1221 | ||
| 1206 | // --- | ||
| 1207 | |||
| 1208 | fn addRootInst(t: *Transform, inst: Inst) !Inst.Index { | 1222 | fn addRootInst(t: *Transform, inst: Inst) !Inst.Index { |
| 1209 | try t.insts.append(t.gpa, inst); | 1223 | try t.insts.append(t.gpa, inst); |
| 1210 | return @enumFromInt(t.insts.len - 1); | 1224 | return @enumFromInt(t.insts.len - 1); |
src/compiler/main.zig+4-111| ... | @@ -131,7 +131,10 @@ pub fn main() !void { | ... | @@ -131,7 +131,10 @@ pub fn main() !void { |
| 131 | try teg.dumpToWriter(stderr); | 131 | try teg.dumpToWriter(stderr); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | try comp.semaEntryPoint(main_file); | 134 | comp.semaEntryPoint(main_file) catch |err| switch (err) { |
| 135 | error.AnalysisFail => std.process.exit(1), | ||
| 136 | else => return err, | ||
| 137 | }; | ||
| 135 | 138 | ||
| 136 | const output = std.io.getStdOut().writer(); | 139 | const output = std.io.getStdOut().writer(); |
| 137 | var bufw = std.io.bufferedWriter(output); | 140 | var bufw = std.io.bufferedWriter(output); |
| ... | @@ -140,114 +143,4 @@ pub fn main() !void { | ... | @@ -140,114 +143,4 @@ pub fn main() !void { |
| 140 | try bufw.flush(); | 143 | try bufw.flush(); |
| 141 | 144 | ||
| 142 | std.process.cleanExit(); | 145 | std.process.cleanExit(); |
| 143 | |||
| 144 | // var error_pos: u32 = 0; | ||
| 145 | // var tokens = Tokenizer.tokenize(source, alloc.allocator(), &error_pos) catch |err| { | ||
| 146 | // var line: usize = 1; | ||
| 147 | // var byte: usize = 0; | ||
| 148 | // var line_data: []const u8 = undefined; | ||
| 149 | // while (true) { | ||
| 150 | // const b = std.mem.indexOfScalarPos(u8, source, byte, '\n') orelse { | ||
| 151 | // line_data = source[byte..]; | ||
| 152 | // break; | ||
| 153 | // }; | ||
| 154 | // if (b > error_pos) { | ||
| 155 | // line_data = source[byte..b]; | ||
| 156 | // break; | ||
| 157 | // } | ||
| 158 | // byte = b + 1; | ||
| 159 | // line += 1; | ||
| 160 | // } | ||
| 161 | // var col: usize = 1; | ||
| 162 | // var arrow_pos: usize = 0; | ||
| 163 | // while (byte < error_pos) { | ||
| 164 | // const b = source[byte]; | ||
| 165 | // std.debug.assert(b != '\n'); | ||
| 166 | // byte += std.unicode.utf8ByteSequenceLength(b) catch break; | ||
| 167 | // col += 1; | ||
| 168 | |||
| 169 | // arrow_pos += 1; // TODO: grapheme cluster | ||
| 170 | // } | ||
| 171 | |||
| 172 | // const stderr = std.io.getStdErr(); | ||
| 173 | // const config = std.io.tty.detectConfig(stderr); | ||
| 174 | // var buf = std.io.bufferedWriter(stderr.writer()); | ||
| 175 | // const writer = buf.writer(); | ||
| 176 | |||
| 177 | // try config.setColor(writer, .red); | ||
| 178 | // try writer.writeAll("error"); | ||
| 179 | // try config.setColor(writer, .bright_black); | ||
| 180 | // try writer.writeAll(": "); | ||
| 181 | // try config.setColor(writer, .reset); | ||
| 182 | // switch (err) { | ||
| 183 | // error.OutOfMemory => try writer.writeAll("Out of Memory"), | ||
| 184 | // error.InvalidUtf8 => try writer.writeAll("Invalid UTF-8"), | ||
| 185 | // error.InvalidSyntax => try writer.writeAll("Syntax Error"), | ||
| 186 | // error.TrailingNumericSeparator => try writer.writeAll("Trailing Numeric Separator"), | ||
| 187 | // error.UnterminatedString => try writer.writeAll("Unterminated String"), | ||
| 188 | // error.InvalidEscapeSequence => try writer.writeAll("Invalid Escape Sequence"), | ||
| 189 | // error.InvalidEscapeCodepoint => try writer.writeAll("Invalid Escape Codepoint"), | ||
| 190 | // error.GitConflict => try writer.writeAll("Found Git Conflict"), | ||
| 191 | // } | ||
| 192 | // try writer.print(" at {d}:{d}\n ", .{ line, col }); | ||
| 193 | // try writer.writeAll(line_data); | ||
| 194 | // try writer.writeAll("\n "); | ||
| 195 | // try writer.writeByteNTimes(' ', col); | ||
| 196 | |||
| 197 | // try config.setColor(writer, .bright_green); | ||
| 198 | // try writer.writeAll("^"); | ||
| 199 | // try config.setColor(writer, .reset); | ||
| 200 | // try writer.writeAll("\n"); | ||
| 201 | |||
| 202 | // try buf.flush(); | ||
| 203 | // return err; | ||
| 204 | // }; | ||
| 205 | // defer tokens.deinit(alloc.allocator()); | ||
| 206 | |||
| 207 | // // std.debug.print("tokens.len = {d}\n", .{tokens.len}); | ||
| 208 | // // std.debug.print("token list bytes = {d}\n", .{tokens.toMultiArrayList().allocatedBytes().len}); | ||
| 209 | // // std.debug.print("source bytes = {d}\n", .{source.len}); | ||
| 210 | // // for ( | ||
| 211 | // // tokens.items(.tag), | ||
| 212 | // // tokens.items(.offset), | ||
| 213 | // // ) |tag, offset| { | ||
| 214 | // // std.debug.print(".tag = {s} .offset = {d}\n", .{ | ||
| 215 | // // @tagName(tag), | ||
| 216 | // // offset, | ||
| 217 | // // }); | ||
| 218 | // // } | ||
| 219 | |||
| 220 | // const ast = ast: { | ||
| 221 | // var p = Parse.init(alloc.allocator(), source, tokens); | ||
| 222 | // errdefer p.deinit(); | ||
| 223 | // try p.nodes.ensureUnusedCapacity(alloc.allocator(), 100); | ||
| 224 | // p.parseRoot() catch |err| { | ||
| 225 | // const tok = p.fullToken(p.pos); | ||
| 226 | |||
| 227 | // std.debug.print("ast_error = {?}\n", .{p.ast_error}); | ||
| 228 | |||
| 229 | // std.debug.print("tok: {s} - '{s}' - {d}\n", .{ | ||
| 230 | // @tagName(tok.tag), | ||
| 231 | // tok.slice(p.source), | ||
| 232 | // tok.offset, | ||
| 233 | // }); | ||
| 234 | |||
| 235 | // return err; | ||
| 236 | // }; | ||
| 237 | // break :ast try p.finalize(tokens); | ||
| 238 | // }; | ||
| 239 | |||
| 240 | // try ast.dumpToWriter(std.io.getStdOut().writer()); | ||
| 241 | |||
| 242 | // const teg = try Transform.transform(ast, alloc.allocator()); | ||
| 243 | // std.debug.print("teg.insts.len = {d}\n", .{teg.insts.len}); | ||
| 244 | // std.debug.print("teg.string_bytes.len = {d}\n", .{teg.string_bytes.len}); | ||
| 245 | // std.debug.print("teg.extra.len = {d}\n", .{teg.extra.len}); | ||
| 246 | |||
| 247 | // for (teg.insts.items(.tag), teg.insts.items(.data)) |tag, data| { | ||
| 248 | // std.debug.print("{s} - {}\n", .{ | ||
| 249 | // @tagName(tag), | ||
| 250 | // data, | ||
| 251 | // }); | ||
| 252 | // } | ||
| 253 | } | 146 | } |