Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #72 from MoeOrganization/prakashk/logical-eq-rel-ops
More operators for ints/strings (take 2)
  • Loading branch information
Stevan Little committed Mar 20, 2013
2 parents fe43f09 + 34e680e commit f145d21
Show file tree
Hide file tree
Showing 15 changed files with 485 additions and 19 deletions.
1 change: 1 addition & 0 deletions src/main/scala/org/moe/ast/AST.scala
Expand Up @@ -52,6 +52,7 @@ case class PostfixUnaryOpNode(rhs: AST, operator: String) extends AST
// binary operators

case class BinaryOpNode(lhs: AST, operator: String, rhs: AST) extends AST
case class ShortCircuitBinaryOpNode(lhs: AST, operator: String, rhs: AST) extends AST

// value lookup, assignment and declaration

Expand Down
12 changes: 12 additions & 0 deletions src/main/scala/org/moe/ast/Serializer.scala
Expand Up @@ -75,6 +75,18 @@ object Serializer {
)
)

case ShortCircuitBinaryOpNode(lhs, operator, rhs) => JSONObject(
Map(
"ShortCircuitBinaryOpNode" -> JSONObject(
Map(
"lhs" -> toJSON(lhs),
"operator" -> operator,
"rhs" -> toJSON(rhs)
)
)
)
)

case ClassAccessNode(name) => JSONObject(Map("ClassAccessNode" -> name))

case ClassDeclarationNode(name, superclass, body) => JSONObject(
Expand Down
16 changes: 16 additions & 0 deletions src/main/scala/org/moe/interpreter/Interpreter.scala
Expand Up @@ -174,6 +174,22 @@ class Interpreter {
)
}

// short circuit binary operators
// rhs is not evaluated, unless it is necessary

case ShortCircuitBinaryOpNode(lhs: AST, operator: String, rhs: AST) => {
val receiver = eval(runtime, env, lhs)
val arg = new MoeLazyEval(this, runtime, env, rhs)
receiver.callMethod(
receiver.getAssociatedClass.getOrElse(
throw new MoeErrors.ClassNotFound(receiver.toString)
).getMethod("infix:<" + operator + ">").getOrElse(
throw new MoeErrors.MethodNotFound("method infix:<" + operator + "> missing in class " + receiver.getClassName)
),
List(arg)
)
}

// value lookup, assignment and declaration

