Index: EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/codegen.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.2.0/mrbgems/mruby-compiler/core/codegen.c	(revision 321)
+++ EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-compiler/core/codegen.c	(revision 331)
@@ -9,14 +9,18 @@
 #include <stdlib.h>
 #include <string.h>
-#include "mruby.h"
-#include "mruby/compile.h"
-#include "mruby/proc.h"
-#include "mruby/numeric.h"
-#include "mruby/string.h"
-#include "mruby/debug.h"
+#include <mruby.h>
+#include <mruby/compile.h>
+#include <mruby/proc.h>
+#include <mruby/numeric.h>
+#include <mruby/string.h>
+#include <mruby/debug.h>
 #include "node.h"
-#include "mruby/opcode.h"
-#include "mruby/re.h"
-#include "mruby/throw.h"
+#include <mruby/opcode.h>
+#include <mruby/re.h>
+#include <mruby/throw.h>
+
+#ifndef MRB_CODEGEN_LEVEL_MAX
+#define MRB_CODEGEN_LEVEL_MAX 1024
+#endif
 
 typedef mrb_ast_node node;
@@ -74,4 +78,6 @@
   uint16_t filename_index;
   parser_state* parser;
+
+  int rlev;                     /* recursion levels */
 } codegen_scope;
 
@@ -94,8 +100,9 @@
   while (s->prev) {
     codegen_scope *tmp = s->prev;
+    mrb_free(s->mrb, s->iseq);
     mrb_pool_close(s->mpool);
     s = tmp;
   }
-#ifndef MBB_DISABLE_STDIO
+#ifndef MRB_DISABLE_STDIO
   if (s->filename && s->lineno) {
     fprintf(stderr, "codegen error:%s:%d: %s\n", s->filename, s->lineno, message);
@@ -340,4 +347,10 @@
         }
       }
+      if (c0 == OP_LOADNIL) {
+        if (GETARG_B(i) == GETARG_A(i0)) {
+          s->pc--;
+          return 0;
+        }
+      }
       break;
     case OP_JMPIF:
@@ -381,4 +394,7 @@
     scope_error(s);
     break;
+  }
+  if (diff > MAXARG_sBx) {
+    codegen_error(s, "too distant jump address");
   }
   s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff);
@@ -495,5 +511,10 @@
 }
 
-static inline int
+/* method symbols should be fit in 9 bits */
+#define MAXMSYMLEN 512
+/* maximum symbol numbers */
+#define MAXSYMLEN 65536
+
+static int
 new_msym(codegen_scope *s, mrb_sym sym)
 {
@@ -503,11 +524,11 @@
 
   len = s->irep->slen;
-  if (len > 256) len = 256;
+  if (len > MAXMSYMLEN) len = MAXMSYMLEN;
   for (i=0; i<len; i++) {
     if (s->irep->syms[i] == sym) return i;
     if (s->irep->syms[i] == 0) break;
   }
-  if (i == 256) {
-    codegen_error(s, "too many symbols (max 256)");
+  if (i == MAXMSYMLEN) {
+    codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXMSYMLEN) ")");
   }
   s->irep->syms[i] = sym;
@@ -516,5 +537,5 @@
 }
 
-static inline int
+static int
 new_sym(codegen_scope *s, mrb_sym sym)
 {
@@ -524,11 +545,16 @@
     if (s->irep->syms[i] == sym) return i;
   }
-  if (s->irep->slen > 125 && s->irep->slen < 256) {
-    s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*65536);
-    for (i = 0; i < 256 - s->irep->slen; i++) {
+  if (s->irep->slen == MAXSYMLEN) {
+    codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXSYMLEN) ")");
+  }
+
+  if (s->irep->slen > MAXMSYMLEN/2 && s->scapa == MAXMSYMLEN) {
+    s->scapa = MAXSYMLEN;
+    s->irep->syms = (mrb_sym *)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*MAXSYMLEN);
+    for (i = s->irep->slen; i < MAXMSYMLEN; i++) {
       static const mrb_sym mrb_sym_zero = { 0 };
-      s->irep->syms[i + s->irep->slen] = mrb_sym_zero;
-    }
-    s->irep->slen = 256;
+      s->irep->syms[i] = mrb_sym_zero;
+    }
+    s->irep->slen = MAXMSYMLEN;
   }
   s->irep->syms[s->irep->slen] = sym;
