Keyword argument implemented.

parent 891839b9
......@@ -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_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=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_KARG" |BB |R(a) = kdict[Syms(Bx)] # 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.
|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=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_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (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.
|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=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_KARG" |BB |R(a) = kdict[Syms(Bx)] # 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.
|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=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_ADDI" |BBB |R(a) = R(a)+mrb_int(c) (Syms[b]=:+)
|OP_SUB" |BB |R(a) = R(a)-R(a+1) (Syms[b]=:-)
......
......@@ -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,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);
/*
* 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 */
/* be careful when you touch the internal */
typedef struct {
......
......@@ -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(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=6:1:5:4) */
OPCODE(ENTER, W) /* arg setup according to flags (23=5:5:1:5:5:1:1) */
OPCODE(KARG, BB) /* R(a) = kdict[Syms(Bx)] # todo */
OPCODE(KARG2, BB) /* R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo */
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(KDICT, B) /* R(a) = kdict # 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=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(ADDI, BBB) /* R(a) = R(a)+mrb_int(c) (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)
if (no_peephole(s)) {
normal:
genop_2(s, OP_MOVE, dst, src);
if (on_eval(s)) {
genop_0(s, OP_NOP);
}
return;
}
else {
......@@ -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
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)
#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 >= 0xffff) {
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 >= 0xffff) {
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
......@@ -644,8 +664,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)
{
......@@ -694,7 +718,7 @@ for_body(codegen_scope *s, node *tree)
/* loop body */
codegen(s, tree->cdr->cdr->car, VAL);
pop();
genop_1(s, OP_RETURN, cursp());
gen_return(s, OP_RETURN, cursp());
loop_pop(s, NOVAL);
scope_finish(s);
s = prev;
......@@ -726,32 +750,44 @@ 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);
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);
......@@ -776,11 +812,50 @@ lambda_body(codegen_scope *s, node *tree, int blk)
if (oa > 0) {
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) {
genop_1(s, OP_RETURN, cursp());
gen_return(s, OP_RETURN, cursp());
}
if (blk) {
loop_pop(s, NOVAL);
......@@ -798,7 +873,7 @@ scope_body(codegen_scope *s, node *tree, int 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) {
genop_0(scope, OP_STOP);
}
......@@ -810,9 +885,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)
{
......@@ -1703,11 +1775,18 @@ 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) {
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->cdr, val);
len++;
......@@ -2055,10 +2134,10 @@ codegen(codegen_scope *s, node *tree, int val)
genop_1(s, OP_LOADNIL, cursp());
}
if (s->loop) {
genop_1(s, OP_RETURN_BLK, cursp());
gen_return(s, OP_RETURN_BLK, cursp());
}
else {
genop_1(s, OP_RETURN, cursp());
gen_return(s, OP_RETURN, cursp());
}
if (val) push();
break;
......@@ -2116,7 +2195,7 @@ codegen(codegen_scope *s, node *tree, int val)
else {
genop_1(s, OP_LOADNIL, cursp());
}
genop_1(s, OP_RETURN, cursp());
gen_return(s, OP_RETURN, cursp());
}
if (val) push();
break;
......@@ -2999,7 +3078,7 @@ loop_break(codegen_scope *s, node *tree)
if (!tree) {
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 {
NODE_ARRAY,
NODE_ZARRAY,
NODE_HASH,
NODE_KW_HASH,
NODE_RETURN,
NODE_YIELD,
NODE_LVAR,
......@@ -73,6 +74,9 @@ enum node_type {
NODE_DREGX_ONCE,
NODE_LIST,
NODE_ARG,
NODE_ARGS_TAIL,
NODE_KW_ARG,
NODE_KW_REST_ARGS,
NODE_ARGSCAT,
NODE_ARGSPUSH,
NODE_SPLAT,
......
......@@ -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 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 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,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);
}
| 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 +3356,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 +3367,6 @@ blkarg_mark : '&'
f_block_arg : blkarg_mark tIDENTIFIER
{
local_add_f(p, $2);
$$ = $2;
}
;
......@@ -3211,7 +3377,6 @@ opt_f_block_arg : ',' f_block_arg
}
| none
{
local_add_f(p, 0);
$$ = 0;
}
;
......@@ -3285,6 +3450,10 @@ assoc : arg tASSOC arg
$$ = cons(new_sym(p, new_strsym(p, $1)), $3);
}
}
| tDSTAR arg_value
{
$$ = cons(cons((node*)NODE_KW_REST_ARGS, 0), $2);
}
;
operation : tIDENTIFIER
......@@ -3450,13 +3619,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 +3638,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 +3677,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 +3726,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 +3751,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 +4188,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 +4534,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 == '=') {
......@@ -5547,7 +5725,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++;
......@@ -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
void
......@@ -5908,7 +6128,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:
......@@ -5968,7 +6188,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:
......@@ -5976,43 +6197,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");
......@@ -6164,7 +6349,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);
......@@ -6281,7 +6466,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;
......@@ -6363,11 +6548,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:
......@@ -6380,7 +6565,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:
......@@ -6393,7 +6578,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:
......@@ -6402,7 +6587,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:
......@@ -6431,7 +6616,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:
......@@ -6547,43 +6732,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;
......@@ -6596,44 +6745,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);
......@@ -6649,18 +6761,35 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
break;
case NODE_LITERAL_DELIM:
printf("NODE_LITERAL_DELIM\n");
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_SYMBOLS:
printf("NODE_SYMBOLS:\n");
dump_recur(mrb, tree, offset+1);
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_WORDS:
printf("NODE_SYMBOLS:\n");
dump_recur(mrb, tree, offset+1);
case NODE_KW_REST_ARGS:
printf("NODE_KW_REST_ARGS %s\n", mrb_sym2name(mrb, sym(tree)));
break;
default:
......
......@@ -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);
}
......
......@@ -149,7 +149,15 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
a = mrb_ary_new(mrb);
mrb_ary_push(mrb, a, sname);
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);
}
......
......@@ -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,
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;
pcend = pc + irep->ilen;
while (pc < pcend) {
......@@ -246,10 +256,11 @@ codedump(mrb_state *mrb, mrb_irep *irep)
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", a,
(b>>10)&0x3f,
(b>>9)&0x1,
(b>>4)&0x1f,
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;
......@@ -263,32 +274,39 @@ codedump(mrb_state *mrb, mrb_irep *irep)
(a>>1)&0x1,
a & 0x1);
break;
CASE(OP_KARG, BB):
printf("OP_KARG\tR(%d)\tK(%d)\n", a, b);
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_KARG2, BB):
printf("OP_KARG2\tR(%d)\tK(%d)\n", a, b);
CASE(OP_KEYEND, Z):
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;
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;
CASE(OP_RETURN, B):
printf("OP_RETURN\tR%d", a);
printf("OP_RETURN\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
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);
break;
CASE(OP_BREAK, B):
printf("OP_BREAK\tR%d", a);
printf("OP_BREAK\tR%d\t\t", a);
print_lv_a(mrb, irep, a);
break;
CASE(OP_BLKPUSH, BS):
printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d", a,
(b>>10)&0x3f,
(b>>9)&0x1,
(b>>4)&0x1f,
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;
......
......@@ -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 */
......@@ -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_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 */
......
......@@ -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;
......
......@@ -969,6 +969,8 @@ check_target_class(mrb_state *mrb)
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)
{
......@@ -1639,9 +1641,10 @@ RETRY_TRY_BLOCK:
}
CASE(OP_ARGARY, BS) {
int m1 = (b>>10)&0x3f;
int r = (b>>9)&0x1;
int m2 = (b>>4)&0x1f;
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;
......@@ -1657,12 +1660,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;
......@@ -1675,7 +1678,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);
......@@ -1686,7 +1689,10 @@ 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);
......@@ -1698,74 +1704,114 @@ RETRY_TRY_BLOCK:
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(a);
int kd = MRB_ASPEC_KDICT(a);
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 (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) {
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 */
regs[blk_pos] = *blk; /* move block */
if (kd) regs[len + 1] = kdict;
SET_NIL_VALUE(regs[argc+1]);
/* 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 += (argc - m1 - m2)*3;
/* 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) {
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);
regs[m1+o+1] = ary;
}
......@@ -1775,29 +1821,60 @@ 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*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, 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;
}
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;
}
CASE(OP_KDICT, B) {
/* not implemented yet */
regs[a] = regs[mrb->c->ci->argc];
NEXT;
}
......@@ -2064,9 +2141,10 @@ RETRY_TRY_BLOCK:
}
CASE(OP_BLKPUSH, BS) {
int m1 = (b>>10)&0x3f;
int r = (b>>9)&0x1;
int m2 = (b>>4)&0x1f;
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;
......@@ -2084,7 +2162,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;
}
......
......@@ -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,183 @@ 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 [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