Skip to content

Commit

Permalink
- Fixed the Optimizer and the Sidef deparser.
Browse files Browse the repository at this point in the history
- Added three optimization levels:

	0 -> does nothing (default)
	1 -> does constant folding on the AST
	2 -> does constant folding, then it deparses the AST into code and parses the code again, after which it does another constant folding on the new AST

- Improved and fixed some corner cases inside the Parser.

For example:
	obj->method[0];		# didn't work before correctly
				# now it means: (obj->method)[0]

- Improved the interactive mode to supprot deparsing with optimization levels specified.

Example:
	$ sidef -i -r -O1	# enters in interactive mode and prints the deparsed code with constant-folding applied
	>> say (1 + 2)
	say(3);			# prints this
	>>
  • Loading branch information
trizen committed Oct 30, 2015
1 parent 1ee0672 commit 83d3450
Show file tree
Hide file tree
Showing 23 changed files with 536 additions and 256 deletions.
54 changes: 39 additions & 15 deletions bin/sidef
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ sub NATIVE () { 0 }
my %args;
if ($#ARGV != -1 and chr ord $ARGV[0] eq '-') {
require Getopt::Std;
Getopt::Std::getopts('e:E:d:Dho:ivHn:WwbcrR:ts:C', \%args);
Getopt::Std::getopts('e:E:d:Dho:ivHn:WwbcrR:ts:CO:', \%args);
}

# Help
Expand Down Expand Up @@ -180,9 +180,6 @@ else {
my $header = "\nuse lib (" . join(', ', map { qq{"\Q$_\E"} } @INC) . ");\n" . "use Sidef;\n";
$deparsed = $header . $deparsed;
}
else {
warn "\n# NOTE: deparsing to Sidef is not fully implemented!\n\n";
}

output($deparsed);
}
Expand Down Expand Up @@ -233,7 +230,35 @@ sub optimize_struct {

sub parse_code {
my ($parser, $code) = @_;
scalar $parser->parse_script(code => \$code);

my $struct = $parser->parse_script(code => \$code);

# Check for optimization
if (defined($args{O})) {

# Optimize the AST
if ($args{O} >= 1) {
$struct = optimize_struct($struct);
}

# Deparse the AST into code, then parse the code again.
if ($args{O} >= 2) {
my $deparser = Sidef::Deparse::Sidef->new(namespaces => [@Sidef::NAMESPACES]);
my $code = $deparser->deparse($struct);

local %Sidef::INCLUDED;
local @Sidef::NAMESPACES;

$struct = Sidef::Parser->new(
file_name => $parser->{file_name},
script_name => $parser->{script_name},
)->parse_script(code => \$code);

$struct = optimize_struct($struct);
}
}

$struct;
}

sub load_math_backend {
Expand Down Expand Up @@ -264,6 +289,7 @@ sub output_usage {
'-d file' => 'load a dumped syntax tree',
'-D' => 'dump the syntax tree of a program',
'-o file' => 'file where to dump the output',
'-O level' => ['perform code optimizations before execution', 'valid levels: 0, 1, 2'],
'-E program' => 'one line of program',
'-H' => 'interactive help',
'-n type' => ['try to use a specific backend for Math::BigInt', 'valid types: GMP, Pari, FastCalc'],
Expand Down Expand Up @@ -342,7 +368,8 @@ HELP

my $parser = new_parser(name => '-H');
$parser->{interactive} = 1;
my $struct = eval { $parser->parse_script(code => \$line) };

my $struct = eval { parse_code($parser, $line) };

if ($@) {
warn $@;
Expand Down Expand Up @@ -445,18 +472,15 @@ EOT
}

# Remove 'var' declarations (if any)
$line =~ s/^\h*var\b\h*//;
if (not defined($args{r}) and not defined($args{R})) {
$line =~ s/^\h*var\b\h*//;
}

$last_line = $line;

my $struct = eval { $parser->parse_script(code => \$line) };
my $struct = eval { parse_code($parser, $line) };

$@ && do {
warn $@;

# $parser = new_parser(name => '-i');
# $parser->{interactive} = 1;

redo;
};

Expand Down Expand Up @@ -546,7 +570,7 @@ sub dump_structure {
print {$out_fh} _get_namespaces();
print {$out_fh} "use Math::BigFloat;\n";
print {$out_fh} $requirify->(_get_loaded_modules());
print {$out_fh} Data::Dump::pp($struct);
print {$out_fh} Data::Dump::pp($struct) . "\n";
}
}

Expand Down Expand Up @@ -603,7 +627,7 @@ HEAD

close $fh;
}
}
}
} => $path
);