@@ -583,7 +609,4 @@
   push();                       /* push for a block parameter */
 
-  lp = loop_push(s, LOOP_FOR);
-  lp->pc1 = new_label(s);
-
   /* generate loop variable */
   n2 = tree->car;
@@ -595,4 +618,9 @@
     gen_vmassignment(s, n2, 1, VAL);
   }
+  /* construct loop */
+  lp = loop_push(s, LOOP_FOR);
+  lp->pc2 = new_label(s);
+
+  /* loop body */
   codegen(s, tree->cdr->cdr->car, VAL);
   pop();
@@ -645,4 +673,7 @@
     ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0;
 
+    if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) {
+      codegen_error(s, "too many formal arguments");
+    }
     a = ((mrb_aspec)(ma & 0x1f) << 18)
       | ((mrb_aspec)(oa & 0x1f) << 13)
@@ -765,6 +796,8 @@
 }
 
+#define CALL_MAXARGS 127
+
 static int
-gen_values(codegen_scope *s, node *t, int val)
+gen_values(codegen_scope *s, node *t, int val, int extra)
 {
   int n = 0;
@@ -773,16 +806,24 @@
   while (t) {
     is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */
-    if (n >= 127 || is_splat) {
+    if (
+      n+extra >= CALL_MAXARGS - 1 /* need to subtract one because vm.c expects an array if n == CALL_MAXARGS */
+      || is_splat) {
       if (val) {
-        pop_n(n);
-        genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
-        push();
-        codegen(s, t->car, VAL);
-        pop(); pop();
-        if (is_splat) {
-          genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+        if (is_splat && n == 0 && (intptr_t)t->car->cdr->car == NODE_ARRAY) {
+          codegen(s, t->car->cdr, VAL);
+          pop();
         }
         else {
-          genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+          pop_n(n);
+          genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
+          push();
+          codegen(s, t->car, VAL);
+          pop(); pop();
+          if (is_splat) {
+            genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+          }
+          else {
+            genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+          }
         }
         t = t->cdr;
@@ -801,6 +842,4 @@
       }
       else {
-        codegen(s, t->car->cdr, NOVAL);
-        t = t->cdr;
         while (t) {
           codegen(s, t->car, NOVAL);
@@ -818,18 +857,27 @@
 }
 
-#define CALL_MAXARGS 127
-
 static void
-gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val)
+gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
 {
   mrb_sym sym = name ? name : sym(tree->cdr->car);
-  int idx;
+  int idx, skip = 0;
   int n = 0, noop = 0, sendv = 0, blk = 0;
 
   codegen(s, tree->car, VAL); /* receiver */
+  if (safe) {
+    int recv = cursp()-1;
+    genop(s, MKOP_A(OP_LOADNIL, cursp()));
+    push();
+    genop(s, MKOP_AB(OP_MOVE, cursp(), recv));
+    push(); pop();              /* space for a block */
+    pop();
+    idx = new_msym(s, mrb_intern_lit(s->mrb, "=="));
+    genop(s, MKOP_ABC(OP_EQ, cursp(), idx, 1));
+    skip = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
+  }
   idx = new_msym(s, sym);
   tree = tree->cdr->cdr->car;
   if (tree) {
-    n = gen_values(s, tree->car, VAL);
+    n = gen_values(s, tree->car, VAL, sp?1:0);
     if (n < 0) {
       n = noop = sendv = 1;
@@ -863,29 +911,29 @@
     const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen);
 
-    if (!noop && symlen == 1 && symname[0] == '+')  {
+    if (!noop && symlen == 1 && symname[0] == '+' && n == 1)  {
       genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val);
     }
-    else if (!noop && symlen == 1 && symname[0] == '-')  {
+    else if (!noop && symlen == 1 && symname[0] == '-' && n == 1)  {
       genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val);
     }
-    else if (!noop && symlen == 1 && symname[0] == '*')  {
+    else if (!noop && symlen == 1 && symname[0] == '*' && n == 1)  {
       genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n));
     }
-    else if (!noop && symlen == 1 && symname[0] == '/')  {
+    else if (!noop && symlen == 1 && symname[0] == '/' && n == 1)  {
       genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n));
     }
-    else if (!noop && symlen == 1 && symname[0] == '<')  {
+    else if (!noop && symlen == 1 && symname[0] == '<' && n == 1)  {
       genop(s, MKOP_ABC(OP_LT, cursp(), idx, n));
     }
-    else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=')  {
+    else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1)  {
       genop(s, MKOP_ABC(OP_LE, cursp(), idx, n));
     }
-    else if (!noop && symlen == 1 && symname[0] == '>')  {
+    else if (!noop && symlen == 1 && symname[0] == '>' && n == 1)  {
       genop(s, MKOP_ABC(OP_GT, cursp(), idx, n));
     }
-    else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=')  {
+    else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1)  {
       genop(s, MKOP_ABC(OP_GE, cursp(), idx, n));
     }
-    else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=')  {
+    else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1)  {
       genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n));
     }
@@ -900,4 +948,7 @@
     }
   }
