#!/usr/bin/perl use strict; use warnings; use 5.10.1; use Nana::Translator::Perl; use Nana::Parser; use Getopt::Long::Descriptive; use Data::Dumper; use Nana::Translator::Perl::Runtime; my ($opt, $usage) = describe_options( 'nana %o ', [], [ 'Dperl', "Dump perl code" ], [ 'Dtree|Dt', "Dump AST" ], [ 'eval|e=s', "Eval expression" ], [ 'I=s@', "Library path" ], [ 'compile-only|c', "Compile only" ], [ 'help|h', "print usage message and exit" ], [ 'version|v', 'print version'], ); if ($opt->help) { print $usage; exit 0; } if ($opt->version) { print "Nana $Nana::Parser::VERSION\n"; exit 0; } Nana::Translator::Perl::Runtime->add_libpath($opt->i || []); my $parser = Nana::Parser->new; my $compiler = Nana::Translator::Perl->new(); if (defined $opt->eval) { my $ast = $parser->parse($opt->eval); say(dump_ast($ast)) if $opt->dtree; my $perl = $compiler->compile($ast, ''); if ($opt->compile_only) { say($perl); exit(0); } else { say($perl) if $opt->dperl; eval $perl; die $@ if $@; } } elsif (@ARGV) { my $fname = shift @ARGV; open my $fh, '<', $fname or die "Cannot open $fname: $!\n"; my $ast = $parser->parse(do { local $/; <$fh>; }, $fname); say(Dumper($ast)) if $opt->dtree; my $perl = $compiler->compile($ast, $fname); if ($opt->compile_only) { print($perl); exit(0); } else { say($perl) if $opt->dperl; eval $perl; die $@ if $@; } } else { if (-t STDIN && -t STDOUT && !$opt->compile_only) { while (1) { print(">> "); last if eof(STDIN); my $input = <>; my $ast = $parser->parse($input); my $perl = $compiler->compile($ast); say("PERL: $perl") if $opt->dperl; my $ret = eval $perl; die $@ if $@; local $Data::Dumper::Terse = 1; warn Dumper($ret); } } else { my $input = join('', <>); my $ast = $parser->parse($input); my $perl = $compiler->compile($ast); eval $perl; die $@ if $@; } } sub dump_ast { my $ast = shift; require Nana::Node; Nana::Node->import(); say _dump_ast($ast); } sub _dump_ast { my $node = shift; my $ret = '['; $ret .= node_name($node->[0]); if ($node->[0] == NODE_STMTS()) { for my $n (@{$node->[2]}) { $ret .= ',' . _dump_ast($n); } } elsif ($node->[0] == NODE_MY()) { $ret .= '['; for my $n (@{$node->[2]}) { if (ref $n eq 'ARRAY') { $ret .= ',' . _dump_ast($n); } else { $ret .= ',' . $n; } } $ret .= ']'; } elsif ($node->[0] == NODE_CALL()) { $ret .= ',' . _dump_ast($node->[2]); $ret .= '['; for my $n (@{$node->[3]}) { if (ref $n eq 'ARRAY') { $ret .= ',' . _dump_ast($n); } else { $ret .= ',' . $n; } } $ret .= ']'; } else { my @node = @$node; shift @node; shift @node; for my $n (@node) { if (ref $n eq 'ARRAY') { $ret .= ',' . _dump_ast($n); } else { $ret .= ',' . $n; } } } return $ret . ']'; } __END__ =head1 NAME nana - tora language interpreter =head1 SYNPOSIS nana [-cehI] [long options...] --Dperl Dump perl code --Dt --Dtree Dump AST -e --eval Eval expression -I Library path -c --compile-only Compile only -h --help print usage message and exit =head1 DESCRIPTION Yet another tora language interpreter on Perl5. =head1 SEE ALSO L