Dallycot
view release on metacpan or search on metacpan
lib/Dallycot/Parser.pm view on Meta::CPAN
package Dallycot::Parser;
our $AUTHORITY = 'cpan:JSMITH';
# ABSTRACT: Parse Dallycot source into an abstract syntax tree
use strict;
use warnings;
use utf8;
use experimental qw(switch);
use Marpa::R2;
use Math::BigRat;
use Dallycot::Value::String;
use Dallycot::Value::URI;
use Scalar::Util qw(blessed);
use String::Escape qw(unbackslash unquote);
use Dallycot::AST::Sequence;
use Dallycot::AST::Apply;
use Dallycot::Value::URI;
my $grammar = Marpa::R2::Scanless::G->new(
{ action_object => __PACKAGE__,
bless_package => 'Dallycot::AST',
default_action => 'copy_arg0',
source => do { local ($/) = undef; my $s = <DATA>; \$s; }
}
);
sub new {
my ($class) = @_;
$class = ref($class) || $class;
return bless {} => $class;
}
sub grammar { return $grammar; }
sub wants_more {
my ( $self, $val ) = @_;
if ( @_ == 2 ) {
$self->{wants_more} = $val;
}
return $self->{wants_more};
}
sub error {
my ( $self, $val ) = @_;
if ( @_ == 2 ) {
$self->{error} = $val;
}
return $self->{error};
}
sub warnings {
my ( $self, $warnings ) = @_;
if ( @_ == 2 ) {
$self->{warnings} = $warnings;
}
if (wantarray) {
return @{ $self->{warnings} };
}
else {
return @{ $self->{warnings} } != 0;
}
}
sub parse {
my ( $self, $input ) = @_;
my $re = Marpa::R2::Scanless::R->new( { grammar => $self->grammar } );
$self->error(undef);
$self->warnings( [] );
my $worked = eval {
$re->read( \$input );
1;
};
if ($@) {
$@ =~ s{Marpa::R2\s+exception\s+at.*$}{}xs;
$self->error($@);
return;
}
elsif ( !$worked ) {
$self->error("Unable to parse.");
return;
}
my $parse = $re->value;
my $result;
lib/Dallycot/Parser.pm view on Meta::CPAN
return bless $constants => 'Dallycot::Value::Vector';
}
sub empty_set {
return bless [] => 'Dallycot::Value::Set';
}
sub build_set {
my ( undef, $expressions ) = @_;
my @expressions = map { flatten_union($_) } @$expressions;
return bless \@expressions => 'Dallycot::AST::BuildSet';
}
sub flatten_union {
my ($thing) = @_;
if ( $thing->isa('Dallycot::AST::Union') ) {
return @$thing;
}
else {
return $thing;
}
}
sub stream_constant {
my ( undef, $constants ) = @_;
if (@$constants) {
my $result = bless [ pop @$constants, undef ] => 'Dallycot::Value::Stream';
while (@$constants) {
$result = bless [ pop @$constants, $result ] => 'Dallycot::Value::Stream';
}
return $result;
}
else {
return bless [] => 'Dallycot::Value::EmptyStream';
}
}
sub _flatten_binary {
my ( undef, $class, $left_value, $right_value ) = @_;
if ( ref $left_value eq $class ) {
if ( $right_value eq $class ) {
push @{$left_value}, @{$right_value};
return $left_value;
}
else {
push @{$left_value}, $right_value;
return $left_value;
}
}
elsif ( ref $right_value eq $class ) {
unshift @$right_value, $left_value;
return $right_value;
}
else {
return bless [ $left_value, $right_value ] => $class;
}
}
sub zip {
my ( undef, $left_value, $right_value ) = @_;
return _flatten_binary( undef, 'Dallycot::AST::Zip', $left_value, $right_value );
}
sub set_union {
my ( undef, $left_value, $right_value ) = @_;
return _flatten_binary( undef, 'Dallycot::AST::Union', $left_value, $right_value );
}
sub set_intersection {
my ( undef, $left_value, $right_value ) = @_;
return _flatten_binary( undef, 'Dallycot::AST::Intersection', $left_value, $right_value );
}
sub vector_index {
my ( undef, $vector, $index ) = @_;
if ( ref $vector eq 'Dallycot::AST::Index' ) {
push @{$vector}, $index;
return $vector;
}
else {
return bless [ $vector, $index ] => 'Dallycot::AST::Index';
}
}
sub vector_push {
my ( undef, $vector, $scalar ) = @_;
if ( $vector->[0] eq 'Push' ) {
push @{$vector}, $scalar;
return $vector;
}
else {
return [ Push => ( $vector, $scalar ) ];
}
}
sub defined_q {
my ( undef, $expression ) = @_;
return bless [$expression] => 'Dallycot::AST::Defined';
}
##
# Eventually, Range will be a type representing all values between
# two endpoints.
#
# Q: how to indicate open/closed endpoints
#
# ( e1 .. e2 )
# [ e1 .. e2 )
# ( e1 .. e2 ]
( run in 2.123 seconds using v1.01-cache-2.11-cpan-75ffa21a3d4 )