+  if (safe) {
+    dispatch(s, skip);
+  }
   if (val) {
     push();
@@ -912,5 +963,5 @@
 
   tree = tree->cdr;
-  switch ((intptr_t)type) {
+  switch (type) {
   case NODE_GVAR:
     idx = new_sym(s, sym(tree));
@@ -962,6 +1013,8 @@
 
   case NODE_CALL:
+  case NODE_SCALL:
     push();
-    gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL);
+    gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL,
+             type == NODE_SCALL);
     pop();
     if (val) {
@@ -980,5 +1033,5 @@
   default:
 #ifndef MRB_DISABLE_STDIO
-    printf("unknown lhs %d\n", type);
+    fprintf(stderr, "unknown lhs %d\n", type);
 #endif
     break;
@@ -1033,5 +1086,7 @@
       }
     }
-    push();
+    if (!val) {
+      push();
+    }
   }
 }
@@ -1176,10 +1231,37 @@
 
 static void
+gen_retval(codegen_scope *s, node *tree)
+{
+  if ((intptr_t)tree->car == NODE_SPLAT) {
+    genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), 0));
+    push();
+    codegen(s, tree, VAL);
+    pop(); pop();
+    genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
+  }
+  else {
+    codegen(s, tree, VAL);
+    pop();
+  }
+}
+
+static void
 codegen(codegen_scope *s, node *tree, int val)
 {
   int nt;
-
-  if (!tree) return;
-
+  int rlev = s->rlev;
+
+  if (!tree) {
+    if (val) {
+      genop(s, MKOP_A(OP_LOADNIL, cursp()));
+      push();
+    }
+    return;
+  }
+
+  s->rlev++;
+  if (s->rlev > MRB_CODEGEN_LEVEL_MAX) {
+    codegen_error(s, "too complex expression");
+  }
   if (s->irep && s->filename_index != tree->filename_index) {
     s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
@@ -1210,11 +1292,10 @@
       struct loopinfo *lp;
 
+      if (tree->car == NULL) goto exit;
       onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
       lp = loop_push(s, LOOP_BEGIN);
       lp->pc1 = onerr;
-      if (tree->car) {
-        codegen(s, tree->car, val);
-        if (val) pop();
-      }
+      codegen(s, tree->car, VAL);
+      pop();
       lp->type = LOOP_RESCUE;
       noexc = genop(s, MKOP_Bx(OP_JMP, 0));
@@ -1227,5 +1308,5 @@
         int exc = cursp();
 
-        genop(s, MKOP_A(OP_RESCUE, exc));
+        genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0));
         push();
         while (n2) {
@@ -1236,18 +1317,20 @@
           pos2 = 0;
           do {
-            if (n4) {
+            if (n4 && n4->car && (intptr_t)n4->car->car == NODE_SPLAT) {
               codegen(s, n4->car, VAL);
-            }
-            else {
-              genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError"))));
-              push();
-            }
-            genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
-            pop();
-            if (n4 && n4->car && (intptr_t)n4->car->car == NODE_SPLAT) {
+              genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
+              pop();
               genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
             }
             else {
-              genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "===")), 1));
+              if (n4) {
+                codegen(s, n4->car, VAL);
+              }
+              else {
+                genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError"))));
+                push();
+              }
+              pop();
+              genop(s, MKOP_ABC(OP_RESCUE, exc, cursp(), 1));
             }
             tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
