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
Expand all
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
This diff is collapsed.
Click to expand it.
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