Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #108 from MoeOrganization/prakashk/for-loop
for loop etc.
  • Loading branch information
Stevan Little committed May 10, 2013
2 parents b82da52 + 6c3516f commit da70954
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 30 deletions.
4 changes: 2 additions & 2 deletions src/main/scala/org/moe/interpreter/guts/Statements.scala
Expand Up @@ -106,7 +106,7 @@ object Statements extends Utils {
obj: MoeObject,
f: (MoeEnvironment, String, MoeObject) => Any
) =>
f(env, name, obj)
f(newEnv, name, obj)
i.evaluate(newEnv, body)
}

Expand Down Expand Up @@ -136,4 +136,4 @@ object Statements extends Utils {
r.NativeObjects.getUndef
}
}
}
}
61 changes: 40 additions & 21 deletions src/main/scala/org/moe/parser/MoeProductions.scala
Expand Up @@ -239,7 +239,7 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse

// assignment

def variableDeclaration = "my" ~> variableName ~ ("=" ~> expression).? <~ statementDelim ^^ {
def variableDeclaration = "my" ~> variableName ~ ("=" ~> expression).? ^^ {
case v ~ expr => VariableDeclarationNode(v, expr.getOrElse(UndefLiteralNode()))
}

Expand All @@ -252,32 +252,32 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse
f(x.head, y.headOption.getOrElse(UndefLiteralNode())) :: zipEm(x.tail, y.tail, f)
}