@@ -1294,5 +1377,7 @@
 
   case NODE_ENSURE:
-    {
+    if (!tree->cdr || !tree->cdr->cdr ||
+        ((intptr_t)tree->cdr->cdr->car == NODE_BEGIN &&
+         tree->cdr->cdr->cdr)) {
       int idx;
       int epush = s->pc;
@@ -1306,8 +1391,11 @@
       genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL);
     }
+    else {                      /* empty ensure ignored */
+      codegen(s, tree->car, val);
+    }
     break;
 
   case NODE_LAMBDA:
-    {
+    if (val) {
       int idx = lambda_body(s, tree, 1);
 
@@ -1318,5 +1406,5 @@
 
   case NODE_BLOCK:
-    {
+    if (val) {
       int idx = lambda_body(s, tree, 1);
 
@@ -1331,4 +1419,8 @@
       node *e = tree->cdr->cdr->car;
 
+      if (!tree->car) {
+        codegen(s, e, val);
+        goto exit;
+      }
       switch ((intptr_t)tree->car->car) {
       case NODE_TRUE:
@@ -1336,9 +1428,9 @@
       case NODE_STR:
         codegen(s, tree->cdr->car, val);
-        return;
+        goto exit;
       case NODE_FALSE:
       case NODE_NIL:
         codegen(s, e, val);
-        return;
+        goto exit;
       }
       codegen(s, tree->car, VAL);
@@ -1347,8 +1439,4 @@
 
       codegen(s, tree->cdr->car, val);
-      if (val && !(tree->cdr->car)) {
-        genop(s, MKOP_A(OP_LOADNIL, cursp()));
-        push();
-      }
       if (e) {
         if (val) pop();
@@ -1485,5 +1573,7 @@
         if (pos3) dispatch_linked(s, pos3);
         if (head) pop();
-        genop(s, MKOP_AB(OP_MOVE, cursp(), pos));
+        if (cursp() != pos) {
+          genop(s, MKOP_AB(OP_MOVE, cursp(), pos));
+        }
         push();
       }
@@ -1505,5 +1595,8 @@
   case NODE_FCALL:
   case NODE_CALL:
-    gen_call(s, tree, 0, 0, val);
+    gen_call(s, tree, 0, 0, val, 0);
+    break;
+  case NODE_SCALL:
+    gen_call(s, tree, 0, 0, val, 1);
     break;
 
@@ -1553,5 +1646,5 @@
       int n;
 
-      n = gen_values(s, tree, val);
+      n = gen_values(s, tree, val, 0);
       if (n >= 0) {
         if (val) {
@@ -1602,5 +1695,5 @@
 
   case NODE_SPLAT:
-    codegen(s, tree, VAL);
+    codegen(s, tree, val);
     break;
 
@@ -1617,5 +1710,5 @@
       int rhs = cursp();
 
-      if ((intptr_t)t->car == NODE_ARRAY && nosplat(t->cdr)) {
+      if ((intptr_t)t->car == NODE_ARRAY && t->cdr && nosplat(t->cdr)) {
         /* fixed rhs */
         t = t->cdr;
@@ -1630,6 +1723,12 @@
           n = 0;
           while (t) {
-            gen_assignment(s, t->car, rhs+n, NOVAL);
-            n++;
+            if (n < len) {
+              gen_assignment(s, t->car, rhs+n, NOVAL);
+              n++;
+            }
+            else {
+              genop(s, MKOP_A(OP_LOADNIL, rhs+n));
+              gen_assignment(s, t->car, rhs+n, NOVAL);
+            }
             t = t->cdr;
           }
@@ -1688,7 +1787,70 @@
       mrb_int len;
       const char *name = mrb_sym2name_len(s->mrb, sym, &len);
-      int idx;
-
-      codegen(s, tree->car, VAL);
+      int idx, callargs = -1, vsp = -1;
+
+      if ((len == 2 && name[0] == '|' && name[1] == '|') &&
+          ((intptr_t)tree->car->car == NODE_CONST ||
+           (intptr_t)tree->car->car == NODE_CVAR)) {
+        int onerr, noexc, exc;
+        struct loopinfo *lp;
+
+        onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
+        lp = loop_push(s, LOOP_BEGIN);
+        lp->pc1 = onerr;
+        exc = cursp();
+        codegen(s, tree->car, VAL);
+        lp->type = LOOP_RESCUE;
+        genop(s, MKOP_A(OP_POPERR, 1));
+        noexc = genop(s, MKOP_Bx(OP_JMP, 0));
+        dispatch(s, onerr);
+        genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0));
+        genop(s, MKOP_A(OP_LOADF, exc));
+        dispatch(s, noexc);
+        loop_pop(s, NOVAL);
+      }
+      else if ((intptr_t)tree->car->car == NODE_CALL) {
+        node *n = tree->car->cdr;
+
+        if (val) {
+          vsp = cursp();
+          push();
+        }
+        codegen(s, n->car, VAL);   /* receiver */
+        idx = new_msym(s, sym(n->cdr->car));
+        if (n->cdr->cdr->car) {
+          int base = cursp()-1;
+          int nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1);
+
+          /* copy receiver and arguments */
+          if (nargs >= 0) {
+            int i;
+
+            genop(s, MKOP_AB(OP_MOVE, cursp(), base));
+            for (i=0; i<nargs; i++) {
+              genop(s, MKOP_AB(OP_MOVE, cursp()+i+1, base+i+1));
+            }
+            push_n(nargs+1);
+            pop_n(nargs+1);
+            callargs = nargs;
+          }
+          else {
+            /* varargs */
+            push();
+            genop(s, MKOP_AB(OP_MOVE, cursp(), base));
+            genop(s, MKOP_AB(OP_MOVE, cursp()+1, base+1));
+            callargs = CALL_MAXARGS;
+          }
+          genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
+        }
+        else {
+          genop(s, MKOP_AB(OP_MOVE, cursp(), cursp()-1));
+          genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 0));
+          callargs = 0;
+        }
+        push();
+      }
+      else {
+        codegen(s, tree->car, VAL);
+      }
       if (len == 2 &&
           ((name[0] == '|' && name[1] == '|') ||
@@ -1697,10 +1859,39 @@
 
         pop();
-        pos = genop_peep(s, MKOP_AsBx(name[0] == '|' ? OP_JMPIF : OP_JMPNOT, cursp(), 0), NOVAL);
+        if (val) {
+          if (vsp >= 0) {
+            genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
+          }
+          pos = genop(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0));
+        }
+        else {
+          pos = genop_peep(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0), NOVAL);
+        }
         codegen(s, tree->cdr->cdr->car, VAL);
         pop();
-        gen_assignment(s, tree->car, cursp(), val);
+        if (val && vsp >= 0) {
+          genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
+        }
+        if ((intptr_t)tree->car->car == NODE_CALL) {
+          mrb_sym m = sym(tree->car->cdr->cdr->car);
+          mrb_sym m2 = attrsym(s, m);
+
+          idx = new_msym(s, m2);
+          pop();
+          if (callargs == CALL_MAXARGS) {
+            genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+            pop();
+            genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
+          }
+          else {
+            pop_n(callargs);
+            genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs+1));
+          }
+        }
+        else {
+          gen_assignment(s, tree->car, cursp(), val);
+        }
         dispatch(s, pos);
-        break;
+        goto exit;
       }
       codegen(s, tree->cdr->cdr->car, VAL);
