Skip to content

Commit

Permalink
Merge pull request #117 from MoeOrganization/prakashk/unless+modifiers
Browse files Browse the repository at this point in the history
unless statement and statement modifiers
  • Loading branch information
Stevan Little committed May 14, 2013
2 parents 054326e + bf1ea90 commit b575655
Show file tree
Hide file tree
Showing 13 changed files with 215 additions and 79 deletions.
17 changes: 3 additions & 14 deletions lib/Test-More/lib/Test/More.mo
Expand Up @@ -74,24 +74,13 @@ package Test {
}

submethod compare_deeply ($got, $expected) {
if ($got.isa("Array") && $expected.isa("Array")) {
self.compare_arrays($got, $expected);
} elsif ($got.isa("Hash") && $expected.isa("Hash")) {
self.compare_hashes($got, $expected);
if ($got.isa("Array") && $expected.isa("Array")
|| $got.isa("Hash") && $expected.isa("Hash")) {
$got.eqv($expected);
} else {
$!output.bailout("Can only compare deeply Array and Hash objects");
}
}

submethod compare_arrays (@got, @expected) {
# poor man's deep-compare of arrays
self.compare(@got.join("|"), @expected.join("|"));
}

submethod compare_hashes (%got, %expected) {
# poor man's deep-compare of hashes
self.compare(%got.pairs.join("|"), %expected.pairs.join("|"));
}
}

