Commits

Laurens Rodriguez committed 531697c

Updating Killa to latest 0.2 branch
- Added bitiwise operators and fixed issues with compound operators
- Updated tests and sample game
- Win32 binaries updated

Comments (0)

Files changed (23)

bin/windows/game/game.kia

     }
 }
 
-// Bit flags utility helpers.
-function isFlagSet(set, flag) {
-    return (set % (2*flag) >= flag)
-}
-
-function setFlag(set, flag) {
-    if (set % (2*flag) >= flag) {
-        return set
-    }
-    return (set + flag)
-}
-
-function clearFlag(set, flag) {
-    if (set % (2*flag) >= flag) {
-        return (set - flag)
-    }
-    return set
-}
-
 // Initialize tetromino cells for every type of tetromino.
 function Game::setTetromino(indexTetromino, tetromino) {
     // Initialize tetromino cells to empty cells.
 
     // Move the falling piece if there was wall collision and it's a legal move.
     if (wallDisplace != 0) {
-        this.m_fallingBlock.x = this.m_fallingBlock.x + wallDisplace
+        this.m_fallingBlock.x += wallDisplace
     }
 
     // There are no collisions, replace tetromino cells with rotated cells.
 // Game scoring: http://tetris.wikia.com/wiki/Scoring
 function Game::onFilledRows(filledRows) {
     // Update total number of filled rows.
-    this.m_stats.lines = this.m_stats.lines + filledRows
+    this.m_stats.lines += filledRows
 
     // Increase score accordingly to the number of filled rows.
     if (filledRows == 1) {
-        this.m_stats.score = this.m_stats.score + SCORE_1_FILLED_ROW * (this.m_stats.level + 1)
+        this.m_stats.score += SCORE_1_FILLED_ROW * (this.m_stats.level + 1)
     }
     else if (filledRows == 2) {
-        this.m_stats.score = this.m_stats.score + SCORE_2_FILLED_ROW * (this.m_stats.level + 1)
+        this.m_stats.score += SCORE_2_FILLED_ROW * (this.m_stats.level + 1)
     }
     else if (filledRows == 3) {
-        this.m_stats.score = this.m_stats.score + SCORE_3_FILLED_ROW * (this.m_stats.level + 1)
+        this.m_stats.score += SCORE_3_FILLED_ROW * (this.m_stats.level + 1)
     }
     else if (filledRows == 4) {
-        this.m_stats.score = this.m_stats.score + SCORE_4_FILLED_ROW * (this.m_stats.level + 1)
+        this.m_stats.score += SCORE_4_FILLED_ROW * (this.m_stats.level + 1)
     }
     else {
         // This shouldn't happen, but if happens kill the game.
 
     // Check if we need to update the level.
     if (this.m_stats.lines >= FILLED_ROWS_FOR_LEVEL_UP * (this.m_stats.level + 1)) {
-        this.m_stats.level = this.m_stats.level + 1
+        this.m_stats.level += 1
 
         // Increase speed for falling tetrominoes.
         this.m_fallingDelay = math.floor(DELAY_FACTOR_FOR_LEVEL_UP * this.m_fallingDelay
     }
     else {
         // There are no collisions, just move the tetromino.
-        this.m_fallingBlock.x = this.m_fallingBlock.x + x
-        this.m_fallingBlock.y = this.m_fallingBlock.y + y
+        this.m_fallingBlock.x += x
+        this.m_fallingBlock.y += y
     }
     this::onTetrominoMoved()
 }
 // Hard drop.
 function Game::dropTetromino() {
     // Shadow has already calculated the landing position.
-    this.m_fallingBlock.y = this.m_fallingBlock.y + this.m_shadowGap
+    this.m_fallingBlock.y += this.m_shadowGap
 
     // Force lock.
     this::moveTetromino(0, 1)
 
     // Update score.
     if (this.m_showShadow) {
-        this.m_stats.score = this.m_stats.score + (SCORE_2_FILLED_ROW * (this.m_stats.level + 1)
+        this.m_stats.score += (SCORE_2_FILLED_ROW * (this.m_stats.level + 1)
                                 / SCORE_DROP_WITH_SHADOW_DIVISOR)
     }
     else {
-        this.m_stats.score = this.m_stats.score + (SCORE_2_FILLED_ROW * (this.m_stats.level + 1)
+        this.m_stats.score += (SCORE_2_FILLED_ROW * (this.m_stats.level + 1)
                                 / SCORE_DROP_DIVISOR)
     }
 }
 function Game::update() {
     // Update game state.
     if (this.m_isOver) {
-        if (isFlagSet(this.m_events, this.Event.RESTART)) {
+        if (this.m_events & this.Event.RESTART != 0) {
             this.m_isOver = false
             this::start()
         }
         var timeDelta = currentTime - this.m_systemTime
 
         if (this.m_delayDown > 0) {
-            this.m_delayDown = this.m_delayDown - timeDelta
+            this.m_delayDown -= timeDelta
             if (this.m_delayDown <= 0) {
                 this.m_delayDown = DAS_MOVE_TIMER
-                this.m_events = setFlag(this.m_events, this.Event.MOVE_DOWN)
+                this.m_events = this.m_events | this.Event.MOVE_DOWN
             }
         }
 
         if (this.m_delayLeft > 0) {
-            this.m_delayLeft = this.m_delayLeft - timeDelta
+            this.m_delayLeft -= timeDelta
             if (this.m_delayLeft <= 0) {
                 this.m_delayLeft = DAS_MOVE_TIMER
-                this.m_events = setFlag(this.m_events, this.Event.MOVE_LEFT)
+                this.m_events = this.m_events | this.Event.MOVE_LEFT
             }
         }
         else if (this.m_delayRight > 0) {
-            this.m_delayRight = this.m_delayRight - timeDelta
+            this.m_delayRight -= timeDelta
             if (this.m_delayRight <= 0) {
                 this.m_delayRight = DAS_MOVE_TIMER
-                this.m_events = setFlag(this.m_events, this.Event.MOVE_RIGHT)
+                this.m_events = this.m_events | this.Event.MOVE_RIGHT
             }
         }
 
         if (this.m_delayRotation > 0) {
-            this.m_delayRotation = this.m_delayRotation - timeDelta
+            this.m_delayRotation -= timeDelta
             if (this.m_delayRotation <= 0) {
                 this.m_delayRotation = ROTATION_AUTOREPEAT_TIMER
-                this.m_events = setFlag(this.m_events, this.Event.ROTATE_CW)
+                this.m_events = this.m_events | this.Event.ROTATE_CW
             }
         }
 
         // Always handle pause event.
-        if (isFlagSet(this.m_events, this.Event.PAUSE)) {
+        if (this.m_events & this.Event.PAUSE != 0) {
             this.m_isPaused = ! this.m_isPaused
             this.m_events = this.Event.NONE
         }
         if (this.m_isPaused) {
             // We achieve the effect of pausing the game
             // adding the last frame duration to lastFallTime.
-            this.m_lastFallTime = this.m_lastFallTime + (currentTime - this.m_systemTime)
+            this.m_lastFallTime += currentTime - this.m_systemTime
         }
         else {
             if (this.m_events != this.Event.NONE) {
-                if (isFlagSet(this.m_events, this.Event.SHOW_NEXT)) {
+                if (this.m_events & this.Event.SHOW_NEXT != 0) {
                     this.m_showPreview = ! this.m_showPreview
                     this.m_stateChanged = true
                 }
-                if (isFlagSet(this.m_events, this.Event.SHOW_SHADOW)) {
+                if (this.m_events & this.Event.SHOW_SHADOW != 0) {
                     this.m_showShadow = ! this.m_showShadow
                     this.m_stateChanged = true
                 }
-                if (isFlagSet(this.m_events, this.Event.DROP)) {
+                if (this.m_events & this.Event.DROP != 0) {
                     this::dropTetromino()
                 }
-                if (isFlagSet(this.m_events, this.Event.ROTATE_CW)) {
+                if (this.m_events & this.Event.ROTATE_CW != 0) {
                     this::rotateTetromino(true)
                 }
 
-                if (isFlagSet(this.m_events, this.Event.MOVE_RIGHT)) {
+                if (this.m_events & this.Event.MOVE_RIGHT != 0) {
                     this::moveTetromino(1, 0)
                 }
-                else if (isFlagSet(this.m_events, this.Event.MOVE_LEFT)) {
+                else if (this.m_events & this.Event.MOVE_LEFT != 0) {
                     this::moveTetromino(-1, 0)
                 }
 
-                if (isFlagSet(this.m_events, this.Event.MOVE_DOWN)) {
+                if (this.m_events & this.Event.MOVE_DOWN != 0) {
                     // Update score if the player accelerates downfall.
-                    this.m_stats.score = this.m_stats.score 
-                                         + (SCORE_2_FILLED_ROW * (this.m_stats.level + 1)
-                                                               / SCORE_MOVE_DOWN_DIVISOR)
+                    this.m_stats.score += (SCORE_2_FILLED_ROW * (this.m_stats.level + 1)
+                                            / SCORE_MOVE_DOWN_DIVISOR)
 
                     this::moveTetromino(0, 1)
                 }
         this.m_errorCode = this.Error.PLAYER_QUITS
     }
     else if (command == this.Event.MOVE_DOWN) {
-        this.m_events = setFlag(this.m_events, this.Event.MOVE_DOWN)
+        this.m_events = this.m_events | this.Event.MOVE_DOWN
         this.m_delayDown = DAS_DELAY_TIMER
     }
     else if (command == this.Event.ROTATE_CW) {
-        this.m_events = setFlag(this.m_events, this.Event.ROTATE_CW)
+        this.m_events = this.m_events | this.Event.ROTATE_CW
         this.m_delayRotation = ROTATION_AUTOREPEAT_DELAY
     }
     else if (command == this.Event.MOVE_LEFT) {
-        this.m_events = setFlag(this.m_events, this.Event.MOVE_LEFT)
+        this.m_events = this.m_events | this.Event.MOVE_LEFT
         this.m_delayLeft = DAS_DELAY_TIMER
     }
     else if (command == this.Event.MOVE_RIGHT) {
-        this.m_events = setFlag(this.m_events, this.Event.MOVE_RIGHT)
+        this.m_events = this.m_events | this.Event.MOVE_RIGHT
         this.m_delayRight = DAS_DELAY_TIMER
     }
     else if ((command == this.Event.DROP)
             || (command == this.Event.PAUSE)
             || (command == this.Event.SHOW_NEXT)
             || (command == this.Event.SHOW_SHADOW)) {
-        this.m_events = setFlag(this.m_events, command)
+        this.m_events = this.m_events | command
     }
 }
 

bin/windows/killa.exe

Binary file modified.

bin/windows/love-killa.exe

Binary file modified.
+
+//------------------------------------------------------------------------------
+var A = {t: {f: 7}, n: 3}
+function A::mutate(yy) {
+    this.t.f *= yy
+    this.n += yy
+}
+A::mutate(10)
+assert(A.t.f == 70 && A.n == 13)
+
+var B = [1,[2,3],4,5]
+B[1][1] *= 3
+assert(B[1][1] == 9);
+var ind = 0
+B[ind + 1][1] *= 3
+assert(B[ind + 1][1] == 27);
 
 //------------------------------------------------------------------------------
 var x, y = "private x", "private y"
 }
 
 //------------------------------------------------------------------------------
-var A = {tt: {x: 20}}
-function A::ax(yy) {
-    // NOTE TOFIX 
-    ////this.tt.x += yy
-}
-A::ax(10)
-print(A.tt.x)
-
-//------------------------------------------------------------------------------
 function fibonacci(n) {
     if (n <= 1) {
         return 1
 print(x) // Output: even
 
 //------------------------------------------------------------------------------
-var s1 = 'testing '
+var s1 = "testing "
 s1 ..= "concatenation"
-print(s1) // prints: "testing concatenation"
+assert(s1 == "testing concatenation")
 
 //------------------------------------------------------------------------------
 // NOTE mixed table construction is disallowed:
         a , b = b , a
         k += 1
     } while (math.abs(a - b) >= precision)
-    print(k)
     return a
 }
 

platform/msvc2008/killa/killa.vcproj

 			>
 		</File>
 		<File
+			RelativePath="..\..\..\src\libraries\killa\kubit.c"
+			>
+		</File>
+		<File
+			RelativePath="..\..\..\src\libraries\killa\kubit.h"
+			>
+		</File>
+		<File
 			RelativePath="..\..\..\src\libraries\killa\kundump.c"
 			>
 		</File>

platform/msvc2008/love-killa.vcproj

 				</FileConfiguration>
 			</File>
 			<File
+				RelativePath="..\..\src\libraries\killa\kubit.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\libraries\killa\kubit.h"
+				>
+			</File>
+			<File
 				RelativePath="..\..\src\libraries\killa\kundump.c"
 				>
 			</File>

src/libraries/killa/kcode.c

 }
 
 
-void killaK_exp2reg (killa_FuncState *fs, killa_expdesc *e, int reg) {
-  killaK_dischargevars(fs, e);
-  freeexp(fs, e);
-  exp2reg(fs, e, reg);
+void killaK_exp2reg (killa_FuncState *fs, killa_expdesc *e, int reg) {
+  killaK_dischargevars(fs, e);
+  freeexp(fs, e);
+  exp2reg(fs, e, reg);
 }
 
 
   if (constfolding(op, e1, e2))
     return;
   else {
-    int o2 = (op != OP_UNM && op != OP_LEN) ? killaK_exp2RK(fs, e2) : 0;
+    int o2 = (op != OP_UNM && op != OP_LEN && op != OP_BNOT) ? killaK_exp2RK(fs, e2) : 0;
     int o1 = killaK_exp2RK(fs, e1);
     if (o1 > o2) {
       freeexp(fs, e1);
 }
 
 
-static void codecomp (killa_FuncState *fs, killa_OpCode op, int cond, killa_expdesc *e1,
-                                                          killa_expdesc *e2) {
+static void codecomp (killa_FuncState *fs, killa_OpCode op, int cond,
+                      killa_expdesc *e1, killa_expdesc *e2) {
   int o1 = killaK_exp2RK(fs, e1);
   int o2 = killaK_exp2RK(fs, e2);
   freeexp(fs, e2);
 }
 
 
+static void codecompound (killa_FuncState *fs, killa_OpCode op, 
+                          killa_expdesc *e1, killa_expdesc *e2) {
+  int o1;
+  int o2;
+
+  /* load expresion 2 into a register. */
+  o2 = killaK_exp2RK(fs, e2);
+
+  switch (e1->k) {
+    case VLOCAL: {
+      /* compound opcode */
+      killaK_codeABC(fs, op, e1->u.info, o2, 0);
+      return;
+    }
+    case VUPVAL: {
+      /* allocate temp. register */
+      o1 = fs->freereg;
+      killaK_reserveregs(fs, 1);
+      /* load upval into temp. register */
+      killaK_codeABC(fs, OP_GETUPVAL, o1, e1->u.info, 0);
+      /* compound opcode */
+      killaK_codeABC(fs, op, o1, o2, 0);
+      /* store results back to upval */
+      killaK_codeABC(fs, OP_SETUPVAL, o1, e1->u.info, 0);
+      /* free temp. register */
+      freereg(fs, o1);
+      break;
+    }
+    case VINDEXED: {
+      /* allocate temp. register */
+      o1 = fs->freereg;
+      killaK_reserveregs(fs, 1);
+      /* load indexed value into temp. register */
+      killaK_codeABC(fs, OP_GETTABLE, o1, e1->u.ind.t, e1->u.ind.idx);
+      /* compound opcode */
+      killaK_codeABC(fs, op, o1, o2, 0);
+      /* store results back to indexed value */
+      killaK_codeABC(fs, OP_SETTABLE, e1->u.ind.t, e1->u.ind.idx, o1);
+      /* free temp. register */
+      freereg(fs, o1);
+      freereg(fs, e1->u.ind.idx);
+      freereg(fs, e1->u.ind.t);
+      break;
+    }
+    default: {
+      killa_assert(0); /* invalid var kind to store */
+      break;
+    }
+  }
+  /* free register for expression 2 */
+  freeexp(fs, e2);
+}
+
+
 void killaK_prefix (killa_FuncState *fs, killaK_UnOpr op, killa_expdesc *e, int line) {
   killa_expdesc e2;
   e2.t = e2.f = KILLA_NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
       codearith(fs, OP_LEN, e, &e2, line);
       break;
     }
+    case OPR_BNOT: {
+      if (e->k == VK)
+        killaK_exp2anyreg(fs, e);  /* cannot operate on non-numeric constants */
+      codearith(fs, OP_BNOT, e, &e2, line);
+      break;
+    }
     default: killa_assert(0);
   }
 }
       break;
     }
     case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
+    case OPR_BAND: case OPR_BOR: case OPR_BXOR: 
+    case OPR_BLSH: case OPR_BRSH: 
     case OPR_MOD: case OPR_POW: {
       if (!isnumeral(v)) killaK_exp2RK(fs, v);
       break;
       codecomp(fs, killa_cast(killa_OpCode, op - OPR_NE + OP_EQ), 0, e1, e2);
       break;
     }
+    case OPR_BAND: case OPR_BOR: case OPR_BXOR: 
+    case OPR_BLSH: case OPR_BRSH: {
+      codearith(fs, killa_cast(killa_OpCode, op - OPR_BAND + OP_BAND), e1, e2, line);
+      break;
+    }
+    case OPR_CADD: case OPR_CSUB: case OPR_CMUL:
+    case OPR_CDIV: case OPR_CMOD: {
+      codecompound(fs, killa_cast(killa_OpCode, op - OPR_CADD + OP_CADD), e1, e2);
+      break;
+    }
     default: killa_assert(0);
   }
 }

src/libraries/killa/kcode.h

-/* ========================================================================== */
-/*   Code generator for Killa                                                 */
-/* -------------------------------------------------------------------------- */
-/*   Copyright (c) 2012 Laurens Rodriguez Oscanoa.                            */
-/*   Copyright (C) 1994-2012 Lua.org, PUC-Rio.                                */
-/*                                                                            */
-/*   This code is licensed under the MIT license:                             */
-/*   http://www.opensource.org/licenses/mit-license.php                       */
-/* -------------------------------------------------------------------------- */
-
-#ifndef KCODE_H_
-#define KCODE_H_
-
-#include "klex.h"
-#include "kobject.h"
-#include "kopcodes.h"
-#include "kparser.h"
-
-
-/*
-** Marks the end of a patch list. It is an invalid value both as an absolute
-** address, and as a list link (would link an element to itself).
-*/
-#define KILLA_NO_JUMP (-1)
-
-
-/*
-** grep "ORDER OPR" if you change these enums  (ORDER OP)
-*/
-typedef enum killaK_BinOpr {
-  OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,
-  OPR_CONCAT,
-  OPR_EQ, OPR_LT, OPR_LE,
-  OPR_NE, OPR_GT, OPR_GE,
-  OPR_AND, OPR_OR,
-  OPR_NOBINOPR
-} killaK_BinOpr;
-
-
-typedef enum killaK_UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } killaK_UnOpr;
-
-
-#define killaK_getcode(fs,e)	((fs)->f->code[(e)->u.info])
-
-#define killaK_codeAsBx(fs,o,A,sBx)	killaK_codeABx(fs,o,A,(sBx)+KILLA_MAXARG_sBx)
-
-#define killaK_setmultret(fs,e)	killaK_setreturns(fs, e, KILLA_MULTRET)
-
-#define killaK_jumpto(fs,t)	killaK_patchlist(fs, killaK_jump(fs), t)
-
-KILLAI_FUNC int  killaK_codeABx (killa_FuncState *fs, killa_OpCode o, int A, unsigned int Bx);
-KILLAI_FUNC int  killaK_codeABC (killa_FuncState *fs, killa_OpCode o, int A, int B, int C);
-KILLAI_FUNC int  killaK_codek (killa_FuncState *fs, int reg, int k);
-KILLAI_FUNC void killaK_fixline (killa_FuncState *fs, int line);
-KILLAI_FUNC void killaK_nil (killa_FuncState *fs, int from, int n);
-KILLAI_FUNC void killaK_reserveregs (killa_FuncState *fs, int n);
-KILLAI_FUNC void killaK_checkstack (killa_FuncState *fs, int n);
-KILLAI_FUNC int  killaK_stringK (killa_FuncState *fs, killa_TString *s);
-KILLAI_FUNC int  killaK_numberK (killa_FuncState *fs, killa_Number r);
-KILLAI_FUNC void killaK_dischargevars (killa_FuncState *fs, killa_expdesc *e);
-KILLAI_FUNC int  killaK_exp2anyreg (killa_FuncState *fs, killa_expdesc *e);
-KILLAI_FUNC void killaK_exp2reg (killa_FuncState *fs, killa_expdesc *e, int reg);
-KILLAI_FUNC void killaK_exp2anyregup (killa_FuncState *fs, killa_expdesc *e);
-KILLAI_FUNC void killaK_exp2nextreg (killa_FuncState *fs, killa_expdesc *e);
-KILLAI_FUNC void killaK_exp2val (killa_FuncState *fs, killa_expdesc *e);
-KILLAI_FUNC int  killaK_exp2RK (killa_FuncState *fs, killa_expdesc *e);
-KILLAI_FUNC void killaK_self (killa_FuncState *fs, killa_expdesc *e, killa_expdesc *key);
-KILLAI_FUNC void killaK_indexed (killa_FuncState *fs, killa_expdesc *t, killa_expdesc *k);
-KILLAI_FUNC void killaK_goiftrue (killa_FuncState *fs, killa_expdesc *e);
-KILLAI_FUNC void killaK_goiffalse (killa_FuncState *fs, killa_expdesc *e);
-KILLAI_FUNC void killaK_storevar (killa_FuncState *fs, killa_expdesc *var, killa_expdesc *e);
-KILLAI_FUNC void killaK_setreturns (killa_FuncState *fs, killa_expdesc *e, int nresults);
-KILLAI_FUNC void killaK_setoneret (killa_FuncState *fs, killa_expdesc *e);
-KILLAI_FUNC int  killaK_jump (killa_FuncState *fs);
-KILLAI_FUNC void killaK_ret (killa_FuncState *fs, int first, int nret);
-KILLAI_FUNC void killaK_patchlist (killa_FuncState *fs, int list, int target);
-KILLAI_FUNC void killaK_patchtohere (killa_FuncState *fs, int list);
-KILLAI_FUNC void killaK_patchclose (killa_FuncState *fs, int list, int level);
-KILLAI_FUNC void killaK_concat (killa_FuncState *fs, int *l1, int l2);
-KILLAI_FUNC int  killaK_getlabel (killa_FuncState *fs);
-KILLAI_FUNC void killaK_prefix (killa_FuncState *fs, killaK_UnOpr op, killa_expdesc *v, int line);
-KILLAI_FUNC void killaK_infix (killa_FuncState *fs, killaK_BinOpr op, killa_expdesc *v);
-KILLAI_FUNC void killaK_posfix (killa_FuncState *fs, killaK_BinOpr op, killa_expdesc *v1,
-                                killa_expdesc *v2, int line);
-KILLAI_FUNC void killaK_setlist (killa_FuncState *fs, int base, int nelems, int tostore);
-
-
-#endif
+/* ========================================================================== */
+/*   Code generator for Killa                                                 */
+/* -------------------------------------------------------------------------- */
+/*   Copyright (c) 2012 Laurens Rodriguez Oscanoa.                            */
+/*   Copyright (C) 1994-2012 Lua.org, PUC-Rio.                                */
+/*                                                                            */
+/*   This code is licensed under the MIT license:                             */
+/*   http://www.opensource.org/licenses/mit-license.php                       */
+/* -------------------------------------------------------------------------- */
+
+#ifndef KCODE_H_
+#define KCODE_H_
+
+#include "klex.h"
+#include "kobject.h"
+#include "kopcodes.h"
+#include "kparser.h"
+
+
+/*
+** Marks the end of a patch list. It is an invalid value both as an absolute
+** address, and as a list link (would link an element to itself).
+*/
+#define KILLA_NO_JUMP (-1)
+
+
+/*
+** grep "ORDER OPR" if you change these enums  (ORDER OP)
+*/
+typedef enum killaK_BinOpr {
+  OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,
+  OPR_BAND, OPR_BOR, OPR_BXOR, OPR_BLSH, OPR_BRSH, 
+  OPR_CONCAT,
+  OPR_EQ, OPR_LT, OPR_LE,
+  OPR_NE, OPR_GT, OPR_GE,
+  OPR_AND, OPR_OR,
+  OPR_CADD, OPR_CSUB, OPR_CMUL, OPR_CDIV, OPR_CMOD, OPR_CCONCAT,
+  OPR_NOBINOPR
+} killaK_BinOpr;
+
+
+typedef enum killaK_UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_BNOT, OPR_NOUNOPR } killaK_UnOpr;
+
+
+#define killaK_getcode(fs,e)	((fs)->f->code[(e)->u.info])
+
+#define killaK_codeAsBx(fs,o,A,sBx)	killaK_codeABx(fs,o,A,(sBx)+KILLA_MAXARG_sBx)
+
+#define killaK_setmultret(fs,e)	killaK_setreturns(fs, e, KILLA_MULTRET)
+
+#define killaK_jumpto(fs,t)	killaK_patchlist(fs, killaK_jump(fs), t)
+
+KILLAI_FUNC int  killaK_codeABx (killa_FuncState *fs, killa_OpCode o, int A, unsigned int Bx);
+KILLAI_FUNC int  killaK_codeABC (killa_FuncState *fs, killa_OpCode o, int A, int B, int C);
+KILLAI_FUNC int  killaK_codek (killa_FuncState *fs, int reg, int k);
+KILLAI_FUNC void killaK_fixline (killa_FuncState *fs, int line);
+KILLAI_FUNC void killaK_nil (killa_FuncState *fs, int from, int n);
+KILLAI_FUNC void killaK_reserveregs (killa_FuncState *fs, int n);
+KILLAI_FUNC void killaK_checkstack (killa_FuncState *fs, int n);
+KILLAI_FUNC int  killaK_stringK (killa_FuncState *fs, killa_TString *s);
+KILLAI_FUNC int  killaK_numberK (killa_FuncState *fs, killa_Number r);
+KILLAI_FUNC void killaK_dischargevars (killa_FuncState *fs, killa_expdesc *e);
+KILLAI_FUNC int  killaK_exp2anyreg (killa_FuncState *fs, killa_expdesc *e);
+KILLAI_FUNC void killaK_exp2reg (killa_FuncState *fs, killa_expdesc *e, int reg);
+KILLAI_FUNC void killaK_exp2anyregup (killa_FuncState *fs, killa_expdesc *e);
+KILLAI_FUNC void killaK_exp2nextreg (killa_FuncState *fs, killa_expdesc *e);
+KILLAI_FUNC void killaK_exp2val (killa_FuncState *fs, killa_expdesc *e);
+KILLAI_FUNC int  killaK_exp2RK (killa_FuncState *fs, killa_expdesc *e);
+KILLAI_FUNC void killaK_self (killa_FuncState *fs, killa_expdesc *e, killa_expdesc *key);
+KILLAI_FUNC void killaK_indexed (killa_FuncState *fs, killa_expdesc *t, killa_expdesc *k);
+KILLAI_FUNC void killaK_goiftrue (killa_FuncState *fs, killa_expdesc *e);
+KILLAI_FUNC void killaK_goiffalse (killa_FuncState *fs, killa_expdesc *e);
+KILLAI_FUNC void killaK_storevar (killa_FuncState *fs, killa_expdesc *var, killa_expdesc *e);
+KILLAI_FUNC void killaK_setreturns (killa_FuncState *fs, killa_expdesc *e, int nresults);
+KILLAI_FUNC void killaK_setoneret (killa_FuncState *fs, killa_expdesc *e);
+KILLAI_FUNC int  killaK_jump (killa_FuncState *fs);
+KILLAI_FUNC void killaK_ret (killa_FuncState *fs, int first, int nret);
+KILLAI_FUNC void killaK_patchlist (killa_FuncState *fs, int list, int target);
+KILLAI_FUNC void killaK_patchtohere (killa_FuncState *fs, int list);
+KILLAI_FUNC void killaK_patchclose (killa_FuncState *fs, int list, int level);
+KILLAI_FUNC void killaK_concat (killa_FuncState *fs, int *l1, int l2);
+KILLAI_FUNC int  killaK_getlabel (killa_FuncState *fs);
+KILLAI_FUNC void killaK_prefix (killa_FuncState *fs, killaK_UnOpr op, killa_expdesc *v, int line);
+KILLAI_FUNC void killaK_infix (killa_FuncState *fs, killaK_BinOpr op, killa_expdesc *v);
+KILLAI_FUNC void killaK_posfix (killa_FuncState *fs, killaK_BinOpr op, killa_expdesc *v1,
+                                killa_expdesc *v2, int line);
+KILLAI_FUNC void killaK_setlist (killa_FuncState *fs, int base, int nelems, int tostore);
+
+
+#endif

src/libraries/killa/kdebug.c

     case OP_LT: tm = TM_LT; break;
     case OP_LE: tm = TM_LE; break;
     case OP_CONCAT: tm = TM_CONCAT; break;
+    case OP_BAND: tm = TM_BAND; break;
+    case OP_BOR:  tm = TM_BOR; break;
+    case OP_BXOR: tm = TM_BXOR; break;
+    case OP_BLSH: tm = TM_BLSH; break;
+    case OP_BRSH: tm = TM_BRSH; break;
+    case OP_BNOT: tm = TM_BNOT; break;
     default:
       return NULL;  /* else no useful name can be found */
   }

src/libraries/killa/killa.h

 /*                                                                            */
 /*   This project is licensed under the MIT license:                          */
 /*                                                                            */
-/*   Permission is hereby granted, free of charge, to any person              */
-/*   obtaining a copy of this software and associated documentation           */
-/*   files (the "Software"), to deal in the Software without                  */
-/*   restriction, including without limitation the rights to use,             */
-/*   copy, modify, merge, publish, distribute, sublicense, and/or sell        */
-/*   copies of the Software, and to permit persons to whom the                */
-/*   Software is furnished to do so, subject to the following                 */
-/*   conditions:                                                              */
-/*                                                                            */
-/*   The above copyright notice and this permission notice shall be           */
-/*   included in all copies or substantial portions of the Software.          */
-/*                                                                            */
-/*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,          */
-/*   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES          */
-/*   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                 */
-/*   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT              */
-/*   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,             */
-/*   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING             */
-/*   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR            */
-/*   OTHER DEALINGS IN THE SOFTWARE.                                          */
-/* -------------------------------------------------------------------------- */
+/*   Permission is hereby granted, free of charge, to any person              */
+/*   obtaining a copy of this software and associated documentation           */
+/*   files (the "Software"), to deal in the Software without                  */
+/*   restriction, including without limitation the rights to use,             */
+/*   copy, modify, merge, publish, distribute, sublicense, and/or sell        */
+/*   copies of the Software, and to permit persons to whom the                */
+/*   Software is furnished to do so, subject to the following                 */
+/*   conditions:                                                              */
+/*                                                                            */
+/*   The above copyright notice and this permission notice shall be           */
+/*   included in all copies or substantial portions of the Software.          */
+/*                                                                            */
+/*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,          */
+/*   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES          */
+/*   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                 */
+/*   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT              */
+/*   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,             */
+/*   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING             */
+/*   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR            */
+/*   OTHER DEALINGS IN THE SOFTWARE.                                          */
+/* -------------------------------------------------------------------------- */
 
 #ifndef KILLA_H_
 #define KILLA_H_
 
 
 #define KILLA_VERSION_MAJOR     "0"
-#define KILLA_VERSION_MINOR     "1"
+#define KILLA_VERSION_MINOR     "2"
 #define KILLA_VERSION_NUM		10
 #define KILLA_VERSION_RELEASE	"0"
 
+#ifdef KILLA_EXTENDED
+#define KILLA_VERSION	"KillaExt " KILLA_VERSION_MAJOR "." KILLA_VERSION_MINOR
+#else
 #define KILLA_VERSION	"Killa " KILLA_VERSION_MAJOR "." KILLA_VERSION_MINOR
+#endif
 #define KILLA_RELEASE	KILLA_VERSION "." KILLA_VERSION_RELEASE
 #define KILLA_COPYRIGHT	KILLA_RELEASE "  Copyright (C) 2012 Laurens Rodriguez"
 #define KILLA_AUTHORS	"L. Rodriguez, R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
 #define KILLA_OPDIV     3
 #define KILLA_OPMOD     4
 #define KILLA_OPPOW     5
-#define KILLA_OPUNM     6
+#define KILLA_OPBAND	6
+#define KILLA_OPBOR	    7
+#define KILLA_OPBXOR	8
+#define KILLA_OPBLSH	9
+#define KILLA_OPBRSH	10
+#define KILLA_OPBNOT	11
+#define KILLA_OPUNM	    12
+
 
 KILLA_API void  (killa_arith) (killa_State *L, int op);
 

src/libraries/killa/kinit.c

 #include "killalib.h"
 #include "kauxlib.h"
 
-#ifdef KILLA_EXT_BC
+#ifdef KILLA_EXTENDED_BC
 #include "lbc.h"
 #endif
 

src/libraries/killa/klex.c

     "interface", "new", "override", "protected", "static",
     "super", "switch", "throw", "try", "undefined",
     /* other terminal symbols */
-    "!", "&&", "||", "**", "::", 
+    "&&", "||", "**", "::", 
     "..", "...", "==", ">=", "<=", "!=",
     "+=", "-=", "*=", "/=", "%=", "..=",
+    "<<", ">>",
     "<eof>", "<number>", "<name>", "<string>"
 };
 
       }
       case '<': {
         next(ls);
-        if (ls->current != '=') return '<';
-        else { next(ls); return TK_LE; }
+        switch (ls->current) {
+          case '=': next(ls); return TK_LE; break;
+          case '<': next(ls); return TK_BLSH; break;
+          default: return '<'; }
       }
       case '>': {
         next(ls);
-        if (ls->current != '=') return '>';
-        else { next(ls); return TK_GE; }
+        switch (ls->current) {
+          case '=': next(ls); return TK_GE; break;
+          case '>': next(ls); return TK_BRSH; break;
+          default: return '>'; }
       }
       case '!': {
         next(ls);
-        if (ls->current != '=') return TK_NOT;
+        if (ls->current != '=') return '!';
         else { next(ls); return TK_NE; }
       }
       case '&': {
         read_string(ls, '\'', seminfo);
         return TK_STRING;
       }
-      case '.': {  /* '.', '..', '...', or number */
+      case '.': {  /* '.', '..', '..=', '...', or number */
         save_and_next(ls);
         if (check_next(ls, ".")) {
           if (check_next(ls, "."))
           else
               if (ls->current == '=') {
                 next(ls);
-                return TK_CCONCAT;
+                return TK_CCONCAT;  /* '..=' */
               }
               else 
                 return TK_CONCAT;   /* '..' */

src/libraries/killa/klex.h

   TK_INTERFACE, TK_NEW, TK_OVERRIDE, TK_PROTECTED, TK_STATIC,
   TK_SUPER, TK_SWITCH, TK_THROW, TK_TRY, TK_UNDEFINED, 
   /* other terminal symbols */
-  TK_NOT, TK_AND, TK_OR, TK_POW, TK_DBCOLON, 
+  TK_AND, TK_OR, TK_POW, TK_DBCOLON, 
   TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, 
   TK_CADD, TK_CSUB, TK_CMUL, TK_CDIV, TK_CMOD, TK_CCONCAT, 
+  TK_BLSH, TK_BRSH,
   TK_EOS, TK_NUMBER, TK_NAME, TK_STRING
 };
 

src/libraries/killa/kobject.c

 #include "kstate.h"
 #include "kstring.h"
 #include "kvm.h"
-
+#include "kubit.h"
 
 
 KILLAI_DDEF const killa_TValue killaO_nilobject_ = {KILLA_NILCONSTANT};
 
 killa_Number killaO_arith (int op, killa_Number v1, killa_Number v2) {
   switch (op) {
-    case KILLA_OPADD: return killai_numadd(NULL, v1, v2);
-    case KILLA_OPSUB: return killai_numsub(NULL, v1, v2);
-    case KILLA_OPMUL: return killai_nummul(NULL, v1, v2);
-    case KILLA_OPDIV: return killai_numdiv(NULL, v1, v2);
-    case KILLA_OPMOD: return killai_nummod(NULL, v1, v2);
-    case KILLA_OPPOW: return killai_numpow(NULL, v1, v2);
-    case KILLA_OPUNM: return killai_numunm(NULL, v1);
+    case KILLA_OPADD:  return killai_numadd(NULL, v1, v2);
+    case KILLA_OPSUB:  return killai_numsub(NULL, v1, v2);
+    case KILLA_OPMUL:  return killai_nummul(NULL, v1, v2);
+    case KILLA_OPDIV:  return killai_numdiv(NULL, v1, v2);
+    case KILLA_OPMOD:  return killai_nummod(NULL, v1, v2);
+    case KILLA_OPPOW:  return killai_numpow(NULL, v1, v2);
+    case KILLA_OPUNM:  return killai_numunm(NULL, v1);
+    case KILLA_OPBAND: return bit_and(NULL,v1,v2);
+    case KILLA_OPBOR:  return bit_or(NULL,v1,v2);
+    case KILLA_OPBXOR: return bit_xor(NULL,v1,v2);
+    case KILLA_OPBLSH: return bit_lshift(NULL,v1,v2);
+    case KILLA_OPBRSH: return bit_rshift(NULL,v1,v2);
+    case KILLA_OPBNOT: return bit_not(NULL,v1);
     default: killa_assert(0); return 0;
   }
 }

src/libraries/killa/kopcodes.c

-/* ========================================================================== */
-/*   Opcodes for Killa virtual machine                                        */
-/* -------------------------------------------------------------------------- */
-/*   Copyright (c) 2012 Laurens Rodriguez Oscanoa.                            */
-/*   Copyright (C) 1994-2012 Lua.org, PUC-Rio.                                */
-/*                                                                            */
-/*   This code is licensed under the MIT license:                             */
-/*   http://www.opensource.org/licenses/mit-license.php                       */
-/* -------------------------------------------------------------------------- */
-
-#define KILLA_CORE
-
-
-#include "kopcodes.h"
-
-
-/* ORDER OP */
-
-KILLAI_DDEF const char *const killaP_opnames[KILLA_NUM_OPCODES+1] = {
-  "MOVE",
-  "LOADK",
-  "LOADKX",
-  "LOADBOOL",
-  "LOADNIL",
-  "GETUPVAL",
-  "GETTABUP",
-  "GETTABLE",
-  "SETTABUP",
-  "SETUPVAL",
-  "SETTABLE",
-  "NEWTABLE",
-  "SELF",
-  "ADD",
-  "SUB",
-  "MUL",
-  "DIV",
-  "MOD",
-  "POW",
-  "UNM",
-  "NOT",
-  "LEN",
-  "CONCAT",
-  "JMP",
-  "EQ",
-  "LT",
-  "LE",
-  "TEST",
-  "TESTSET",
-  "CALL",
-  "TAILCALL",
-  "RETURN",
-  "FORLOOP",
-  "FORPREP",
-  "TFORCALL",
-  "TFORLOOP",
-  "SETLIST",
-  "CLOSURE",
-  "VARARG",
-  "EXTRAARG",
-  NULL
-};
-
-
-#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))
-
-KILLAI_DDEF const killa_ubyte killaP_opmodes[KILLA_NUM_OPCODES] = {
-/*       T  A    B       C     mode		   opcode	*/
-  opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_MOVE */
- ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_LOADK */
- ,opmode(0, 1, OpArgN, OpArgN, iABx)		/* OP_LOADKX */
- ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_LOADBOOL */
- ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_LOADNIL */
- ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_GETUPVAL */
- ,opmode(0, 1, OpArgU, OpArgK, iABC)		/* OP_GETTABUP */
- ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_GETTABLE */
- ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABUP */
- ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_SETUPVAL */
- ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABLE */
- ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_NEWTABLE */
- ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_SELF */
- ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_ADD */
- ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_SUB */
- ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MUL */
- ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_DIV */
- ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MOD */
- ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_POW */
- ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_UNM */
- ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_NOT */
- ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LEN */
- ,opmode(0, 1, OpArgR, OpArgR, iABC)		/* OP_CONCAT */
- ,opmode(0, 0, OpArgR, OpArgN, iAsBx)		/* OP_JMP */
- ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_EQ */
- ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LT */
- ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LE */
- ,opmode(1, 0, OpArgN, OpArgU, iABC)		/* OP_TEST */
- ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TESTSET */
- ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_CALL */
- ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_TAILCALL */
- ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_RETURN */
- ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORLOOP */
- ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORPREP */
- ,opmode(0, 0, OpArgN, OpArgU, iABC)		/* OP_TFORCALL */
- ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_TFORLOOP */
- ,opmode(0, 0, OpArgU, OpArgU, iABC)		/* OP_SETLIST */
- ,opmode(0, 1, OpArgU, OpArgN, iABx)		/* OP_CLOSURE */
- ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_VARARG */
- ,opmode(0, 0, OpArgU, OpArgU, iAx)		/* OP_EXTRAARG */
-};
-
+/* ========================================================================== */
+/*   Opcodes for Killa virtual machine                                        */
+/* -------------------------------------------------------------------------- */
+/*   Copyright (c) 2012 Laurens Rodriguez Oscanoa.                            */
+/*   Copyright (C) 1994-2012 Lua.org, PUC-Rio.                                */
+/*                                                                            */
+/*   This code is licensed under the MIT license:                             */
+/*   http://www.opensource.org/licenses/mit-license.php                       */
+/* -------------------------------------------------------------------------- */
+
+#define KILLA_CORE
+
+
+#include "kopcodes.h"
+
+
+/* ORDER OP */
+
+KILLAI_DDEF const char *const killaP_opnames[KILLA_NUM_OPCODES+1] = {
+  "MOVE",
+  "LOADK",
+  "LOADKX",
+  "LOADBOOL",
+  "LOADNIL",
+  "GETUPVAL",
+  "GETTABUP",
+  "GETTABLE",
+  "SETTABUP",
+  "SETUPVAL",
+  "SETTABLE",
+  "NEWTABLE",
+  "SELF",
+  "ADD",
+  "SUB",
+  "MUL",
+  "DIV",
+  "MOD",
+  "POW",
+  "BITAND",
+  "BITOR",
+  "BITXOR",
+  "BITLSH",
+  "BITRSH",
+  "BITNOT",
+  "UNM",
+  "NOT",
+  "LEN",
+  "CONCAT",
+  "JMP",
+  "EQ",
+  "LT",
+  "LE",
+  "TEST",
+  "TESTSET",
+  "CALL",
+  "TAILCALL",
+  "RETURN",
+  "FORLOOP",
+  "FORPREP",
+  "TFORCALL",
+  "TFORLOOP",
+  "SETLIST",
+  "CLOSURE",
+  "VARARG",
+  "CADD",
+  "CSUB",
+  "CMUL",
+  "CDIV",
+  "CMOD",
+  "CCONCAT",
+  "EXTRAARG",
+  NULL
+};
+
+
+#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))
+
+KILLAI_DDEF const killa_ubyte killaP_opmodes[KILLA_NUM_OPCODES] = {
+/*       T  A    B       C     mode		   opcode	*/
+  opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_MOVE */
+ ,opmode(0, 1, OpArgK, OpArgN, iABx)		/* OP_LOADK */
+ ,opmode(0, 1, OpArgN, OpArgN, iABx)		/* OP_LOADKX */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_LOADBOOL */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_LOADNIL */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_GETUPVAL */
+ ,opmode(0, 1, OpArgU, OpArgK, iABC)		/* OP_GETTABUP */
+ ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_GETTABLE */
+ ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABUP */
+ ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_SETUPVAL */
+ ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABLE */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_NEWTABLE */
+ ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_SELF */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_ADD */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_SUB */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MUL */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_DIV */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_MOD */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)		/* OP_POW */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)        /* OP_BITAND */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)        /* OP_BITOR */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)        /* OP_BITXOR */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)        /* OP_BITLSH */
+ ,opmode(0, 1, OpArgK, OpArgK, iABC)        /* OP_BITRSH */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC)        /* OP_BITNOT */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_UNM */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_NOT */
+ ,opmode(0, 1, OpArgR, OpArgN, iABC)		/* OP_LEN */
+ ,opmode(0, 1, OpArgR, OpArgR, iABC)		/* OP_CONCAT */
+ ,opmode(0, 0, OpArgR, OpArgN, iAsBx)		/* OP_JMP */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_EQ */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LT */
+ ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LE */
+ ,opmode(1, 0, OpArgN, OpArgU, iABC)		/* OP_TEST */
+ ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TESTSET */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_CALL */
+ ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_TAILCALL */
+ ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_RETURN */
+ ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORLOOP */
+ ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_FORPREP */
+ ,opmode(0, 0, OpArgN, OpArgU, iABC)		/* OP_TFORCALL */
+ ,opmode(0, 1, OpArgR, OpArgN, iAsBx)		/* OP_TFORLOOP */
+ ,opmode(0, 0, OpArgU, OpArgU, iABC)		/* OP_SETLIST */
+ ,opmode(0, 1, OpArgU, OpArgN, iABx)		/* OP_CLOSURE */
+ ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_VARARG */
+ ,opmode(0, 1, OpArgK, OpArgN, iABC)		/* OP_CADD */
+ ,opmode(0, 1, OpArgK, OpArgN, iABC)		/* OP_CSUB */
+ ,opmode(0, 1, OpArgK, OpArgN, iABC)		/* OP_CMUL */
+ ,opmode(0, 1, OpArgK, OpArgN, iABC)		/* OP_CDIV */
+ ,opmode(0, 1, OpArgK, OpArgN, iABC)		/* OP_CMOD */
+ ,opmode(0, 1, OpArgK, OpArgN, iABC)		/* OP_CCONCAT */
+ ,opmode(0, 0, OpArgU, OpArgU, iAx)		    /* OP_EXTRAARG */
+};
+

src/libraries/killa/kopcodes.h

-/* ========================================================================== */
-/*   Opcodes for Killa virtual machine                                        */
-/* -------------------------------------------------------------------------- */
-/*   Copyright (c) 2012 Laurens Rodriguez Oscanoa.                            */
-/*   Copyright (C) 1994-2012 Lua.org, PUC-Rio.                                */
-/*                                                                            */
-/*   This code is licensed under the MIT license:                             */
-/*   http://www.opensource.org/licenses/mit-license.php                       */
-/* -------------------------------------------------------------------------- */
+/* ========================================================================== */
+/*   Opcodes for Killa virtual machine                                        */
+/* -------------------------------------------------------------------------- */
+/*   Copyright (c) 2012 Laurens Rodriguez Oscanoa.                            */
+/*   Copyright (C) 1994-2012 Lua.org, PUC-Rio.                                */
+/*                                                                            */
+/*   This code is licensed under the MIT license:                             */
+/*   http://www.opensource.org/licenses/mit-license.php                       */
+/* -------------------------------------------------------------------------- */
+
+#ifndef KOPCODES_H_
+#define KOPCODES_H_
+
+#include "klimits.h"
+
+
+/*===========================================================================
+  We assume that instructions are unsigned numbers.
+  All instructions have an opcode in the first 6 bits.
+  Instructions can have the following fields:
+	`A' : 8 bits
+	`B' : 9 bits
+	`C' : 9 bits
+	'Ax' : 26 bits ('A', 'B', and 'C' together)
+	`Bx' : 18 bits (`B' and `C' together)
+	`sBx' : signed Bx
+
+  A signed argument is represented in excess K; that is, the number
+  value is the unsigned value minus K. K is exactly the maximum value
+  for that argument (so that -max is represented by 0, and +max is
+  represented by 2*max), which is half the maximum for the corresponding
+  unsigned argument.
+===========================================================================*/
+
+
+enum killa_OpMode {iABC, iABx, iAsBx, iAx};  /* basic instruction format */
+
+
+/*
+** size and position of opcode arguments.
+*/
+#define KILLA_SIZE_C    9
+#define KILLA_SIZE_B    9
+#define KILLA_SIZE_Bx   (KILLA_SIZE_C + KILLA_SIZE_B)
+#define KILLA_SIZE_A    8
+#define KILLA_SIZE_Ax   (KILLA_SIZE_C + KILLA_SIZE_B + KILLA_SIZE_A)
+
+#define KILLA_SIZE_OP   6
+
+#define KILLA_POS_OP    0
+#define KILLA_POS_A     (KILLA_POS_OP + KILLA_SIZE_OP)
+#define KILLA_POS_C     (KILLA_POS_A + KILLA_SIZE_A)
+#define KILLA_POS_B     (KILLA_POS_C + KILLA_SIZE_C)
+#define KILLA_POS_Bx    KILLA_POS_C
+#define KILLA_POS_Ax    KILLA_POS_A
+
+
+/*
+** limits for opcode arguments.
+** we use (signed) int to manipulate most arguments,
+** so they must fit in KILLAI_BITSINT-1 bits (-1 for sign)
+*/
+#if KILLA_SIZE_Bx < KILLAI_BITSINT-1
+#define KILLA_MAXARG_Bx     ((1<<KILLA_SIZE_Bx)-1)
+#define KILLA_MAXARG_sBx    (KILLA_MAXARG_Bx>>1)         /* `sBx' is signed */
+#else
+#define KILLA_MAXARG_Bx     KILLA_MAX_INT
+#define KILLA_MAXARG_sBx    KILLA_MAX_INT
+#endif
+
+#if KILLA_SIZE_Ax < KILLAI_BITSINT-1
+#define KILLA_MAXARG_Ax     ((1<<KILLA_SIZE_Ax)-1)
+#else
+#define KILLA_MAXARG_Ax     KILLA_MAX_INT
+#endif
+
+
+#define KILLA_MAXARG_A  ((1<<KILLA_SIZE_A)-1)
+#define KILLA_MAXARG_B  ((1<<KILLA_SIZE_B)-1)
+#define KILLA_MAXARG_C  ((1<<KILLA_SIZE_C)-1)
+
+
+/* creates a mask with `n' 1 bits at position `p' */
+#define KILLA_MASK1(n,p)    ((~((~(killa_Instruction)0)<<(n)))<<(p))
+
+/* creates a mask with `n' 0 bits at position `p' */
+#define KILLA_MASK0(n,p)    (~KILLA_MASK1(n,p))
+
+/*
+** the following macros help to manipulate instructions
+*/
+
+#define KILLA_GET_OPCODE(i) (killa_cast(killa_OpCode, ((i)>>KILLA_POS_OP) & KILLA_MASK1(KILLA_SIZE_OP,0)))
+#define KILLA_SET_OPCODE(i,o)	((i) = (((i)&KILLA_MASK0(KILLA_SIZE_OP,KILLA_POS_OP)) | \
+        ((killa_cast(killa_Instruction, o)<<KILLA_POS_OP)&KILLA_MASK1(KILLA_SIZE_OP,KILLA_POS_OP))))
+
+#define killa_getarg(i,pos,size)    (killa_cast(int, ((i)>>pos) & KILLA_MASK1(size,0)))
+#define killa_setarg(i,v,pos,size)	((i) = (((i)&KILLA_MASK0(size,pos)) | \
+                ((killa_cast(killa_Instruction, v)<<pos)&KILLA_MASK1(size,pos))))
+
+#define KILLA_GETARG_A(i)   killa_getarg(i, KILLA_POS_A, KILLA_SIZE_A)
+#define KILLA_SETARG_A(i,v) killa_setarg(i, v, KILLA_POS_A, KILLA_SIZE_A)
+
+#define KILLA_GETARG_B(i)   killa_getarg(i, KILLA_POS_B, KILLA_SIZE_B)
+#define KILLA_SETARG_B(i,v) killa_setarg(i, v, KILLA_POS_B, KILLA_SIZE_B)
+
+#define KILLA_GETARG_C(i)   killa_getarg(i, KILLA_POS_C, KILLA_SIZE_C)
+#define KILLA_SETARG_C(i,v) killa_setarg(i, v, KILLA_POS_C, KILLA_SIZE_C)
+
+#define KILLA_GETARG_Bx(i)      killa_getarg(i, KILLA_POS_Bx, KILLA_SIZE_Bx)
+#define KILLA_SETARG_Bx(i,v)    killa_setarg(i, v, KILLA_POS_Bx, KILLA_SIZE_Bx)
+
+#define KILLA_GETARG_Ax(i)      killa_getarg(i, KILLA_POS_Ax, KILLA_SIZE_Ax)
+#define KILLA_SETARG_Ax(i,v)    killa_setarg(i, v, KILLA_POS_Ax, KILLA_SIZE_Ax)
+
+#define KILLA_GETARG_sBx(i)     (KILLA_GETARG_Bx(i)-KILLA_MAXARG_sBx)
+#define KILLA_SETARG_sBx(i,b)   KILLA_SETARG_Bx((i),killa_cast(unsigned int, (b)+KILLA_MAXARG_sBx))
+
+
+#define KILLA_CREATE_ABC(o,a,b,c)   ((killa_cast(killa_Instruction, o)<<KILLA_POS_OP) \
+			| (killa_cast(killa_Instruction, a)<<KILLA_POS_A) \
+			| (killa_cast(killa_Instruction, b)<<KILLA_POS_B) \
+			| (killa_cast(killa_Instruction, c)<<KILLA_POS_C))
+
+#define KILLA_CREATE_ABx(o,a,bc)    ((killa_cast(killa_Instruction, o)<<KILLA_POS_OP) \
+			| (killa_cast(killa_Instruction, a)<<KILLA_POS_A) \
+			| (killa_cast(killa_Instruction, bc)<<KILLA_POS_Bx))
+
+#define KILLA_CREATE_Ax(o,a)        ((killa_cast(killa_Instruction, o)<<KILLA_POS_OP) \
+			| (killa_cast(killa_Instruction, a)<<KILLA_POS_Ax))
+
+
+/*
+** Macros to operate RK indices
+*/
+
+/* this bit 1 means constant (0 means register) */
+#define KILLA_BITRK     (1 << (KILLA_SIZE_B - 1))
+
+/* test whether value is a constant */
+#define KILLA_ISK(x)    ((x) & KILLA_BITRK)
+
+/* gets the index of the constant */
+#define KILLA_INDEXK(r) ((int)(r) & ~KILLA_BITRK)
+
+#define KILLA_MAXINDEXRK    (KILLA_BITRK - 1)
+
+/* code a constant index as a RK value */
+#define KILLA_RKASK(x)  ((x) | KILLA_BITRK)
+
+
+/*
+** invalid register that fits in 8 bits
+*/
+#define KILLA_NO_REG    KILLA_MAXARG_A
+
+
+/*
+** R(x) - register
+** Kst(x) - constant (in constant table)
+** RK(x) == if KILLA_ISK(x) then Kst(KILLA_INDEXK(x)) else R(x)
+*/
+
+
+/*
+** grep "ORDER OP" if you change these enums
+*/
+
+typedef enum {
+/*----------------------------------------------------------------------
+name		args	description
+------------------------------------------------------------------------*/
+OP_MOVE,/*	A B	R(A) := R(B)					*/
+OP_LOADK,/*	A Bx	R(A) := Kst(Bx)					*/
+OP_LOADKX,/*	A 	R(A) := Kst(extra arg)				*/
+OP_LOADBOOL,/*	A B C	R(A) := (Bool)B; if (C) pc++			*/
+OP_LOADNIL,/*	A B	R(A), R(A+1), ..., R(A+B) := nil		*/
+OP_GETUPVAL,/*	A B	R(A) := UpValue[B]				*/
+
+OP_GETTABUP,/*	A B C	R(A) := UpValue[B][RK(C)]			*/
+OP_GETTABLE,/*	A B C	R(A) := R(B)[RK(C)]				*/
+
+OP_SETTABUP,/*	A B C	UpValue[A][RK(B)] := RK(C)			*/
+OP_SETUPVAL,/*	A B	UpValue[B] := R(A)				*/
+OP_SETTABLE,/*	A B C	R(A)[RK(B)] := RK(C)				*/
+
+OP_NEWTABLE,/*	A B C	R(A) := {} (size = B,C)				*/
+
+OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C)]		*/
+
+OP_ADD,/*	A B C	R(A) := RK(B) + RK(C)				*/
+OP_SUB,/*	A B C	R(A) := RK(B) - RK(C)				*/
+OP_MUL,/*	A B C	R(A) := RK(B) * RK(C)				*/
+OP_DIV,/*	A B C	R(A) := RK(B) / RK(C)				*/
+OP_MOD,/*	A B C	R(A) := RK(B) % RK(C)				*/
+OP_POW,/*	A B C	R(A) := RK(B) ^ RK(C)				*/
+
+OP_BAND,/*  A B C   R(A) := RK(B) & RK(C)               */
+OP_BOR,/*   A B C   R(A) := RK(B) | RK(C)               */
+OP_BXOR,/*  A B C   R(A) := RK(B) ^^ RK(C)              */
+OP_BLSH,/*  A B C   R(A) := RK(B) << RK(C)              */
+OP_BRSH,/*  A B C   R(A) := RK(B) >> RK(C)              */
+OP_BNOT,/*   A B C   R(A) := ~RK(B)                      */
+
+OP_UNM,/*	A B	R(A) := -R(B)					*/
+OP_NOT,/*	A B	R(A) := not R(B)				*/
+OP_LEN,/*	A B	R(A) := length of R(B)				*/
+
+OP_CONCAT,/*	A B C	R(A) := R(B).. ... ..R(C)			*/
+
+OP_JMP,/*	A sBx	pc+=sBx; if (A) close all upvalues >= R(A) + 1	*/
+OP_EQ,/*	A B C	if ((RK(B) == RK(C)) ~= A) then pc++		*/
+OP_LT,/*	A B C	if ((RK(B) <  RK(C)) ~= A) then pc++		*/
+OP_LE,/*	A B C	if ((RK(B) <= RK(C)) ~= A) then pc++		*/
+
+OP_TEST,/*	A C	if not (R(A) <=> C) then pc++			*/
+OP_TESTSET,/*	A B C	if (R(B) <=> C) then R(A) := R(B) else pc++	*/
+
+OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
+OP_TAILCALL,/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/
+OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see note)	*/
+
+OP_FORLOOP,/*	A sBx	R(A)+=R(A+2);
+			if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
+OP_FORPREP,/*	A sBx	R(A)-=R(A+2); pc+=sBx				*/
+
+OP_TFORCALL,/*	A C	R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));	*/
+OP_TFORLOOP,/*	A sBx	if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
+
+OP_SETLIST,/*	A B C	R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B	*/
+
+OP_CLOSURE,/*	A Bx	R(A) := closure(KPROTO[Bx])         */
+
+OP_VARARG,/*	A B	R(A), R(A+1), ..., R(A+B-2) = vararg    */
 