@@ -1736,17 +1927,45 @@
         genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1));
       }
-    }
-    gen_assignment(s, tree->car, cursp(), val);
+      if (callargs < 0) {
+        gen_assignment(s, tree->car, cursp(), val);
+      }
+      else {
+        if (val && vsp >= 0) {
+          genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
+        }
+        if (callargs == CALL_MAXARGS) {
+          pop();
+          genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+        }
+        else {
+          pop_n(callargs);
+          callargs++;
+        }
+        pop();
+        idx = new_msym(s, attrsym(s,sym(tree->car->cdr->cdr->car)));
+        genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
+      }
+    }
     break;
 
   case NODE_SUPER:
     {
+      codegen_scope *s2 = s;
+      int lv = 0;
       int n = 0, noop = 0, sendv = 0;
 
       push();        /* room for receiver */
+      while (!s2->mscope) {
+        lv++;
+        s2 = s2->prev;
+        if (!s2) break;
+      }
+      genop(s, MKOP_ABx(OP_ARGARY, cursp(), (lv & 0xf)));
+      push(); push();         /* ARGARY pushes two values */
+      pop(); pop();
       if (tree) {
         node *args = tree->car;
         if (args) {
-          n = gen_values(s, args, VAL);
+          n = gen_values(s, args, VAL, 0);
           if (n < 0) {
             n = noop = sendv = 1;
@@ -1796,6 +2015,5 @@
   case NODE_RETURN:
     if (tree) {
-      codegen(s, tree, VAL);
-      pop();
+      gen_retval(s, tree);
     }
     else {
@@ -1823,8 +2041,7 @@
       }
       if (s2) ainfo = s2->ainfo;
-      genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)));
       push();
       if (tree) {
-        n = gen_values(s, tree, VAL);
+        n = gen_values(s, tree, VAL, 0);
         if (n < 0) {
           n = sendv = 1;
@@ -1833,4 +2050,5 @@
       }
       pop_n(n+1);
+      genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)));
       if (sendv) n = CALL_MAXARGS;
       genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "call")), n));
