Permalink
Browse files

major refactor of the parser to start making varargout and multi-assi…

…gnment work. The code is U-G-L-Y ugly, but all tests miraculously pass (we even gained a passing test)
  • Loading branch information...
1 parent 136c693 commit 6b496903884328a7892a2e060fb60d46f87ce1f2 @Whiteknight committed Dec 9, 2009
Showing with 153 additions and 48 deletions.
  1. +17 −0 src/internals/aggregates.pir
  2. +7 −1 src/internals/dispatch.pir
  3. +115 −42 src/parser/actions.pm
  4. +12 −4 src/parser/grammar.pg
  5. +2 −1 t/2-function.t
@@ -239,3 +239,20 @@
.return($P0)
.end
+.sub '_is_defined'
+ .param pmc item
+ if null item goto not_defined
+ $S0 = typeof item
+ if $S0 == "Undef" goto not_defined
+ .return(1)
+ not_defined:
+ .return(0)
+.end
+
+.sub '_integer_copy'
+ .param int i
+ $P0 = new 'Integer'
+ $P0 = i
+ .return($P0)
+.end
+
@@ -273,9 +273,15 @@ Returns the modified variable.
.sub '!indexed_assign'
.param pmc var
.param pmc value
+ .param int idx
+ .param int array_assign
.param pmc indices :slurpy
- # TODO: Handle block assignments for matrices.
+ # If array_assign == 1, value is a regular scalar value. Otherwise, it's an
+ # aggregate and idx is the index of the value
+ if array_assign == 0 goto have_final_value
+ value = value[idx]
+ have_final_value:
$I0 = elements indices
if $I0 == 0 goto assign_scalar
View
@@ -88,6 +88,7 @@ method terminator($/) {
method stmt_with_value($/, $key) {
our $?TERMINATOR;
+ our $NUMLVALUES;
if $?TERMINATOR == 1 {
make PAST::Op.new(:pasttype('inline'), :node($/),
:inline(" '!store_last_ans'(%0)"),
@@ -259,71 +260,133 @@ method do_block($/) {
make $( $<block> );
}
-# We're turning this:
-# x(a, b) = c
-# into this:
-# x = '!indexed_assign'(x, c, a, b)
-# We have to do this because of the way that indices are managed in M, and how
-# matrices can be indexed like vectors.
+=begin
+
+Here is what we want things to look like:
+
+ x(...) = c
+ x = '!indexed_assign'(x, c, ...)
+
+ [a(...), b(...)] = c
+ $P1 = c[0]
+ a = '!indexed_assign'(a, $P1, ...)
+ $P2 = c[1]
+ b = '!indexed_assign'(b, $P2, ...)
+
+=cut
+
method assignment($/, $key) {
our $?BLOCK;
our %?GLOBALS;
- our @?PARAMS;
- our $?LVALUECELL;
+ our $NUMLVALUES; # number of values in current assignment
+ our $ASSIGNVALUE; # value or array of values to assign
+ our $ARRAYASSIGN; # Whether we are in array or scalar mode
+ our $?LVALUECELL; # lvalue is being indexed with {}
+ our @?LVALUEPARAMS;
+
if $key eq "open" {
- @?PARAMS := _new_empty_array();
+ @?LVALUEPARAMS := _new_empty_array();
+ $NUMLVALUES := 1;
+ $ASSIGNVALUE := PAST::Var.new(
+ :name("__tmp_assign_helper")
+ );
+ $ARRAYASSIGN := PAST::Val.new(
+ :value(0),
+ :returns('Integer')
+ );
+ }
+ elsif $key eq "lvalues" {
+ $NUMLVALUES--;
}
else {
- my $indexer := '!indexed_assign';
- if $?LVALUECELL {
- $indexer := '!indexed_assign_cell';
- $?LVALUECELL := 0;
- }
- my $rhs := $( $<expression> );
- my $lhs := $( $<variable> );
- $lhs.lvalue(1);
- my $name := $lhs.name();
- if %?GLOBALS{$name} {
- # TODO: Make sure we want "Matrixy::globals", not ["Matrixy","globals"]
- $lhs.namespace("Matrixy::globals");
+ if +($<lvalue>) > 1 {
+ $ARRAYASSIGN.value(1);
}
- $rhs := PAST::Op.new(
- :pasttype('call'),
- :name($indexer),
- PAST::Var.new(
- :name($lhs.name()),
- :scope('package')
- ),
- $rhs
+ # $ASSIGNVALUE = <expression>
+ my $region := PAST::Stmts.new(
+ PAST::Op.new(
+ :pasttype('bind'),
+ :node($/),
+ $ASSIGNVALUE,
+ $($<expression>)
+ )
);
- for @?PARAMS {
- $rhs.push($_);
+ # Now push all the items that read from $ASSIGNVALUE
+ for $<lvalue> {
+ $region.push( $($_) );
}
- make PAST::Op.new(
- $lhs,
- $rhs,
- :pasttype('bind'),
- :name( $lhs.name() ),
- :node($/)
- );
+ make $region;
+ }
+}
+
+method lvalue($/) {
+ our $NUMLVALUES; # number of values in current assignment
+ our $ASSIGNVALUE; # value or array of values to assign
+ our $ARRAYASSIGN; # Whether we are in array or scalar mode
+ our $?LVALUECELL; # Whether the lvalue is indexed with {}
+ our %?GLOBALS; # list of variables explicitly described as global
+ our @?LVALUEPARAMS; # the indices on the lvalue
+
+ my $indexer := '!indexed_assign';
+ if $?LVALUECELL {
+ $indexer := '!indexed_assign_cell';
+ $?LVALUECELL := 0;
+ }
+ my $lhs := $( $<variable> );
+ $lhs.lvalue(1);
+ my $name := $lhs.name();
+ if %?GLOBALS{$name} {
+ # TODO: Make sure we want "Matrixy::globals", not ["Matrixy","globals"]
+ $lhs.namespace("Matrixy::globals");
+ }
+ # ... = '!indexed_assign'(var, value, idx, array?, ...)
+ my $idx := _integer_copy($NUMLVALUES);
+ $idx--;
+ my $idxnode := PAST::Val.new(
+ :value($idx),
+ :returns('Integer')
+ );
+ my $rhs := PAST::Op.new(
+ :pasttype('call'),
+ :name($indexer),
+ PAST::Var.new(
+ :name($name),
+ :scope('package')
+ ),
+ $ASSIGNVALUE,
+ $idxnode,
+ $ARRAYASSIGN
+ );
+ for @?LVALUEPARAMS {
+ $rhs.push($_);
}
+ $NUMLVALUES++;
+ make PAST::Op.new(
+ $lhs,
+ $rhs,
+ :pasttype('bind'),
+ :name( $name ),
+ :node($/)
+ );
}
+
+
method lvalue_postfix_index($/, $key) {
- our @?PARAMS;
+ our @?LVALUEPARAMS;
our $?LVALUECELL;
if $key eq "cellexpression" {
$?LVALUECELL := 1;
}
if $key eq "expressions" || $key eq "cellexpression" {
for $<expression> {
- @?PARAMS.push($($_));
+ @?LVALUEPARAMS.push($($_));
}
}
else {
# TODO: This isn't right for structures
my $name := $( $<identifier> ).name();
- @?PARAMS.push(
+ @?LVALUEPARAMS.push(
PAST::Val.new(
:value($name),
:returns('String')
@@ -562,9 +625,12 @@ method anon_func_constructor($/) {
method sub_or_var($/, $key) {
our @?BLOCK;
our %?GLOBALS;
+ our $NUMLVALUES;
+
my $invocant := $( $<primary> );
my $name := $invocant.name();
my $parens := 0;
+
if $key eq "args" {
$parens := 1;
} elsif $key eq "cellargs" {
@@ -574,19 +640,26 @@ method sub_or_var($/, $key) {
# TODO: "Matrixy";"globals"
$invocant.namespace("Matrixy::globals");
}
+
my $nargin := 0;
- my $nargout := 0;
+ my $nargout := 1;
+ if _is_defined($NUMLVALUES) {
+ $nargout := $NUMLVALUES;
+ }
+
my $past := PAST::Op.new(
:name('!dispatch'),
:pasttype('call'),
:node($/)
);
+
if $<expression> {
for $<expression> {
$past.push($($_));
$nargin++;
}
}
+
$past.unshift(
PAST::Val.new(
:value($parens),
View
@@ -68,11 +68,19 @@ token sys_bare_words {
}
rule assignment {
- {*} #= open
- <variable>
- <lvalue_postfix_index>*
+ {*} #= open
+ [
+ <lvalue> [',' <lvalue>]*
+ | '[' <lvalue> [',' <lvalue>]* ']'
+ ]
+ {*} #= lvalues
'=' <expression>
- {*} #= close
+ {*} #= close
+}
+
+rule lvalue {
+ <variable> <lvalue_postfix_index>*
+ {*}
}
rule lvalue_postfix_index {
View
@@ -76,7 +76,8 @@ function x = argsouttest()
if nargout == 1
printf("ok 10\n");
else
- printf("not ok 10 - %d# TODO need to implement nargout\n", nargout);
+ printf("not ok 10\n");
endif
endfunction
a = argsouttest();
+

0 comments on commit 6b49690

Please sign in to comment.