-#ifndef KOPCODES_H_
-#define KOPCODES_H_
-
-#include "klimits.h"
-
-
-/*===========================================================================
-  We assume that instructions are unsigned numbers.
-  All instructions have an opcode in the first 6 bits.
-  Instructions can have the following fields:
-	`A' : 8 bits
-	`B' : 9 bits
-	`C' : 9 bits
-	'Ax' : 26 bits ('A', 'B', and 'C' together)
-	`Bx' : 18 bits (`B' and `C' together)
-	`sBx' : signed Bx
-
-  A signed argument is represented in excess K; that is, the number
-  value is the unsigned value minus K. K is exactly the maximum value
-  for that argument (so that -max is represented by 0, and +max is
-  represented by 2*max), which is half the maximum for the corresponding
-  unsigned argument.
-===========================================================================*/
-
-
-enum killa_OpMode {iABC, iABx, iAsBx, iAx};  /* basic instruction format */
-
-
-/*
-** size and position of opcode arguments.
-*/
-#define KILLA_SIZE_C    9
-#define KILLA_SIZE_B    9
-#define KILLA_SIZE_Bx   (KILLA_SIZE_C + KILLA_SIZE_B)
-#define KILLA_SIZE_A    8
-#define KILLA_SIZE_Ax   (KILLA_SIZE_C + KILLA_SIZE_B + KILLA_SIZE_A)
-
-#define KILLA_SIZE_OP   6
-
-#define KILLA_POS_OP    0
-#define KILLA_POS_A     (KILLA_POS_OP + KILLA_SIZE_OP)
-#define KILLA_POS_C     (KILLA_POS_A + KILLA_SIZE_A)
-#define KILLA_POS_B     (KILLA_POS_C + KILLA_SIZE_C)
-#define KILLA_POS_Bx    KILLA_POS_C
-#define KILLA_POS_Ax    KILLA_POS_A
-
-
-/*
-** limits for opcode arguments.
-** we use (signed) int to manipulate most arguments,
-** so they must fit in KILLAI_BITSINT-1 bits (-1 for sign)
-*/
-#if KILLA_SIZE_Bx < KILLAI_BITSINT-1
-#define KILLA_MAXARG_Bx     ((1<<KILLA_SIZE_Bx)-1)
-#define KILLA_MAXARG_sBx    (KILLA_MAXARG_Bx>>1)         /* `sBx' is signed */
-#else
-#define KILLA_MAXARG_Bx     KILLA_MAX_INT
-#define KILLA_MAXARG_sBx    KILLA_MAX_INT
-#endif
-
-#if KILLA_SIZE_Ax < KILLAI_BITSINT-1
-#define KILLA_MAXARG_Ax     ((1<<KILLA_SIZE_Ax)-1)
-#else
-#define KILLA_MAXARG_Ax     KILLA_MAX_INT
-#endif
-
-
-#define KILLA_MAXARG_A  ((1<<KILLA_SIZE_A)-1)
-#define KILLA_MAXARG_B  ((1<<KILLA_SIZE_B)-1)
-#define KILLA_MAXARG_C  ((1<<KILLA_SIZE_C)-1)
-
-
-/* creates a mask with `n' 1 bits at position `p' */
-#define KILLA_MASK1(n,p)    ((~((~(killa_Instruction)0)<<(n)))<<(p))
-
-/* creates a mask with `n' 0 bits at position `p' */
-#define KILLA_MASK0(n,p)    (~KILLA_MASK1(n,p))
-
-/*
-** the following macros help to manipulate instructions
-*/
-
-#define KILLA_GET_OPCODE(i) (killa_cast(killa_OpCode, ((i)>>KILLA_POS_OP) & KILLA_MASK1(KILLA_SIZE_OP,0)))
-#define KILLA_SET_OPCODE(i,o)	((i) = (((i)&KILLA_MASK0(KILLA_SIZE_OP,KILLA_POS_OP)) | \
-        ((killa_cast(killa_Instruction, o)<<KILLA_POS_OP)&KILLA_MASK1(KILLA_SIZE_OP,KILLA_POS_OP))))
-
-#define killa_getarg(i,pos,size)    (killa_cast(int, ((i)>>pos) & KILLA_MASK1(size,0)))
-#define killa_setarg(i,v,pos,size)	((i) = (((i)&KILLA_MASK0(size,pos)) | \
-                ((killa_cast(killa_Instruction, v)<<pos)&KILLA_MASK1(size,pos))))
-
-#define KILLA_GETARG_A(i)   killa_getarg(i, KILLA_POS_A, KILLA_SIZE_A)
-#define KILLA_SETARG_A(i,v) killa_setarg(i, v, KILLA_POS_A, KILLA_SIZE_A)
-
-#define KILLA_GETARG_B(i)   killa_getarg(i, KILLA_POS_B, KILLA_SIZE_B)
-#define KILLA_SETARG_B(i,v) killa_setarg(i, v, KILLA_POS_B, KILLA_SIZE_B)
-
-#define KILLA_GETARG_C(i)   killa_getarg(i, KILLA_POS_C, KILLA_SIZE_C)
-#define KILLA_SETARG_C(i,v) killa_setarg(i, v, KILLA_POS_C, KILLA_SIZE_C)
-
-#define KILLA_GETARG_Bx(i)      killa_getarg(i, KILLA_POS_Bx, KILLA_SIZE_Bx)
-#define KILLA_SETARG_Bx(i,v)    killa_setarg(i, v, KILLA_POS_Bx, KILLA_SIZE_Bx)
-
-#define KILLA_GETARG_Ax(i)      killa_getarg(i, KILLA_POS_Ax, KILLA_SIZE_Ax)
-#define KILLA_SETARG_Ax(i,v)    killa_setarg(i, v, KILLA_POS_Ax, KILLA_SIZE_Ax)
-
-#define KILLA_GETARG_sBx(i)     (KILLA_GETARG_Bx(i)-KILLA_MAXARG_sBx)
-#define KILLA_SETARG_sBx(i,b)   KILLA_SETARG_Bx((i),killa_cast(unsigned int, (b)+KILLA_MAXARG_sBx))
-
-
-#define KILLA_CREATE_ABC(o,a,b,c)   ((killa_cast(killa_Instruction, o)<<KILLA_POS_OP) \
-			| (killa_cast(killa_Instruction, a)<<KILLA_POS_A) \
-			| (killa_cast(killa_Instruction, b)<<KILLA_POS_B) \
-			| (killa_cast(killa_Instruction, c)<<KILLA_POS_C))
-
-#define KILLA_CREATE_ABx(o,a,bc)    ((killa_cast(killa_Instruction, o)<<KILLA_POS_OP) \
-			| (killa_cast(killa_Instruction, a)<<KILLA_POS_A) \
-			| (killa_cast(killa_Instruction, bc)<<KILLA_POS_Bx))
-
-#define KILLA_CREATE_Ax(o,a)        ((killa_cast(killa_Instruction, o)<<KILLA_POS_OP) \
-			| (killa_cast(killa_Instruction, a)<<KILLA_POS_Ax))
-
-
-/*
-** Macros to operate RK indices
-*/
-
-/* this bit 1 means constant (0 means register) */
-#define KILLA_BITRK     (1 << (KILLA_SIZE_B - 1))
-
-/* test whether value is a constant */
-#define KILLA_ISK(x)    ((x) & KILLA_BITRK)
-
-/* gets the index of the constant */
-#define KILLA_INDEXK(r) ((int)(r) & ~KILLA_BITRK)
-
-#define KILLA_MAXINDEXRK    (KILLA_BITRK - 1)
-
-/* code a constant index as a RK value */
-#define KILLA_RKASK(x)  ((x) | KILLA_BITRK)
-
-
-/*
-** invalid register that fits in 8 bits
-*/
-#define KILLA_NO_REG    KILLA_MAXARG_A
-
-
-/*
-** R(x) - register
-** Kst(x) - constant (in constant table)
-** RK(x) == if KILLA_ISK(x) then Kst(KILLA_INDEXK(x)) else R(x)
-*/
-
-
-/*
-** grep "ORDER OP" if you change these enums
-*/
-
-typedef enum {
-/*----------------------------------------------------------------------
-name		args	description
-------------------------------------------------------------------------*/
-OP_MOVE,/*	A B	R(A) := R(B)					*/
-OP_LOADK,/*	A Bx	R(A) := Kst(Bx)					*/
-OP_LOADKX,/*	A 	R(A) := Kst(extra arg)				*/
-OP_LOADBOOL,/*	A B C	R(A) := (Bool)B; if (C) pc++			*/
-OP_LOADNIL,/*	A B	R(A), R(A+1), ..., R(A+B) := nil		*/
-OP_GETUPVAL,/*	A B	R(A) := UpValue[B]				*/
-
-OP_GETTABUP,/*	A B C	R(A) := UpValue[B][RK(C)]			*/
-OP_GETTABLE,/*	A B C	R(A) := R(B)[RK(C)]				*/
-
-OP_SETTABUP,/*	A B C	UpValue[A][RK(B)] := RK(C)			*/
-OP_SETUPVAL,/*	A B	UpValue[B] := R(A)				*/
-OP_SETTABLE,/*	A B C	R(A)[RK(B)] := RK(C)				*/
-
-OP_NEWTABLE,/*	A B C	R(A) := {} (size = B,C)				*/
-
-OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C)]		*/
-
-OP_ADD,/*	A B C	R(A) := RK(B) + RK(C)				*/
-OP_SUB,/*	A B C	R(A) := RK(B) - RK(C)				*/
-OP_MUL,/*	A B C	R(A) := RK(B) * RK(C)				*/
-OP_DIV,/*	A B C	R(A) := RK(B) / RK(C)				*/
-OP_MOD,/*	A B C	R(A) := RK(B) % RK(C)				*/
-OP_POW,/*	A B C	R(A) := RK(B) ^ RK(C)				*/
-OP_UNM,/*	A B	R(A) := -R(B)					*/
-OP_NOT,/*	A B	R(A) := not R(B)				*/
-OP_LEN,/*	A B	R(A) := length of R(B)				*/
-
-OP_CONCAT,/*	A B C	R(A) := R(B).. ... ..R(C)			*/
-
-OP_JMP,/*	A sBx	pc+=sBx; if (A) close all upvalues >= R(A) + 1	*/
-OP_EQ,/*	A B C	if ((RK(B) == RK(C)) ~= A) then pc++		*/
-OP_LT,/*	A B C	if ((RK(B) <  RK(C)) ~= A) then pc++		*/
-OP_LE,/*	A B C	if ((RK(B) <= RK(C)) ~= A) then pc++		*/
-
-OP_TEST,/*	A C	if not (R(A) <=> C) then pc++			*/
-OP_TESTSET,/*	A B C	if (R(B) <=> C) then R(A) := R(B) else pc++	*/
-
-OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
-OP_TAILCALL,/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/
-OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see note)	*/
-
-OP_FORLOOP,/*	A sBx	R(A)+=R(A+2);
-			if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
-OP_FORPREP,/*	A sBx	R(A)-=R(A+2); pc+=sBx				*/
-
-OP_TFORCALL,/*	A C	R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));	*/
-OP_TFORLOOP,/*	A sBx	if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
-
-OP_SETLIST,/*	A B C	R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B	*/
-
-OP_CLOSURE,/*	A Bx	R(A) := closure(KPROTO[Bx])			*/
-
-OP_VARARG,/*	A B	R(A), R(A+1), ..., R(A+B-2) = vararg		*/
-
-OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
-} killa_OpCode;
-
-
-#define KILLA_NUM_OPCODES   (killa_cast(int, OP_EXTRAARG) + 1)
-
-
-
-/*===========================================================================
-  Notes:
-  (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then `top' is
-  set to last_result+1, so next open instruction (OP_CALL, OP_RETURN,
-  OP_SETLIST) may use `top'.
-
-  (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
-  set top (like in OP_CALL with C == 0).
-
-  (*) In OP_RETURN, if (B == 0) then return up to `top'.
-
-  (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next
-  'instruction' is EXTRAARG(real C).
-
-  (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
-
-  (*) For comparisons, A specifies what condition the test should accept
-  (true or false).
-
-  (*) All `skips' (pc++) assume that next instruction is a jump.
-
-===========================================================================*/
-
-
-/*
-** masks for instruction properties. The format is:
-** bits 0-1: op mode
-** bits 2-3: C arg mode
-** bits 4-5: B arg mode
-** bit 6: instruction set register A
-** bit 7: operator is a test (next instruction must be a jump)
-*/
-
-enum killa_OpArgMask {
-  OpArgN,  /* argument is not used */
-  OpArgU,  /* argument is used */
-  OpArgR,  /* argument is a register or a jump offset */
-  OpArgK   /* argument is a constant or register/constant */
-};
-
-KILLAI_DDEC const killa_ubyte killaP_opmodes[KILLA_NUM_OPCODES];
-
-#define killa_getOpMode(m)  (killa_cast(enum killa_OpMode, killaP_opmodes[m] & 3))
-#define killa_getBMode(m)   (killa_cast(enum killa_OpArgMask, (killaP_opmodes[m] >> 4) & 3))
-#define killa_getCMode(m)   (killa_cast(enum killa_OpArgMask, (killaP_opmodes[m] >> 2) & 3))
-#define killa_testAMode(m)  (killaP_opmodes[m] & (1 << 6))
-#define killa_testTMode(m)  (killaP_opmodes[m] & (1 << 7))
-
-
-KILLAI_DDEC const char *const killaP_opnames[KILLA_NUM_OPCODES+1];  /* opcode names */
-
-
-/* number of list items to accumulate before a SETLIST instruction */
-#define KILLA_LFIELDS_PER_FLUSH	50
-
-
-#endif
+OP_CADD,/*	A B R(A) := R(A) + RK(B)        */
+OP_CSUB,/*	A B R(A) := R(A) - RK(B)        */
+OP_CMUL,/*	A B R(A) := R(A) * RK(B)        */
+OP_CDIV,/*	A B R(A) := R(A) / RK(B)        */
+OP_CMOD,/*	A B R(A) := R(A) % RK(B)        */
+OP_CCONCAT,/*	A B R(A) := R(A) .. RK(B)   */
+
+OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
+} killa_OpCode;
+
+
+#define KILLA_NUM_OPCODES   (killa_cast(int, OP_EXTRAARG) + 1)
+
+
+
+/*===========================================================================
+  Notes:
+  (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then `top' is
+  set to last_result+1, so next open instruction (OP_CALL, OP_RETURN,
+  OP_SETLIST) may use `top'.
+
+  (*) In OP_VARARG, if (B == 0) then use actual number of varargs and
+  set top (like in OP_CALL with C == 0).
+
+  (*) In OP_RETURN, if (B == 0) then return up to `top'.
+
+  (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next
+  'instruction' is EXTRAARG(real C).
+
+  (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
+
+  (*) For comparisons, A specifies what condition the test should accept
+  (true or false).
+
+  (*) All `skips' (pc++) assume that next instruction is a jump.
+
+===========================================================================*/
+
+
+/*
+** masks for instruction properties. The format is:
+** bits 0-1: op mode
+** bits 2-3: C arg mode
+** bits 4-5: B arg mode
+** bit 6: instruction set register A
+** bit 7: operator is a test (next instruction must be a jump)
+*/
+
+enum killa_OpArgMask {
+  OpArgN,  /* argument is not used */
+  OpArgU,  /* argument is used */
+  OpArgR,  /* argument is a register or a jump offset */
+  OpArgK   /* argument is a constant or register/constant */
+};
+
+KILLAI_DDEC const killa_ubyte killaP_opmodes[KILLA_NUM_OPCODES];
+
+#define killa_getOpMode(m)  (killa_cast(enum killa_OpMode, killaP_opmodes[m] & 3))
+#define killa_getBMode(m)   (killa_cast(enum killa_OpArgMask, (killaP_opmodes[m] >> 4) & 3))
+#define killa_getCMode(m)   (killa_cast(enum killa_OpArgMask, (killaP_opmodes[m] >> 2) & 3))
+#define killa_testAMode(m)  (killaP_opmodes[m] & (1 << 6))
+#define killa_testTMode(m)  (killaP_opmodes[m] & (1 << 7))
+
+
+KILLAI_DDEC const char *const killaP_opnames[KILLA_NUM_OPCODES+1];  /* opcode names */
+
+
+/* number of list items to accumulate before a SETLIST instruction */
+#define KILLA_LFIELDS_PER_FLUSH	50
+
+
+#endif