@@ -1869,5 +2087,5 @@
 
   case NODE_REDO:
-    if (!s->loop) {
+    if (!s->loop || s->loop->type == LOOP_BEGIN || s->loop->type == LOOP_RESCUE) {
       raise_error(s, "unexpected redo");
     }
@@ -1878,4 +2096,5 @@
       genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc));
     }
+    if (val) push();
     break;
 
@@ -1912,4 +2131,5 @@
         }
       }
+      if (val) push();
     }
     break;
@@ -1984,25 +2204,23 @@
   case NODE_BACK_REF:
     if (val) {
-      char buf[2] = { '$' };
+      char buf[3];
+      int sym;
+
+      buf[0] = '$';
+      buf[1] = (char)(intptr_t)tree;
+      buf[2] = 0;
+      sym = new_sym(s, mrb_intern_cstr(s->mrb, buf));
+      genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
+      push();
+    }
+    break;
+
+  case NODE_NTH_REF:
+    if (val) {
+      mrb_state *mrb = s->mrb;
       mrb_value str;
       int sym;
 
-      buf[1] = (char)(intptr_t)tree;
-      str = mrb_str_new(s->mrb, buf, 2);
-      sym = new_sym(s, mrb_intern_str(s->mrb, str));
-      genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
-      push();
-    }
-    break;
-
-  case NODE_NTH_REF:
-    if (val) {
-      int sym;
-      mrb_state *mrb = s->mrb;
-      mrb_value fix = mrb_fixnum_value((intptr_t)tree);
-      mrb_value str = mrb_str_buf_new(mrb, 4);
-
-      mrb_str_cat_lit(mrb, str, "$");
-      mrb_str_cat_str(mrb, str, mrb_fixnum_to_str(mrb, fix, 10));
+      str = mrb_format(mrb, "$%S", mrb_fixnum_value((mrb_int)(intptr_t)tree));
       sym = new_sym(s, mrb_intern_str(mrb, str));
       genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
@@ -2051,5 +2269,5 @@
     if (val) {
       char *p = (char*)tree;
-      mrb_float f = str_to_mrb_float(p);
+      mrb_float f = mrb_float_read(p, NULL);
       int off = new_lit(s, mrb_float_value(s->mrb, f));
 
@@ -2065,7 +2283,7 @@
       switch (nt) {
       case NODE_FLOAT:
-        {
+        if (val) {
           char *p = (char*)tree;
-          mrb_float f = str_to_mrb_float(p);
+          mrb_float f = mrb_float_read(p, NULL);
           int off = new_lit(s, mrb_float_value(s->mrb, -f));
 
@@ -2076,5 +2294,5 @@
 
       case NODE_INT:
-        {
+        if (val) {
           char *p = (char*)tree->car;
           int base = (intptr_t)tree->cdr->car;
@@ -2105,5 +2323,5 @@
 
       default:
-        {
+        if (val) {
           int sym = new_msym(s, mrb_intern_lit(s->mrb, "-"));
 
@@ -2113,4 +2331,7 @@
           pop(); pop();
           genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2));
+        }
+        else {
+          codegen(s, tree, NOVAL);
         }
         break;
@@ -2139,5 +2360,9 @@
       node *n = tree;
 
-      if (!n) break;
+      if (!n) {
+        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+        push();
+        break;
+      }
       codegen(s, n->car, VAL);
       n = n->cdr;
@@ -2176,7 +2401,5 @@
       int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
 
-      if (val == NOVAL) { push(); }
-      genop(s, MKOP_A(OP_OCLASS, cursp()));
-      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      genop(s, MKOP_A(OP_LOADSELF, cursp()));
       push();
       codegen(s, tree->car, VAL);
@@ -2193,10 +2416,9 @@
         n = n->cdr;
       }
-      pop();
-      pop();
+      push();                   /* for block */
+      pop_n(3);
       sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
       genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
-      if (val == NOVAL) { pop(); }
-      else { push(); }
+      if (val) push();
       mrb_gc_arena_restore(s->mrb, ai);
     }
@@ -2208,17 +2430,15 @@
       size_t len = (intptr_t)tree->cdr;
       int ai = mrb_gc_arena_save(s->mrb);
-      int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
       int off = new_lit(s, mrb_str_new(s->mrb, p, len));
-
-      if (val == NOVAL) { push(); }
-      genop(s, MKOP_A(OP_OCLASS, cursp()));
-      genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+      int sym;
+
+      genop(s, MKOP_A(OP_LOADSELF, cursp()));
       push();
       genop(s, MKOP_ABx(OP_STRING, cursp(), off));
-      pop();
+      push(); push();
+      pop_n(3);
       sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
       genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
-      if (val == NOVAL) { pop(); }
-      else { push(); }
+      if (val) push();
       mrb_gc_arena_restore(s->mrb, ai);
     }
@@ -2244,5 +2464,6 @@
           off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
           genop(s, MKOP_ABx(OP_STRING, cursp(), off));
-        } else {
+        }
+        else {
           genop(s, MKOP_A(OP_LOADNIL, cursp()));
         }
@@ -2295,6 +2516,6 @@
         genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
       }
-      if (n->cdr) {
-        char *p2 = (char*)n->cdr;
+      if (n->cdr->car) {
+        char *p2 = (char*)n->cdr->car;
 
         push();
@@ -2302,7 +2523,14 @@
         genop(s, MKOP_ABx(OP_STRING, cursp(), off));
         argc++;
-        pop();
-      }
-      pop();
+      }
+      if (n->cdr->cdr) {
+        char *p2 = (char*)n->cdr->cdr;
+
+        push();
+        off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
+        genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+        argc++;
+      }
+      pop_n(argc);
       sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
       genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
@@ -2379,5 +2607,6 @@
       push();
       genop(s, MKOP_A(OP_LOADNIL, cursp()));
-      pop_n(3);
+      push();
+      pop_n(4);
       genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2));
       if (val) {
@@ -2396,5 +2625,20 @@
       push();
       while (t) {
-        int symbol = new_msym(s, sym(t->car));
+        int symbol;
+        if (num >= CALL_MAXARGS - 1) {
+          pop_n(num);
+          genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), num));
+          while (t) {
+            symbol = new_msym(s, sym(t->car));
+            push();
+            genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
+            pop();
+            genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+            t = t->cdr;
+          }
+          num = CALL_MAXARGS;
+          break;
+        }
+        symbol = new_msym(s, sym(t->car));
         genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
         push();
