diff --git a/lib/SAFE.setting b/lib/SAFE.setting index 89829a3d..682879ba 100644 --- a/lib/SAFE.setting +++ b/lib/SAFE.setting @@ -571,7 +571,7 @@ my class GatherIterator is Iterator { my $*nextframe; $!reify // ($!reify = ( Q:CgOp { - (letn getv (rawsccall Kernel.CoTake (cast clr:Frame + (letn getv (rawscall Kernel.CoTake (cast clr:Frame (@ {$!frame}))) (box Parcel (ternary (== (@ {EMPTY}) (@ (l getv))) (rawnewarr var) @@ -588,7 +588,7 @@ sub _gather($fr) { } sub take($p) { # should be \|$p - Q:CgOp { (rawsccall Kernel.Take (l $p)) } + Q:CgOp { (rawscall Kernel.Take (l $p)) } } sub infix:<< => >>($k, $v) { Pair.RAWCREATE("key", $k, "value", $v) } @@ -630,16 +630,16 @@ sub die($msg) { Q:CgOp { (die (@ {$msg})) } } # XXX multi dispatch sub next { - Q:CgOp { (rawsccall Kernel.SearchForHandler (int 1) (null clr:Frame) (int -1) (null str) (null var)) } + Q:CgOp { (rawscall Kernel.SearchForHandler (int 1) (null clr:Frame) (int -1) (null str) (null var)) } } sub last { - Q:CgOp { (rawsccall Kernel.SearchForHandler (int 2) (null clr:Frame) (int -1) (null str) (null var)) } + Q:CgOp { (rawscall Kernel.SearchForHandler (int 2) (null clr:Frame) (int -1) (null str) (null var)) } } sub redo { - Q:CgOp { (rawsccall Kernel.SearchForHandler (int 3) (null clr:Frame) (int -1) (null str) (null var)) } + Q:CgOp { (rawscall Kernel.SearchForHandler (int 3) (null clr:Frame) (int -1) (null str) (null var)) } } sub return is rawcall { - Q:CgOp { (rawsccall Kernel.SearchForHandler (int 4) (null clr:Frame) (int -1) (null str) (pos 0)) } + Q:CgOp { (rawscall Kernel.SearchForHandler (int 4) (null clr:Frame) (int -1) (null str) (pos 0)) } } sub assignop($fn) { diff --git a/lib/Threads.pm6 b/lib/Threads.pm6 index 89313c18..f467a92c 100644 --- a/lib/Threads.pm6 +++ b/lib/Threads.pm6 @@ -24,7 +24,7 @@ sub lock($m,$f) is export { $m.lock($f); } my class Thread is export { has $!value; method new($func) { - Q:CgOp { (box Thread (rawsccall + Q:CgOp { (box Thread (rawscall Kernel.StartP6Thread:c,System.Threading.Thread (@ {$func}))) } } diff --git a/src/CSharpBackend.pm b/src/CSharpBackend.pm index f4ecc1af..5ee9eb91 100644 --- a/src/CSharpBackend.pm +++ b/src/CSharpBackend.pm @@ -278,14 +278,14 @@ sub access_lex { CgOp::rawsget($lex->{peer}); } elsif ((my $ix = $lex->{peer}) >= 0) { return $set_to ? - CgOp::Primitive->new(op => [ rtpadputi => $order, $ix ], + CgOp->new(op => [ rtpadputi => $order, $ix ], zyg => [ $set_to ]) : - CgOp::Primitive->new(op => [ rtpadgeti => 'Variable',$order,$ix ]); + CgOp->new(op => [ rtpadgeti => 'Variable', $order, $ix ]); } else { return $set_to ? - CgOp::Primitive->new(op => [ rtpadput => $order, $name ], + CgOp->new(op => [ rtpadput => $order, $name ], zyg => [ $set_to ]) : - CgOp::Primitive->new(op => [ rtpadget => 'Variable',$order,$name ]); + CgOp->new(op => [ rtpadget => 'Variable', $order, $name ]); } } elsif ($lex->isa('Metamodel::Lexical::Stash')) { die "cannot rebind stashes" if $set_to; @@ -308,18 +308,17 @@ sub access_lex { sub resolve_lex { my ($body, $op) = @_; - if ($op->isa('CgOp::Primitive')) { - my ($opc, $arg, @rest) = @{ $op->op }; - if ($opc eq 'scopelex') { - my $nn = access_lex($body, $arg, $op->zyg->[0]); - #XXX - %$op = %$nn; - bless $op, ref($nn); - } - } + my ($opc, $arg, @rest) = @{ $op->op }; + if ($opc eq 'scopelex') { + my $nn = access_lex($body, $arg, $op->zyg->[0]); + #XXX + %$op = %$nn; + bless $op, ref($nn); + + resolve_lex($body, $_) for @{ $op->zyg }; + } elsif ($opc eq 'let') { + local $haslet{$arg} = 1; - if ($op->isa('CgOp::Let')) { - local $haslet{$op->name} = 1; resolve_lex($body, $_) for @{ $op->zyg }; } else { resolve_lex($body, $_) for @{ $op->zyg }; @@ -332,7 +331,7 @@ sub codegen_sub { # TODO: Bind a return value here to catch non-ro sub use if ($_->gather_hack) { $ops = CgOp::prog(@enter, CgOp::sink($_->code->cgop($_)), - CgOp::rawsccall('Kernel.Take', CgOp::scopedlex('EMPTY'))); + CgOp::rawscall('Kernel.Take', CgOp::scopedlex('EMPTY'))); } elsif ($_->returnable && defined($_->signature)) { $ops = CgOp::prog(@enter, CgOp::return(CgOp::span("rstart", "rend", diff --git a/src/CgOp.pm b/src/CgOp.pm index be77b069..c62c93c1 100644 --- a/src/CgOp.pm +++ b/src/CgOp.pm @@ -2,178 +2,73 @@ use 5.010; use strict; use warnings; -# The invariant of cps_convert is that, in the output, a primitive which does -# a CPS call cannot appear inside the argument list of another primitive. - { package CgOp; use Moose; + has op => (isa => 'ArrayRef', is => 'ro', required => 1); has zyg => (isa => 'ArrayRef[CgOp]', is => 'ro', default => sub { [] }); no Moose; __PACKAGE__->meta->make_immutable; } -{ - package CgOp::Annotation; - use Moose; - extends 'CgOp'; - - has file => (isa => 'Str', is => 'ro', required => 1); - has line => (isa => 'Int', is => 'ro', required => 1); - - no Moose; - __PACKAGE__->meta->make_immutable; -} - -{ - package CgOp::Let; - use Moose; - extends 'CgOp'; - - has name => (isa => 'Str', is => 'ro'); - - no Moose; - __PACKAGE__->meta->make_immutable; -} - -{ - package CgOp::Span; - use Moose; - extends 'CgOp'; - - has lstart => (isa => 'Str', is => 'ro'); - has lend => (isa => 'Str', is => 'ro'); - - no Moose; - __PACKAGE__->meta->make_immutable; -} - -{ - package CgOp::Seq; - use Moose; - extends 'CgOp'; - - no Moose; - __PACKAGE__->meta->make_immutable; -} - -{ - package CgOp::Primitive; - use Moose; - extends 'CgOp'; - - has op => (isa => 'ArrayRef', is => 'ro', required => 1); - has is_cps_call => (isa => 'Bool', is => 'ro', default => 0); - has constant => (isa => 'Bool', is => 'ro', default => 0); - - no Moose; - __PACKAGE__->meta->make_immutable; -} - -{ - package CgOp::Ternary; - use Moose; - extends 'CgOp'; - - no Moose; - __PACKAGE__->meta->make_immutable; -} - -{ - package CgOp::While; - use Moose; - extends 'CgOp'; - - has once => (is => 'ro', isa => 'Bool'); - has until => (is => 'ro', isa => 'Bool'); - - no Moose; - __PACKAGE__->meta->make_immutable; -} - -# just a bunch of smart constructors { package CgOp; use Scalar::Util 'blessed'; - sub _str { blessed($_[0]) ? $_[0] : clr_string($_[0]) } - sub _int { blessed($_[0]) ? $_[0] : CgOp::int($_[0]) } - - sub noop { - CgOp::Seq->new; - } - - sub null { - CgOp::Primitive->new(op => [ push_null => CLRTypes->mapt($_[0]) ], constant => 1); - } + # really primitive sub prog { - CgOp::Seq->new(zyg => [ @_ ]); + CgOp->new(op => ['seq'], zyg => [ @_ ]); } sub span { my ($ls,$le,@r) = @_; - CgOp::Span->new(lstart => $ls, lend => $le, zyg => [prog(@r)]); + CgOp->new(op => [span => $ls, $le], zyg => [prog(@r)]); } - sub ehspan { - CgOp::Primitive->new(op => [ ehspan => @_ ]); + sub null { + CgOp->new(op => [ push_null => CLRTypes->mapt($_[0]) ]); } - sub sink { - CgOp::Primitive->new(op => ['drop'], zyg => [ $_[0] ]); - } + sub ehspan { CgOp->new(op => [ ehspan => @_ ]); } - sub rnull { - prog($_[0], null('var')); - } + sub sink { CgOp->new(op => ['drop'], zyg => [ $_[0] ]); } - sub fetch { - rawcall($_[0], 'Fetch'); - } + sub fetch { rawcall($_[0], 'Fetch'); } - sub how { - rawccall($_[0], "HOW"); - } + sub how { rawcall($_[0], "HOW"); } sub getfield { - CgOp::Primitive->new(op => [ 'clr_field_get', $_[0] ], - zyg => [ $_[1] ]); + CgOp->new(op => [ 'clr_field_get', $_[0] ], zyg => [ $_[1] ]); } sub setfield { - CgOp::Primitive->new(op => [ 'clr_field_set', $_[0] ], + CgOp->new(op => [ 'clr_field_set', $_[0] ], zyg => [ $_[1], $_[2] ]); } sub getindex { - CgOp::Primitive->new(op => [ 'clr_index_get' ], + CgOp->new(op => [ 'clr_index_get' ], zyg => [ _str($_[0]), $_[1] ]); } sub setindex { - CgOp::Primitive->new(op => [ 'clr_index_set' ], + CgOp->new(op => [ 'clr_index_set' ], zyg => [ _str($_[0]), $_[1], $_[2] ]); } - sub getattr { - fetch(varattr($_[0], $_[1])); - } - sub getslot { cast($_[1], rawcall($_[2], 'GetSlot', _str($_[0]))); } sub setslot { rawcall($_[1], 'SetSlot', _str($_[0]), $_[2]); } - sub varattr { getslot($_[0], 'var', $_[1]); } - sub cast { - CgOp::Primitive->new(op => [ 'cast', CLRTypes->mapt($_[0]) ], zyg => [ $_[1] ]); + CgOp->new(op => [ 'cast', CLRTypes->mapt($_[0]) ], zyg => [ $_[1] ]); } sub const { - CgOp::Primitive->new(op => [ 'const' ], zyg => [ $_[0] ], constant => 1); + CgOp->new(op => [ 'const' ], zyg => [ $_[0] ]); } sub newscalar { @@ -188,6 +83,34 @@ use warnings; sub newrwlistvar { rawscall('Kernel.NewRWListVar', $_[0]); } + sub double { CgOp->new(op => [ 'clr_double', $_[0] ]); } + + sub labelid { CgOp->new(op => [ 'labelid', $_[0] ]) } + + sub int { CgOp->new(op => [ 'clr_int', $_[0] ]); } + + sub bool { CgOp->new(op => [ 'clr_bool', $_[0] ]); } + + sub unbox { + cast($_[0], rawscall('Kernel.UnboxAny', $_[1])); + } + + # begin smarter constructors + sub _str { blessed($_[0]) ? $_[0] : clr_string($_[0]) } + sub _int { blessed($_[0]) ? $_[0] : CgOp::int($_[0]) } + + sub noop { prog() } + + sub rnull { + prog($_[0], null('var')); + } + + sub getattr { + fetch(varattr($_[0], $_[1])); + } + + sub varattr { getslot($_[0], 'var', $_[1]); } + sub newblanklist { newrwlistvar(ternary( compare('==', rawsget('Kernel.ArrayP'), null('obj')), @@ -202,27 +125,6 @@ use warnings; sub string_var { box('Str', clr_string($_[0])); } - sub double { - CgOp::Primitive->new(op => [ 'clr_double', $_[0] ], constant => 1); - } - - sub labelid { - CgOp::Primitive->new(op => [ 'labelid', $_[0] ], zyg => [ ], - constant => 1); - } - - sub int { - CgOp::Primitive->new(op => [ 'clr_int', $_[0] ], constant => 1); - } - - sub bool { - CgOp::Primitive->new(op => [ 'clr_bool', $_[0] ], constant => 1); - } - - sub unbox { - cast($_[0], rawscall('Kernel.UnboxAny', $_[1])); - } - sub box { rawscall('Kernel.BoxAny', $_[1], blessed($_[0]) ? $_[0] : @@ -266,29 +168,26 @@ use warnings; sub bset { setfield('v', $_[0], $_[1]) } sub newboundvar { - rawsccall('Kernel.NewBoundVar', bool($_[0] || $_[1]), bool($_[1]), + rawscall('Kernel.NewBoundVar', bool($_[0] || $_[1]), bool($_[1]), $_[2]); } sub assign { - rawsccall('Kernel.Assign', $_[0], $_[1]); + rawscall('Kernel.Assign', $_[0], $_[1]); } sub compare { - CgOp::Primitive->new(op => [ 'clr_compare', $_[0] ], - zyg => [ $_[1], $_[2] ]); + CgOp->new(op => [ 'clr_compare', $_[0] ], zyg => [ $_[1], $_[2] ]); } sub arith { - CgOp::Primitive->new(op => [ 'clr_arith', $_[0] ], - zyg => [ $_[1], $_[2] ]); + CgOp->new(op => [ 'clr_arith', $_[0] ], 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 @_ ], - zyg => [ @_ ]); + CgOp->new(op => [ scopelex => $n ], zyg => [ @_ ]); } sub _process_arglist { @@ -310,22 +209,18 @@ use warnings; sub subcall { my ($sub, @args) = @_; my @sig = _process_arglist(\@args); - CgOp::Primitive->new(op => [ 'call_sub', \@sig ], - zyg => [ $sub, @args ], is_cps_call => 1); + CgOp->new(op => [ 'call_sub', \@sig ], zyg => [ $sub, @args ]); } sub methodcall { my ($obj, $name, @args) = @_; my @sig = _process_arglist(\@args); let($obj, sub { - CgOp::Primitive->new(op => [ 'call_method', $name, ['', @sig] ], - zyg => [ fetch($_[0]), $_[0], @args ], is_cps_call => 1)}); + CgOp->new(op => [ 'call_method', $name, ['', @sig] ], + zyg => [ fetch($_[0]), $_[0], @args ])}); } - sub callframe { - # for the life of the function, constant - CgOp::Primitive->new(op => [ 'callframe' ], constant => 1); - } + sub callframe { CgOp->new(op => [ 'callframe' ]); } sub rxframe { getfield('rx', callframe) } sub rxcall { rawcall(rxframe, @_) } @@ -334,17 +229,13 @@ use warnings; sub letvar { $_[1] ? - CgOp::Primitive->new(op => [ 'poke_let', $_[0] ], zyg => [ $_[1] ]): - CgOp::Primitive->new(op => [ 'peek_let', $_[0] ]); + CgOp->new(op => [ 'poke_let', $_[0] ], zyg => [ $_[1] ]): + CgOp->new(op => [ 'peek_let', $_[0] ]); } - sub clr_string { - CgOp::Primitive->new(op => [ 'clr_string', $_[0] ], constant => 1); - } + sub clr_string { CgOp->new(op => [ 'clr_string', $_[0] ]); } - sub char { - CgOp::Primitive->new(op => [ 'clr_char', $_[0] ], constant => 1); - } + sub char { CgOp->new(op => [ 'clr_char', $_[0] ]); } sub withtypes { if (blessed($_[0])) { @@ -358,111 +249,79 @@ use warnings; sub return { $_[0] ? - CgOp::Primitive->new(op => [ 'return', 1 ], zyg => [ $_[0] ]) : - CgOp::Primitive->new(op => [ return => 0]); + CgOp->new(op => [ 'return', 1 ], zyg => [ $_[0] ]) : + CgOp->new(op => [ return => 0]); } sub rawscall { my ($name, @args) = @_; - CgOp::Primitive->new(op => [ 'clr_call_direct', $name, scalar @args ], - zyg => [ @args ]); + CgOp->new(op => [ 'clr_call_direct', $name ], zyg => [ @args ]); } sub rawcall { my ($inv, $name, @args) = @_; - CgOp::Primitive->new(op => [ 'clr_call_virt', $name, scalar @args ], - zyg => [ $inv, @args ]); - } - - sub rawsccall { - my ($name, @args) = @_; - CgOp::Primitive->new(op => [ 'clr_call_direct', $name, scalar @args ], - zyg => [ @args ], is_cps_call => 1); - } - - sub rawccall { - my ($inv, $name, @args) = @_; - CgOp::Primitive->new(op => [ 'clr_call_virt', $name, scalar @args ], - zyg => [ $inv, @args ], is_cps_call => 1); + CgOp->new(op => [ 'clr_call_virt', $name ], zyg => [ $inv, @args ]); } - sub label { - my ($name) = @_; - CgOp::Primitive->new(op => [ 'labelhere', $name ], - zyg => [ ], is_cps_call => 1); - } + sub label { CgOp->new(op => [ 'labelhere', $_[0] ]); } sub goto { my ($name) = @_; - CgOp::Primitive->new(op => [ 'goto', $name ], - zyg => [ ], is_cps_call => 1); + CgOp->new(op => [ 'goto', $name ]); } - sub cgoto { - my ($name) = @_; - CgOp::Primitive->new(op => [ 'cgoto', $name ], - zyg => [ $_[1] ], is_cps_call => 1); - } + sub cgoto { CgOp->new(op => [ 'cgoto', $_[0] ], zyg => [ $_[1] ]); } - sub ncgoto { - my ($name) = @_; - CgOp::Primitive->new(op => [ 'ncgoto', $name ], - zyg => [ $_[1] ], is_cps_call => 1); - } + sub ncgoto { CgOp->new(op => [ 'ncgoto', $_[0] ], zyg => [ $_[1] ]); } sub rxpushb { my ($tag, $lbl) = @_; - CgOp::Primitive->new(op => [ 'rxpushb', $tag, $lbl ], - zyg => [ ], is_cps_call => 1); + CgOp->new(op => [ 'rxpushb', $tag, $lbl ]); } sub rxbprim { my ($name, @args) = @_; - CgOp::Primitive->new(op => [ 'rxbprim', $name, scalar @args ], - zyg => [ @args ], is_cps_call => 1); + CgOp->new(op => [ 'rxbprim', $name ], zyg => [ @args ]); } sub rawsget { Carp::confess "Undefined name in rawsget" unless defined $_[0]; - CgOp::Primitive->new(op => [ 'clr_sfield_get', $_[0] ]); + CgOp->new(op => [ 'clr_sfield_get', $_[0] ]); } sub rawsset { Carp::confess "Undefined name in rawsset" unless defined $_[0]; - CgOp::Primitive->new(op => [ 'clr_sfield_set', $_[0] ], - zyg => [ $_[1] ]); + CgOp->new(op => [ 'clr_sfield_set', $_[0] ], zyg => [ $_[1] ]); } sub rawnew { my ($name, @args) = @_; - CgOp::Primitive->new(op => [ 'clr_new', CLRTypes->mapt($name), scalar @args ], - zyg => \@args); + CgOp->new(op => [ 'clr_new', CLRTypes->mapt($name) ], zyg => \@args); } sub rawnewarr { my ($name, @args) = @_; - CgOp::Primitive->new(op => [ 'clr_new_arr', CLRTypes->mapt($name), scalar @args ], + CgOp->new(op => [ 'clr_new_arr', CLRTypes->mapt($name) ], zyg => \@args); } sub rawnewzarr { my ($name, $ni) = @_; - CgOp::Primitive->new(op => [ 'clr_new_zarr', CLRTypes->mapt($name) ], zyg => [ $ni ]); + CgOp->new(op => [ 'clr_new_zarr', CLRTypes->mapt($name) ], zyg => [ $ni ]); } sub ann { my ($file, $line, $stuff) = @_; - CgOp::Annotation->new(file => $file, line => $line, - zyg => [$stuff]); + CgOp->new(op => [ 'ann', $line ], zyg => [$stuff]); } sub die { my ($msg) = @_; if (blessed($msg)) { - rawsccall('Kernel.SearchForHandler', &int(5), null('clr:Niecza.Frame'), + rawscall('Kernel.SearchForHandler', &int(5), null('clr:Niecza.Frame'), &int(-1), null('str'), newscalar($msg)); } else { - rawsccall('Kernel.Die', clr_string($msg)); + rawscall('Kernel.Die', clr_string($msg)); } } @@ -475,24 +334,18 @@ use warnings; Carp::confess "Invalid letn protocol"; } my ($name, $value) = splice @stuff, 0, 2; - CgOp::Let->new(name => $name, zyg => [ $value, letn(@stuff) ]); + CgOp->new(op => ['let', $name], zyg => [ $value, letn(@stuff) ]); } } - sub pos { - CgOp::Primitive->new(op => [ 'pos' ], zyg => [ _int($_[0]) ], - constant => 1); - } + sub pos { CgOp->new(op => [ 'pos' ], zyg => [ _int($_[0]) ]); } sub ternary { - CgOp::Ternary->new(zyg => [ $_[0], $_[1], $_[2] ]); + CgOp->new(op => ['ternary'], zyg => [ $_[0], $_[1], $_[2] ]); } sub whileloop { - CgOp::While->new( - until => $_[0], - once => $_[1], - zyg => [ $_[2], $_[3] ]); + CgOp->new(op => ['while', $_[0], $_[1]], zyg => [ $_[2], $_[3] ]); } my $nextlet = 0; diff --git a/src/CgOpToCLROp.pm b/src/CgOpToCLROp.pm index 1648f9db..bfac2667 100644 --- a/src/CgOpToCLROp.pm +++ b/src/CgOpToCLROp.pm @@ -65,18 +65,27 @@ $fixtype{$_} = 'Void' for (qw/ poke_let labelhere goto cgoto ncgoto ehspan $fixtype{$_} = 'Variable' for (qw/ pos call_sub call_method /); +my %_cps = map { $_ => 1 } qw/ call_method call_sub cgoto goto labelhere + ncgoto return rxbprim /; +my %_const = map { $_ => 1 } qw/ callframe clr_bool clr_char clr_double clr_int + clr_string const labelid pos push_null /; + sub type_infer { - my ($op, @argtypes) = @_; + my ($cpsr, $op, @argtypes) = @_; my $head = $op->[0]; if ($fixtype{$head}) { return $fixtype{$head} } given ($head) { when ("clr_call_direct") { - return (CLRTypes->info("cm", $op->[1]))[2]; + my ($n, $cps, $type) = CLRTypes->info("cm", $op->[1]); + $$cpsr = ($cps eq 'c'); + return $type; } when ("clr_call_virt") { - return (CLRTypes->info("cm", $argtypes[0], $op->[1]))[2]; + my ($n, $cps, $type) = CLRTypes->info("cm", $argtypes[0], $op->[1]); + $$cpsr = ($cps eq 'c'); + return $type; } when ("clr_field_get") { return (CLRTypes->info("f", $argtypes[0], $op->[1]))[2]; @@ -103,37 +112,36 @@ sub type_infer { } # C# has a lot of special cases for this. -sub _drop { CgOp::Primitive->new(op => ['drop'], zyg => [$_[0]]) } +sub _drop { CgOp->new(op => ['drop'], zyg => [$_[0]]) } my %_dropnow = map {; $_ => 1 } qw/ push_null rtpadget rtpadgeti hint_get clr_sfield_get result pos peek_let /; -sub cvt_drop { - my $self = shift; +sub do_drop { + my ($tgt) = @_; - my $tgt = $self->zyg->[0]; my @zyg = @{ $tgt->zyg }; + my $op = $tgt->op; - given (ref $tgt) { - when ('CgOp::Let') { + given ($op->[0]) { + when ('let') { $zyg[-1] = _drop($zyg[-1]); - return cvt(CgOp::Let->new(name => $tgt->name, zyg => [ @zyg ])); + return cvt(CgOp->new(op => $op, zyg => [ @zyg ])); } - when ('CgOp::Seq') { + when ('seq') { $zyg[-1] = _drop($zyg[-1]); - return cvt(CgOp::Seq->new(zyg => [ @zyg ])); + return cvt(CgOp->new(op => $op, zyg => [ @zyg ])); } - when ('CgOp::Ternary') { + when ('ternary') { @zyg[1,2] = map { _drop($_) } @zyg[1,2]; - return cvt(CgOp::Ternary->new(zyg => [ @zyg ])); + return cvt(CgOp->new(op => $op, zyg => [ @zyg ])); } - when ('CgOp::Annotation') { - return cvt(CgOp::Annotation->new(line => $tgt->line, - file => $tgt->file, zyg => [ _drop($zyg[0]) ])); + when ('ann') { + return cvt(CgOp->new(op => $op, zyg => [ _drop($zyg[0]) ])); } - when ('CgOp::Span') { - return cvt(CgOp::Span->new(lstart => $tgt->lstart, - lend => $tgt->lend, zyg => [ _drop($zyg[0]) ])); + when ('span') { + return cvt(CgOp->new(op => $op, zyg => [ _drop($zyg[0]) ])); } - when ('CgOp::Primitive') { + when ("while") { die "implausible use of drop on while" } + default { my $v = cvt($tgt); my @zyg = @{ $v->stmts }; my $h = $v->head; @@ -143,14 +151,11 @@ sub cvt_drop { } return CLROp::Value->new(type => 'Void', stmts => \@zyg); } - when ("CgOp::While") { die "implausible use of drop on while" } } } -sub cvt_primitive { - my $self = $_[0]; - if ($self->op->[0] eq 'drop') { goto &cvt_drop; } - my @zyg = map { cvt($_) } @{ $self->zyg }; +sub do_primitive { + my ($ops, @zyg) = @_; my @args; my @prep; my @pop; @@ -181,39 +186,40 @@ sub cvt_primitive { } } - my $type = type_infer($self->op, map { $_->type } @args); + my $cps = $_cps{$ops->[0]}; + my $type = type_infer(\$cps, $ops, map { $_->type } @args); + my $const = $_const{$ops->[0]}; if ($type eq 'Void') { - my $nhead = CLROp::Term->new(op => $self->op, type => $type, + my $nhead = CLROp::Term->new(op => $ops, type => $type, zyg => [ @args ]); return CLROp::Value->new(stmts => [ @prep, $nhead, @pop ], type => 'Void'); - } elsif ($self->is_cps_call) { - my $nhead = CLROp::Term->new(op => $self->op, type => 'Void', + } elsif ($cps) { + my $nhead = CLROp::Term->new(op => $ops, type => 'Void', zyg => [ @args ]); return CLROp::Value->new(stmts => [ @prep, $nhead, @pop ], type => $type); } elsif (@pop) { my $nhead = CLROp::Term->new(op => ['set_result'], type => 'Void', - zyg => [ CLROp::Term->new(op => $self->op, type => $type, + zyg => [ CLROp::Term->new(op => $ops, type => $type, zyg => [ @args ]) ]); return CLROp::Value->new(stmts => [ @prep, $nhead, @pop ], type => $type); } else { - my $nhead = CLROp::Term->new(op => $self->op, type => $type, - zyg => [ @args ], constant => $self->constant); + my $nhead = CLROp::Term->new(op => $ops, type => $type, + zyg => [ @args ], constant => $const); return CLROp::Value->new(stmts => [ @prep ], type => $type, head => $nhead); } } -sub cvt_ternary { - my $self = shift; - my ($check, $true, $false) = map { cvt($_) } @{ $self->zyg }; +sub do_ternary { + my ($op, $check, $true, $false) = @_; my $lf = 'false' . ($spill++); my $le = 'end' . ($spill++); @@ -231,11 +237,10 @@ sub cvt_ternary { ]); } -sub cvt_while { - my $self = shift; - my ($check, $body) = map { cvt($_) } @{ $self->zyg }; - my $once = $self->once; - my $until = $self->until; +sub do_while { + my ($op, $check, $body) = @_; + my $once = $op->[1]; + my $until = $op->[2]; die "type error" unless $body->type eq 'Void'; my $lagain = 'again' . ($spill++); @@ -252,9 +257,8 @@ sub cvt_while { CLROp::Value->new(stmts => \@bits, type => 'Void'); } -sub cvt_seq { - my $self = shift; - my @zyg = map { cvt($_) } @{ $self->zyg }; +sub do_seq { + my ($op, @zyg) = @_; return CLROp::Value->new(stmts => [ ], type => 'Void') unless @zyg; my $fin = pop @zyg; for (@zyg) { next if $_->type eq 'Void'; say(YAML::XS::Dump($_)); die "type error"; } @@ -262,51 +266,65 @@ sub cvt_seq { head => $fin->head, type => $fin->type); } -sub cvt_span { - my $self = shift; - my $zyg = cvt($self->zyg->[0]); +sub do_span { + my ($op, $zyg) = @_; CLROp::Value->new(type => $zyg->type, stmts => [ - CLROp::Term->new(op => ['labelhere', $self->lstart]), + CLROp::Term->new(op => ['labelhere', $op->[1]]), $zyg->stmts_result, - CLROp::Term->new(op => ['labelhere', $self->lend]) ]); + CLROp::Term->new(op => ['labelhere', $op->[2]]) ]); } -sub cvt_annotation { - my $self = shift; - my $zyg = cvt($self->zyg->[0]); +sub do_annotation { + my ($op, $zyg) = @_; return $zyg unless @{ $zyg->stmts }; CLROp::Value->new(type => $zyg->type, head => $zyg->head, stmts => [ - CLROp::Term->new(op => ['push_line', $self->line]), + CLROp::Term->new(op => ['push_line', $op->[1]]), @{ $zyg->stmts }, CLROp::Term->new(op => ['pop_line']) ]); } -sub cvt_let { - my $self = shift; - my ($head, @zyg) = @{ $self->zyg }; - $head = cvt($head); - { - local $lettypes{$self->name} = $head->type; - @zyg = map { cvt($_) } @zyg; - } +sub do_let { + my ($op, $head, @zyg) = @_; CLROp::Value->new(type => (@zyg ? $zyg[-1]->type : 'Void'), stmts => [ @{ $head->stmts }, - CLROp::Term->new(op => ['push_let', $self->name], + CLROp::Term->new(op => ['push_let', $op->[1]], zyg => [ $head->anyhead ]), (map { $_->stmts_result } @zyg), - CLROp::Term->new(op => ['drop_let', $self->name])]); + CLROp::Term->new(op => ['drop_let', $op->[1]])]); } +my @_all = qw/ callframe call_method call_sub cast cgoto clr_arith clr_bool + clr_call_direct clr_call_virt clr_char clr_compare clr_double clr_field_get + clr_field_set clr_index_get clr_index_set clr_int clr_new clr_new_arr + clr_new_zarr clr_sfield_get clr_sfield_set clr_string const drop drop_let + ehspan goto hintget labelhere labelid ncgoto peek_let poke_let pop_line + pos push_let push_line push_null return rtpadget rtpadgeti rtpadput + rtpadputi rxbprim rxpushb /; + my %_md = ( - 'CgOp::Annotation' => \&cvt_annotation, - 'CgOp::Let' => \&cvt_let, - 'CgOp::Primitive' => \&cvt_primitive, - 'CgOp::While' => \&cvt_while, - 'CgOp::Ternary' => \&cvt_ternary, - 'CgOp::Span' => \&cvt_span, - 'CgOp::Seq' => \&cvt_seq, + 'ann' => \&do_annotation, + 'while' => \&do_while, + 'ternary' => \&do_ternary, + 'span' => \&do_span, + 'seq' => \&do_seq, + (map { $_ => \&do_primitive } @_all), ); -sub cvt { goto &{ $_md{ref($_[0])} } } + +sub cvt { + my $zyg = $_[0]->zyg; + my $op = $_[0]->op; + + if ($op->[0] eq 'let') { + my ($z, @r) = @$zyg; + $z = cvt($z); + local $lettypes{$op->[1]} = $z->type; + do_let($op, $z, map { cvt($_) } @r); + } elsif ($op->[0] eq 'drop') { + do_drop($zyg->[0]); + } else { + $_md{$op->[0]}->($op, map { cvt($_) } @$zyg); + } +} sub codegen { my ($cg, $root) = @_; diff --git a/src/CodeGen.pm b/src/CodeGen.pm index f38309a0..f11385a6 100644 --- a/src/CodeGen.pm +++ b/src/CodeGen.pm @@ -304,12 +304,12 @@ use CLRTypes; } sub clr_new { - my ($self, $class, $nargs, @args) = @_; + my ($self, $class, @args) = @_; $class, "new $class(" . join(", ", _odds @args) . ")"; } sub clr_new_arr { - my ($self, $class, $nitems, @args) = @_; + my ($self, $class, @args) = @_; $class . "[]", "new $class []{" . join(", ", _odds @args) . "}"; } @@ -395,7 +395,7 @@ use CLRTypes; } sub clr_call_direct { - my ($self, $name, $nargs, @args) = @_; + my ($self, $name, @args) = @_; my ($nm, $cl, $rt) = CLRTypes->info('cm', $name); if ($cl eq 'c') { $self->_cpscall($rt, @@ -408,7 +408,7 @@ use CLRTypes; } sub clr_call_virt { - my ($self, $name, $nargs, $ity, $inv, @args) = @_; + my ($self, $name, $ity, $inv, @args) = @_; my ($nm, $cl, $rt) = CLRTypes->info('cm', $ity, $name); if ($cl eq 'c') { $self->_cpscall($rt, @@ -421,7 +421,7 @@ use CLRTypes; } sub rxbprim { - my ($self, $name, $nargs, @args) = @_; + my ($self, $name, @args) = @_; $self->_emit("if (!th.rx.$name(" . join(", ", _odds @args) . ")) goto case \@\@Lbacktrack"); } diff --git a/src/Metamodel.pm b/src/Metamodel.pm index 9b2ed751..aa706672 100644 --- a/src/Metamodel.pm +++ b/src/Metamodel.pm @@ -155,6 +155,7 @@ our $unit; sub add_super { my ($self, $targ) = @_; + Carp::confess "bad attempt to add null super" unless $targ; push @{ $self->superclasses }, $targ; } @@ -514,6 +515,7 @@ our $unit; sub deref { my ($self, $thing) = @_; + Carp::confess "trying to dereference null" unless $thing; return $self->get_unit($thing->[0])->xref->[$thing->[1]]; } diff --git a/src/Op.pm b/src/Op.pm index c10fa0c2..ec4a1f1e 100644 --- a/src/Op.pm +++ b/src/Op.pm @@ -904,7 +904,7 @@ use CgOp; sub code { my ($self, $body) = @_; - CgOp::rawsccall('Kernel.Take', $self->value->cgop($body)); + CgOp::rawscall('Kernel.Take', $self->value->cgop($body)); } __PACKAGE__->meta->make_immutable; @@ -927,7 +927,7 @@ use CgOp; # construct a List from the iterator CgOp::subcall(CgOp::fetch(CgOp::scopedlex('&_gather')), - CgOp::newscalar(CgOp::rawsccall('Kernel.GatherHelper', + CgOp::newscalar(CgOp::rawscall('Kernel.GatherHelper', CgOp::fetch(CgOp::scopedlex($self->var))))); } @@ -968,9 +968,9 @@ use CgOp; CgOp::const(CgOp::rawnewarr('str', @mcaps)), CgOp::null('clr:Cursor')), $self->rxop->code($body), - CgOp::rawccall(CgOp::rxframe, 'End'), + CgOp::rawcall(CgOp::rxframe, 'End'), CgOp::label('backtrack'), - CgOp::rawccall(CgOp::rxframe, 'Backtrack'), + CgOp::rawcall(CgOp::rxframe, 'Backtrack'), CgOp::null('var')); } diff --git a/src/RxOp.pm b/src/RxOp.pm index ddcfa861..dc17d636 100644 --- a/src/RxOp.pm +++ b/src/RxOp.pm @@ -434,7 +434,7 @@ use CgOp; if ($self->selfcut) { push @code, CgOp::letn( - "k", CgOp::fetch(CgOp::rawsccall('Kernel.GetFirst:c,Variable', + "k", CgOp::fetch(CgOp::rawscall('Kernel.GetFirst:c,Variable', CgOp::fetch($callf))), $updatef); } else { @@ -445,7 +445,7 @@ use CgOp; "GetCursorList"), "shift")); push @code, CgOp::label($sk); push @code, CgOp::letn( - "k", CgOp::fetch(CgOp::rawsccall('Kernel.GetFirst:c,Variable', + "k", CgOp::fetch(CgOp::rawscall('Kernel.GetFirst:c,Variable', CgOp::fetch(CgOp::rxcall("GetCursorList")))), $updatef); push @code, CgOp::rxpushb("SUBRULE", $bt); @@ -643,11 +643,11 @@ use CgOp; CgOp::letvar("fns")), CgOp::newscalar(CgOp::rxcall( 'MakeCursor')))), CgOp::letvar("i", CgOp::arith('+', CgOp::letvar("i"), CgOp::int(1))), - CgOp::letvar("k", CgOp::fetch(CgOp::rawsccall('Kernel.GetFirst:c,Variable', + CgOp::letvar("k", CgOp::fetch(CgOp::rawscall('Kernel.GetFirst:c,Variable', CgOp::fetch(CgOp::letvar("ks"))))), CgOp::ncgoto('backtrack', CgOp::rawcall(CgOp::letvar("k"), 'IsDefined')), - CgOp::rawccall(CgOp::rxframe, 'End', CgOp::cast('clr:Cursor', + CgOp::rawcall(CgOp::rxframe, 'End', CgOp::cast('clr:Cursor', CgOp::letvar("k"))), CgOp::letvar('ks', CgOp::methodcall(CgOp::methodcall( CgOp::letvar('ks'), "list"), "clone")), @@ -656,7 +656,7 @@ use CgOp; CgOp::ncgoto('backtrack', CgOp::unbox('bool', CgOp::fetch( CgOp::methodcall(CgOp::letvar('ks'), 'Bool')))), CgOp::rxpushb('SUBRULE', 'nextcsr'), - CgOp::rawccall(CgOp::rxframe, 'End', CgOp::cast('clr:Cursor', + CgOp::rawcall(CgOp::rxframe, 'End', CgOp::cast('clr:Cursor', CgOp::fetch(CgOp::methodcall(CgOp::letvar('ks'), 'shift')))), CgOp::goto('backtrack')); }