Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Resolve lexicals as a separate pass before to_anf
  • Loading branch information
sorear committed Aug 17, 2010
1 parent e4ff073 commit b4ad6c2
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 70 deletions.
16 changes: 14 additions & 2 deletions CgOp.pm
Expand Up @@ -208,7 +208,16 @@ use warnings;
$z->zyg->[0]->var_cg($cg);
return;
}
when ("scopelex") {
when ("hint_get") {
return;
}
when ("peek_let") {
return;
}
when ("clr_sfield_get") {
return;
}
when ("rtpadget") {
return;
}
when ("push_null") {
Expand Down Expand Up @@ -461,6 +470,7 @@ use warnings;
zyg => [ $_[1], $_[2] ]);
}

# Not a CgOp function, rewritten by the resolve_lex pass
sub scopedlex {
my $n = shift;
CgOp::Primitive->new(op => [ scopelex => $n, scalar @_ ],
Expand All @@ -485,7 +495,9 @@ use warnings;
}

sub letvar {
CgOp::Primitive->new(op => [ 'peek_let', $_[0] ]);
$_[1] ?
CgOp::Primitive->new(op => [ 'poke_let', $_[0] ], zyg => [ $_[1] ]):
CgOp::Primitive->new(op => [ 'peek_let', $_[0] ]);
}

sub clr_string {
Expand Down
92 changes: 24 additions & 68 deletions CodeGen.pm
Expand Up @@ -293,6 +293,14 @@ use 5.010;
$self->cast($self->lettypes->[$i]);
}

sub poke_let {
my ($self, $which) = @_;
my $i = @{ $self->letstack } - 1;
while ($i >= 0 && $self->letstack->[$i] ne $which) { $i-- }
my ($v) = $self->_popn(1);
$self->_emit("th.lexn[" . ($self->minlets + $i) . "] = $v");
}

sub has_let {
my ($self, $which) = @_;
my $i = @{ $self->letstack } - 1;
Expand Down Expand Up @@ -356,42 +364,25 @@ use 5.010;
$self->_emit("th.lex[" . qm($name) . "] = " . ($self->_popn(1))[0]);
}

sub lexget {
my ($self, $order, $type, $kind, $data, $name) = @_;
if ($kind == 1) {
$self->_push($type, $data);
return;
}
if ($kind == 2) {
$self->_push("object", "$data.hints[" . qm($name) . "]");
$self->cast($type);
return;
}
my $frame = 'th.';
if ($self->has_let('protopad')) {
$self->peek_let('protopad');
$frame = ($self->_popn(1))[0] . ".";
}
$self->_push("object", $frame . ("outer." x $order) .
"lex[" . qm($name) . "]");
sub hintget {
my ($self, $type, $data, $name) = @_;
$self->_push("object", "$data.hints[" . qm($name) . "]");
$self->cast($type);
}

sub lexput {
my ($self, $order, $type, $kind, $data, $name) = @_;
if ($kind == 1) {
$self->clr_sfield_set($data);
return;
}
if ($kind == 2) {
die "panic: assigning to a hint";
}
my $frame = 'th.';
if ($self->has_let('protopad')) {
$self->peek_let('protopad');
$frame = ($self->_popn(1))[0] . ".";
}
$self->_emit($frame . ("outer." x $order) . "lex[" . qm($name) . "] = " . ($self->_popn(1))[0]);
sub rtpadget {
my ($self, $type, $order, $name) = @_;
$self->callframe;
my ($frame) = $self->_popn(1);
$self->_push("object", $frame . (".outer" x $order) . ".lex[" . qm($name) . "]");
$self->cast($type);
}

sub rtpadput {
my ($self, $order, $name) = @_;
$self->callframe;
my ($val, $frame) = $self->_popn(2);
$self->_emit($frame . (".outer" x $order) . ".lex[" . qm($name) . "] = $val");
}

sub callframe {
Expand Down Expand Up @@ -643,41 +634,6 @@ use 5.010;
$self->_emit("$pp.lex[" . qm($name) . "] = ($pv)");
}

sub scopelex {
my ($self, $name, $set) = @_;
my $body = $self->body // $self->bodies->[-1];
my $order = 0;
my ($type, $kind, $data);
if ($self->has_let($name)) {
my $i = @{ $self->letstack } - 1;
while ($i >= 0 && $self->letstack->[$i] ne $name) { $i-- }
$name = "th.lexn[" . ($self->minlets + $i) . "]";
$type = $self->lettypes->[$i];

if ($set) {
$self->_emit("$name = " . ($self->_popn(1))[0]);
} else {
$self->_push("object", $name);
$self->cast($type);
}
return;
} else {
($order, $type, $kind, $data) = $body->lex_info($name);
if ($order < 0) {
#print STDERR YAML::XS::Dump ($body);
die "Internal error: failed to resolve lexical $name in " . $body->name;
}
}
if (($kind == 1 || $kind == 2) && $data =~ /(.*)\./) {
$::UNITDEPS{$1} = 1;
}
if ($set) {
$self->lexput($order, $type, $kind, $data, $name);
} else {
$self->lexget($order, $type, $kind, $data, $name);
}
}

# XXX a bit too much integration here
sub set_ltm {
my ($self, $bodyn) = @_;
Expand Down
2 changes: 2 additions & 0 deletions CompilerDriver.pm
Expand Up @@ -23,6 +23,7 @@ use Decl ();
use Unit ();
use Op ();
use Optimizer::Beta ();
use ResolveLex ();
use Storable;

use Niecza::Grammar ();
Expand Down Expand Up @@ -61,6 +62,7 @@ sub compile {
[ 'beta', sub { Optimizer::Beta::run($ast) } ],
[ 'extract_scopes', sub { $ast->extract_scopes } ],
[ 'to_cgop', sub { $ast->to_cgop } ],
[ 'resolve_lex', sub { ResolveLex::run($ast) } ],
[ 'to_anf', sub { $ast->to_anf } ],
[ 'writecs', sub {
$basename = $::UNITNAME;
Expand Down
95 changes: 95 additions & 0 deletions ResolveLex.pm
@@ -0,0 +1,95 @@
use 5.010;
use strict;
use warnings;
use utf8;

package ResolveLex;

sub run {
my ($unit) = @_;

run_body($unit->mainline);
run_cgop($unit->bootcgop, []);
}

sub run_body {
my ($body) = @_;

for my $d (@{ $body->decls }) {
for my $b ($d->bodies) {
run_body($b);
}
}

local %::haslet;
run_cgop($body->cgoptree, [ $body ]);
}

sub run_cgop {
my ($op, $btree) = @_;
my $lvl = scalar @$btree;

if ($op->isa('CgOp::Let')) {
local $::haslet{$op->name} = 1;
run_cgop($_, $btree) for @{ $op->zyg };
} else {
run_cgop($_, $btree) for @{ $op->zyg };
}

if ($op->isa('CgOp::Primitive')) {
my ($opc, $arg, @rest) = @{ $op->op };
if ($opc eq 'open_protopad') {
push @$btree, $arg;
} elsif ($opc eq 'close_sub') {
pop @$btree;
} elsif ($opc eq 'scopelex') {
my $nn = resolve_lex($arg, $btree->[-1], $op->zyg->[0]);
#XXX
%$op = %$nn;
bless $op, ref($nn);
}
}
}

sub resolve_lex {
my ($name, $body, $set_to) = @_;

if ($::haslet{$name}) {
return CgOp::letvar($name, $set_to);
}

my ($order, $type, $kind, $data) = $body->lex_info($name);
if ($order < 0) {
#print STDERR YAML::XS::Dump ($body);
die "Internal error: failed to resolve lexical $name in " . $body->name;
}

if (($kind == 1 || $kind == 2) && $data =~ /(.*)\./) {
$::UNITDEPS{$1} = 1;
}

if ($kind == 2) {
if ($set_to) {
die "panic: Assigning to a hint";
} else {
return CgOp::Primitive->new(op => ['hintget', $type, $data, $name]);
}
} elsif ($kind == 1) {
if ($set_to) {
return CgOp::rawsset($data, $set_to);
} else {
return CgOp::rawsget($data . ":f," . $type);
}
} elsif ($kind == 0) {
if ($set_to) {
return CgOp::Primitive->new(op => ['rtpadput', $order, $name],
zyg => [$set_to]);
} else {
return CgOp::Primitive->new(op => ['rtpadget', $type, $order, $name]);
}
} else {
die "panic: invalid kind $kind";
}
}

1;

0 comments on commit b4ad6c2

Please sign in to comment.