@@ -2402,5 +2646,8 @@
         num++;
       }
-      pop_n(num + 1);
+      pop();
+      if (num < CALL_MAXARGS) {
+        pop_n(num);
+      }
       genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num));
       if (val) {
@@ -2529,4 +2776,6 @@
     break;
   }
+ exit:
+  s->rlev = rlev;
 }
 
@@ -2570,5 +2819,5 @@
   p->icapa = 1024;
   p->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*p->icapa);
-  p->irep->iseq = p->iseq;
+  p->irep->iseq = NULL;
 
   p->pcapa = 32;
@@ -2576,5 +2825,5 @@
   p->irep->plen = 0;
 
-  p->scapa = 256;
+  p->scapa = MAXMSYMLEN;
   p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa);
   p->irep->slen = 0;
@@ -2620,4 +2869,6 @@
   p->filename_index = prev->filename_index;
 
+  p->rlev = prev->rlev+1;
+
   return p;
 }
@@ -2646,6 +2897,6 @@
   irep->reps = (mrb_irep**)codegen_realloc(s, irep->reps, sizeof(mrb_irep*)*irep->rlen);
   if (s->filename) {
-    s->irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
-    mrb_debug_info_append_file(mrb, s->irep, s->debug_start_pos, s->pc);
+    irep->filename = mrb_parser_get_filename(s->parser, s->filename_index);
+    mrb_debug_info_append_file(mrb, irep, s->debug_start_pos, s->pc);
 
     fname_len = strlen(s->filename);
@@ -2654,4 +2905,5 @@
     fname[fname_len] = '\0';
     irep->filename = fname;
+    irep->own_filename = TRUE;
   }
 