def multiVariableDeclaration = "my" ~> ("(" ~> repsep(variableName, ",") <~ ")") ~ ("=" ~> "(" ~> repsep(expression, ",") <~ ")").? <~ statementDelim ^^ {
def multiVariableDeclaration = "my" ~> ("(" ~> repsep(variableName, ",") <~ ")") ~ ("=" ~> "(" ~> repsep(expression, ",") <~ ")").? ^^ {
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 ^^ {
def variableAssignment = variableName ~ "=" ~ expression ^^ {
case v ~ _ ~ expr => VariableAssignmentNode(v, expr)
}

def multiVariableAssignment = ("(" ~> repsep(variableName, ",") <~ ")") ~ "=" ~ ("(" ~> repsep(expression, ",") <~ ")") <~ statementDelim ^^ {
def multiVariableAssignment = ("(" ~> repsep(variableName, ",") <~ ")") ~ "=" ~ ("(" ~> repsep(expression, ",") <~ ")") ^^ {
case vars ~ _ ~ exprs => MultiVariableAssignmentNode(vars, exprs)
}

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

def multiAttributeAssignment = ("(" ~> repsep(attributeName, ",") <~ ")") ~ "=" ~ ("(" ~> repsep(expression, ",") <~ ")") <~ statementDelim ^^ {
def multiAttributeAssignment = ("(" ~> repsep(attributeName, ",") <~ ")") ~ "=" ~ ("(" ~> repsep(expression, ",") <~ ")") ^^ {
case vars ~ _ ~ exprs => MultiAttributeAssignmentNode(vars, exprs)
}

def arrayElementAssignment = array_index_rule ~ "=" ~ expression <~ statementDelim ^^ {
def arrayElementAssignment = array_index_rule ~ "=" ~ expression ^^ {
case array ~ index_exprs ~ "=" ~ value_expr => ArrayElementLvalueNode(array, index_exprs, value_expr)
}

def hashElementAssignment = hash_index_rule ~ "=" ~ expression <~ statementDelim ^^ {
def hashElementAssignment = hash_index_rule ~ "=" ~ expression ^^ {
case hash ~ key_exprs ~ "=" ~ value_expr => HashElementLvalueNode(hash, key_exprs, value_expr)
}

Expand All @@ -292,13 +292,18 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse

def statementDelim: Parser[List[String]] = rep1(";")

def statements: Parser[StatementsNode] = repsep((
def statements: Parser[StatementsNode] = rep((
blockStatement
| declarationStatement
| statement
), statementDelim.?) ^^ StatementsNode
| terminatedStatement
| simpleStatement
| scopeBlock
)) ~ opt(statement) ^^ {
case stmts ~ Some(lastStmt) => StatementsNode(stmts ++ List(lastStmt))
case stmts ~ None => StatementsNode(stmts)
}

def block: Parser[StatementsNode] = "{" ~> statements <~ "}"
def block: Parser[StatementsNode] = ("{" ~> statements <~ "}")

def doBlock: Parser[StatementsNode] = "do".r ~> block
def scopeBlock: Parser[ScopeNode] = block ^^ { ScopeNode(_) }
Expand Down Expand Up @@ -347,7 +352,7 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse

// Classes

def attributeDecl = "has" ~> attributeName ~ ("=" ~> expression).? <~ statementDelim ^^ {
def attributeDecl = "has" ~> attributeName ~ ("=" ~> expression).? ^^ {
case v ~ expr => AttributeDeclarationNode(v, expr.getOrElse(UndefLiteralNode()))
}

Expand All @@ -364,6 +369,7 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse
def classBodyParts: Parser[AST] = (
methodDecl
| submethodDecl
| (attributeDecl <~ statementDelim)
| attributeDecl
)

Expand All @@ -384,7 +390,7 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse
*********************************************************************
*/

def useStatement: Parser[UseStatement] = ("use" ~> namespacedIdentifier) <~ statementDelim ^^ UseStatement
def useStatement: Parser[UseStatement] = ("use" ~> namespacedIdentifier) ^^ UseStatement

def elseBlock: Parser[IfStruct] = "else" ~> block ^^ {
case body => new IfStruct(BooleanLiteralNode(true), body)
Expand All @@ -408,8 +414,17 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse
case cond ~ body => WhileNode(PrefixUnaryOpNode(cond, "!"), body)
}

// def forLoop = "for" ~ "(" ~> expression <~ ";" ~> expression <~ ";" ~> expression <~ ")" ~ block
// def foreachLoop = "for(each)?".r ~ varDeclare ~ "(" ~> expression <~ ")" ~ block
def topicVariable = ("my".? ~> variableName) ^^ {
v => VariableDeclarationNode(v, UndefLiteralNode())
}
def foreachBlock = "for(each)?".r ~> opt(topicVariable) ~ ("(" ~> expression <~ ")") ~ block ^^ {
case Some(topic) ~ list ~ block => ForeachNode(topic, list, block)
case None ~ list ~ block => ForeachNode(VariableDeclarationNode("$_", UndefLiteralNode()), list, block)
}

def forBlock = "for" ~> (("(" ~> variableDeclaration) <~ ";") ~ (expression <~ ";") ~ (statement <~ ")") ~ block ^^ {
case init ~ termCond ~ step ~ block => ForNode(init, termCond, step, block)
}

def tryBlock: Parser[TryNode] = ("try" ~> block) ~ rep(catchBlock) ~ rep(finallyBlock) ^^ {
case a ~ b ~ c => TryNode(a, b, c)
Expand All @@ -432,17 +447,19 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse
ifElseBlock
| whileBlock
| untilBlock
| foreachBlock
| forBlock
| doBlock
| tryBlock
)
) <~ opt(statementDelim)

lazy val declarationStatement: Parser[AST] = (
packageDecl
| subroutineDecl
| classDecl
)
) <~ opt(statementDelim)

lazy val statement: Parser[AST] = (
lazy val simpleStatement: Parser[AST] = (
variableDeclaration
| multiVariableDeclaration
| variableAssignment
Expand All @@ -452,8 +469,10 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse
| useStatement
| arrayElementAssignment
| hashElementAssignment
| expression <~ statementDelim.?
| scopeBlock
| expression
// | scopeBlock
)

lazy val statement: Parser[AST] = simpleStatement
lazy val terminatedStatement: Parser[AST] = simpleStatement <~ statementDelim
}
4 changes: 4 additions & 0 deletions src/test/scala/org/moe/parser/AssignmentTestSuite.scala
Expand Up @@ -17,4 +17,8 @@ class AssignmentTestSuite extends FunSuite with BeforeAndAfter with ParserTestUt
result.unboxToInt.get should equal (20)
}

test("... a basic assignment -- multiple statements") {
val result = interpretCode("my $foo = 10; sub foo { $foo = $foo + 10; $foo = $foo + 20 } foo()")
result.unboxToInt.get should equal (40)
}
}
8 changes: 4 additions & 4 deletions src/test/scala/org/moe/parser/ClassTestSuite.scala
Expand Up @@ -115,7 +115,7 @@ class ClassTestSuite extends FunSuite with BeforeAndAfter with ParserTestUtils w
}

test("... make sure $?SELF and $?CLASS work") {
val result = interpretCode("class Foo { method bar { [ $?SELF, $?CLASS ] } }; Foo.new.bar")
val result = interpretCode("class Foo { method bar { [ $?SELF, $?CLASS ] } } Foo.new.bar")
val array = result.unboxToArrayBuffer.get
val obj = array(0).asInstanceOf[MoeObject]
val cls = array(1).asInstanceOf[MoeClass]
Expand All @@ -132,17 +132,17 @@ class ClassTestSuite extends FunSuite with BeforeAndAfter with ParserTestUtils w
submethod BUILD { self.set_foo }
method set_foo { $!foo = "FOO"; }
method get_foo { $!foo }
};
}
class Bar extends Foo {
has $!bar;
submethod BUILD { self.set_bar }
method set_bar { $!bar = "BAR"; }
method get_bar { $!bar }
};
}
"""

test("... submethod test") {
val result = interpretCode(submethodTest + "; my $b = Bar.new; [ $b.get_foo, $b.get_bar ]")
val result = interpretCode(submethodTest + "my $b = Bar.new; [ $b.get_foo, $b.get_bar ]")
val array = result.unboxToArrayBuffer.get

assert(array(0).unboxToString.get === "FOO")
Expand Down
18 changes: 18 additions & 0 deletions src/test/scala/org/moe/parser/ForStatementTestSuite.scala
@@ -0,0 +1,18 @@
package org.moe.parser

import org.scalatest.FunSuite
import org.scalatest.BeforeAndAfter

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

class ForStatementTestSuite extends FunSuite with BeforeAndAfter with ParserTestUtils {

test("... a for block") {
val result = interpretCode("my @a = [1,2,3]; my $sum = 0; for (my $i = 0; $i < @a.length; $i = $i + 1) { $sum = $sum + @a[$i] } $sum")
assert(result.unboxToInt.get === 6)
}

}
40 changes: 40 additions & 0 deletions src/test/scala/org/moe/parser/ForeachStatementTestSuite.scala
@@ -0,0 +1,40 @@
package org.moe.parser

import org.scalatest.FunSuite
import org.scalatest.BeforeAndAfter

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

class ForeachStatementTestSuite extends FunSuite with BeforeAndAfter with ParserTestUtils {

test("... a foreach block") {
val result = interpretCode("my @a = [1,2,3]; my $sum = 0; foreach (0..2) { $sum = $sum + @a[$_] } $sum")
assert(result.unboxToInt.get === 6)
}

test("... a for block with topic") {
val result = interpretCode("my $sum = 0; for $x (1..3) { $sum = $sum + $x } $sum")
assert(result.unboxToInt.get === 6)
}

test("... a for block with multiple statements") {
val result = interpretCode("my $result = 0; for $x (1..3) { $result = $result + $x; $result = $result * 2 } $result")
assert(result.unboxToInt.get === 22)
}

test("... a for block to modify array") {
val result = interpretCode("my @a = [1,2,3]; for (0..2) { @a[$_] = @a[$_] + 1 } @a.join(',')")
assert(result.unboxToString.get === "2,3,4")
}

// XXXX: this should work when binding the topic variable to array
// elements is implemented

// test("... a for block to modify array (take 2)") {
// val result = interpretCode("my @a = [1,2,3]; for (@a) { $_ = $_ + 1 } @a.join(',')")
// assert(result.unboxToString.get === "2,3,4")
// }
}
Expand Up @@ -31,17 +31,17 @@ class PackageDefinitionTestSuite extends FunSuite with BeforeAndAfter with Parse
}

test("... test automatic package tree creation") {
val result = interpretCode("package Foo::Bar { sub baz {'BAZ'} }; Foo::Bar::baz()")
val result = interpretCode("package Foo::Bar { sub baz {'BAZ'} } Foo::Bar::baz()")
assert(result.unboxToString.get === "BAZ")
}

test("... test automatic package tree creation doesn't clobber existing packages") {
val result = interpretCode("package Foo { sub bar { 'BAR' } }; package Foo::Bar { sub baz { 'BAZ' } }; Foo::bar();")
val result = interpretCode("package Foo { sub bar { 'BAR' } } package Foo::Bar { sub baz { 'BAZ' } } Foo::bar();")
assert(result.unboxToString.get === "BAR")
}

test("... test automatic package tree creation doesn't clobber existing packages (again)") {
val result = interpretCode("package Foo { sub bar {'BAR'} }; package Foo { sub baz {'BAZ'} }; Foo::bar() ~ Foo::baz()")
val result = interpretCode("package Foo { sub bar {'BAR'} } package Foo { sub baz {'BAZ'} } Foo::bar() ~ Foo::baz()")
assert(result.unboxToString.get === "BARBAZ")
}

Expand Down

0 comments on commit da70954

Please sign in to comment.