package More {
Expand Down
9 changes: 7 additions & 2 deletions src/main/scala/org/moe/ast/AST.scala
Expand Up @@ -116,8 +116,13 @@ case class IfStruct (

case class IfNode(if_node: IfStruct) extends AST

case class UnlessNode(unless_condition: AST, unless_body: AST) extends AST
case class UnlessElseNode(unless_condition: AST, unless_body: AST, else_body: AST) extends AST
case class UnlessStruct(
var condition: AST,
var body: AST,
var else_node: Option[IfStruct] = None
) extends AST

case class UnlessNode(unless_node: UnlessStruct) extends AST

case class TryNode(
body: AST,
Expand Down
16 changes: 2 additions & 14 deletions src/main/scala/org/moe/ast/Serializer.scala
Expand Up @@ -374,23 +374,11 @@ object Serializer {
)
)

case UnlessNode(unless_condition, unless_body) => JSONObject(
case UnlessNode(unless_node) => JSONObject(
Map(
"UnlessNode" -> JSONObject(
Map(
"unless_condition" -> toJSON(unless_condition),
"unless_body" -> toJSON(unless_body)
)
)
)
)
case UnlessElseNode(unless_condition, unless_body, else_body) => JSONObject(
Map(
"UnlessElseNode" -> JSONObject(
Map(
"unless_condition" -> toJSON(unless_condition),
"unless_body" -> toJSON(unless_body),
"else_body" -> toJSON(else_body)
"unless_node" -> toJSON(unless_node)
)
)
)
Expand Down
31 changes: 9 additions & 22 deletions src/main/scala/org/moe/interpreter/guts/Statements.scala
Expand Up @@ -52,28 +52,15 @@ object Statements extends Utils {
r.NativeObjects.getUndef
}
}

case (env, UnlessNode(unless_condition, unless_body)) => {
i.evaluate(env,
UnlessElseNode(
unless_condition,
unless_body,
UndefLiteralNode()
)
)
}
case (env, UnlessElseNode(unless_condition, unless_body, else_body)) => {
var if_node = new IfStruct(
PrefixUnaryOpNode(unless_condition, "!"),
unless_body,
Some(
new IfStruct(
BooleanLiteralNode(true),
else_body
)
)
)
i.evaluate(env, IfNode(if_node))

case (env, UnlessNode(unless_node)) => {
if (i.evaluate(env, unless_node.condition).isFalse) {
i.evaluate(env, unless_node.body)
} else if (unless_node.else_node.isDefined) {
i.evaluate(env, IfNode(unless_node.else_node.get))
} else {
r.NativeObjects.getUndef
}
}

case (env, TryNode(body, catch_nodes, finally_nodes)) => stub
Expand Down
10 changes: 2 additions & 8 deletions src/main/scala/org/moe/interpreter/guts/Utils.scala
Expand Up @@ -108,14 +108,8 @@ trait Utils {
walkAST(if_node, callback)
}

case UnlessNode(unless_condition, unless_body) => {
walkAST(unless_condition, callback)
walkAST(unless_body, callback)
}
case UnlessElseNode(unless_condition, unless_body, else_body) => {
walkAST(unless_condition, callback)
walkAST(unless_body, callback)
walkAST(else_body, callback)
case UnlessNode(unless_node) => {
walkAST(unless_node, callback)
}

case TryNode(body, catch_nodes, finally_nodes) => {
Expand Down
26 changes: 22 additions & 4 deletions src/main/scala/org/moe/parser/MoeProductions.scala
Expand Up @@ -296,7 +296,7 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse
blockStatement
| declarationStatement
| terminatedStatement
| simpleStatement
| statement
| scopeBlock
)) ~ opt(statement) ^^ {
case stmts ~ Some(lastStmt) => StatementsNode(stmts ++ List(lastStmt))
Expand Down Expand Up @@ -406,6 +406,11 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse
case if_cond ~ if_body ~ Some(_else) => IfNode(new IfStruct(if_cond,if_body, Some(_else)))
}

def unlessElseBlock: Parser[AST] = "unless" ~> ("(" ~> expression <~ ")") ~ block ~ (elsifBlock | elseBlock).? ^^ {
case unless_cond ~ unless_body ~ None => UnlessNode(new UnlessStruct(unless_cond, unless_body))
case unless_cond ~ unless_body ~ Some(_else) => UnlessNode(new UnlessStruct(unless_cond, unless_body, Some(_else)))
}

def whileBlock: Parser[WhileNode] = "while" ~> ("(" ~> expression <~ ")") ~ block ^^ {
case cond ~ body => WhileNode(cond, body)
}
Expand Down Expand Up @@ -445,6 +450,7 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse

lazy val blockStatement: Parser[AST] = (
ifElseBlock
| unlessElseBlock
| whileBlock
| untilBlock
| foreachBlock
Expand All @@ -470,9 +476,21 @@ trait MoeProductions extends MoeLiterals with JavaTokenParsers with PackratParse
| arrayElementAssignment
| hashElementAssignment
| expression
// | scopeBlock
)

lazy val statement: Parser[AST] = simpleStatement
lazy val terminatedStatement: Parser[AST] = simpleStatement <~ statementDelim
/**
* Statement modifiers
*/

lazy val modifiedStatement: Parser[AST] = simpleStatement ~ "if|unless|for(each)?|while|until".r ~ expression ^^ {
case stmt ~ "if" ~ cond => IfNode(new IfStruct(cond, StatementsNode(List(stmt))))
case stmt ~ "unless" ~ cond => UnlessNode(new UnlessStruct(cond, StatementsNode(List(stmt))))
case stmt ~ "foreach" ~ list => ForeachNode(VariableDeclarationNode("$_", UndefLiteralNode()), list, StatementsNode(List(stmt)))
case stmt ~ "for" ~ list => ForeachNode(VariableDeclarationNode("$_", UndefLiteralNode()), list, StatementsNode(List(stmt)))
case stmt ~ "while" ~ cond => WhileNode(cond, StatementsNode(List(stmt)))
case stmt ~ "until" ~ cond => WhileNode(PrefixUnaryOpNode(cond, "!"), StatementsNode(List(stmt)))
}

lazy val statement: Parser[AST] = ( modifiedStatement | simpleStatement )
lazy val terminatedStatement: Parser[AST] = statement <~ statementDelim
}
32 changes: 20 additions & 12 deletions src/test/scala/org/moe/interpreter/UnlessNodeTestSuite.scala
Expand Up @@ -11,8 +11,10 @@ class UnlessNodeTestSuite extends FunSuite with InterpreterTestUtils {
val ast = wrapSimpleAST(
List(
UnlessNode(
BooleanLiteralNode( false ),
IntLiteralNode( 42 )
new UnlessStruct(
BooleanLiteralNode( false ),
IntLiteralNode( 42 )
)
)
)
)
Expand All @@ -24,8 +26,10 @@ class UnlessNodeTestSuite extends FunSuite with InterpreterTestUtils {
val ast = wrapSimpleAST(
List(
UnlessNode(
BooleanLiteralNode( true ),
IntLiteralNode( 42 )
new UnlessStruct(
BooleanLiteralNode( true ),
IntLiteralNode( 42 )
)
)
)
)
Expand All @@ -36,10 +40,12 @@ class UnlessNodeTestSuite extends FunSuite with InterpreterTestUtils {
test("... basic test with UnlessElse") {
val ast = wrapSimpleAST(
List(
UnlessElseNode(
BooleanLiteralNode( false ),
IntLiteralNode( 42 ),
IntLiteralNode( 21 )
UnlessNode(
new UnlessStruct(
BooleanLiteralNode( false ),
IntLiteralNode( 42 ),
Some(new IfStruct(BooleanLiteralNode(true), IntLiteralNode(21)))
)
)
)
)
Expand All @@ -50,10 +56,12 @@ class UnlessNodeTestSuite extends FunSuite with InterpreterTestUtils {
test("... basic (true) test with UnlessElse") {
val ast = wrapSimpleAST(
List(
UnlessElseNode(
BooleanLiteralNode( true ),
IntLiteralNode( 42 ),
IntLiteralNode( 21 )
UnlessNode(
new UnlessStruct(
BooleanLiteralNode( true ),
IntLiteralNode( 42 ),
Some(new IfStruct(BooleanLiteralNode(true), IntLiteralNode(21)))
)
)
)
)
Expand Down
14 changes: 13 additions & 1 deletion t/006-statements/001-if.t
Expand Up @@ -24,4 +24,16 @@ use Test::More;
is($r, 30, '... got the expected value');
}

done_testing();
{
my $r = eval("10 if true");
ok(not($!.defined), '... the modifier statement worked correctly');
is($r, 10, '... got the expected value');
}

{
my $r = eval("my $a = 0; $a = $a + 1 if $a < 1; $a");
ok(not($!.defined), '... the modifier statement worked correctly');
is($r, 1, '... got the expected value');
}

done_testing();
22 changes: 21 additions & 1 deletion t/006-statements/002-for.t
Expand Up @@ -13,4 +13,24 @@ use Test::More;
is($r, 10, '... got the expected value');
}

done_testing();
{
my $r = eval(
"my $a = 0;" ~
"$a = $a + 1 for 1..5;" ~
"$a"
);
ok(not($!.defined), '... the modifier statement with range worked correctly');
is($r, 5, '... got the expected value');
}

{
my $r = eval(
"my $a = 0;" ~
"$a = $a + $_ for [1,2,3];" ~
"$a"
);
ok(not($!.defined), '... the modifier statement with list worked correctly');
is($r, 6, '... got the expected value');
}

done_testing();
22 changes: 21 additions & 1 deletion t/006-statements/003-foreach.t
Expand Up @@ -25,4 +25,24 @@ use Test::More;
is($r, 55, '... got the expected value');
}

done_testing();
{
my $r = eval(
"my $a = 0;" ~
"$a = $a + 1 foreach 1..5;" ~
"$a"
);
ok(not($!.defined), '... the modifier statement with range worked correctly');
is($r, 5, '... got the expected value');
}

{
my $r = eval(
"my $a = 0;" ~
"$a = $a + $_ foreach [1,2,3];" ~
"$a"
);
ok(not($!.defined), '... the modifier statement with list worked correctly');
is($r, 6, '... got the expected value');
}

done_testing();
45 changes: 45 additions & 0 deletions t/006-statements/004-unless.t
@@ -0,0 +1,45 @@
use Test::More;

{
my $r = eval("unless (false) { 10 }");
ok(not($!.defined), '... the statement worked correctly');
is($r, 10, '... got the expected value');
}

{
my $r = eval("unless (true) { 10 } else { 20 }");
ok(not($!.defined), '... the statement worked correctly');
is($r, 20, '... got the expected value');
}

{
my $r = eval("unless (false) { 10 } elsif (true) { 20 }");
ok(not($!.defined), '... the statement worked correctly');
is($r, 10, '... got the expected value');
}

{
my $r = eval("unless (true) { 10 } elsif (true) { 20 }");
ok(not($!.defined), '... the statement worked correctly');
is($r, 20, '... got the expected value');
}

{
my $r = eval("unless (true) { 10 } elsif (false) { 20 } else { 30 }");
ok(not($!.defined), '... the statement worked correctly');
is($r, 30, '... got the expected value');
}

{
my $r = eval("10 unless false");
ok(not($!.defined), '... the modifier statement worked correctly');
is($r, 10, '... got the expected value');
}

{
my $r = eval("my $a = 0; $a = $a + 1 unless $a > 0; $a");
ok(not($!.defined), '... the modifier statement worked correctly');
is($r, 1, '... got the expected value');
}

done_testing();
25 changes: 25 additions & 0 deletions t/006-statements/005-while.t
@@ -0,0 +1,25 @@
use Test::More;

{
my $r = eval(
"my $x = 0;" ~
"while ($x < 10) {" ~
" $x = $x + 1;" ~
"}" ~
"$x"
);
ok(not($!.defined), '... the statement worked correctly');
is($r, 10, '... got the expected value');
}

{
my $r = eval(
"my $a = 0;" ~
"$a = $a + 1 while $a < 5;" ~
"$a"
);
ok(not($!.defined), '... the modifier statement worked correctly');
is($r, 5, '... got the expected value');
}

done_testing();

0 comments on commit b575655

Please sign in to comment.