src/libraries/killa/kparser.c

-/* ========================================================================== */
-/*   Killa Parser                                                             */
-/* -------------------------------------------------------------------------- */
-/*   Copyright (c) 2012 Laurens Rodriguez Oscanoa.                            */
-/*   Copyright (C) 1994-2012 Lua.org, PUC-Rio.                                */
-/*                                                                            */
-/*   This code is licensed under the MIT license:                             */
-/*   http://www.opensource.org/licenses/mit-license.php                       */
-/* -------------------------------------------------------------------------- */
-
-#include <string.h>
-
-#define KILLA_CORE
-
-#include "killa.h"
-
-#include "kcode.h"
-#include "kdebug.h"
-#include "kdo.h"
-#include "kfunc.h"
-#include "klex.h"
-#include "kmem.h"
-#include "kobject.h"
-#include "kopcodes.h"
-#include "kparser.h"
-#include "kstate.h"
-#include "kstring.h"
-#include "ktable.h"
-
-
-/* Define 'this' symbol */
-#define TK_THIS     "this"
-
-
-/* maximum number of local variables per function (must be smaller
-   than 250, due to the bytecode format) */
-#define MAXVARS		200
-
-
-#define hasmultret(k)		((k) == VCALL || (k) == VVARARG)
-
-
-
-/*
-** nodes for block list (list of active blocks)
-*/
-typedef struct killa_BlockCnt {
-  struct killa_BlockCnt *previous;  /* chain */
-  short firstlabel;  /* index of first label in this block */
-  short firstgoto;  /* index of first pending goto in this block */
-  killa_ubyte nactvar;  /* # active locals outside the block */
-  killa_ubyte upval;  /* true if some variable in the block is an upvalue */
-  killa_ubyte isloop;  /* true if `block' is a loop */
-} killa_BlockCnt;
-
-
-
-/*
-** prototypes for recursive non-terminal functions
-*/
-static void statement (killa_LexState *ls);
-static void expr (killa_LexState *ls, killa_expdesc *v);
-
-
-static void anchor_token (killa_LexState *ls) {
-  /* last token from outer function must be EOS */
-  killa_assert(ls->fs != NULL || ls->t.token == TK_EOS);
-  if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
-    killa_TString *ts = ls->t.seminfo.ts;
-    killaX_newstring(ls, killa_getstr(ts), ts->tsv.len);
-  }
-}
-
-
-/* semantic error */
-static killa_noret semerror (killa_LexState *ls, const char *msg) {
-  ls->t.token = 0;  /* remove 'near to' from final message */
-  killaX_syntaxerror(ls, msg);
-}
-
-
-static killa_noret error_expected (killa_LexState *ls, int token) {
-  killaX_syntaxerror(ls,
-      killaO_pushfstring(ls->L, "%s expected", killaX_token2str(ls, token)));
-}
-
-
-static killa_noret errorlimit (killa_FuncState *fs, int limit, const char *what) {
-  killa_State *L = fs->ls->L;
-  const char *msg;
-  int line = fs->f->linedefined;
-  const char *where = (line == 0)
-                      ? "main function"
-                      : killaO_pushfstring(L, "function at line %d", line);
-  msg = killaO_pushfstring(L, "too many %s (limit is %d) in %s",
-                             what, limit, where);
-  killaX_syntaxerror(fs->ls, msg);
-}
-
-
-static void checklimit (killa_FuncState *fs, int v, int l, const char *what) {
-  if (v > l) errorlimit(fs, l, what);
-}
-
-
-static int testnext (killa_LexState *ls, int c) {
-  if (ls->t.token == c) {
-    killaX_next(ls);
-    return 1;
-  }
-  else return 0;
-}
-
-
-static void check (killa_LexState *ls, int c) {
-  if (ls->t.token != c)
-    error_expected(ls, c);
-}
-
-
-static void checknext (killa_LexState *ls, int c) {
-  check(ls, c);
-  killaX_next(ls);
-}
-
-
-#define check_condition(ls,c,msg)	{ if (!(c)) killaX_syntaxerror(ls, msg); }
-
-
-
-static void check_match (killa_LexState *ls, int what, int who, int where) {
-  if (!testnext(ls, what)) {
-    if (where == ls->linenumber)
-      error_expected(ls, what);
-    else {
-      killaX_syntaxerror(ls, killaO_pushfstring(ls->L,
-             "%s expected (to close %s at line %d)",
-              killaX_token2str(ls, what), killaX_token2str(ls, who), where));
-    }
-  }
-}
-
-
-static killa_TString *str_checkname (killa_LexState *ls) {
-  killa_TString *ts;
-  check(ls, TK_NAME);
-  ts = ls->t.seminfo.ts;
-  killaX_next(ls);
-  return ts;
-}
-
-
-static void init_exp (killa_expdesc *e, killa_expkind k, int i) {
-  e->f = e->t = KILLA_NO_JUMP;
-  e->k = k;
-  e->u.info = i;
-}
-
-
-static void codestring (killa_LexState *ls, killa_expdesc *e, killa_TString *s) {
-  init_exp(e, VK, killaK_stringK(ls->fs, s));
-}
-
-
-static void checkname (killa_LexState *ls, killa_expdesc *e) {
-  codestring(ls, e, str_checkname(ls));
-}
-
-
-static int registerlocalvar (killa_LexState *ls, killa_TString *varname) {
-  killa_FuncState *fs = ls->fs;
-  killa_Proto *f = fs->f;
-  int oldsize = f->sizelocvars;
-  killaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
-                  killa_LocVar, SHRT_MAX, "local variables");
-  while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
-  f->locvars[fs->nlocvars].varname = varname;
-  killaC_objbarrier(ls->L, f, varname);
-  return fs->nlocvars++;
-}
-
-
-static void new_localvar (killa_LexState *ls, killa_TString *name) {
-  killa_FuncState *fs = ls->fs;
-  killa_Dyndata *dyd = ls->dyd;
-  int reg = registerlocalvar(ls, name);
-  checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
-                  MAXVARS, "local variables");
-  killaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
-                  dyd->actvar.size, killa_Vardesc, KILLA_MAX_INT, "local variables");
-  dyd->actvar.arr[dyd->actvar.n++].idx = killa_cast(short, reg);
-}
-
-
-static void new_localvarliteral_ (killa_LexState *ls, const char *name, size_t sz) {
-  new_localvar(ls, killaX_newstring(ls, name, sz));
-}
-
-#define new_localvarliteral(ls,v) \
-	new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1)
-
-
-static killa_LocVar *getlocvar (killa_FuncState *fs, int i) {
-  int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;
-  killa_assert(idx < fs->nlocvars);
-  return &fs->f->locvars[idx];
-}
-
-
-static void adjustlocalvars (killa_LexState *ls, int nvars) {
-  killa_FuncState *fs = ls->fs;
-  fs->nactvar = killa_cast_byte(fs->nactvar + nvars);
-  for (; nvars; nvars--) {
-    getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;
-  }
-}
-
-
-static void removevars (killa_FuncState *fs, int tolevel) {
-  fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);
-  while (fs->nactvar > tolevel)
-    getlocvar(fs, --fs->nactvar)->endpc = fs->pc;
-}
-
-
-static int searchupvalue (killa_FuncState *fs, killa_TString *name) {
-  int i;
-  killa_Upvaldesc *up = fs->f->upvalues;
-  for (i = 0; i < fs->nups; i++) {
-    if (killa_eqstr(up[i].name, name)) return i;
-  }
-  return -1;  /* not found */
-}
-
-
-static int newupvalue (killa_FuncState *fs, killa_TString *name, killa_expdesc *v) {
-  killa_Proto *f = fs->f;
-  int oldsize = f->sizeupvalues;
-  checklimit(fs, fs->nups + 1, KILLA_MAXUPVAL, "upvalues");
-  killaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
-                  killa_Upvaldesc, KILLA_MAXUPVAL, "upvalues");
-  while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
-  f->upvalues[fs->nups].instack = (v->k == VLOCAL);
-  f->upvalues[fs->nups].idx = killa_cast_byte(v->u.info);
-  f->upvalues[fs->nups].name = name;
-  killaC_objbarrier(fs->ls->L, f, name);
-  return fs->nups++;
-}
-
-
-static int searchvar (killa_FuncState *fs, killa_TString *n) {
-  int i;
-  for (i=fs->nactvar-1; i >= 0; i--) {
-    if (killa_eqstr(n, getlocvar(fs, i)->varname))
-      return i;
-  }
-  return -1;  /* not found */
-}
-
-
-/*
-  Mark block where variable at given level was defined
-  (to emit close instructions later).
-*/
-static void markupval (killa_FuncState *fs, int level) {
-  killa_BlockCnt *bl = fs->bl;
-  while (bl->nactvar > level) bl = bl->previous;
-  bl->upval = 1;
-}
-
-
-/*
-  Find variable with given name 'n'. If it is an upvalue, add this
-  upvalue into all intermediate functions.
-*/
-static int singlevaraux (killa_FuncState *fs, killa_TString *n, killa_expdesc *var, int base) {
-  if (fs == NULL)  /* no more levels? */
-    return VVOID;  /* default is global */
-  else {
-    int v = searchvar(fs, n);  /* look up locals at current level */
-    if (v >= 0) {  /* found? */
-      init_exp(var, VLOCAL, v);  /* variable is local */
-      if (!base)
-        markupval(fs, v);  /* local will be used as an upval */
-      return VLOCAL;
-    }
-    else {  /* not found as local at current level; try upvalues */
-      int idx = searchupvalue(fs, n);  /* try existing upvalues */
-      if (idx < 0) {  /* not found? */
-        if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */
-          return VVOID;  /* not found; is a global */
-        /* else was LOCAL or UPVAL */
-        idx  = newupvalue(fs, n, var);  /* will be a new upvalue */
-      }
-      init_exp(var, VUPVAL, idx);
-      return VUPVAL;
-    }