package Perlito5::Grammar::Number;
use strict;
use Perlito5::Grammar::Precedence;

token term_digit {
    | <Perlito5::Grammar::Number::val_octal>
        # 0123
        { $MATCH->{capture} = [ 'term', Perlito5::Match::flat($MATCH->{"Perlito5::Grammar::Number::val_octal"}) ]  }
    | <Perlito5::Grammar::Number::val_vstring>
        # 123.456.789
        { $MATCH->{capture} = [ 'term', Perlito5::Match::flat($MATCH->{"Perlito5::Grammar::Number::val_vstring"}) ]  }
    | <Perlito5::Grammar::Number::val_num>
        # 123.456
        { $MATCH->{capture} = [ 'term', Perlito5::Match::flat($MATCH->{"Perlito5::Grammar::Number::val_num"}) ]  }
    | <Perlito5::Grammar::Number::val_int>
        # 123
        { $MATCH->{capture} = [ 'term', Perlito5::Match::flat($MATCH->{"Perlito5::Grammar::Number::val_int"}) ]  }
};

Perlito5::Grammar::Precedence::add_term( $_  => \&term_digit )
    for '.', '0' .. '9';


sub digit {
    substr( $_[0], $_[1], 1 ) =~ m/\d/
    ? {
        str  => $_[0],
        from => $_[1],
        to   => $_[1] + 1,
      }
    : 0;
}

token exponent {
    [ 'e' | 'E' ]  [ '+' | '-' | '' ]  [ '_' | \d ]+
};

token val_num {
    [   \. \d [ '_' | \d]*    <.exponent>?    # .10 .10e10
    |      \d [ '_' | \d]*  [ <.exponent>  |   \. <!before \. > [ '_' | \d]*  <.exponent>? ]
    ]
    {
        my $s = Perlito5::Match::flat($MATCH);
        $s =~ s/_//g;
        $MATCH->{capture} = Perlito5::AST::Num->new( num => $s ) 
    }
};

token digits {
    \d+
};

token digits_underscore {
    \d [ '_' | \d]*
};

token val_octal {
    '0' [  ['x'|'X'] <.Perlito5::Grammar::word>+   # XXX test for hex digits
        |  ['b'|'B'] [ '_' | '0' | '1' ]+
        |  [ '_' | \d]+        # XXX test for octal digits
        ]
        { $MATCH->{capture} = Perlito5::AST::Int->new( int => oct(lc(Perlito5::Match::flat($MATCH))) ) }
};

token val_int {
    <.digits_underscore>
        {
            my $s = Perlito5::Match::flat($MATCH);
            $s =~ s/_//g;
            $MATCH->{capture} = Perlito5::AST::Int->new( int => $s )
        }
};

token val_vstring {
    <val_int> [ '.' <digits_underscore> ]+
    {
        my @parts = map { Perlito5::Match::flat($_) }
                        @{ $MATCH->{digits_underscore} };
        return if @parts < 2;
        $MATCH->{capture} = Perlito5::AST::Buf->new(
                    buf => join( '', map { chr($_) }
                                        $MATCH->{val_int}{capture}{int},
                                        @parts,
                               ),
               );
    }
};

token val_version {
    'v' <val_int> [ '.' <digits_underscore> ]*
    {
        my @parts = map { Perlito5::Match::flat($_) }
                        @{ $MATCH->{digits_underscore} };
        $MATCH->{capture} = Perlito5::AST::Buf->new(
                    buf => join( '', map { chr($_) }
                                        $MATCH->{val_int}{capture}{int},
                                        @parts,
                               ),
               );
    }
};

1;

=begin

=head1 NAME

Perlito5::Grammar::Number - Parser and AST generator for Perlito

=head1 SYNOPSIS

    term_digit($str)

=head1 DESCRIPTION

This module parses source code for Perl 5 statements and generates Perlito5 AST.

=head1 AUTHORS

Flavio Soibelmann Glock <fglock@gmail.com>.
The Pugs Team E<lt>perl6-compiler@perl.orgE<gt>.

=head1 COPYRIGHT

Copyright 2013 by Flavio Soibelmann Glock and others.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

See L<http://www.perl.com/perl/misc/Artistic.html>

=end