summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2018-08-28 22:13:52 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2018-08-28 22:13:52 +0900
commit93bab387a71841fabe31ae3e0301417da543cbf8 (patch)
tree591f23d1411380b090b6cedeeeda99a4151dae8d
parentfe77272c25f3b6d91506a51d0621275074542890 (diff)
parent471288f37d18e640f98029fabcdcb7ee16b95d93 (diff)
downloadmruby-93bab387a71841fabe31ae3e0301417da543cbf8.tar.gz
mruby-93bab387a71841fabe31ae3e0301417da543cbf8.zip
Merge branch 'mruby2-draft'
-rw-r--r--.gitignore1
-rw-r--r--doc/limitations.md22
-rw-r--r--doc/opcode.md127
-rw-r--r--include/mruby.h16
-rw-r--r--include/mruby/class.h3
-rw-r--r--include/mruby/compile.h2
-rw-r--r--include/mruby/hash.h37
-rw-r--r--include/mruby/irep.h11
-rw-r--r--include/mruby/opcode.h186
-rw-r--r--include/mruby/ops.h117
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c8
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c1494
-rw-r--r--mrbgems/mruby-compiler/core/node.h24
-rw-r--r--mrbgems/mruby-compiler/core/parse.y504
-rw-r--r--mrbgems/mruby-eval/src/eval.c112
-rw-r--r--mrbgems/mruby-method/src/method.c6
-rw-r--r--mrbgems/mruby-objectspace/src/mruby_objectspace.c2
-rw-r--r--mrbgems/mruby-proc-ext/src/proc.c22
-rw-r--r--mrbgems/mruby-string-ext/src/string.c4
-rw-r--r--mrblib/hash.rb5
-rw-r--r--src/class.c8
-rw-r--r--src/codedump.c790
-rw-r--r--src/hash.c119
-rw-r--r--src/kernel.c12
-rw-r--r--src/load.c6
-rw-r--r--src/proc.c10
-rw-r--r--src/vm.c1109
-rw-r--r--test/t/syntax.rb184
28 files changed, 2876 insertions, 2065 deletions
diff --git a/.gitignore b/.gitignore
index bccfaf218..9c34b5f29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@
.DS_Store
.ccmalloc
.svn
+.vscode
/.git
cscope.files
cscope.out
diff --git a/doc/limitations.md b/doc/limitations.md
index afcb7b56e..92858cb1f 100644
--- a/doc/limitations.md
+++ b/doc/limitations.md
@@ -205,3 +205,25 @@ trace (most recent call last):
[0] -e:1
-e:1: undefined method 'binding' (NoMethodError)
```
+
+## Keyword arguments
+
+mruby keyword arguments behave slightly different from CRuby 2.5
+to make the behavior simpler and less confusing. Maybe in the
+future, the simpler behavior will be adopted to CRuby as well.
+
+#### Ruby [ruby 2.5.1p57 (2018-03-29 revision 63029)]
+
+```
+$ ruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
+[[{"a"=>1}], {:b=>2}]
+```
+
+#### mruby []
+
+```
+$ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
+trace (most recent call last):
+ [0] -e:1
+-e:1: keyword argument hash with non symbol keys (ArgumentError)
+```
diff --git a/doc/opcode.md b/doc/opcode.md
new file mode 100644
index 000000000..fea0afafd
--- /dev/null
+++ b/doc/opcode.md
@@ -0,0 +1,127 @@
+# The new bytecode
+
+We will reimplement VM to use 8bit instruction code. By
+bytecode, we mean real byte code. The whole purpose is
+reducing the memory consumption of mruby VM.
+
+# Instructions
+
+Instructions are bytes. There can be 256 instructions. Currently we
+have 94 instructions. Instructions can take 0 to 3 operands.
+
+## operands
+
+The size of operands can be either 8bits, 16bits or 24bits.
+In the table.1 below, the second field describes the size (and
+sign) of operands.
+
+* B: 8bit
+* sB: signed 8bit
+* S: 16bit
+* sS: signed 16bit
+* W: 24bit
+
+First two byte operands may be extended to 16bit. When those byte
+operands are bigger than 256, the instruction will be prefixed by
+`OP_EXT1` (means 1st operand is 16bit) or `OP_EXT2` (means 2nd operand
+is 16bit) or `OP_EXT3` (means 1st and 2nd operands are 16bit).
+
+For instructions marked by `'`, `OP_EXT1` can be prefixed. For those
+with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed.
+
+## table.1 Instruction Table
+
+|Instruction Name |Operand type |Semantics
+|-----------------|-------------|-----------------
+|OP_NOP | - |
+|OP_MOVE" |BB |R(a) = R(b)
+|OP_LOADL" |BB |R(a) = Pool(b)
+|OP_LOADI" |BsB |R(a) = mrb_int(b)
+|OP_LOADI_0' |B |R(a) = 0
+|OP_LOADI_1' |B |R(a) = 1
+|OP_LOADI_2' |B |R(a) = 2
+|OP_LOADI_3' |B |R(a) = 3
+|OP_LOADSYM" |BB |R(a) = Syms(b)
+|OP_LOADNIL' |B |R(a) = nil
+|OP_LOADSELF' |B |R(a) = self
+|OP_LOADT' |B |R(a) = true
+|OP_LOADF' |B |R(a) = false
+|OP_GETGV" |BB |R(a) = getglobal(Syms(b))
+|OP_SETGV" |BB |setglobal(Syms(b), R(a))
+|OP_GETSV" |BB |R(a) = Special[b]
+|OP_SETSV" |BB |Special[b] = R(a)
+|OP_GETIV" |BB |R(a) = ivget(Syms(b))
+|OP_SETIV" |BB |ivset(Syms(b),R(a))
+|OP_GETCV" |BB |R(a) = cvget(Syms(b))
+|OP_SETCV" |BB |cvset(Syms(b),R(a))
+|OP_GETCONST" |BB |R(a) = constget(Syms(b))
+|OP_SETCONST" |BB |constset(Syms(b),R(a))
+|OP_GETMCNST" |BB |R(a) = R(a)::Syms(b)
+|OP_SETMCNST" |BB |R(a+1)::Syms(b) = R(a)
+|OP_GETUPVAR' |BBB |R(a) = uvget(b,c)
+|OP_SETUPVAR' |BBB |uvset(b,c,R(a))
+|OP_JMP |S |pc+=a
+|OP_JMPIF' |SB |if R(b) pc+=a
+|OP_JMPNOT' |SB |if !R(b) pc+=a
+|OP_ONERR |sS |rescue_push(pc+a)
+|OP_EXCEPT' |B |R(a) = exc
+|OP_RESCUE" |BB |R(b) = R(a).isa?(R(b))
+|OP_POPERR |B |a.times{rescue_pop()}
+|OP_RAISE' |B |raise(R(a))
+|OP_EPUSH' |B |ensure_push(SEQ[a])
+|OP_EPOP |B |A.times{ensure_pop().call}
+|OP_SENDV" |BB |R(a) = call(R(a),Syms(b),*R(a+1))
+|OP_SENDVB" |BB |R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2))
+|OP_SEND" |BBB |R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c))
+|OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1))
+|OP_CALL' |B |R(a) = self.call(frame.argc, frame.argv)
+|OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1))
+|OP_ARGARY' |BS |R(a) = argument array (16=5:1:5:1:4)
+|OP_ENTER |W |arg setup according to flags (23=5:5:1:5:5:1:1)
+|OP_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo
+|OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo
+|OP_RETURN' |B |return R(a) (normal)
+|OP_RETURN_BLK' |B |return R(a) (in-block return)
+|OP_BREAK' |B |break R(a)
+|OP_BLKPUSH' |BS |R(a) = block (16=5:1:5:1:4)
+|OP_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+)
+|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+)
+|OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-)
+|OP_SUBI" |BB |R(a) = R(a)-C (Syms[b]=:-)
+|OP_MUL" |BB |R(a) = R(a)*R(a+1) (Syms[b]=:*)
+|OP_DIV" |BB |R(a) = R(a)/R(a+1) (Syms[b]=:/)
+|OP_EQ" |BB |R(a) = R(a)==R(a+1) (Syms[b]=:==)
+|OP_LT" |BB |R(a) = R(a)<R(a+1) (Syms[b]=:<)
+|OP_LE" |BB |R(a) = R(a)<=R(a+1) (Syms[b]=:<=)
+|OP_GT" |BB |R(a) = R(a)>R(a+1) (Syms[b]=:>)
+|OP_GE" |BB |R(a) = R(a)>=R(a+1) (Syms[b]=:>=)
+|OP_ARRAY' |BB |R(a) = ary_new(R(a),R(a+1)..R(a+b))
+|OP_ARRAY2" |BB |R(a) = ary_new(R(b),R(b+1)..R(b+c))
+|OP_ARYCAT' |B |ary_cat(R(a),R(a+1))
+|OP_ARYPUSH' |B |ary_push(R(a),R(a+1))
+|OP_AREF' |BB |R(a) = R(a)[b]
+|OP_ASET' |BB |R(a)[b] = R(a+1)
+|OP_APOST' |BB |*R(a),R(A+1)..R(A+C) = R(a)[B..]
+|OP_STRING" |BB |R(a) = str_dup(Lit(b))
+|OP_STRCAT' |B |str_cat(R(a),R(a+1))
+|OP_HASH' |BB |R(a) = hash_new(R(a),R(a+1)..R(a+b))
+|OP_HASHADD' |BB |R(a) = hash_push(R(a),R(a+1)..R(a+b))
+|OP_LAMBDA" |BB |R(a) = lambda(SEQ[b],OP_L_LAMBDA)
+|OP_BLOCK" |BB |R(a) = lambda(SEQ[b],OP_L_BLOCK)
+|OP_METHOD" |BB |R(a) = lambda(SEQ[b],OP_L_METHOD)
+|OP_RANGE_INC' |B |R(a) = range_new(R(a),R(a+1),FALSE)
+|OP_RANGE_EXC' |B |R(a) = range_new(R(a),R(a+1),TRUE)
+|OP_OCLASS' |B |R(a) = ::Object
+|OP_CLASS" |BB |R(a) = newclass(R(a),Syms(b),R(a+1))
+|OP_MODULE" |BB |R(a) = newmodule(R(a),Syms(b))
+|OP_EXEC" |BB |R(a) = blockexec(R(a),SEQ[b])
+|OP_DEF" |BB |R(a).newmethod(Syms(b),R(a+1))
+|OP_ALIAS' |B |alias_method(R(a),R(a+1),R(a+2))
+|OP_UNDEF" |BB |undef_method(R(a),Syms(b))
+|OP_SCLASS' |B |R(a) = R(a).singleton_class
+|OP_TCLASS' |B |R(a) = target_class
+|OP_ERR' |B |raise(RuntimeError, Lit(Bx))
+|OP_EXT1 |- |make 1st operand 16bit
+|OP_EXT2 |- |make 2nd operand 16bit
+|OP_EXT3 |- |make 1st and 2nd operands 16bit
+|OP_STOP |- |stop VM
diff --git a/include/mruby.h b/include/mruby.h
index bc6d72330..872396899 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -93,7 +93,7 @@
*/
MRB_BEGIN_DECL
-typedef uint32_t mrb_code;
+typedef uint8_t mrb_code;
/**
* Required arguments signature type.
@@ -123,8 +123,8 @@ typedef struct {
mrb_sym mid;
struct RProc *proc;
mrb_value *stackent;
- int ridx;
- int epos;
+ uint16_t ridx;
+ uint16_t epos;
struct REnv *env;
mrb_code *pc; /* return address */
mrb_code *err; /* error position */
@@ -151,10 +151,10 @@ struct mrb_context {
mrb_callinfo *ci;
mrb_callinfo *cibase, *ciend;
- mrb_code **rescue; /* exception handler stack */
+ uint16_t *rescue; /* exception handler stack */
int rsize;
struct RProc **ensure; /* ensure handler stack */
- int esize, eidx;
+ uint8_t esize, eidx;
enum mrb_fiber_state status;
mrb_bool vmexec;
@@ -485,9 +485,10 @@ MRB_API void mrb_define_const(mrb_state*, struct RClass*, const char *name, mrb_
* }
* @param [mrb_state*] mrb_state* The mruby state reference.
* @param [struct RClass*] RClass* A class the method will be undefined from.
- * @param [const char*] constchar* The name of the method to be undefined.
+ * @param [const char] const char* The name of the method to be undefined.
*/
MRB_API void mrb_undef_method(mrb_state*, struct RClass*, const char*);
+MRB_API void mrb_undef_method_id(mrb_state*, struct RClass*, mrb_sym);
/**
* Undefine a class method.
@@ -1196,7 +1197,6 @@ typedef enum call_type {
CALL_TYPE_MAX
} call_type;
-MRB_API void mrb_define_alias(mrb_state *mrb, struct RClass *klass, const char *name1, const char *name2);
MRB_API const char *mrb_class_name(mrb_state *mrb, struct RClass* klass);
MRB_API void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val);
@@ -1234,7 +1234,7 @@ MRB_API mrb_value mrb_fiber_alive_p(mrb_state *mrb, mrb_value fib);
* @mrbgem mruby-fiber
*/
#define E_FIBER_ERROR (mrb_exc_get(mrb, "FiberError"))
-MRB_API void mrb_stack_extend(mrb_state*, int);
+MRB_API void mrb_stack_extend(mrb_state*, mrb_int);
/* memory pool implementation */
typedef struct mrb_pool mrb_pool;
diff --git a/include/mruby/class.h b/include/mruby/class.h
index dfe63999c..96a9f7f95 100644
--- a/include/mruby/class.h
+++ b/include/mruby/class.h
@@ -79,7 +79,8 @@ MRB_API struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb
MRB_API struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym);
MRB_API void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, mrb_method_t);
MRB_API void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec);
-MRB_API void mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b);
+MRB_API void mrb_alias_method(mrb_state*, struct RClass *c, mrb_sym a, mrb_sym b);
+MRB_API void mrb_define_alias(mrb_state*, struct RClass *c, const char* a, const char* b);
MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym);
MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym);
diff --git a/include/mruby/compile.h b/include/mruby/compile.h
index d7d029616..a85460415 100644
--- a/include/mruby/compile.h
+++ b/include/mruby/compile.h
@@ -33,6 +33,7 @@ typedef struct mrbc_context {
mrb_bool no_exec:1;
mrb_bool keep_lv:1;
mrb_bool no_optimize:1;
+ mrb_bool on_eval:1;
size_t parser_nerr;
} mrbc_context;
@@ -151,6 +152,7 @@ struct mrb_parser_state {
mrb_ast_node *tree;
mrb_bool no_optimize:1;
+ mrb_bool on_eval:1;
mrb_bool capture_errors:1;
struct mrb_parser_message error_buffer[10];
struct mrb_parser_message warn_buffer[10];
diff --git a/include/mruby/hash.h b/include/mruby/hash.h
index 1a870785a..2026c8e0d 100644
--- a/include/mruby/hash.h
+++ b/include/mruby/hash.h
@@ -25,6 +25,7 @@ struct RHash {
#define mrb_hash_value(p) mrb_obj_value((void*)(p))
MRB_API mrb_value mrb_hash_new_capa(mrb_state*, mrb_int);
+MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
/*
* Initializes a new hash.
@@ -110,7 +111,19 @@ MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value
* @return An array with the keys of the hash.
*/
MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash);
-MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
+/*
+ * Check if the hash has the key.
+ *
+ * Equivalent to:
+ *
+ * hash.key?(key)
+ *
+ * @param mrb The mruby state reference.
+ * @param hash The target hash.
+ * @param key The key to check existence.
+ * @return True if the hash has the key
+ */
+MRB_API mrb_bool mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key);
/*
* Check if the hash is empty
@@ -123,7 +136,7 @@ MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
* @param self The target hash.
* @return True if the hash is empty, false otherwise.
*/
-MRB_API mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self);
+MRB_API mrb_bool mrb_hash_empty_p(mrb_state *mrb, mrb_value self);
/*
* Gets an array of values.
@@ -151,6 +164,26 @@ MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash);
*/
MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash);
+/*
+ * Copies the hash.
+ *
+ *
+ * @param mrb The mruby state reference.
+ * @param hash The target hash.
+ * @return The copy of the hash
+ */
+MRB_API mrb_value mrb_hash_dup(mrb_state *mrb, mrb_value hash);
+
+/*
+ * Merges two hashes. The first hash will be modified by the
+ * second hash.
+ *
+ * @param mrb The mruby state reference.
+ * @param hash1 The target hash.
+ * @param hash2 Updating hash
+ */
+MRB_API void mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2);
+
/* declaration of struct kh_ht */
/* be careful when you touch the internal */
typedef struct {
diff --git a/include/mruby/irep.h b/include/mruby/irep.h
index ad227be5d..7dcf33735 100644
--- a/include/mruby/irep.h
+++ b/include/mruby/irep.h
@@ -44,7 +44,7 @@ typedef struct mrb_irep {
uint16_t *lines;
struct mrb_irep_debug_info* debug_info;
- int ilen, plen, slen, rlen, refcnt;
+ uint16_t ilen, plen, slen, rlen, refcnt;
} mrb_irep;
#define MRB_ISEQ_NO_FREE 1
@@ -58,6 +58,15 @@ void mrb_irep_decref(mrb_state*, struct mrb_irep*);
void mrb_irep_cutref(mrb_state*, struct mrb_irep*);
void mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep);
+struct mrb_insn_data {
+ uint8_t insn;
+ uint16_t a;
+ uint16_t b;
+ uint8_t c;
+};
+
+struct mrb_insn_data mrb_decode_insn(mrb_code *pc);
+
MRB_END_DECL
#endif /* MRUBY_IREP_H */
diff --git a/include/mruby/opcode.h b/include/mruby/opcode.h
index a5e3af158..d513ca472 100644
--- a/include/mruby/opcode.h
+++ b/include/mruby/opcode.h
@@ -7,145 +7,10 @@
#ifndef MRUBY_OPCODE_H
#define MRUBY_OPCODE_H
-#define MAXARG_Bx (0xffff)
-#define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */
-
-/* instructions: packed 32 bit */
-/* ------------------------------- */
-/* A:B:C:OP = 9: 9: 7: 7 */
-/* A:Bx:OP = 9:16: 7 */
-/* Ax:OP = 25: 7 */
-/* A:Bz:Cz:OP = 9:14: 2: 7 */
-
-#define GET_OPCODE(i) ((int)(((mrb_code)(i)) & 0x7f))
-#define GETARG_A(i) ((int)((((mrb_code)(i)) >> 23) & 0x1ff))
-#define GETARG_B(i) ((int)((((mrb_code)(i)) >> 14) & 0x1ff))
-#define GETARG_C(i) ((int)((((mrb_code)(i)) >> 7) & 0x7f))
-#define GETARG_Bx(i) ((int)((((mrb_code)(i)) >> 7) & 0xffff))
-#define GETARG_sBx(i) ((int)(GETARG_Bx(i)-MAXARG_sBx))
-#define GETARG_Ax(i) ((int32_t)((((mrb_code)(i)) >> 7) & 0x1ffffff))
-#define GETARG_UNPACK_b(i,n1,n2) ((int)((((mrb_code)(i)) >> (7+(n2))) & (((1<<(n1))-1))))
-#define GETARG_UNPACK_c(i,n1,n2) ((int)((((mrb_code)(i)) >> 7) & (((1<<(n2))-1))))
-#define GETARG_b(i) GETARG_UNPACK_b(i,14,2)
-#define GETARG_c(i) GETARG_UNPACK_c(i,14,2)
-
-#define MKOPCODE(op) ((op) & 0x7f)
-#define MKARG_A(c) ((mrb_code)((c) & 0x1ff) << 23)
-#define MKARG_B(c) ((mrb_code)((c) & 0x1ff) << 14)
-#define MKARG_C(c) (((c) & 0x7f) << 7)
-#define MKARG_Bx(v) ((mrb_code)((v) & 0xffff) << 7)
-#define MKARG_sBx(v) MKARG_Bx((v)+MAXARG_sBx)
-#define MKARG_Ax(v) ((mrb_code)((v) & 0x1ffffff) << 7)
-#define MKARG_PACK(b,n1,c,n2) ((((b) & ((1<<n1)-1)) << (7+n2))|(((c) & ((1<<n2)-1)) << 7))
-#define MKARG_bc(b,c) MKARG_PACK(b,14,c,2)
-
-#define MKOP_A(op,a) (MKOPCODE(op)|MKARG_A(a))
-#define MKOP_AB(op,a,b) (MKOP_A(op,a)|MKARG_B(b))
-#define MKOP_ABC(op,a,b,c) (MKOP_AB(op,a,b)|MKARG_C(c))
-#define MKOP_ABx(op,a,bx) (MKOP_A(op,a)|MKARG_Bx(bx))
-#define MKOP_Bx(op,bx) (MKOPCODE(op)|MKARG_Bx(bx))
-#define MKOP_sBx(op,sbx) (MKOPCODE(op)|MKARG_sBx(sbx))
-#define MKOP_AsBx(op,a,sbx) (MKOP_A(op,a)|MKARG_sBx(sbx))
-#define MKOP_Ax(op,ax) (MKOPCODE(op)|MKARG_Ax(ax))
-#define MKOP_Abc(op,a,b,c) (MKOP_A(op,a)|MKARG_bc(b,c))
-
-enum {
- /*-----------------------------------------------------------------------
- operation code operand description
- ------------------------------------------------------------------------*/
- OP_NOP=0,/* */
- OP_MOVE,/* A B R(A) := R(B) */
- OP_LOADL,/* A Bx R(A) := Pool(Bx) */
- OP_LOADI,/* A sBx R(A) := sBx */
- OP_LOADSYM,/* A Bx R(A) := Syms(Bx) */
- OP_LOADNIL,/* A R(A) := nil */
- OP_LOADSELF,/* A R(A) := self */
- OP_LOADT,/* A R(A) := true */
- OP_LOADF,/* A R(A) := false */
-
- OP_GETGLOBAL,/* A Bx R(A) := getglobal(Syms(Bx)) */
- OP_SETGLOBAL,/* A Bx setglobal(Syms(Bx), R(A)) */
- OP_GETSPECIAL,/*A Bx R(A) := Special[Bx] */
- OP_SETSPECIAL,/*A Bx Special[Bx] := R(A) */
- OP_GETIV,/* A Bx R(A) := ivget(Syms(Bx)) */
- OP_SETIV,/* A Bx ivset(Syms(Bx),R(A)) */
- OP_GETCV,/* A Bx R(A) := cvget(Syms(Bx)) */
- OP_SETCV,/* A Bx cvset(Syms(Bx),R(A)) */
- OP_GETCONST,/* A Bx R(A) := constget(Syms(Bx)) */
- OP_SETCONST,/* A Bx constset(Syms(Bx),R(A)) */
- OP_GETMCNST,/* A Bx R(A) := R(A)::Syms(Bx) */
- OP_SETMCNST,/* A Bx R(A+1)::Syms(Bx) := R(A) */
- OP_GETUPVAR,/* A B C R(A) := uvget(B,C) */
- OP_SETUPVAR,/* A B C uvset(B,C,R(A)) */
-
- OP_JMP,/* sBx pc+=sBx */
- OP_JMPIF,/* A sBx if R(A) pc+=sBx */
- OP_JMPNOT,/* A sBx if !R(A) pc+=sBx */
- OP_ONERR,/* sBx rescue_push(pc+sBx) */
- OP_RESCUE,/* A B C if A (if C exc=R(A) else R(A) := exc);
- if B R(B) := exc.isa?(R(B)); clear(exc) */
- OP_POPERR,/* A A.times{rescue_pop()} */
- OP_RAISE,/* A raise(R(A)) */
- OP_EPUSH,/* Bx ensure_push(SEQ[Bx]) */
- OP_EPOP,/* A A.times{ensure_pop().call} */
-
- OP_SEND,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */
- OP_SENDB,/* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/
- OP_FSEND,/* A B C R(A) := fcall(R(A),Syms(B),R(A+1),...,R(A+C-1)) */
- OP_CALL,/* A R(A) := self.call(frame.argc, frame.argv) */
- OP_SUPER,/* A C R(A) := super(R(A+1),... ,R(A+C+1)) */
- OP_ARGARY,/* A Bx R(A) := argument array (16=6:1:5:4) */
- OP_ENTER,/* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */
- OP_KARG,/* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */
- OP_KDICT,/* A C R(A) := kdict */
-
- OP_RETURN,/* A B return R(A) (B=normal,in-block return/break) */
- OP_TAILCALL,/* A B C return call(R(A),Syms(B),*R(C)) */
- OP_BLKPUSH,/* A Bx R(A) := block (16=6:1:5:4) */
-
- OP_ADD,/* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1) */
- OP_ADDI,/* A B C R(A) := R(A)+C (Syms[B]=:+) */
- OP_SUB,/* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1) */
- OP_SUBI,/* A B C R(A) := R(A)-C (Syms[B]=:-) */
- OP_MUL,/* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1) */
- OP_DIV,/* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1) */
- OP_EQ,/* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1) */
- OP_LT,/* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1) */
- OP_LE,/* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1) */
- OP_GT,/* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1) */
- OP_GE,/* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1) */
-
- OP_ARRAY,/* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
- OP_ARYCAT,/* A B ary_cat(R(A),R(B)) */
- OP_ARYPUSH,/* A B ary_push(R(A),R(B)) */
- OP_AREF,/* A B C R(A) := R(B)[C] */
- OP_ASET,/* A B C R(B)[C] := R(A) */
- OP_APOST,/* A B C *R(A),R(A+1)..R(A+C) := R(A)[B..] */
-
- OP_STRING,/* A Bx R(A) := str_dup(Lit(Bx)) */
- OP_STRCAT,/* A B str_cat(R(A),R(B)) */
-
- OP_HASH,/* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */
- OP_LAMBDA,/* A Bz Cz R(A) := lambda(SEQ[Bz],Cz) */
- OP_RANGE,/* A B C R(A) := range_new(R(B),R(B+1),C) */
-
- OP_OCLASS,/* A R(A) := ::Object */
- OP_CLASS,/* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */
- OP_MODULE,/* A B R(A) := newmodule(R(A),Syms(B)) */
- OP_EXEC,/* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */
- OP_METHOD,/* A B R(A).newmethod(Syms(B),R(A+1)) */
- OP_SCLASS,/* A B R(A) := R(B).singleton_class */
- OP_TCLASS,/* A R(A) := target_class */
-
- OP_DEBUG,/* A B C print R(A),R(B),R(C) */
- OP_STOP,/* stop VM */
- OP_ERR,/* Bx raise RuntimeError with message Lit(Bx) */
-
- OP_RSVD1,/* reserved instruction #1 */
- OP_RSVD2,/* reserved instruction #2 */
- OP_RSVD3,/* reserved instruction #3 */
- OP_RSVD4,/* reserved instruction #4 */
- OP_RSVD5,/* reserved instruction #5 */
+enum mrb_insn {
+#define OPCODE(x,_) OP_ ## x,
+#include "mruby/ops.h"
+#undef OPCODE
};
#define OP_L_STRICT 1
@@ -158,4 +23,47 @@ enum {
#define OP_R_BREAK 1
#define OP_R_RETURN 2
+#define PEEK_B(pc) (*(pc))
+#define PEEK_S(pc) ((pc)[0]<<8|(pc)[1])
+#define PEEK_W(pc) ((pc)[0]<<16|(pc)[1]<<8|(pc)[2])
+
+#define READ_B() PEEK_B(pc++)
+#define READ_S() (pc+=2, PEEK_S(pc-2))
+#define READ_W() (pc+=3, PEEK_W(pc-3))
+
+#define FETCH_Z() /* nothing */
+#define FETCH_B() do {a=READ_B();} while (0)
+#define FETCH_BB() do {a=READ_B(); b=READ_B();} while (0)
+#define FETCH_BBB() do {a=READ_B(); b=READ_B(); c=READ_B();} while (0)
+#define FETCH_BS() do {a=READ_B(); b=READ_S();} while (0)
+#define FETCH_S() do {a=READ_S();} while (0)
+#define FETCH_W() do {a=READ_W();} while (0)
+
+/* with OP_EXT1 (1st 16bit) */
+#define FETCH_Z_1() FETCH_Z()
+#define FETCH_B_1() FETCH_S()
+#define FETCH_BB_1() do {a=READ_S(); b=READ_B();} while (0)
+#define FETCH_BBB_1() do {a=READ_S(); b=READ_B(); c=READ_B();} while (0)
+#define FETCH_BS_1() do {a=READ_S(); b=READ_S();} while (0)
+#define FETCH_S_1() FETCH_S()
+#define FETCH_W_1() FETCH_W()
+
+/* with OP_EXT2 (2nd 16bit) */
+#define FETCH_Z_2() FETCH_Z()
+#define FETCH_B_2() FETCH_B()
+#define FETCH_BB_2() do {a=READ_B(); b=READ_S();} while (0)
+#define FETCH_BBB_2() do {a=READ_B(); b=READ_S(); c=READ_B();} while (0)
+#define FETCH_BS_2() FETCH_BS()
+#define FETCH_S_2() FETCH_S()
+#define FETCH_W_2() FETCH_W()
+
+/* with OP_EXT3 (1st & 2nd 16bit) */
+#define FETCH_Z_3() FETCH_Z()
+#define FETCH_B_3() FETCH_B()
+#define FETCH_BB_3() do {a=READ_S(); b=READ_S();} while (0)
+#define FETCH_BBB_3() do {a=READ_S(); b=READ_S(); c=READ_B();} while (0)
+#define FETCH_BS_3() do {a=READ_S(); b=READ_S();} while (0)
+#define FETCH_S_3() FETCH_S()
+#define FETCH_W_3() FETCH_W()
+
#endif /* MRUBY_OPCODE_H */
diff --git a/include/mruby/ops.h b/include/mruby/ops.h
new file mode 100644
index 000000000..f23bb1b0b
--- /dev/null
+++ b/include/mruby/ops.h
@@ -0,0 +1,117 @@
+/* operand types:
+ + Z: no operand (Z,Z,Z,Z)
+ + B: 8bit (B,S,B,B)
+ + BB: 8+8bit (BB,SB,BS,SS)
+ + BBB: 8+8+8bit (BBB,SBB,BSB,SSB)
+ + BS: 8+16bit (BS,SS,BS,BS)
+ + S: 16bit (S,S,S,S)
+ + W: 24bit (W,W,W,W)
+*/
+
+/*-----------------------------------------------------------------------
+operation code operands semantics
+------------------------------------------------------------------------*/
+OPCODE(NOP, Z) /* no operation */
+OPCODE(MOVE, BB) /* R(a) = R(b) */
+OPCODE(LOADL, BB) /* R(a) = Pool(b) */
+OPCODE(LOADI, BB) /* R(a) = mrb_int(b) */
+OPCODE(LOADINEG, BB) /* R(a) = mrb_int(-b) */
+OPCODE(LOADI__1, B) /* R(a) = mrb_int(-1) */
+OPCODE(LOADI_0, B) /* R(a) = mrb_int(0) */
+OPCODE(LOADI_1, B) /* R(a) = mrb_int(1) */
+OPCODE(LOADI_2, B) /* R(a) = mrb_int(2) */
+OPCODE(LOADI_3, B) /* R(a) = mrb_int(3) */
+OPCODE(LOADI_4, B) /* R(a) = mrb_int(4) */
+OPCODE(LOADI_5, B) /* R(a) = mrb_int(5) */
+OPCODE(LOADI_6, B) /* R(a) = mrb_int(6) */
+OPCODE(LOADI_7, B) /* R(a) = mrb_int(7) */
+OPCODE(LOADSYM, BB) /* R(a) = Syms(b) */
+OPCODE(LOADNIL, B) /* R(a) = nil */
+OPCODE(LOADSELF, B) /* R(a) = self */
+OPCODE(LOADT, B) /* R(a) = true */
+OPCODE(LOADF, B) /* R(a) = false */
+OPCODE(GETGV, BB) /* R(a) = getglobal(Syms(b)) */
+OPCODE(SETGV, BB) /* setglobal(Syms(b), R(a)) */
+OPCODE(GETSV, BB) /* R(a) = Special[Syms(b)] */
+OPCODE(SETSV, BB) /* Special[Syms(b)] = R(a) */
+OPCODE(GETIV, BB) /* R(a) = ivget(Syms(b)) */
+OPCODE(SETIV, BB) /* ivset(Syms(b),R(a)) */
+OPCODE(GETCV, BB) /* R(a) = cvget(Syms(b)) */
+OPCODE(SETCV, BB) /* cvset(Syms(b),R(a)) */
+OPCODE(GETCONST, BB) /* R(a) = constget(Syms(b)) */
+OPCODE(SETCONST, BB) /* constset(Syms(b),R(a)) */
+OPCODE(GETMCNST, BB) /* R(a) = R(a)::Syms(b) */
+OPCODE(SETMCNST, BB) /* R(a+1)::Syms(b) = R(a) */
+OPCODE(GETUPVAR, BBB) /* R(a) = uvget(b,c) */
+OPCODE(SETUPVAR, BBB) /* uvset(b,c,R(a)) */
+OPCODE(JMP, S) /* pc=a */
+OPCODE(JMPIF, BS) /* if R(b) pc=a */
+OPCODE(JMPNOT, BS) /* if !R(b) pc=a */
+OPCODE(JMPNIL, BS) /* if R(b)==nil pc=a */
+OPCODE(ONERR, S) /* rescue_push(a) */
+OPCODE(EXCEPT, B) /* R(a) = exc */
+OPCODE(RESCUE, BB) /* R(b) = R(a).isa?(R(b)) */
+OPCODE(POPERR, B) /* a.times{rescue_pop()} */
+OPCODE(RAISE, B) /* raise(R(a)) */
+OPCODE(EPUSH, B) /* ensure_push(SEQ[a]) */
+OPCODE(EPOP, B) /* A.times{ensure_pop().call} */
+OPCODE(SENDV, BB) /* R(a) = call(R(a),Syms(b),*R(a+1)) */
+OPCODE(SENDVB, BB) /* R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) */
+OPCODE(SEND, BBB) /* R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) */
+OPCODE(SENDB, BBB) /* R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) */
+OPCODE(CALL, Z) /* R(0) = self.call(frame.argc, frame.argv) */
+OPCODE(SUPER, BB) /* R(a) = super(R(a+1),... ,R(a+b+1)) */
+OPCODE(ARGARY, BS) /* R(a) = argument array (16=m5:r1:m5:d1:lv4) */
+OPCODE(ENTER, W) /* arg setup according to flags (23=m5:o5:r1:m5:k5:d1:b1) */
+OPCODE(KEY_P, BB) /* R(a) = kdict.key?(Syms(b)) # todo */
+OPCODE(KEYEND, Z) /* raise unless kdict.empty? # todo */
+OPCODE(KARG, BB) /* R(a) = kdict[Syms(b)]; kdict.delete(Syms(b)) # todo */
+OPCODE(RETURN, B) /* return R(a) (normal) */
+OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */
+OPCODE(BREAK, B) /* break R(a) */
+OPCODE(BLKPUSH, BS) /* R(a) = block (16=m5:r1:m5:d1:lv4) */
+OPCODE(ADD, BB) /* R(a) = R(a)+R(a+1) (Syms[b]=:+) */
+OPCODE(ADDI, BBB) /* R(a) = R(a)+mrb_int(c) (Syms[b]=:+) */
+OPCODE(SUB, BB) /* R(a) = R(a)-R(a+1) (Syms[b]=:-) */
+OPCODE(SUBI, BBB) /* R(a) = R(a)-C (Syms[b]=:-) */
+OPCODE(MUL, BB) /* R(a) = R(a)*R(a+1) (Syms[b]=:*) */
+OPCODE(DIV, BB) /* R(a) = R(a)/R(a+1) (Syms[b]=:/) */
+OPCODE(EQ, BB) /* R(a) = R(a)==R(a+1) (Syms[b]=:==) */
+OPCODE(LT, BB) /* R(a) = R(a)<R(a+1) (Syms[b]=:<) */
+OPCODE(LE, BB) /* R(a) = R(a)<=R(a+1) (Syms[b]=:<=) */
+OPCODE(GT, BB) /* R(a) = R(a)>R(a+1) (Syms[b]=:>) */
+OPCODE(GE, BB) /* R(a) = R(a)>=R(a+1) (Syms[b]=:>=) */
+OPCODE(ARRAY, BB) /* R(a) = ary_new(R(a),R(a+1)..R(a+b)) */
+OPCODE(ARRAY2, BBB) /* R(a) = ary_new(R(b),R(b+1)..R(b+c)) */
+OPCODE(ARYCAT, B) /* ary_cat(R(a),R(a+1)) */
+OPCODE(ARYPUSH, B) /* ary_push(R(a),R(a+1)) */
+OPCODE(ARYDUP, B) /* R(a) = ary_dup(R(a)) */
+OPCODE(AREF, BBB) /* R(a) = R(b)[c] */
+OPCODE(ASET, BBB) /* R(a)[c] = R(b) */
+OPCODE(APOST, BBB) /* *R(a),R(a+1)..R(a+C) = R(a)[b..] */
+OPCODE(INTERN, B) /* R(a) = intern(R(a)) */
+OPCODE(STRING, BB) /* R(a) = str_dup(Lit(b)) */
+OPCODE(STRCAT, B) /* str_cat(R(a),R(a+1)) */
+OPCODE(HASH, BB) /* R(a) = hash_new(R(a),R(a+1)..R(a+b)) */
+OPCODE(HASHADD, BB) /* R(a) = hash_push(R(a),R(a+1)..R(a+b)) */
+OPCODE(HASHCAT, B) /* R(a) = hash_cat(R(a),R(a+1)) */
+OPCODE(LAMBDA, BB) /* R(a) = lambda(SEQ[b],L_LAMBDA) */
+OPCODE(BLOCK, BB) /* R(a) = lambda(SEQ[b],L_BLOCK) */
+OPCODE(METHOD, BB) /* R(a) = lambda(SEQ[b],L_METHOD) */
+OPCODE(RANGE_INC, B) /* R(a) = range_new(R(a),R(a+1),FALSE) */
+OPCODE(RANGE_EXC, B) /* R(a) = range_new(R(a),R(a+1),TRUE) */
+OPCODE(OCLASS, B) /* R(a) = ::Object */
+OPCODE(CLASS, BB) /* R(a) = newclass(R(a),Syms(b),R(a+1)) */
+OPCODE(MODULE, BB) /* R(a) = newmodule(R(a),Syms(b)) */
+OPCODE(EXEC, BB) /* R(a) = blockexec(R(a),SEQ[b]) */
+OPCODE(DEF, BB) /* R(a).newmethod(Syms(b),R(a+1)) */
+OPCODE(ALIAS, BB) /* alias_method(target_class,Syms(a),Syms(b)) */
+OPCODE(UNDEF, B) /* undef_method(target_class,Syms(a)) */
+OPCODE(SCLASS, B) /* R(a) = R(a).singleton_class */
+OPCODE(TCLASS, B) /* R(a) = target_class */
+OPCODE(DEBUG, BBB) /* print a,b,c */
+OPCODE(ERR, B) /* raise(LocalJumpError, Lit(a)) */
+OPCODE(EXT1, Z) /* make 1st operand 16bit */
+OPCODE(EXT2, Z) /* make 2nd operand 16bit */
+OPCODE(EXT3, Z) /* make 1st and 2nd operands 16bit */
+OPCODE(STOP, Z) /* stop VM */
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c
index 0588dfca5..05a6f3622 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/mrdb.c
@@ -510,6 +510,7 @@ check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value
mrb_sym sym;
int32_t bpno;
mrb_bool isCfunc;
+ struct mrb_insn_data insn;
mrb_debug_context *dbg = mrb_debug_context_get(mrb);
@@ -517,11 +518,12 @@ check_method_breakpoint(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value
bpno = dbg->method_bpno;
dbg->method_bpno = 0;
- switch(GET_OPCODE(*pc)) {
+ insn = mrb_decode_insn(pc);
+ switch(insn.insn) {
case OP_SEND:
case OP_SENDB:
- c = mrb_class(mrb, regs[GETARG_A(*pc)]);
- sym = irep->syms[GETARG_B(*pc)];
+ c = mrb_class(mrb, regs[insn.a]);
+ sym = irep->syms[insn.b];
break;
case OP_SUPER:
c = mrb->c->ci->target_class->super;
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index 945ddcc1a..a835a563e 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -23,6 +23,8 @@
#define MRB_CODEGEN_LEVEL_MAX 1024
#endif
+#define MAXARG_S (1<<16)
+
typedef mrb_ast_node node;
typedef struct mrb_parser_state parser_state;
@@ -36,7 +38,7 @@ enum looptype {
struct loopinfo {
enum looptype type;
- int pc1, pc2, pc3, acc;
+ int pc0, pc1, pc2, pc3, acc;
int ensure_level;
struct loopinfo *prev;
};
@@ -50,9 +52,10 @@ typedef struct scope {
node *lv;
- int sp;
- int pc;
- int lastlabel;
+ uint16_t sp;
+ uint16_t pc;
+ uint16_t lastpc;
+ uint16_t lastlabel;
int ainfo:15;
mrb_bool mscope:1;
@@ -63,10 +66,10 @@ typedef struct scope {
mrb_code *iseq;
uint16_t *lines;
- int icapa;
+ uint32_t icapa;
mrb_irep *irep;
- int pcapa, scapa, rcapa;
+ uint32_t pcapa, scapa, rcapa;
uint16_t nlocals;
uint16_t nregs;
@@ -142,38 +145,141 @@ codegen_realloc(codegen_scope *s, void *p, size_t len)
static int
new_label(codegen_scope *s)
{
- s->lastlabel = s->pc;
- return s->pc;
+ return s->lastlabel = s->pc;
}
-static inline int
-genop(codegen_scope *s, mrb_code i)
+static void
+emit_B(codegen_scope *s, uint32_t pc, uint8_t i)
{
- if (s->pc >= s->icapa) {
+ if (pc >= s->icapa) {
s->icapa *= 2;
- if (s->pc >= MAXARG_sBx) {
+ if (pc >= MAXARG_S) {
codegen_error(s, "too big code block");
}
- if (s->icapa > MAXARG_sBx) {
- s->icapa = MAXARG_sBx;
+ if (s->icapa > MAXARG_S) {
+ s->icapa = MAXARG_S;
}
s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa);
if (s->lines) {
- s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa);
+ s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(uint16_t)*s->icapa);
s->irep->lines = s->lines;
}
}
- s->iseq[s->pc] = i;
if (s->lines) {
- s->lines[s->pc] = s->lineno;
+ s->lines[pc] = s->lineno;
}
- return s->pc++;
+ s->iseq[pc] = i;
+}
+
+static void
+emit_S(codegen_scope *s, int pc, uint16_t i)
+{
+ uint8_t hi = i>>8;
+ uint8_t lo = i&0xff;
+
+ emit_B(s, pc, hi);
+ emit_B(s, pc+1, lo);
+}
+
+static void
+gen_B(codegen_scope *s, uint8_t i)
+{
+ emit_B(s, s->pc++, i);
+}
+
+static void
+gen_S(codegen_scope *s, uint16_t i)
+{
+ emit_S(s, s->pc, i);
+ s->pc += 2;
+}
+
+static void
+genop_0(codegen_scope *s, mrb_code i)
+{
+ s->lastpc = s->pc;
+ gen_B(s, i);
+}
+
+static void
+genop_1(codegen_scope *s, mrb_code i, uint16_t a)
+{
+ s->lastpc = s->pc;
+ if (a > 0xff) {
+ gen_B(s, OP_EXT1);
+ gen_B(s, i);
+ gen_S(s, a);
+ }
+ else {
+ gen_B(s, i);
+ gen_B(s, (uint8_t)a);
+ }
+}
+
+static void
+genop_2(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b)
+{
+ s->lastpc = s->pc;
+ if (a > 0xff && b > 0xff) {
+ gen_B(s, OP_EXT3);
+ gen_B(s, i);
+ gen_S(s, a);
+ gen_S(s, b);
+ }
+ else if (b > 0xff) {
+ gen_B(s, OP_EXT2);
+ gen_B(s, i);
+ gen_B(s, (uint8_t)a);
+ gen_S(s, b);
+ }
+ else if (a > 0xff) {
+ gen_B(s, OP_EXT1);
+ gen_B(s, i);
+ gen_S(s, a);
+ gen_B(s, (uint8_t)b);
+ }
+ else {
+ gen_B(s, i);
+ gen_B(s, (uint8_t)a);
+ gen_B(s, (uint8_t)b);
+ }
+}
+
+static void
+genop_3(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b, uint8_t c)
+{
+ s->lastpc = s->pc;
+ genop_2(s, i, a, b);
+ gen_B(s, c);
+}
+
+static void
+genop_2S(codegen_scope *s, mrb_code i, uint16_t a, uint16_t b)
+{
+ s->lastpc = s->pc;
+ genop_1(s, i, a);
+ gen_S(s, b);
+}
+
+static void
+genop_W(codegen_scope *s, mrb_code i, uint32_t a)
+{
+ uint8_t a1 = (a>>16) & 0xff;
+ uint8_t a2 = (a>>8) & 0xff;
+ uint8_t a3 = a & 0xff;
+
+ s->lastpc = s->pc;
+ gen_B(s, i);
+ gen_B(s, a1);
+ gen_B(s, a2);
+ gen_B(s, a3);
}
#define NOVAL 0
#define VAL 1
-static mrb_bool
+//static
+mrb_bool
no_optimize(codegen_scope *s)
{
if (s && s->parser && s->parser->no_optimize)
@@ -181,298 +287,270 @@ no_optimize(codegen_scope *s)
return FALSE;
}
-static int
-genop_peep(codegen_scope *s, mrb_code i, int val)
+static
+mrb_bool
+on_eval(codegen_scope *s)
{
- /* peephole optimization */
- if (!no_optimize(s) && s->lastlabel != s->pc && s->pc > 0) {
- mrb_code i0 = s->iseq[s->pc-1];
- int c1 = GET_OPCODE(i);
- int c0 = GET_OPCODE(i0);
+ if (s && s->parser && s->parser->on_eval)
+ return TRUE;
+ return FALSE;
+}
- switch (c1) {
- case OP_MOVE:
- if (GETARG_A(i) == GETARG_B(i)) {
- /* skip useless OP_MOVE */
- return 0;
- }
- if (val) break;
- switch (c0) {
- case OP_MOVE:
- if (GETARG_A(i) == GETARG_A(i0)) {
- /* skip overridden OP_MOVE */
- s->pc--;
- s->iseq[s->pc] = i;
- }
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i) == GETARG_B(i0)) {
- /* skip swapping OP_MOVE */
- return 0;
- }
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->pc--;
- return genop_peep(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_B(i0)), val);
- }
- break;
- case OP_LOADI:
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_AsBx(OP_LOADI, GETARG_A(i), GETARG_sBx(i0));
- return 0;
- }
- break;
- case OP_ARRAY:
- case OP_HASH:
- case OP_RANGE:
- case OP_AREF:
- case OP_GETUPVAR:
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_ABC(c0, GETARG_A(i), GETARG_B(i0), GETARG_C(i0));
- return 0;
- }
- break;
- case OP_LOADSYM:
- case OP_GETGLOBAL:
- case OP_GETIV:
- case OP_GETCV:
- case OP_GETCONST:
- case OP_GETSPECIAL:
- case OP_LOADL:
- case OP_STRING:
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_ABx(c0, GETARG_A(i), GETARG_Bx(i0));
- return 0;
- }
- break;
- case OP_SCLASS:
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_AB(c0, GETARG_A(i), GETARG_B(i0));
- return 0;
- }
- break;
- case OP_LOADNIL:
- case OP_LOADSELF:
- case OP_LOADT:
- case OP_LOADF:
- case OP_OCLASS:
- if (GETARG_B(i) == GETARG_A(i0) && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_A(c0, GETARG_A(i));
- return 0;
- }
- break;
- default:
- break;
- }
- break;
- case OP_SETIV:
- case OP_SETCV:
- case OP_SETCONST:
- case OP_SETMCNST:
- case OP_SETGLOBAL:
- if (val) break;
- if (c0 == OP_MOVE) {
- if (GETARG_A(i) == GETARG_A(i0)) {
- s->iseq[s->pc-1] = MKOP_ABx(c1, GETARG_B(i0), GETARG_Bx(i));
- return 0;
- }
- }
- break;
- case OP_SETUPVAR:
- if (val) break;
- if (c0 == OP_MOVE) {
- if (GETARG_A(i) == GETARG_A(i0)) {
- s->iseq[s->pc-1] = MKOP_ABC(c1, GETARG_B(i0), GETARG_B(i), GETARG_C(i));
- return 0;
- }
- }
- break;
- case OP_GETUPVAR:
- if (c0 == OP_SETUPVAR) {
- if (GETARG_B(i) == GETARG_B(i0) && GETARG_C(i) == GETARG_C(i0)) {
- if (GETARG_A(i) == GETARG_A(i0)) {
- /* just skip OP_SETUPVAR */
- return 0;
- }
- else {
- return genop(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_A(i0)));
- }
- }
- }
- break;
- case OP_EPOP:
- if (c0 == OP_EPOP) {
- s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i));
- return 0;
- }
- break;
- case OP_POPERR:
- if (c0 == OP_POPERR) {
- s->iseq[s->pc-1] = MKOP_A(OP_POPERR, GETARG_A(i0)+GETARG_A(i));
- return 0;
- }
- break;
- case OP_RETURN:
- switch (c0) {
- case OP_RETURN:
- return 0;
- case OP_MOVE:
- if (GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_AB(OP_RETURN, GETARG_B(i0), OP_R_NORMAL);
- return 0;
- }
- break;
- case OP_SETIV:
- case OP_SETCV:
- case OP_SETCONST:
- case OP_SETMCNST:
- case OP_SETUPVAR:
- case OP_SETGLOBAL:
- s->pc--;
- genop_peep(s, i0, NOVAL);
- i0 = s->iseq[s->pc-1];
- return genop(s, MKOP_AB(OP_RETURN, GETARG_A(i0), OP_R_NORMAL));
-#if 0
- case OP_SEND:
- if (GETARG_B(i) == OP_R_NORMAL && GETARG_A(i) == GETARG_A(i0)) {
- s->iseq[s->pc-1] = MKOP_ABC(OP_TAILCALL, GETARG_A(i0), GETARG_B(i0), GETARG_C(i0));
- return;
- }
- break;
-#endif
- default:
- break;
- }
- break;
- case OP_ADD:
- case OP_SUB:
- if (c0 == OP_LOADI) {
- int c = GETARG_sBx(i0);
-
- if (c1 == OP_SUB) c = -c;
- if (c > 127 || c < -127) break;
- if (0 <= c)
- s->iseq[s->pc-1] = MKOP_ABC(OP_ADDI, GETARG_A(i), GETARG_B(i), c);
- else
- s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c);
- return 0;
- }
- break;
- case OP_ARYCAT:
- case OP_ARYPUSH:
- if (c0 == OP_MOVE && GETARG_A(i0) >= s->nlocals) {
- s->iseq[s->pc-1] = MKOP_AB(c1, GETARG_A(i), GETARG_B(i0));
- return 0;
- }
- break;
- case OP_STRCAT:
- if (c0 == OP_STRING) {
- mrb_value v = s->irep->pool[GETARG_Bx(i0)];
+struct mrb_insn_data
+mrb_decode_insn(mrb_code *pc)
+{
+ struct mrb_insn_data data = { 0 };
+ mrb_code insn = READ_B();
+ uint16_t a = 0;
+ uint16_t b = 0;
+ uint8_t c = 0;
+
+ switch (insn) {
+#define FETCH_Z() /* empty */
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ switch (insn) {
+ case OP_EXT1:
+ insn = READ_B();
+ switch (insn) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ break;
+ case OP_EXT2:
+ insn = READ_B();
+ switch (insn) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ break;
+ case OP_EXT3:
+ insn = READ_B();
+ switch (insn) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); break;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ break;
+ default:
+ break;
+ }
+ data.insn = insn;
+ data.a = a;
+ data.b = b;
+ data.c = c;
+ return data;
+}
- if (mrb_string_p(v) && RSTRING_LEN(v) == 0) {
- s->pc--;
- return 0;
- }
- }
- if (c0 == OP_LOADNIL) {
- if (GETARG_B(i) == GETARG_A(i0)) {
- s->pc--;
- return 0;
- }
- }
+static struct mrb_insn_data
+mrb_last_insn(codegen_scope *s)
+{
+ if (s->pc == s->lastpc) {
+ struct mrb_insn_data data;
+
+ data.insn = OP_NOP;
+ return data;
+ }
+ return mrb_decode_insn(&s->iseq[s->lastpc]);
+}
+
+static mrb_bool
+no_peephole(codegen_scope *s)
+{
+ return no_optimize(s) || s->lastlabel == s->pc || s->pc == 0 || s->pc == s->lastpc;
+}
+
+static uint16_t
+genjmp(codegen_scope *s, mrb_code i, uint16_t pc)
+{
+ uint16_t pos;
+
+ s->lastpc = s->pc;
+ gen_B(s, i);
+ pos = s->pc;
+ gen_S(s, pc);
+ return pos;
+}
+
+static uint16_t
+genjmp2(codegen_scope *s, mrb_code i, uint16_t a, int pc, int val)
+{
+ uint16_t pos;
+
+ if (!no_peephole(s) && !val) {
+ struct mrb_insn_data data = mrb_last_insn(s);
+
+ if (data.insn == OP_MOVE && data.a == a) {
+ s->pc = s->lastpc;
+ a = data.b;
+ }
+ }
+
+ s->lastpc = s->pc;
+ if (a > 0xff) {
+ gen_B(s, OP_EXT1);
+ gen_B(s, i);
+ gen_S(s, a);
+ pos = s->pc;
+ gen_S(s, pc);
+ }
+ else {
+ gen_B(s, i);
+ gen_B(s, (uint8_t)a);
+ pos = s->pc;
+ gen_S(s, pc);
+ }
+ return pos;
+}
+
+static void
+gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
+{
+ if (no_peephole(s)) {
+ normal:
+ genop_2(s, OP_MOVE, dst, src);
+ if (on_eval(s)) {
+ genop_0(s, OP_NOP);
+ }
+ return;
+ }
+ else {
+ struct mrb_insn_data data = mrb_last_insn(s);
+
+ switch (data.insn) {
+ case OP_MOVE:
+ if (dst == src) return; /* remove useless MOVE */
+ if (data.b == dst && data.a == src) /* skip swapping MOVE */
+ return;
+ goto normal;
+ case OP_LOADNIL: case OP_LOADSELF: case OP_LOADT: case OP_LOADF:
+ case OP_LOADI__1:
+ case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3:
+ case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7:
+ if (nopeep || data.a != src || data.a < s->nlocals) goto normal;
+ s->pc = s->lastpc;
+ genop_1(s, data.insn, dst);
break;
- case OP_JMPIF:
- case OP_JMPNOT:
- if (c0 == OP_MOVE && GETARG_A(i) == GETARG_A(i0)) {
- s->iseq[s->pc-1] = MKOP_AsBx(c1, GETARG_B(i0), GETARG_sBx(i));
- return s->pc-1;
- }
+ case OP_LOADI: case OP_LOADINEG: case OP_LOADL: case OP_LOADSYM:
+ case OP_GETGV: case OP_GETSV: case OP_GETIV: case OP_GETCV:
+ case OP_GETCONST: case OP_STRING:
+ case OP_LAMBDA: case OP_BLOCK: case OP_METHOD: case OP_BLKPUSH:
+ if (nopeep || data.a != src || data.a < s->nlocals) goto normal;
+ s->pc = s->lastpc;
+ genop_2(s, data.insn, dst, data.b);
break;
default:
- break;
+ goto normal;
}
}
- return genop(s, i);
}
static void
-scope_error(codegen_scope *s)
+gen_return(codegen_scope *s, uint8_t op, uint16_t src)
{
- exit(EXIT_FAILURE);
+ if (no_peephole(s)) {
+ genop_1(s, op, src);
+ }
+ else {
+ struct mrb_insn_data data = mrb_last_insn(s);
+
+ if (data.insn == OP_MOVE && src == data.a) {
+ s->pc = s->lastpc;
+ genop_1(s, op, data.b);
+ }
+ else {
+ genop_1(s, op, src);
+ }
+ }
}
static void
-distcheck(codegen_scope *s, int diff)
+gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx)
{
- if (diff > MAXARG_sBx || diff < -MAXARG_sBx) {
- codegen_error(s, "too distant jump address");
+ if (no_peephole(s)) {
+ normal:
+ genop_2(s, op, dst, idx);
+ return;
+ }
+ else {
+ struct mrb_insn_data data = mrb_last_insn(s);
+
+ switch (data.insn) {
+ case OP_LOADI__1:
+ if (op == OP_ADD) op = OP_SUB;
+ else op = OP_ADD;
+ data.b = 1;
+ goto replace;
+ case OP_LOADI_0: case OP_LOADI_1: case OP_LOADI_2: case OP_LOADI_3:
+ case OP_LOADI_4: case OP_LOADI_5: case OP_LOADI_6: case OP_LOADI_7:
+ data.b = data.insn - OP_LOADI_0;
+ /* fall through */
+ case OP_LOADI:
+ replace:
+ if (data.b >= 128) goto normal;
+ s->pc = s->lastpc;
+ if (op == OP_ADD) {
+ genop_3(s, OP_ADDI, dst, idx, (uint8_t)data.b);
+ }
+ else {
+ genop_3(s, OP_SUBI, dst, idx, (uint8_t)data.b);
+ }
+ break;
+ default:
+ goto normal;
+ }
}
}
-static inline void
-dispatch(codegen_scope *s, int pc)
+static int
+dispatch(codegen_scope *s, uint16_t pos0)
{
- int diff = s->pc - pc;
- mrb_code i = s->iseq[pc];
- int c = GET_OPCODE(i);
+ uint16_t newpos;
s->lastlabel = s->pc;
- switch (c) {
- case OP_JMP:
- case OP_JMPIF:
- case OP_JMPNOT:
- case OP_ONERR:
- break;
- default:
-#ifndef MRB_DISABLE_STDIO
- fprintf(stderr, "bug: dispatch on non JMP op\n");
-#endif
- scope_error(s);
- break;
- }
- distcheck(s, diff);
- s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff);
+ newpos = PEEK_S(s->iseq+pos0);
+ emit_S(s, pos0, s->pc);
+ return newpos;
}
static void
-dispatch_linked(codegen_scope *s, int pc)
+dispatch_linked(codegen_scope *s, uint16_t pos)
{
- mrb_code i;
- int pos;
-
- if (!pc) return;
+ if (pos==0) return;
for (;;) {
- i = s->iseq[pc];
- pos = GETARG_sBx(i);
- dispatch(s, pc);
- if (!pos) break;
- pc = pos;
+ pos = dispatch(s, pos);
+ if (pos==0) break;
}
}
#define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0)
static void
-push_(codegen_scope *s)
+push_n_(codegen_scope *s, int n)
{
- if (s->sp > 511) {
+ if (s->sp+n >= 0xffff) {
codegen_error(s, "too complex expression");
}
- s->sp++;
+ s->sp+=n;
nregs_update;
}
static void
-push_n_(codegen_scope *s, int n)
+pop_n_(codegen_scope *s, int n)
{
- if (s->sp+n > 511) {
- codegen_error(s, "too complex expression");
+ if ((int)s->sp-n < 0) {
+ codegen_error(s, "stack pointer underflow");
}
- s->sp+=n;
- nregs_update;
+ s->sp-=n;
}
-#define push() push_(s)
+#define push() push_n_(s,1)
#define push_n(n) push_n_(s,n)
-#define pop_(s) ((s)->sp--)
-#define pop() pop_(s)
-#define pop_n(n) (s->sp-=(n))
+#define pop() pop_n_(s,1)
+#define pop_n(n) pop_n_(s,n)
#define cursp() (s->sp)
static inline int
@@ -545,52 +623,23 @@ new_lit(codegen_scope *s, mrb_value val)
return i;
}
-/* method symbols should be fit in 9 bits */
-#define MAXMSYMLEN 512
/* maximum symbol numbers */
-#define MAXSYMLEN 65536
+#define MAXSYMLEN 0x10000
static int
-new_msym(codegen_scope *s, mrb_sym sym)
+new_sym(codegen_scope *s, mrb_sym sym)
{
int i, len;
mrb_assert(s->irep);
len = s->irep->slen;
- 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 == MAXMSYMLEN) {
- codegen_error(s, "too many symbols (max " MRB_STRINGIZE(MAXMSYMLEN) ")");
- }
- s->irep->syms[i] = sym;
- if (i == s->irep->slen) s->irep->slen++;
- return i;
-}
-
-static int
-new_sym(codegen_scope *s, mrb_sym sym)
-{
- int i;
-
- for (i=0; i<s->irep->slen; i++) {
- if (s->irep->syms[i] == sym) return 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] = mrb_sym_zero;
- }
- s->irep->slen = MAXMSYMLEN;
+ if (s->irep->slen >= s->scapa) {
+ s->scapa *= 2;
+ s->irep->syms = (mrb_sym*)codegen_realloc(s, s->irep->syms, sizeof(mrb_sym)*s->scapa);
}
s->irep->syms[s->irep->slen] = sym;
return s->irep->slen++;
@@ -608,8 +657,12 @@ node_len(node *tree)
return n;
}
+#define nint(x) ((int)(intptr_t)(x))
+#define nchar(x) ((char)(intptr_t)(x))
#define nsym(x) ((mrb_sym)(intptr_t)(x))
+
#define lv_name(lv) nsym((lv)->car)
+
static int
lv_idx(codegen_scope *s, mrb_sym id)
{
@@ -631,7 +684,6 @@ for_body(codegen_scope *s, node *tree)
int idx;
struct loopinfo *lp;
node *n2;
- mrb_code c;
/* generate receiver */
codegen(s, tree->cdr->car, VAL);
@@ -645,7 +697,7 @@ for_body(codegen_scope *s, node *tree)
/* generate loop variable */
n2 = tree->car;
- genop(s, MKOP_Ax(OP_ENTER, 0x40000));
+ genop_W(s, OP_ENTER, 0x40000);
if (n2->car && !n2->car->cdr && !n2->cdr) {
gen_assignment(s, n2->car->car, 1, NOVAL);
}
@@ -659,25 +711,20 @@ for_body(codegen_scope *s, node *tree)
/* loop body */
codegen(s, tree->cdr->cdr->car, VAL);
pop();
- if (s->pc > 0) {
- c = s->iseq[s->pc-1];
- if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel)
- genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
- }
+ gen_return(s, OP_RETURN, cursp());
loop_pop(s, NOVAL);
scope_finish(s);
s = prev;
- genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK));
+ genop_2(s, OP_BLOCK, cursp(), s->irep->rlen-1);
push();pop(); /* space for a block */
pop();
- idx = new_msym(s, mrb_intern_lit(s->mrb, "each"));
- genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0));
+ idx = new_sym(s, mrb_intern_lit(s->mrb, "each"));
+ genop_3(s, OP_SENDB, cursp(), idx, 0);
}
static int
lambda_body(codegen_scope *s, node *tree, int blk)
{
- mrb_code c;
codegen_scope *parent = s;
s = scope_new(s->mrb, s, tree->car);
if (s == NULL) {
@@ -688,7 +735,7 @@ lambda_body(codegen_scope *s, node *tree, int blk)
if (blk) {
struct loopinfo *lp = loop_push(s, LOOP_BLOCK);
- lp->pc1 = new_label(s);
+ lp->pc0 = new_label(s);
}
tree = tree->cdr;
if (tree->car) {
@@ -696,70 +743,112 @@ lambda_body(codegen_scope *s, node *tree, int blk)
int ma, oa, ra, pa, ka, kd, ba;
int pos, i;
node *n, *opt;
+ node *tail;
+ /* mandatory arguments */
ma = node_len(tree->car->car);
n = tree->car->car;
while (n) {
n = n->cdr;
}
+ tail = tree->car->cdr->cdr->cdr->cdr;
+
+ /* optional arguments */
oa = node_len(tree->car->cdr->car);
+ /* rest argument? */
ra = tree->car->cdr->cdr->car ? 1 : 0;
+ /* mandatory arugments after rest argument */
pa = node_len(tree->car->cdr->cdr->cdr->car);
- ka = kd = 0;
- ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0;
-
+ /* keyword arguments */
+ ka = tail? node_len(tail->cdr->car) : 0;
+ /* keyword dictionary? */
+ kd = tail && tail->cdr->cdr->car? 1 : 0;
+ /* block argument? */
+ ba = tail && tail->cdr->cdr->cdr->car ? 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)
- | ((ra & 1) << 12)
- | ((pa & 0x1f) << 7)
- | ((ka & 0x1f) << 2)
- | ((kd & 1)<< 1)
- | (ba & 1);
- s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */
- | ((ra & 1) << 5)
- | (pa & 0x1f);
- genop(s, MKOP_Ax(OP_ENTER, a));
+ a = MRB_ARGS_REQ(ma)
+ | MRB_ARGS_OPT(oa)
+ | (ra? MRB_ARGS_REST() : 0)
+ | MRB_ARGS_POST(pa)
+ | MRB_ARGS_KEY(ka, kd)
+ | (ba? MRB_ARGS_BLOCK() : 0);
+ s->ainfo = (((ma+oa) & 0x3f) << 7) /* (12bits = 5:1:5:1) */
+ | ((ra & 0x1) << 6)
+ | ((pa & 0x1f) << 1)
+ | (kd & 0x1);
+ genop_W(s, OP_ENTER, a);
+ /* generate jump table for optional arguments initializer */
pos = new_label(s);
for (i=0; i<oa; i++) {
new_label(s);
- genop(s, MKOP_sBx(OP_JMP, 0));
+ genjmp(s, OP_JMP, 0);
}
if (oa > 0) {
- genop(s, MKOP_sBx(OP_JMP, 0));
+ genjmp(s, OP_JMP, 0);
}
opt = tree->car->cdr->car;
i = 0;
while (opt) {
int idx;
- dispatch(s, pos+i);
+ dispatch(s, pos+i*3+1);
codegen(s, opt->car->cdr, VAL);
- idx = lv_idx(s, nsym(opt->car->car));
pop();
- genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL);
+ idx = lv_idx(s, nsym(opt->car->car));
+ gen_move(s, idx, cursp(), 0);
i++;
opt = opt->cdr;
}
if (oa > 0) {
- dispatch(s, pos+i);
+ dispatch(s, pos+i*3+1);
+ }
+
+ if (tail) {
+ node *kwds = tail->cdr->car;
+ int kwrest = 0;
+
+ if (tail->cdr->cdr->car) {
+ kwrest = 1;
+ }
+ mrb_assert(nint(tail->car) == NODE_ARGS_TAIL);
+ mrb_assert(node_len(tail) == 4);
+
+ while (kwds) {
+ int jmpif_key_p, jmp_def_set = -1;
+ node *kwd = kwds->car, *def_arg = kwd->cdr->cdr->car;
+ mrb_sym kwd_sym = nsym(kwd->cdr->car);
+
+ mrb_assert(nint(kwd->car) == NODE_KW_ARG);
+
+ if (def_arg) {
+ genop_2(s, OP_KEY_P, cursp(), new_sym(s, kwd_sym));
+ jmpif_key_p = genjmp2(s, OP_JMPIF, cursp(), 0, 0);
+ codegen(s, def_arg, VAL);
+ pop();
+ gen_move(s, lv_idx(s, kwd_sym), cursp(), 0);
+ jmp_def_set = genjmp(s, OP_JMP, 0);
+ dispatch(s, jmpif_key_p);
+ }
+ genop_2(s, OP_KARG, lv_idx(s, kwd_sym), new_sym(s, kwd_sym));
+ if (jmp_def_set != -1) {
+ dispatch(s, jmp_def_set);
+ }
+ i++;
+
+ kwds = kwds->cdr;
+ }
+ if (tail->cdr->car && !kwrest) {
+ genop_0(s, OP_KEYEND);
+ }
}
}
codegen(s, tree->cdr->car, VAL);
pop();
if (s->pc > 0) {
- c = s->iseq[s->pc-1];
- if (GET_OPCODE(c) != OP_RETURN || GETARG_B(c) != OP_R_NORMAL || s->pc == s->lastlabel) {
- if (s->nregs == 0) {
- genop(s, MKOP_A(OP_LOADNIL, 0));
- genop(s, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
- }
- else {
- genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
- }
- }
+ gen_return(s, OP_RETURN, cursp());
}
if (blk) {
loop_pop(s, NOVAL);
@@ -773,24 +862,13 @@ scope_body(codegen_scope *s, node *tree, int val)
{
codegen_scope *scope = scope_new(s->mrb, s, tree->car);
if (scope == NULL) {
- raise_error(s, "unexpected scope");
+ codegen_error(s, "unexpected scope");
}
codegen(scope, tree->cdr, VAL);
+ gen_return(scope, OP_RETURN, scope->sp-1);
if (!s->iseq) {
- genop(scope, MKOP_A(OP_STOP, 0));
- }
- else if (!val) {
- genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
- }
- else {
- if (scope->nregs == 0) {
- genop(scope, MKOP_A(OP_LOADNIL, 0));
- genop(scope, MKOP_AB(OP_RETURN, 0, OP_R_NORMAL));
- }
- else {
- genop_peep(scope, MKOP_AB(OP_RETURN, scope->sp-1, OP_R_NORMAL), NOVAL);
- }
+ genop_0(scope, OP_STOP);
}
scope_finish(scope);
if (!s->irep) {
@@ -800,9 +878,6 @@ scope_body(codegen_scope *s, node *tree, int val)
return s->irep->rlen - 1;
}
-#define nint(x) ((int)(intptr_t)(x))
-#define nchar(x) ((char)(intptr_t)(x))
-
static mrb_bool
nosplat(node *t)
{
@@ -854,15 +929,15 @@ gen_values(codegen_scope *s, node *t, int val, int extra)
}
else {
pop_n(n);
- genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
+ genop_2(s, OP_ARRAY, cursp(), n);
push();
codegen(s, t->car, VAL);
pop(); pop();
if (is_splat) {
- genop_peep(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1), NOVAL);
+ genop_1(s, OP_ARYCAT, cursp());
}
else {
- genop_peep(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1), NOVAL);
+ genop_1(s, OP_ARYPUSH, cursp());
}
}
t = t->cdr;
@@ -871,10 +946,10 @@ gen_values(codegen_scope *s, node *t, int val, int extra)
codegen(s, t->car, VAL);
pop(); pop();
if (nint(t->car->car) == NODE_SPLAT) {
- genop_peep(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1), NOVAL);
+ genop_1(s, OP_ARYCAT, cursp());
}
else {
- genop_peep(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1), NOVAL);
+ genop_1(s, OP_ARYPUSH, cursp());
}
t = t->cdr;
}
@@ -905,16 +980,10 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
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_n(2); pop_n(2); /* space for one arg and 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));
+ gen_move(s, cursp(), recv, 0);
+ skip = genjmp2(s, OP_JMPNIL, cursp(), 0, val);
}
- idx = new_msym(s, sym);
+ idx = new_sym(s, sym);
tree = tree->cdr->cdr->car;
if (tree) {
n = gen_values(s, tree->car, VAL, sp?1:0);
@@ -923,14 +992,15 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
push();
}
}
- if (sp) {
+ if (sp) { /* last argument pushed (attr=) */
if (sendv) {
+ gen_move(s, cursp(), sp, 0);
pop();
- genop(s, MKOP_AB(OP_ARYPUSH, cursp(), sp));
+ genop_1(s, OP_ARYPUSH, cursp());
push();
}
else {
- genop(s, MKOP_AB(OP_MOVE, cursp(), sp));
+ gen_move(s, cursp(), sp, 0);
push();
n++;
}
@@ -939,9 +1009,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
noop = 1;
codegen(s, tree->cdr, VAL);
pop();
- }
- else {
- blk = cursp();
+ blk = 1;
}
push();pop();
pop_n(n+1);
@@ -950,39 +1018,38 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen);
if (!noop && symlen == 1 && symname[0] == '+' && n == 1) {
- genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, n), val);
+ gen_addsub(s, OP_ADD, cursp(), idx);
}
else if (!noop && symlen == 1 && symname[0] == '-' && n == 1) {
- genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, n), val);
+ gen_addsub(s, OP_SUB, cursp(), idx);
}
else if (!noop && symlen == 1 && symname[0] == '*' && n == 1) {
- genop(s, MKOP_ABC(OP_MUL, cursp(), idx, n));
+ genop_2(s, OP_MUL, cursp(), idx);
}
else if (!noop && symlen == 1 && symname[0] == '/' && n == 1) {
- genop(s, MKOP_ABC(OP_DIV, cursp(), idx, n));
+ genop_2(s, OP_DIV, cursp(), idx);
}
else if (!noop && symlen == 1 && symname[0] == '<' && n == 1) {
- genop(s, MKOP_ABC(OP_LT, cursp(), idx, n));
+ genop_2(s, OP_LT, cursp(), idx);
}
else if (!noop && symlen == 2 && symname[0] == '<' && symname[1] == '=' && n == 1) {
- genop(s, MKOP_ABC(OP_LE, cursp(), idx, n));
+ genop_2(s, OP_LE, cursp(), idx);
}
else if (!noop && symlen == 1 && symname[0] == '>' && n == 1) {
- genop(s, MKOP_ABC(OP_GT, cursp(), idx, n));
+ genop_2(s, OP_GT, cursp(), idx);
}
else if (!noop && symlen == 2 && symname[0] == '>' && symname[1] == '=' && n == 1) {
- genop(s, MKOP_ABC(OP_GE, cursp(), idx, n));
+ genop_2(s, OP_GE, cursp(), idx);
}
else if (!noop && symlen == 2 && symname[0] == '=' && symname[1] == '=' && n == 1) {
- genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n));
+ genop_2(s, OP_EQ, cursp(), idx);
}
else {
- if (sendv) n = CALL_MAXARGS;
- if (blk > 0) { /* no block */
- genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n));
+ if (sendv) {
+ genop_2(s, blk ? OP_SENDVB : OP_SENDV, cursp(), idx);
}
else {
- genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n));
+ genop_3(s, blk ? OP_SENDB : OP_SEND, cursp(), idx, n);
}
}
}
@@ -1004,13 +1071,14 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
switch (type) {
case NODE_GVAR:
idx = new_sym(s, nsym(tree));
- genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val);
+ genop_2(s, OP_SETGV, sp, idx);
break;
case NODE_LVAR:
idx = lv_idx(s, nsym(tree));
if (idx > 0) {
if (idx != sp) {
- genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val);
+ gen_move(s, idx, sp, val);
+ if (val && on_eval(s)) genop_0(s, OP_NOP);
}
break;
}
@@ -1021,7 +1089,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
while (up) {
idx = lv_idx(up, nsym(tree));
if (idx > 0) {
- genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val);
+ genop_3(s, OP_SETUPVAR, sp, idx, lv);
break;
}
lv++;
@@ -1031,23 +1099,23 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
break;
case NODE_IVAR:
idx = new_sym(s, nsym(tree));
- genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val);
+ genop_2(s, OP_SETIV, sp, idx);
break;
case NODE_CVAR:
idx = new_sym(s, nsym(tree));
- genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val);
+ genop_2(s, OP_SETCV, sp, idx);
break;
case NODE_CONST:
idx = new_sym(s, nsym(tree));
- genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val);
+ genop_2(s, OP_SETCONST, sp, idx);
break;
case NODE_COLON2:
- idx = new_sym(s, nsym(tree->cdr));
- genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL);
+ gen_move(s, cursp(), sp, 0);
push();
codegen(s, tree->car, VAL);
pop_n(2);
- genop_peep(s, MKOP_ABx(OP_SETMCNST, cursp(), idx), val);
+ idx = new_sym(s, nsym(tree->cdr));
+ genop_2(s, OP_SETMCNST, sp, idx);
break;
case NODE_CALL:
@@ -1057,7 +1125,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
type == NODE_SCALL);
pop();
if (val) {
- genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), val);
+ gen_move(s, cursp(), sp, 0);
}
break;
@@ -1090,7 +1158,7 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val)
while (t) {
int sp = cursp();
- genop(s, MKOP_ABC(OP_AREF, sp, rhs, n));
+ genop_3(s, OP_AREF, sp, rhs, n);
push();
gen_assignment(s, t->car, sp, NOVAL);
pop();
@@ -1107,10 +1175,10 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val)
p = p->cdr;
}
}
- genop(s, MKOP_AB(OP_MOVE, cursp(), rhs));
+ gen_move(s, cursp(), rhs, val);
push_n(post+1);
pop_n(post+1);
- genop(s, MKOP_ABC(OP_APOST, cursp(), n, post));
+ genop_3(s, OP_APOST, cursp(), n, post);
n = 1;
if (t->car) { /* rest */
gen_assignment(s, t->car, cursp(), NOVAL);
@@ -1124,19 +1192,19 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val)
}
}
if (val) {
- genop(s, MKOP_AB(OP_MOVE, cursp(), rhs));
+ gen_move(s, cursp(), rhs, 0);
}
}
}
static void
-gen_send_intern(codegen_scope *s)
+gen_intern(codegen_scope *s)
{
- push();pop(); /* space for a block */
pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0));
+ genop_1(s, OP_INTERN, cursp());
push();
}
+
static void
gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
{
@@ -1159,25 +1227,25 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
j = 0;
++i;
if (sym)
- gen_send_intern(s);
+ gen_intern(s);
}
break;
}
- if (j >= 2) {
+ while (j >= 2) {
pop(); pop();
- genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+ genop_1(s, OP_STRCAT, cursp());
push();
- j = 1;
+ j--;
}
tree = tree->cdr;
}
if (j > 0) {
++i;
if (sym)
- gen_send_intern(s);
+ gen_intern(s);
}
pop_n(i);
- genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), i));
+ genop_2(s, OP_ARRAY, cursp(), i);
push();
}
else {
@@ -1196,7 +1264,7 @@ raise_error(codegen_scope *s, const char *msg)
{
int idx = new_lit(s, mrb_str_new_cstr(s->mrb, msg));
- genop(s, MKOP_ABx(OP_ERR, 1, idx));
+ genop_1(s, OP_ERR, idx);
}
#ifndef MRB_WITHOUT_FLOAT
@@ -1274,11 +1342,9 @@ static void
gen_retval(codegen_scope *s, node *tree)
{
if (nint(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));
+ pop();
+ genop_1(s, OP_ARYDUP, cursp());
}
else {
codegen(s, tree, VAL);
@@ -1294,7 +1360,7 @@ codegen(codegen_scope *s, node *tree, int val)
if (!tree) {
if (val) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
push();
}
return;
@@ -1318,7 +1384,7 @@ codegen(codegen_scope *s, node *tree, int val)
switch (nt) {
case NODE_BEGIN:
if (val && !tree) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
push();
}
while (tree) {
@@ -1329,18 +1395,18 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_RESCUE:
{
- int onerr, noexc, exend, pos1, pos2, tmp;
+ int noexc, exend, pos1, pos2, tmp;
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;
+ lp->pc0 = new_label(s);
+ lp->pc1 = genjmp(s, OP_ONERR, 0);
codegen(s, tree->car, VAL);
pop();
lp->type = LOOP_RESCUE;
- noexc = genop(s, MKOP_Bx(OP_JMP, 0));
- dispatch(s, onerr);
+ noexc = genjmp(s, OP_JMP, 0);
+ dispatch(s, lp->pc1);
tree = tree->cdr;
exend = 0;
pos1 = 0;
@@ -1348,7 +1414,7 @@ codegen(codegen_scope *s, node *tree, int val)
node *n2 = tree->car;
int exc = cursp();
- genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0));
+ genop_1(s, OP_EXCEPT, exc);
push();
while (n2) {
node *n3 = n2->car;
@@ -1359,30 +1425,29 @@ codegen(codegen_scope *s, node *tree, int val)
do {
if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) {
codegen(s, n4->car, VAL);
- genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
+ gen_move(s, cursp(), exc, 0);
push_n(2); pop_n(2); /* space for one arg and a block */
pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
+ genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1);
}
else {
if (n4) {
codegen(s, n4->car, VAL);
}
else {
- genop(s, MKOP_ABx(OP_GETCONST, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "StandardError"))));
+ genop_2(s, OP_GETCONST, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "StandardError")));
push();
}
pop();
- genop(s, MKOP_ABC(OP_RESCUE, exc, cursp(), 1));
+ genop_2(s, OP_RESCUE, exc, cursp());
}
- distcheck(s, pos2);
- tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+ tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, val);
pos2 = tmp;
if (n4) {
n4 = n4->cdr;
}
} while (n4);
- pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
+ pos1 = genjmp(s, OP_JMP, 0);
dispatch_linked(s, pos2);
pop();
@@ -1393,21 +1458,20 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, n3->cdr->cdr->car, val);
if (val) pop();
}
- distcheck(s, exend);
- tmp = genop(s, MKOP_sBx(OP_JMP, exend));
+ tmp = genjmp(s, OP_JMP, exend);
exend = tmp;
n2 = n2->cdr;
push();
}
if (pos1) {
dispatch(s, pos1);
- genop(s, MKOP_A(OP_RAISE, exc));
+ genop_1(s, OP_RAISE, exc);
}
}
pop();
tree = tree->cdr;
dispatch(s, noexc);
- genop(s, MKOP_A(OP_POPERR, 1));
+ genop_1(s, OP_POPERR, 1);
if (tree->car) {
codegen(s, tree->car, val);
}
@@ -1424,15 +1488,13 @@ codegen(codegen_scope *s, node *tree, int val)
(nint(tree->cdr->cdr->car) == NODE_BEGIN &&
tree->cdr->cdr->cdr)) {
int idx;
- int epush = s->pc;
- genop(s, MKOP_Bx(OP_EPUSH, 0));
s->ensure_level++;
- codegen(s, tree->car, val);
idx = scope_body(s, tree->cdr, NOVAL);
- s->iseq[epush] = MKOP_Bx(OP_EPUSH, idx);
+ genop_1(s, OP_EPUSH, idx);
+ codegen(s, tree->car, val);
s->ensure_level--;
- genop_peep(s, MKOP_A(OP_EPOP, 1), NOVAL);
+ genop_1(s, OP_EPOP, 1);
}
else { /* empty ensure ignored */
codegen(s, tree->car, val);
@@ -1443,7 +1505,7 @@ codegen(codegen_scope *s, node *tree, int val)
if (val) {
int idx = lambda_body(s, tree, 1);
- genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_LAMBDA));
+ genop_2(s, OP_LAMBDA, cursp(), idx);
push();
}
break;
@@ -1452,7 +1514,7 @@ codegen(codegen_scope *s, node *tree, int val)
if (val) {
int idx = lambda_body(s, tree, 1);
- genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_BLOCK));
+ genop_2(s, OP_BLOCK, cursp(), idx);
push();
}
break;
@@ -1460,10 +1522,10 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_IF:
{
int pos1, pos2;
- node *e = tree->cdr->cdr->car;
+ node *elsepart = tree->cdr->cdr->car;
if (!tree->car) {
- codegen(s, e, val);
+ codegen(s, elsepart, val);
goto exit;
}
switch (nint(tree->car->car)) {
@@ -1474,27 +1536,27 @@ codegen(codegen_scope *s, node *tree, int val)
goto exit;
case NODE_FALSE:
case NODE_NIL:
- codegen(s, e, val);
+ codegen(s, elsepart, val);
goto exit;
}
codegen(s, tree->car, VAL);
pop();
- pos1 = genop_peep(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0), NOVAL);
+ pos1 = genjmp2(s, OP_JMPNOT, cursp(), 0, val);
codegen(s, tree->cdr->car, val);
- if (e) {
+ if (elsepart) {
if (val) pop();
- pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
+ pos2 = genjmp(s, OP_JMP, 0);
dispatch(s, pos1);
- codegen(s, e, val);
+ codegen(s, elsepart, val);
dispatch(s, pos2);
}
else {
if (val) {
pop();
- pos2 = genop(s, MKOP_sBx(OP_JMP, 0));
+ pos2 = genjmp(s, OP_JMP, 0);
dispatch(s, pos1);
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
dispatch(s, pos2);
push();
}
@@ -1511,7 +1573,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->car, VAL);
pop();
- pos = genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), 0));
+ pos = genjmp2(s, OP_JMPNOT, cursp(), 0, val);
codegen(s, tree->cdr, val);
dispatch(s, pos);
}
@@ -1523,7 +1585,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->car, VAL);
pop();
- pos = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), 0));
+ pos = genjmp2(s, OP_JMPIF, cursp(), 0, val);
codegen(s, tree->cdr, val);
dispatch(s, pos);
}
@@ -1533,14 +1595,14 @@ codegen(codegen_scope *s, node *tree, int val)
{
struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
- lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
+ lp->pc0 = new_label(s);
+ lp->pc1 = genjmp(s, OP_JMP, 0);
lp->pc2 = new_label(s);
codegen(s, tree->cdr, NOVAL);
dispatch(s, lp->pc1);
codegen(s, tree->car, VAL);
pop();
- distcheck(s, lp->pc2 - s->pc);
- genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc));
+ genjmp2(s, OP_JMPIF, cursp(), lp->pc2, NOVAL);
loop_pop(s, val);
}
@@ -1550,14 +1612,14 @@ codegen(codegen_scope *s, node *tree, int val)
{
struct loopinfo *lp = loop_push(s, LOOP_NORMAL);
- lp->pc1 = genop(s, MKOP_sBx(OP_JMP, 0));
+ lp->pc0 = new_label(s);
+ lp->pc1 = genjmp(s, OP_JMP, 0);
lp->pc2 = new_label(s);
codegen(s, tree->cdr, NOVAL);
dispatch(s, lp->pc1);
codegen(s, tree->car, VAL);
pop();
- distcheck(s, lp->pc2 - s->pc);
- genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc));
+ genjmp2(s, OP_JMPNOT, cursp(), lp->pc2, NOVAL);
loop_pop(s, val);
}
@@ -1586,43 +1648,40 @@ codegen(codegen_scope *s, node *tree, int val)
while (n) {
codegen(s, n->car, VAL);
if (head) {
- genop(s, MKOP_AB(OP_MOVE, cursp(), head));
- push_n(2); pop_n(2); /* space for one arg and a block */
- pop();
+ gen_move(s, cursp(), head, 0);
+ push(); push(); pop(); pop(); pop();
if (nint(n->car->car) == NODE_SPLAT) {
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
+ genop_3(s, OP_SEND, cursp(), new_sym(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));
+ genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "===")), 1);
}
}
else {
pop();
}
- distcheck(s, pos2);
- tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
+ tmp = genjmp2(s, OP_JMPIF, cursp(), pos2, NOVAL);
pos2 = tmp;
n = n->cdr;
}
if (tree->car->car) {
- pos1 = genop(s, MKOP_sBx(OP_JMP, 0));
+ pos1 = genjmp(s, OP_JMP, 0);
dispatch_linked(s, pos2);
}
codegen(s, tree->car->cdr, val);
if (val) pop();
- distcheck(s, pos3);
- tmp = genop(s, MKOP_sBx(OP_JMP, pos3));
+ tmp = genjmp(s, OP_JMP, pos3);
pos3 = tmp;
if (pos1) dispatch(s, pos1);
tree = tree->cdr;
}
if (val) {
int pos = cursp();
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
if (pos3) dispatch_linked(s, pos3);
if (head) pop();
if (cursp() != pos) {
- genop(s, MKOP_AB(OP_MOVE, cursp(), pos));
+ gen_move(s, cursp(), pos, 0);
}
push();
}
@@ -1654,7 +1713,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->cdr, val);
if (val) {
pop(); pop();
- genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), FALSE));
+ genop_1(s, OP_RANGE_INC, cursp());
push();
}
break;
@@ -1664,7 +1723,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->cdr, val);
if (val) {
pop(); pop();
- genop(s, MKOP_ABC(OP_RANGE, cursp(), cursp(), TRUE));
+ genop_1(s, OP_RANGE_EXC, cursp());
push();
}
break;
@@ -1675,7 +1734,7 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->car, VAL);
pop();
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+ genop_2(s, OP_GETMCNST, cursp(), sym);
if (val) push();
}
break;
@@ -1684,8 +1743,8 @@ codegen(codegen_scope *s, node *tree, int val)
{
int sym = new_sym(s, nsym(tree));
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+ genop_1(s, OP_OCLASS, cursp());
+ genop_2(s, OP_GETMCNST, cursp(), sym);
if (val) push();
}
break;
@@ -1698,7 +1757,7 @@ codegen(codegen_scope *s, node *tree, int val)
if (n >= 0) {
if (val) {
pop_n(n);
- genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), n));
+ genop_2(s, OP_ARRAY, cursp(), n);
push();
}
}
@@ -1709,21 +1768,47 @@ codegen(codegen_scope *s, node *tree, int val)
break;
case NODE_HASH:
+ case NODE_KW_HASH:
{
int len = 0;
mrb_bool update = FALSE;
while (tree) {
- codegen(s, tree->car->car, val);
- codegen(s, tree->car->cdr, val);
- len++;
+ if (nint(tree->car->car->car) == NODE_KW_REST_ARGS) {
+ if (len > 0) {
+ pop_n(len*2);
+ if (!update) {
+ genop_2(s, OP_HASH, cursp(), len);
+ }
+ else {
+ pop();
+ genop_2(s, OP_HASHADD, cursp(), len);
+ }
+ push();
+ }
+ codegen(s, tree->car->cdr, VAL);
+ if (len > 0) {
+ pop(); pop();
+ genop_1(s, OP_HASHCAT, cursp());
+ push();
+ }
+ update = TRUE;
+ len = 0;
+ }
+ else {
+ codegen(s, tree->car->car, VAL);
+ codegen(s, tree->car->cdr, VAL);
+ len++;
+ }
tree = tree->cdr;
- if (val && len == 126) {
+ if (val && len == 255) {
pop_n(len*2);
- genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
- if (update) {
+ if (!update) {
+ genop_2(s, OP_HASH, cursp(), len);
+ }
+ else {
pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
+ genop_2(s, OP_HASHADD, cursp(), len);
}
push();
update = TRUE;
@@ -1732,10 +1817,14 @@ codegen(codegen_scope *s, node *tree, int val)
}
if (val) {
pop_n(len*2);
- genop(s, MKOP_ABC(OP_HASH, cursp(), cursp(), len));
- if (update) {
+ if (!update) {
+ genop_2(s, OP_HASH, cursp(), len);
+ }
+ else {
pop();
- genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__update")), 1));
+ if (len > 0) {
+ genop_2(s, OP_HASHADD, cursp(), len);
+ }
}
push();
}
@@ -1776,7 +1865,7 @@ codegen(codegen_scope *s, node *tree, int val)
n++;
}
else {
- genop(s, MKOP_A(OP_LOADNIL, rhs+n));
+ genop_1(s, OP_LOADNIL, rhs+n);
gen_assignment(s, t->car, rhs+n, NOVAL);
}
t = t->cdr;
@@ -1800,7 +1889,7 @@ codegen(codegen_scope *s, node *tree, int val)
else {
rn = len - post - n;
}
- genop(s, MKOP_ABC(OP_ARRAY, cursp(), rhs+n, rn));
+ genop_3(s, OP_ARRAY2, cursp(), rhs+n, rn);
gen_assignment(s, t->car, cursp(), NOVAL);
n += rn;
}
@@ -1815,7 +1904,7 @@ codegen(codegen_scope *s, node *tree, int val)
}
pop_n(len);
if (val) {
- genop(s, MKOP_ABC(OP_ARRAY, rhs, rhs, len));
+ genop_2(s, OP_ARRAY, rhs, len);
push();
}
}
@@ -1843,17 +1932,17 @@ codegen(codegen_scope *s, node *tree, int val)
int onerr, noexc, exc;
struct loopinfo *lp;
- onerr = genop(s, MKOP_Bx(OP_ONERR, 0));
+ onerr = genjmp(s, 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));
+ genop_1(s, OP_POPERR, 1);
+ noexc = genjmp(s, OP_JMP, 0);
dispatch(s, onerr);
- genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0));
- genop(s, MKOP_A(OP_LOADF, exc));
+ genop_1(s, OP_EXCEPT, exc);
+ genop_1(s, OP_LOADF, exc);
dispatch(s, noexc);
loop_pop(s, NOVAL);
}
@@ -1867,7 +1956,7 @@ codegen(codegen_scope *s, node *tree, int val)
push();
}
codegen(s, n->car, VAL); /* receiver */
- idx = new_msym(s, nsym(n->cdr->car));
+ idx = new_sym(s, nsym(n->cdr->car));
base = cursp()-1;
if (n->cdr->cdr->car) {
nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1);
@@ -1881,12 +1970,12 @@ codegen(codegen_scope *s, node *tree, int val)
}
}
/* copy receiver and arguments */
- genop(s, MKOP_AB(OP_MOVE, cursp(), base));
+ gen_move(s, cursp(), base, 0);
for (i=0; i<nargs; i++) {
- genop(s, MKOP_AB(OP_MOVE, cursp()+i+1, base+i+1));
+ gen_move(s, cursp()+i+1, base+i+1, 0);
}
push_n(nargs+2);pop_n(nargs+2); /* space for receiver, arguments and a block */
- genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
+ genop_3(s, OP_SEND, cursp(), idx, callargs);
push();
}
else {
@@ -1900,30 +1989,30 @@ codegen(codegen_scope *s, node *tree, int val)
pop();
if (val) {
if (vsp >= 0) {
- genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
+ gen_move(s, vsp, cursp(), 0);
}
- pos = genop(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0));
+ pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val);
}
else {
- pos = genop_peep(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0), NOVAL);
+ pos = genjmp2(s, name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0, val);
}
codegen(s, tree->cdr->cdr->car, VAL);
pop();
if (val && vsp >= 0) {
- genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
+ gen_move(s, vsp, cursp(), 0);
}
if (nint(tree->car->car) == NODE_CALL) {
if (callargs == CALL_MAXARGS) {
pop();
- genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+ genop_1(s, OP_ARYPUSH, cursp());
}
else {
pop_n(callargs);
callargs++;
}
pop();
- idx = new_msym(s, attrsym(s, nsym(tree->car->cdr->cdr->car)));
- genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
+ idx = new_sym(s, attrsym(s, nsym(tree->car->cdr->cdr->car)));
+ genop_3(s, OP_SEND, cursp(), idx, callargs);
}
else {
gen_assignment(s, tree->car, cursp(), val);
@@ -1935,52 +2024,52 @@ codegen(codegen_scope *s, node *tree, int val)
push(); pop();
pop(); pop();
- idx = new_msym(s, sym);
+ idx = new_sym(s, sym);
if (len == 1 && name[0] == '+') {
- genop_peep(s, MKOP_ABC(OP_ADD, cursp(), idx, 1), val);
+ gen_addsub(s, OP_ADD, cursp(), idx);
}
else if (len == 1 && name[0] == '-') {
- genop_peep(s, MKOP_ABC(OP_SUB, cursp(), idx, 1), val);
+ gen_addsub(s, OP_SUB, cursp(), idx);
}
else if (len == 1 && name[0] == '*') {
- genop(s, MKOP_ABC(OP_MUL, cursp(), idx, 1));
+ genop_2(s, OP_MUL, cursp(), idx);
}
else if (len == 1 && name[0] == '/') {
- genop(s, MKOP_ABC(OP_DIV, cursp(), idx, 1));
+ genop_2(s, OP_DIV, cursp(), idx);
}
else if (len == 1 && name[0] == '<') {
- genop(s, MKOP_ABC(OP_LT, cursp(), idx, 1));
+ genop_2(s, OP_LT, cursp(), idx);
}
else if (len == 2 && name[0] == '<' && name[1] == '=') {
- genop(s, MKOP_ABC(OP_LE, cursp(), idx, 1));
+ genop_2(s, OP_LE, cursp(), idx);
}
else if (len == 1 && name[0] == '>') {
- genop(s, MKOP_ABC(OP_GT, cursp(), idx, 1));
+ genop_2(s, OP_GT, cursp(), idx);
}
else if (len == 2 && name[0] == '>' && name[1] == '=') {
- genop(s, MKOP_ABC(OP_GE, cursp(), idx, 1));
+ genop_2(s, OP_GE, cursp(), idx);
}
else {
- genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 1));
+ genop_3(s, OP_SEND, cursp(), idx, 1);
}
if (callargs < 0) {
gen_assignment(s, tree->car, cursp(), val);
}
else {
if (val && vsp >= 0) {
- genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
+ gen_move(s, vsp, cursp(), 0);
}
if (callargs == CALL_MAXARGS) {
pop();
- genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
+ genop_1(s, OP_ARYPUSH, cursp());
}
else {
pop_n(callargs);
callargs++;
}
pop();
- idx = new_msym(s, attrsym(s,nsym(tree->car->cdr->cdr->car)));
- genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
+ idx = new_sym(s, attrsym(s,nsym(tree->car->cdr->cdr->car)));
+ genop_3(s, OP_SEND, cursp(), idx, callargs);
}
}
break;
@@ -1997,7 +2086,7 @@ codegen(codegen_scope *s, node *tree, int val)
s2 = s2->prev;
if (!s2) break;
}
- genop(s, MKOP_ABx(OP_ARGARY, cursp(), (lv & 0xf)));
+ genop_2S(s, OP_ARGARY, cursp(), (lv & 0xf));
push(); push(); /* ARGARY pushes two values */
pop(); pop();
if (tree) {
@@ -2015,12 +2104,12 @@ codegen(codegen_scope *s, node *tree, int val)
pop();
}
else {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
push(); pop();
}
pop_n(n+1);
if (sendv) n = CALL_MAXARGS;
- genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, n));
+ genop_2(s, OP_SUPER, cursp(), n);
if (val) push();
}
break;
@@ -2037,14 +2126,14 @@ codegen(codegen_scope *s, node *tree, int val)
if (!s2) break;
}
if (s2) ainfo = s2->ainfo;
- genop(s, MKOP_ABx(OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf)));
+ genop_2S(s, OP_ARGARY, cursp(), (ainfo<<4)|(lv & 0xf));
push(); push(); pop(); /* ARGARY pushes two values */
if (tree && tree->cdr) {
codegen(s, tree->cdr, VAL);
pop();
}
pop(); pop();
- genop(s, MKOP_ABC(OP_SUPER, cursp(), 0, CALL_MAXARGS));
+ genop_2(s, OP_SUPER, cursp(), CALL_MAXARGS);
if (val) push();
}
break;
@@ -2054,13 +2143,13 @@ codegen(codegen_scope *s, node *tree, int val)
gen_retval(s, tree);
}
else {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
}
if (s->loop) {
- genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_RETURN));
+ gen_return(s, OP_RETURN_BLK, cursp());
}
else {
- genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
+ gen_return(s, OP_RETURN, cursp());
}
if (val) push();
break;
@@ -2087,9 +2176,9 @@ codegen(codegen_scope *s, node *tree, int val)
}
push();pop(); /* space for a block */
pop_n(n+1);
- genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)));
+ genop_2S(s, 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));
+ genop_3(s, OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "call")), n);
if (val) push();
}
break;
@@ -2105,11 +2194,10 @@ codegen(codegen_scope *s, node *tree, int val)
}
else if (s->loop->type == LOOP_NORMAL) {
if (s->ensure_level > s->loop->ensure_level) {
- genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
+ genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
}
codegen(s, tree, NOVAL);
- distcheck(s, s->loop->pc1 - s->pc);
- genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc));
+ genjmp(s, OP_JMP, s->loop->pc0);
}
else {
if (tree) {
@@ -2117,9 +2205,9 @@ codegen(codegen_scope *s, node *tree, int val)
pop();
}
else {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
}
- genop_peep(s, MKOP_AB(OP_RETURN, cursp(), OP_R_NORMAL), NOVAL);
+ gen_return(s, OP_RETURN, cursp());
}
if (val) push();
break;
@@ -2130,10 +2218,9 @@ codegen(codegen_scope *s, node *tree, int val)
}
else {
if (s->ensure_level > s->loop->ensure_level) {
- genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
+ genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
}
- distcheck(s, s->loop->pc2 - s->pc);
- genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc));
+ genjmp(s, OP_JMP, s->loop->pc2);
}
if (val) push();
break;
@@ -2160,13 +2247,12 @@ codegen(codegen_scope *s, node *tree, int val)
}
else {
if (n > 0) {
- genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL);
+ genop_1(s, OP_POPERR, n);
}
if (s->ensure_level > lp->ensure_level) {
- genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL);
+ genop_1(s, OP_EPOP, s->ensure_level - lp->ensure_level);
}
- distcheck(s, s->loop->pc1 - s->pc);
- genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc));
+ genjmp(s, OP_JMP, lp->pc0);
}
}
if (val) push();
@@ -2178,7 +2264,8 @@ codegen(codegen_scope *s, node *tree, int val)
int idx = lv_idx(s, nsym(tree));
if (idx > 0) {
- genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL);
+ gen_move(s, cursp(), idx, val);
+ if (val && on_eval(s)) genop_0(s, OP_NOP);
}
else {
int lv = 0;
@@ -2187,7 +2274,7 @@ codegen(codegen_scope *s, node *tree, int val)
while (up) {
idx = lv_idx(up, nsym(tree));
if (idx > 0) {
- genop_peep(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv), VAL);
+ genop_3(s, OP_GETUPVAR, cursp(), idx, lv);
break;
}
lv++;
@@ -2199,29 +2286,29 @@ codegen(codegen_scope *s, node *tree, int val)
break;
case NODE_GVAR:
- if (val) {
+ {
int sym = new_sym(s, nsym(tree));
- genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
- push();
+ genop_2(s, OP_GETGV, cursp(), sym);
+ if (val) push();
}
break;
case NODE_IVAR:
- if (val) {
+ {
int sym = new_sym(s, nsym(tree));
- genop(s, MKOP_ABx(OP_GETIV, cursp(), sym));
- push();
+ genop_2(s, OP_GETIV, cursp(), sym);
+ if (val) push();
}
break;
case NODE_CVAR:
- if (val) {
+ {
int sym = new_sym(s, nsym(tree));
- genop(s, MKOP_ABx(OP_GETCV, cursp(), sym));
- push();
+ genop_2(s, OP_GETCV, cursp(), sym);
+ if (val) push();
}
break;
@@ -2229,15 +2316,13 @@ codegen(codegen_scope *s, node *tree, int val)
{
int sym = new_sym(s, nsym(tree));
- genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym));
- if (val) {
- push();
- }
+ genop_2(s, OP_GETCONST, cursp(), sym);
+ if (val) push();
}
break;
case NODE_DEFINED:
- codegen(s, tree, VAL);
+ codegen(s, tree, val);
break;
case NODE_BACK_REF:
@@ -2249,7 +2334,7 @@ codegen(codegen_scope *s, node *tree, int val)
buf[1] = nchar(tree);
buf[2] = 0;
sym = new_sym(s, mrb_intern_cstr(s->mrb, buf));
- genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
+ genop_2(s, OP_GETGV, cursp(), sym);
push();
}
break;
@@ -2262,7 +2347,7 @@ codegen(codegen_scope *s, node *tree, int val)
str = mrb_format(mrb, "$%S", mrb_fixnum_value(nint(tree)));
sym = new_sym(s, mrb_intern_str(mrb, str));
- genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
+ genop_2(s, OP_GETGV, cursp(), sym);
push();
}
break;
@@ -2272,7 +2357,7 @@ codegen(codegen_scope *s, node *tree, int val)
break;
case NODE_BLOCK_ARG:
- codegen(s, tree, VAL);
+ codegen(s, tree, val);
break;
case NODE_INT:
@@ -2280,7 +2365,6 @@ codegen(codegen_scope *s, node *tree, int val)
char *p = (char*)tree->car;
int base = nint(tree->cdr->car);
mrb_int i;
- mrb_code co;
mrb_bool overflow;
i = readint_mrb_int(s, p, base, FALSE, &overflow);
@@ -2289,19 +2373,19 @@ codegen(codegen_scope *s, node *tree, int val)
double f = readint_float(s, p, base);
int off = new_lit(s, mrb_float_value(s->mrb, f));
- genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
+ genop_2(s, OP_LOADL, cursp(), off);
}
else
#endif
{
- if (i < MAXARG_sBx && i > -MAXARG_sBx) {
- co = MKOP_AsBx(OP_LOADI, cursp(), i);
- }
+ if (i == -1) genop_1(s, OP_LOADI__1, cursp());
+ else if (i < 0) genop_2(s, OP_LOADINEG, cursp(), -i);
+ else if (i < 8) genop_1(s, OP_LOADI_0 + i, cursp());
+ else if (i <= 0xffff) genop_2(s, OP_LOADI, cursp(), i);
else {
int off = new_lit(s, mrb_fixnum_value(i));
- co = MKOP_ABx(OP_LOADL, cursp(), off);
+ genop_2(s, OP_LOADL, cursp(), off);
}
- genop(s, co);
}
push();
}
@@ -2314,7 +2398,7 @@ codegen(codegen_scope *s, node *tree, int val)
mrb_float f = mrb_float_read(p, NULL);
int off = new_lit(s, mrb_float_value(s->mrb, f));
- genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
+ genop_2(s, OP_LOADL, cursp(), off);
push();
}
break;
@@ -2332,7 +2416,7 @@ codegen(codegen_scope *s, node *tree, int val)
mrb_float f = mrb_float_read(p, NULL);
int off = new_lit(s, mrb_float_value(s->mrb, -f));
- genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
+ genop_2(s, OP_LOADL, cursp(), off);
push();
}
break;
@@ -2343,7 +2427,6 @@ codegen(codegen_scope *s, node *tree, int val)
char *p = (char*)tree->car;
int base = nint(tree->cdr->car);
mrb_int i;
- mrb_code co;
mrb_bool overflow;
i = readint_mrb_int(s, p, base, TRUE, &overflow);
@@ -2352,18 +2435,18 @@ codegen(codegen_scope *s, node *tree, int val)
double f = readint_float(s, p, base);
int off = new_lit(s, mrb_float_value(s->mrb, -f));
- genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
+ genop_2(s, OP_LOADL, cursp(), off);
}
else {
#endif
- if (i < MAXARG_sBx && i > -MAXARG_sBx) {
- co = MKOP_AsBx(OP_LOADI, cursp(), i);
+ if (i == -1) genop_1(s, OP_LOADI__1, cursp());
+ else if (i >= -0xffff) {
+ genop_2(s, OP_LOADINEG, cursp(), (uint16_t)-i);
}
else {
int off = new_lit(s, mrb_fixnum_value(i));
- co = MKOP_ABx(OP_LOADL, cursp(), off);
+ genop_2(s, OP_LOADL, cursp(), off);
}
- genop(s, co);
#ifndef MRB_WITHOUT_FLOAT
}
#endif
@@ -2373,13 +2456,13 @@ codegen(codegen_scope *s, node *tree, int val)
default:
if (val) {
- int sym = new_msym(s, mrb_intern_lit(s->mrb, "-"));
+ int sym = new_sym(s, mrb_intern_lit(s->mrb, "-"));
- genop(s, MKOP_ABx(OP_LOADI, cursp(), 0));
+ genop_1(s, OP_LOADI_0, cursp());
push();
codegen(s, tree, VAL);
pop(); pop();
- genop(s, MKOP_ABC(OP_SUB, cursp(), sym, 2));
+ genop_2(s, OP_SUB, cursp(), sym);
}
else {
codegen(s, tree, NOVAL);
@@ -2397,7 +2480,7 @@ codegen(codegen_scope *s, node *tree, int val)
int off = new_lit(s, mrb_str_new(s->mrb, p, len));
mrb_gc_arena_restore(s->mrb, ai);
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ genop_2(s, OP_STRING, cursp(), off);
push();
}
break;
@@ -2410,7 +2493,7 @@ codegen(codegen_scope *s, node *tree, int val)
node *n = tree;
if (!n) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
push();
break;
}
@@ -2419,7 +2502,7 @@ codegen(codegen_scope *s, node *tree, int val)
while (n) {
codegen(s, n->car, VAL);
pop(); pop();
- genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+ genop_1(s, OP_STRCAT, cursp());
push();
n = n->cdr;
}
@@ -2450,7 +2533,7 @@ codegen(codegen_scope *s, node *tree, int val)
int ai = mrb_gc_arena_save(s->mrb);
int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
- genop(s, MKOP_A(OP_LOADSELF, cursp()));
+ genop_1(s, OP_LOADSELF, cursp());
push();
codegen(s, tree->car, VAL);
n = tree->cdr;
@@ -2461,14 +2544,14 @@ codegen(codegen_scope *s, node *tree, int val)
}
codegen(s, n->car, VAL);
pop(); pop();
- genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+ genop_1(s, OP_STRCAT, cursp());
push();
n = n->cdr;
}
push(); /* for block */
pop_n(3);
sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
- genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+ genop_3(s, OP_SEND, cursp(), sym, 1);
if (val) push();
mrb_gc_arena_restore(s->mrb, ai);
}
@@ -2482,13 +2565,13 @@ codegen(codegen_scope *s, node *tree, int val)
int off = new_lit(s, mrb_str_new(s->mrb, p, len));
int sym;
- genop(s, MKOP_A(OP_LOADSELF, cursp()));
+ genop_1(s, OP_LOADSELF, cursp());
push();
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ genop_2(s, OP_STRING, cursp(), off);
push(); push();
pop_n(3);
sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
- genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
+ genop_3(s, OP_SEND, cursp(), sym, 1);
if (val) push();
mrb_gc_arena_restore(s->mrb, ai);
}
@@ -2504,24 +2587,24 @@ codegen(codegen_scope *s, node *tree, int val)
int off = new_lit(s, mrb_str_new_cstr(s->mrb, p1));
int argc = 1;
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+ genop_1(s, OP_OCLASS, cursp());
+ genop_2(s, OP_GETMCNST, cursp(), sym);
push();
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ genop_2(s, OP_STRING, cursp(), off);
push();
if (p2 || p3) {
if (p2) { /* opt */
off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ genop_2(s, OP_STRING, cursp(), off);
}
else {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
}
push();
argc++;
if (p3) { /* enc */
off = new_lit(s, mrb_str_new(s->mrb, p3, 1));
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ genop_2(s, OP_STRING, cursp(), off);
push();
argc++;
}
@@ -2529,7 +2612,7 @@ codegen(codegen_scope *s, node *tree, int val)
push(); /* space for a block */
pop_n(argc+2);
sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
- genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
+ genop_3(s, OP_SEND, cursp(), sym, argc);
mrb_gc_arena_restore(s->mrb, ai);
push();
}
@@ -2544,15 +2627,15 @@ codegen(codegen_scope *s, node *tree, int val)
int off;
char *p;
- genop(s, MKOP_A(OP_OCLASS, cursp()));
- genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
+ genop_1(s, OP_OCLASS, cursp());
+ genop_2(s, OP_GETMCNST, cursp(), sym);
push();
codegen(s, n->car, VAL);
n = n->cdr;
while (n) {
codegen(s, n->car, VAL);
pop(); pop();
- genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+ genop_1(s, OP_STRCAT, cursp());
push();
n = n->cdr;
}
@@ -2561,29 +2644,29 @@ codegen(codegen_scope *s, node *tree, int val)
p = (char*)n->car;
off = new_lit(s, mrb_str_new_cstr(s->mrb, p));
codegen(s, tree->car, VAL);
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ genop_2(s, OP_STRING, cursp(), off);
pop();
- genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
+ genop_1(s, OP_STRCAT, cursp());
push();
}
if (n->cdr->car) { /* opt */
char *p2 = (char*)n->cdr->car;
off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ genop_2(s, OP_STRING, cursp(), off);
push();
argc++;
}
if (n->cdr->cdr) { /* enc */
char *p2 = (char*)n->cdr->cdr;
off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
- genop(s, MKOP_ABx(OP_STRING, cursp(), off));
+ genop_2(s, OP_STRING, cursp(), off);
push();
argc++;
}
push(); /* space for a block */
pop_n(argc+2);
sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
- genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
+ genop_3(s, OP_SEND, cursp(), sym, argc);
mrb_gc_arena_restore(s->mrb, ai);
push();
}
@@ -2603,7 +2686,7 @@ codegen(codegen_scope *s, node *tree, int val)
if (val) {
int sym = new_sym(s, nsym(tree));
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
+ genop_2(s, OP_LOADSYM, cursp(), sym);
push();
}
break;
@@ -2611,55 +2694,46 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_DSYM:
codegen(s, tree, val);
if (val) {
- gen_send_intern(s);
+ gen_intern(s);
}
break;
case NODE_SELF:
if (val) {
- genop(s, MKOP_A(OP_LOADSELF, cursp()));
+ genop_1(s, OP_LOADSELF, cursp());
push();
}
break;
case NODE_NIL:
if (val) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
push();
}
break;
case NODE_TRUE:
if (val) {
- genop(s, MKOP_A(OP_LOADT, cursp()));
+ genop_1(s, OP_LOADT, cursp());
push();
}
break;
case NODE_FALSE:
if (val) {
- genop(s, MKOP_A(OP_LOADF, cursp()));
+ genop_1(s, OP_LOADF, cursp());
push();
}
break;
case NODE_ALIAS:
{
- int a = new_msym(s, nsym(tree->car));
- int b = new_msym(s, nsym(tree->cdr));
- int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method"));
+ int a = new_sym(s, nsym(tree->car));
+ int b = new_sym(s, nsym(tree->cdr));
- genop(s, MKOP_A(OP_TCLASS, cursp()));
- push();
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), a));
- push();
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b));
- push();
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
- push(); /* space for a block */
- pop_n(4);
- genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2));
+ genop_2(s, OP_ALIAS, a, b);
if (val) {
+ genop_1(s, OP_LOADNIL, cursp());
push();
}
}
@@ -2667,41 +2741,15 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_UNDEF:
{
- int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method"));
- int num = 0;
node *t = tree;
- genop(s, MKOP_A(OP_TCLASS, cursp()));
- push();
while (t) {
- 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, nsym(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, nsym(t->car));
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
- push();
+ int symbol = new_sym(s, nsym(t->car));
+ genop_1(s, OP_UNDEF, symbol);
t = t->cdr;
- num++;
}
- push();pop(); /* space for a block */
- pop();
- if (num < CALL_MAXARGS) {
- pop_n(num);
- }
- genop(s, MKOP_ABC(OP_SEND, cursp(), undef, num));
if (val) {
+ genop_1(s, OP_LOADNIL, cursp());
push();
}
}
@@ -2710,13 +2758,14 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_CLASS:
{
int idx;
+ node *body;
if (tree->car->car == (node*)0) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
push();
}
else if (tree->car->car == (node*)1) {
- genop(s, MKOP_A(OP_OCLASS, cursp()));
+ genop_1(s, OP_OCLASS, cursp());
push();
}
else {
@@ -2726,14 +2775,17 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->cdr->car, VAL);
}
else {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
push();
}
pop(); pop();
- idx = new_msym(s, nsym(tree->car->cdr));
- genop(s, MKOP_AB(OP_CLASS, cursp(), idx));
- idx = scope_body(s, tree->cdr->cdr->car, val);
- genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
+ idx = new_sym(s, nsym(tree->car->cdr));
+ genop_2(s, OP_CLASS, cursp(), idx);
+ body = tree->cdr->cdr->car;
+ if (!(nint(body->cdr->car) == NODE_BEGIN && body->cdr->cdr == NULL)) {
+ idx = scope_body(s, body, val);
+ genop_2(s, OP_EXEC, cursp(), idx);
+ }
if (val) {
push();
}
@@ -2745,21 +2797,24 @@ codegen(codegen_scope *s, node *tree, int val)
int idx;
if (tree->car->car == (node*)0) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
push();
}
else if (tree->car->car == (node*)1) {
- genop(s, MKOP_A(OP_OCLASS, cursp()));
+ genop_1(s, OP_OCLASS, cursp());
push();
}
else {
codegen(s, tree->car->car, VAL);
}
pop();
- idx = new_msym(s, nsym(tree->car->cdr));
- genop(s, MKOP_AB(OP_MODULE, cursp(), idx));
- idx = scope_body(s, tree->cdr->car, val);
- genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
+ idx = new_sym(s, nsym(tree->car->cdr));
+ genop_2(s, OP_MODULE, cursp(), idx);
+ if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
+ tree->cdr->car->cdr->cdr == NULL)) {
+ idx = scope_body(s, tree->cdr->car, val);
+ genop_2(s, OP_EXEC, cursp(), idx);
+ }
if (val) {
push();
}
@@ -2772,9 +2827,12 @@ codegen(codegen_scope *s, node *tree, int val)
codegen(s, tree->car, VAL);
pop();
- genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp()));
- idx = scope_body(s, tree->cdr->car, val);
- genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
+ genop_1(s, OP_SCLASS, cursp());
+ if (!(nint(tree->cdr->car->cdr->car) == NODE_BEGIN &&
+ tree->cdr->car->cdr->cdr == NULL)) {
+ idx = scope_body(s, tree->cdr->car, val);
+ genop_2(s, OP_EXEC, cursp(), idx);
+ }
if (val) {
push();
}
@@ -2783,17 +2841,17 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_DEF:
{
- int sym = new_msym(s, nsym(tree->car));
+ int sym = new_sym(s, nsym(tree->car));
int idx = lambda_body(s, tree->cdr, 0);
- genop(s, MKOP_A(OP_TCLASS, cursp()));
+ genop_1(s, OP_TCLASS, cursp());
push();
- genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD));
+ genop_2(s, OP_METHOD, cursp(), idx);
push(); pop();
pop();
- genop(s, MKOP_AB(OP_METHOD, cursp(), sym));
+ genop_2(s, OP_DEF, cursp(), sym);
if (val) {
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
+ genop_2(s, OP_LOADSYM, cursp(), sym);
push();
}
}
@@ -2802,18 +2860,18 @@ codegen(codegen_scope *s, node *tree, int val)
case NODE_SDEF:
{
node *recv = tree->car;
- int sym = new_msym(s, nsym(tree->cdr->car));
+ int sym = new_sym(s, nsym(tree->cdr->car));
int idx = lambda_body(s, tree->cdr->cdr, 0);
codegen(s, recv, VAL);
pop();
- genop(s, MKOP_AB(OP_SCLASS, cursp(), cursp()));
+ genop_1(s, OP_SCLASS, cursp());
push();
- genop(s, MKOP_Abc(OP_LAMBDA, cursp(), idx, OP_L_METHOD));
+ genop_2(s, OP_METHOD, cursp(), idx);
pop();
- genop(s, MKOP_AB(OP_METHOD, cursp(), sym));
+ genop_2(s, OP_DEF, cursp(), sym);
if (val) {
- genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
+ genop_2(s, OP_LOADSYM, cursp(), sym);
push();
}
}
@@ -2875,7 +2933,7 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
p->irep->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*p->pcapa);
p->irep->plen = 0;
- p->scapa = MAXMSYMLEN;
+ p->scapa = 256;
p->irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*p->scapa);
p->irep->slen = 0;
@@ -2971,7 +3029,7 @@ loop_push(codegen_scope *s, enum looptype t)
struct loopinfo *p = (struct loopinfo *)codegen_palloc(s, sizeof(struct loopinfo));
p->type = t;
- p->pc1 = p->pc2 = p->pc3 = 0;
+ p->pc0 = p->pc1 = p->pc2 = p->pc3 = 0;
p->prev = s->loop;
p->ensure_level = s->ensure_level;
p->acc = cursp();
@@ -3013,27 +3071,26 @@ loop_break(codegen_scope *s, node *tree)
return;
}
if (n > 0) {
- genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL);
+ genop_1(s, OP_POPERR, n);
}
if (loop->type == LOOP_NORMAL) {
int tmp;
if (s->ensure_level > s->loop->ensure_level) {
- genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
+ genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level);
}
if (tree) {
- genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL);
+ gen_move(s, loop->acc, cursp(), 0);
}
- distcheck(s, s->loop->pc3);
- tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3));
+ tmp = genjmp(s, OP_JMP, loop->pc3);
loop->pc3 = tmp;
}
else {
if (!tree) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
}
- genop(s, MKOP_AB(OP_RETURN, cursp(), OP_R_BREAK));
+ gen_return(s, OP_BREAK, cursp());
}
}
}
@@ -3042,7 +3099,7 @@ static void
loop_pop(codegen_scope *s, int val)
{
if (val) {
- genop(s, MKOP_A(OP_LOADNIL, cursp()));
+ genop_1(s, OP_LOADNIL, cursp());
}
dispatch_linked(s, s->loop->pc3);
s->loop = s->loop->prev;
@@ -3107,3 +3164,56 @@ mrb_irep_remove_lv(mrb_state *mrb, mrb_irep *irep)
mrb_irep_remove_lv(mrb, irep->reps[i]);
}
}
+
+#undef OPCODE
+#define Z 1
+#define S 3
+#define W 4
+/* instruction sizes */
+uint8_t mrb_insn_size[] = {
+#define B 2
+#define BB 3
+#define BBB 4
+#define BS 4
+#define SB 4
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+#undef OPCODE
+#undef B
+#undef BB
+#undef BS
+#undef SB
+#undef BBB
+};
+/* EXT1 instruction sizes */
+uint8_t mrb_insn_size1[] = {
+#define B 3
+#define BB 4
+#define BBB 5
+#define BS 5
+#define SB 5
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+#undef OPCODE
+#undef B
+};
+/* EXT2 instruction sizes */
+uint8_t mrb_insn_size2[] = {
+#define B 2
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+#undef OPCODE
+#undef BB
+#undef BBB
+#undef BS
+#undef SB
+};
+/* EXT3 instruction sizes */
+#define BB 5
+#define BBB 6
+#define BS 4
+#define SB 5
+uint8_t mrb_insn_size3[] = {
+#define OPCODE(_,x) x,
+#include "mruby/ops.h"
+};
diff --git a/mrbgems/mruby-compiler/core/node.h b/mrbgems/mruby-compiler/core/node.h
index 9636dd759..219bddab0 100644
--- a/mrbgems/mruby-compiler/core/node.h
+++ b/mrbgems/mruby-compiler/core/node.h
@@ -9,14 +9,11 @@
enum node_type {
NODE_METHOD,
- NODE_FBODY,
- NODE_CFUNC,
NODE_SCOPE,
NODE_BLOCK,
NODE_IF,
NODE_CASE,
NODE_WHEN,
- NODE_OPT_N,
NODE_WHILE,
NODE_UNTIL,
NODE_ITER,
@@ -40,12 +37,12 @@ enum node_type {
NODE_CALL,
NODE_SCALL,
NODE_FCALL,
- NODE_VCALL,
NODE_SUPER,
NODE_ZSUPER,
NODE_ARRAY,
NODE_ZARRAY,
NODE_HASH,
+ NODE_KW_HASH,
NODE_RETURN,
NODE_YIELD,
NODE_LVAR,
@@ -57,8 +54,6 @@ enum node_type {
NODE_NTH_REF,
NODE_BACK_REF,
NODE_MATCH,
- NODE_MATCH2,
- NODE_MATCH3,
NODE_INT,
NODE_FLOAT,
NODE_NEGATE,
@@ -71,10 +66,10 @@ enum node_type {
NODE_REGX,
NODE_DREGX,
NODE_DREGX_ONCE,
- NODE_LIST,
NODE_ARG,
- NODE_ARGSCAT,
- NODE_ARGSPUSH,
+ NODE_ARGS_TAIL,
+ NODE_KW_ARG,
+ NODE_KW_REST_ARGS,
NODE_SPLAT,
NODE_TO_ARY,
NODE_SVALUE,
@@ -88,26 +83,15 @@ enum node_type {
NODE_SCLASS,
NODE_COLON2,
NODE_COLON3,
- NODE_CREF,
NODE_DOT2,
NODE_DOT3,
- NODE_FLIP2,
- NODE_FLIP3,
- NODE_ATTRSET,
NODE_SELF,
NODE_NIL,
NODE_TRUE,
NODE_FALSE,
NODE_DEFINED,
- NODE_NEWLINE,
NODE_POSTEXE,
- NODE_ALLOCA,
- NODE_DMETHOD,
- NODE_BMETHOD,
- NODE_MEMO,
- NODE_IFUNC,
NODE_DSYM,
- NODE_ATTRASGN,
NODE_HEREDOC,
NODE_LITERAL_DELIM,
NODE_WORDS,
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index 7f848b4df..5e6cda236 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -568,6 +568,13 @@ new_hash(parser_state *p, node *a)
return cons((node*)NODE_HASH, a);
}
+/* (:kw_hash (k . v) (k . v)...) */
+static node*
+new_kw_hash(parser_state *p, node *a)
+{
+ return cons((node*)NODE_KW_HASH, a);
+}
+
/* (:sym . a) */
static node*
new_sym(parser_state *p, mrb_sym sym)
@@ -671,23 +678,61 @@ new_arg(parser_state *p, mrb_sym sym)
return cons((node*)NODE_ARG, nsym(sym));
}
-/* (m o r m2 b) */
+/* (m o r m2 tail) */
/* m: (a b c) */
/* o: ((a . e1) (b . e2)) */
/* r: a */
/* m2: (a b c) */
/* b: a */
static node*
-new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk)
+new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, node *tail)
{
node *n;
- n = cons(m2, nsym(blk));
+ n = cons(m2, tail);
n = cons(nsym(rest), n);
n = cons(opt, n);
return cons(m, n);
}
+/* (:args_tail keywords rest_keywords_sym block_sym) */
+static node*
+new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk)
+{
+ node *k;
+
+ /* allocate register for keywords hash */
+ if (kws || kwrest) {
+ local_add_f(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : mrb_intern_lit(p->mrb, "**"));
+ }
+
+ /* allocate register for block */
+ local_add_f(p, blk? blk : mrb_intern_lit(p->mrb, "&"));
+
+ // allocate register for keywords arguments
+ // order is for Proc#parameters
+ for (k = kws; k; k = k->cdr) {
+ if (!k->car->cdr->cdr->car) { // allocate required keywords
+ local_add_f(p, sym(k->car->cdr->car));
+ }
+ }
+ for (k = kws; k; k = k->cdr) {
+ if (k->car->cdr->cdr->car) { // allocate keywords with default
+ local_add_f(p, sym(k->car->cdr->car));
+ }
+ }
+
+ return list4((node*)NODE_ARGS_TAIL, kws, kwrest, nsym(blk));
+}
+
+/* (:kw_arg kw_sym def_arg) */
+static node*
+new_kw_arg(parser_state *p, mrb_sym kw, node *def_arg)
+{
+ mrb_assert(kw);
+ return list3((node*)NODE_KW_ARG, nsym(kw), def_arg);
+}
+
/* (:block_arg . a) */
static node*
new_block_arg(parser_state *p, node *a)
@@ -1134,6 +1179,10 @@ heredoc_end(parser_state *p)
%type <nd> heredoc words symbols
%type <num> call_op call_op2 /* 0:'&.', 1:'.', 2:'::' */
+%type <nd> args_tail opt_args_tail f_kwarg f_kw f_kwrest
+%type <nd> f_block_kwarg f_block_kw block_args_tail opt_block_args_tail
+%type <id> f_label
+
%token tUPLUS /* unary+ */
%token tUMINUS /* unary- */
%token tPOW /* ** */
@@ -1159,6 +1208,7 @@ heredoc_end(parser_state *p)
%token tLBRACE /* { */
%token tLBRACE_ARG /* { */
%token tSTAR /* * */
+%token tDSTAR /* ** */
%token tAMPER /* & */
%token tLAMBDA /* -> */
%token tANDDOT /* &. */
@@ -1736,6 +1786,7 @@ op : '|' { $$ = intern_c('|'); }
| '/' { $$ = intern_c('/'); }
| '%' { $$ = intern_c('%'); }
| tPOW { $$ = intern("**",2); }
+ | tDSTAR { $$ = intern("**",2); }
| '!' { $$ = intern_c('!'); }
| '~' { $$ = intern_c('~'); }
| tUPLUS { $$ = intern("+@",2); }
@@ -1944,11 +1995,11 @@ aref_args : none
}
| args comma assocs trailer
{
- $$ = push($1, new_hash(p, $3));
+ $$ = push($1, new_kw_hash(p, $3));
}
| assocs trailer
{
- $$ = cons(new_hash(p, $1), 0);
+ $$ = cons(new_kw_hash(p, $1), 0);
NODE_LINENO($$, $1);
}
;
@@ -1984,12 +2035,12 @@ opt_call_args : none
}
| args comma assocs ','
{
- $$ = cons(push($1, new_hash(p, $3)), 0);
+ $$ = cons(push($1, new_kw_hash(p, $3)), 0);
NODE_LINENO($$, $1);
}
| assocs ','
{
- $$ = cons(list1(new_hash(p, $1)), 0);
+ $$ = cons(list1(new_kw_hash(p, $1)), 0);
NODE_LINENO($$, $1);
}
;
@@ -2007,12 +2058,12 @@ call_args : command
}
| assocs opt_block_arg
{
- $$ = cons(list1(new_hash(p, $1)), $2);
+ $$ = cons(list1(new_kw_hash(p, $1)), $2);
NODE_LINENO($$, $1);
}
| args comma assocs opt_block_arg
{
- $$ = cons(push($1, new_hash(p, $3)), $4);
+ $$ = cons(push($1, new_kw_hash(p, $3)), $4);
NODE_LINENO($$, $1);
}
| block_arg
@@ -2451,23 +2502,51 @@ f_margs : f_marg_list
}
;
-block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
+block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg
+ {
+ $$ = new_args_tail(p, $1, $3, $4);
+ }
+ | f_block_kwarg opt_f_block_arg
+ {
+ $$ = new_args_tail(p, $1, 0, $2);
+ }
+ | f_kwrest opt_f_block_arg
+ {
+ $$ = new_args_tail(p, 0, $1, $2);
+ }
+ | f_block_arg
+ {
+ $$ = new_args_tail(p, 0, 0, $1);
+ }
+ ;
+
+opt_block_args_tail : ',' block_args_tail
+ {
+ $$ = $2;
+ }
+ | /* none */
+ {
+ $$ = new_args_tail(p, 0, 0, 0);
+ }
+ ;
+
+block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail
{
$$ = new_args(p, $1, $3, $5, 0, $6);
}
- | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
{
$$ = new_args(p, $1, $3, $5, $7, $8);
}
- | f_arg ',' f_block_optarg opt_f_block_arg
+ | f_arg ',' f_block_optarg opt_block_args_tail
{
$$ = new_args(p, $1, $3, 0, 0, $4);
}
- | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg
+ | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail
{
$$ = new_args(p, $1, $3, 0, $5, $6);
}
- | f_arg ',' f_rest_arg opt_f_block_arg
+ | f_arg ',' f_rest_arg opt_block_args_tail
{
$$ = new_args(p, $1, 0, $3, 0, $4);
}
@@ -2475,39 +2554,39 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
{
$$ = new_args(p, $1, 0, 0, 0, 0);
}
- | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail
{
$$ = new_args(p, $1, 0, $3, $5, $6);
}
- | f_arg opt_f_block_arg
+ | f_arg opt_block_args_tail
{
$$ = new_args(p, $1, 0, 0, 0, $2);
}
- | f_block_optarg ',' f_rest_arg opt_f_block_arg
+ | f_block_optarg ',' f_rest_arg opt_block_args_tail
{
$$ = new_args(p, 0, $1, $3, 0, $4);
}
- | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
{
$$ = new_args(p, 0, $1, $3, $5, $6);
}
- | f_block_optarg opt_f_block_arg
+ | f_block_optarg opt_block_args_tail
{
$$ = new_args(p, 0, $1, 0, 0, $2);
}
- | f_block_optarg ',' f_arg opt_f_block_arg
+ | f_block_optarg ',' f_arg opt_block_args_tail
{
$$ = new_args(p, 0, $1, 0, $3, $4);
}
- | f_rest_arg opt_f_block_arg
+ | f_rest_arg opt_block_args_tail
{
$$ = new_args(p, 0, 0, $1, 0, $2);
}
- | f_rest_arg ',' f_arg opt_f_block_arg
+ | f_rest_arg ',' f_arg opt_block_args_tail
{
$$ = new_args(p, 0, 0, $1, $3, $4);
}
- | f_block_arg
+ | block_args_tail
{
$$ = new_args(p, 0, 0, 0, 0, $1);
}
@@ -3021,65 +3100,151 @@ f_arglist : '(' f_args rparen
}
;
-f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg
+f_label : tIDENTIFIER tLABEL_TAG
+ ;
+
+f_kw : f_label arg
+ {
+ void_expr_error(p, $2);
+ $$ = new_kw_arg(p, $1, $2);
+ }
+ | f_label
+ {
+ $$ = new_kw_arg(p, $1, 0);
+ }
+ ;
+
+f_block_kw : f_label primary_value
+ {
+ $$ = new_kw_arg(p, $1, $2);
+ }
+ | f_label
+ {
+ $$ = new_kw_arg(p, $1, 0);
+ }
+ ;
+
+f_block_kwarg : f_block_kw
+ {
+ $$ = list1($1);
+ }
+ | f_block_kwarg ',' f_block_kw
+ {
+ $$ = push($1, $3);
+ }
+ ;
+
+f_kwarg : f_kw
+ {
+ $$ = list1($1);
+ }
+ | f_kwarg ',' f_kw
+ {
+ $$ = push($1, $3);
+ }
+ ;
+
+kwrest_mark : tPOW
+ | tDSTAR
+ ;
+
+f_kwrest : kwrest_mark tIDENTIFIER
+ {
+ $$ = cons((node*)NODE_KW_REST_ARGS, nsym($2));
+ }
+ | kwrest_mark
+ {
+ $$ = cons((node*)NODE_KW_REST_ARGS, 0);
+ }
+ ;
+
+args_tail : f_kwarg ',' f_kwrest opt_f_block_arg
+ {
+ $$ = new_args_tail(p, $1, $3, $4);
+ }
+ | f_kwarg opt_f_block_arg
+ {
+ $$ = new_args_tail(p, $1, 0, $2);
+ }
+ | f_kwrest opt_f_block_arg
+ {
+ $$ = new_args_tail(p, 0, $1, $2);
+ }
+ | f_block_arg
+ {
+ $$ = new_args_tail(p, 0, 0, $1);
+ }
+ ;
+
+opt_args_tail : ',' args_tail
+ {
+ $$ = $2;
+ }
+ | /* none */
+ {
+ $$ = new_args_tail(p, 0, 0, 0);
+ }
+ ;
+
+f_args : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail
{
$$ = new_args(p, $1, $3, $5, 0, $6);
}
- | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
{
$$ = new_args(p, $1, $3, $5, $7, $8);
}
- | f_arg ',' f_optarg opt_f_block_arg
+ | f_arg ',' f_optarg opt_args_tail
{
$$ = new_args(p, $1, $3, 0, 0, $4);
}
- | f_arg ',' f_optarg ',' f_arg opt_f_block_arg
+ | f_arg ',' f_optarg ',' f_arg opt_args_tail
{
$$ = new_args(p, $1, $3, 0, $5, $6);
}
- | f_arg ',' f_rest_arg opt_f_block_arg
+ | f_arg ',' f_rest_arg opt_args_tail
{
$$ = new_args(p, $1, 0, $3, 0, $4);
}
- | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ | f_arg ',' f_rest_arg ',' f_arg opt_args_tail
{
$$ = new_args(p, $1, 0, $3, $5, $6);
}
- | f_arg opt_f_block_arg
+ | f_arg opt_args_tail
{
$$ = new_args(p, $1, 0, 0, 0, $2);
}
- | f_optarg ',' f_rest_arg opt_f_block_arg
+ | f_optarg ',' f_rest_arg opt_args_tail
{
$$ = new_args(p, 0, $1, $3, 0, $4);
}
- | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+ | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
{
$$ = new_args(p, 0, $1, $3, $5, $6);
}
- | f_optarg opt_f_block_arg
+ | f_optarg opt_args_tail
{
$$ = new_args(p, 0, $1, 0, 0, $2);
}
- | f_optarg ',' f_arg opt_f_block_arg
+ | f_optarg ',' f_arg opt_args_tail
{
$$ = new_args(p, 0, $1, 0, $3, $4);
}
- | f_rest_arg opt_f_block_arg
+ | f_rest_arg opt_args_tail
{
$$ = new_args(p, 0, 0, $1, 0, $2);
}
- | f_rest_arg ',' f_arg opt_f_block_arg
+ | f_rest_arg ',' f_arg opt_args_tail
{
$$ = new_args(p, 0, 0, $1, $3, $4);
}
- | f_block_arg
+ | args_tail
{
$$ = new_args(p, 0, 0, 0, 0, $1);
}
| /* none */
{
- local_add_f(p, 0);
+ local_add_f(p, mrb_intern_lit(p->mrb, "&"));
$$ = new_args(p, 0, 0, 0, 0, 0);
}
;
@@ -3189,7 +3354,7 @@ f_rest_arg : restarg_mark tIDENTIFIER
}
| restarg_mark
{
- local_add_f(p, 0);
+ local_add_f(p, mrb_intern_lit(p->mrb, "*"));
$$ = -1;
}
;
@@ -3200,7 +3365,6 @@ blkarg_mark : '&'
f_block_arg : blkarg_mark tIDENTIFIER
{
- local_add_f(p, $2);
$$ = $2;
}
;
@@ -3211,7 +3375,6 @@ opt_f_block_arg : ',' f_block_arg
}
| none
{
- local_add_f(p, 0);
$$ = 0;
}
;
@@ -3285,6 +3448,11 @@ assoc : arg tASSOC arg
$$ = cons(new_sym(p, new_strsym(p, $1)), $3);
}
}
+ | tDSTAR arg
+ {
+ void_expr_error(p, $2);
+ $$ = cons(cons((node*)NODE_KW_REST_ARGS, 0), $2);
+ }
;
operation : tIDENTIFIER
@@ -3450,13 +3618,13 @@ backref_error(parser_state *p, node *n)
{
int c;
- c = (int)(intptr_t)n->car;
+ c = intn(n->car);
if (c == NODE_NTH_REF) {
- yyerror_i(p, "can't set variable $%" MRB_PRId, (int)(intptr_t)n->cdr);
+ yyerror_i(p, "can't set variable $%" MRB_PRId, intn(n->cdr));
}
else if (c == NODE_BACK_REF) {
- yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr);
+ yyerror_i(p, "can't set variable $%c", intn(n->cdr));
}
else {
mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c));
@@ -3469,7 +3637,7 @@ void_expr_error(parser_state *p, node *n)
int c;
if (n == NULL) return;
- c = (int)(intptr_t)n->car;
+ c = intn(n->car);
switch (c) {
case NODE_BREAK:
case NODE_RETURN:
@@ -3508,7 +3676,7 @@ nextc(parser_state *p)
if (p->pb) {
node *tmp;
- c = (int)(intptr_t)p->pb->car;
+ c = intn(p->pb->car);
tmp = p->pb;
p->pb = p->pb->cdr;
cons_free(tmp);
@@ -3557,7 +3725,7 @@ pushback(parser_state *p, int c)
if (c >= 0) {
p->column--;
}
- p->pb = cons((node*)(intptr_t)c, p->pb);
+ p->pb = cons(nint(c), p->pb);
}
static void
@@ -3582,7 +3750,7 @@ peekc_n(parser_state *p, int n)
c0 = nextc(p);
if (c0 == -1) return c0; /* do not skip partial EOF */
if (c0 >= 0) --p->column;
- list = push(list, (node*)(intptr_t)c0);
+ list = push(list, nint(c0));
} while(n--);
if (p->pb) {
p->pb = append((node*)list, p->pb);
@@ -4019,11 +4187,11 @@ parse_string(parser_state *p)
}
else if (c == beg) {
nest_level++;
- p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level;
+ p->lex_strterm->cdr->car = nint(nest_level);
}
else if (c == end) {
nest_level--;
- p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level;
+ p->lex_strterm->cdr->car = nint(nest_level);
}
else if (c == '\\') {
c = nextc(p);
@@ -4365,7 +4533,16 @@ parser_yylex(parser_state *p)
return tOP_ASGN;
}
pushback(p, c);
- c = tPOW;
+ if (IS_SPCARG(c)) {
+ yywarning(p, "`**' interpreted as argument prefix");
+ c = tDSTAR;
+ }
+ else if (IS_BEG()) {
+ c = tDSTAR;
+ }
+ else {
+ c = tPOW; /* "**", "argument prefix" */
+ }
}
else {
if (c == '=') {
@@ -5534,6 +5711,7 @@ parser_init_cxt(parser_state *p, mrbc_context *cxt)
}
p->capture_errors = cxt->capture_errors;
p->no_optimize = cxt->no_optimize;
+ p->on_eval = cxt->on_eval;
if (cxt->partial_hook) {
p->cxt = cxt;
}
@@ -5546,7 +5724,7 @@ parser_update_cxt(parser_state *p, mrbc_context *cxt)
int i = 0;
if (!cxt) return;
- if ((int)(intptr_t)p->tree->car != NODE_SCOPE) return;
+ if (intn(p->tree->car) != NODE_SCOPE) return;
n0 = n = p->tree->cdr->car;
while (n) {
i++;
@@ -5896,6 +6074,48 @@ dump_recur(mrb_state *mrb, node *tree, int offset)
}
}
+static void
+dump_args(mrb_state *mrb, node *n, int offset)
+{
+ if (n->car) {
+ dump_prefix(n, offset+1);
+ printf("mandatory args:\n");
+ dump_recur(mrb, n->car, offset+2);
+ }
+ n = n->cdr;
+ if (n->car) {
+ dump_prefix(n, offset+1);
+ printf("optional args:\n");
+ {
+ node *n2 = n->car;
+
+ while (n2) {
+ dump_prefix(n2, offset+2);
+ printf("%s=\n", mrb_sym2name(mrb, sym(n2->car->car)));
+ mrb_parser_dump(mrb, n2->car->cdr, offset+3);
+ n2 = n2->cdr;
+ }
+ }
+ }
+ n = n->cdr;
+ if (n->car) {
+ dump_prefix(n, offset+1);
+ printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
+ }
+ n = n->cdr;
+ if (n->car) {
+ dump_prefix(n, offset+1);
+ printf("post mandatory args:\n");
+ dump_recur(mrb, n->car, offset+2);
+ }
+
+ n = n->cdr;
+ if (n) {
+ mrb_assert(intn(n->car) == NODE_ARGS_TAIL);
+ mrb_parser_dump(mrb, n, offset);
+ }
+}
+
#endif
void
@@ -5907,7 +6127,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
if (!tree) return;
again:
dump_prefix(tree, offset);
- nodetype = (int)(intptr_t)tree->car;
+ nodetype = intn(tree->car);
tree = tree->cdr;
switch (nodetype) {
case NODE_BEGIN:
@@ -5967,7 +6187,8 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
break;
case NODE_LAMBDA:
- printf("NODE_BLOCK:\n");
+ printf("NODE_LAMBDA:\n");
+ dump_prefix(tree, offset);
goto block;
case NODE_BLOCK:
@@ -5975,43 +6196,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
printf("NODE_BLOCK:\n");
tree = tree->cdr;
if (tree->car) {
- node *n = tree->car;
-
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("optional args:\n");
- {
- node *n2 = n->car;
-
- while (n2) {
- dump_prefix(n2, offset+2);
- printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
- mrb_parser_dump(mrb, n2->car->cdr, 0);
- n2 = n2->cdr;
- }
- }
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("post mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- if (n->cdr) {
- dump_prefix(n, offset+1);
- printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr)));
- }
+ dump_args(mrb, tree->car, offset+1);
}
dump_prefix(tree, offset+1);
printf("body:\n");
@@ -6163,7 +6348,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
dump_prefix(tree, offset+1);
printf("method='%s' (%d)\n",
mrb_sym2name(mrb, sym(tree->cdr->car)),
- (int)(intptr_t)tree->cdr->car);
+ intn(tree->cdr->car));
tree = tree->cdr->cdr->car;
if (tree) {
dump_prefix(tree, offset+1);
@@ -6218,6 +6403,19 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
}
break;
+ case NODE_KW_HASH:
+ printf("NODE_KW_HASH:\n");
+ while (tree) {
+ dump_prefix(tree, offset+1);
+ printf("key:\n");
+ mrb_parser_dump(mrb, tree->car->car, offset+2);
+ dump_prefix(tree, offset+1);
+ printf("value:\n");
+ mrb_parser_dump(mrb, tree->car->cdr, offset+2);
+ tree = tree->cdr;
+ }
+ break;
+
case NODE_SPLAT:
printf("NODE_SPLAT:\n");
mrb_parser_dump(mrb, tree, offset+1);
@@ -6280,7 +6478,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
mrb_parser_dump(mrb, tree->car, offset+2);
tree = tree->cdr;
dump_prefix(tree, offset+1);
- printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car);
+ printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), intn(tree->car));
tree = tree->cdr;
mrb_parser_dump(mrb, tree->car, offset+1);
break;
@@ -6362,11 +6560,11 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
break;
case NODE_BACK_REF:
- printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree);
+ printf("NODE_BACK_REF: $%c\n", intn(tree));
break;
case NODE_NTH_REF:
- printf("NODE_NTH_REF: $%" MRB_PRId "\n", (mrb_int)(intptr_t)tree);
+ printf("NODE_NTH_REF: $%d\n", intn(tree));
break;
case NODE_ARG:
@@ -6379,7 +6577,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
break;
case NODE_INT:
- printf("NODE_INT %s base %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr->car);
+ printf("NODE_INT %s base %d\n", (char*)tree->car, intn(tree->cdr->car));
break;
case NODE_FLOAT:
@@ -6392,7 +6590,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
break;
case NODE_STR:
- printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr);
+ printf("NODE_STR \"%s\" len %d\n", (char*)tree->car, intn(tree->cdr));
break;
case NODE_DSTR:
@@ -6401,7 +6599,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
break;
case NODE_XSTR:
- printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, (int)(intptr_t)tree->cdr);
+ printf("NODE_XSTR \"%s\" len %d\n", (char*)tree->car, intn(tree->cdr));
break;
case NODE_DXSTR:
@@ -6430,7 +6628,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_SYM:
printf("NODE_SYM :%s (%d)\n", mrb_sym2name(mrb, sym(tree)),
- (int)(intptr_t)tree);
+ intn(tree));
break;
case NODE_SELF:
@@ -6546,43 +6744,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
}
tree = tree->cdr;
if (tree->car) {
- node *n = tree->car;
-
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("optional args:\n");
- {
- node *n2 = n->car;
-
- while (n2) {
- dump_prefix(n2, offset+2);
- printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
- mrb_parser_dump(mrb, n2->car->cdr, 0);
- n2 = n2->cdr;
- }
- }
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("post mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- if (n->cdr) {
- dump_prefix(n, offset+1);
- printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr)));
- }
+ dump_args(mrb, tree->car, offset);
}
mrb_parser_dump(mrb, tree->cdr->car, offset+1);
break;
@@ -6595,44 +6757,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
printf(":%s\n", mrb_sym2name(mrb, sym(tree->car)));
tree = tree->cdr->cdr;
if (tree->car) {
- node *n = tree->car;
-
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("optional args:\n");
- {
- node *n2 = n->car;
-
- while (n2) {
- dump_prefix(n2, offset+2);
- printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
- mrb_parser_dump(mrb, n2->car->cdr, 0);
- n2 = n2->cdr;
- }
- }
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
- }
- n = n->cdr;
- if (n->car) {
- dump_prefix(n, offset+1);
- printf("post mandatory args:\n");
- dump_recur(mrb, n->car, offset+2);
- }
- n = n->cdr;
- if (n) {
- dump_prefix(n, offset+1);
- printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
- }
+ dump_args(mrb, tree->car, offset+1);
}
tree = tree->cdr;
mrb_parser_dump(mrb, tree->car, offset+1);
@@ -6648,6 +6773,37 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
break;
+ case NODE_ARGS_TAIL:
+ printf("NODE_ARGS_TAIL:\n");
+ {
+ node *kws = tree->car;
+
+ while (kws) {
+ mrb_parser_dump(mrb, kws->car, offset+1);
+ kws = kws->cdr;
+ }
+ }
+ tree = tree->cdr;
+ if (tree->car) {
+ mrb_assert(intn(tree->car->car) == NODE_KW_REST_ARGS);
+ mrb_parser_dump(mrb, tree->car, offset+1);
+ }
+ tree = tree->cdr;
+ if (tree->car) {
+ dump_prefix(tree, offset+1);
+ printf("block='%s'\n", mrb_sym2name(mrb, sym(tree->car)));
+ }
+ break;
+
+ case NODE_KW_ARG:
+ printf("NODE_KW_ARG %s\n", mrb_sym2name(mrb, sym(tree->car)));
+ mrb_parser_dump(mrb, tree->cdr->car, offset + 1);
+ break;
+
+ case NODE_KW_REST_ARGS:
+ printf("NODE_KW_REST_ARGS %s\n", mrb_sym2name(mrb, sym(tree)));
+ break;
+
default:
printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype);
break;
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c
index 47d029a98..b9c87f6d1 100644
--- a/mrbgems/mruby-eval/src/eval.c
+++ b/mrbgems/mruby-eval/src/eval.c
@@ -44,7 +44,7 @@ search_irep(mrb_irep *top, int bnest, int lev, mrb_irep *bottom)
return NULL;
}
-static inline mrb_code
+static uint16_t
search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
{
mrb_irep *virep;
@@ -57,7 +57,7 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
}
for (pos = 0; pos < virep->nlocals - 1; pos++) {
if (vsym == virep->lv[pos].name) {
- return (MKARG_B(pos + 1) | MKARG_C(level + bnest));
+ return (pos+1)<<8 | (level+bnest);
}
}
}
@@ -71,8 +71,8 @@ irep_argc(mrb_irep *irep)
mrb_code c;
c = irep->iseq[0];
- if (GET_OPCODE(c) == OP_ENTER) {
- mrb_aspec ax = GETARG_Ax(c);
+ if (c == OP_ENTER) {
+ mrb_aspec ax = PEEK_W(irep->iseq+1);
/* extra 1 means a slot for block */
return MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1;
}
@@ -88,95 +88,132 @@ potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals)
return TRUE;
}
+extern uint8_t mrb_insn_size[];
+extern uint8_t mrb_insn_size1[];
+extern uint8_t mrb_insn_size2[];
+extern uint8_t mrb_insn_size3[];
+
static void
patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top)
{
int i;
- mrb_code c;
+ uint32_t a;
+ uint16_t b;
+ uint8_t c;
+ mrb_code insn;
int argc = irep_argc(irep);
- for (i = 0; i < irep->ilen; i++) {
- c = irep->iseq[i];
- switch(GET_OPCODE(c)){
+ for (i = 0; i < irep->ilen; ) {
+ insn = irep->iseq[i];
+ switch(insn){
case OP_EPUSH:
- patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1, top);
+ b = PEEK_S(irep->iseq+i+1);
+ patch_irep(mrb, irep->reps[b], bnest + 1, top);
break;
case OP_LAMBDA:
- {
- int arg_c = GETARG_c(c);
- if (arg_c & OP_L_CAPTURE) {
- patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1, top);
- }
- }
+ case OP_BLOCK:
+ a = PEEK_B(irep->iseq+i+1);
+ b = PEEK_B(irep->iseq+i+2);
+ patch_irep(mrb, irep->reps[b], bnest + 1, top);
break;
case OP_SEND:
- if (GETARG_C(c) != 0) {
+ b = PEEK_B(irep->iseq+i+2);
+ c = PEEK_B(irep->iseq+i+3);
+ if (c != 0) {
break;
}
else {
- mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest);
+ uint16_t arg = search_variable(mrb, irep->syms[b], bnest);
if (arg != 0) {
/* must replace */
- irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
+ irep->iseq[i] = OP_GETUPVAR;
+ irep->iseq[i+2] = arg >> 8;
+ irep->iseq[i+3] = arg & 0xff;
}
}
break;
case OP_MOVE:
+ a = PEEK_B(irep->iseq+i+1);
+ b = PEEK_B(irep->iseq+i+2);
/* src part */
- if (potential_upvar_p(irep->lv, GETARG_B(c), argc, irep->nlocals)) {
- mrb_code arg = search_variable(mrb, irep->lv[GETARG_B(c) - 1].name, bnest);
+ if (potential_upvar_p(irep->lv, b, argc, irep->nlocals)) {
+ uint16_t arg = search_variable(mrb, irep->lv[b - 1].name, bnest);
if (arg != 0) {
/* must replace */
- irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
+ irep->iseq[i] = insn = OP_GETUPVAR;
+ irep->iseq[i+2] = arg >> 8;
+ irep->iseq[i+3] = arg & 0xff;
}
}
/* dst part */
- if (potential_upvar_p(irep->lv, GETARG_A(c), argc, irep->nlocals)) {
- mrb_code arg = search_variable(mrb, irep->lv[GETARG_A(c) - 1].name, bnest);
+ if (potential_upvar_p(irep->lv, a, argc, irep->nlocals)) {
+ uint16_t arg = search_variable(mrb, irep->lv[a - 1].name, bnest);
if (arg != 0) {
/* must replace */
- irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_B(c)) | arg;
+ irep->iseq[i] = insn = OP_SETUPVAR;
+ irep->iseq[i+1] = (mrb_code)b;
+ irep->iseq[i+2] = arg >> 8;
+ irep->iseq[i+3] = arg & 0xff;
}
}
break;
case OP_GETUPVAR:
+ a = PEEK_B(irep->iseq+i+1);
+ b = PEEK_B(irep->iseq+i+2);
+ c = PEEK_B(irep->iseq+i+3);
{
- int lev = GETARG_C(c)+1;
+ int lev = c+1;
mrb_irep *tmp = search_irep(top, bnest, lev, irep);
- if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) {
- mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest);
+ if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) {
+ uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest);
if (arg != 0) {
/* must replace */
- irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
+ irep->iseq[i] = OP_GETUPVAR;
+ irep->iseq[i+2] = arg >> 8;
+ irep->iseq[i+3] = arg & 0xff;
}
}
}
break;
case OP_SETUPVAR:
+ a = PEEK_B(irep->iseq+i+1);
+ b = PEEK_B(irep->iseq+i+2);
+ c = PEEK_B(irep->iseq+i+3);
{
- int lev = GETARG_C(c)+1;
+ int lev = c+1;
mrb_irep *tmp = search_irep(top, bnest, lev, irep);
- if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) {
- mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest);
+ if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) {
+ uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest);
if (arg != 0) {
/* must replace */
- irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
+ irep->iseq[i] = OP_SETUPVAR;
+ irep->iseq[i+1] = a;
+ irep->iseq[i+2] = arg >> 8;
+ irep->iseq[i+3] = arg & 0xff;
}
}
}
break;
- case OP_STOP:
- if (mrb->c->ci->acc >= 0) {
- irep->iseq[i] = MKOP_AB(OP_RETURN, irep->nlocals, OP_R_NORMAL);
- }
- break;
+ case OP_EXT1:
+ insn = PEEK_B(irep->iseq+1);
+ i += mrb_insn_size1[insn];
+ continue;
+ case OP_EXT2:
+ insn = PEEK_B(irep->iseq+1);
+ i += mrb_insn_size2[insn];
+ continue;
+ case OP_EXT3:
+ insn = PEEK_B(irep->iseq+1);
+ i += mrb_insn_size3[insn];
+ continue;
}
+ i+=mrb_insn_size[insn];
}
}
@@ -203,6 +240,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding,
mrbc_filename(mrb, cxt, file ? file : "(eval)");
cxt->capture_errors = TRUE;
cxt->no_optimize = TRUE;
+ cxt->on_eval = TRUE;
p = mrb_parse_nstring(mrb, s, len, cxt);
diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c
index e445b34c8..600567cac 100644
--- a/mrbgems/mruby-method/src/method.c
+++ b/mrbgems/mruby-method/src/method.c
@@ -387,7 +387,7 @@ mrb_mruby_method_gem_init(mrb_state* mrb)
mrb_define_method(mrb, unbound_method, "bind", unbound_method_bind, MRB_ARGS_REQ(1));
mrb_define_method(mrb, unbound_method, "super_method", method_super_method, MRB_ARGS_NONE());
mrb_define_method(mrb, unbound_method, "==", method_eql, MRB_ARGS_REQ(1));
- mrb_alias_method(mrb, unbound_method, mrb_intern_lit(mrb, "eql?"), mrb_intern_lit(mrb, "=="));
+ mrb_define_alias(mrb, unbound_method, "eql?", "==");
mrb_define_method(mrb, unbound_method, "to_s", method_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, unbound_method, "inspect", method_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, unbound_method, "arity", method_arity, MRB_ARGS_NONE());
@@ -396,11 +396,11 @@ mrb_mruby_method_gem_init(mrb_state* mrb)
mrb_undef_class_method(mrb, method, "new");
mrb_define_method(mrb, method, "==", method_eql, MRB_ARGS_REQ(1));
- mrb_alias_method(mrb, method, mrb_intern_lit(mrb, "eql?"), mrb_intern_lit(mrb, "=="));
+ mrb_define_alias(mrb, method, "eql?", "==");
mrb_define_method(mrb, method, "to_s", method_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, method, "inspect", method_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, method, "call", method_call, MRB_ARGS_ANY());
- mrb_alias_method(mrb, method, mrb_intern_lit(mrb, "[]"), mrb_intern_lit(mrb, "call"));
+ mrb_define_alias(mrb, method, "[]", "call");
mrb_define_method(mrb, method, "unbind", method_unbind, MRB_ARGS_NONE());
mrb_define_method(mrb, method, "super_method", method_super_method, MRB_ARGS_NONE());
mrb_define_method(mrb, method, "arity", method_arity, MRB_ARGS_NONE());
diff --git a/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/mrbgems/mruby-objectspace/src/mruby_objectspace.c
index 3887091d3..b31dee04c 100644
--- a/mrbgems/mruby-objectspace/src/mruby_objectspace.c
+++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c
@@ -57,7 +57,7 @@ os_count_objects(mrb_state *mrb, mrb_value self)
hash = mrb_hash_new(mrb);
}
- if (!mrb_test(mrb_hash_empty_p(mrb, hash))) {
+ if (!mrb_hash_empty_p(mrb, hash)) {
mrb_hash_clear(mrb, hash);
}
diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c
index b13606f5f..9ce6c1831 100644
--- a/mrbgems/mruby-proc-ext/src/proc.c
+++ b/mrbgems/mruby-proc-ext/src/proc.c
@@ -109,6 +109,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
mrb_aspec aspec;
mrb_value sname, parameters;
int i, j;
+ int max = -1;
if (MRB_PROC_CFUNC_P(proc)) {
// TODO cfunc aspec is not implemented yet
@@ -120,7 +121,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
if (!irep->lv) {
return mrb_ary_new(mrb);
}
- if (GET_OPCODE(*irep->iseq) != OP_ENTER) {
+ if (*irep->iseq != OP_ENTER) {
return mrb_ary_new(mrb);
}
@@ -129,7 +130,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
parameters_list[3].name = "opt";
}
- aspec = GETARG_Ax(*irep->iseq);
+ aspec = PEEK_W(irep->iseq+1);
parameters_list[0].size = MRB_ASPEC_REQ(aspec);
parameters_list[1].size = MRB_ASPEC_OPT(aspec);
parameters_list[2].size = MRB_ASPEC_REST(aspec);
@@ -138,14 +139,25 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
parameters = mrb_ary_new_capa(mrb, irep->nlocals-1);
+ max = irep->nlocals-1;
for (i = 0, p = parameters_list; p->name; p++) {
if (p->size <= 0) continue;
sname = mrb_symbol_value(mrb_intern_cstr(mrb, p->name));
for (j = 0; j < p->size; i++, j++) {
- mrb_value a = mrb_ary_new(mrb);
+ mrb_value a;
+
+ a = mrb_ary_new(mrb);
mrb_ary_push(mrb, a, sname);
- if (irep->lv[i].name) {
- mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i].name));
+ if (i < max && irep->lv[i].name) {
+ mrb_sym sym = irep->lv[i].name;
+ const char *name = mrb_sym2name(mrb, sym);
+ switch (name[0]) {
+ case '*': case '&':
+ break;
+ default:
+ mrb_ary_push(mrb, a, mrb_symbol_value(sym));
+ break;
+ }
}
mrb_ary_push(mrb, parameters, a);
}
diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c
index 4cab49094..142d449f4 100644
--- a/mrbgems/mruby-string-ext/src/string.c
+++ b/mrbgems/mruby-string-ext/src/string.c
@@ -627,8 +627,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb)
mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "succ", mrb_str_succ, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "succ!", mrb_str_succ_bang, MRB_ARGS_NONE());
- mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ"));
- mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!"));
+ mrb_define_alias(mrb, s, "next", "succ");
+ mrb_define_alias(mrb, s, "next!", "succ!");
mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "delete_prefix!", mrb_str_del_prefix_bang, MRB_ARGS_REQ(1));
mrb_define_method(mrb, s, "delete_prefix", mrb_str_del_prefix, MRB_ARGS_REQ(1));
diff --git a/mrblib/hash.rb b/mrblib/hash.rb
index 7e1db905f..96029a230 100644
--- a/mrblib/hash.rb
+++ b/mrblib/hash.rb
@@ -341,11 +341,6 @@ class Hash
}
self.replace(h)
end
-
- def __update(h)
- h.each_key{|k| self[k] = h[k]}
- self
- end
end
##
diff --git a/src/class.c b/src/class.c
index d3a1e2fb2..37bc39c75 100644
--- a/src/class.c
+++ b/src/class.c
@@ -1953,8 +1953,8 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod)
return mrb_nil_value();
}
-static void
-undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a)
+void
+mrb_undef_method_id(mrb_state *mrb, struct RClass *c, mrb_sym a)
{
if (!mrb_obj_respond_to(mrb, c, a)) {
mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c));
@@ -1970,7 +1970,7 @@ undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a)
MRB_API void
mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name)
{
- undef_method(mrb, c, mrb_intern_cstr(mrb, name));
+ mrb_undef_method_id(mrb, c, mrb_intern_cstr(mrb, name));
}
MRB_API void
@@ -1988,7 +1988,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod)
mrb_get_args(mrb, "*", &argv, &argc);
while (argc--) {
- undef_method(mrb, c, to_sym(mrb, *argv));
+ mrb_undef_method_id(mrb, c, to_sym(mrb, *argv));
argv++;
}
return mrb_nil_value();
diff --git a/src/codedump.c b/src/codedump.c
index d79a65a70..80802778f 100644
--- a/src/codedump.c
+++ b/src/codedump.c
@@ -6,451 +6,521 @@
#include <mruby/proc.h>
#ifndef MRB_DISABLE_STDIO
-static int
-print_r(mrb_state *mrb, mrb_irep *irep, size_t n, int pre)
+static void
+print_r(mrb_state *mrb, mrb_irep *irep, size_t n)
{
size_t i;
- if (n == 0) return 0;
+ if (n == 0) return;
for (i=0; i+1<irep->nlocals; i++) {
if (irep->lv[i].r == n) {
mrb_sym sym = irep->lv[i].name;
- if (pre) printf(" ");
- printf("R%d:%s", (int)n, mrb_sym2name(mrb, sym));
- return 1;
+ printf(" R%d:%s", (int)n, mrb_sym2name(mrb, sym));
}
}
- return 0;
}
-#define RA 1
-#define RB 2
-#define RAB 3
-
static void
-print_lv(mrb_state *mrb, mrb_irep *irep, mrb_code c, int r)
+print_lv_a(mrb_state *mrb, mrb_irep *irep, uint16_t a)
{
- int pre = 0;
-
- if (!irep->lv
- || ((!(r & RA) || GETARG_A(c) >= irep->nlocals)
- && (!(r & RB) || GETARG_B(c) >= irep->nlocals))) {
+ if (!irep->lv || a >= irep->nlocals || a == 0) {
printf("\n");
return;
}
- printf("\t; ");
- if (r & RA) {
- pre = print_r(mrb, irep, GETARG_A(c), 0);
- }
- if (r & RB) {
- print_r(mrb, irep, GETARG_B(c), pre);
+ printf("\t;");
+ print_r(mrb, irep, a);
+ printf("\n");
+}
+
+static void
+print_lv_ab(mrb_state *mrb, mrb_irep *irep, uint16_t a, uint16_t b)
+{
+ if (!irep->lv || (a >= irep->nlocals && b >= irep->nlocals) || a+b == 0) {
+ printf("\n");
+ return;
}
+ printf("\t;");
+ if (a > 0) print_r(mrb, irep, a);
+ if (b > 0) print_r(mrb, irep, b);
printf("\n");
}
#endif
static void
+print_header(mrb_irep *irep, ptrdiff_t i)
+{
+ int32_t line;
+
+ line = mrb_debug_get_line(irep, i);
+ if (line < 0) {
+ printf(" ");
+ }
+ else {
+ printf("%5d ", line);
+ }
+
+ printf("%03d ", (int)i);
+}
+
+#define CASE(insn,ops) case insn: FETCH_ ## ops (); L_ ## insn
+
+static void
codedump(mrb_state *mrb, mrb_irep *irep)
{
#ifndef MRB_DISABLE_STDIO
- int i;
int ai;
- mrb_code c;
+ mrb_code *pc, *pcend;
+ mrb_code ins;
const char *file = NULL, *next_file;
- int32_t line;
if (!irep) return;
printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep,
irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen);
- for (i = 0; i < (int)irep->ilen; i++) {
+ if (irep->lv) {
+ int i;
+
+ printf("local variable names:\n");
+ for (i = 1; i < irep->nlocals; ++i) {
+ char const *n = mrb_sym2name(mrb, irep->lv[i - 1].name);
+ printf(" R%d:%s\n", irep->lv[i - 1].r, n? n : "");
+ }
+ }
+
+ pc = irep->iseq;
+ pcend = pc + irep->ilen;
+ while (pc < pcend) {
+ ptrdiff_t i;
+ uint32_t a;
+ uint16_t b;
+ uint8_t c;
+
ai = mrb_gc_arena_save(mrb);
+ i = pc - irep->iseq;
next_file = mrb_debug_get_filename(irep, i);
if (next_file && file != next_file) {
printf("file: %s\n", next_file);
file = next_file;
}
- line = mrb_debug_get_line(irep, i);
- if (line < 0) {
- printf(" ");
- }
- else {
- printf("%5d ", line);
- }
-
- printf("%03d ", i);
- c = irep->iseq[i];
- switch (GET_OPCODE(c)) {
- case OP_NOP:
+ print_header(irep, i);
+ ins = READ_B();
+ switch (ins) {
+ CASE(OP_NOP, Z):
printf("OP_NOP\n");
break;
- case OP_MOVE:
- printf("OP_MOVE\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
- print_lv(mrb, irep, c, RAB);
+ CASE(OP_MOVE, BB):
+ printf("OP_MOVE\tR%d\tR%d\t", a, b);
+ print_lv_ab(mrb, irep, a, b);
break;
- case OP_LOADL:
+ CASE(OP_LOADL, BB):
{
- mrb_value v = irep->pool[GETARG_Bx(c)];
+ mrb_value v = irep->pool[b];
mrb_value s = mrb_inspect(mrb, v);
- printf("OP_LOADL\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s));
+ printf("OP_LOADL\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s));
}
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADI:
- printf("OP_LOADI\tR%d\t%d\t", GETARG_A(c), GETARG_sBx(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADSYM:
- printf("OP_LOADSYM\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADNIL:
- printf("OP_LOADNIL\tR%d\t\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADSELF:
- printf("OP_LOADSELF\tR%d\t\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADT:
- printf("OP_LOADT\tR%d\t\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_LOADF:
- printf("OP_LOADF\tR%d\t\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETGLOBAL:
- printf("OP_GETGLOBAL\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_SETGLOBAL:
- printf("OP_SETGLOBAL\t:%s\tR%d\t",
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
- GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETCONST:
- printf("OP_GETCONST\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_SETCONST:
- printf("OP_SETCONST\t:%s\tR%d\t",
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
- GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETMCNST:
- printf("OP_GETMCNST\tR%d\tR%d::%s", GETARG_A(c), GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RAB);
- break;
- case OP_SETMCNST:
- printf("OP_SETMCNST\tR%d::%s\tR%d", GETARG_A(c)+1,
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
- GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETIV:
- printf("OP_GETIV\tR%d\t%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_SETIV:
- printf("OP_SETIV\t%s\tR%d",
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
- GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETUPVAR:
- printf("OP_GETUPVAR\tR%d\t%d\t%d",
- GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_SETUPVAR:
- printf("OP_SETUPVAR\tR%d\t%d\t%d",
- GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_GETCV:
- printf("OP_GETCV\tR%d\t%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_SETCV:
- printf("OP_SETCV\t%s\tR%d",
- mrb_sym2name(mrb, irep->syms[GETARG_Bx(c)]),
- GETARG_A(c));
- print_lv(mrb, irep, c, RA);
- break;
- case OP_JMP:
- printf("OP_JMP\t%03d (%d)\n", i+GETARG_sBx(c), GETARG_sBx(c));
- break;
- case OP_JMPIF:
- printf("OP_JMPIF\tR%d\t%03d (%d)\n", GETARG_A(c), i+GETARG_sBx(c), GETARG_sBx(c));
- break;
- case OP_JMPNOT:
- printf("OP_JMPNOT\tR%d\t%03d (%d)\n", GETARG_A(c), i+GETARG_sBx(c), GETARG_sBx(c));
- break;
- case OP_SEND:
- printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_SENDB:
- printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_CALL:
- printf("OP_CALL\tR%d\n", GETARG_A(c));
- break;
- case OP_TAILCALL:
- printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_SUPER:
- printf("OP_SUPER\tR%d\t%d\n", GETARG_A(c),
- GETARG_C(c));
- break;
- case OP_ARGARY:
- printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", GETARG_A(c),
- (GETARG_Bx(c)>>10)&0x3f,
- (GETARG_Bx(c)>>9)&0x1,
- (GETARG_Bx(c)>>4)&0x1f,
- (GETARG_Bx(c)>>0)&0xf);
- print_lv(mrb, irep, c, RA);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_LOADI, BB):
+ printf("OP_LOADI\tR%d\t%d\t", a, b);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_LOADINEG, BB):
+ printf("OP_LOADI\tR%d\t-%d\t", a, b);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_LOADI__1, B):
+ printf("OP_LOADI__1\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_LOADI_0, B): goto L_LOADI;
+ CASE(OP_LOADI_1, B): goto L_LOADI;
+ CASE(OP_LOADI_2, B): goto L_LOADI;
+ CASE(OP_LOADI_3, B): goto L_LOADI;
+ CASE(OP_LOADI_4, B): goto L_LOADI;
+ CASE(OP_LOADI_5, B): goto L_LOADI;
+ CASE(OP_LOADI_6, B): goto L_LOADI;
+ CASE(OP_LOADI_7, B):
+ L_LOADI:
+ printf("OP_LOADI_%d\tR%d\t\t", ins-(int)OP_LOADI_0, a);
+ print_lv_a(mrb, irep, a);
break;
-
- case OP_ENTER:
+ CASE(OP_LOADSYM, BB):
+ printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_LOADNIL, B):
+ printf("OP_LOADNIL\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_LOADSELF, B):
+ printf("OP_LOADSELF\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_LOADT, B):
+ printf("OP_LOADT\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_LOADF, B):
+ printf("OP_LOADF\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_GETGV, BB):
+ printf("OP_GETGV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_SETGV, BB):
+ printf("OP_SETGV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_GETSV, BB):
+ printf("OP_GETSV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_SETSV, BB):
+ printf("OP_SETSV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_GETCONST, BB):
+ printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_SETCONST, BB):
+ printf("OP_SETCONST\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_GETMCNST, BB):
+ printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym2name(mrb, irep->syms[b]));
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_SETMCNST, BB):
+ printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym2name(mrb, irep->syms[b]), a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_GETIV, BB):
+ printf("OP_GETIV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_SETIV, BB):
+ printf("OP_SETIV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_GETUPVAR, BBB):
+ printf("OP_GETUPVAR\tR%d\t%d\t%d", a, b, c);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_SETUPVAR, BBB):
+ printf("OP_SETUPVAR\tR%d\t%d\t%d", a, b, c);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_GETCV, BB):
+ printf("OP_GETCV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_SETCV, BB):
+ printf("OP_SETCV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_JMP, S):
+ printf("OP_JMP\t\t%03d\n", a);
+ break;
+ CASE(OP_JMPIF, BS):
+ printf("OP_JMPIF\tR%d\t%03d\t", a, b);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_JMPNOT, BS):
+ printf("OP_JMPNOT\tR%d\t%03d\t", a, b);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_JMPNIL, BS):
+ printf("OP_JMPNIL\tR%d\t%03d\t", a, b);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_SENDV, BB):
+ printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_SENDVB, BB):
+ printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_SEND, BBB):
+ printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c);
+ break;
+ CASE(OP_SENDB, BBB):
+ printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c);
+ break;
+ CASE(OP_CALL, Z):
+ printf("OP_CALL\n");
+ break;
+ CASE(OP_SUPER, BB):
+ printf("OP_SUPER\tR%d\t%d\n", a, b);
+ break;
+ CASE(OP_ARGARY, BS):
+ printf("OP_ARGARY\tR%d\t%d:%d:%d:%d (%d)", a,
+ (b>>11)&0x3f,
+ (b>>10)&0x1,
+ (b>>5)&0x1f,
+ (b>>4)&0x1,
+ (b>>0)&0xf);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_ENTER, W):
printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n",
- (GETARG_Ax(c)>>18)&0x1f,
- (GETARG_Ax(c)>>13)&0x1f,
- (GETARG_Ax(c)>>12)&0x1,
- (GETARG_Ax(c)>>7)&0x1f,
- (GETARG_Ax(c)>>2)&0x1f,
- (GETARG_Ax(c)>>1)&0x1,
- GETARG_Ax(c) & 0x1);
- break;
- case OP_RETURN:
- printf("OP_RETURN\tR%d", GETARG_A(c));
- switch (GETARG_B(c)) {
- case OP_R_NORMAL:
- printf("\tnormal\t"); break;
- case OP_R_RETURN:
- printf("\treturn\t"); break;
- case OP_R_BREAK:
- printf("\tbreak\t"); break;
- default:
- printf("\tbroken\t"); break;
- }
- print_lv(mrb, irep, c, RA);
+ (a>>18)&0x1f,
+ (a>>13)&0x1f,
+ (a>>12)&0x1,
+ (a>>7)&0x1f,
+ (a>>2)&0x1f,
+ (a>>1)&0x1,
+ a & 0x1);
break;
- case OP_BLKPUSH:
- printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", GETARG_A(c),
- (GETARG_Bx(c)>>10)&0x3f,
- (GETARG_Bx(c)>>9)&0x1,
- (GETARG_Bx(c)>>4)&0x1f,
- (GETARG_Bx(c)>>0)&0xf);
- print_lv(mrb, irep, c, RA);
+ CASE(OP_KEY_P, BB):
+ printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
+ print_lv_a(mrb, irep, a);
break;
-
- case OP_LAMBDA:
- printf("OP_LAMBDA\tR%d\tI(%+d)\t", GETARG_A(c), GETARG_b(c)+1);
- switch (GETARG_c(c)) {
- case OP_L_METHOD:
- printf("method"); break;
- case OP_L_BLOCK:
- printf("block"); break;
- case OP_L_LAMBDA:
- printf("lambda"); break;
- }
- print_lv(mrb, irep, c, RA);
+ CASE(OP_KEYEND, Z):
+ printf("OP_KEYEND\n");
break;
- case OP_RANGE:
- printf("OP_RANGE\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RAB);
+ CASE(OP_KARG, BB):
+ printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
+ print_lv_a(mrb, irep, a);
break;
- case OP_METHOD:
- printf("OP_METHOD\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
- print_lv(mrb, irep, c, RA);
+ CASE(OP_RETURN, B):
+ printf("OP_RETURN\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
break;
-
- case OP_ADD:
- printf("OP_ADD\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_ADDI:
- printf("OP_ADDI\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_SUB:
- printf("OP_SUB\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_SUBI:
- printf("OP_SUBI\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_MUL:
- printf("OP_MUL\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_DIV:
- printf("OP_DIV\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_LT:
- printf("OP_LT\t\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_LE:
- printf("OP_LE\t\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_GT:
- printf("OP_GT\t\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_GE:
- printf("OP_GE\t\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
- break;
- case OP_EQ:
- printf("OP_EQ\t\tR%d\t:%s\t%d\n", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
- GETARG_C(c));
+ CASE(OP_RETURN_BLK, B):
+ printf("OP_RETURN_BLK\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
break;
-
- case OP_STOP:
- printf("OP_STOP\n");
+ CASE(OP_BREAK, B):
+ printf("OP_BREAK\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
break;
-
- case OP_ARRAY:
- printf("OP_ARRAY\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RAB);
+ CASE(OP_BLKPUSH, BS):
+ printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)", a,
+ (b>>11)&0x3f,
+ (b>>10)&0x1,
+ (b>>5)&0x1f,
+ (b>>4)&0x1,
+ (b>>0)&0xf);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_LAMBDA, BB):
+ printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]);
+ break;
+ CASE(OP_BLOCK, BB):
+ printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]);
+ break;
+ CASE(OP_METHOD, BB):
+ printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]);
+ break;
+ CASE(OP_RANGE_INC, B):
+ printf("OP_RANGE_INC\tR%d\n", a);
+ break;
+ CASE(OP_RANGE_EXC, B):
+ printf("OP_RANGE_EXC\tR%d\n", a);
+ break;
+ CASE(OP_DEF, BB):
+ printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_UNDEF, B):
+ printf("OP_UNDEF\t:%s\n", mrb_sym2name(mrb, irep->syms[a]));
+ break;
+ CASE(OP_ALIAS, BB):
+ printf("OP_ALIAS\t:%s\t%s\n", mrb_sym2name(mrb, irep->syms[a]), mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_ADD, BB):
+ printf("OP_ADD\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_ADDI, BBB):
+ printf("OP_ADDI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c);
+ break;
+ CASE(OP_SUB, BB):
+ printf("OP_SUB\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_SUBI, BBB):
+ printf("OP_SUBI\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c);
+ break;
+ CASE(OP_MUL, BB):
+ printf("OP_MUL\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_DIV, BB):
+ printf("OP_DIV\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_LT, BB):
+ printf("OP_LT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_LE, BB):
+ printf("OP_LE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_GT, BB):
+ printf("OP_GT\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_GE, BB):
+ printf("OP_GE\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
+ break;
+ CASE(OP_EQ, BB):
+ printf("OP_EQ\t\tR%d\t:%s\t\n", a, mrb_sym2name(mrb, irep->syms[b]));
break;
- case OP_ARYCAT:
- printf("OP_ARYCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
- print_lv(mrb, irep, c, RAB);
+ CASE(OP_ARRAY, BB):
+ printf("OP_ARRAY\tR%d\t%d\t", a, b);
+ print_lv_a(mrb, irep, a);
break;
- case OP_ARYPUSH:
- printf("OP_ARYPUSH\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
- print_lv(mrb, irep, c, RAB);
+ CASE(OP_ARRAY2, BBB):
+ printf("OP_ARRAY\tR%d\tR%d\t%d\t", a, b, c);
+ print_lv_ab(mrb, irep, a, b);
break;
- case OP_AREF:
- printf("OP_AREF\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RAB);
+ CASE(OP_ARYCAT, B):
+ printf("OP_ARYCAT\tR%d\t", a);
+ print_lv_a(mrb, irep, a);
break;
- case OP_APOST:
- printf("OP_APOST\tR%d\t%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RA);
+ CASE(OP_ARYPUSH, B):
+ printf("OP_ARYPUSH\tR%d\t", a);
+ print_lv_a(mrb, irep, a);
break;
- case OP_STRING:
+ CASE(OP_ARYDUP, B):
+ printf("OP_ARYDUP\tR%d\t", a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_AREF, BBB):
+ printf("OP_AREF\tR%d\tR%d\t%d", a, b, c);
+ print_lv_ab(mrb, irep, a, b);
+ break;
+ CASE(OP_ASET, BBB):
+ printf("OP_ASET\tR%d\tR%d\t%d", a, b, c);
+ print_lv_ab(mrb, irep, a, b);
+ break;
+ CASE(OP_APOST, BBB):
+ printf("OP_APOST\tR%d\t%d\t%d", a, b, c);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_INTERN, B):
+ printf("OP_INTERN\tR%d", a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_STRING, BB):
{
- mrb_value v = irep->pool[GETARG_Bx(c)];
+ mrb_value v = irep->pool[b];
mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
- printf("OP_STRING\tR%d\tL(%d)\t; %s", GETARG_A(c), GETARG_Bx(c), RSTRING_PTR(s));
+ printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s));
}
- print_lv(mrb, irep, c, RA);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_STRCAT, B):
+ printf("OP_STRCAT\tR%d\t", a);
+ print_lv_a(mrb, irep, a);
break;
- case OP_STRCAT:
- printf("OP_STRCAT\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
- print_lv(mrb, irep, c, RAB);
+ CASE(OP_HASH, BB):
+ printf("OP_HASH\tR%d\t%d\t", a, b);
+ print_lv_a(mrb, irep, a);
break;
- case OP_HASH:
- printf("OP_HASH\tR%d\tR%d\t%d", GETARG_A(c), GETARG_B(c), GETARG_C(c));
- print_lv(mrb, irep, c, RAB);
+ CASE(OP_HASHADD, BB):
+ printf("OP_HASHADD\tR%d\t%d\t", a, b);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_HASHCAT, B):
+ printf("OP_HASHCAT\tR%d\t", a);
+ print_lv_a(mrb, irep, a);
break;
- case OP_OCLASS:
- printf("OP_OCLASS\tR%d\t\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
+ CASE(OP_OCLASS, B):
+ printf("OP_OCLASS\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
break;
- case OP_CLASS:
- printf("OP_CLASS\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
- print_lv(mrb, irep, c, RA);
+ CASE(OP_CLASS, BB):
+ printf("OP_CLASS\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ print_lv_a(mrb, irep, a);
break;
- case OP_MODULE:
- printf("OP_MODULE\tR%d\t:%s", GETARG_A(c),
- mrb_sym2name(mrb, irep->syms[GETARG_B(c)]));
- print_lv(mrb, irep, c, RA);
+ CASE(OP_MODULE, BB):
+ printf("OP_MODULE\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b]));
+ print_lv_a(mrb, irep, a);
break;
- case OP_EXEC:
- printf("OP_EXEC\tR%d\tI(%+d)", GETARG_A(c), GETARG_Bx(c)+1);
- print_lv(mrb, irep, c, RA);
+ CASE(OP_EXEC, BB):
+ printf("OP_EXEC\tR%d\tI(%d:%p)", a, b, irep->reps[b]);
+ print_lv_a(mrb, irep, a);
break;
- case OP_SCLASS:
- printf("OP_SCLASS\tR%d\tR%d\t", GETARG_A(c), GETARG_B(c));
- print_lv(mrb, irep, c, RAB);
+ CASE(OP_SCLASS, B):
+ printf("OP_SCLASS\tR%d\t", a);
+ print_lv_a(mrb, irep, a);
break;
- case OP_TCLASS:
- printf("OP_TCLASS\tR%d\t\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
+ CASE(OP_TCLASS, B):
+ printf("OP_TCLASS\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
break;
- case OP_ERR:
+ CASE(OP_ERR, B):
{
- mrb_value v = irep->pool[GETARG_Bx(c)];
+ mrb_value v = irep->pool[a];
mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v)));
printf("OP_ERR\t%s\n", RSTRING_PTR(s));
}
break;
- case OP_EPUSH:
- printf("OP_EPUSH\t:I(%+d)\n", GETARG_Bx(c)+1);
+ CASE(OP_EPUSH, B):
+ printf("OP_EPUSH\t\t:I(%d:%p)\n", a, irep->reps[a]);
break;
- case OP_ONERR:
- printf("OP_ONERR\t%03d\n", i+GETARG_sBx(c));
+ CASE(OP_ONERR, S):
+ printf("OP_ONERR\t%03d\n", a);
break;
- case OP_RESCUE:
- {
- int a = GETARG_A(c);
- int b = GETARG_B(c);
- int cnt = GETARG_C(c);
-
- if (b == 0) {
- printf("OP_RESCUE\tR%d\t\t%s", a, cnt ? "cont" : "");
- print_lv(mrb, irep, c, RA);
- break;
- }
- else {
- printf("OP_RESCUE\tR%d\tR%d\t%s", a, b, cnt ? "cont" : "");
- print_lv(mrb, irep, c, RAB);
- break;
- }
- }
+ CASE(OP_EXCEPT, B):
+ printf("OP_EXCEPT\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_RESCUE, BB):
+ printf("OP_RESCUE\tR%d\tR%d", a, b);
+ print_lv_ab(mrb, irep, a, b);
break;
- case OP_RAISE:
- printf("OP_RAISE\tR%d\t\t", GETARG_A(c));
- print_lv(mrb, irep, c, RA);
+ CASE(OP_RAISE, B):
+ printf("OP_RAISE\tR%d\t\t", a);
+ print_lv_a(mrb, irep, a);
break;
- case OP_POPERR:
- printf("OP_POPERR\t%d\t\t\n", GETARG_A(c));
+ CASE(OP_POPERR, B):
+ printf("OP_POPERR\t%d\t\t\n", a);
break;
- case OP_EPOP:
- printf("OP_EPOP\t%d\n", GETARG_A(c));
+ CASE(OP_EPOP, B):
+ printf("OP_EPOP\t%d\n", a);
break;
+ CASE(OP_DEBUG, BBB):
+ printf("OP_DEBUG\t%d\t%d\t%d\n", a, b, c);
+ break;
+
+ CASE(OP_STOP, Z):
+ printf("OP_STOP\n");
+ break;
+
+ CASE(OP_EXT1, Z):
+ ins = READ_B();
+ printf("OP_EXT1\n");
+ print_header(irep, pc-irep->iseq-2);
+ switch (ins) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ break;
+ CASE(OP_EXT2, Z):
+ ins = READ_B();
+ printf("OP_EXT2\n");
+ print_header(irep, pc-irep->iseq-2);
+ switch (ins) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ break;
+ CASE(OP_EXT3, Z):
+ ins = READ_B();
+ printf("OP_EXT3\n");
+ print_header(irep, pc-irep->iseq-2);
+ switch (ins) {
+#define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ break;
+
default:
- printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c),
- GETARG_A(c), GETARG_B(c), GETARG_C(c));
+ printf("OP_unknown (0x%x)\n", ins);
break;
}
mrb_gc_arena_restore(mrb, ai);
diff --git a/src/hash.c b/src/hash.c
index db9d1d9c8..122f5b5d5 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -208,6 +208,54 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
return vret;
}
+void
+mrb_hash_check_kdict(mrb_state *mrb, mrb_value self)
+{
+ khash_t(ht) *orig_h;
+ khiter_t k;
+ int nosym = FALSE;
+
+ orig_h = RHASH_TBL(self);
+ if (!orig_h || kh_size(orig_h) == 0) return;
+ for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) {
+ if (kh_exist(orig_h, k)) {
+ mrb_value key = kh_key(orig_h, k);
+
+ if (!mrb_symbol_p(key)) nosym = TRUE;
+ }
+ }
+ if (nosym) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys");
+ }
+}
+
+MRB_API mrb_value
+mrb_hash_dup(mrb_state *mrb, mrb_value self)
+{
+ struct RHash* copy;
+ khash_t(ht) *orig_h;
+
+ orig_h = RHASH_TBL(self);
+ copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
+ copy->ht = kh_init(ht, mrb);
+
+ if (orig_h && kh_size(orig_h) > 0) {
+ int ai = mrb_gc_arena_save(mrb);
+ khash_t(ht) *copy_h = copy->ht;
+ khiter_t k, copy_k;
+
+ for (k = kh_begin(orig_h); k != kh_end(orig_h); k++) {
+ if (kh_exist(orig_h, k)) {
+ copy_k = kh_put(ht, mrb, copy_h, KEY(kh_key(orig_h, k)));
+ mrb_gc_arena_restore(mrb, ai);
+ kh_val(copy_h, copy_k).v = kh_val(orig_h, k).v;
+ kh_val(copy_h, copy_k).n = kh_size(copy_h)-1;
+ }
+ }
+ }
+ return mrb_obj_value(copy);
+}
+
MRB_API mrb_value
mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
{
@@ -716,13 +764,21 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self)
* {}.empty? #=> true
*
*/
-MRB_API mrb_value
+MRB_API mrb_bool
mrb_hash_empty_p(mrb_state *mrb, mrb_value self)
{
khash_t(ht) *h = RHASH_TBL(self);
- if (h) return mrb_bool_value(kh_size(h) == 0);
- return mrb_true_value();
+ if (h) return kh_size(h) == 0;
+ return TRUE;
+}
+
+static mrb_value
+mrb_hash_empty_m(mrb_state *mrb, mrb_value self)
+{
+ if (mrb_hash_empty_p(mrb, self))
+ return mrb_true_value();
+ return mrb_false_value();
}
/* 15.2.13.4.29 (x)*/
@@ -833,21 +889,29 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash)
*
*/
-static mrb_value
-mrb_hash_has_key(mrb_state *mrb, mrb_value hash)
+MRB_API mrb_bool
+mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key)
{
- mrb_value key;
khash_t(ht) *h;
khiter_t k;
- mrb_get_args(mrb, "o", &key);
-
h = RHASH_TBL(hash);
if (h) {
k = kh_get(ht, mrb, h, key);
- return mrb_bool_value(k != kh_end(h));
+ return k != kh_end(h);
}
- return mrb_false_value();
+ return FALSE;
+}
+
+static mrb_value
+mrb_hash_has_key(mrb_state *mrb, mrb_value hash)
+{
+ mrb_value key;
+ mrb_bool key_p;
+
+ mrb_get_args(mrb, "o", &key);
+ key_p = mrb_hash_key_p(mrb, hash, key);
+ return mrb_bool_value(key_p);
}
/* 15.2.13.4.14 */
@@ -887,6 +951,39 @@ mrb_hash_has_value(mrb_state *mrb, mrb_value hash)
return mrb_false_value();
}
+MRB_API void
+mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2)
+{
+ khash_t(ht) *h1;
+ khash_t(ht) *h2;
+ khiter_t k;
+
+ mrb_hash_modify(mrb, hash1);
+ hash2 = mrb_check_hash_type(mrb, hash2);
+ h1 = RHASH_TBL(hash1);
+ h2 = RHASH_TBL(hash2);
+
+ if (!h1) {
+ RHASH_TBL(hash1) = kh_copy(ht, mrb, h2);
+ return;
+ }
+ for (k = kh_begin(h2); k != kh_end(h2); k++) {
+ khiter_t k1;
+ int r;
+
+ if (!kh_exist(h2, k)) continue;
+ k1 = kh_put2(ht, mrb, h1, kh_key(h2, k), &r);
+ kh_value(h1, k1).v = kh_value(h2,k).v;
+ if (r != 0) {
+ /* expand */
+ kh_key(h1, k1) = kh_key(h2, k);
+ kh_value(h1, k1).n = kh_size(h1)-1;
+ }
+ }
+ mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1));
+ return;
+}
+
void
mrb_init_hash(mrb_state *mrb)
{
@@ -904,7 +1001,7 @@ mrb_init_hash(mrb_state *mrb)
mrb_define_method(mrb, h, "default_proc", mrb_hash_default_proc,MRB_ARGS_NONE()); /* 15.2.13.4.7 */
mrb_define_method(mrb, h, "default_proc=", mrb_hash_set_default_proc,MRB_ARGS_REQ(1)); /* 15.2.13.4.7 */
mrb_define_method(mrb, h, "__delete", mrb_hash_delete, MRB_ARGS_REQ(1)); /* core of 15.2.13.4.8 */
- mrb_define_method(mrb, h, "empty?", mrb_hash_empty_p, MRB_ARGS_NONE()); /* 15.2.13.4.12 */
+ mrb_define_method(mrb, h, "empty?", mrb_hash_empty_m, MRB_ARGS_NONE()); /* 15.2.13.4.12 */
mrb_define_method(mrb, h, "has_key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.13 */
mrb_define_method(mrb, h, "has_value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.14 */
mrb_define_method(mrb, h, "include?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.15 */
diff --git a/src/kernel.c b/src/kernel.c
index 50ad50f00..fed64e9b0 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -1194,7 +1194,15 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
if (!irep->lv) break;
for (i = 0; i + 1 < irep->nlocals; ++i) {
if (irep->lv[i].name) {
- mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value());
+ mrb_sym sym = irep->lv[i].name;
+ const char *name = mrb_sym2name(mrb, sym);
+ switch (name[0]) {
+ case '*': case '&':
+ break;
+ default:
+ mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value());
+ break;
+ }
}
}
if (!MRB_PROC_ENV_P(proc)) break;
@@ -1266,5 +1274,5 @@ mrb_init_kernel(mrb_state *mrb)
mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1));
mrb_include_module(mrb, mrb->object_class, mrb->kernel_module);
- mrb_alias_method(mrb, mrb->module_class, mrb_intern_lit(mrb, "dup"), mrb_intern_lit(mrb, "clone"));
+ mrb_define_alias(mrb, mrb->module_class, "dup", "clone"); /* XXX */
}
diff --git a/src/load.c b/src/load.c
index ddf3cdfbf..54b50b14d 100644
--- a/src/load.c
+++ b/src/load.c
@@ -68,7 +68,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
/* Binary Data Section */
/* ISEQ BLOCK */
- irep->ilen = (size_t)bin_to_uint32(src);
+ irep->ilen = (uint16_t)bin_to_uint32(src);
src += sizeof(uint32_t);
src += skip_padding(src);
@@ -79,7 +79,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
if ((flags & FLAG_SRC_MALLOC) == 0 &&
(flags & FLAG_BYTEORDER_NATIVE)) {
irep->iseq = (mrb_code*)src;
- src += sizeof(uint32_t) * irep->ilen;
+ src += sizeof(mrb_code) * irep->ilen;
irep->flags |= MRB_ISEQ_NO_FREE;
}
else {
@@ -157,7 +157,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
}
/* SYMS BLOCK */
- irep->slen = (size_t)bin_to_uint32(src); /* syms length */
+ irep->slen = (uint16_t)bin_to_uint32(src); /* syms length */
src += sizeof(uint32_t);
if (irep->slen > 0) {
if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) {
diff --git a/src/proc.c b/src/proc.c
index c6e9be433..05b897480 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -10,7 +10,7 @@
#include <mruby/opcode.h>
static mrb_code call_iseq[] = {
- MKOP_A(OP_CALL, 0),
+ OP_CALL,
};
struct RProc*
@@ -223,7 +223,7 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self)
{
struct RProc *p = mrb_proc_ptr(self);
struct mrb_irep *irep;
- mrb_code *iseq;
+ mrb_code *pc;
mrb_aspec aspec;
int ma, op, ra, pa, arity;
@@ -237,13 +237,13 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self)
return mrb_fixnum_value(0);
}
- iseq = irep->iseq;
+ pc = irep->iseq;
/* arity is depend on OP_ENTER */
- if (GET_OPCODE(*iseq) != OP_ENTER) {
+ if (*pc != OP_ENTER) {
return mrb_fixnum_value(0);
}
- aspec = GETARG_Ax(*iseq);
+ aspec = PEEK_W(pc+1);
ma = MRB_ASPEC_REQ(aspec);
op = MRB_ASPEC_OPT(aspec);
ra = MRB_ASPEC_REST(aspec);
diff --git a/src/vm.c b/src/vm.c
index 2bf8f965d..44472e311 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -218,7 +218,7 @@ stack_extend_alloc(mrb_state *mrb, int room)
}
MRB_API void
-mrb_stack_extend(mrb_state *mrb, int room)
+mrb_stack_extend(mrb_state *mrb, mrb_int room)
{
if (mrb->c->stack + room >= mrb->c->stend) {
stack_extend_alloc(mrb, room);
@@ -333,7 +333,7 @@ ecall(mrb_state *mrb)
struct REnv *env;
ptrdiff_t cioff;
int ai = mrb_gc_arena_save(mrb);
- int i = --c->eidx;
+ uint8_t i = --c->eidx;
int nregs;
if (i<0) return;
@@ -934,18 +934,18 @@ argnum_error(mrb_state *mrb, mrb_int num)
#ifndef DIRECT_THREADED
-#define INIT_DISPATCH for (;;) { i = BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (GET_OPCODE(i)) {
-#define CASE(op) case op:
-#define NEXT pc++; break
-#define JUMP break
+#define INIT_DISPATCH for (;;) { insn = BYTECODE_DECODER(*pc); pc++; CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (insn) {
+#define CASE(insn,ops) case insn: pc++; FETCH_ ## ops ();; L_ ## insn ## _BODY:
+#define NEXT break
+#define JUMP NEXT
#define END_DISPATCH }}
#else
#define INIT_DISPATCH JUMP; return mrb_nil_value();
-#define CASE(op) L_ ## op:
-#define NEXT i=BYTECODE_DECODER(*++pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)]
-#define JUMP i=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)]
+#define CASE(insn,ops) L_ ## insn: pc++; FETCH_ ## ops (); L_ ## insn ## _BODY:
+#define NEXT insn=BYTECODE_DECODER(*pc); CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[insn]
+#define JUMP NEXT
#define END_DISPATCH
@@ -981,6 +981,19 @@ mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stac
return result;
}
+static mrb_bool
+check_target_class(mrb_state *mrb)
+{
+ if (!mrb->c->ci->target_class) {
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module");
+ mrb_exc_set(mrb, exc);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
+
MRB_API mrb_value
mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
{
@@ -988,33 +1001,19 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
mrb_irep *irep = proc->body.irep;
mrb_value *pool = irep->pool;
mrb_sym *syms = irep->syms;
- mrb_code i;
+ mrb_code insn;
int ai = mrb_gc_arena_save(mrb);
struct mrb_jmpbuf *prev_jmp = mrb->jmp;
struct mrb_jmpbuf c_jmp;
+ uint32_t a;
+ uint16_t b;
+ uint8_t c;
#ifdef DIRECT_THREADED
static void *optable[] = {
- &&L_OP_NOP, &&L_OP_MOVE,
- &&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL,
- &&L_OP_LOADSELF, &&L_OP_LOADT, &&L_OP_LOADF,
- &&L_OP_GETGLOBAL, &&L_OP_SETGLOBAL, &&L_OP_GETSPECIAL, &&L_OP_SETSPECIAL,
- &&L_OP_GETIV, &&L_OP_SETIV, &&L_OP_GETCV, &&L_OP_SETCV,
- &&L_OP_GETCONST, &&L_OP_SETCONST, &&L_OP_GETMCNST, &&L_OP_SETMCNST,
- &&L_OP_GETUPVAR, &&L_OP_SETUPVAR,
- &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_JMPNOT,
- &&L_OP_ONERR, &&L_OP_RESCUE, &&L_OP_POPERR, &&L_OP_RAISE, &&L_OP_EPUSH, &&L_OP_EPOP,
- &&L_OP_SEND, &&L_OP_SENDB, &&L_OP_FSEND,
- &&L_OP_CALL, &&L_OP_SUPER, &&L_OP_ARGARY, &&L_OP_ENTER,
- &&L_OP_KARG, &&L_OP_KDICT, &&L_OP_RETURN, &&L_OP_TAILCALL, &&L_OP_BLKPUSH,
- &&L_OP_ADD, &&L_OP_ADDI, &&L_OP_SUB, &&L_OP_SUBI, &&L_OP_MUL, &&L_OP_DIV,
- &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE,
- &&L_OP_ARRAY, &&L_OP_ARYCAT, &&L_OP_ARYPUSH, &&L_OP_AREF, &&L_OP_ASET, &&L_OP_APOST,
- &&L_OP_STRING, &&L_OP_STRCAT, &&L_OP_HASH,
- &&L_OP_LAMBDA, &&L_OP_RANGE, &&L_OP_OCLASS,
- &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC,
- &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS,
- &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR,
+#define OPCODE(x,_) &&L_OP_ ## x,
+#include "mruby/ops.h"
+#undef OPCODE
};
#endif
@@ -1035,25 +1034,19 @@ RETRY_TRY_BLOCK:
#define regs (mrb->c->stack)
INIT_DISPATCH {
- CASE(OP_NOP) {
+ CASE(OP_NOP, Z) {
/* do nothing */
NEXT;
}
- CASE(OP_MOVE) {
- /* A B R(A) := R(B) */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
+ CASE(OP_MOVE, BB) {
regs[a] = regs[b];
NEXT;
}
- CASE(OP_LOADL) {
- /* A Bx R(A) := Pool(Bx) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
+ CASE(OP_LOADL, BB) {
#ifdef MRB_WORD_BOXING
- mrb_value val = pool[bx];
+ mrb_value val = pool[b];
#ifndef MRB_WITHOUT_FLOAT
if (mrb_float_p(val)) {
val = mrb_float_value(mrb, mrb_float(val));
@@ -1061,125 +1054,109 @@ RETRY_TRY_BLOCK:
#endif
regs[a] = val;
#else
- regs[a] = pool[bx];
+ regs[a] = pool[b];
#endif
NEXT;
}
- CASE(OP_LOADI) {
- /* A sBx R(A) := sBx */
- int a = GETARG_A(i);
- mrb_int bx = GETARG_sBx(i);
- SET_INT_VALUE(regs[a], bx);
+ CASE(OP_LOADI, BB) {
+ SET_INT_VALUE(regs[a], b);
+ NEXT;
+ }
+
+ CASE(OP_LOADINEG, BB) {
+ SET_INT_VALUE(regs[a], -b);
+ NEXT;
+ }
+
+ CASE(OP_LOADI__1,B) goto L_LOADI;
+ CASE(OP_LOADI_0,B) goto L_LOADI;
+ CASE(OP_LOADI_1,B) goto L_LOADI;
+ CASE(OP_LOADI_2,B) goto L_LOADI;
+ CASE(OP_LOADI_3,B) goto L_LOADI;
+ CASE(OP_LOADI_4,B) goto L_LOADI;
+ CASE(OP_LOADI_5,B) goto L_LOADI;
+ CASE(OP_LOADI_6,B) goto L_LOADI;
+ CASE(OP_LOADI_7, B) {
+ L_LOADI:
+ SET_INT_VALUE(regs[a], (mrb_int)insn - (mrb_int)OP_LOADI_0);
+ NEXT;
+ }
+
+ CASE(OP_LOADSYM, BB) {
+ SET_SYM_VALUE(regs[a], syms[b]);
NEXT;
}
- CASE(OP_LOADSYM) {
- /* A Bx R(A) := Syms(Bx) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- SET_SYM_VALUE(regs[a], syms[bx]);
+ CASE(OP_LOADNIL, B) {
+ SET_NIL_VALUE(regs[a]);
NEXT;
}
- CASE(OP_LOADSELF) {
- /* A R(A) := self */
- int a = GETARG_A(i);
+ CASE(OP_LOADSELF, B) {
regs[a] = regs[0];
NEXT;
}
- CASE(OP_LOADT) {
- /* A R(A) := true */
- int a = GETARG_A(i);
+ CASE(OP_LOADT, B) {
SET_TRUE_VALUE(regs[a]);
NEXT;
}
- CASE(OP_LOADF) {
- /* A R(A) := false */
- int a = GETARG_A(i);
+ CASE(OP_LOADF, B) {
SET_FALSE_VALUE(regs[a]);
NEXT;
}
- CASE(OP_GETGLOBAL) {
- /* A Bx R(A) := getglobal(Syms(Bx)) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- mrb_value val = mrb_gv_get(mrb, syms[bx]);
+ CASE(OP_GETGV, BB) {
+ mrb_value val = mrb_gv_get(mrb, syms[b]);
regs[a] = val;
NEXT;
}
- CASE(OP_SETGLOBAL) {
- /* A Bx setglobal(Syms(Bx), R(A)) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- mrb_gv_set(mrb, syms[bx], regs[a]);
+ CASE(OP_SETGV, BB) {
+ mrb_gv_set(mrb, syms[b], regs[a]);
NEXT;
}
- CASE(OP_GETSPECIAL) {
- /* A Bx R(A) := Special[Bx] */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- mrb_value val = mrb_vm_special_get(mrb, bx);
+ CASE(OP_GETSV, BB) {
+ mrb_value val = mrb_vm_special_get(mrb, b);
regs[a] = val;
NEXT;
}
- CASE(OP_SETSPECIAL) {
- /* A Bx Special[Bx] := R(A) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- mrb_vm_special_set(mrb, bx, regs[a]);
+ CASE(OP_SETSV, BB) {
+ mrb_vm_special_set(mrb, b, regs[a]);
NEXT;
}
- CASE(OP_GETIV) {
- /* A Bx R(A) := ivget(Bx) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- mrb_value val = mrb_iv_get(mrb, regs[0], syms[bx]);
- regs[a] = val;
+ CASE(OP_GETIV, BB) {
+ regs[a] = mrb_iv_get(mrb, regs[0], syms[b]);
NEXT;
}
- CASE(OP_SETIV) {
- /* A Bx ivset(Syms(Bx),R(A)) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- mrb_iv_set(mrb, regs[0], syms[bx], regs[a]);
+ CASE(OP_SETIV, BB) {
+ mrb_iv_set(mrb, regs[0], syms[b], regs[a]);
NEXT;
}
- CASE(OP_GETCV) {
- /* A Bx R(A) := cvget(Syms(Bx)) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
+ CASE(OP_GETCV, BB) {
mrb_value val;
ERR_PC_SET(mrb, pc);
- val = mrb_vm_cv_get(mrb, syms[bx]);
+ val = mrb_vm_cv_get(mrb, syms[b]);
ERR_PC_CLR(mrb);
regs[a] = val;
NEXT;
}
- CASE(OP_SETCV) {
- /* A Bx cvset(Syms(Bx),R(A)) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- mrb_vm_cv_set(mrb, syms[bx], regs[a]);
+ CASE(OP_SETCV, BB) {
+ mrb_vm_cv_set(mrb, syms[b], regs[a]);
NEXT;
}
- CASE(OP_GETCONST) {
- /* A Bx R(A) := constget(Syms(Bx)) */
+ CASE(OP_GETCONST, BB) {
mrb_value val;
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- mrb_sym sym = syms[bx];
+ mrb_sym sym = syms[b];
ERR_PC_SET(mrb, pc);
val = mrb_vm_const_get(mrb, sym);
@@ -1188,40 +1165,27 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_SETCONST) {
- /* A Bx constset(Syms(Bx),R(A)) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- mrb_vm_const_set(mrb, syms[bx], regs[a]);
+ CASE(OP_SETCONST, BB) {
+ mrb_vm_const_set(mrb, syms[b], regs[a]);
NEXT;
}
- CASE(OP_GETMCNST) {
- /* A Bx R(A) := R(A)::Syms(Bx) */
+ CASE(OP_GETMCNST, BB) {
mrb_value val;
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
ERR_PC_SET(mrb, pc);
- val = mrb_const_get(mrb, regs[a], syms[bx]);
+ val = mrb_const_get(mrb, regs[a], syms[b]);
ERR_PC_CLR(mrb);
regs[a] = val;
NEXT;
}
- CASE(OP_SETMCNST) {
- /* A Bx R(A+1)::Syms(Bx) := R(A) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- mrb_const_set(mrb, regs[a+1], syms[bx], regs[a]);
+ CASE(OP_SETMCNST, BB) {
+ mrb_const_set(mrb, regs[a+1], syms[b], regs[a]);
NEXT;
}
- CASE(OP_GETUPVAR) {
- /* A B C R(A) := uvget(B,C) */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
- int c = GETARG_C(i);
+ CASE(OP_GETUPVAR, BBB) {
mrb_value *regs_a = regs + a;
struct REnv *e = uvenv(mrb, c);
@@ -1234,12 +1198,7 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_SETUPVAR) {
- /* A B C uvset(B,C,R(A)) */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
- int c = GETARG_C(i);
-
+ CASE(OP_SETUPVAR, BBB) {
struct REnv *e = uvenv(mrb, c);
if (e) {
@@ -1253,110 +1212,86 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_JMP) {
- /* sBx pc+=sBx */
- int sbx = GETARG_sBx(i);
- pc += sbx;
+ CASE(OP_JMP, S) {
+ pc = irep->iseq+a;
JUMP;
}
-
- CASE(OP_JMPIF) {
- /* A sBx if R(A) pc+=sBx */
- int a = GETARG_A(i);
- int sbx = GETARG_sBx(i);
+ CASE(OP_JMPIF, BS) {
if (mrb_test(regs[a])) {
- pc += sbx;
+ pc = irep->iseq+b;
JUMP;
}
NEXT;
}
-
- CASE(OP_JMPNOT) {
- /* A sBx if !R(A) pc+=sBx */
- int a = GETARG_A(i);
- int sbx = GETARG_sBx(i);
+ CASE(OP_JMPNOT, BS) {
if (!mrb_test(regs[a])) {
- pc += sbx;
+ pc = irep->iseq+b;
+ JUMP;
+ }
+ NEXT;
+ }
+ CASE(OP_JMPNIL, BS) {
+ if (mrb_nil_p(regs[a])) {
+ pc = irep->iseq+b;
JUMP;
}
NEXT;
}
- CASE(OP_ONERR) {
- /* sBx pc+=sBx on exception */
- int sbx = GETARG_sBx(i);
+ CASE(OP_ONERR, S) {
if (mrb->c->rsize <= mrb->c->ci->ridx) {
if (mrb->c->rsize == 0) mrb->c->rsize = RESCUE_STACK_INIT_SIZE;
else mrb->c->rsize *= 2;
- mrb->c->rescue = (mrb_code **)mrb_realloc(mrb, mrb->c->rescue, sizeof(mrb_code*) * mrb->c->rsize);
+ mrb->c->rescue = (uint16_t*)mrb_realloc(mrb, mrb->c->rescue, sizeof(uint16_t) * mrb->c->rsize);
}
- mrb->c->rescue[mrb->c->ci->ridx++] = pc + sbx;
+ mrb->c->rescue[mrb->c->ci->ridx++] = a;
NEXT;
}
- CASE(OP_RESCUE) {
- /* A B R(A) := exc; clear(exc); R(B) := matched (bool) */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
- int c = GETARG_C(i);
- mrb_value exc;
-
- if (c == 0) {
- exc = mrb_obj_value(mrb->exc);
- mrb->exc = 0;
- }
- else { /* continued; exc taken from R(A) */
- exc = regs[a];
- }
- if (b != 0) {
- mrb_value e = regs[b];
- struct RClass *ec;
+ CASE(OP_EXCEPT, B) {
+ mrb_value exc = mrb_obj_value(mrb->exc);
+ mrb->exc = 0;
+ regs[a] = exc;
+ NEXT;
+ }
+ CASE(OP_RESCUE, BB) {
+ mrb_value exc = regs[a]; /* exc on stack */
+ mrb_value e = regs[b];
+ struct RClass *ec;
- switch (mrb_type(e)) {
- case MRB_TT_CLASS:
- case MRB_TT_MODULE:
- break;
- default:
- {
- mrb_value exc;
+ switch (mrb_type(e)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ break;
+ default:
+ {
+ mrb_value exc;
- exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR,
- "class or module required for rescue clause");
- mrb_exc_set(mrb, exc);
- goto L_RAISE;
- }
+ exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR,
+ "class or module required for rescue clause");
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
}
- ec = mrb_class_ptr(e);
- regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec));
- }
- if (a != 0 && c == 0) {
- regs[a] = exc;
}
+ ec = mrb_class_ptr(e);
+ regs[b] = mrb_bool_value(mrb_obj_is_kind_of(mrb, exc, ec));
NEXT;
}
- CASE(OP_POPERR) {
- /* A A.times{rescue_pop()} */
- int a = GETARG_A(i);
-
+ CASE(OP_POPERR, B) {
mrb->c->ci->ridx -= a;
NEXT;
}
- CASE(OP_RAISE) {
- /* A raise(R(A)) */
- int a = GETARG_A(i);
-
+ CASE(OP_RAISE, B) {
mrb_exc_set(mrb, regs[a]);
goto L_RAISE;
}
- CASE(OP_EPUSH) {
- /* Bx ensure_push(SEQ[Bx]) */
- int bx = GETARG_Bx(i);
+ CASE(OP_EPUSH, B) {
struct RProc *p;
- p = mrb_closure_new(mrb, irep->reps[bx]);
+ p = mrb_closure_new(mrb, irep->reps[a]);
/* push ensure_stack */
if (mrb->c->esize <= mrb->c->eidx+1) {
if (mrb->c->esize == 0) mrb->c->esize = ENSURE_STACK_INIT_SIZE;
@@ -1369,11 +1304,9 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_EPOP) {
- /* A A.times{ensure_pop().call} */
- int a = GETARG_A(i);
+ CASE(OP_EPOP, B) {
mrb_callinfo *ci = mrb->c->ci;
- int n, epos = ci->epos;
+ unsigned int n, epos = ci->epos;
mrb_value self = regs[0];
struct RClass *target_class = ci->target_class;
@@ -1381,9 +1314,8 @@ RETRY_TRY_BLOCK:
NEXT;
}
- if (a > mrb->c->eidx - epos)
+ if (a > (int)mrb->c->eidx - epos)
a = mrb->c->eidx - epos;
- pc = pc + 1;
for (n=0; n<a; n++) {
int nregs = irep->nregs;
@@ -1410,29 +1342,32 @@ RETRY_TRY_BLOCK:
JUMP;
}
- CASE(OP_LOADNIL) {
- /* A R(A) := nil */
- int a = GETARG_A(i);
+ CASE(OP_SENDV, BB) {
+ c = CALL_MAXARGS;
+ goto L_SEND;
+ };
- SET_NIL_VALUE(regs[a]);
- NEXT;
- }
+ CASE(OP_SENDVB, BB) {
+ c = CALL_MAXARGS;
+ goto L_SENDB;
+ };
- CASE(OP_SENDB) {
- /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/
- /* fall through */
+ CASE(OP_SEND, BBB)
+ L_SEND:
+ {
+ /* push nil after arguments */
+ int bidx = (c == CALL_MAXARGS) ? a+2 : a+c+1;
+ SET_NIL_VALUE(regs[bidx]);
+ goto L_SENDB;
};
- L_SEND:
- CASE(OP_SEND) {
- /* A B C R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
- int n = GETARG_C(i);
- int argc = (n == CALL_MAXARGS) ? -1 : n;
- int bidx = (argc < 0) ? a+2 : a+n+1;
+ CASE(OP_SENDB, BBB)
+ L_SENDB:
+ {
+ int argc = (c == CALL_MAXARGS) ? -1 : c;
+ int bidx = (argc < 0) ? a+2 : a+c+1;
mrb_method_t m;
- struct RClass *c;
+ struct RClass *cls;
mrb_callinfo *ci = mrb->c->ci;
mrb_value recv, blk;
mrb_sym mid = syms[b];
@@ -1440,26 +1375,20 @@ RETRY_TRY_BLOCK:
mrb_assert(bidx < irep->nregs);
recv = regs[a];
- if (GET_OPCODE(i) != OP_SENDB) {
- SET_NIL_VALUE(regs[bidx]);
- blk = regs[bidx];
- }
- else {
- blk = regs[bidx];
- if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
- blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
- /* The stack might have been reallocated during mrb_convert_type(),
- see #3622 */
- regs[bidx] = blk;
- }
+ blk = regs[bidx];
+ if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
+ blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
+ /* The stack might have been reallocated during mrb_convert_type(),
+ see #3622 */
+ regs[bidx] = blk;
}
- c = mrb_class(mrb, recv);
- m = mrb_method_search_vm(mrb, &c, mid);
+ cls = mrb_class(mrb, recv);
+ m = mrb_method_search_vm(mrb, &cls, mid);
if (MRB_METHOD_UNDEF_P(m)) {
mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
- m = mrb_method_search_vm(mrb, &c, missing);
+ m = mrb_method_search_vm(mrb, &cls, missing);
if (MRB_METHOD_UNDEF_P(m) || (missing == mrb->c->ci->mid && mrb_obj_eq(mrb, regs[0], recv))) {
- mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1);
+ mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, c, regs+a+1);
ERR_PC_SET(mrb, pc);
mrb_method_missing(mrb, mid, recv, args);
}
@@ -1467,7 +1396,7 @@ RETRY_TRY_BLOCK:
if (a+2 >= irep->nregs) {
mrb_stack_extend(mrb, a+3);
}
- regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
+ regs[a+1] = mrb_ary_new_from_values(mrb, c, regs+a+1);
regs[a+2] = blk;
argc = -1;
}
@@ -1479,10 +1408,10 @@ RETRY_TRY_BLOCK:
ci = cipush(mrb);
ci->mid = mid;
ci->stackent = mrb->c->stack;
- ci->target_class = c;
+ ci->target_class = cls;
ci->argc = argc;
- ci->pc = pc + 1;
+ ci->pc = pc;
ci->acc = a;
/* prepare stack */
@@ -1502,12 +1431,10 @@ RETRY_TRY_BLOCK:
mrb_gc_arena_shrink(mrb, ai);
if (mrb->exc) goto L_RAISE;
ci = mrb->c->ci;
- if (GET_OPCODE(i) == OP_SENDB) {
- if (mrb_type(blk) == MRB_TT_PROC) {
- struct RProc *p = mrb_proc_ptr(blk);
- if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) {
- p->flags |= MRB_PROC_ORPHAN;
- }
+ if (mrb_type(blk) == MRB_TT_PROC) {
+ struct RProc *p = mrb_proc_ptr(blk);
+ if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) {
+ p->flags |= MRB_PROC_ORPHAN;
}
}
if (!ci->target_class) { /* return from context modifying method (resume/yield) */
@@ -1542,14 +1469,7 @@ RETRY_TRY_BLOCK:
}
}
- CASE(OP_FSEND) {
- /* A B C R(A) := fcall(R(A),Syms(B),R(A+1),... ,R(A+C-1)) */
- /* not implemented yet */
- NEXT;
- }
-
- CASE(OP_CALL) {
- /* A R(A) := self.call(frame.argc, frame.argv) */
+ CASE(OP_CALL, Z) {
mrb_callinfo *ci;
mrb_value recv = mrb->c->stack[0];
struct RProc *m = mrb_proc_ptr(recv);
@@ -1592,7 +1512,9 @@ RETRY_TRY_BLOCK:
irep = m->body.irep;
if (!irep) {
mrb->c->stack[0] = mrb_nil_value();
- goto L_RETURN;
+ a = 0;
+ c = OP_R_NORMAL;
+ goto L_OP_RETURN_BODY;
}
pool = irep->pool;
syms = irep->syms;
@@ -1613,14 +1535,11 @@ RETRY_TRY_BLOCK:
}
}
- CASE(OP_SUPER) {
- /* A C R(A) := super(R(A+1),... ,R(A+C+1)) */
- int a = GETARG_A(i);
- int n = GETARG_C(i);
- int argc = (n == CALL_MAXARGS) ? -1 : n;
- int bidx = (argc < 0) ? a+2 : a+n+1;
+ CASE(OP_SUPER, BB) {
+ int argc = (b == CALL_MAXARGS) ? -1 : b;
+ int bidx = (argc < 0) ? a+2 : a+b+1;
mrb_method_t m;
- struct RClass *c;
+ struct RClass *cls;
mrb_callinfo *ci = mrb->c->ci;
mrb_value recv, blk;
mrb_sym mid = ci->mid;
@@ -1656,17 +1575,17 @@ RETRY_TRY_BLOCK:
regs[bidx] = blk;
ci = mrb->c->ci;
}
- c = target_class->super;
- m = mrb_method_search_vm(mrb, &c, mid);
+ cls = target_class->super;
+ m = mrb_method_search_vm(mrb, &cls, mid);
if (MRB_METHOD_UNDEF_P(m)) {
mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
if (mid != missing) {
- c = mrb_class(mrb, recv);
+ cls = mrb_class(mrb, recv);
}
- m = mrb_method_search_vm(mrb, &c, missing);
+ m = mrb_method_search_vm(mrb, &cls, missing);
if (MRB_METHOD_UNDEF_P(m)) {
- mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1);
+ mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1);
ERR_PC_SET(mrb, pc);
mrb_method_missing(mrb, mid, recv, args);
}
@@ -1675,7 +1594,7 @@ RETRY_TRY_BLOCK:
if (a+2 >= irep->nregs) {
mrb_stack_extend(mrb, a+3);
}
- regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1);
+ regs[a+1] = mrb_ary_new_from_values(mrb, b, regs+a+1);
regs[a+2] = blk;
argc = -1;
}
@@ -1686,8 +1605,8 @@ RETRY_TRY_BLOCK:
ci = cipush(mrb);
ci->mid = mid;
ci->stackent = mrb->c->stack;
- ci->target_class = c;
- ci->pc = pc + 1;
+ ci->target_class = cls;
+ ci->pc = pc;
ci->argc = argc;
/* prepare stack */
@@ -1739,14 +1658,12 @@ RETRY_TRY_BLOCK:
}
}
- CASE(OP_ARGARY) {
- /* A Bx R(A) := argument array (16=6:1:5:4) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- int m1 = (bx>>10)&0x3f;
- int r = (bx>>9)&0x1;
- int m2 = (bx>>4)&0x1f;
- int lv = (bx>>0)&0xf;
+ CASE(OP_ARGARY, BS) {
+ int m1 = (b>>11)&0x3f;
+ int r = (b>>10)&0x1;
+ int m2 = (b>>5)&0x1f;
+ int kd = (b>>4)&0x1;
+ int lv = (b>>0)&0xf;
mrb_value *stack;
if (mrb->c->ci->mid == 0 || mrb->c->ci->target_class == NULL) {
@@ -1761,12 +1678,12 @@ RETRY_TRY_BLOCK:
else {
struct REnv *e = uvenv(mrb, lv-1);
if (!e) goto L_NOSUPER;
- if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+1)
+ if (MRB_ENV_STACK_LEN(e) <= m1+r+m2+kd+1)
goto L_NOSUPER;
stack = e->stack + 1;
}
if (r == 0) {
- regs[a] = mrb_ary_new_from_values(mrb, m1+m2, stack);
+ regs[a] = mrb_ary_new_from_values(mrb, m1+m2+kd, stack);
}
else {
mrb_value *pp = NULL;
@@ -1779,7 +1696,7 @@ RETRY_TRY_BLOCK:
pp = ARY_PTR(ary);
len = (int)ARY_LEN(ary);
}
- regs[a] = mrb_ary_new_capa(mrb, m1+len+m2);
+ regs[a] = mrb_ary_new_capa(mrb, m1+len+m2+kd);
rest = mrb_ary_ptr(regs[a]);
if (m1 > 0) {
stack_copy(ARY_PTR(rest), stack, m1);
@@ -1790,89 +1707,130 @@ RETRY_TRY_BLOCK:
if (m2 > 0) {
stack_copy(ARY_PTR(rest)+m1+len, stack+m1+1, m2);
}
- ARY_SET_LEN(rest, m1+len+m2);
+ if (kd) {
+ stack_copy(ARY_PTR(rest)+m1+len+m2, stack+m1+m2+1, kd);
+ }
+ ARY_SET_LEN(rest, m1+len+m2+kd);
}
regs[a+1] = stack[m1+r+m2];
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_ENTER) {
- /* Ax arg setup according to flags (23=5:5:1:5:5:1:1) */
- /* number of optional arguments times OP_JMP should follow */
- mrb_aspec ax = GETARG_Ax(i);
- int m1 = MRB_ASPEC_REQ(ax);
- int o = MRB_ASPEC_OPT(ax);
- int r = MRB_ASPEC_REST(ax);
- int m2 = MRB_ASPEC_POST(ax);
+ CASE(OP_ENTER, W) {
+ int m1 = MRB_ASPEC_REQ(a);
+ int o = MRB_ASPEC_OPT(a);
+ int r = MRB_ASPEC_REST(a);
+ int m2 = MRB_ASPEC_POST(a);
+ int kd = (MRB_ASPEC_KEY(a) > 0 || MRB_ASPEC_KDICT(a))? 1 : 0;
/* unused
- int k = MRB_ASPEC_KEY(ax);
- int kd = MRB_ASPEC_KDICT(ax);
- int b = MRB_ASPEC_BLOCK(ax);
+ int b = MRB_ASPEC_BLOCK(a);
*/
int argc = mrb->c->ci->argc;
mrb_value *argv = regs+1;
- mrb_value *argv0 = argv;
- int len = m1 + o + r + m2;
+ mrb_value * const argv0 = argv;
+ int const len = m1 + o + r + m2;
+ int const blk_pos = len + kd + 1;
mrb_value *blk = &argv[argc < 0 ? 1 : argc];
+ mrb_value kdict;
+ int kargs = kd;
+ /* arguments is passed with Array */
if (argc < 0) {
struct RArray *ary = mrb_ary_ptr(regs[1]);
argv = ARY_PTR(ary);
argc = (int)ARY_LEN(ary);
mrb_gc_protect(mrb, regs[1]);
}
+
+ /* strict argument check */
if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) {
- if (argc >= 0) {
- if (argc < m1 + m2 || (r == 0 && argc > len)) {
+ if (argc >= 0 && !(argc <= 1 && kd)) {
+ if (argc < m1 + m2 + kd || (r == 0 && argc > len + kd)) {
argnum_error(mrb, m1+m2);
goto L_RAISE;
}
}
}
+ /* extract first argument array to arguments */
else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) {
mrb_gc_protect(mrb, argv[0]);
argc = (int)RARRAY_LEN(argv[0]);
argv = RARRAY_PTR(argv[0]);
}
- if (argc < len) {
+
+ if (kd) {
+ /* check last arguments is hash if method takes keyword arguments */
+ if (argc == m1+m2) {
+ kdict = mrb_hash_new(mrb);
+ kargs = 0;
+ }
+ else {
+ if (!mrb_hash_p(argv[argc - 1])) {
+ if (r) {
+ kdict = mrb_hash_new(mrb);
+ kargs = 0;
+ }
+ else {
+ mrb_value str = mrb_str_new_lit(mrb, "Excepcted `Hash` as last argument for keyword arguments");
+ mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
+ goto L_RAISE;
+ }
+ }
+ else {
+ kdict = argv[argc-1];
+ }
+ mrb_hash_check_kdict(mrb, kdict);
+ if (MRB_ASPEC_KEY(a) > 0) {
+ kdict = mrb_hash_dup(mrb, kdict);
+ }
+ }
+ }
+
+ /* no rest arguments */
+ if (argc-kargs < len) {
int mlen = m2;
if (argc < m1+m2) {
- if (m1 < argc)
- mlen = argc - m1;
- else
- mlen = 0;
+ mlen = m1 < argc ? argc - m1 : 0;
}
- regs[len+1] = *blk; /* move block */
- SET_NIL_VALUE(regs[argc+1]);
+ regs[blk_pos] = *blk; /* move block */
+ if (kd) regs[len + 1] = kdict;
+
+ /* copy mandatory and optional arguments */
if (argv0 != argv) {
value_move(&regs[1], argv, argc-mlen); /* m1 + o */
}
if (argc < m1) {
stack_clear(&regs[argc+1], m1-argc);
}
+ /* copy post mandatory arguments */
if (mlen) {
value_move(&regs[len-m2+1], &argv[argc-mlen], mlen);
}
if (mlen < m2) {
stack_clear(&regs[len-m2+mlen+1], m2-mlen);
}
+ /* initalize rest arguments with empty Array */
if (r) {
regs[m1+o+1] = mrb_ary_new_capa(mrb, 0);
}
- if (o == 0 || argc < m1+m2) pc++;
- else
- pc += argc - m1 - m2 + 1;
+ /* skip initailizer of passed arguments */
+ if (o > 0 && argc-kargs > m1+m2)
+ pc += (argc - kargs - m1 - m2)*3;
}
else {
int rnum = 0;
if (argv0 != argv) {
- regs[len+1] = *blk; /* move block */
+ regs[blk_pos] = *blk; /* move block */
+ if (kd) regs[len + 1] = kdict;
value_move(&regs[1], argv, m1+o);
}
if (r) {
- rnum = argc-m1-o-m2;
- regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o);
+ mrb_value ary;
+
+ rnum = argc-m1-o-m2-kargs;
+ ary = mrb_ary_new_from_values(mrb, rnum, argv+m1+o);
+ regs[m1+o+1] = ary;
}
if (m2) {
if (argc-m2 > m1) {
@@ -1880,36 +1838,71 @@ RETRY_TRY_BLOCK:
}
}
if (argv0 == argv) {
- regs[len+1] = *blk; /* move block */
+ regs[blk_pos] = *blk; /* move block */
+ if (kd) regs[len + 1] = kdict;
}
- pc += o + 1;
+ pc += o*3;
}
- mrb->c->ci->argc = len;
+
+ /* format arguments for generated code */
+ mrb->c->ci->argc = len + kd;
+
/* clear local (but non-argument) variables */
- if (irep->nlocals-len-2 > 0) {
- stack_clear(&regs[len+2], irep->nlocals-len-2);
+ if (irep->nlocals-blk_pos-1 > 0) {
+ stack_clear(&regs[blk_pos+1], irep->nlocals-blk_pos-1);
}
JUMP;
}
- CASE(OP_KARG) {
- /* A B C R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */
- /* if C == 2; raise unless kdict.empty? */
- /* OP_JMP should follow to skip init code */
+ CASE(OP_KARG, BB) {
+ mrb_value k = mrb_symbol_value(syms[b]);
+ mrb_value kdict = regs[mrb->c->ci->argc];
+
+ if (!mrb_hash_key_p(mrb, kdict, k)) {
+ mrb_value str = mrb_format(mrb, "missing keyword: %S", k);
+ mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
+ goto L_RAISE;
+ }
+ regs[a] = mrb_hash_get(mrb, kdict, k);
+ mrb_hash_delete_key(mrb, kdict, k);
+ NEXT;
+ }
+
+ CASE(OP_KEY_P, BB) {
+ mrb_value k = mrb_symbol_value(syms[b]);
+ mrb_value kdict = regs[mrb->c->ci->argc];
+ mrb_bool key_p = mrb_hash_key_p(mrb, kdict, k);
+
+ regs[a] = mrb_bool_value(key_p);
NEXT;
}
- CASE(OP_KDICT) {
- /* A C R(A) := kdict */
+ CASE(OP_KEYEND, Z) {
+ mrb_value kdict = regs[mrb->c->ci->argc];
+
+ if (mrb_hash_p(kdict) && !mrb_hash_empty_p(mrb, kdict)) {
+ mrb_value keys = mrb_hash_keys(mrb, kdict);
+ mrb_value key1 = RARRAY_PTR(keys)[0];
+ mrb_value str = mrb_format(mrb, "unknown keyword: %S", key1);
+ mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
+ goto L_RAISE;
+ }
NEXT;
}
+ CASE(OP_BREAK, B) {
+ c = OP_R_BREAK;
+ goto L_RETURN;
+ }
+ CASE(OP_RETURN_BLK, B) {
+ c = OP_R_RETURN;
+ goto L_RETURN;
+ }
+ CASE(OP_RETURN, B)
+ c = OP_R_NORMAL;
L_RETURN:
- i = MKOP_AB(OP_RETURN, GETARG_A(i), OP_R_NORMAL);
- /* fall through */
- CASE(OP_RETURN) {
- /* A B return R(A) (B=normal,in-block return/break) */
- mrb_callinfo *ci;
+ {
+ mrb_callinfo *ci;
#define ecall_adjust() do {\
ptrdiff_t cioff = ci - mrb->c->cibase;\
@@ -1995,7 +1988,7 @@ RETRY_TRY_BLOCK:
mrb->c->stack = ci[1].stackent;
}
mrb_stack_extend(mrb, irep->nregs);
- pc = mrb->c->rescue[--ci->ridx];
+ pc = irep->iseq+mrb->c->rescue[--ci->ridx];
}
else {
int acc;
@@ -2003,9 +1996,9 @@ RETRY_TRY_BLOCK:
struct RProc *dst;
ci = mrb->c->ci;
- v = regs[GETARG_A(i)];
+ v = regs[a];
mrb_gc_protect(mrb, v);
- switch (GETARG_B(i)) {
+ switch (c) {
case OP_R_RETURN:
/* Fall through to OP_R_NORMAL otherwise */
if (ci->acc >=0 && MRB_PROC_ENV_P(proc) && !MRB_PROC_STRICT_P(proc)) {
@@ -2040,8 +2033,7 @@ RETRY_TRY_BLOCK:
struct mrb_context *c;
if (!mrb->c->prev) { /* toplevel return */
- localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
- goto L_RAISE;
+ goto L_STOP;
}
if (mrb->c->prev->ci == mrb->c->prev->cibase) {
mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume");
@@ -2160,91 +2152,12 @@ RETRY_TRY_BLOCK:
JUMP;
}
- CASE(OP_TAILCALL) {
- /* A B C return call(R(A),Syms(B),R(A+1),... ,R(A+C+1)) */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
- int n = GETARG_C(i);
- mrb_method_t m;
- struct RClass *c;
- mrb_callinfo *ci;
- mrb_value recv;
- mrb_sym mid = syms[b];
-
- recv = regs[a];
- c = mrb_class(mrb, recv);
- m = mrb_method_search_vm(mrb, &c, mid);
- if (MRB_METHOD_UNDEF_P(m)) {
- mrb_value sym = mrb_symbol_value(mid);
- mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
- m = mrb_method_search_vm(mrb, &c, missing);
- if (MRB_METHOD_UNDEF_P(m)) {
- mrb_value args;
-
- if (n == CALL_MAXARGS) {
- args = regs[a+1];
- }
- else {
- args = mrb_ary_new_from_values(mrb, n, regs+a+1);
- }
- ERR_PC_SET(mrb, pc);
- mrb_method_missing(mrb, mid, recv, args);
- }
- mid = missing;
- if (n == CALL_MAXARGS) {
- mrb_ary_unshift(mrb, regs[a+1], sym);
- }
- else {
- value_move(regs+a+2, regs+a+1, ++n);
- regs[a+1] = sym;
- }
- }
-
- /* replace callinfo */
- ci = mrb->c->ci;
- ci->mid = mid;
- ci->target_class = c;
- if (n == CALL_MAXARGS) {
- ci->argc = -1;
- }
- else {
- ci->argc = n;
- }
-
- /* move stack */
- value_move(mrb->c->stack, &regs[a], ci->argc+1);
-
- if (MRB_METHOD_CFUNC_P(m)) {
- mrb_value v = MRB_METHOD_CFUNC(m)(mrb, recv);
- mrb->c->stack[0] = v;
- mrb_gc_arena_restore(mrb, ai);
- goto L_RETURN;
- }
- else {
- /* setup environment for calling method */
- struct RProc *p = MRB_METHOD_PROC(m);
- irep = p->body.irep;
- pool = irep->pool;
- syms = irep->syms;
- if (ci->argc < 0) {
- mrb_stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs);
- }
- else {
- mrb_stack_extend(mrb, irep->nregs);
- }
- pc = irep->iseq;
- }
- JUMP;
- }
-
- CASE(OP_BLKPUSH) {
- /* A Bx R(A) := block (16=6:1:5:4) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
- int m1 = (bx>>10)&0x3f;
- int r = (bx>>9)&0x1;
- int m2 = (bx>>4)&0x1f;
- int lv = (bx>>0)&0xf;
+ CASE(OP_BLKPUSH, BS) {
+ int m1 = (b>>11)&0x3f;
+ int r = (b>>10)&0x1;
+ int m2 = (b>>5)&0x1f;
+ int kd = (b>>4)&0x1;
+ int lv = (b>>0)&0xf;
mrb_value *stack;
if (lv == 0) stack = regs + 1;
@@ -2261,7 +2174,7 @@ RETRY_TRY_BLOCK:
localjump_error(mrb, LOCALJUMP_ERROR_YIELD);
goto L_RAISE;
}
- regs[a] = stack[m1+r+m2];
+ regs[a] = stack[m1+r+m2+kd];
NEXT;
}
@@ -2270,10 +2183,7 @@ RETRY_TRY_BLOCK:
v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\
} while(0)
- CASE(OP_ADD) {
- /* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/
- int a = GETARG_A(i);
-
+ CASE(OP_ADD, BB) {
/* need to check if op is overridden */
switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
@@ -2327,16 +2237,14 @@ RETRY_TRY_BLOCK:
regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]);
break;
default:
+ c = 1;
goto L_SEND;
}
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_SUB) {
- /* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/
- int a = GETARG_A(i);
-
+ CASE(OP_SUB, BB) {
/* need to check if op is overridden */
switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
@@ -2386,15 +2294,13 @@ RETRY_TRY_BLOCK:
break;
#endif
default:
+ c = 1;
goto L_SEND;
}
NEXT;
}
- CASE(OP_MUL) {
- /* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/
- int a = GETARG_A(i);
-
+ CASE(OP_MUL, BB) {
/* need to check if op is overridden */
switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
@@ -2444,14 +2350,13 @@ RETRY_TRY_BLOCK:
break;
#endif
default:
+ c = 1;
goto L_SEND;
}
NEXT;
}
- CASE(OP_DIV) {
- /* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/
- int a = GETARG_A(i);
+ CASE(OP_DIV, BB) {
#ifndef MRB_WITHOUT_FLOAT
double x, y, f;
#endif
@@ -2484,6 +2389,7 @@ RETRY_TRY_BLOCK:
break;
#endif
default:
+ c = 1;
goto L_SEND;
}
@@ -2501,16 +2407,13 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_ADDI) {
- /* A B C R(A) := R(A)+C (Syms[B]=:+)*/
- int a = GETARG_A(i);
-
+ CASE(OP_ADDI, BBB) {
/* need to check if + is overridden */
switch (mrb_type(regs[a])) {
case MRB_TT_FIXNUM:
{
mrb_int x = mrb_fixnum(regs[a]);
- mrb_int y = GETARG_C(i);
+ mrb_int y = (mrb_int)c;
mrb_int z;
if (mrb_int_add_overflow(x, y, &z)) {
@@ -2527,24 +2430,22 @@ RETRY_TRY_BLOCK:
#ifdef MRB_WORD_BOXING
{
mrb_float x = mrb_float(regs[a]);
- SET_FLOAT_VALUE(mrb, regs[a], x + GETARG_C(i));
+ SET_FLOAT_VALUE(mrb, regs[a], x + c);
}
#else
- mrb_float(regs[a]) += GETARG_C(i);
+ mrb_float(regs[a]) += c;
#endif
break;
#endif
default:
- SET_INT_VALUE(regs[a+1], GETARG_C(i));
- i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
+ SET_INT_VALUE(regs[a+1], c);
+ c = 1;
goto L_SEND;
}
NEXT;
}
- CASE(OP_SUBI) {
- /* A B C R(A) := R(A)-C (Syms[B]=:-)*/
- int a = GETARG_A(i);
+ CASE(OP_SUBI, BBB) {
mrb_value *regs_a = regs + a;
/* need to check if + is overridden */
@@ -2552,7 +2453,7 @@ RETRY_TRY_BLOCK:
case MRB_TT_FIXNUM:
{
mrb_int x = mrb_fixnum(regs_a[0]);
- mrb_int y = GETARG_C(i);
+ mrb_int y = (mrb_int)c;
mrb_int z;
if (mrb_int_sub_overflow(x, y, &z)) {
@@ -2569,16 +2470,16 @@ RETRY_TRY_BLOCK:
#ifdef MRB_WORD_BOXING
{
mrb_float x = mrb_float(regs[a]);
- SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i));
+ SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)c);
}
#else
- mrb_float(regs_a[0]) -= GETARG_C(i);
+ mrb_float(regs_a[0]) -= c;
#endif
break;
#endif
default:
- SET_INT_VALUE(regs_a[1], GETARG_C(i));
- i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
+ SET_INT_VALUE(regs_a[1], c);
+ c = 1;
goto L_SEND;
}
NEXT;
@@ -2595,6 +2496,7 @@ RETRY_TRY_BLOCK:
result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\
break;\
default:\
+ c = 1;\
goto L_SEND;\
}\
if (result) {\
@@ -2622,6 +2524,7 @@ RETRY_TRY_BLOCK:
result = OP_CMP_BODY(op,mrb_float,mrb_float);\
break;\
default:\
+ c = 1;\
goto L_SEND;\
}\
if (result) {\
@@ -2633,9 +2536,7 @@ RETRY_TRY_BLOCK:
} while(0)
#endif
- CASE(OP_EQ) {
- /* A B C R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1)*/
- int a = GETARG_A(i);
+ CASE(OP_EQ, BB) {
if (mrb_obj_eq(mrb, regs[a], regs[a+1])) {
SET_TRUE_VALUE(regs[a]);
}
@@ -2645,68 +2546,59 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_LT) {
- /* A B C R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
- int a = GETARG_A(i);
+ CASE(OP_LT, BB) {
OP_CMP(<);
NEXT;
}
- CASE(OP_LE) {
- /* A B C R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1)*/
- int a = GETARG_A(i);
+ CASE(OP_LE, BB) {
OP_CMP(<=);
NEXT;
}
- CASE(OP_GT) {
- /* A B C R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1)*/
- int a = GETARG_A(i);
+ CASE(OP_GT, BB) {
OP_CMP(>);
NEXT;
}
- CASE(OP_GE) {
- /* A B C R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)*/
- int a = GETARG_A(i);
+ CASE(OP_GE, BB) {
OP_CMP(>=);
NEXT;
}
- CASE(OP_ARRAY) {
- /* A B C R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
- int c = GETARG_C(i);
+ CASE(OP_ARRAY, BB) {
+ mrb_value v = mrb_ary_new_from_values(mrb, b, &regs[a]);
+ regs[a] = v;
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+ CASE(OP_ARRAY2, BBB) {
mrb_value v = mrb_ary_new_from_values(mrb, c, &regs[b]);
regs[a] = v;
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_ARYCAT) {
- /* A B mrb_ary_concat(R(A),R(B)) */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
- mrb_value splat = mrb_ary_splat(mrb, regs[b]);
+ CASE(OP_ARYCAT, B) {
+ mrb_value splat = mrb_ary_splat(mrb, regs[a+1]);
mrb_ary_concat(mrb, regs[a], splat);
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_ARYPUSH) {
- /* A B R(A).push(R(B)) */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
- mrb_ary_push(mrb, regs[a], regs[b]);
+ CASE(OP_ARYPUSH, B) {
+ mrb_ary_push(mrb, regs[a], regs[a+1]);
NEXT;
}
- CASE(OP_AREF) {
- /* A B C R(A) := R(B)[C] */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
- int c = GETARG_C(i);
+ CASE(OP_ARYDUP, B) {
+ mrb_value ary = regs[a];
+ ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary));
+ regs[a] = ary;
+ NEXT;
+ }
+
+ CASE(OP_AREF, BBB) {
mrb_value v = regs[b];
if (!mrb_array_p(v)) {
@@ -2724,21 +2616,15 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_ASET) {
- /* A B C R(B)[C] := R(A) */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
- int c = GETARG_C(i);
+ CASE(OP_ASET, BBB) {
mrb_ary_set(mrb, regs[b], c, regs[a]);
NEXT;
}
- CASE(OP_APOST) {
- /* A B C *R(A),R(A+1)..R(A+C) := R(A)[B..] */
- int a = GETARG_A(i);
+ CASE(OP_APOST, BBB) {
mrb_value v = regs[a];
- int pre = GETARG_B(i);
- int post = GETARG_C(i);
+ int pre = b;
+ int post = c;
struct RArray *ary;
int len, idx;
@@ -2769,48 +2655,62 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_STRING) {
- /* A Bx R(A) := str_new(Lit(Bx)) */
- mrb_int a = GETARG_A(i);
- mrb_int bx = GETARG_Bx(i);
- mrb_value str = mrb_str_dup(mrb, pool[bx]);
+ CASE(OP_INTERN, B) {
+ mrb_sym sym = mrb_intern_str(mrb, regs[a]);
+
+ regs[a] = mrb_symbol_value(sym);
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_STRING, BB) {
+ mrb_value str = mrb_str_dup(mrb, pool[b]);
regs[a] = str;
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_STRCAT) {
- /* A B R(A).concat(R(B)) */
- mrb_int a = GETARG_A(i);
- mrb_int b = GETARG_B(i);
+ CASE(OP_STRCAT, B) {
+ mrb_str_concat(mrb, regs[a], regs[a+1]);
+ NEXT;
+ }
+
+ CASE(OP_HASH, BB) {
+ mrb_value hash = mrb_hash_new_capa(mrb, b);
+ int i;
+ int lim = a+b*2;
- mrb_str_concat(mrb, regs[a], regs[b]);
+ for (i=a; i<lim; i+=2) {
+ mrb_hash_set(mrb, hash, regs[i], regs[i+1]);
+ }
+ regs[a] = hash;
+ mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_HASH) {
- /* A B C R(A) := hash_new(R(B),R(B+1)..R(B+C)) */
- int b = GETARG_B(i);
- int c = GETARG_C(i);
- int lim = b+c*2;
- mrb_value hash = mrb_hash_new_capa(mrb, c);
+ CASE(OP_HASHADD, BB) {
+ mrb_value hash = regs[a];
+ int i;
+ int lim = a+b*2+1;
- while (b < lim) {
- mrb_hash_set(mrb, hash, regs[b], regs[b+1]);
- b+=2;
+ for (i=a+1; i<lim; i+=2) {
+ mrb_hash_set(mrb, hash, regs[i], regs[i+1]);
}
- regs[GETARG_A(i)] = hash;
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+ CASE(OP_HASHCAT, B) {
+ mrb_hash_merge(mrb, regs[a], regs[a+1]);
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_LAMBDA) {
- /* A b c R(A) := lambda(SEQ[b],c) (b:c = 14:2) */
+ CASE(OP_LAMBDA, BB)
+ c = OP_L_LAMBDA;
+ L_MAKE_LAMBDA:
+ {
struct RProc *p;
- int a = GETARG_A(i);
- int b = GETARG_b(i);
- int c = GETARG_c(i);
mrb_irep *nirep = irep->reps[b];
if (c & OP_L_CAPTURE) {
@@ -2825,19 +2725,38 @@ RETRY_TRY_BLOCK:
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
+ CASE(OP_BLOCK, BB) {
+ c = OP_L_BLOCK;
+ goto L_MAKE_LAMBDA;
+ }
+ CASE(OP_METHOD, BB) {
+ c = OP_L_METHOD;
+ goto L_MAKE_LAMBDA;
+ }
+
+ CASE(OP_RANGE_INC, B) {
+ mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], FALSE);
+ regs[a] = val;
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
+
+ CASE(OP_RANGE_EXC, B) {
+ mrb_value val = mrb_range_new(mrb, regs[a], regs[a+1], TRUE);
+ regs[a] = val;
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
- CASE(OP_OCLASS) {
- /* A R(A) := ::Object */
- regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class);
+ CASE(OP_OCLASS, B) {
+ regs[a] = mrb_obj_value(mrb->object_class);
NEXT;
}
- CASE(OP_CLASS) {
- /* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */
+ CASE(OP_CLASS, BB) {
struct RClass *c = 0, *baseclass;
- int a = GETARG_A(i);
mrb_value base, super;
- mrb_sym id = syms[GETARG_B(i)];
+ mrb_sym id = syms[b];
base = regs[a];
super = regs[a+1];
@@ -2851,32 +2770,27 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_MODULE) {
- /* A B R(A) := newmodule(R(A),Syms(B)) */
- struct RClass *c = 0, *baseclass;
- int a = GETARG_A(i);
+ CASE(OP_MODULE, BB) {
+ struct RClass *cls = 0, *baseclass;
mrb_value base;
- mrb_sym id = syms[GETARG_B(i)];
+ mrb_sym id = syms[b];
base = regs[a];
if (mrb_nil_p(base)) {
baseclass = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
base = mrb_obj_value(baseclass);
}
- c = mrb_vm_define_module(mrb, base, id);
- regs[a] = mrb_obj_value(c);
+ cls = mrb_vm_define_module(mrb, base, id);
+ regs[a] = mrb_obj_value(cls);
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_EXEC) {
- /* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */
- int a = GETARG_A(i);
- int bx = GETARG_Bx(i);
+ CASE(OP_EXEC, BB) {
mrb_callinfo *ci;
mrb_value recv = regs[a];
struct RProc *p;
- mrb_irep *nirep = irep->reps[bx];
+ mrb_irep *nirep = irep->reps[b];
/* prepare closure */
p = mrb_proc_new(mrb, nirep);
@@ -2887,7 +2801,7 @@ RETRY_TRY_BLOCK:
/* prepare call stack */
ci = cipush(mrb);
- ci->pc = pc + 1;
+ ci->pc = pc;
ci->acc = a;
ci->mid = 0;
ci->stackent = mrb->c->stack;
@@ -2909,56 +2823,53 @@ RETRY_TRY_BLOCK:
JUMP;
}
- CASE(OP_METHOD) {
- /* A B R(A).newmethod(Syms(B),R(A+1)) */
- int a = GETARG_A(i);
- struct RClass *c = mrb_class_ptr(regs[a]);
+ CASE(OP_DEF, BB) {
+ struct RClass *target = mrb_class_ptr(regs[a]);
struct RProc *p = mrb_proc_ptr(regs[a+1]);
mrb_method_t m;
MRB_METHOD_FROM_PROC(m, p);
- mrb_define_method_raw(mrb, c, syms[GETARG_B(i)], m);
+ mrb_define_method_raw(mrb, target, syms[b], m);
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_SCLASS) {
- /* A B R(A) := R(B).singleton_class */
- int a = GETARG_A(i);
- int b = GETARG_B(i);
-
- regs[a] = mrb_singleton_class(mrb, regs[b]);
+ CASE(OP_SCLASS, B) {
+ regs[a] = mrb_singleton_class(mrb, regs[a]);
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
- CASE(OP_TCLASS) {
- /* A R(A) := target_class */
- if (!mrb->c->ci->target_class) {
- mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module");
- mrb_exc_set(mrb, exc);
- goto L_RAISE;
- }
- regs[GETARG_A(i)] = mrb_obj_value(mrb->c->ci->target_class);
+ CASE(OP_TCLASS, B) {
+ if (!check_target_class(mrb)) goto L_RAISE;
+ regs[a] = mrb_obj_value(mrb->c->ci->target_class);
NEXT;
}
- CASE(OP_RANGE) {
- /* A B C R(A) := range_new(R(B),R(B+1),C) */
- int b = GETARG_B(i);
- mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
- regs[GETARG_A(i)] = val;
- mrb_gc_arena_restore(mrb, ai);
+ CASE(OP_ALIAS, BB) {
+ struct RClass *target;
+
+ if (!check_target_class(mrb)) goto L_RAISE;
+ target = mrb->c->ci->target_class;
+ mrb_alias_method(mrb, target, syms[a], syms[b]);
+ NEXT;
+ }
+ CASE(OP_UNDEF, B) {
+ struct RClass *target;
+
+ if (!check_target_class(mrb)) goto L_RAISE;
+ target = mrb->c->ci->target_class;
+ mrb_undef_method_id(mrb, target, syms[a]);
NEXT;
}
- CASE(OP_DEBUG) {
- /* A B C debug print R(A),R(B),R(C) */
+ CASE(OP_DEBUG, Z) {
+ FETCH_BBB();
#ifdef MRB_ENABLE_DEBUG_HOOK
mrb->debug_op_hook(mrb, irep, pc, regs);
#else
#ifndef MRB_DISABLE_STDIO
- printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i));
+ printf("OP_DEBUG %d %d %d\n", a, b, c);
#else
abort();
#endif
@@ -2966,7 +2877,48 @@ RETRY_TRY_BLOCK:
NEXT;
}
- CASE(OP_STOP) {
+ CASE(OP_ERR, B) {
+ mrb_value msg = mrb_str_dup(mrb, pool[a]);
+ mrb_value exc;
+
+ exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
+ ERR_PC_SET(mrb, pc);
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
+
+ CASE(OP_EXT1, Z) {
+ insn = READ_B();
+ switch (insn) {
+#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _1(); goto L_OP_ ## insn ## _BODY;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ pc--;
+ NEXT;
+ }
+ CASE(OP_EXT2, Z) {
+ insn = READ_B();
+ switch (insn) {
+#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _2(); goto L_OP_ ## insn ## _BODY;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ pc--;
+ NEXT;
+ }
+ CASE(OP_EXT3, Z) {
+ uint8_t insn = READ_B();
+ switch (insn) {
+#define OPCODE(insn,ops) case OP_ ## insn: FETCH_ ## ops ## _3(); goto L_OP_ ## insn ## _BODY;
+#include "mruby/ops.h"
+#undef OPCODE
+ }
+ pc--;
+ NEXT;
+ }
+
+ CASE(OP_STOP, Z) {
/* stop VM */
L_STOP:
while (mrb->c->eidx > 0) {
@@ -2979,26 +2931,9 @@ RETRY_TRY_BLOCK:
}
return regs[irep->nlocals];
}
-
- CASE(OP_ERR) {
- /* Bx raise RuntimeError with message Lit(Bx) */
- mrb_value msg = mrb_str_dup(mrb, pool[GETARG_Bx(i)]);
- mrb_value exc;
-
- if (GETARG_A(i) == 0) {
- exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, msg);
- }
- else {
- exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
- }
- ERR_PC_SET(mrb, pc);
- mrb_exc_set(mrb, exc);
- goto L_RAISE;
- }
}
END_DISPATCH;
#undef regs
-
}
MRB_CATCH(&c_jmp) {
exc_catched = TRUE;
diff --git a/test/t/syntax.rb b/test/t/syntax.rb
index 299394557..c5405aa9c 100644
--- a/test/t/syntax.rb
+++ b/test/t/syntax.rb
@@ -403,6 +403,9 @@ assert('External command execution.') do
assert_equal 'test dynamic `', t
assert_equal ['test', 'test dynamic `', 'test', 'test dynamic `'], results
+ results = []
+ assert_equal 'test sym test sym test', `test #{:sym} test #{:sym} test`
+
alias_method sym, :old_cmd
end
true
@@ -466,3 +469,184 @@ this is a comment that has extra after =begin and =end with tabs after it
=end xxxxxxxxxxxxxxxxxxxxxxxxxx
assert_equal(line + 4, __LINE__)
end
+
+assert 'keyword arguments' do
+ def m(a, b:) [a, b] end
+ assert_equal [1, 2], m(1, b: 2)
+ assert_raise(ArgumentError) { m b: 1 }
+ assert_raise(ArgumentError) { m 1 }
+
+ def m(a:) a end
+ assert_equal 1, m(a: 1)
+ assert_raise(ArgumentError) { m }
+ assert_raise(ArgumentError) { m 'a' => 1, a: 1 }
+ h = { a: 1 }
+ assert_equal 1, m(h)
+ assert_equal({ a: 1 }, h)
+
+ def m(a: 1) a end
+ assert_equal 1, m
+ assert_equal 2, m(a: 2)
+ assert_raise(ArgumentError) { m 1 }
+
+ def m(**) end
+ assert_nil m
+ assert_nil m a: 1, b: 2
+ assert_raise(ArgumentError) { m 2 }
+
+ def m(a, **) a end
+ assert_equal 1, m(1)
+ assert_equal 1, m(1, a: 2, b: 3)
+ assert_equal({ 'a' => 1, b: 2 }, m('a' => 1, b: 2))
+
+ def m(a, **k) [a, k] end
+ assert_equal [1, {}], m(1)
+ assert_equal [1, {a: 2, b: 3}], m(1, a: 2, b: 3)
+ assert_equal [{'a' => 1, b: 2}, {}], m('a' => 1, b: 2)
+
+ def m(a=1, **) a end
+ assert_equal 1, m
+ assert_equal 2, m(2, a: 1, b: 0)
+ assert_raise(ArgumentError) { m('a' => 1, a: 2) }
+
+ def m(a=1, **k) [a, k] end
+ assert_equal [1, {}], m
+ assert_equal [1, {a: 1}], m(a: 1)
+ assert_equal [2, {a: 1, b: 2}], m(2, a: 1, b: 2)
+ assert_equal [{a: 1}, {b: 2}], m({a: 1}, {b: 2})
+
+ def m(*, a:) a end
+ assert_equal 1, m(a: 1)
+ assert_equal 3, m(1, 2, a: 3)
+ assert_raise(ArgumentError) { m('a' => 1, a: 2) }
+
+ def m(*a, b:) [a, b] end
+ assert_equal [[], 1], m(b: 1)
+ assert_equal [[1, 2], 3], m(1, 2, b: 3)
+ assert_raise(ArgumentError) { m('a' => 1, b: 2) }
+
+ def m(*a, b: 1) [a, b] end
+ assert_equal [[], 1], m
+ assert_equal [[1, 2, 3], 4], m(1, 2, 3, b: 4)
+ assert_raise(ArgumentError) { m('a' => 1, b: 2) }
+
+ def m(*, **) end
+ assert_nil m()
+ assert_nil m(a: 1, b: 2)
+ assert_nil m(1, 2, 3, a: 4, b: 5)
+
+ def m(*a, **) a end
+ assert_equal [], m()
+ assert_equal [1, 2, 3], m(1, 2, 3, a: 4, b: 5)
+ assert_raise(ArgumentError) { m("a" => 1, a: 1) }
+ assert_equal [1], m(1, **{a: 2})
+
+ def m(*, **k) k end
+ assert_equal({}, m())
+ assert_equal({a: 4, b: 5}, m(1, 2, 3, a: 4, b: 5))
+ assert_raise(ArgumentError) { m("a" => 1, a: 1) }
+
+ def m(a = nil, b = nil, **k) [a, k] end
+ assert_equal [nil, {}], m()
+ assert_equal([nil, {a: 1}], m(a: 1))
+ assert_raise(ArgumentError) { m("a" => 1, a: 1) }
+ assert_equal([{"a" => 1}, {a: 1}], m({ "a" => 1 }, a: 1))
+ assert_equal([{a: 1}, {}], m({a: 1}, {}))
+ assert_equal([nil, {}], m({}))
+
+ def m(*a, **k) [a, k] end
+ assert_equal([[], {}], m())
+ assert_equal([[1], {}], m(1))
+ assert_equal([[], {a: 1, b: 2}], m(a: 1, b: 2))
+ assert_equal([[1, 2, 3], {a: 2}], m(1, 2, 3, a: 2))
+ assert_raise(ArgumentError) { m("a" => 1, a: 1) }
+ assert_raise(ArgumentError) { m("a" => 1) }
+ assert_equal([[], {a: 1}], m(a: 1))
+ assert_raise(ArgumentError) { m("a" => 1, a: 1) }
+ assert_equal([[{"a" => 1}], {a: 1}], m({ "a" => 1 }, a: 1))
+ assert_equal([[{a: 1}], {}], m({a: 1}, {}))
+ assert_raise(ArgumentError) { m({a: 1}, {"a" => 1}) }
+
+ def m(a:, b:) [a, b] end
+ assert_equal([1, 2], m(a: 1, b: 2))
+ assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) }
+
+ def m(a:, b: 1) [a, b] end
+ assert_equal([1, 1], m(a: 1))
+ assert_equal([1, 2], m(a: 1, b: 2))
+ assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) }
+
+ def m(a:, **) a end
+ assert_equal(1, m(a: 1))
+ assert_equal(1, m(a: 1, b: 2))
+ assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) }
+
+ def m(a:, **k) [a, k] end
+ assert_equal([1, {}], m(a: 1))
+ assert_equal([1, {b: 2, c: 3}], m(a: 1, b: 2, c: 3))
+ assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) }
+
+=begin
+ def m(a:, &b) [a, b] end
+ assert_equal([1, nil], m(a: 1))
+ assert_equal([1, l], m(a: 1, &(l = ->{})))
+=end
+
+ def m(a: 1, b:) [a, b] end
+ assert_equal([1, 0], m(b: 0))
+ assert_equal([3, 2], m(b: 2, a: 3))
+ assert_raise(ArgumentError) { m a: 1 }
+
+ def m(a: def m(a: 1) a end, b:)
+ [a, b]
+ end
+ assert_equal([2, 3], m(a: 2, b: 3))
+ assert_equal([:m, 1], m(b: 1))
+ # Note the default value of a: in the original method.
+ assert_equal(1, m())
+
+ def m(a: 1, b: 2) [a, b] end
+ assert_equal([1, 2], m())
+ assert_equal([4, 3], m(b: 3, a: 4))
+
+ def m(a: 1, **) a end
+ assert_equal(1, m())
+ assert_equal(2, m(a: 2, b: 1))
+
+ def m(a: 1, **k) [a, k] end
+ assert_equal([1, {b: 2, c: 3}], m(b: 2, c: 3))
+
+ def m(a:, **) yield end
+ assert_raise(ArgumentError) { m { :blk } }
+ assert_equal :blk, m(a: 1){ :blk }
+
+ def m(a:, **k, &b) [b.call, k] end
+ assert_raise(ArgumentError) { m { :blk } }
+ assert_equal [:blk, {b: 2}], m(a: 1, b: 2){ :blk }
+
+ def m(**k, &b) [k, b] end
+ assert_equal([{ a: 1, b: 2}, nil], m(a: 1, b: 2))
+ assert_equal :blk, m{ :blk }[1].call
+
+ def m(hsh = {}) hsh end
+ assert_equal({ a: 1, b: 2 }, m(a: 1, b: 2))
+ assert_equal({ a: 1, 'b' => 2 }, m(a: 1, 'b' => 2))
+
+ def m(hsh) hsh end
+ assert_equal({ a: 1, b: 2 }, m(a: 1, b: 2))
+ assert_equal({ a: 1, 'b' => 2 }, m(a: 1, 'b' => 2))
+
+=begin
+ def m(a, b=1, *c, (*d, (e)), f: 2, g:, h:, **k, &l)
+ [a, b, c, d, e, f, g, h, k, l]
+ end
+ result = m(9, 8, 7, 6, f: 5, g: 4, h: 3, &(l = ->{}))
+ assert_equal([9, 8, [7], [], 6, 5, 4, 3, {}, l], result)
+
+ def m a, b=1, *c, d, e:, f: 2, g:, **k, &l
+ [a, b, c, d, e, f, g, k, l]
+ end
+ result = m(1, 2, e: 3, g: 4, h: 5, i: 6, &(l = ->{}))
+ assert_equal([1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l], result)
+=end
+end