Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mruby
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
mruby
Commits
8c9e7127
Commit
8c9e7127
authored
Jul 30, 2018
by
Yukihiro "Matz" Matsumoto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Keyword argument implemented.
parent
891839b9
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
887 additions
and
292 deletions
+887
-292
doc/opcode.md
doc/opcode.md
+4
-4
include/mruby/hash.h
include/mruby/hash.h
+25
-2
include/mruby/ops.h
include/mruby/ops.h
+6
-5
mrbgems/mruby-compiler/core/codegen.c
mrbgems/mruby-compiler/core/codegen.c
+114
-35
mrbgems/mruby-compiler/core/node.h
mrbgems/mruby-compiler/core/node.h
+4
-0
mrbgems/mruby-compiler/core/parse.y
mrbgems/mruby-compiler/core/parse.y
+311
-182
mrbgems/mruby-objectspace/src/mruby_objectspace.c
mrbgems/mruby-objectspace/src/mruby_objectspace.c
+1
-1
mrbgems/mruby-proc-ext/src/proc.c
mrbgems/mruby-proc-ext/src/proc.c
+9
-1
src/codedump.c
src/codedump.c
+34
-16
src/hash.c
src/hash.c
+75
-11
src/kernel.c
src/kernel.c
+9
-1
src/vm.c
src/vm.c
+112
-34
test/t/syntax.rb
test/t/syntax.rb
+183
-0
No files found.
doc/opcode.md
View file @
8c9e7127
...
...
@@ -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]=:-)
...
...
include/mruby/hash.h
View file @
8c9e7127
...
...
@@ -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
{
...
...
include/mruby/ops.h
View file @
8c9e7127
...
...
@@ -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:lv
4) */
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]=:-) */
...
...
mrbgems/mruby-compiler/core/codegen.c
View file @
8c9e7127
...
...
@@ -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
p
ush
_n_
(
codegen_scope
*
s
,
int
n
)
p
op
_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
();
gen
op_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
)
{
gen
op_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
);
gen
op_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
)
{
gen
op_1
(
s
,
OP_RETURN_BLK
,
cursp
());
gen
_return
(
s
,
OP_RETURN_BLK
,
cursp
());
}
else
{
gen
op_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
());
}
gen
op_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
());
}
gen
op_1
(
s
,
OP_BREAK
,
cursp
());
gen
_return
(
s
,
OP_BREAK
,
cursp
());
}
}
}
...
...
mrbgems/mruby-compiler/core/node.h
View file @
8c9e7127
...
...
@@ -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
,
...
...
mrbgems/mruby-compiler/core/parse.y
View file @
8c9e7127
...
...
@@ -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:
...
...
mrbgems/mruby-objectspace/src/mruby_objectspace.c
View file @
8c9e7127
...
...
@@ -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
);
}
...
...
mrbgems/mruby-proc-ext/src/proc.c
View file @
8c9e7127
...
...
@@ -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
);
}
...
...
src/codedump.c
View file @
8c9e7127
...
...
@@ -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
\t
R%d
\t
%d
\n
"
,
a
,
b
);
break
;
CASE
(
OP_ARGARY
,
BS
)
:
printf
(
"OP_ARGARY
\t
R%d
\t
%d:%d:%d:%d"
,
a
,
(
b
>>
10
)
&
0x3f
,
(
b
>>
9
)
&
0x1
,
(
b
>>
4
)
&
0x1f
,
printf
(
"OP_ARGARY
\t
R%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
\t
R(%d)
\t
K(%d)
\n
"
,
a
,
b
);
CASE
(
OP_KEY_P
,
BB
)
:
printf
(
"OP_KEY_P
\t
R%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
\t
R(%d)
\t
K(%d)
\n
"
,
a
,
b
);
CASE
(
OP_KEYEND
,
Z
)
:
printf
(
"OP_KEYEND
\n
"
);
break
;
CASE
(
OP_KARG
,
BB
)
:
printf
(
"OP_KARG
\t
R%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
\t
R(%d)
\n
"
,
a
);
printf
(
"OP_KDICT
\t
R%d
\t\t
"
,
a
);
print_lv_a
(
mrb
,
irep
,
a
);
break
;
CASE
(
OP_RETURN
,
B
)
:
printf
(
"OP_RETURN
\t
R%d"
,
a
);
printf
(
"OP_RETURN
\t
R%d
\t\t
"
,
a
);
print_lv_a
(
mrb
,
irep
,
a
);
break
;
CASE
(
OP_RETURN_BLK
,
B
)
:
printf
(
"OP_RETURN_BLK
\t
R%d"
,
a
);
printf
(
"OP_RETURN_BLK
\t
R%d
\t\t
"
,
a
);
print_lv_a
(
mrb
,
irep
,
a
);
break
;
CASE
(
OP_BREAK
,
B
)
:
printf
(
"OP_BREAK
\t
R%d"
,
a
);
printf
(
"OP_BREAK
\t
R%d
\t\t
"
,
a
);
print_lv_a
(
mrb
,
irep
,
a
);
break
;
CASE
(
OP_BLKPUSH
,
BS
)
:
printf
(
"OP_BLKPUSH
\t
R%d
\t
%d:%d:%d:%d"
,
a
,
(
b
>>
10
)
&
0x3f
,
(
b
>>
9
)
&
0x1
,
(
b
>>
4
)
&
0x1f
,
printf
(
"OP_BLKPUSH
\t
R%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
;
...
...
src/hash.c
View file @
8c9e7127
...
...
@@ -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 */
...
...
src/kernel.c
View file @
8c9e7127
...
...
@@ -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
;
...
...
src/vm.c
View file @
8c9e7127
...
...
@@ -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
;
}
...
...
test/t/syntax.rb
View file @
8c9e7127
...
...
@@ -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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment