DzLox

:)
git clone https://git.sr.ht/~ashymad/DzLox
Log | Files | Refs | Submodules | LICENSE

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 }