PageRenderTime 75ms CodeModel.GetById 15ms app.highlight 12ms RepoModel.GetById 29ms app.codeStats 0ms

/source/Parser.ooc

http://github.com/fperrad/ooc-lua
Unknown | 2234 lines | 1936 code | 298 blank | 0 comment | 0 complexity | a8a9aa5862e8ac43d17a84cb129ccde3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1
   2import math
   3import structs/ArrayList
   4
   5import Lexer
   6import Types
   7import Opcodes
   8
   9ExpKind: enum {
  10    VVOID,      /* no value */
  11    VNIL,
  12    VTRUE,
  13    VFALSE,
  14    VK,         /* info = index of constant in `k' */
  15    VKNUM,      /* nval = numerical value */
  16    VNONRELOC,  /* info = result register */
  17    VLOCAL,     /* info = local register */
  18    VUPVAL,     /* info = index of upvalue in 'upvalues' */
  19    VINDEXED,   /* t = table register/upvalue; idx = index R/K */
  20    VJMP,       /* info = instruction pc */
  21    VRELOCABLE, /* info = instruction pc */
  22    VCALL,      /* info = instruction pc */
  23    VVARARG     /* info = instruction pc */
  24
  25    vkisvar: inline func -> Bool {
  26        return (ExpKind VLOCAL <= this) && (this <= ExpKind VINDEXED)
  27    }
  28
  29    vkisinreg: inline func -> Bool {
  30        return (this == ExpKind VNONRELOC) || (this == ExpKind VLOCAL)
  31    }
  32
  33    hasmultret: inline func -> Bool {
  34        return (this == ExpKind VCALL) || (this == ExpKind VVARARG)
  35    }
  36}
  37
  38ExpDesc: cover {
  39    k: ExpKind
  40    ind_idx: Int16  /* index (R/K) */
  41    ind_t: UInt8  /* table (register or upvalue) */
  42    ind_vt: ExpKind  /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
  43    info: Int  /* for generic use */
  44    nval: Double  /* for VKNUM     lua_Number */
  45    t: Int  /* patch list of `exit when true' */
  46    f: Int  /* patch list of `exit when false' */
  47
  48    isnumeral: inline func -> Bool {
  49        return k == ExpKind VKNUM && t == NO_JUMP && f == NO_JUMP
  50    }
  51
  52    hasjumps: inline func -> Bool {
  53        return t != f
  54    }
  55}
  56
  57init_exp: inline func(e: ExpDesc@, k: ExpKind, info: Int) {
  58    e k = k
  59    e info = info
  60    e ind_idx = 0
  61    e ind_t = 0
  62    e ind_vt = ExpKind VVOID
  63    e f = NO_JUMP
  64    e t = NO_JUMP
  65}
  66
  67
  68
  69/* state needed to generate code for a given function */
  70FuncState: final class {
  71    f: LuaProto  /* current function header */
  72    h: Table  /* table to find (and reuse) elements in `k' */
  73    prev: FuncState  /* enclosing function */
  74    ls: Parser  /* lexical state */
  75    bl: BlockCnt*  /* chain of current blocks */
  76    lasttarget: Int  /* `pc' of last `jump target' */
  77    jpc: Int  /* list of pending jumps to `pc' */
  78    freereg: Int  /* first free register */
  79    firstlocal: Int  /* index of first local var of this function */
  80    nactvar: Short  /* number of active local variables */
  81
  82    init: func(=ls, =prev) {
  83        f = LuaProto new()
  84        f source = ls source
  85        f maxstacksize = 2  /* registers 0/1 are always valid */
  86        h = Table new(0, 0)
  87        bl = null
  88        lasttarget = 0
  89        jpc = NO_JUMP
  90        freereg = 0
  91        firstlocal = ls actvar getSize()
  92        nactvar = 0
  93    }
  94
  95
  96    finalize: func -> FuncState {
  97        luaK_ret(0, 0)  /* final return */
  98        removevars(0)
  99        version(debug) {
 100            assert(! bl)
 101        }
 102        return prev
 103    }
 104
 105
 106    getlocvar: func(i: Int) -> LocVar* {
 107        idx := ls actvar get(firstlocal + i)
 108        version(debug) {
 109            assert(idx < f locvars getSize())
 110        }
 111        return f locvars data as LocVar* + idx
 112    }
 113
 114    enterblock: func(_bl: BlockCnt@, _isbreakable: Bool) {
 115        _bl breaklist = NO_JUMP
 116        _bl isbreakable = _isbreakable
 117        _bl nactvar = nactvar
 118        _bl upval = false
 119        _bl previous = bl
 120        bl = _bl&
 121        version(debug) {
 122            assert(freereg == nactvar)
 123        }
 124    }
 125
 126    leaveblock: func {
 127        _bl := bl
 128        bl = _bl@ previous
 129        removevars(_bl@ nactvar)
 130        if (_bl@ upval)
 131            luaK_codeABC(OpCode OP_CLOSE, _bl@ nactvar, 0, 0)
 132        version(debug) {
 133            /* a block either controls scope or breaks (never both) */
 134            assert(!_bl@ isbreakable || !_bl@ upval)
 135            assert(_bl@ nactvar == nactvar)
 136        }
 137        freereg = nactvar  /* free registers */
 138        luaK_patchtohere(_bl@ breaklist)
 139    }
 140
 141    removevars: func(tolevel: Int) {
 142        pc := f code getSize()
 143        actvar := ls actvar
 144        while (nactvar > tolevel) {
 145            nactvar -= 1
 146            pvar := getlocvar(nactvar)
 147            pvar@ endpc = pc
 148            actvar removeAt(actvar lastIndex())
 149        }
 150    }
 151
 152
 153    searchupvalue: func(name: String) -> Int {
 154        up := f upvalues
 155        for (i in 0 .. up getSize())
 156            if (up get(i) name equals?(name))
 157                return i
 158        return -1  /* not found */
 159    }
 160
 161
 162    newupvalue: func(name: String, v: ExpDesc@) -> Int {
 163        up := f upvalues
 164        idx := up getSize()
 165        up add(UpvalDesc new(name, v k == ExpKind VLOCAL, v info))
 166        return idx
 167    }
 168
 169    searchvar: func(n: String) -> Int {
 170        i := nactvar - 1
 171        while (i >= 0) {
 172            pvar := getlocvar(i)
 173            if (pvar@ varname equals?(n))
 174                return i
 175            i -= 1
 176        }
 177        return -1;  /* not found */
 178    }
 179
 180/*
 181  Mark block where variable at given level was defined
 182  (to emit OP_CLOSE later).
 183*/
 184    markupval: func(level: Int) {
 185        _bl := bl
 186        while (_bl) {
 187            if (!(_bl@ nactvar > level))
 188                break
 189            _bl = _bl@ previous
 190        }
 191        if (_bl)
 192            _bl@ upval = true
 193    }
 194
 195
 196/*
 197  Find variable with given name 'n'. If it is an upvalue, add this
 198  upvalue into all intermediate functions.
 199*/
 200    singlevaraux: func(n: String, var: ExpDesc@, base: Int) -> ExpKind {
 201        v := searchvar(n)  /* look up locals at current level */
 202        if (v >= 0) {  /* found? */
 203            init_exp(var&, ExpKind VLOCAL, v)  /* variable is local */
 204            if (!base)
 205                markupval(v)  /* local will be used as an upval */
 206            return ExpKind VLOCAL
 207        }
 208        else {  /* not found as local at current level; try upvalues */
 209            idx := searchupvalue(n)  /* try existing upvalues */
 210            if (idx < 0) {  /* not found? */
 211                if (! prev || /* no more levels */
 212                      prev singlevaraux(n, var&, 0) == ExpKind VVOID) /* try upper levels */
 213                    return ExpKind VVOID;  /* not found; is a global */
 214                /* else was LOCAL or UPVAL */
 215                idx  = newupvalue(n, var&)  /* will be a new upvalue */
 216            }
 217            init_exp(var&, ExpKind VUPVAL, idx)
 218            return ExpKind VUPVAL
 219        }
 220    }
 221
 222
 223    luaK_nil: func(_from, n: Int) {
 224        pc := f code getSize()
 225        if (pc > lasttarget) {  /* no jumps to current position? */
 226            previous := f code data as Instruction* + pc - 1
 227            if (previous@ getOpcode() == OpCode OP_LOADNIL) {
 228                pfrom := previous@ getarg_A()
 229                pto := previous@ getarg_B()
 230                if (pfrom <= _from && _from <= pto + 1) {  /* can connect both? */
 231                    if (_from + n - 1 > pto)
 232                        previous@ = previous@ setarg_B(_from + n - 1)
 233                    return
 234                }
 235            }
 236        }
 237        luaK_codeABC(OpCode OP_LOADNIL, _from, _from + n - 1, 0)  /* else no optimization */
 238    }
 239
 240
 241    luaK_jump: func -> Int {
 242        save := jpc  /* save list of jumps to here */
 243        jpc = NO_JUMP
 244        j := luaK_codeABx(OpCode OP_JMP, 0, NO_JUMP + MAXARG_sBx)
 245        luaK_concat(j&, save)  /* keep them on hold */
 246        return j
 247    }
 248
 249
 250    luaK_ret: func(first, nret: Int) {
 251        luaK_codeABC(OpCode OP_RETURN, first, nret+1, 0)
 252    }
 253
 254
 255    _condjump: func(op: OpCode, A, B, C: Int) -> Int {
 256        luaK_codeABC(op, A, B, C)
 257        return luaK_jump()
 258    }
 259
 260
 261    _fixjump: func(pc, dest: Int) {
 262        jmp := f code data as Instruction* + pc
 263        offset := dest - (pc + 1)
 264        version(debug) {
 265            assert(dest != NO_JUMP)
 266        }
 267        if (offset abs() > MAXARG_sBx)
 268            ls syntaxError("control structure too long")
 269        jmp@ = jmp@ setarg_sBx(offset)
 270    }
 271
 272
 273/*
 274** returns current `pc' and marks it as a jump target (to avoid wrong
 275** optimizations with consecutive instructions not in the same basic block).
 276*/
 277    luaK_getlabel: func -> Int {
 278        lasttarget = f code getSize()
 279        return lasttarget
 280    }
 281
 282
 283    _getjump: func(pc: Int) -> Int {
 284        offset := f code get(pc) getarg_sBx()
 285        if (offset == NO_JUMP)  /* point to itself represents end of list */
 286            return NO_JUMP  /* end of list */
 287        else
 288            return pc + 1 + offset  /* turn offset into absolute position */
 289    }
 290
 291
 292    _getjumpcontrol: func(pc: Int) -> Instruction* {
 293        pi := f code data as Instruction* + pc
 294        if (pc >= 1 && (pi-1)@ getOpcode() testTMode())
 295            return pi - 1
 296        else
 297            return pi
 298    }
 299
 300
 301/*
 302** check whether list has any jump that do not produce a value
 303** (or produce an inverted value)
 304*/
 305    _need_value: func(list: Int) -> Bool {
 306        while (list != NO_JUMP) {
 307            i := _getjumpcontrol(list)@
 308            if (i getOpcode() != OpCode OP_TESTSET)
 309                return true
 310            list = _getjump(list)
 311        }
 312        return false  /* not found */
 313    }
 314
 315
 316    _patchtestreg: func(node, reg: Int) -> Int {
 317        i := _getjumpcontrol(node)
 318        if (i@ getOpcode() != OpCode OP_TESTSET)
 319            return 0;  /* cannot patch other instructions */
 320        if (reg != NO_REG && reg != i@ getarg_B())
 321            i@ = i@ setarg_A(reg)
 322        else  /* no register to put value or register already has the value */
 323            i@ = Instruction createABC(OpCode OP_TEST, i@ getarg_B(), 0, i@ getarg_C())
 324
 325        return 1
 326    }
 327
 328
 329    _removevalues: func(list: Int) {
 330        while (list != NO_JUMP) {
 331            _patchtestreg(list, NO_REG)
 332            list = _getjump(list)
 333        }
 334    }
 335
 336
 337    _patchlistaux: func(list, vtarget, reg, dtarget: Int) {
 338        while (list != NO_JUMP) {
 339            next := _getjump(list)
 340            if (_patchtestreg(list, reg))
 341                _fixjump(list, vtarget)
 342            else
 343                _fixjump(list, dtarget)  /* jump to default target */
 344            list = next
 345        }
 346    }
 347
 348
 349    _dischargejpc: func {
 350        pc := f code getSize()
 351        _patchlistaux(jpc, pc, NO_REG, pc)
 352        jpc = NO_JUMP
 353    }
 354
 355
 356    luaK_patchlist: func(list, target: Int) {
 357        pc := f code getSize()
 358        if (target == pc)
 359            luaK_patchtohere(list)
 360        else {
 361            version(debug) {
 362                assert(target < pc)
 363            }
 364            _patchlistaux(list, target, NO_REG, target)
 365        }
 366    }
 367
 368
 369    luaK_patchtohere: func(list: Int) {
 370        luaK_getlabel()
 371        luaK_concat(jpc&, list)
 372    }
 373
 374
 375    luaK_concat: func(l1: Int*, l2: Int) {
 376        if (l2 == NO_JUMP)
 377            return
 378        else if (l1@ == NO_JUMP)
 379            l1@ = l2
 380        else {
 381            list := l1@
 382            next := _getjump(list)
 383            while (next != NO_JUMP) {  /* find last element */
 384                list = next
 385                next = _getjump(next)
 386            }
 387            _fixjump(list, l2)
 388        }
 389    }
 390
 391
 392    luaK_code: func(i: Instruction) -> Int{
 393        _dischargejpc()  /* `pc' will change */
 394        pc := f code getSize()
 395        /* put new instruction in code array */
 396        f code add(i)
 397        /* save corresponding line information */
 398        f lineinfo add(ls lastline)
 399        return pc
 400    }
 401
 402
 403   luaK_codeABC: func(o: OpCode, a, b, c: Int) -> Int {
 404        version(debug) {
 405            assert(o getOpMode() == OpMode iABC)
 406            assert(o getBMode() != OpArgMask OpArgN || b == 0)
 407            assert(o getCMode() != OpArgMask OpArgN || c == 0)
 408            assert(a <= MAXARG_A)
 409            assert(b <= MAXARG_B)
 410            assert(c <= MAXARG_C)
 411        }
 412        return luaK_code(Instruction createABC(o, a, b, c))
 413    }
 414
 415
 416    luaK_codeABx: func(o: OpCode, a: Int, bc: UInt) -> Int {
 417        version(debug) {
 418            assert(o getOpMode() == OpMode iABx || o getOpMode() == OpMode iAsBx)
 419            assert(o getCMode() == OpArgMask OpArgN)
 420            assert(a <= MAXARG_A)
 421            assert(bc <= MAXARG_Bx)
 422        }
 423        return luaK_code(Instruction createABx(o, a, bc))
 424    }
 425
 426
 427    luaK_codeABxX: func(o: OpCode, reg, k: Int) -> Int {
 428        if (k < MAXARG_Bx)
 429            return luaK_codeABx(o, reg, k + 1)
 430        else {
 431            p := luaK_codeABx(o, reg, 0)
 432            version(debug) {
 433                assert(k <= MAXARG_Ax)
 434            }
 435            luaK_code(Instruction createAx(OpCode OP_EXTRAARG, k))
 436            return p
 437        }
 438    }
 439
 440
 441    luaK_checkstack: func(n: Int) {
 442        newstack := freereg + n
 443        if (newstack > f maxstacksize) {
 444            if (newstack >= MAXSTACK)
 445                ls syntaxError("function or expression too complex")
 446            f maxstacksize = newstack
 447        }
 448    }
 449
 450
 451    luaK_reserveregs: func(n: Int) {
 452        luaK_checkstack(n)
 453        freereg += n
 454    }
 455
 456
 457    _freereg: func(reg: Int) {
 458        if (!(reg & BITRK) && reg >= nactvar) {
 459            freereg -= 1
 460            version(debug) {
 461                assert(reg == freereg)
 462            }
 463        }
 464    }
 465
 466
 467    _freeexp: func(e: ExpDesc@) {
 468        if (e k == ExpKind VNONRELOC)
 469            _freereg(e info)
 470    }
 471
 472
 473    _addk: func(key, v: LuaAny) -> Int {
 474        n := h get(key)
 475        if (n) {
 476            k := n as LuaNumber v as Int
 477            if (f k get(k) eq(v))
 478                return k
 479                /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0");
 480                   go through and create a new entry for this value */
 481        }
 482        /* constant not found; create a new entry */
 483        nk := f k getSize()
 484        h set(key, LuaNumber new(nk))
 485        f k add(v)
 486        return nk
 487    }
 488
 489
 490    luaK_stringK: func(s: String) -> Int {
 491        o := LuaString new(s)
 492        return _addk(o, o)
 493    }
 494
 495
 496    luaK_numberK: func(r: Double) -> Int {
 497        o := LuaNumber new(r)
 498        if (r == 0 || !(r == r)) {  /* handle -0 and NaN */
 499            /* use raw representation as key to avoid numeric problems */
 500            k := LuaString new(r toString())
 501            return _addk(k, o)
 502        }
 503        else
 504            return _addk(o, o)  /* regular case */
 505    }
 506
 507
 508    _boolK: func(b: Bool) -> Int {
 509        o := LuaBoolean new(b)
 510        return _addk(o, o)
 511    }
 512
 513
 514    _nilK: func -> Int {
 515        o := LuaNil new()
 516        return _addk(o, o)
 517    }
 518
 519
 520    luaK_setreturns: func(e: ExpDesc@, nresults: Int) {
 521        pi := f code data as Instruction* + e info
 522        if (e k == ExpKind VCALL) {  /* expression is an open function call? */
 523            pi@ = pi@ setarg_C(nresults + 1)
 524        }
 525        else if (e k == ExpKind VVARARG) {
 526            pi@ = pi@ setarg_B(nresults + 1)
 527            pi@ = pi@ setarg_A(freereg)
 528            luaK_reserveregs(1)
 529        }
 530    }
 531
 532
 533    luaK_setoneret: func(e: ExpDesc@) {
 534        pi := f code data as Instruction* + e info
 535        if (e k == ExpKind VCALL) {  /* expression is an open function call? */
 536            e k = ExpKind VNONRELOC
 537            e info = pi@ getarg_A()
 538        }
 539        else if (e k == ExpKind VVARARG) {
 540            pi@ = pi@ setarg_B(2)
 541            e k = ExpKind VRELOCABLE  /* can relocate its simple result */
 542        }
 543    }
 544
 545
 546    luaK_dischargevars: func(e: ExpDesc@) {
 547        k := e k
 548        match {
 549            case k == ExpKind VLOCAL =>
 550                e k = ExpKind VNONRELOC
 551            case k == ExpKind VUPVAL =>
 552                e info = luaK_codeABC(OpCode OP_GETUPVAL, 0, e info, 0)
 553                e k = ExpKind VRELOCABLE
 554            case k == ExpKind VINDEXED =>
 555                op := OpCode OP_GETTABUP  /* assume 't' is in an upvalue */
 556                _freereg(e ind_idx)
 557                if (e ind_vt == ExpKind VLOCAL) {  /* 't' is in a register? */
 558                    _freereg(e ind_t)
 559                    op = OpCode OP_GETTABLE
 560                }
 561                e info = luaK_codeABC(op, 0, e ind_t, e ind_idx)
 562                e k = ExpKind VRELOCABLE
 563            case k == ExpKind VVARARG ||
 564                 k == ExpKind VCALL =>
 565                luaK_setoneret(e&)
 566        }
 567    }
 568
 569
 570    _code_label: func(A, b, jump: Int) -> Int {
 571        luaK_getlabel()  /* those instructions may be jump targets */
 572        return luaK_codeABC(OpCode OP_LOADBOOL, A, b, jump)
 573    }
 574
 575
 576    _discharge2reg: func(e: ExpDesc@, reg: Int) {
 577        luaK_dischargevars(e&)
 578        match (e k) {
 579            case ExpKind VNIL =>
 580                luaK_nil(reg, 1)
 581            case ExpKind VFALSE =>
 582                luaK_codeABC(OpCode OP_LOADBOOL, reg, 0, 0)
 583            case ExpKind VTRUE =>
 584                luaK_codeABC(OpCode OP_LOADBOOL, reg, 1, 0)
 585            case ExpKind VK =>
 586                luaK_codeABxX(OpCode OP_LOADK, reg, e info)
 587            case ExpKind VKNUM =>
 588                luaK_codeABxX(OpCode OP_LOADK, reg, luaK_numberK(e nval))
 589            case ExpKind VRELOCABLE =>
 590                pc := f code data as Instruction* + e info
 591                pc@ = pc@ setarg_A(reg)
 592            case ExpKind VNONRELOC =>
 593                if (reg != e info)
 594                    luaK_codeABC(OpCode OP_MOVE, reg, e info, 0)
 595            case =>
 596                version(debug) {
 597                    assert(e k == ExpKind VVOID || e k == ExpKind VJMP)
 598                }
 599                return  /* nothing to do... */
 600        }
 601        e info = reg
 602        e k = ExpKind VNONRELOC
 603    }
 604
 605
 606    _discharge2anyreg: func(e: ExpDesc@) {
 607        if (e k != ExpKind VNONRELOC) {
 608            luaK_reserveregs(1)
 609            _discharge2reg(e&, freereg-1)
 610        }
 611    }
 612
 613
 614    _exp2reg: func(e: ExpDesc@, reg: Int) {
 615        _discharge2reg(e&, reg)
 616        if (e k == ExpKind VJMP)
 617            luaK_concat(e t&, e info)  /* put this jump in `t' list */
 618        if (e hasjumps()) {
 619            p_f := NO_JUMP  /* position of an eventual LOAD false */
 620            p_t := NO_JUMP  /* position of an eventual LOAD true */
 621            if (_need_value(e t) || _need_value(e f)) {
 622                fj := (e k == ExpKind VJMP) ? NO_JUMP : luaK_jump()
 623                p_f = _code_label(reg, 0, 1)
 624                p_t = _code_label(reg, 1, 0)
 625                luaK_patchtohere(fj)
 626            }
 627            _final := luaK_getlabel()  /* position after whole expression */
 628            _patchlistaux(e f, _final, reg, p_f)
 629            _patchlistaux(e t, _final, reg, p_t)
 630        }
 631        e f = NO_JUMP
 632        e t = NO_JUMP
 633        e info = reg
 634        e k = ExpKind VNONRELOC
 635    }
 636
 637
 638    luaK_exp2nextreg: func(e: ExpDesc@) {
 639        luaK_dischargevars(e&)
 640        _freeexp(e&)
 641        luaK_reserveregs(1)
 642        _exp2reg(e&, freereg - 1)
 643    }
 644
 645
 646    luaK_exp2anyreg: func(e: ExpDesc@) -> Int {
 647        luaK_dischargevars(e&)
 648        if (e k == ExpKind VNONRELOC) {
 649            if (! e hasjumps())
 650                return e info  /* exp is already in a register */
 651            if (e info >= nactvar) {  /* reg. is not a local? */
 652                _exp2reg(e&, e info)  /* put value on it */
 653                return e info
 654            }
 655        }
 656        luaK_exp2nextreg(e&)  /* default */
 657        return e info
 658    }
 659
 660
 661    luaK_exp2anyregup: func(e: ExpDesc@) {
 662        if (e k != ExpKind VUPVAL || e hasjumps())
 663            luaK_exp2anyreg(e&)
 664    }
 665
 666
 667    luaK_exp2val: func(e: ExpDesc@) {
 668        if (e hasjumps())
 669            luaK_exp2anyreg(e&)
 670        else
 671            luaK_dischargevars(e&)
 672    }
 673
 674
 675    luaK_exp2RK: func(e: ExpDesc@) -> Int {
 676        luaK_exp2val(e&)
 677        k := e k
 678        nk := f k getSize()
 679        match {
 680            case k == ExpKind VTRUE ||
 681                 k == ExpKind VFALSE ||
 682                 k == ExpKind VNIL =>
 683                if (nk <= MAXINDEXRK) {  /* constant fits in RK operand? */
 684                    e info = (e k == ExpKind VNIL) ? _nilK() : _boolK(e k == ExpKind VTRUE)
 685                    e k =  ExpKind VK
 686                    return e info | BITRK
 687                }
 688            case k == ExpKind VKNUM =>
 689                e info = luaK_numberK(e nval)
 690                e k = ExpKind VK
 691                if (e info <= MAXINDEXRK)  /* constant fits in argC? */
 692                    return e info | BITRK
 693            case k == ExpKind VK =>
 694                if (e info <= MAXINDEXRK)  /* constant fits in argC? */
 695                    return e info | BITRK
 696        }
 697        /* not a constant in the right range: put it in a register */
 698        return luaK_exp2anyreg(e&)
 699    }
 700
 701
 702    luaK_storevar: func(var, ex: ExpDesc@) {
 703        match (var k) {
 704            case ExpKind VLOCAL =>
 705                _freeexp(ex&)
 706                _exp2reg(ex&, var info)
 707            case ExpKind VUPVAL =>
 708                e := luaK_exp2anyreg(ex&)
 709                luaK_codeABC(OpCode OP_SETUPVAL, e, var info, 0)
 710            case ExpKind VINDEXED =>
 711                op := (var ind_vt == ExpKind VLOCAL) ? OpCode OP_SETTABLE : OpCode OP_SETTABUP
 712                e := luaK_exp2RK(ex&)
 713                luaK_codeABC(op, var ind_t, var ind_idx, e)
 714            case =>
 715                version(debug) {
 716                    assert(false)  /* invalid var kind to store */
 717                }
 718        }
 719        _freeexp(ex&)
 720    }
 721
 722
 723    luaK_self: func(e, key: ExpDesc@) {
 724        luaK_exp2anyreg(e&)
 725        _freeexp(e&)
 726        _func := freereg
 727        luaK_codeABC(OpCode OP_SELF, _func, e info, luaK_exp2RK(key&))
 728        _freeexp(key&)
 729        luaK_reserveregs(2)
 730        e info = _func
 731        e k = ExpKind VNONRELOC
 732    }
 733
 734
 735    _invertjump: func(e: ExpDesc@) {
 736        pc := _getjumpcontrol(e info)
 737        version(debug) {
 738            op := pc@ getOpcode()
 739            assert(op testTMode())
 740            assert(op != OpCode OP_TESTSET)
 741            assert(op != OpCode OP_TEST)
 742        }
 743        pc@ = pc@ setarg_A(pc@ getarg_A() == 0 ? 1 : 0)
 744    }
 745
 746
 747    _jumponcond: func(e: ExpDesc@, cond: Int) -> Int {
 748        if (e k == ExpKind VRELOCABLE) {
 749            ie := f code get(e info)
 750            if (ie getOpcode() == OpCode OP_NOT) {
 751                f code removeAt(f code lastIndex()) /* remove previous OP_NOT */
 752                return _condjump(OpCode OP_TEST, ie getarg_B(), 0, cond == 0 ? 1 : 0)
 753            }
 754            /* else go through */
 755        }
 756        _discharge2anyreg(e&)
 757        _freeexp(e&)
 758        return _condjump(OpCode OP_TESTSET, NO_REG, e info, cond)
 759    }
 760
 761
 762    luaK_goiftrue: func(e: ExpDesc@) {
 763        pc: Int  /* pc of last jump */
 764        luaK_dischargevars(e&)
 765        k := e k
 766        match {
 767            case k == ExpKind VK ||
 768                 k == ExpKind VKNUM ||
 769                 k == ExpKind VTRUE =>
 770                pc = NO_JUMP  /* always true; do nothing */
 771            case k == ExpKind VJMP =>
 772                _invertjump(e&)
 773                pc = e info
 774            case k == ExpKind VFALSE =>
 775                if (! e hasjumps())
 776                    pc = luaK_jump()  /* always jump */
 777                else
 778                    pc = _jumponcond(e&, 0)
 779            case =>
 780                pc = _jumponcond(e&, 0)
 781        }
 782        luaK_concat(e f&, pc)  /* insert last jump in `f' list */
 783        luaK_patchtohere(e t)
 784        e t = NO_JUMP
 785    }
 786
 787
 788    luaK_goiffalse: func(e: ExpDesc@) {
 789        pc: Int  /* pc of last jump */
 790        luaK_dischargevars(e&)
 791        k := e k
 792        match {
 793            case k == ExpKind VNIL ||
 794                 k == ExpKind VFALSE =>
 795                pc = NO_JUMP  /* always false; do nothing */
 796            case k == ExpKind VJMP =>
 797                pc = e info
 798            case k == ExpKind VTRUE =>
 799                if (! e hasjumps())
 800                    pc = luaK_jump()  /* always jump */
 801                else
 802                    pc = _jumponcond(e&, 1)
 803            case =>
 804                pc = _jumponcond(e&, 1)
 805        }
 806        luaK_concat(e t&, pc)  /* insert last jump in `t' list */
 807        luaK_patchtohere(e f)
 808        e f = NO_JUMP
 809    }
 810
 811
 812    _codenot: func(e: ExpDesc@) {
 813        luaK_dischargevars(e&)
 814        k := e k
 815        match {
 816            case k == ExpKind VNIL ||
 817                 k == ExpKind VFALSE =>
 818                e k = ExpKind VTRUE
 819            case k == ExpKind VK ||
 820                 k == ExpKind VKNUM ||
 821                 k == ExpKind VTRUE =>
 822                e k = ExpKind VFALSE
 823            case k == ExpKind VJMP =>
 824                _invertjump(e&)
 825            case k == ExpKind VRELOCABLE ||
 826                 k == ExpKind VNONRELOC =>
 827                _discharge2anyreg(e&)
 828                _freeexp(e&)
 829                e info = luaK_codeABC(OpCode OP_NOT, 0, e info, 0)
 830                e k = ExpKind VRELOCABLE
 831            case =>
 832                version(debug) {
 833                    assert(false)  /* cannot happen */
 834                }
 835        }
 836        /* interchange true and false lists */
 837        temp := e f; e f = e t; e t = temp
 838        _removevalues(e f)
 839        _removevalues(e t)
 840    }
 841
 842
 843    luaK_indexed: func(t, k: ExpDesc@) {
 844        version(debug) {
 845            assert(! t hasjumps())
 846        }
 847        t ind_t = t info
 848        t ind_idx = luaK_exp2RK(k&)
 849        version(debug) {
 850            if (t k != ExpKind VUPVAL)
 851                assert(t k vkisinreg())
 852        }
 853        t ind_vt = (t k == ExpKind VUPVAL) ? ExpKind VUPVAL : ExpKind VLOCAL
 854        t k = ExpKind VINDEXED
 855    }
 856
 857
 858    _constfolding: func(op: OpCode, e1, e2: ExpDesc@) -> Bool {
 859        if (! e1 isnumeral() || ! e2 isnumeral())
 860            return false
 861        if ((op == OpCode OP_DIV || op == OpCode OP_MOD) && e2 nval == 0)
 862            return false  /* do not attempt to divide by 0 */
 863        match (op) {
 864            case OpCode OP_ADD =>
 865                e1 nval = e1 nval + e2 nval
 866            case OpCode OP_SUB =>
 867                e1 nval = e1 nval - e2 nval
 868            case OpCode OP_MUL =>
 869                e1 nval = e1 nval * e2 nval
 870            case OpCode OP_DIV =>
 871                e1 nval = e1 nval / e2 nval
 872            case OpCode OP_MOD =>
 873                e1 nval = e1 nval - (e1 nval / e2 nval) floor() * e2 nval
 874            case OpCode OP_POW =>
 875                e1 nval = e1 nval pow(e2 nval)
 876            case =>
 877                assert(false)
 878        }
 879        return true
 880    }
 881
 882
 883    _codearith: func(op: OpCode, e1, e2: ExpDesc@, line: Int) {
 884        if (_constfolding(op, e1&, e2&))
 885            return
 886        else {
 887            o2 := (op != OpCode OP_UNM && op != OpCode OP_LEN) ? luaK_exp2RK(e2&) : 0
 888            o1 := luaK_exp2RK(e1&)
 889            if (o1 > o2) {
 890                _freeexp(e1&)
 891                _freeexp(e2&)
 892            }
 893            else {
 894                _freeexp(e2&)
 895                _freeexp(e1&)
 896            }
 897            e1 info = luaK_codeABC(op, 0, o1, o2)
 898            e1 k = ExpKind VRELOCABLE
 899            luaK_fixline(line)
 900        }
 901    }
 902
 903
 904    _codecomp: func(op: OpCode, cond: Int, e1, e2: ExpDesc@) {
 905        o1 := luaK_exp2RK(e1&)
 906        o2 := luaK_exp2RK(e2&)
 907        _freeexp(e2&)
 908        _freeexp(e1&)
 909        if (! cond && op != OpCode OP_EQ) {
 910            /* exchange args to replace by `<' or `<=' */
 911            temp := o1; o1 = o2; o2 = temp;  /* o1 <==> o2 */
 912            cond = 1
 913        }
 914        e1 info = _condjump(op, cond, o1, o2)
 915        e1 k = ExpKind VJMP
 916    }
 917
 918
 919    luaK_prefix: func(op: UnOpr, e: ExpDesc@, line: Int) {
 920        e2: ExpDesc
 921        e2 t = NO_JUMP
 922        e2 f = NO_JUMP
 923        e2 k = ExpKind VKNUM
 924        e2 nval = 0
 925        match (op) {
 926            case UnOpr OPR_MINUS =>
 927                if (e isnumeral())  /* minus constant? */
 928                    e nval = - e nval  /* fold it */
 929                else {
 930                    luaK_exp2anyreg(e&)
 931                    _codearith(OpCode OP_UNM, e&, e2&, line)
 932                }
 933            case UnOpr OPR_NOT =>
 934                _codenot(e&)
 935            case UnOpr OPR_LEN =>
 936                luaK_exp2anyreg(e&)  /* cannot operate on constants */
 937                _codearith(OpCode OP_LEN, e&, e2&, line)
 938            case =>
 939                version(debug) {
 940                    assert(false)
 941                }
 942        }
 943    }
 944
 945
 946    luaK_infix: func(op: BinOpr, v: ExpDesc@) {
 947        match {
 948            case op == BinOpr OPR_AND =>
 949                luaK_goiftrue(v&)
 950            case op == BinOpr OPR_OR =>
 951                luaK_goiffalse(v&)
 952            case op == BinOpr OPR_CONCAT =>
 953                luaK_exp2nextreg(v&)  /* operand must be on the `stack' */
 954            case op == BinOpr OPR_ADD ||
 955                 op == BinOpr OPR_SUB ||
 956                 op == BinOpr OPR_MUL ||
 957                 op == BinOpr OPR_DIV ||
 958                 op == BinOpr OPR_MOD ||
 959                 op == BinOpr OPR_POW =>
 960                if (! v isnumeral())
 961                    luaK_exp2RK(v&)
 962            case =>
 963                luaK_exp2RK(v&)
 964        }
 965    }
 966
 967
 968    luaK_posfix: func(op: BinOpr, e1, e2: ExpDesc@, line: Int) {
 969        match {
 970            case op == BinOpr OPR_AND =>
 971                version(debug) {
 972                    assert(e1 t == NO_JUMP)  /* list must be closed */
 973                }
 974                luaK_dischargevars(e2&)
 975                luaK_concat(e2 f&, e1 f)
 976                e1 = e2
 977            case op == BinOpr OPR_OR =>
 978                version(debug) {
 979                    assert(e1 f == NO_JUMP)  /* list must be closed */
 980                }
 981                luaK_dischargevars(e2&)
 982                luaK_concat(e2 t&, e1 t)
 983                e1 = e2
 984            case op == BinOpr OPR_CONCAT =>
 985                luaK_exp2val(e2&)
 986                pi := f code data as Instruction* + e2 info
 987                if (e2 k == ExpKind VRELOCABLE && pi@ getOpcode() == OpCode OP_CONCAT) {
 988                    version(debug) {
 989                        assert(e1 info == pi@ getarg_B() - 1)
 990                    }
 991                    _freeexp(e1&)
 992                    pi@ = pi@ setarg_B(e1 info)
 993                    e1 k = ExpKind VRELOCABLE
 994                    e1 info = e2 info
 995                }
 996                else {
 997                    luaK_exp2nextreg(e2&)  /* operand must be on the 'stack' */
 998                    _codearith(OpCode OP_CONCAT, e1&, e2&, line)
 999                }
1000            case op == BinOpr OPR_ADD =>
1001                _codearith(OpCode OP_ADD, e1&, e2&, line)
1002            case op == BinOpr OPR_SUB =>
1003                _codearith(OpCode OP_SUB, e1&, e2&, line)
1004            case op == BinOpr OPR_MUL =>
1005                _codearith(OpCode OP_MUL, e1&, e2&, line)
1006            case op == BinOpr OPR_DIV =>
1007                _codearith(OpCode OP_DIV, e1&, e2&, line)
1008            case op == BinOpr OPR_MOD =>
1009                _codearith(OpCode OP_MOD, e1&, e2&, line)
1010            case op == BinOpr OPR_POW =>
1011                _codearith(OpCode OP_POW, e1&, e2&, line)
1012            case op == BinOpr OPR_EQ =>
1013                _codecomp(OpCode OP_EQ, 1, e1&, e2&)
1014            case op == BinOpr OPR_LT =>
1015                _codecomp(OpCode OP_LT, 1, e1&, e2&)
1016            case op == BinOpr OPR_LE =>
1017                _codecomp(OpCode OP_LE, 1, e1&, e2&)
1018            case op == BinOpr OPR_NE =>
1019                _codecomp(OpCode OP_EQ, 0, e1&, e2&)
1020            case op == BinOpr OPR_GT =>
1021                _codecomp(OpCode OP_LT, 0, e1&, e2&)
1022            case op == BinOpr OPR_GE =>
1023                _codecomp(OpCode OP_LE, 0, e1&, e2&)
1024            case =>
1025                version(debug) {
1026                    assert(false)
1027                }
1028        }
1029    }
1030
1031
1032    luaK_fixline: func(line: Int) {
1033        f lineinfo set(f code getSize() - 1, line)
1034    }
1035
1036
1037    luaK_setlist: func(base, nelems, tostore: Int) {
1038        c :=  (nelems - 1)/LFIELDS_PER_FLUSH + 1
1039        b := (tostore == LUA_MULTRET) ? 0 : tostore
1040        version(debug) {
1041            assert(tostore != 0)
1042        }
1043        if (c <= MAXARG_C)
1044            luaK_codeABC(OpCode OP_SETLIST, base, b, c)
1045        else if (c <= MAXARG_Ax) {
1046            luaK_codeABC(OpCode OP_SETLIST, base, b, 0)
1047            version(debug) {
1048                assert(c <= MAXARG_Ax)
1049            }
1050            luaK_code(Instruction createAx(OpCode OP_EXTRAARG, c))
1051        }
1052        else
1053            ls syntaxError("constructor too long")
1054        freereg = base + 1  /* free registers with list values */
1055    }
1056
1057    checklimit: func(v, l: Int, what: String) {
1058        if (v > l) {
1059            line := f linedefined
1060            where := (line == 0) ? "main function" : "function at line %d" format(line)
1061            msg := "too many %s (limit is %d) in %s" format(what, l, where)
1062            ls syntaxError(msg)
1063        }
1064    }
1065
1066}
1067
1068
1069/*
1070** nodes for block list (list of active blocks)
1071*/
1072BlockCnt: cover {
1073    previous: BlockCnt*  /* chain */
1074    breaklist: Int  /* list of jumps out of this loop */
1075    nactvar: UInt8  /* # active locals outside the breakable structure */
1076    upval: Bool  /* true if some variable in the block is an upvalue */
1077    isbreakable: Bool  /* true if `block' is a loop */
1078}
1079
1080/*
1081** structure to chain all variables in the left-hand side of an
1082** assignment
1083*/
1084LHS_assign: cover {
1085    prev: LHS_assign*
1086    v: ExpDesc  /* variable (global, local, upvalue, or indexed) */
1087}
1088
1089
1090ConsControl: cover {
1091    v: ExpDesc  /* last list item read */
1092    t: ExpDesc*  /* table descriptor */
1093    nh: Int  /* total number of `record' elements */
1094    na: Int  /* total number of array elements */
1095    tostore: Int  /* number of array elements pending to be stored */
1096}
1097
1098
1099
1100Parser: final class extends Lexer {
1101    fs: FuncState  /* `FuncState' is private to the parser */
1102    actvar: ArrayList<UInt16>  /* list of all active local variables */
1103
1104    init: func {}
1105
1106
1107    parse: func(=actvar) -> LuaProto {
1108        _mainfunc()
1109        next()  /* read first token */
1110        chunk()  /* read main chunk */
1111        _check(TK_EOS)
1112        fs finalize()
1113        version(debug) {
1114            assert(! fs prev)
1115            assert(fs f upvalues getSize() == 1)
1116        }
1117        return fs f
1118    }
1119
1120/*============================================================*/
1121/* GRAMMAR RULES */
1122/*============================================================*/
1123
1124
1125    fieldsel: func(v: ExpDesc@) {
1126        /* fieldsel -> ['.' | ':'] NAME */
1127        key: ExpDesc
1128        fs luaK_exp2anyregup(v&)
1129        next()  /* skip the dot or colon */
1130        _checkname(key&)
1131        fs luaK_indexed(v&, key&)
1132    }
1133
1134
1135    yindex: func(v: ExpDesc@) {
1136        /* index -> '[' expr ']' */
1137        next()  /* skip the '[' */
1138        expr(v&)
1139        fs luaK_exp2val(v&)
1140        _checknext(']' as Int)
1141    }
1142
1143
1144/*
1145** {======================================================================
1146** Rules for Constructors
1147** =======================================================================
1148*/
1149
1150
1151    recfield: func(cc: ConsControl@) {
1152        /* recfield -> (NAME | `['exp1`]') = exp1 */
1153        reg := fs freereg
1154        key: ExpDesc
1155        if (t token == TK_NAME) {
1156            fs checklimit(cc nh, MAX_INT, "items in a constructor")
1157            _checkname(key&)
1158        }
1159        else  /* ls->t.token == '[' */
1160            yindex(key&)
1161        cc nh += 1
1162        _checknext('=' as Int)
1163        rkkey := fs luaK_exp2RK(key&)
1164        val: ExpDesc
1165        expr(val&)
1166        fs luaK_codeABC(OpCode OP_SETTABLE, cc t@ info, rkkey, fs luaK_exp2RK(val&))
1167        fs freereg = reg  /* free registers */
1168    }
1169
1170
1171    closelistfield: func(cc: ConsControl@) {
1172        if (cc v k == ExpKind VVOID)
1173            return;  /* there is no list item */
1174        fs luaK_exp2nextreg(cc v&)
1175        cc v k = ExpKind VVOID
1176        if (cc tostore == LFIELDS_PER_FLUSH) {
1177            fs luaK_setlist(cc t@ info, cc na, cc tostore)  /* flush */
1178            cc tostore = 0  /* no more items pending */
1179        }
1180    }
1181
1182
1183    lastlistfield: func(cc: ConsControl@) {
1184        if (cc tostore == 0)
1185            return
1186        if (cc v k hasmultret()) {
1187            fs luaK_setreturns(cc v&, LUA_MULTRET)
1188            fs luaK_setlist(cc t@ info, cc na, LUA_MULTRET)
1189            cc na -= 1  /* do not count last expression (unknown number of elements) */
1190        }
1191        else {
1192            if (cc v k != ExpKind VVOID)
1193                fs luaK_exp2nextreg(cc v&)
1194            fs luaK_setlist(cc t@ info, cc na, cc tostore)
1195        }
1196    }
1197
1198
1199    listfield: func(cc: ConsControl@) {
1200        /* listfield -> exp */
1201        expr(cc v&)
1202        fs checklimit(cc na, MAX_INT, "items in a constructor")
1203        cc na += 1
1204        cc tostore += 1
1205    }
1206
1207
1208    field: func(cc: ConsControl@) {
1209        /* field -> listfield | recfield */
1210        match (t token) {
1211            case TK_NAME =>  /* may be 'listfield' or 'recfield' */
1212                if (lookahead() != '=')  /* expression? */
1213                    listfield(cc&)
1214                else
1215                    recfield(cc&)
1216            case '[' =>
1217                recfield(cc&)
1218            case =>
1219                listfield(cc&)
1220        }
1221    }
1222
1223
1224    constructor: func(_t: ExpDesc@) {
1225        /* constructor -> '{' [ field { sep field } [sep] ] '}'
1226           sep -> ',' | ';' */
1227        line := linenumber
1228        pc := fs luaK_codeABC(OpCode OP_NEWTABLE, 0, 0, 0)
1229        cc: ConsControl
1230        cc na = 0
1231        cc nh = 0
1232        cc tostore = 0
1233        cc t = _t&
1234        init_exp(_t&, ExpKind VRELOCABLE, pc)
1235        init_exp(cc v&, ExpKind VVOID, 0)  /* no value (yet) */
1236        fs luaK_exp2nextreg(_t&)  /* fix it at stack top (for gc) */
1237        _checknext('{' as Int)
1238        while (true) {
1239            version(debug) {
1240                assert(cc v k == ExpKind VVOID || cc tostore > 0)
1241            }
1242            if (t token == '}')
1243                break
1244            closelistfield(cc&)
1245            field(cc&)
1246            if (! _testnext(',' as Int) && ! _testnext(';' as Int))
1247                break
1248        }
1249        _check_match('}' as Int, '{' as Int, line)
1250        lastlistfield(cc&)
1251        pi := fs f code data as Instruction* + pc
1252        pi@ = pi@ setarg_B(int2fb(cc na))  /* set initial array size */
1253        pi@ = pi@ setarg_C(int2fb(cc nh))  /* set initial table size */
1254    }
1255
1256/* }====================================================================== */
1257
1258
1259
1260    parlist: func {
1261        /* parlist -> [ param { `,' param } ] */
1262        f := fs f
1263        nparams := 0
1264        f is_vararg = false
1265        if (t token != ')') {  /* is `parlist' not empty? */
1266            while (! f is_vararg) {
1267                match (t token) {
1268                    case TK_NAME =>  /* param -> NAME */
1269                        _new_localvar(_str_checkname())
1270                        nparams += 1
1271                    case TK_DOTS =>  /* param -> `...' */
1272                        next()
1273                        f is_vararg = true
1274                    case =>
1275                        syntaxError("<name> or '...' expected")
1276                }
1277                if (! _testnext(',' as Int))
1278                    break
1279            }
1280        }
1281        _adjustlocalvars(nparams)
1282        f numparams = fs nactvar
1283        fs luaK_reserveregs(fs nactvar)  /* reserve register for parameters */
1284    }
1285
1286
1287    body: func(e: ExpDesc@, needself: Bool, line: Int) {
1288        /* body ->  `(' parlist `)' chunk END */
1289        fs = FuncState new(this, fs)
1290        f := fs f
1291        f linedefined = line
1292        _checknext('(' as Int)
1293        if (needself) {
1294            _new_localvarliteral("self")
1295            _adjustlocalvars(1)
1296        }
1297        parlist()
1298        _checknext(')' as Int)
1299        chunk()
1300        f lastlinedefined = linenumber
1301        _check_match(TK_END, TK_FUNCTION, line)
1302        _codeclosure(f, e&)
1303        fs = fs finalize()
1304    }
1305
1306
1307    explist1: func(v: ExpDesc@) -> Int {
1308        /* explist1 -> expr { `,' expr } */
1309        n := 1  /* at least one expression */
1310        expr(v&)
1311        while (_testnext(',' as Int)) {
1312            fs luaK_exp2nextreg(v&)
1313            expr(v&)
1314            n += 1
1315        }
1316        return n
1317    }
1318
1319
1320    funcargs: func(f: ExpDesc@, line: Int) {
1321        args: ExpDesc
1322        match (t token) {
1323            case '(' =>  /* funcargs -> `(' [ explist1 ] `)' */
1324                next()
1325                if (t token == ')')  /* arg list is empty? */
1326                    args k = ExpKind VVOID
1327                else {
1328                    explist1(args&)
1329                    fs luaK_setreturns(args&, LUA_MULTRET)
1330                }
1331                _check_match(')' as Int, '(' as Int, line)
1332            case '{' =>  /* funcargs -> constructor */
1333                constructor(args&)
1334            case TK_STRING =>  /* funcargs -> STRING */
1335                _codestring(args&, t str);
1336                next()  /* must use `seminfo' before `next' */
1337            case =>
1338                syntaxError("function arguments expected")
1339        }
1340        version(debug) {
1341            assert(f k == ExpKind VNONRELOC)
1342        }
1343        nparams: Int
1344        base := f info  /* base register for call */
1345        if (args k hasmultret())
1346            nparams = LUA_MULTRET  /* open call */
1347        else {
1348            if (args k != ExpKind VVOID)
1349                fs luaK_exp2nextreg(args&)  /* close last argument */
1350            nparams = fs freereg - (base+1)
1351        }
1352        init_exp(f&, ExpKind VCALL, fs luaK_codeABC(OpCode OP_CALL, base, nparams+1, 2))
1353        fs luaK_fixline(line)
1354        fs freereg = base+1  /* call remove function and arguments and leaves
1355                                 (unless changed) one result */
1356    }
1357
1358
1359
1360
1361/*
1362** {======================================================================
1363** Expression parsing
1364** =======================================================================
1365*/
1366
1367
1368    prefixexp: func(v: ExpDesc@) {
1369        /* prefixexp -> NAME | '(' expr ')' */
1370        match (t token) {
1371            case '(' =>
1372                line := linenumber
1373                next()
1374                expr(v&)
1375                _check_match(')' as Int, '(' as Int, line)
1376                fs luaK_dischargevars(v&)
1377            case TK_NAME =>
1378                _singlevar(v&)
1379            case =>
1380                syntaxError("unexpected symbol")
1381        }
1382    }
1383
1384
1385    primaryexp: func(v: ExpDesc@) {
1386        /* primaryexp ->
1387            prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
1388        line := linenumber
1389        prefixexp(v&)
1390        while (true) {
1391            match {
1392                case t token == '.' =>  /* fieldsel */
1393                    fieldsel(v&)
1394                case t token == '[' =>  /* `[' exp1 `]' */
1395                    key: ExpDesc
1396                    fs luaK_exp2anyregup(v&)
1397                    yindex(key&)
1398                    fs luaK_indexed(v&, key&)
1399                case t token == ':' =>  /* `:' NAME funcargs */
1400                    key: ExpDesc
1401                    next()
1402                    _checkname(key&)
1403                    fs luaK_self(v&, key&)
1404                    funcargs(v&, line)
1405                case t token == '(' ||
1406                     t token == TK_STRING ||
1407                     t token == '{' =>  /* funcargs */
1408                    fs luaK_exp2nextreg(v&)
1409                    funcargs(v&, line)
1410                case =>
1411                    return
1412            }
1413        }
1414    }
1415
1416
1417    simpleexp: func(v: ExpDesc@) {
1418        /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
1419                        constructor | FUNCTION body | primaryexp */
1420        match (t token) {
1421            case TK_NUMBER =>
1422                init_exp(v&, ExpKind VKNUM, 0)
1423                v nval = t num
1424            case TK_STRING =>
1425                _codestring(v&, t str);
1426            case TK_NIL =>
1427                init_exp(v&, ExpKind VNIL, 0)
1428            case TK_TRUE =>
1429                init_exp(v&, ExpKind VTRUE, 0)
1430            case TK_FALSE =>
1431                init_exp(v&, ExpKind VFALSE, 0)
1432            case TK_DOTS =>  /* vararg */
1433                _check_condition(fs f is_vararg,
1434                                "cannot use '...' outside a vararg function")
1435                init_exp(v&, ExpKind VVARARG, fs luaK_codeABC(OpCode OP_VARARG, 0, 1, 0))
1436            case '{' =>  /* constructor */
1437                constructor(v&)
1438                return
1439            case TK_FUNCTION =>
1440                next()
1441                body(v&, false, linenumber)
1442                return
1443            case =>
1444                primaryexp(v&)
1445                return
1446        }
1447        next()
1448    }
1449
1450
1451    getunopr: func(op: Int) -> UnOpr {
1452        match (op) {
1453            case TK_NOT =>
1454                return UnOpr OPR_NOT
1455            case '-' =>
1456                return UnOpr OPR_MINUS
1457            case '#' =>
1458                return UnOpr OPR_LEN
1459            case =>
1460                return UnOpr OPR_NOUNOPR
1461        }
1462        return UnOpr OPR_NOUNOPR // avoir error
1463    }
1464
1465
1466    getbinopr: func(op: Int) -> BinOpr {
1467        match (op) {
1468            case '+' =>
1469                return BinOpr OPR_ADD
1470            case '-' =>
1471                return BinOpr OPR_SUB
1472            case '*' =>
1473                return BinOpr OPR_MUL
1474            case '/' =>
1475                return BinOpr OPR_DIV
1476            case '%' =>
1477                return BinOpr OPR_MOD
1478            case '^' =>
1479                return BinOpr OPR_POW
1480            case TK_CONCAT =>
1481                return BinOpr OPR_CONCAT
1482            case TK_NE =>
1483                return BinOpr OPR_NE
1484            case TK_EQ =>
1485                return BinOpr OPR_EQ
1486            case '<' =>
1487                return BinOpr OPR_LT
1488            case TK_LE =>
1489                return BinOpr OPR_LE
1490            case '>' =>
1491                return BinOpr OPR_GT
1492            case TK_GE =>
1493                return BinOpr OPR_GE
1494            case TK_AND =>
1495                return BinOpr OPR_AND
1496            case TK_OR =>
1497                return BinOpr OPR_OR
1498            case =>
1499                return BinOpr OPR_NOBINOPR
1500        }
1501        return BinOpr OPR_NOBINOPR // avoid error
1502    }
1503
1504
1505/*
1506** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
1507** where `binop' is any binary operator with a priority higher than `limit'
1508*/
1509    subexpr: func(v: ExpDesc@, limit: Int) -> BinOpr {
1510        _enterlevel()
1511        uop := getunopr(t token)
1512        if (uop != UnOpr OPR_NOUNOPR) {
1513            line := linenumber
1514            next()
1515            subexpr(v&, UNARY_PRIORITY)
1516            fs luaK_prefix(uop, v&, line)
1517        }
1518        else
1519            simpleexp(v&)
1520        /* expand while operators have priorities higher than `limit' */
1521        op := getbinopr(t token)
1522        while (op != BinOpr OPR_NOBINOPR && PRIORITY_LEFT[op] > limit) {
1523            v2: ExpDesc
1524            line := linenumber
1525            next()
1526            fs luaK_infix(op, v&)
1527            /* read sub-expression with higher priority */
1528            nextop := subexpr(v2&, PRIORITY_RIGHT[op])
1529            fs luaK_posfix(op, v&, v2&, line)
1530            op = nextop
1531        }
1532        _leavelevel()
1533        return op;  /* return first untreated operator */
1534    }
1535
1536
1537    expr: func(v: ExpDesc@) {
1538        subexpr(v&, 0)
1539    }
1540
1541/* }==================================================================== */
1542
1543
1544
1545/*
1546** {======================================================================
1547** Rules for Statements
1548** =======================================================================
1549*/
1550
1551    block_follow: func(token: Int) -> Bool {
1552        return (token == TK_ELSE ||
1553                token == TK_ELSEIF ||
1554                token == TK_END ||
1555                token == TK_UNTIL ||
1556                token == TK_EOS)
1557    }
1558
1559
1560    block: func {
1561        /* block -> chunk */
1562        bl: BlockCnt
1563        fs enterblock(bl&, false)
1564        chunk()
1565        version(debug) {
1566            assert(bl breaklist == NO_JUMP)
1567        }
1568        fs leaveblock()
1569    }
1570
1571
1572/*
1573** check whether, in an assignment to a local variable, the local variable
1574** is needed in a previous assignment (to a table). If so, save original
1575** local value in a safe place and use this safe copy in the previous
1576** assignment.
1577*/
1578    _check_conflict: func(lh: LHS_assign*, v: ExpDesc@) {
1579        extra := fs freereg  /* eventual position to save local variable */
1580        conflict := false
1581        while (lh) {
1582            /* conflict in table 't'? */
1583            if (lh@ v ind_vt == v k && lh@ v ind_t == v info) {
1584                conflict = true
1585                lh@ v ind_vt = ExpKind VLOCAL
1586                lh@ v ind_t = extra  /* previous assignment will use safe copy */
1587            }
1588            /* conflict in index 'idx'? */
1589            if (v k == ExpKind VLOCAL && lh@ v ind_idx == v info) {
1590                conflict = true
1591                lh@ v ind_idx = extra  /* previous assignment will use safe copy */
1592            }
1593            lh = lh@ prev
1594        }
1595        if (conflict) {
1596            op := (v k == ExpKind VLOCAL) ? OpCode OP_MOVE : OpCode OP_GETUPVAL
1597            fs luaK_codeABC(op, fs freereg, v info, 0)  /* make copy */
1598            fs luaK_reserveregs(1)
1599        }
1600    }
1601
1602
1603    assignment: func(lh: LHS_assign@, nvars: Int) {
1604        e: ExpDesc
1605        _check_condition(lh v k vkisvar(), "syntax error")
1606        if (_testnext(',' as Int)) {  /* assignment -> `,' primaryexp assignment */
1607            nv: LHS_assign
1608            nv prev = lh&
1609            primaryexp(nv v&)
1610            if (nv v k != ExpKind VINDEXED)
1611                _check_conflict(lh&, nv v&)
1612            assignment(nv&, nvars+1)
1613        }
1614        else {  /* assignment -> `=' explist1 */
1615            _checknext('=' as Int)
1616            nexps := explist1(e&)
1617            if (nexps != nvars) {
1618                _adjust_assign(nvars, nexps, e&)
1619                if (nexps > nvars)
1620                    fs freereg -= nexps - nvars  /* remove extra values */
1621            }
1622            else {
1623                fs luaK_setoneret(e&)  /* close last expression */
1624                fs luaK_storevar(lh v&, e&)
1625                return  /* avoid default */
1626            }
1627        }
1628        init_exp(e&, ExpKind VNONRELOC, fs freereg - 1)  /* default assignment */
1629        fs luaK_storevar(lh v&, e&)
1630    }
1631
1632
1633    cond: func -> Int {
1634        /* cond -> exp */
1635        v: ExpDesc
1636        expr(v&)  /* read condition */
1637        if (v k == ExpKind VNIL)
1638            v k = ExpKind VFALSE  /* `falses' are all equal here */
1639        fs luaK_goiftrue(v&)
1640        return v f
1641    }
1642
1643
1644    breakstat: func {
1645        bl := fs bl
1646        upval := false
1647        while (bl) {
1648            if (bl@ i…

Large files files are truncated, but you can click here to view the full file