@@ -2689,6 +2941,5 @@
 
     if (tree) {
-      codegen(s, tree, VAL);
-      pop();
+      gen_retval(s, tree);
     }
 
@@ -2702,5 +2953,6 @@
     }
     if (!loop) {
-      codegen_error(s, "unexpected break");
+      raise_error(s, "unexpected break");
+      return;
     }
 
@@ -2718,4 +2970,7 @@
     }
     else {
+      if (!tree) {
+        genop(s, MKOP_A(OP_LOADNIL, cursp()));
+      }
       genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK));
     }
@@ -2726,8 +2981,8 @@
 loop_pop(codegen_scope *s, int val)
 {
+  dispatch_linked(s, s->loop->pc3);
   if (val) {
     genop(s, MKOP_A(OP_LOADNIL, cursp()));
   }
-  dispatch_linked(s, s->loop->pc3);
   s->loop = s->loop->prev;
   if (val) push();
@@ -2739,4 +2994,5 @@
   codegen_scope *scope = scope_new(mrb, 0, 0);
   struct RProc *proc;
+  struct mrb_jmpbuf *prev_jmp = mrb->jmp;
 
   if (!scope) {
@@ -2749,4 +3005,5 @@
 
   MRB_TRY(&scope->jmp) {
+    mrb->jmp = &scope->jmp; 
     /* prepare irep */
     codegen(scope, p->tree, NOVAL);
@@ -2754,12 +3011,12 @@
     mrb_irep_decref(mrb, scope->irep);
     mrb_pool_close(scope->mpool);
+    proc->c = NULL;
+    mrb->jmp = prev_jmp;
     return proc;
   }
   MRB_CATCH(&scope->jmp) {
-    if (scope->filename == scope->irep->filename) {
-      scope->irep->filename = NULL;
-    }
     mrb_irep_decref(mrb, scope->irep);
     mrb_pool_close(scope->mpool);
+    mrb->jmp = prev_jmp;
     return NULL;
   }
