# PIL2-JSON simple tokenizer, parser, and code emitter
# ../../pugs -CPIL2-JSON -e ' say "hello" ' | ../../pugs pil2_json_emit.pl

use v6-alpha;

# tokenizer

my $tokens =
    m:g:perl5 {(\"(?:\\\\|\\"|.)*?\"|[\:\,\=\{\(\[\}\)\]]|\w+)};

# JSON parser 
# outputs a p6 tree = Hash of Array|Hash|Scalar ...

sub parse (@start, $token, @end, @_ is rw) {
    state %tok = (
        token => sub (@_ is rw) { 
                ~ @_.shift;     # '~' stringifies "Match" object
            },
        hash =>  sub (@_ is rw) {
                my Array $a;
                loop {
                    return $a if @_[0] eq '}';
                    push $a, parse( <<>>, 'pair', <<>>, @_ );
                    return $a if @_[0] ne ',';
                    @_.shift; 
                }
            },
        list =>  sub (@_ is rw) {
                my Array $a;
                loop {
                    return $a if @_[0] eq ']';
                    push $a, parse( <<>>, 'item', <<>>, @_ );
                    return $a if @_[0] ne ',';
                    @_.shift; 
                }
            },
        pair =>  sub (@_ is rw) {
                my $key = parse( <<>>, 'token', << : >>, @_ );
                # say " Key $key";
                my $value = parse( <<>>, 'item', <<>>, @_ );
                [ $key, $value ];
            },
        item =>  sub (@_ is rw) {
                if @_[0] eq '{' { 
                    return parse( << { >>, 'hash', << } >>, @_ ) 
                };
                if @_[0] eq '[' { 
                    return parse( << [ >>, 'list', << ] >>, @_ ) 
                };
                parse( <<>>, 'token', <<>>, @_ );
            },
    );
    # say " parse: @start[] <$token> @end[]";
    for @start { @_.shift eq $_ or die "Expected $_" }; 
    # say " Tail @_[]";
    my $ret = %tok{$token}( @_ );
    for @end   { @_.shift eq $_ or die "Expected $_" }; 
    $ret;
}

#my @pil2 = =<>;
#my $pil2 = @pil2.join('');

# slurp stdin - xinming++ 
my $pil2 = ** $*IN.slurp;

my @b = $pil2 ~~ $tokens;
# say "Tokens: ", @b.join('><');
my $ast = parse( << { >>, 'hash', << } >>, @b );
# say $ast.perl;

sub print_tree ( $tree ) {
    state $depth = 0;
    $depth++;

    if $tree.WHAT eq 'Array' {

        return if $tree[0] eq '"pPos"';  # ignore position info

        for $tree.values {
            print_tree( $_ );
        }
        say '  ' x ( $depth - 1 ), '-';
    }
    else {
        say '  ' x $depth, "< $tree >";
    }

    $depth--;
}

sub traverse_stmts ( $tree ) {
    if $tree.WHAT eq 'Array' {
        #say $tree.perl;
        if $tree[0] eq '"PApp"' {   
            state $depth = 0;
            $depth++;
            my $tab = '  ' x $depth;

            say "$tab < App start >";
            my %app = $tree[1];  # keys: "pArgs" "pCxt" "pFun" "pInv"
            #say %app.keys;
            say "$tab     Function:  %app<"pFun">";
            say "$tab     Arguments: %app<"pArgs">";
            say "$tab     Context:   %app<"pCxt">";
            say "$tab     Invocant:  %app<"pInv">";
            # print_tree( $tree[1] )
            traverse_stmts( $tree[1] );
            say "$tab < App end >";

            $depth--;
        }
        else {
            traverse_stmts( $_ ) for $tree
        }
    }
}

traverse_stmts( $ast );

# TODO - process BEGIN, END, ...