Expand Down
74 changes: 38 additions & 36 deletions lib/Sidef/Deparse/Perl.pm
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ HEADER
}
}

sub _get_reftype {
sub _dump_reftype {
my ($self, $obj) = @_;

my $ref = ref($obj);
Expand Down Expand Up @@ -326,7 +326,7 @@ HEADER

if (exists($var->{ref_type})) {
my $var_name = "\$$var->{name}" . refaddr($var);
my $type = $self->_get_reftype($var->{ref_type});
my $type = $self->_dump_reftype($var->{ref_type});
$code .=
(' ' x $Sidef::SPACES)
. "(ref($var_name) eq $type || ($type ne 'REF' && eval{$var_name->SUPER::isa($type)})) or "
Expand Down Expand Up @@ -418,9 +418,14 @@ HEADER

sub deparse_bare_block {
my ($self, @args) = @_;
$self->deparse_generic("{\n" . " " x ($Sidef::SPACES + $Sidef::SPACES_INCR),
";\n" . (" " x ($Sidef::SPACES + $Sidef::SPACES_INCR)),
"\n" . (" " x $Sidef::SPACES) . "}", @args);

$Sidef::SPACES += $Sidef::SPACES_INCR;
my $code = $self->deparse_generic("{\n" . " " x ($Sidef::SPACES),
";\n" . (" " x ($Sidef::SPACES)),
"\n" . (" " x ($Sidef::SPACES - $Sidef::SPACES_INCR)) . "}", @args);
$Sidef::SPACES -= $Sidef::SPACES_INCR;

$code;
}

sub deparse_expr {
Expand All @@ -433,7 +438,7 @@ HEADER
# Self obj
my $ref = ref($obj);
if ($ref eq 'HASH') {
$code = join(', ', $self->deparse_script($obj));
$code = join(', ', exists($obj->{self}) ? $self->deparse_expr($obj) : $self->deparse_script($obj));
}
elsif ($ref eq 'Sidef::Variable::Variable') {
if ($obj->{type} eq 'var') {
Expand Down Expand Up @@ -498,7 +503,7 @@ HEADER
# Check the return value (when "-> Type" is specified)
if (exists $obj->{returns}) {

my $type = $self->_get_reftype($obj->{returns});
my $type = $self->_dump_reftype($obj->{returns});

$code =
"do { $code;\n"
Expand Down Expand Up @@ -634,9 +639,7 @@ HEADER
}
}
elsif ($ref eq 'Sidef::Variable::ConstInit') {
foreach my $var (@{$obj->{vars}}) {
$code .= $self->deparse_expr({self => $var}) . ";\n";
}
$code = join(";\n" . (" " x $Sidef::SPACES), map { $self->deparse_expr({self => $_}) } @{$obj->{vars}});
}
elsif ($ref eq 'Sidef::Variable::Init') {
$code = $self->_dump_init_vars($obj);
Expand Down Expand Up @@ -860,20 +863,10 @@ HEADER
$code = $self->make_constant($ref, '__NEW__', "MOD_F$refaddr", $self->_dump_string($obj->{module}));
}
elsif ($ref eq 'Sidef::Types::Block::Break') {
if (not exists $expr->{call}) {
$code = 'last';
}
else {
die "[ERROR] Arguments and method calls for 'break' are not supported!";
}
$code = 'last';
}
elsif ($ref eq 'Sidef::Types::Block::Next') {
if (not exists $expr->{call}) {
$code = 'next';
}
else {
die "[ERROR] Arguments and method calls for 'next' are not supported!";
}
$code = 'next';
}
elsif ($ref eq 'Sidef::Types::Block::Continue') {
$code = 'continue';
Expand Down Expand Up @@ -947,7 +940,7 @@ HEADER
$code = $self->make_constant($ref, 'new', "Sig$refaddr");
}
elsif ($ref eq 'Sidef::Types::Number::Complex') {
$code = $self->make_constant($ref, 'new', "Complex$refaddr");
$code = $self->make_constant($ref, 'new', "Complex$refaddr", "'" . ${$obj}->Re . "'", "'" . ${$obj}->Im . "'");
}
elsif ($ref eq 'Sidef::Types::Array::Pair') {
$code = $ref . '->new';
Expand All @@ -969,12 +962,7 @@ HEADER
$code = $self->_dump_array('Sidef::Types::Array::Array', $obj);
}
elsif ($ref eq 'Sidef::Types::Nil::Nil') {
if (not exists $expr->{call}) {
$code = 'undef';
}
else {
die "[ERROR] Arguments and method calls for 'nil' are not supported!";
}
$code = 'undef';
}
elsif ($ref eq 'Sidef::Types::Null::Null') {
$code = $self->make_constant($ref, 'new', "Null$refaddr");
Expand Down Expand Up @@ -1230,8 +1218,9 @@ HEADER
}
}

if (ref($method) eq 'HASH') {
$code .= '->${\\do{' . $self->deparse_expr($method) . '}}';
if (ref($method)) {
$code .=
'->${\\do{' . $self->deparse_expr(ref($method) eq 'HASH' ? $method : {self => $method}) . '}}';
}
elsif ($method =~ /^[\pL_]/) {

Expand Down Expand Up @@ -1304,7 +1293,7 @@ HEADER
if (exists $call->{block}) {
if ($ref eq 'Sidef::Types::Block::Given'
or ($ref eq 'Sidef::Types::Block::If' and $i == $#{$expr->{call}})) {
$code = "do { " . $code . $self->deparse_bare_block(@{$call->{block}}) . '}';
$code = "do {\n" . (' ' x $Sidef::SPACES) . $code . $self->deparse_bare_block(@{$call->{block}}) . '}';
}
else {
$code .= $self->deparse_bare_block(@{$call->{block}});
Expand All @@ -1330,11 +1319,24 @@ HEADER

push @results, ref($expr) eq 'HASH' ? $self->deparse_expr($expr) : $self->deparse_expr({self => $expr});

if ($i > 0 and ref($struct->{$class}[$i - 1]{self}) eq 'Sidef::Variable::Label') {
$results[-1] = $struct->{$class}[$i - 1]{self}->{name} . ':' . $results[-1];
if (
$i > 0
and (
ref($expr) eq 'Sidef::Variable::Label'
or ( ref($struct->{$class}[$i - 1]) eq 'HASH'
and ref($struct->{$class}[$i - 1]{self}) eq 'Sidef::Variable::Label')
)
) {
$results[-1] =
(ref($expr) eq 'Sidef::Variable::Label' ? $expr->{name} : $struct->{$class}[$i - 1]{self}->{name}) . ':'
. $results[-1];
}
elsif ($i == $max and ref($expr->{self}) eq 'Sidef::Variable::Label') {
$results[-1] = $expr->{self}{name} . ':';
elsif (
$i == $max
and (ref($expr) eq 'Sidef::Variable::Label'
or (ref($expr) eq 'HASH' and ref($expr->{self}) eq 'Sidef::Variable::Label'))
) {
$results[-1] = (ref($expr) eq 'Sidef::Variable::Label' ? $expr->{name} : $expr->{self}{name}) . ':';
}
}
}
Expand Down
Loading

0 comments on commit 83d3450

Please sign in to comment.