has
yaml
=> ();
has
from
=> ();
has
code
=> ();
has
loader
=> ();
has
ns
=> ();
BEGIN {
my
$create_mapping
= \
&YAML::PP::Schema::create_mapping
;
my
$create_sequence
= \
&YAML::PP::Schema::create_sequence
;
my
$load_scalar
= \
&YAML::PP::Schema::load_scalar
;
no
warnings
'redefine'
;
*YAML::PP::Schema::create_mapping
=
sub
{
$_
[2]->{tag} //=
'-'
;
goto
$create_mapping
;
};
*YAML::PP::Schema::create_sequence
=
sub
{
$_
[2]->{tag} //=
'-'
;
goto
$create_sequence
;
};
*YAML::PP::Schema::load_scalar
=
sub
{
$_
[2]->{tag} //=
'-'
if
$_
[2]->{style} == 1;
goto
$load_scalar
;
};
}
my
$lc
=
qr/(?:[a-z])/
;
my
$dg
=
qw/(?:[0-9])/
;
my
$an
=
qr/(?:[a-z0-9])/
;
my
$sp
=
qr/(?:[-])/
;
my
$p1
=
qr/(?:$lc$an*)/
;
my
$pt
=
qr/(?:$an+)/
;
my
$id
=
qr/(?:$p1(?:$sp$pt)*)/
;
my
$punc
=
qr/(?:[\-\+\*\/
\.\=\<\>\:])/;
my
$ops
= {
'..'
=>
'range'
,
'+'
=>
'add'
,
'-'
=>
'sub'
,
};
my
$key_defn
=
qr/^($id)\((.*)\)$/
;
my
%exprs
= (
def
=>
qr/^($id)\ *=$/
,
defn
=>
$key_defn
,
op
=>
qr/^\(($punc+)\)$/
,
call
=>
qr/^($id)$/
,
);
sub
compile {
my
(
$self
) =
@_
;
my
$loader
=
$self
->{loader} =
YAML::PP->new(
schema
=> [
'Failsafe'
],
);
$self
->configure;
my
$yaml
=
$self
->yaml;
my
$code
=
$self
->{code} =
$loader
->load_string(
$yaml
);
my
$ns
= YAMLScript::NS->new(
need
=> [
'YS-Core'
],
);
while
(
my
(
$key
,
$val
) =
each
%$code
) {
if
(
$key
eq
'use'
) {
$val
= [
$val
]
unless
ref
(
$val
) eq
'ARRAY'
;
unshift
@$val
,
'YS-Core'
unless
grep
{
$_
eq
'YS-Core'
}
@$val
;
$ns
->need(
$val
);
}
else
{
$key
=~
$key_defn
or
die
"Invalid key '$key' in top level of '${\$self->from}'"
;
my
$name
= $1;
my
$sign
= $2;
$sign
= [
split
/\s*,\s*/,
$sign
];
my
$func
= YAMLScript::Func->new(
____
=>
$name
,
sign
=>
$sign
,
body
=>
$val
,
);
$ns
->vars->{
$name
} =
$func
;
}
}
return
$ns
;
}
sub
configure {
my
(
$self
) =
@_
;
my
$loader
=
$self
->loader;
my
$schema
=
$loader
->schema;
$schema
->add_mapping_resolver(
tag
=>
qr/^/
,
on_create
=>
sub
{
my
(
$constructor
,
$event
) =
@_
;
{};
},
on_data
=>
sub
{
my
(
$constructor
,
$ref
,
$data
) =
@_
;
my
$hash
=
$$ref
;
for
(
my
$i
= 0;
$i
<
@$data
;
$i
+= 2) {
my
(
$key
,
$val
) =
@$data
[
$i
,
$i
+1];
$key
=
$$key
if
ref
(
$key
) eq
'YAMLScript::Str'
;
if
(
ref
(
$val
) eq
'YAMLScript::Str'
) {
if
(
$$val
!~ /\
$$id
/) {
$val
=
$$val
;
}
}
$hash
->{
$key
} =
$val
;
}
if
(
@$data
== 2) {
my
(
$key
,
$val
) =
@$data
;
if
(
ref
(
$key
) eq
'YAMLScript::Str'
) {
$key
=
$$key
;
$val
=
delete
$hash
->{
$key
} or
die
;
if
(
$key
=~ /^([-\w]+)\s*=$/) {
$hash
->{____} =
'def'
;
$hash
->{args} = [$1,
$val
];
}
elsif
(
$key
=~ /^([-\w]+)\((.*)\)$/) {
my
(
$name
,
$sign
) = ($1, $2);
$sign
= [
split
/\s*,\s*/,
$sign
];
$val
= [
$val
]
unless
ref
(
$val
) eq
'ARRAY'
;
my
$func
=
bless
{
____
=>
$name
,
sign
=>
$sign
,
body
=>
$val
,
},
'YAMLScript::Func'
;
$hash
->{____} =
'defn'
;
$hash
->{args} =
$func
;
}
else
{
$hash
->{____} =
$key
;
$val
= [
$val
]
unless
ref
(
$val
) eq
'ARRAY'
;
$hash
->{args} =
$val
;
}
bless
$hash
,
'YAMLScript::Expr'
;
}
}
return
;
},
);
$schema
->add_sequence_resolver(
tag
=>
qr/^/
,
on_create
=>
sub
{
my
$tag
=
$_
[1]->{tag};
if
(
$tag
eq
'-'
) {
return
[];
}
else
{
return
{
____
=>
substr
(
$tag
, 1)};
}
},
on_data
=>
sub
{
my
(
$constructor
,
$ref
,
$data
) =
@_
;
if
(
ref
(
$$ref
) eq
'HASH'
) {
my
$hash
=
bless
$$ref
,
'YAMLScript::Expr'
;
my
$args
= [
map
{
if
(
ref
eq
'YAMLScript::Str'
) {
if
(
$$_
!~ /\
$$id
/) {
$_
=
$$_
;
}
}
$_
;
}
@$data
];
$hash
->{args} =
$args
;
}
else
{
my
$array
=
$$ref
;
for
my
$val
(
@$data
) {
if
(
ref
(
$val
) eq
'YAMLScript::Str'
) {
if
(
$$val
!~ /\
$$id
/) {
$val
=
$$val
;
}
}
push
@$array
,
$val
;
}
}
},
);
my
$re_num
=
qr/^-?\d+$/
;
$schema
->add_resolver(
tag
=>
'-'
,
match
=> [
all
=>
sub
{
my
(
$constructor
,
$event
) =
@_
;
my
$value
=
$event
->{value};
if
(
$value
=~
$re_num
) {
$value
+= 0;
return
$value
;
}
return
bless
\
$value
,
'YAMLScript::Str'
;
},
],
);
}