Keyword argument implemented.

parent 891839b9
...@@ -77,7 +77,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. ...@@ -77,7 +77,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed.
|OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) |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_CALL' |B |R(a) = self.call(frame.argc, frame.argv)
|OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) |OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1))
|OP_ARGARY' |BS |R(a) = argument array (16=6:1:5:4) |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_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_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo
|OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo |OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo
...@@ -85,7 +85,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. ...@@ -85,7 +85,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed.
|OP_RETURN' |B |return R(a) (normal) |OP_RETURN' |B |return R(a) (normal)
|OP_RETURN_BLK' |B |return R(a) (in-block return) |OP_RETURN_BLK' |B |return R(a) (in-block return)
|OP_BREAK' |B |break R(a) |OP_BREAK' |B |break R(a)
|OP_BLKPUSH' |BS |R(a) = block (16=6:1:5:4) |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_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+)
|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (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_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-)
...@@ -207,7 +207,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. ...@@ -207,7 +207,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed.
|OP_SENDB" |BBB |R(a) = call(R(a),Syms(Bx),R(a+1),...,R(a+c),&R(a+c+1)) |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_CALL' |B |R(a) = self.call(frame.argc, frame.argv)
|OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1)) |OP_SUPER' |BB |R(a) = super(R(a+1),... ,R(a+b+1))
|OP_ARGARY' |BS |R(a) = argument array (16=6:1:5:4) |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_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_KARG" |BB |R(a) = kdict[Syms(Bx)] # todo
|OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo |OP_KARG2" |BB |R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo
...@@ -215,7 +215,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed. ...@@ -215,7 +215,7 @@ with `"`, either `OP_EXT1` or `OP_EXT2` or `OP_EXT2` can be prefixed.
|OP_RETURN' |B |return R(a) (normal) |OP_RETURN' |B |return R(a) (normal)
|OP_RETURN_BLK' |B |return R(a) (in-block return) |OP_RETURN_BLK' |B |return R(a) (in-block return)
|OP_BREAK' |B |break R(a) |OP_BREAK' |B |break R(a)
|OP_BLKPUSH' |BS |R(a) = block (16=6:1:5:4) |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_ADD" |BB |R(a) = R(a)+R(a+1) (Syms[b]=:+)
|OP_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (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_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-)
......
...@@ -25,6 +25,7 @@ struct RHash { ...@@ -25,6 +25,7 @@ struct RHash {
#define mrb_hash_value(p) mrb_obj_value((void*)(p)) #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_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. * Initializes a new hash.
...@@ -110,7 +111,19 @@ MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value ...@@ -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. * @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_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 * Check if the hash is empty
...@@ -123,7 +136,7 @@ MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); ...@@ -123,7 +136,7 @@ MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash);
* @param self The target hash. * @param self The target hash.
* @return True if the hash is empty, false otherwise. * @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. * Gets an array of values.
...@@ -151,6 +164,16 @@ MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash); ...@@ -151,6 +164,16 @@ 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); 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);
/* declaration of struct kh_ht */ /* declaration of struct kh_ht */
/* be careful when you touch the internal */ /* be careful when you touch the internal */
typedef struct { typedef struct {
......
...@@ -61,15 +61,16 @@ OPCODE(SEND, BBB) /* R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) */ ...@@ -61,15 +61,16 @@ 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(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(CALL, Z) /* R(0) = self.call(frame.argc, frame.argv) */
OPCODE(SUPER, BB) /* R(a) = super(R(a+1),... ,R(a+b+1)) */ OPCODE(SUPER, BB) /* R(a) = super(R(a+1),... ,R(a+b+1)) */
OPCODE(ARGARY, BS) /* R(a) = argument array (16=6:1:5:4) */ OPCODE(ARGARY, BS) /* R(a) = argument array (16=m5:r1:m5:d1:lv4) */
OPCODE(ENTER, W) /* arg setup according to flags (23=5:5:1:5:5:1:1) */ OPCODE(ENTER, W) /* arg setup according to flags (23=m5:o5:r1:m5:k5:d1:b1) */
OPCODE(KARG, BB) /* R(a) = kdict[Syms(Bx)] # todo */ OPCODE(KEY_P, BB) /* R(a) = kdict.key?(Syms(b)) # todo */
OPCODE(KARG2, BB) /* R(a) = kdict[Syms(Bx)]; kdict.rm(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(KDICT, B) /* R(a) = kdict # todo */ OPCODE(KDICT, B) /* R(a) = kdict # todo */
OPCODE(RETURN, B) /* return R(a) (normal) */ OPCODE(RETURN, B) /* return R(a) (normal) */
OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */ OPCODE(RETURN_BLK, B) /* return R(a) (in-block return) */
OPCODE(BREAK, B) /* break R(a) */ OPCODE(BREAK, B) /* break R(a) */
OPCODE(BLKPUSH, BS) /* R(a) = block (16=6:1:5:4) */ 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(ADD, BB) /* R(a) = R(a)+R(a+1) (Syms[b]=:+) */
OPCODE(ADDI, BBB) /* R(a) = R(a)+mrb_int(c) (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(SUB, BB) /* R(a) = R(a)-R(a+1) (Syms[b]=:-) */
......
...@@ -420,6 +420,9 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) ...@@ -420,6 +420,9 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
if (no_peephole(s)) { if (no_peephole(s)) {
normal: normal:
genop_2(s, OP_MOVE, dst, src); genop_2(s, OP_MOVE, dst, src);
if (on_eval(s)) {
genop_0(s, OP_NOP);
}
return; return;
} }
else { else {
...@@ -453,6 +456,25 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep) ...@@ -453,6 +456,25 @@ gen_move(codegen_scope *s, uint16_t dst, uint16_t src, int nopeep)
} }
} }
static void
gen_return(codegen_scope *s, uint8_t op, uint16_t src)
{
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 static void
gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx) gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst, uint16_t idx)
{ {
...@@ -514,30 +536,28 @@ dispatch_linked(codegen_scope *s, uint16_t pos) ...@@ -514,30 +536,28 @@ dispatch_linked(codegen_scope *s, uint16_t pos)
#define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0) #define nregs_update do {if (s->sp > s->nregs) s->nregs = s->sp;} while (0)
static void static void
push_(codegen_scope *s) push_n_(codegen_scope *s, int n)
{ {
if (s->sp >= 0xffff) { if (s->sp+n >= 0xffff) {
codegen_error(s, "too complex expression"); codegen_error(s, "too complex expression");
} }
s->sp++; s->sp+=n;
nregs_update; nregs_update;
} }
static void static void
push_n_(codegen_scope *s, int n) pop_n_(codegen_scope *s, int n)
{ {
if (s->sp+n >= 0xffff) { if ((int)s->sp-n < 0) {
codegen_error(s, "too complex expression"); codegen_error(s, "stack pointer underflow");
} }
s->sp+=n; s->sp-=n;
nregs_update;
} }
#define push() push_(s) #define push() push_n_(s,1)
#define push_n(n) push_n_(s,n) #define push_n(n) push_n_(s,n)
#define pop_(s) ((s)->sp--) #define pop() pop_n_(s,1)
#define pop() pop_(s) #define pop_n(n) pop_n_(s,n)
#define pop_n(n) (s->sp-=(n))
#define cursp() (s->sp) #define cursp() (s->sp)
static inline int static inline int
...@@ -644,8 +664,12 @@ node_len(node *tree) ...@@ -644,8 +664,12 @@ node_len(node *tree)
return n; 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 nsym(x) ((mrb_sym)(intptr_t)(x))
#define lv_name(lv) nsym((lv)->car) #define lv_name(lv) nsym((lv)->car)
static int static int
lv_idx(codegen_scope *s, mrb_sym id) lv_idx(codegen_scope *s, mrb_sym id)
{ {
...@@ -694,7 +718,7 @@ for_body(codegen_scope *s, node *tree) ...@@ -694,7 +718,7 @@ for_body(codegen_scope *s, node *tree)
/* loop body */ /* loop body */
codegen(s, tree->cdr->cdr->car, VAL); codegen(s, tree->cdr->cdr->car, VAL);
pop(); pop();
genop_1(s, OP_RETURN, cursp()); gen_return(s, OP_RETURN, cursp());
loop_pop(s, NOVAL); loop_pop(s, NOVAL);
scope_finish(s); scope_finish(s);
s = prev; s = prev;
...@@ -726,32 +750,44 @@ lambda_body(codegen_scope *s, node *tree, int blk) ...@@ -726,32 +750,44 @@ lambda_body(codegen_scope *s, node *tree, int blk)
int ma, oa, ra, pa, ka, kd, ba; int ma, oa, ra, pa, ka, kd, ba;
int pos, i; int pos, i;
node *n, *opt; node *n, *opt;
node *tail;
/* mandatory arguments */
ma = node_len(tree->car->car); ma = node_len(tree->car->car);
n = tree->car->car; n = tree->car->car;
while (n) { while (n) {
n = n->cdr; n = n->cdr;
} }
tail = tree->car->cdr->cdr->cdr->cdr;
/* optional arguments */
oa = node_len(tree->car->cdr->car); oa = node_len(tree->car->cdr->car);
/* rest argument? */
ra = tree->car->cdr->cdr->car ? 1 : 0; ra = tree->car->cdr->cdr->car ? 1 : 0;
/* mandatory arugments after rest argument */
pa = node_len(tree->car->cdr->cdr->cdr->car); pa = node_len(tree->car->cdr->cdr->cdr->car);
ka = kd = 0; /* keyword arguments */
ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0; 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) { if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) {
codegen_error(s, "too many formal arguments"); codegen_error(s, "too many formal arguments");
} }
a = ((mrb_aspec)(ma & 0x1f) << 18) a = MRB_ARGS_REQ(ma)
| ((mrb_aspec)(oa & 0x1f) << 13) | MRB_ARGS_OPT(oa)
| ((ra & 1) << 12) | (ra? MRB_ARGS_REST() : 0)
| ((pa & 0x1f) << 7) | MRB_ARGS_POST(pa)
| ((ka & 0x1f) << 2) | MRB_ARGS_KEY(ka, kd)
| ((kd & 1)<< 1) | (ba? MRB_ARGS_BLOCK() : 0);
| (ba & 1); s->ainfo = (((ma+oa) & 0x3f) << 7) /* (12bits = 5:1:5:1) */
s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */ | ((ra & 0x1) << 6)
| ((ra & 1) << 5) | ((pa & 0x1f) << 1)
| (pa & 0x1f); | (kd & 0x1);
genop_W(s, OP_ENTER, a); genop_W(s, OP_ENTER, a);
/* generate jump table for optional arguments initializer */
pos = new_label(s); pos = new_label(s);
for (i=0; i<oa; i++) { for (i=0; i<oa; i++) {
new_label(s); new_label(s);
...@@ -776,11 +812,50 @@ lambda_body(codegen_scope *s, node *tree, int blk) ...@@ -776,11 +812,50 @@ lambda_body(codegen_scope *s, node *tree, int blk)
if (oa > 0) { if (oa > 0) {
dispatch(s, pos+i*3+1); 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); codegen(s, tree->cdr->car, VAL);
pop(); pop();
if (s->pc > 0) { if (s->pc > 0) {
genop_1(s, OP_RETURN, cursp()); gen_return(s, OP_RETURN, cursp());
} }
if (blk) { if (blk) {
loop_pop(s, NOVAL); loop_pop(s, NOVAL);
...@@ -798,7 +873,7 @@ scope_body(codegen_scope *s, node *tree, int val) ...@@ -798,7 +873,7 @@ scope_body(codegen_scope *s, node *tree, int val)
} }
codegen(scope, tree->cdr, VAL); codegen(scope, tree->cdr, VAL);
genop_1(scope, OP_RETURN, scope->sp-1); gen_return(scope, OP_RETURN, scope->sp-1);
if (!s->iseq) { if (!s->iseq) {
genop_0(scope, OP_STOP); genop_0(scope, OP_STOP);
} }
...@@ -810,9 +885,6 @@ scope_body(codegen_scope *s, node *tree, int val) ...@@ -810,9 +885,6 @@ scope_body(codegen_scope *s, node *tree, int val)
return s->irep->rlen - 1; return s->irep->rlen - 1;
} }
#define nint(x) ((int)(intptr_t)(x))
#define nchar(x) ((char)(intptr_t)(x))
static mrb_bool static mrb_bool
nosplat(node *t) nosplat(node *t)
{ {
...@@ -1703,11 +1775,18 @@ codegen(codegen_scope *s, node *tree, int val) ...@@ -1703,11 +1775,18 @@ codegen(codegen_scope *s, node *tree, int val)
break; break;
case NODE_HASH: case NODE_HASH:
case NODE_KW_HASH:
{ {
int len = 0; int len = 0;
mrb_bool update = FALSE; mrb_bool update = FALSE;
while (tree) { while (tree) {
if (nt == NODE_KW_HASH &&
nint(tree->car->car->car) == NODE_KW_REST_ARGS) {
tree = tree->cdr;
continue;
}
codegen(s, tree->car->car, val); codegen(s, tree->car->car, val);
codegen(s, tree->car->cdr, val); codegen(s, tree->car->cdr, val);
len++; len++;
...@@ -2055,10 +2134,10 @@ codegen(codegen_scope *s, node *tree, int val) ...@@ -2055,10 +2134,10 @@ codegen(codegen_scope *s, node *tree, int val)
genop_1(s, OP_LOADNIL, cursp()); genop_1(s, OP_LOADNIL, cursp());
} }
if (s->loop) { if (s->loop) {
genop_1(s, OP_RETURN_BLK, cursp()); gen_return(s, OP_RETURN_BLK, cursp());
} }
else { else {
genop_1(s, OP_RETURN, cursp()); gen_return(s, OP_RETURN, cursp());
} }
if (val) push(); if (val) push();
break; break;
...@@ -2116,7 +2195,7 @@ codegen(codegen_scope *s, node *tree, int val) ...@@ -2116,7 +2195,7 @@ codegen(codegen_scope *s, node *tree, int val)
else { else {
genop_1(s, OP_LOADNIL, cursp()); genop_1(s, OP_LOADNIL, cursp());
} }
genop_1(s, OP_RETURN, cursp()); gen_return(s, OP_RETURN, cursp());
} }
if (val) push(); if (val) push();
break; break;
...@@ -2999,7 +3078,7 @@ loop_break(codegen_scope *s, node *tree) ...@@ -2999,7 +3078,7 @@ loop_break(codegen_scope *s, node *tree)
if (!tree) { if (!tree) {
genop_1(s, OP_LOADNIL, cursp()); genop_1(s, OP_LOADNIL, cursp());
} }
genop_1(s, OP_BREAK, cursp()); gen_return(s, OP_BREAK, cursp());
} }
} }
} }
......
...@@ -46,6 +46,7 @@ enum node_type { ...@@ -46,6 +46,7 @@ enum node_type {
NODE_ARRAY, NODE_ARRAY,
NODE_ZARRAY, NODE_ZARRAY,
NODE_HASH, NODE_HASH,
NODE_KW_HASH,
NODE_RETURN, NODE_RETURN,
NODE_YIELD, NODE_YIELD,
NODE_LVAR, NODE_LVAR,
...@@ -73,6 +74,9 @@ enum node_type { ...@@ -73,6 +74,9 @@ enum node_type {
NODE_DREGX_ONCE, NODE_DREGX_ONCE,
NODE_LIST, NODE_LIST,
NODE_ARG, NODE_ARG,
NODE_ARGS_TAIL,
NODE_KW_ARG,
NODE_KW_REST_ARGS,
NODE_ARGSCAT, NODE_ARGSCAT,
NODE_ARGSPUSH, NODE_ARGSPUSH,
NODE_SPLAT, NODE_SPLAT,
......
...@@ -568,6 +568,13 @@ new_hash(parser_state *p, node *a) ...@@ -568,6 +568,13 @@ new_hash(parser_state *p, node *a)
return cons((node*)NODE_HASH, 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) */ /* (:sym . a) */
static node* static node*
new_sym(parser_state *p, mrb_sym sym) new_sym(parser_state *p, mrb_sym sym)
...@@ -671,23 +678,61 @@ new_arg(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)); return cons((node*)NODE_ARG, nsym(sym));
} }
/* (m o r m2 b) */ /* (m o r m2 tail) */
/* m: (a b c) */ /* m: (a b c) */
/* o: ((a . e1) (b . e2)) */ /* o: ((a . e1) (b . e2)) */
/* r: a */ /* r: a */
/* m2: (a b c) */ /* m2: (a b c) */
/* b: a */ /* b: a */
static node* 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; node *n;
n = cons(m2, nsym(blk)); n = cons(m2, tail);
n = cons(nsym(rest), n); n = cons(nsym(rest), n);
n = cons(opt, n); n = cons(opt, n);
return cons(m, 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) */ /* (:block_arg . a) */
static node* static node*
new_block_arg(parser_state *p, node *a) new_block_arg(parser_state *p, node *a)
...@@ -1134,6 +1179,10 @@ heredoc_end(parser_state *p) ...@@ -1134,6 +1179,10 @@ heredoc_end(parser_state *p)
%type <nd> heredoc words symbols %type <nd> heredoc words symbols
%type <num> call_op call_op2 /* 0:'&.', 1:'.', 2:'::' */ %type <num> call_op call_op2 /* 0:'&.', 1:'.', 2:'::' */
%type <nd> args_tail opt_args_tail f_kwarg f_kw arg_value 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 tUPLUS /* unary+ */
%token tUMINUS /* unary- */ %token tUMINUS /* unary- */
%token tPOW /* ** */ %token tPOW /* ** */
...@@ -1159,6 +1208,7 @@ heredoc_end(parser_state *p) ...@@ -1159,6 +1208,7 @@ heredoc_end(parser_state *p)
%token tLBRACE /* { */ %token tLBRACE /* { */
%token tLBRACE_ARG /* { */ %token tLBRACE_ARG /* { */
%token tSTAR /* * */ %token tSTAR /* * */
%token tDSTAR /* ** */
%token tAMPER /* & */ %token tAMPER /* & */
%token tLAMBDA /* -> */ %token tLAMBDA /* -> */
%token tANDDOT /* &. */ %token tANDDOT /* &. */
...@@ -1736,6 +1786,7 @@ op : '|' { $$ = intern_c('|'); } ...@@ -1736,6 +1786,7 @@ op : '|' { $$ = intern_c('|'); }
| '/' { $$ = intern_c('/'); } | '/' { $$ = intern_c('/'); }
| '%' { $$ = intern_c('%'); } | '%' { $$ = intern_c('%'); }
| tPOW { $$ = intern("**",2); } | tPOW { $$ = intern("**",2); }
| tDSTAR { $$ = intern("**",2); }
| '!' { $$ = intern_c('!'); } | '!' { $$ = intern_c('!'); }
| '~' { $$ = intern_c('~'); } | '~' { $$ = intern_c('~'); }
| tUPLUS { $$ = intern("+@",2); } | tUPLUS { $$ = intern("+@",2); }
...@@ -1944,11 +1995,11 @@ aref_args : none ...@@ -1944,11 +1995,11 @@ aref_args : none
} }
| args comma assocs trailer | args comma assocs trailer
{ {
$$ = push($1, new_hash(p, $3)); $$ = push($1, new_kw_hash(p, $3));
} }
| assocs trailer | assocs trailer
{ {
$$ = cons(new_hash(p, $1), 0); $$ = cons(new_kw_hash(p, $1), 0);
NODE_LINENO($$, $1); NODE_LINENO($$, $1);
} }
; ;
...@@ -1984,12 +2035,12 @@ opt_call_args : none ...@@ -1984,12 +2035,12 @@ opt_call_args : none
} }
| args comma assocs ',' | args comma assocs ','
{ {
$$ = cons(push($1, new_hash(p, $3)), 0); $$ = cons(push($1, new_kw_hash(p, $3)), 0);
NODE_LINENO($$, $1); NODE_LINENO($$, $1);
} }
| assocs ',' | assocs ','
{ {
$$ = cons(list1(new_hash(p, $1)), 0); $$ = cons(list1(new_kw_hash(p, $1)), 0);
NODE_LINENO($$, $1); NODE_LINENO($$, $1);
} }
; ;
...@@ -2007,12 +2058,12 @@ call_args : command ...@@ -2007,12 +2058,12 @@ call_args : command
} }
| assocs opt_block_arg | assocs opt_block_arg
{ {
$$ = cons(list1(new_hash(p, $1)), $2); $$ = cons(list1(new_kw_hash(p, $1)), $2);
NODE_LINENO($$, $1); NODE_LINENO($$, $1);
} }
| args comma assocs opt_block_arg | 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); NODE_LINENO($$, $1);
} }
| block_arg | block_arg
...@@ -2451,23 +2502,51 @@ f_margs : f_marg_list ...@@ -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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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 ...@@ -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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = new_args(p, 0, 0, $1, $3, $4);
} }
| f_block_arg | block_args_tail
{ {
$$ = new_args(p, 0, 0, 0, 0, $1); $$ = new_args(p, 0, 0, 0, 0, $1);
} }
...@@ -3021,65 +3100,153 @@ f_arglist : '(' f_args rparen ...@@ -3021,65 +3100,153 @@ f_arglist : '(' f_args rparen
} }
; ;
f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg f_label : tIDENTIFIER tLABEL_TAG
;
arg_value : arg
;
f_kw : f_label arg_value
{
$$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = 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); $$ = new_args(p, 0, 0, $1, $3, $4);
} }
| f_block_arg | args_tail
{ {
$$ = new_args(p, 0, 0, 0, 0, $1); $$ = new_args(p, 0, 0, 0, 0, $1);
} }
| /* none */ | /* none */
{ {
local_add_f(p, 0); local_add_f(p, mrb_intern_lit(p->mrb, "&"));
$$ = new_args(p, 0, 0, 0, 0, 0); $$ = new_args(p, 0, 0, 0, 0, 0);
} }
; ;
...@@ -3189,7 +3356,7 @@ f_rest_arg : restarg_mark tIDENTIFIER ...@@ -3189,7 +3356,7 @@ f_rest_arg : restarg_mark tIDENTIFIER
} }
| restarg_mark | restarg_mark
{ {
local_add_f(p, 0); local_add_f(p, mrb_intern_lit(p->mrb, "*"));
$$ = -1; $$ = -1;
} }
; ;
...@@ -3200,7 +3367,6 @@ blkarg_mark : '&' ...@@ -3200,7 +3367,6 @@ blkarg_mark : '&'
f_block_arg : blkarg_mark tIDENTIFIER f_block_arg : blkarg_mark tIDENTIFIER
{ {
local_add_f(p, $2);
$$ = $2; $$ = $2;
} }
; ;
...@@ -3211,7 +3377,6 @@ opt_f_block_arg : ',' f_block_arg ...@@ -3211,7 +3377,6 @@ opt_f_block_arg : ',' f_block_arg
} }
| none | none
{ {
local_add_f(p, 0);
$$ = 0; $$ = 0;
} }
; ;
...@@ -3285,6 +3450,10 @@ assoc : arg tASSOC arg ...@@ -3285,6 +3450,10 @@ assoc : arg tASSOC arg
$$ = cons(new_sym(p, new_strsym(p, $1)), $3); $$ = cons(new_sym(p, new_strsym(p, $1)), $3);
} }
} }
| tDSTAR arg_value
{
$$ = cons(cons((node*)NODE_KW_REST_ARGS, 0), $2);
}
; ;
operation : tIDENTIFIER operation : tIDENTIFIER
...@@ -3450,13 +3619,13 @@ backref_error(parser_state *p, node *n) ...@@ -3450,13 +3619,13 @@ backref_error(parser_state *p, node *n)
{ {
int c; int c;
c = (int)(intptr_t)n->car; c = intn(n->car);
if (c == NODE_NTH_REF) { 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) { 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 { else {
mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c));
...@@ -3469,7 +3638,7 @@ void_expr_error(parser_state *p, node *n) ...@@ -3469,7 +3638,7 @@ void_expr_error(parser_state *p, node *n)
int c; int c;
if (n == NULL) return; if (n == NULL) return;
c = (int)(intptr_t)n->car; c = intn(n->car);
switch (c) { switch (c) {
case NODE_BREAK: case NODE_BREAK:
case NODE_RETURN: case NODE_RETURN:
...@@ -3508,7 +3677,7 @@ nextc(parser_state *p) ...@@ -3508,7 +3677,7 @@ nextc(parser_state *p)
if (p->pb) { if (p->pb) {
node *tmp; node *tmp;
c = (int)(intptr_t)p->pb->car; c = intn(p->pb->car);
tmp = p->pb; tmp = p->pb;
p->pb = p->pb->cdr; p->pb = p->pb->cdr;
cons_free(tmp); cons_free(tmp);
...@@ -3557,7 +3726,7 @@ pushback(parser_state *p, int c) ...@@ -3557,7 +3726,7 @@ pushback(parser_state *p, int c)
if (c >= 0) { if (c >= 0) {
p->column--; p->column--;
} }
p->pb = cons((node*)(intptr_t)c, p->pb); p->pb = cons(nint(c), p->pb);
} }
static void static void
...@@ -3582,7 +3751,7 @@ peekc_n(parser_state *p, int n) ...@@ -3582,7 +3751,7 @@ peekc_n(parser_state *p, int n)
c0 = nextc(p); c0 = nextc(p);
if (c0 == -1) return c0; /* do not skip partial EOF */ if (c0 == -1) return c0; /* do not skip partial EOF */
if (c0 >= 0) --p->column; if (c0 >= 0) --p->column;
list = push(list, (node*)(intptr_t)c0); list = push(list, nint(c0));
} while(n--); } while(n--);
if (p->pb) { if (p->pb) {
p->pb = append((node*)list, p->pb); p->pb = append((node*)list, p->pb);
...@@ -4019,11 +4188,11 @@ parse_string(parser_state *p) ...@@ -4019,11 +4188,11 @@ parse_string(parser_state *p)
} }
else if (c == beg) { else if (c == beg) {
nest_level++; nest_level++;
p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; p->lex_strterm->cdr->car = nint(nest_level);
} }
else if (c == end) { else if (c == end) {
nest_level--; nest_level--;
p->lex_strterm->cdr->car = (node*)(intptr_t)nest_level; p->lex_strterm->cdr->car = nint(nest_level);
} }
else if (c == '\\') { else if (c == '\\') {
c = nextc(p); c = nextc(p);
...@@ -4365,7 +4534,16 @@ parser_yylex(parser_state *p) ...@@ -4365,7 +4534,16 @@ parser_yylex(parser_state *p)
return tOP_ASGN; return tOP_ASGN;
} }
pushback(p, c); 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 { else {
if (c == '=') { if (c == '=') {
...@@ -5547,7 +5725,7 @@ parser_update_cxt(parser_state *p, mrbc_context *cxt) ...@@ -5547,7 +5725,7 @@ parser_update_cxt(parser_state *p, mrbc_context *cxt)
int i = 0; int i = 0;
if (!cxt) return; 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; n0 = n = p->tree->cdr->car;
while (n) { while (n) {
i++; i++;
...@@ -5897,6 +6075,48 @@ dump_recur(mrb_state *mrb, node *tree, int offset) ...@@ -5897,6 +6075,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 #endif
void void
...@@ -5908,7 +6128,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -5908,7 +6128,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
if (!tree) return; if (!tree) return;
again: again:
dump_prefix(tree, offset); dump_prefix(tree, offset);
nodetype = (int)(intptr_t)tree->car; nodetype = intn(tree->car);
tree = tree->cdr; tree = tree->cdr;
switch (nodetype) { switch (nodetype) {
case NODE_BEGIN: case NODE_BEGIN:
...@@ -5968,7 +6188,8 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -5968,7 +6188,8 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
break; break;
case NODE_LAMBDA: case NODE_LAMBDA:
printf("NODE_BLOCK:\n"); printf("NODE_LAMBDA:\n");
dump_prefix(tree, offset);
goto block; goto block;
case NODE_BLOCK: case NODE_BLOCK:
...@@ -5976,43 +6197,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -5976,43 +6197,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
printf("NODE_BLOCK:\n"); printf("NODE_BLOCK:\n");
tree = tree->cdr; tree = tree->cdr;
if (tree->car) { if (tree->car) {
node *n = tree->car; dump_args(mrb, tree->car, offset+1);
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_prefix(tree, offset+1); dump_prefix(tree, offset+1);
printf("body:\n"); printf("body:\n");
...@@ -6164,7 +6349,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -6164,7 +6349,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
dump_prefix(tree, offset+1); dump_prefix(tree, offset+1);
printf("method='%s' (%d)\n", printf("method='%s' (%d)\n",
mrb_sym2name(mrb, sym(tree->cdr->car)), mrb_sym2name(mrb, sym(tree->cdr->car)),
(int)(intptr_t)tree->cdr->car); intn(tree->cdr->car));
tree = tree->cdr->cdr->car; tree = tree->cdr->cdr->car;
if (tree) { if (tree) {
dump_prefix(tree, offset+1); dump_prefix(tree, offset+1);
...@@ -6281,7 +6466,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -6281,7 +6466,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
mrb_parser_dump(mrb, tree->car, offset+2); mrb_parser_dump(mrb, tree->car, offset+2);
tree = tree->cdr; tree = tree->cdr;
dump_prefix(tree, offset+1); 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; tree = tree->cdr;
mrb_parser_dump(mrb, tree->car, offset+1); mrb_parser_dump(mrb, tree->car, offset+1);
break; break;
...@@ -6363,11 +6548,11 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -6363,11 +6548,11 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
break; break;
case NODE_BACK_REF: case NODE_BACK_REF:
printf("NODE_BACK_REF: $%c\n", (int)(intptr_t)tree); printf("NODE_BACK_REF: $%c\n", intn(tree));
break; break;
case NODE_NTH_REF: 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; break;
case NODE_ARG: case NODE_ARG:
...@@ -6380,7 +6565,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -6380,7 +6565,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
break; break;
case NODE_INT: 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; break;
case NODE_FLOAT: case NODE_FLOAT:
...@@ -6393,7 +6578,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -6393,7 +6578,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
break; break;
case NODE_STR: 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; break;
case NODE_DSTR: case NODE_DSTR:
...@@ -6402,7 +6587,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -6402,7 +6587,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
break; break;
case NODE_XSTR: 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; break;
case NODE_DXSTR: case NODE_DXSTR:
...@@ -6431,7 +6616,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -6431,7 +6616,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
case NODE_SYM: case NODE_SYM:
printf("NODE_SYM :%s (%d)\n", mrb_sym2name(mrb, sym(tree)), printf("NODE_SYM :%s (%d)\n", mrb_sym2name(mrb, sym(tree)),
(int)(intptr_t)tree); intn(tree));
break; break;
case NODE_SELF: case NODE_SELF:
...@@ -6547,43 +6732,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -6547,43 +6732,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
} }
tree = tree->cdr; tree = tree->cdr;
if (tree->car) { if (tree->car) {
node *n = tree->car; dump_args(mrb, tree->car, 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=", 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)));
}
} }
mrb_parser_dump(mrb, tree->cdr->car, offset+1); mrb_parser_dump(mrb, tree->cdr->car, offset+1);
break; break;
...@@ -6596,44 +6745,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -6596,44 +6745,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
printf(":%s\n", mrb_sym2name(mrb, sym(tree->car))); printf(":%s\n", mrb_sym2name(mrb, sym(tree->car)));
tree = tree->cdr->cdr; tree = tree->cdr->cdr;
if (tree->car) { if (tree->car) {
node *n = tree->car; dump_args(mrb, tree->car, offset+1);
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)));
}
} }
tree = tree->cdr; tree = tree->cdr;
mrb_parser_dump(mrb, tree->car, offset+1); mrb_parser_dump(mrb, tree->car, offset+1);
...@@ -6649,18 +6761,35 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -6649,18 +6761,35 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
break; break;
case NODE_LITERAL_DELIM: case NODE_ARGS_TAIL:
printf("NODE_LITERAL_DELIM\n"); 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; break;
case NODE_SYMBOLS: case NODE_KW_ARG:
printf("NODE_SYMBOLS:\n"); printf("NODE_KW_ARG %s\n", mrb_sym2name(mrb, sym(tree->car)));
dump_recur(mrb, tree, offset+1); mrb_parser_dump(mrb, tree->cdr->car, offset + 1);
break; break;
case NODE_WORDS: case NODE_KW_REST_ARGS:
printf("NODE_SYMBOLS:\n"); printf("NODE_KW_REST_ARGS %s\n", mrb_sym2name(mrb, sym(tree)));
dump_recur(mrb, tree, offset+1);
break; break;
default: default:
......
...@@ -57,7 +57,7 @@ os_count_objects(mrb_state *mrb, mrb_value self) ...@@ -57,7 +57,7 @@ os_count_objects(mrb_state *mrb, mrb_value self)
hash = mrb_hash_new(mrb); 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); mrb_hash_clear(mrb, hash);
} }
......
...@@ -149,7 +149,15 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) ...@@ -149,7 +149,15 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
a = mrb_ary_new(mrb); a = mrb_ary_new(mrb);
mrb_ary_push(mrb, a, sname); mrb_ary_push(mrb, a, sname);
if (i < max && irep->lv[i].name) { if (i < max && irep->lv[i].name) {
mrb_ary_push(mrb, a, mrb_symbol_value(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); mrb_ary_push(mrb, parameters, a);
} }
......
...@@ -78,6 +78,16 @@ codedump(mrb_state *mrb, mrb_irep *irep) ...@@ -78,6 +78,16 @@ codedump(mrb_state *mrb, mrb_irep *irep)
printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep, 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); irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen);
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; pc = irep->iseq;
pcend = pc + irep->ilen; pcend = pc + irep->ilen;
while (pc < pcend) { while (pc < pcend) {
...@@ -246,10 +256,11 @@ codedump(mrb_state *mrb, mrb_irep *irep) ...@@ -246,10 +256,11 @@ codedump(mrb_state *mrb, mrb_irep *irep)
printf("OP_SUPER\tR%d\t%d\n", a, b); printf("OP_SUPER\tR%d\t%d\n", a, b);
break; break;
CASE(OP_ARGARY, BS): CASE(OP_ARGARY, BS):
printf("OP_ARGARY\tR%d\t%d:%d:%d:%d", a, printf("OP_ARGARY\tR%d\t%d:%d:%d:%d (%d)", a,
(b>>10)&0x3f, (b>>11)&0x3f,
(b>>9)&0x1, (b>>10)&0x1,
(b>>4)&0x1f, (b>>5)&0x1f,
(b>>4)&0x1,
(b>>0)&0xf); (b>>0)&0xf);
print_lv_a(mrb, irep, a); print_lv_a(mrb, irep, a);
break; break;
...@@ -263,32 +274,39 @@ codedump(mrb_state *mrb, mrb_irep *irep) ...@@ -263,32 +274,39 @@ codedump(mrb_state *mrb, mrb_irep *irep)
(a>>1)&0x1, (a>>1)&0x1,
a & 0x1); a & 0x1);
break; break;
CASE(OP_KARG, BB): CASE(OP_KEY_P, BB):
printf("OP_KARG\tR(%d)\tK(%d)\n", a, b); printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b]));
print_lv_a(mrb, irep, a);
break; break;
CASE(OP_KARG2, BB): CASE(OP_KEYEND, Z):
printf("OP_KARG2\tR(%d)\tK(%d)\n", a, b); printf("OP_KEYEND\n");
break;
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; break;
CASE(OP_KDICT, B): CASE(OP_KDICT, B):
printf("OP_KDICt\tR(%d)\n", a); printf("OP_KDICT\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break; break;
CASE(OP_RETURN, B): CASE(OP_RETURN, B):
printf("OP_RETURN\tR%d", a); printf("OP_RETURN\tR%d\t\t", a);
print_lv_a(mrb, irep, a); print_lv_a(mrb, irep, a);
break; break;
CASE(OP_RETURN_BLK, B): CASE(OP_RETURN_BLK, B):
printf("OP_RETURN_BLK\tR%d", a); printf("OP_RETURN_BLK\tR%d\t\t", a);
print_lv_a(mrb, irep, a); print_lv_a(mrb, irep, a);
break; break;
CASE(OP_BREAK, B): CASE(OP_BREAK, B):
printf("OP_BREAK\tR%d", a); printf("OP_BREAK\tR%d\t\t", a);
print_lv_a(mrb, irep, a); print_lv_a(mrb, irep, a);
break; break;
CASE(OP_BLKPUSH, BS): CASE(OP_BLKPUSH, BS):
printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", a, printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)", a,
(b>>10)&0x3f, (b>>11)&0x3f,
(b>>9)&0x1, (b>>10)&0x1,
(b>>4)&0x1f, (b>>5)&0x1f,
(b>>4)&0x1,
(b>>0)&0xf); (b>>0)&0xf);
print_lv_a(mrb, irep, a); print_lv_a(mrb, irep, a);
break; break;
......
...@@ -208,6 +208,54 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self) ...@@ -208,6 +208,54 @@ mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
return vret; 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_API mrb_value
mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) 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) ...@@ -716,13 +764,21 @@ mrb_hash_size_m(mrb_state *mrb, mrb_value self)
* {}.empty? #=> true * {}.empty? #=> true
* *
*/ */
MRB_API mrb_value MRB_API mrb_bool
mrb_hash_empty_p(mrb_state *mrb, mrb_value self) mrb_hash_empty_p(mrb_state *mrb, mrb_value self)
{ {
khash_t(ht) *h = RHASH_TBL(self); khash_t(ht) *h = RHASH_TBL(self);
if (h) return mrb_bool_value(kh_size(h) == 0); if (h) return kh_size(h) == 0;
return mrb_true_value(); 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)*/ /* 15.2.13.4.29 (x)*/
...@@ -833,21 +889,29 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash) ...@@ -833,21 +889,29 @@ mrb_hash_values(mrb_state *mrb, mrb_value hash)
* *
*/ */
static mrb_value MRB_API mrb_bool
mrb_hash_has_key(mrb_state *mrb, mrb_value hash) mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key)
{ {
mrb_value key;
khash_t(ht) *h; khash_t(ht) *h;
khiter_t k; khiter_t k;
mrb_get_args(mrb, "o", &key);
h = RHASH_TBL(hash); h = RHASH_TBL(hash);
if (h) { if (h) {
k = kh_get(ht, mrb, h, key); 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 */ /* 15.2.13.4.14 */
...@@ -904,7 +968,7 @@ mrb_init_hash(mrb_state *mrb) ...@@ -904,7 +968,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_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, "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, "__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_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, "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 */ mrb_define_method(mrb, h, "include?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.15 */
......
...@@ -1194,7 +1194,15 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) ...@@ -1194,7 +1194,15 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
if (!irep->lv) break; if (!irep->lv) break;
for (i = 0; i + 1 < irep->nlocals; ++i) { for (i = 0; i + 1 < irep->nlocals; ++i) {
if (irep->lv[i].name) { 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; if (!MRB_PROC_ENV_P(proc)) break;
......
...@@ -969,6 +969,8 @@ check_target_class(mrb_state *mrb) ...@@ -969,6 +969,8 @@ check_target_class(mrb_state *mrb)
return TRUE; return TRUE;
} }
void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
MRB_API mrb_value MRB_API mrb_value
mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc) mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
{ {
...@@ -1639,9 +1641,10 @@ RETRY_TRY_BLOCK: ...@@ -1639,9 +1641,10 @@ RETRY_TRY_BLOCK:
} }
CASE(OP_ARGARY, BS) { CASE(OP_ARGARY, BS) {
int m1 = (b>>10)&0x3f; int m1 = (b>>11)&0x3f;
int r = (b>>9)&0x1; int r = (b>>10)&0x1;
int m2 = (b>>4)&0x1f; int m2 = (b>>5)&0x1f;
int kd = (b>>4)&0x1;
int lv = (b>>0)&0xf; int lv = (b>>0)&0xf;
mrb_value *stack; mrb_value *stack;
...@@ -1657,12 +1660,12 @@ RETRY_TRY_BLOCK: ...@@ -1657,12 +1660,12 @@ RETRY_TRY_BLOCK:
else { else {
struct REnv *e = uvenv(mrb, lv-1); struct REnv *e = uvenv(mrb, lv-1);
if (!e) goto L_NOSUPER; 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; goto L_NOSUPER;
stack = e->stack + 1; stack = e->stack + 1;
} }
if (r == 0) { 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 { else {
mrb_value *pp = NULL; mrb_value *pp = NULL;
...@@ -1675,7 +1678,7 @@ RETRY_TRY_BLOCK: ...@@ -1675,7 +1678,7 @@ RETRY_TRY_BLOCK:
pp = ARY_PTR(ary); pp = ARY_PTR(ary);
len = (int)ARY_LEN(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]); rest = mrb_ary_ptr(regs[a]);
if (m1 > 0) { if (m1 > 0) {
stack_copy(ARY_PTR(rest), stack, m1); stack_copy(ARY_PTR(rest), stack, m1);
...@@ -1686,7 +1689,10 @@ RETRY_TRY_BLOCK: ...@@ -1686,7 +1689,10 @@ RETRY_TRY_BLOCK:
if (m2 > 0) { if (m2 > 0) {
stack_copy(ARY_PTR(rest)+m1+len, stack+m1+1, m2); 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]; regs[a+1] = stack[m1+r+m2];
mrb_gc_arena_restore(mrb, ai); mrb_gc_arena_restore(mrb, ai);
...@@ -1698,74 +1704,114 @@ RETRY_TRY_BLOCK: ...@@ -1698,74 +1704,114 @@ RETRY_TRY_BLOCK:
int o = MRB_ASPEC_OPT(a); int o = MRB_ASPEC_OPT(a);
int r = MRB_ASPEC_REST(a); int r = MRB_ASPEC_REST(a);
int m2 = MRB_ASPEC_POST(a); int m2 = MRB_ASPEC_POST(a);
int kd = (MRB_ASPEC_KEY(a) > 0 || MRB_ASPEC_KDICT(a))? 1 : 0;
/* unused /* unused
int k = MRB_ASPEC_KEY(a);
int kd = MRB_ASPEC_KDICT(a);
int b = MRB_ASPEC_BLOCK(a); int b = MRB_ASPEC_BLOCK(a);
*/ */
int argc = mrb->c->ci->argc; int argc = mrb->c->ci->argc;
mrb_value *argv = regs+1; mrb_value *argv = regs+1;
mrb_value *argv0 = argv; mrb_value * const argv0 = argv;
int len = m1 + o + r + m2; int const len = m1 + o + r + m2;
int const blk_pos = len + kd + 1;
mrb_value *blk = &argv[argc < 0 ? 1 : argc]; mrb_value *blk = &argv[argc < 0 ? 1 : argc];
mrb_value kdict;
int kargs = kd;
/* arguments is passed with Array */
if (argc < 0) { if (argc < 0) {
struct RArray *ary = mrb_ary_ptr(regs[1]); struct RArray *ary = mrb_ary_ptr(regs[1]);
argv = ARY_PTR(ary); argv = ARY_PTR(ary);
argc = (int)ARY_LEN(ary); argc = (int)ARY_LEN(ary);
mrb_gc_protect(mrb, regs[1]); mrb_gc_protect(mrb, regs[1]);
} }
/* strict argument check */
if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) { if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) {
if (argc >= 0) { if (argc >= 0 && !(argc <= 1 && kd)) {
if (argc < m1 + m2 || (r == 0 && argc > len)) { if (argc < m1 + m2 + kd || (r == 0 && argc > len + kd)) {
argnum_error(mrb, m1+m2); argnum_error(mrb, m1+m2);
goto L_RAISE; goto L_RAISE;
} }
} }
} }
/* extract first argument array to arguments */
else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) { else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) {
mrb_gc_protect(mrb, argv[0]); mrb_gc_protect(mrb, argv[0]);
argc = (int)RARRAY_LEN(argv[0]); argc = (int)RARRAY_LEN(argv[0]);
argv = RARRAY_PTR(argv[0]); argv = RARRAY_PTR(argv[0]);
} }
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 < len) { if (argc < len) {
int mlen = m2; int mlen = m2;
if (argc < m1+m2) { if (argc < m1+m2) {
if (m1 < argc) mlen = m1 < argc ? argc - m1 : 0;
mlen = argc - m1;
else
mlen = 0;
} }
regs[len+1] = *blk; /* move block */ regs[blk_pos] = *blk; /* move block */
if (kd) regs[len + 1] = kdict;
SET_NIL_VALUE(regs[argc+1]); SET_NIL_VALUE(regs[argc+1]);
/* copy mandatory and optional arguments */
if (argv0 != argv) { if (argv0 != argv) {
value_move(&regs[1], argv, argc-mlen); /* m1 + o */ value_move(&regs[1], argv, argc-mlen); /* m1 + o */
} }
if (argc < m1) { if (argc < m1) {
stack_clear(&regs[argc+1], m1-argc); stack_clear(&regs[argc+1], m1-argc);
} }
/* copy post mandatory arguments */
if (mlen) { if (mlen) {
value_move(&regs[len-m2+1], &argv[argc-mlen], mlen); value_move(&regs[len-m2+1], &argv[argc-mlen], mlen);
} }
if (mlen < m2) { if (mlen < m2) {
stack_clear(&regs[len-m2+mlen+1], m2-mlen); stack_clear(&regs[len-m2+mlen+1], m2-mlen);
} }
/* initalize rest arguments with empty Array */
if (r) { if (r) {
regs[m1+o+1] = mrb_ary_new_capa(mrb, 0); regs[m1+o+1] = mrb_ary_new_capa(mrb, 0);
} }
if (o > 0 && argc >= m1+m2) /* skip initailizer of passed arguments */
pc += (argc - m1 - m2)*3; if (o > 0 && argc-kargs >= m1+m2)
pc += (argc - kargs - m1 - m2)*3;
} }
else { else {
int rnum = 0; int rnum = 0;
if (argv0 != argv) { 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); value_move(&regs[1], argv, m1+o);
} }
if (r) { if (r) {
mrb_value ary; mrb_value ary;
rnum = argc-m1-o-m2; rnum = argc-m1-o-m2-kargs;
ary = mrb_ary_new_from_values(mrb, rnum, argv+m1+o); ary = mrb_ary_new_from_values(mrb, rnum, argv+m1+o);
regs[m1+o+1] = ary; regs[m1+o+1] = ary;
} }
...@@ -1775,29 +1821,60 @@ RETRY_TRY_BLOCK: ...@@ -1775,29 +1821,60 @@ RETRY_TRY_BLOCK:
} }
} }
if (argv0 == argv) { if (argv0 == argv) {
regs[len+1] = *blk; /* move block */ regs[blk_pos] = *blk; /* move block */
if (kd) regs[len + 1] = kdict;
} }
pc += o*3; 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 */ /* clear local (but non-argument) variables */
if (irep->nlocals-len-2 > 0) { if (irep->nlocals-blk_pos-1 > 0) {
stack_clear(&regs[len+2], irep->nlocals-len-2); stack_clear(&regs[blk_pos+1], irep->nlocals-blk_pos-1);
} }
JUMP; JUMP;
} }
CASE(OP_KARG, BB) { CASE(OP_KARG, BB) {
/* not implemented yet */ 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; NEXT;
} }
CASE(OP_KARG2, BB) {
/* not implemented yet */ 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_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; NEXT;
} }
CASE(OP_KDICT, B) { CASE(OP_KDICT, B) {
/* not implemented yet */ regs[a] = regs[mrb->c->ci->argc];
NEXT; NEXT;
} }
...@@ -2064,9 +2141,10 @@ RETRY_TRY_BLOCK: ...@@ -2064,9 +2141,10 @@ RETRY_TRY_BLOCK:
} }
CASE(OP_BLKPUSH, BS) { CASE(OP_BLKPUSH, BS) {
int m1 = (b>>10)&0x3f; int m1 = (b>>11)&0x3f;
int r = (b>>9)&0x1; int r = (b>>10)&0x1;
int m2 = (b>>4)&0x1f; int m2 = (b>>5)&0x1f;
int kd = (b>>4)&0x1;
int lv = (b>>0)&0xf; int lv = (b>>0)&0xf;
mrb_value *stack; mrb_value *stack;
...@@ -2084,7 +2162,7 @@ RETRY_TRY_BLOCK: ...@@ -2084,7 +2162,7 @@ RETRY_TRY_BLOCK:
localjump_error(mrb, LOCALJUMP_ERROR_YIELD); localjump_error(mrb, LOCALJUMP_ERROR_YIELD);
goto L_RAISE; goto L_RAISE;
} }
regs[a] = stack[m1+r+m2]; regs[a] = stack[m1+r+m2+kd];
NEXT; NEXT;
} }
......
...@@ -403,6 +403,9 @@ assert('External command execution.') do ...@@ -403,6 +403,9 @@ assert('External command execution.') do
assert_equal 'test dynamic `', t assert_equal 'test dynamic `', t
assert_equal ['test', 'test dynamic `', 'test', 'test dynamic `'], results 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 alias_method sym, :old_cmd
end end
true true
...@@ -466,3 +469,183 @@ this is a comment that has extra after =begin and =end with tabs after it ...@@ -466,3 +469,183 @@ this is a comment that has extra after =begin and =end with tabs after it
=end xxxxxxxxxxxxxxxxxxxxxxxxxx =end xxxxxxxxxxxxxxxxxxxxxxxxxx
assert_equal(line + 4, __LINE__) assert_equal(line + 4, __LINE__)
end 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 [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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment