#!/usr/bin/perl
use
5.010001;
use
Fatal
qw( open close )
;
my
$trace_rules
=
q{}
;
sub
do_S {
my
(
$action_object
) =
@_
;
my
$rule_id
=
$Marpa::R3::Context::rule
;
my
$slg
=
$Marpa::R3::Context::slg
;
my
(
$lhs
,
@rhs
) =
map
{
$slg
->symbol_display_form(
$_
) }
$slg
->rule_expand(
$rule_id
);
$action_object
->{text} =
"rule $rule_id: $lhs ::= "
. (
join
q{ }
,
@rhs
) .
"\n"
.
"locations: "
. (
join
q{-}
, Marpa::R3::Context::g1_range() ) .
"\n"
;
return
$action_object
;
}
my
$bail_message
=
"This is a bail out message!"
;
sub
do_bail_with_message_if_A {
my
(
$action_object
,
$terminal
) =
@_
;
Marpa::R3::Context::bail(
$bail_message
)
if
$terminal
eq
'A'
;
}
sub
do_bail_with_object_if_A {
my
(
$action_object
,
$terminal
) =
@_
;
Marpa::R3::Context::bail([
$bail_message
])
if
$terminal
eq
'A'
;
}
my
@terminals
=
qw/A B C D/
;
my
$grammar
= Marpa::R3::Scanless::G->new(
{
source
=> \
<<'END_OF_SOURCE',
:start ::= S
S ::= A B C D action => main::do_S
A ~ 'A'
B ~ 'B'
C ~ 'C'
D ~ 'D'
END_OF_SOURCE
});
sub
do_parse {
my
$slr
= Marpa::R3::Scanless::R->new( {
grammar
=>
$grammar
} );
$slr
->
read
( \
'ABCD'
);
return
$slr
->value();
}
my
$value_ref
;
$value_ref
= do_parse();
VALUE_TEST: {
if
(
ref
$value_ref
ne
'REF'
) {
my
$ref_type
=
ref
$value_ref
;
Test::More::fail(
qq{Parse result ref type is "$ref_type"; it needs to be "REF"}
);
last
VALUE_TEST;
}
my
$value
= ${
$value_ref
};
if
(
ref
$value
ne
'HASH'
) {
my
$ref_type
=
ref
$value
;
Test::More::fail(
qq{Parse value ref type is "$ref_type"; it needs to be "HASH"}
);
last
VALUE_TEST;
}
my
$expected_text
=
qq{rule 0: S ::= A B C D\nlocations: 0-4\n}
;
Test::More::is(
$value
->{text},
$expected_text
,
'Parse ok?'
);
}
my
$eval_ok
;
{
local
*do_S
=
*do_bail_with_message_if_A
;
$eval_ok
=
eval
{
$value_ref
= do_parse(); 1 };
}
my
$actual_eval_error
=
$EVAL_ERROR
//
'no eval error'
;
Test::More::ok( ( not
defined
$eval_ok
),
"bail with string argument happened"
);
$actual_eval_error
=~ s/\A User \s+ bailed \s+ at \s+ line \s+ \d+ [^\n]* \n/<LOCATION LINE>/xms;
Test::More::is(
$actual_eval_error
,
'<LOCATION LINE>'
.
$bail_message
.
"\n"
,
"bail with string argument"
);
{
local
*do_S
=
*do_bail_with_object_if_A
;
$eval_ok
=
eval
{
$value_ref
= do_parse(); 1 };
}
$actual_eval_error
=
$EVAL_ERROR
;
my
$eval_error_ref_type
=
ref
$actual_eval_error
;
my
$exception_value_desc
=
$eval_error_ref_type
eq
'ARRAY'
?
$actual_eval_error
->[0]
:
"ref type of exception is $eval_error_ref_type"
;
Test::More::ok( ( not
defined
$eval_ok
),
"bail with object argument happened"
);
Test::More::is(
$eval_error_ref_type
,
'ARRAY'
,
"bail with object argument ref type"
);
Test::More::is(
$exception_value_desc
,
$bail_message
,
"bail with object argument value"
);