compiler.zig (43284B)
1 const std = @import("std"); 2 3 const vm_native = @import("vm::native.zig"); 4 const utils = @import("lib::utils.zig"); 5 const scanner = @import("scanner.zig"); 6 const debug = @import("debug.zig"); 7 const value = @import("value.zig"); 8 9 const Token = scanner.TokenType; 10 const OP = @import("op.zig").OP; 11 const Value = value.Value; 12 const GC = @import("gc.zig").GC; 13 const Obj = GC.Obj; 14 const Chunk = Obj.Chunk; 15 16 pub const CompilerError = Obj.Error || scanner.ScannerError || Chunk.Error || Value.ParseNumberError || error{ UnexpectedToken, NotAnExpression }; 17 18 const Precedence = enum { 19 NONE, 20 ASSIGNMENT, // = 21 TERNARY, // ? : 22 OR, // or 23 AND, // and 24 EQUALITY, // == != 25 COMPARISON, // < > <= >= 26 TERM, // + - 27 FACTOR, // * / 28 UNARY, // ! - 29 CALL, // . () [] 30 PRIMARY, 31 32 pub fn inc(self: @This()) @This() { 33 return @enumFromInt(@intFromEnum(self) + 1); 34 } 35 36 pub fn lessOrEq(self: @This(), rhs: @This()) bool { 37 return @intFromEnum(self) <= @intFromEnum(rhs); 38 } 39 }; 40 41 pub fn Compiler(size: comptime_int) type { 42 return struct { 43 current: scanner.Token, 44 previous: scanner.Token, 45 scanner: *scanner.Scanner, 46 lastError: CompilerError, 47 hadError: bool, 48 panicMode: bool, 49 chunk: *Obj.Chunk, 50 initializer: bool, 51 objects: *GC, 52 locals: [size]Local, 53 localCount: usize, 54 scopeDepth: usize, 55 enclosing: ?*Self, 56 upvalues: [upvalues_size]Upvalue, 57 upvaluesCount: u8, 58 currentClass: ?*Class, 59 60 const Class = struct { 61 enclosing: ?*Class, 62 hasSuperclass: bool = false, 63 }; 64 65 const Self = @This(); 66 pub const Stack = size; 67 68 pub const Upvalue = struct { 69 pub const Type = enum(u8) { local = 0, remote = 1, empty = 2, immediate = 3 }; 70 71 index: u8, 72 type: Type, 73 }; 74 75 const upvalues_size = std.math.maxInt(u8); 76 77 const Local = struct { 78 name: scanner.Token = scanner.Token.Empty, 79 depth: ?usize = null, 80 con: bool = true, 81 captured: bool = false, 82 placeholder: bool = false, 83 immediate: bool = false, 84 }; 85 86 const ParseFn = *const fn (*Self, bool) void; 87 88 const ParseRule = struct { 89 prefix: ?ParseFn, 90 infix: ?ParseFn, 91 precedence: Precedence, 92 pub fn init(prefix: ?ParseFn, infix: ?ParseFn, precedence: Precedence) @This() { 93 return @This(){ .prefix = prefix, .infix = infix, .precedence = precedence }; 94 } 95 }; 96 97 const rules = init: { 98 var new: [utils.enum_len(Token)]ParseRule = undefined; 99 for (&new, 0..) |*v, i| { 100 const T = Token; 101 const S = Self; 102 const R = ParseRule.init; 103 const P = Precedence; 104 const tok: Token = @enumFromInt(i); 105 v.* = switch (tok) { 106 // zig fmt: off 107 T.LEFT_PAREN => R(S.grouping, S.call, P.CALL ), 108 T.LEFT_BRACKET => R(S.listTable, S.index, P.CALL ), 109 T.MINUS => R(S.unary, S.binary, P.TERM ), 110 T.PLUS => R(null, S.binary, P.TERM ), 111 T.SLASH => R(null, S.binary, P.FACTOR ), 112 T.STAR => R(null, S.binary, P.FACTOR ), 113 T.QUESTION => R(null, S.ternary, P.TERNARY ), 114 T.BANG => R(S.unary, null, P.NONE ), 115 T.BANG_EQUAL => R(null, S.binary, P.EQUALITY ), 116 T.EQUAL_EQUAL => R(null, S.binary, P.EQUALITY ), 117 T.GREATER => R(null, S.binary, P.COMPARISON ), 118 T.GREATER_EQUAL => R(null, S.binary, P.COMPARISON ), 119 T.LESS => R(null, S.binary, P.COMPARISON ), 120 T.LESS_EQUAL => R(null, S.binary, P.COMPARISON ), 121 T.IDENTIFIER => R(S.variable, null, P.NONE ), 122 T.STRING => R(S.string, null, P.NONE ), 123 T.CHAR => R(S.char, null, P.NONE ), 124 T.NUMBER => R(S.number, null, P.NONE ), 125 T.AND => R(null, S._and, P.AND ), 126 T.FALSE => R(S.literal, null, P.NONE ), 127 T.NIL => R(S.literal, null, P.NONE ), 128 T.OR => R(null, S._or, P.OR ), 129 T.TRUE => R(S.literal, null, P.NONE ), 130 T.FUN => R(S.funExpression, null, P.NONE ), 131 T.CLASS => R(S.classExpression, null, P.NONE ), 132 T.DOT => R(null, S.dot, P.CALL ), 133 T.THIS => R(S.this, null, P.NONE ), 134 T.SUPER => R(S.super, null, P.NONE ), 135 else => R(null, null, P.NONE ), 136 // zig fmt: on 137 }; 138 } 139 break :init new; 140 }; 141 142 fn getRule(tok: Token) *const ParseRule { 143 return &Self.rules[@intFromEnum(tok)]; 144 } 145 146 fn advance(self: *Self) void { 147 self.previous = self.current; 148 149 while (true) { 150 self.current = self.scanner.scanToken(); 151 152 if (self.current.type) |_| { 153 break; 154 } else |err| { 155 self.lastError = err; 156 self.errorAtCurrent(scanner.ScannerErrorString(err)); 157 } 158 } 159 } 160 161 fn emitByte(self: *Self, byte: u8) void { 162 self.chunk.write(byte, self.previous.line) catch |err| { 163 self.lastError = err; 164 self.errorAtCurrent("Out of Memory"); 165 }; 166 } 167 168 fn emitOP(self: *Self, op: OP) void { 169 self.chunk.writeOP(op, self.previous.line) catch |err| { 170 self.lastError = err; 171 self.errorAtCurrent("Out of Memory"); 172 }; 173 } 174 175 fn emit(self: *Self, op: OP, byte: u8) void { 176 self.emitOP(op); 177 self.emitByte(byte); 178 } 179 180 fn emit2OP(self: *Self, op: OP, op2: OP) void { 181 self.emitOP(op); 182 self.emitOP(op2); 183 } 184 185 fn end(self: *Self) !*Obj.Chunk { 186 self.emitReturn(); 187 return self.chunk; 188 } 189 190 fn emitReturn(self: *Self) void { 191 if (self.initializer) 192 self.namedVariable(makeIdentifier("this"), false) 193 else if (self.enclosing) |_| 194 self.emitOP(OP.NIL); 195 196 self.emitOP(OP.RETURN); 197 } 198 199 fn errorAtCurrent(self: *Self, message: []const u8) void { 200 self.errorAt(self.current, message); 201 } 202 203 fn errorAtPrevious(self: *Self, message: []const u8) void { 204 self.errorAt(self.previous, message); 205 } 206 207 fn expression(self: *Self) void { 208 self.parsePrecedence(Precedence.ASSIGNMENT); 209 } 210 211 fn parsePrecedence(self: *Self, precedence: Precedence) void { 212 const canAssign = precedence.lessOrEq(Precedence.ASSIGNMENT); 213 214 self.advance(); 215 if (getRule(self.previous.type catch return).prefix) |prefixRule| { 216 prefixRule(self, canAssign); 217 } else { 218 self.lastError = CompilerError.NotAnExpression; 219 self.errorAtPrevious("Expect expression."); 220 return; 221 } 222 223 while (precedence.lessOrEq(getRule(self.current.type catch unreachable).precedence)) { 224 self.advance(); 225 if (getRule(self.previous.type catch unreachable).infix) |infixRule| { 226 infixRule(self, canAssign); 227 } else { 228 self.lastError = CompilerError.NotAnExpression; 229 self.errorAtPrevious("Expect expression."); 230 return; 231 } 232 } 233 234 if (canAssign and self.match(Token.EQUAL)) { 235 self.errorAtPrevious("Invalid assignment target."); 236 } 237 } 238 239 fn errorAt(self: *Self, token: scanner.Token, message: []const u8) void { 240 if (self.panicMode) return; 241 self.panicMode = true; 242 std.debug.print("[{d}:{d}] Error", .{ token.line, token.column }); 243 if (token.type) |tpe| { 244 if (tpe == Token.EOF) { 245 std.debug.print(" at end", .{}); 246 } else { 247 std.debug.print(" at {s}", .{token.lexeme}); 248 } 249 } else |_| {} 250 std.debug.print(": {s}\n", .{message}); 251 self.hadError = true; 252 } 253 254 fn consume(self: *Self, tok: Token, message: []const u8) void { 255 if (self.current.type) |tpe| { 256 if (tpe == tok) { 257 self.advance(); 258 return; 259 } 260 } else |_| {} 261 self.lastError = CompilerError.UnexpectedToken; 262 self.errorAtCurrent(message); 263 } 264 265 fn number(self: *Self, _: bool) void { 266 self.emitConstant(Value.parseNumber(self.previous.lexeme) catch |err| { 267 self.lastError = err; 268 self.errorAtPrevious("Invalid numeric literal"); 269 return; 270 }); 271 } 272 273 fn string(self: *Self, _: bool) void { 274 self.emitObj(.String, null, &.{self.previous.lexeme[1 .. self.previous.lexeme.len - 1]}) catch return; 275 } 276 277 fn char(self: *Self, _: bool) void { 278 self.emitConstant(Value.init(self.previous.lexeme[1])); 279 } 280 281 fn call(self: *Self, _: bool) void { 282 const argCount = self.argumentList(); 283 self.emit(OP.CALL, argCount); 284 } 285 286 fn dot(self: *Self, canAssign: bool) void { 287 self.consume(Token.IDENTIFIER, "Expect property name after '.'"); 288 const name = self.identifierConstant(self.previous) catch return; 289 290 if (canAssign and self.match(Token.EQUAL)) { 291 self.expression(); 292 self.emit(OP.SET_PROPERTY, name); 293 } else { 294 self.emit(OP.GET_PROPERTY, name); 295 } 296 } 297 298 fn argumentList(self: *Self) u8 { 299 var argCount: u8 = 0; 300 if (!self.check(Token.RIGHT_PAREN)) { 301 while (true) { 302 self.expression(); 303 if (argCount == std.math.maxInt(u8)) { 304 self.errorAtPrevious("Too many arguments"); 305 return argCount; 306 } 307 argCount += 1; 308 if (!self.match(Token.COMMA)) break; 309 } 310 } 311 self.consume(Token.RIGHT_PAREN, "Expect ')' after arguments"); 312 return argCount; 313 } 314 315 fn makeObj(self: *Self, comptime tp: Obj.Type, name: ?[]const u8, arg: tp.get().Arg) !u8 { 316 return self.makeConstant(Value.init(self.objects.emplace_cast(tp, name, arg) catch |err| { 317 self.lastError = err; 318 self.errorAtPrevious("Unable to allocate obj"); 319 return err; 320 })); 321 } 322 323 fn emitObj(self: *Self, comptime tp: Obj.Type, name: ?[]const u8, arg: tp.get().Arg) !void { 324 self.emit(OP.CONSTANT, try self.makeObj(tp, name, arg)); 325 } 326 327 fn listTable(self: *Self, _: bool) void { 328 self.emit(OP.CONSTANT, 0xff); 329 const offset = self.chunk.code.ptr().len - 1; 330 var argCount: u8 = 0; 331 var isList = true; 332 333 if (self.match(Token.RIGHT_BRACKET)) {} else if (self.match(Token.COLON)) { 334 isList = false; 335 self.consume(Token.RIGHT_BRACKET, "Expect ']'"); 336 } else { 337 self.expression(); 338 argCount += 1; 339 if (self.match(Token.COLON)) { 340 isList = false; 341 self.expression(); 342 argCount += 1; 343 } 344 while (!self.match(Token.RIGHT_BRACKET)) { 345 self.consume(Token.COMMA, "Expect ',' between expressions"); 346 if (self.match(Token.RIGHT_BRACKET)) break; 347 self.expression(); 348 argCount += 1; 349 if (!isList) { 350 self.consume(Token.COLON, "Expect ':' between key and value"); 351 self.expression(); 352 argCount += 1; 353 } 354 } 355 } 356 if (isList) { 357 self.chunk.code.ptr().set(offset, self.makeObj(.Native, "L::list", .{ 358 .fun = vm_native.list, 359 }) catch return) catch return; 360 } else { 361 self.chunk.code.ptr().set(offset, self.makeObj(.Native, "L::table", .{ 362 .fun = vm_native.table, 363 }) catch return) catch return; 364 } 365 self.emit(OP.CALL, argCount); 366 } 367 368 fn index(self: *Self, canAssign: bool) void { 369 self.expression(); 370 self.consume(Token.RIGHT_BRACKET, "Expect ']' after index expression"); 371 if (canAssign and self.match(Token.EQUAL)) { 372 self.expression(); 373 self.emitOP(OP.SET_INDEX); 374 } else { 375 self.emitOP(OP.GET_INDEX); 376 } 377 } 378 379 fn this(self: *Self, _: bool) void { 380 if (self.currentClass) |_| { 381 self.variable(false); 382 } else { 383 self.errorAtPrevious("Can't use 'this' outside of class."); 384 } 385 } 386 387 fn super(self: *Self, _: bool) void { 388 if (self.currentClass) |cls| { 389 if (cls.hasSuperclass) { 390 self.consume(Token.DOT, "Expect '.' after 'super'."); 391 self.consume(Token.IDENTIFIER, "Expect superclass method name."); 392 const name = self.identifierConstant(self.previous) catch return; 393 self.namedVariable(makeIdentifier("this"), false); 394 self.namedVariable(makeIdentifier("super"), false); 395 self.emit(OP.GET_SUPER, name); 396 } else { 397 self.errorAtPrevious("Can't use 'super' in a class with no parent."); 398 } 399 } else { 400 self.errorAtPrevious("Can't use 'super' outside of a class."); 401 } 402 } 403 404 fn variable(self: *Self, canAssign: bool) void { 405 self.namedVariable(self.previous, canAssign); 406 } 407 408 fn namedVariable(self: *Self, tok: scanner.Token, canAssign: bool) void { 409 const OPs: struct { get: OP, set: OP, arg: u8 } = if (self.resolveLocal(tok)) |arg| 410 .{ .get = OP.GET_LOCAL, .set = OP.SET_LOCAL, .arg = arg } 411 else if (self.resolveUpvalue(tok)) |arg| 412 .{ .get = OP.GET_UPVALUE, .set = OP.SET_UPVALUE, .arg = arg } 413 else 414 .{ .get = OP.GET_GLOBAL, .set = OP.SET_GLOBAL, .arg = self.identifierConstant(tok) catch return }; 415 416 if (canAssign and self.match(Token.EQUAL)) { 417 if (OPs.get == OP.GET_LOCAL and self.locals[OPs.arg].con) { 418 self.errorAtPrevious("Cannot assign to a constant"); 419 return; 420 } 421 self.expression(); 422 self.emit(OPs.set, OPs.arg); 423 } else { 424 self.emit(OPs.get, OPs.arg); 425 } 426 } 427 428 fn resolveUpvalue(self: *Self, name: scanner.Token) ?u8 { 429 if (self.enclosing) |enclosing| { 430 if (enclosing.resolveLocal(name)) |local| { 431 const loc = &enclosing.locals[local]; 432 loc.captured = !loc.placeholder and !loc.immediate; 433 return self.addUpvalue( 434 local, 435 if (loc.placeholder) .empty else if (loc.immediate) .immediate else .local, 436 ) catch null; 437 } else if (enclosing.resolveUpvalue(name)) |upvalue| { 438 return self.addUpvalue(upvalue, .remote) catch null; 439 } 440 } 441 return null; 442 } 443 444 fn addUpvalue(self: *Self, idx: u8, tp: Upvalue.Type) !u8 { 445 const count = self.upvaluesCount; 446 447 for (self.upvalues[0..count], 0..) |upvalue, i| { 448 if (upvalue.index == idx and upvalue.type == tp) { 449 return @intCast(i); 450 } 451 } 452 453 if (count == upvalues_size) { 454 self.errorAtPrevious("Too many upvalues"); 455 self.lastError = error.OutOfMemory; 456 return self.lastError; 457 } 458 459 self.upvalues[count] = .{ .index = idx, .type = tp }; 460 self.upvaluesCount += 1; 461 return count; 462 } 463 464 fn resolveLocal(self: *Self, name: scanner.Token) ?u8 { 465 var i = self.localCount; 466 while (i > 0) : (i -= 1) { 467 if (identifiersEql(self.locals[i - 1].name, name)) { 468 if (self.locals[i - 1].depth) |_| { 469 return @intCast(i - 1); 470 } else { 471 self.errorAt(name, "Can't read local variable in it's own initializer"); 472 } 473 } 474 } 475 return null; 476 } 477 478 fn emitConstant(self: *Self, val: Value) void { 479 self.emit(OP.CONSTANT, self.makeConstant(val)); 480 } 481 482 fn makeConstant(self: *Self, val: Value) u8 { 483 return self.chunk.addConstant(val) catch |err| { 484 self.lastError = err; 485 self.errorAtPrevious("Too many constants in one chunk"); 486 return 0; 487 }; 488 } 489 490 fn grouping(self: *Self, _: bool) void { 491 self.expression(); 492 self.consume(Token.RIGHT_PAREN, "Expected ')' after expression"); 493 } 494 495 fn _and(self: *Self, _: bool) void { 496 const endJump = self.emitJump(OP.JUMP_IF_FALSE); 497 498 self.emitOP(OP.POP); 499 self.parsePrecedence(Precedence.AND); 500 self.patchJump(endJump); 501 } 502 503 fn _or(self: *Self, _: bool) void { 504 const elseJump = self.emitJump(OP.JUMP_IF_FALSE); 505 const endJump = self.emitJump(OP.JUMP); 506 507 self.patchJump(elseJump); 508 self.emitOP(OP.POP); 509 self.parsePrecedence(Precedence.OR); 510 self.patchJump(endJump); 511 } 512 513 fn unary(self: *Self, _: bool) void { 514 const operatorType = self.previous.type catch unreachable; 515 516 self.parsePrecedence(Precedence.UNARY); 517 518 switch (operatorType) { 519 Token.MINUS => self.emitOP(OP.NEGATE), 520 Token.BANG => self.emitOP(OP.NOT), 521 else => unreachable, 522 } 523 } 524 525 fn literal(self: *Self, _: bool) void { 526 switch (self.previous.type catch unreachable) { 527 Token.FALSE => self.emitOP(OP.FALSE), 528 Token.TRUE => self.emitOP(OP.TRUE), 529 Token.NIL => self.emitOP(OP.NIL), 530 else => unreachable, 531 } 532 } 533 534 fn binary(self: *Self, _: bool) void { 535 const operatorType = self.previous.type catch unreachable; 536 self.parsePrecedence(getRule(operatorType).precedence.inc()); 537 538 switch (operatorType) { 539 Token.PLUS => self.emitOP(OP.ADD), 540 Token.MINUS => self.emitOP(OP.SUBTRACT), 541 Token.STAR => self.emitOP(OP.MULTIPLY), 542 Token.SLASH => self.emitOP(OP.DIVIDE), 543 Token.BANG_EQUAL => self.emit2OP(OP.EQUAL, OP.NOT), 544 Token.EQUAL_EQUAL => self.emitOP(OP.EQUAL), 545 Token.GREATER => self.emitOP(OP.GREATER), 546 Token.GREATER_EQUAL => self.emit2OP(OP.LESS, OP.NOT), 547 Token.LESS => self.emitOP(OP.LESS), 548 Token.LESS_EQUAL => self.emit2OP(OP.GREATER, OP.NOT), 549 else => unreachable, 550 } 551 } 552 553 fn ternary(self: *Self, _: bool) void { 554 const operatorType = self.previous.type catch unreachable; 555 556 const thenJump = self.emitJump(OP.JUMP_IF_FALSE); 557 self.emitOP(OP.POP); 558 self.parsePrecedence(getRule(operatorType).precedence.inc()); 559 const elseJump = self.emitJump(OP.JUMP); 560 self.patchJump(thenJump); 561 562 self.consume(Token.COLON, "Expected ':' in ternary expression."); 563 564 self.emitOP(OP.POP); 565 self.parsePrecedence(getRule(operatorType).precedence.inc()); 566 self.patchJump(elseJump); 567 } 568 569 fn declaration(self: *Self) void { 570 if (self.match(Token.CLASS)) { 571 self.classDeclaration(); 572 } else if (self.match(Token.FUN)) { 573 self.funDeclaration(); 574 } else if (self.match(Token.VAR)) { 575 self.varDeclaration(); 576 } else if (self.match(Token.CON)) { 577 self.conDeclaration(); 578 } else { 579 self.statement(); 580 } 581 582 if (self.panicMode) self.synchronize(); 583 } 584 585 fn classDeclaration(self: *Self) void { 586 const global = self.parseVariable("Expect class name.", true) catch return; 587 self.markInitialized(); 588 self.class(self.previous.lexeme); 589 self.defineVariable(global, true); 590 } 591 592 fn makeIdentifier(name: []const u8) scanner.Token { 593 return .{ 594 .type = Token.IDENTIFIER, 595 .lexeme = name, 596 .line = -1, 597 .column = 0, 598 }; 599 } 600 601 fn classExpression(self: *Self, _: bool) void { 602 self.class(null); 603 } 604 605 fn class(self: *Self, name: ?[]const u8) void { 606 const cls = self.objects.emplace_cast(Obj.Type.Class, name, {}) catch |err| { 607 self.errorAtPrevious("Couldn't allocate class"); 608 self.lastError = err; 609 return; 610 }; 611 612 self.beginScope(); 613 614 self.emit(OP.CONSTANT, self.makeConstant(Value.init(cls))); 615 self.addLocal(makeIdentifier("this"), true); 616 self.markInitialized(); 617 self.markPlaceholder(); 618 619 const subclass = self.match(Token.LESS); 620 621 if (subclass) { 622 self.expression(); 623 self.addLocal(makeIdentifier("super"), true); 624 self.markInitialized(); 625 self.markImmediate(); 626 self.emitOP(OP.INHERIT); 627 } 628 629 self.consume(Token.LEFT_BRACE, "Expect '{' before class body"); 630 631 var curcls = Class{ .enclosing = self.currentClass, .hasSuperclass = subclass }; 632 self.currentClass = &curcls; 633 634 while (!self.check(Token.RIGHT_BRACE) and !self.check(Token.EOF)) { 635 self.method(); 636 } 637 638 self.currentClass = self.currentClass.?.enclosing; 639 640 self.consume(Token.RIGHT_BRACE, "Expect '}' after class body"); 641 self.endScope(); 642 } 643 644 fn method(self: *Self) void { 645 self.consume(Token.IDENTIFIER, "Expect method name"); 646 const constant = self.identifierConstant(self.previous) catch return; 647 self.function(true, self.previous.lexeme); 648 self.emit(OP.METHOD, constant); 649 self.emitByte(if (self.currentClass.?.hasSuperclass) 1 else 0); 650 } 651 652 fn funDeclaration(self: *Self) void { 653 const global = self.parseVariable("Expect function name.", true) catch return; 654 self.markInitialized(); 655 self.function(false, self.previous.lexeme); 656 self.defineVariable(global, true); 657 } 658 659 fn funExpression(self: *Self, _: bool) void { 660 self.function(false, null); 661 } 662 663 fn function(self: *Self, isMethod: bool, name: ?[]const u8) void { 664 const chunk = self.objects.emplace(.Chunk, name, {}) catch |err| { 665 self.errorAtPrevious("Couldn't allocate chunk"); 666 self.lastError = err; 667 return; 668 }; 669 670 var compiler = Self.init_enclosed(self, chunk) catch |err| { 671 self.errorAtPrevious("Couldn't init enclosed function"); 672 self.lastError = err; 673 return; 674 }; 675 676 compiler.initializer = if (name) |n| isMethod and std.mem.eql(u8, n, "init") else false; 677 678 compiler.objects.push_callback(&gc_callback, &compiler) catch @panic("Couln't push callback"); 679 defer compiler.objects.pop_callback(); 680 681 var arity: u8 = 0; 682 683 compiler.consume(Token.LEFT_PAREN, "Expect '(' in function definition"); 684 if (!compiler.check(Token.RIGHT_PAREN)) { 685 while (true) { 686 if (arity == std.math.maxInt(@TypeOf(arity))) { 687 self.errorAtCurrent("Too many arguments to a function"); 688 return; 689 } 690 arity += 1; 691 compiler.defineVariable(compiler.parseVariable("Expect parameter name.", true) catch return, true); 692 if (!compiler.match(Token.COMMA)) break; 693 } 694 } 695 compiler.consume(Token.RIGHT_PAREN, "Expect ')' after parameters"); 696 697 compiler.consume(Token.LEFT_BRACE, "Expect '{' before function body"); 698 699 compiler.block(); 700 701 self.current = compiler.current; 702 703 if (compiler.hadError) { 704 self.lastError = compiler.lastError; 705 } else { 706 const endchunk = compiler.end() catch return; 707 if (compiler.upvaluesCount == 0) { 708 const fun = self.objects.emplace(.Function, name, .{ 709 .chunk = endchunk, 710 .arity = arity, 711 }) catch |err| { 712 self.errorAtPrevious("Couldn't allocate function"); 713 self.lastError = err; 714 return; 715 }; 716 self.emit(OP.CONSTANT, self.makeConstant(Value.init(fun.cast()))); 717 } else { 718 self.emit(OP.CLOSURE, self.makeConstant(Value.init(endchunk.cast()))); 719 720 self.emitByte(arity); 721 self.emitByte(compiler.upvaluesCount); 722 for (compiler.upvalues[0..compiler.upvaluesCount]) |upvalue| { 723 self.emitByte(@intFromEnum(upvalue.type)); 724 self.emitByte(upvalue.index); 725 } 726 } 727 } 728 } 729 730 fn varDeclaration(self: *Self) void { 731 const global = self.parseVariable("Expect variable name.", false) catch return; 732 733 if (self.match(Token.EQUAL)) { 734 self.expression(); 735 } else { 736 self.emitOP(OP.NIL); 737 } 738 739 self.consume(Token.SEMICOLON, "Expect ';' after variable declaration."); 740 741 self.defineVariable(global, false); 742 } 743 744 fn conDeclaration(self: *Self) void { 745 const global = self.parseVariable("Expect variable name.", true) catch return; 746 747 self.consume(Token.EQUAL, "Constant variable has to be initialized."); 748 749 self.expression(); 750 751 self.consume(Token.SEMICOLON, "Expect ';' after variable declaration."); 752 753 self.defineVariable(global, true); 754 } 755 756 fn parseVariable(self: *Self, errorMessage: []const u8, con: bool) !u8 { 757 self.consume(Token.IDENTIFIER, errorMessage); 758 759 self.declareVariable(con); 760 if (self.scopeDepth > 0) return 0; 761 762 return self.identifierConstant(self.previous); 763 } 764 765 fn identifierConstant(self: *Self, tok: scanner.Token) !u8 { 766 return self.makeConstant(Value.init(self.objects.emplace_cast(.String, null, &.{tok.lexeme}) catch |err| { 767 self.lastError = err; 768 self.errorAtPrevious("Couldn't allocate identifier"); 769 return err; 770 })); 771 } 772 773 fn declareVariable(self: *Self, con: bool) void { 774 if (self.scopeDepth == 0) return; 775 776 var i = self.localCount; 777 while (i > 0) : (i -= 1) { 778 const local = self.locals[i - 1]; 779 if (local.depth) |depth| { 780 if (depth < self.scopeDepth) break; 781 } 782 783 if (identifiersEql(local.name, self.previous)) { 784 self.errorAtPrevious("Already a variable with this name in this scope."); 785 } 786 } 787 788 self.addLocal(self.previous, con); 789 } 790 791 fn identifiersEql(a: scanner.Token, b: scanner.Token) bool { 792 return std.mem.eql(u8, a.lexeme, b.lexeme); 793 } 794 795 fn addLocal(self: *Self, name: scanner.Token, con: bool) void { 796 if (self.localCount == size) { 797 self.errorAt(name, "Too many variables in function"); 798 return; 799 } 800 self.locals[self.localCount] = Local{ .name = name, .con = con }; 801 self.localCount += 1; 802 } 803 804 fn markInitialized(self: *Self) void { 805 if (self.scopeDepth == 0) return; 806 self.locals[self.localCount - 1].depth = self.scopeDepth; 807 } 808 809 fn markPlaceholder(self: *Self) void { 810 if (self.scopeDepth == 0) return; 811 self.locals[self.localCount - 1].placeholder = true; 812 } 813 814 fn markImmediate(self: *Self) void { 815 if (self.scopeDepth == 0) return; 816 self.locals[self.localCount - 1].immediate = true; 817 } 818 819 fn defineVariable(self: *Self, global: u8, con: bool) void { 820 if (self.scopeDepth > 0) { 821 self.markInitialized(); 822 return; 823 } 824 825 if (con) { 826 self.emit(OP.DEFINE_GLOBAL_CONSTANT, global); 827 } else { 828 self.emit(OP.DEFINE_GLOBAL, global); 829 } 830 } 831 832 fn synchronize(self: *Self) void { 833 self.panicMode = false; 834 835 while ((self.current.type catch Token.NIL) != Token.EOF) { 836 if ((self.previous.type catch Token.NIL) == Token.SEMICOLON) return; 837 switch (self.current.type catch Token.NIL) { 838 Token.CLASS, Token.VAR, Token.CON, Token.IF, Token.FOR, Token.WHILE, Token.SWITCH, Token.PRINT, Token.LEFT_BRACE, Token.RETURN => return, 839 else => self.advance(), 840 } 841 } 842 } 843 844 fn statement(self: *Self) void { 845 if (self.match(Token.PRINT)) { 846 self.printStatement(); 847 } else if (self.match(Token.IF)) { 848 self.ifStatement(); 849 } else if (self.match(Token.RETURN)) { 850 self.returnStatement(); 851 } else if (self.match(Token.WHILE)) { 852 self.whileStatement(); 853 } else if (self.match(Token.FOR)) { 854 self.forStatement(); 855 } else if (self.match(Token.SWITCH)) { 856 self.switchStatement(); 857 } else if (self.match(Token.LEFT_BRACE)) { 858 self.beginScope(); 859 self.block(); 860 self.endScope(); 861 } else { 862 self.expressionStatement(); 863 } 864 } 865 866 fn returnStatement(self: *Self) void { 867 if (self.enclosing == null) { 868 self.errorAtPrevious("Can't return from top-level code"); 869 return; 870 } 871 if (self.match(Token.SEMICOLON)) { 872 self.emitReturn(); 873 } else if (self.initializer) { 874 self.errorAtCurrent("Can't return a value from an initializer"); 875 } else { 876 self.expression(); 877 self.consume(Token.SEMICOLON, "Expect ';' after return value"); 878 self.emitOP(OP.RETURN); 879 } 880 } 881 882 fn switchStatement(self: *Self) void { 883 var defaultPresent = false; 884 var argCount: u8 = 0; 885 886 self.consume(Token.LEFT_PAREN, "Expect '(' after 'switch'."); 887 888 self.emitObj(.Native, "L::table", Obj.Native.Arg{ 889 .fun = vm_native.table, 890 }) catch return; 891 892 var jumpOver = self.emitJump(OP.JUMP); 893 const switchExpression = self.chunk.code.ptr().len; 894 self.expression(); 895 896 self.consume(Token.RIGHT_PAREN, "Expect ')' after expression"); 897 898 self.emitOP(OP.GET_INDEX); 899 const defaultJump = self.emitJump(OP.JUMP_IF_FALSE); 900 self.emitOP(OP.JUMP_POP); 901 const switchJump = self.chunk.code.ptr().len; 902 const exitJump = self.emitJump(OP.JUMP); 903 904 self.patchJump(jumpOver); 905 906 self.consume(Token.LEFT_BRACE, "Expect '{' after switch()"); 907 908 while (!self.match(Token.RIGHT_BRACE)) { 909 if (self.match(Token.CASE)) { 910 self.expression(); 911 argCount += 2; 912 const distance = self.chunk.code.ptr().len - switchJump + 5; 913 if (distance > std.math.maxInt(u52)) { 914 self.errorAtCurrent("Switch body too large"); 915 return; 916 } 917 self.emitConstant(Value.init(@as(Value.tagType(.number), @floatFromInt(distance)))); 918 jumpOver = self.emitJump(OP.JUMP); 919 } else if (self.match(Token.DEFAULT)) { 920 if (defaultPresent) { 921 self.errorAtCurrent("Duplicate default"); 922 return; 923 } 924 jumpOver = self.emitJump(OP.JUMP); 925 self.patchJump(defaultJump); 926 self.emitOP(OP.POP); 927 defaultPresent = true; 928 } else { 929 self.errorAtCurrent("Expect 'case' or 'default'"); 930 return; 931 } 932 self.consume(Token.COLON, "Expect ':' after case"); 933 self.statement(); 934 self.emitLoop(switchJump); 935 self.patchJump(jumpOver); 936 } 937 self.emit(OP.CALL, argCount); 938 self.emitLoop(switchExpression); 939 940 if (!defaultPresent) { 941 self.patchJump(defaultJump); 942 self.emitOP(OP.POP); 943 self.emitLoop(switchJump); 944 } 945 946 self.patchJump(exitJump); 947 } 948 949 fn whileStatement(self: *Self) void { 950 const loopStart = self.chunk.code.ptr().len; 951 952 self.consume(Token.LEFT_PAREN, "Expect '(' after 'while'."); 953 self.expression(); 954 self.consume(Token.RIGHT_PAREN, "Expect ')' after condition"); 955 956 const exitJump = self.emitJump(OP.JUMP_IF_FALSE); 957 self.emitOP(OP.POP); 958 if (!self.match(Token.SEMICOLON)) { 959 self.statement(); 960 } 961 self.emitLoop(loopStart); 962 963 self.patchJump(exitJump); 964 self.emitOP(OP.POP); 965 } 966 967 fn forStatement(self: *Self) void { 968 self.beginScope(); 969 self.consume(Token.LEFT_PAREN, "Expect '(' after 'for'."); 970 971 if (self.match(Token.SEMICOLON)) { 972 // Empty initializer 973 } else if (self.match(Token.VAR)) { 974 self.varDeclaration(); 975 } else if (self.match(Token.CON)) { 976 self.conDeclaration(); 977 } else { 978 self.expressionStatement(); 979 } 980 981 var loopStart = self.chunk.code.ptr().len; 982 983 var exitJump: ?usize = null; 984 if (!self.match(Token.SEMICOLON)) { 985 self.expression(); 986 self.consume(Token.SEMICOLON, "Expect ';' after condition clause"); 987 988 exitJump = self.emitJump(OP.JUMP_IF_FALSE); 989 self.emitOP(OP.POP); 990 } 991 992 if (!self.match(Token.RIGHT_PAREN)) { 993 const bodyJump = self.emitJump(OP.JUMP); 994 const incrementStart = self.chunk.code.ptr().len; 995 self.expression(); 996 self.emitOP(OP.POP); 997 self.consume(Token.RIGHT_PAREN, "Expect ')' after increment clause"); 998 999 self.emitLoop(loopStart); 1000 loopStart = incrementStart; 1001 self.patchJump(bodyJump); 1002 } 1003 if (!self.match(Token.SEMICOLON)) { 1004 self.statement(); 1005 } 1006 self.emitLoop(loopStart); 1007 1008 if (exitJump) |jump| { 1009 self.patchJump(jump); 1010 self.emitOP(OP.POP); 1011 } 1012 self.endScope(); 1013 } 1014 1015 fn emitLoop(self: *Self, start: usize) void { 1016 self.emitOP(OP.LOOP); 1017 const offset = self.chunk.code.ptr().len - start + 2; 1018 1019 if (offset > std.math.maxInt(u16)) { 1020 self.errorAtPrevious("Loop body too large"); 1021 return; 1022 } 1023 1024 self.emitByte(@intCast((offset >> 8) & 0xff)); 1025 self.emitByte(@intCast(offset & 0xff)); 1026 } 1027 1028 fn ifStatement(self: *Self) void { 1029 self.consume(Token.LEFT_PAREN, "Expect '(' after 'if'."); 1030 self.expression(); 1031 self.consume(Token.RIGHT_PAREN, "Expect ')' after condition"); 1032 1033 const thenJump = self.emitJump(OP.JUMP_IF_FALSE); 1034 self.emitOP(OP.POP); 1035 self.statement(); 1036 const elseJump = self.emitJump(OP.JUMP); 1037 self.patchJump(thenJump); 1038 self.emitOP(OP.POP); 1039 if (self.match(Token.ELSE)) self.statement(); 1040 self.patchJump(elseJump); 1041 } 1042 1043 fn emitJump(self: *Self, instruction: OP) usize { 1044 self.emitOP(instruction); 1045 self.emitByte(0xff); 1046 self.emitByte(0xff); 1047 return self.chunk.code.ptr().len - 2; 1048 } 1049 1050 fn patchJump(self: *Self, offset: usize) void { 1051 const jump = self.chunk.code.ptr().len - offset - 2; 1052 if (jump > std.math.maxInt(u16)) { 1053 self.errorAtPrevious("Jump too large"); 1054 return; 1055 } 1056 1057 self.chunk.code.ptr().set(offset, @intCast((jump >> 8) & 0xff)) catch { 1058 self.errorAtPrevious("Invalid jump offset"); 1059 }; 1060 self.chunk.code.ptr().set(offset + 1, @intCast(jump & 0xff)) catch { 1061 self.errorAtPrevious("Invalid jump offset"); 1062 }; 1063 } 1064 1065 fn block(self: *Self) void { 1066 while (!self.check(Token.RIGHT_BRACE) and !self.check(Token.EOF)) { 1067 self.declaration(); 1068 } 1069 1070 self.consume(Token.RIGHT_BRACE, "Expect '}' after block."); 1071 } 1072 1073 fn beginScope(self: *Self) void { 1074 self.scopeDepth += 1; 1075 } 1076 1077 fn endScope(self: *Self) void { 1078 self.scopeDepth -= 1; 1079 1080 while (self.localCount > 0) { 1081 const local = self.locals[self.localCount - 1]; 1082 1083 if (local.depth) |depth| { 1084 if (depth <= self.scopeDepth) break; 1085 } else { 1086 self.errorAt(local.name, "Unitialized variable at scope end"); 1087 } 1088 1089 if (local.captured) { 1090 self.emitOP(OP.CLOSE_UPVALUE); 1091 } else if (!local.placeholder) { 1092 self.emitOP(OP.POP); 1093 } 1094 self.localCount -= 1; 1095 } 1096 } 1097 1098 fn expressionStatement(self: *Self) void { 1099 self.expression(); 1100 self.consume(Token.SEMICOLON, "Expect ';' after expression."); 1101 self.emitOP(OP.POP); 1102 } 1103 1104 fn match(self: *Self, token: Token) bool { 1105 if (!self.check(token)) return false; 1106 self.advance(); 1107 return true; 1108 } 1109 1110 fn check(self: *const Self, token: Token) bool { 1111 return if (self.current.type) |tp| tp == token else |_| false; 1112 } 1113 1114 fn printStatement(self: *Self) void { 1115 self.expression(); 1116 self.consume(Token.SEMICOLON, "Expect ';' after value."); 1117 self.emitOP(OP.PRINT); 1118 } 1119 1120 fn init(scan: *scanner.Scanner, objects: *GC, chunk: *Obj.Chunk) !Self { 1121 var self = Self{ 1122 .scanner = scan, 1123 .current = scanner.Token.Empty, 1124 .previous = scanner.Token.Empty, 1125 .panicMode = false, 1126 .hadError = false, 1127 .lastError = scanner.ScannerError.EmptyToken, 1128 .chunk = chunk, 1129 .objects = objects, 1130 .locals = @splat(Local{}), 1131 .localCount = 1, 1132 .scopeDepth = 0, 1133 .enclosing = null, 1134 .upvalues = @splat(Upvalue{ .index = 0, .type = .local }), 1135 .upvaluesCount = 0, 1136 .currentClass = null, 1137 .initializer = false, 1138 }; 1139 self.locals[0].depth = 0; 1140 1141 return self; 1142 } 1143 1144 fn init_enclosed(enclosing: *Self, chunk: *Obj.Chunk) !Self { 1145 var enclosed = try Self.init(enclosing.scanner, enclosing.objects, chunk); 1146 enclosed.current = enclosing.current; 1147 enclosed.enclosing = enclosing; 1148 enclosed.currentClass = enclosing.currentClass; 1149 enclosed.beginScope(); 1150 1151 return enclosed; 1152 } 1153 1154 fn gc_callback(self_ptr: *anyopaque) void { 1155 var self: *@This() = @ptrCast(@alignCast(self_ptr)); 1156 1157 self.objects.mark("C", self.chunk); 1158 } 1159 1160 pub fn compile(source: []const u8, objects: *GC) CompilerError!*Obj.Chunk { 1161 var scan = try scanner.Scanner.init(source); 1162 const chunk = try objects.emplace(.Chunk, "toplevel", {}); 1163 var self = try Self.init(&scan, objects, chunk); 1164 1165 try objects.push_callback(&gc_callback, &self); 1166 defer objects.pop_callback(); 1167 1168 self.advance(); 1169 1170 while (!self.match(Token.EOF)) { 1171 self.declaration(); 1172 } 1173 1174 return if (self.hadError) self.lastError else try self.end(); 1175 } 1176 }; 1177 }