Skip to content

Commit

Permalink
multi-assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
Stevan Little committed Apr 10, 2013
1 parent 43b732f commit 18c8f04
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 0 deletions.
25 changes: 25 additions & 0 deletions src/main/scala/org/moe/parser/MoeProductions.scala
Expand Up @@ -247,14 +247,36 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse
case v ~ expr => VariableDeclarationNode(v, expr.getOrElse(UndefLiteralNode()))
}

private def zipEm (x: List[String], y: List[AST], f: ((String, AST)) => AST): List[AST] = {
if (y.isEmpty)
x.map(f(_, UndefLiteralNode()))
else if (x.isEmpty)
List()
else
f(x.head, y.headOption.getOrElse(UndefLiteralNode())) :: zipEm(x.tail, y.tail, f)
}

def multiVariableDeclaration = "my" ~> ("(" ~> repsep(variableName, ",") <~ ")") ~ ("=" ~> "(" ~> repsep(expression, ",") <~ ")").? <~ statementDelim ^^ {
case vars ~ None => StatementsNode(vars.map(VariableDeclarationNode(_, UndefLiteralNode())))
case vars ~ Some(exprs) => StatementsNode(zipEm(vars, exprs, (p) => VariableDeclarationNode(p._1, p._2)))
}

def variableAssignment = variableName ~ "=" ~ expression <~ statementDelim ^^ {
case v ~ _ ~ expr => VariableAssignmentNode(v, expr)
}

def multiVariableAssignment = ("(" ~> repsep(variableName, ",") <~ ")") ~ "=" ~ ("(" ~> repsep(expression, ",") <~ ")") <~ statementDelim ^^ {
case vars ~ _ ~ exprs => StatementsNode(zipEm(vars, exprs, (p) => VariableAssignmentNode(p._1, p._2)))
}

def attributeAssignment = attributeName ~ "=" ~ expression <~ statementDelim ^^ {
case v ~ _ ~ expr => AttributeAssignmentNode(v, expr)
}

def multiAttributeAssignment = ("(" ~> repsep(attributeName, ",") <~ ")") ~ "=" ~ ("(" ~> repsep(expression, ",") <~ ")") <~ statementDelim ^^ {
case vars ~ _ ~ exprs => StatementsNode(zipEm(vars, exprs, (p) => AttributeAssignmentNode(p._1, p._2)))
}

def arrayElementAssignment = array_index_rule ~ "=" ~ expression <~ statementDelim ^^ {
case "@" ~ array ~ index_expr ~ "=" ~ value_expr => ArrayElementLvalueNode("@" + array, index_expr, value_expr)
}
Expand Down Expand Up @@ -421,8 +443,11 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse

lazy val statement: Parser[AST] = (
variableDeclaration
| multiVariableDeclaration
| variableAssignment
| multiVariableAssignment
| attributeAssignment
| multiAttributeAssignment
| useStatement
| arrayElementAssignment
| hashElementAssignment
Expand Down
109 changes: 109 additions & 0 deletions src/test/scala/org/moe/parser/MultiAssignmentTestSuite.scala
@@ -0,0 +1,109 @@
package org.moe.parser

import org.scalatest.FunSuite
import org.scalatest.BeforeAndAfter
import org.scalatest.matchers.ShouldMatchers

import org.moe.runtime._
import org.moe.runtime.nativeobjects._
import org.moe.interpreter._
import org.moe.ast._
import org.moe.parser._

class MultiAssignmentTestSuite extends FunSuite with BeforeAndAfter with ParserTestUtils with ShouldMatchers {

// declaration

test("... basic multi-declaration") {
val result = interpretCode("my ($x, $y) = (1, 2); [ $x, $y ]")
var a = result.unboxToArrayBuffer.get
a(0).unboxToInt.get should equal (1)
a(1).unboxToInt.get should equal (2)
}

test("... basic multi-declaration w/ extra var") {
val result = interpretCode("my ($x, $y, $z) = (1, 2); [ $x, $y, $z ]")
var a = result.unboxToArrayBuffer.get
a(0).unboxToInt.get should equal (1)
a(1).unboxToInt.get should equal (2)
a(2) should equal (runtime.NativeObjects.getUndef)
}

test("... basic multi-declaration w/ extra element") {
val result = interpretCode("my ($x, $y) = (1, 2, 3); [ $x, $y ]")
var a = result.unboxToArrayBuffer.get
a(0).unboxToInt.get should equal (1)
a(1).unboxToInt.get should equal (2)
}

// assignment

test("... basic multi-assign") {
val result = interpretCode("my ($x, $y); ($x, $y) = (1, 2); [ $x, $y ]")
var a = result.unboxToArrayBuffer.get
a(0).unboxToInt.get should equal (1)
a(1).unboxToInt.get should equal (2)
}

test("... basic multi-assign w/ extra var") {
val result = interpretCode("my ($x, $y, $z); ($x, $y, $z) = (1, 2); [ $x, $y, $z ]")
var a = result.unboxToArrayBuffer.get
a(0).unboxToInt.get should equal (1)
a(1).unboxToInt.get should equal (2)
a(2) should equal (runtime.NativeObjects.getUndef)
}

test("... basic multi-assign w/ extra element") {
val result = interpretCode("my ($x, $y); ($x, $y) = (1, 2, 3); [ $x, $y ]")
var a = result.unboxToArrayBuffer.get
a(0).unboxToInt.get should equal (1)
a(1).unboxToInt.get should equal (2)
}

// attribute assignment

private val testClass = """
class Foo {
has $!x;
has $!y;
has $!z;
method test1 {
($!x, $!y) = (1, 2);
}
method test2 {
($!x, $!y, $!z) = (1, 2);
}
method test3 {
($!x, $!y) = (1, 2, 3);
}
method get { [ $!x, $!y, $!z ] }
}
"""

test("... basic multi-attribute-assign") {
val result = interpretCode(testClass + "; my $x = ^Foo.new; $x.test1; $x.get")
var a = result.unboxToArrayBuffer.get
a(0).unboxToInt.get should equal (1)
a(1).unboxToInt.get should equal (2)
}

test("... basic multi-attribute-assign w/ extra var") {
val result = interpretCode(testClass + "; my $x = ^Foo.new; $x.test2; $x.get")
var a = result.unboxToArrayBuffer.get
a(0).unboxToInt.get should equal (1)
a(1).unboxToInt.get should equal (2)
a(2) should equal (runtime.NativeObjects.getUndef)
}

test("... basic multi-attribute-assign w/ extra element") {
val result = interpretCode(testClass + "; my $x = ^Foo.new; $x.test3; $x.get")
var a = result.unboxToArrayBuffer.get
a(0).unboxToInt.get should equal (1)
a(1).unboxToInt.get should equal (2)
}

}

0 comments on commit 18c8f04

Please sign in to comment.