case ClassAccessNode(name) => {
Expand Down
50 changes: 46 additions & 4 deletions src/main/scala/org/moe/parser/Expressions.scala
Expand Up @@ -14,42 +14,83 @@ trait Expressions extends Literals with JavaTokenParsers with PackratParsers {
(namespacedIdentifier <~ "{") ~
(expression <~ "}")

lazy val expression: PackratParser[AST] = bitOrOp
lazy val expression: PackratParser[AST] = logicalOrOp

// This is what I want
// def binOpResult = { case left ~ op ~ right => MethodCallNode(left, op, List(right)) }
// lazy val addOp: PackratParser[AST] = addOp ~ "[-+]".r ~ mulOp ^^ binOpResult | mulOp
// lazy val mulOp: PackratParser[AST] = mulOp ~ "[*/]".r ~ simpleExpression ^^ binOpResult | simpleExpression

// TODO: left or xor
// TODO: left and
// TODO: right not
// TODO: nonassoc list operators (rightward)
// TODO: left , =>
// TODO: right = += -= *= etc.
// TODO: right ?:


// left || TODO: //
lazy val logicalOrOp: PackratParser[AST] = logicalOrOp ~ """\|\||//""".r ~ logicalAndOp ^^ {
case left ~ op ~ right => ShortCircuitBinaryOpNode(left, op, right)
} | logicalAndOp

// left &&
lazy val logicalAndOp: PackratParser[AST] = logicalAndOp ~ "&&" ~ bitOrOp ^^ {
case left ~ op ~ right => ShortCircuitBinaryOpNode(left, op, right)
} | bitOrOp

// left | ^
lazy val bitOrOp: PackratParser[AST] = bitOrOp ~ "[|^]".r ~ bitAndOp ^^ {
case left ~ op ~ right => BinaryOpNode(left, op, right)
} | bitAndOp

lazy val bitAndOp: PackratParser[AST] = bitAndOp ~ "&" ~ relOp ^^ {
// left &
lazy val bitAndOp: PackratParser[AST] = bitAndOp ~ "&" ~ eqOp ^^ {
case left ~ op ~ right => BinaryOpNode(left, op, right)
} | eqOp

// nonassoc == != eq ne cmp ~~
lazy val eqOp: PackratParser[AST] = eqOp ~ "[!=]=|<=>|eq|ne|cmp".r ~ relOp ^^ {
case left ~ op ~ right => BinaryOpNode(left, op, right)
} | relOp

lazy val relOp: PackratParser[AST] = relOp ~ "[<>]=?|[!=]=".r ~ addOp ^^ {
// nonassoc < > <= >= lt gt le ge
lazy val relOp: PackratParser[AST] = relOp ~ "[<>]=?|lt|gt|le|ge".r ~ addOp ^^ {
case left ~ op ~ right => BinaryOpNode(left, op, right)
} | addOp

// TODO: nonassoc named unary operators
// TODO: left << >>

// left + - .
lazy val addOp: PackratParser[AST] = addOp ~ "[-+.]".r ~ mulOp ^^ {
case left ~ op ~ right => BinaryOpNode(left, op, right)
} | mulOp

// left * / % x
lazy val mulOp: PackratParser[AST] = mulOp ~ "[*/%x]".r ~ expOp ^^ {
case left ~ op ~ right => BinaryOpNode(left, op, right)
} | expOp

// TODO: left =~ !~
// TODO: right ! ~ \ and unary + and -

// This one is right-recursive (associative) instead of left
// right **
lazy val expOp: PackratParser[AST] = applyOp ~ "**" ~ expOp ^^ {
case left ~ op ~ right => BinaryOpNode(left, op, right)
} | applyOp

// TODO: nonassoc ++ --

// left ->
lazy val applyOp: PackratParser[AST] = (applyOp <~ "->") ~ namespacedIdentifier ^^ {
case invocant ~ method => MethodCallNode(invocant, method, List())
} | simpleExpression

// TODO: left terms and list operators (leftward)

lazy val simpleExpression: PackratParser[AST] = (
arrayIndex
| hashIndex
Expand All @@ -64,9 +105,10 @@ trait Expressions extends Literals with JavaTokenParsers with PackratParsers {
)

def expressionParens: Parser[AST] = "(" ~> expression <~ ")"
def signedExpressionParens: PackratParser[AST] = "[-+]".r ~ expressionParens ^^ {
def signedExpressionParens: PackratParser[AST] = "[-+!]".r ~ expressionParens ^^ {
case "+" ~ expr => expr
case "-" ~ expr => PrefixUnaryOpNode(expr, "-")
case "!" ~ expr => PrefixUnaryOpNode(expr, "!")
}

// List stuff
Expand Down
22 changes: 22 additions & 0 deletions src/main/scala/org/moe/runtime/MoeLazyEval.scala
@@ -0,0 +1,22 @@
package org.moe.runtime

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

/**
* MoeLazyEval: Class for wrapping an AST node whose evaluation is deferred.
*
*/

class MoeLazyEval (
interpreter: Interpreter,
runtime: MoeRuntime,
env: MoeEnvironment,
node: AST
) extends MoeObject {
def eval = {
println("lazy eval - " + Serializer.toJSONPretty(node))
interpreter.eval(runtime, env, node)
}
}
16 changes: 14 additions & 2 deletions src/main/scala/org/moe/runtime/builtins/AnyClass.scala
Expand Up @@ -33,7 +33,13 @@ object AnyClass {
env,
{ (e) =>
val inv = e.getCurrentInvocant.get
if (inv.isTrue) e.get("$other").get else inv
if (inv.isFalse)
inv
else
e.get("$other").get match {
case deferred: MoeLazyEval => deferred.eval
case other: MoeObject => other
}
}
)
)
Expand All @@ -45,7 +51,13 @@ object AnyClass {
env,
{ (e) =>
val inv = e.getCurrentInvocant.get
if (inv.isTrue) inv else e.get("$other").get
if (inv.isTrue)
inv
else
e.get("$other").get match {
case deferred: MoeLazyEval => deferred.eval
case other: MoeObject => other
}
}
)
)
Expand Down
14 changes: 14 additions & 0 deletions src/main/scala/org/moe/runtime/builtins/BoolClass.scala
@@ -1,6 +1,7 @@
package org.moe.runtime.builtins

import org.moe.runtime._
import org.moe.runtime.nativeobjects._

/**
* setup class Bool
Expand All @@ -13,8 +14,21 @@ object BoolClass {
throw new MoeErrors.MoeStartupError("Could not find class Bool")
)

def self(e: MoeEnvironment): MoeBoolObject = e.getCurrentInvocant.get.asInstanceOf[MoeBoolObject]

// MRO: Bool, Scalar, Any, Object

import r.NativeObjects._

boolClass.addMethod(
new MoeMethod(
"prefix:<+>",
new MoeSignature(),
env,
(e) => getInt(self(e).unboxToInt.getOrElse(0))
)
)

/**
* List of Methods to support:
*
Expand Down
11 changes: 11 additions & 0 deletions src/main/scala/org/moe/runtime/builtins/IntClass.scala
Expand Up @@ -180,6 +180,8 @@ object IntClass {
)
)

// equality operators

intClass.addMethod(
new MoeMethod(
"infix:<==>",
Expand All @@ -198,6 +200,15 @@ object IntClass {
)
)

intClass.addMethod(
new MoeMethod(
"infix:<<=>>",
new MoeSignature(List(new MoeParameter("$other"))),
env,
(e) => e.getCurrentInvocant.get.asInstanceOf[MoeIntObject].compare_to(r, e.get("$other").get)
)
)

// bitwise operators

intClass.addMethod(
Expand Down
67 changes: 66 additions & 1 deletion src/main/scala/org/moe/runtime/builtins/StrClass.scala
Expand Up @@ -47,7 +47,72 @@ object StrClass {
)
)

// operators
// relational operators

strClass.addMethod(
new MoeMethod(
"infix:<lt>",
new MoeSignature(List(new MoeParameter("$other"))),
env,
(e) => e.getCurrentInvocant.get.asInstanceOf[MoeStrObject].less_than(r, e.get("$other").get)
)
)

strClass.addMethod(
new MoeMethod(
"infix:<gt>",
new MoeSignature(List(new MoeParameter("$other"))),
env,
(e) => e.getCurrentInvocant.get.asInstanceOf[MoeStrObject].greater_than(r, e.get("$other").get)
)
)

strClass.addMethod(
new MoeMethod(
"infix:<le>",
new MoeSignature(List(new MoeParameter("$other"))),
env,
(e) => e.getCurrentInvocant.get.asInstanceOf[MoeStrObject].less_than_or_equal_to(r, e.get("$other").get)
)
)

strClass.addMethod(
new MoeMethod(
"infix:<ge>",
new MoeSignature(List(new MoeParameter("$other"))),
env,
(e) => e.getCurrentInvocant.get.asInstanceOf[MoeStrObject].greater_than_or_equal_to(r, e.get("$other").get)
)
)

// equality operators

strClass.addMethod(
new MoeMethod(
"infix:<eq>",
new MoeSignature(List(new MoeParameter("$other"))),
env,
(e) => e.getCurrentInvocant.get.asInstanceOf[MoeStrObject].equal_to(r, e.get("$other").get)
)
)

strClass.addMethod(
new MoeMethod(
"infix:<ne>",
new MoeSignature(List(new MoeParameter("$other"))),
env,
(e) => e.getCurrentInvocant.get.asInstanceOf[MoeStrObject].not_equal_to(r, e.get("$other").get)
)
)

strClass.addMethod(
new MoeMethod(
"infix:<cmp>",
new MoeSignature(List(new MoeParameter("$other"))),
env,
(e) => e.getCurrentInvocant.get.asInstanceOf[MoeStrObject].compare_to(r, e.get("$other").get)
)
)

// methods

Expand Down
11 changes: 9 additions & 2 deletions src/main/scala/org/moe/runtime/nativeobjects/MoeBoolObject.scala
@@ -1,15 +1,22 @@
package org.moe.runtime.nativeobjects

import org.moe.runtime._
import org.moe.runtime.nativeobjects._

import scala.util.{Try, Success, Failure}

class MoeBoolObject(
v: Boolean, klass : Option[MoeClass] = None
) extends MoeNativeObject[Boolean](v, klass) {

// MoeObject overrides
// runtime methods

def toInt: Int = if (getNativeValue) 1 else 0

override def isFalse: Boolean = getNativeValue == false
override def toString: String = if (getNativeValue) "true" else "false"
}

// unboxing

override def unboxToInt: Try[Int] = Try(toInt)
}
Expand Up @@ -64,6 +64,12 @@ class MoeIntObject(
case _ => throw new MoeErrors.UnexpectedType(other.toString)
}

def compare_to (r: MoeRuntime, other: MoeObject): MoeIntObject = other match {
case i: MoeIntObject => r.NativeObjects.getInt(getNativeValue compareTo i.unboxToInt.get)
case f: MoeNumObject => r.NativeObjects.getInt(unboxToDouble.get compareTo f.unboxToDouble.get)
case _ => throw new MoeErrors.UnexpectedType(other.toString)
}

// comparison

def less_than (r: MoeRuntime, other: MoeObject): MoeBoolObject = other match {
Expand Down

0 comments on commit f145d21

Please sign in to comment.