Navigation Menu

Skip to content

Commit

Permalink
WIP/EXPERIMENTAL: Attempt to expose class instance to runtime
Browse files Browse the repository at this point in the history
This is just enough to make tests pass. May not be the right approach
but just seeing where this can go.
  • Loading branch information
jasonmay committed Feb 9, 2013
1 parent c68bedf commit ab1b44b
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 59 deletions.
20 changes: 17 additions & 3 deletions src/main/scala/org/moe/interpreter/Interpreter.scala
Expand Up @@ -206,6 +206,9 @@ class Interpreter {

val superclass_class: Option[MoeClass] = superclass.map(
pkg.getClass(_).getOrElse(
// FIXME error for class instance
throw new MoeErrors.ClassNotFound(superclass.getOrElse(""))
).getAssociatedClass.getOrElse(
throw new MoeErrors.ClassNotFound(superclass.getOrElse(""))
)
)
Expand All @@ -214,7 +217,7 @@ class Interpreter {
name, None, None, superclass_class
)

pkg.addClass(klass)
pkg.addClass(klass.newInstance)

scoped { klass_env =>
klass_env.setCurrentClass(klass)
Expand Down Expand Up @@ -326,8 +329,19 @@ class Interpreter {
}

// operations

case MethodCallNode(invocant, method_name, args) => stub
case MethodCallNode(invocant, method_name, args) => {
val invocant_object = eval(runtime, env, invocant)
invocant_object match {
case obj: MoeObject =>
val meth = obj.getAssociatedClass.getOrElse(
throw new MoeErrors.ClassNotFound("__CLASS__")
).getMethod(method_name).getOrElse(
throw new MoeErrors.MethodNotFound(method_name)
)
meth.execute(invocant_object, args.map(eval(runtime, env, _)))
case _ => throw new MoeErrors.MoeException("Object expected")
}
}
case SubroutineCallNode(function_name, args) => {
val sub = env.getCurrentPackage.getOrElse(
throw new MoeErrors.PackageNotFound("__PACKAGE__")
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/org/moe/runtime/MoeClass.scala
Expand Up @@ -103,7 +103,7 @@ class MoeClass(
/**
* Creates a new instance of this class.
*/
def newInstance: MoeObject = new MoeOpaque(Some(this))
def newInstance: MoeOpaque = new MoeOpaque(Some(this))

// Methods ...

Expand Down
5 changes: 3 additions & 2 deletions src/main/scala/org/moe/runtime/MoeObject.scala
Expand Up @@ -15,7 +15,8 @@ class MoeObject(
def getID: Int = id

/**
* Returns the class associted with this object, if there is one.
* Returns the class associted with this object.
* There should always be one after the bootstrap
*/
def getAssociatedClass: Option[MoeClass] = associatedClass

Expand Down Expand Up @@ -73,4 +74,4 @@ class MoeObject(
override def toString: String = {
"{ #instance(" + id + ")" + associatedClass.map({ k => k.toString }).getOrElse("") + " }"
}
}
}
11 changes: 7 additions & 4 deletions src/main/scala/org/moe/runtime/MoePackage.scala
Expand Up @@ -15,7 +15,7 @@ class MoePackage(
) extends MoeObject {

private var parent: Option[MoePackage] = None
private val klasses: Map[String, MoeClass] = new HashMap[String, MoeClass]()
private val klasses: Map[String, MoeOpaque] = new HashMap[String, MoeOpaque]()
private val subs: Map[String, MoeSubroutine] = new HashMap[String, MoeSubroutine]()
private val sub_packages: Map[String, MoePackage] = new HashMap[String, MoePackage]()

Expand Down Expand Up @@ -83,16 +83,19 @@ class MoePackage(
*
* @param klass The class
*/
def addClass(klass: MoeClass): Unit = {
klasses += (klass.getName -> klass)
def addClass(klass: MoeOpaque): Unit = {
val klass_klass = klass.getAssociatedClass.getOrElse(
new MoeClass("Unknown") // FIXME extract from runtime somehow?
)
klasses += (klass_klass.getName -> klass)
}

/**
* returns the class with the specified name
*
* @param name The name of the class to return
*/
def getClass(name: String): Option[MoeClass] = klasses.get(name)
def getClass(name: String): Option[MoeOpaque] = klasses.get(name)

/**
* checks if a class with the specified name is in package
Expand Down
93 changes: 62 additions & 31 deletions src/main/scala/org/moe/runtime/MoeRuntime.scala
Expand Up @@ -16,6 +16,12 @@ class MoeRuntime (
private val objectClass = new MoeClass("Object", Some(VERSION), Some(AUTHORITY))
private val classClass = new MoeClass("Class", Some(VERSION), Some(AUTHORITY), Some(objectClass))

private val unknownClass = new MoeClass("Unknown", Some(VERSION), Some(AUTHORITY), Some(objectClass))

private val classInstance = classClass.newInstance
private val objectInstance = objectClass.newInstance
private val unknownInstance = unknownClass.newInstance

def getVersion = VERSION
def getAuthority = AUTHORITY

Expand All @@ -29,16 +35,40 @@ class MoeRuntime (
def getObjectClass = objectClass
def getClassClass = classClass

def getObjectInstance = objectInstance
def getClassInstance = classInstance
def getUnknownInstance = unknownInstance

implicit def unboxClass(c: Option[MoeClass]) = c.getOrElse(unknownClass)
implicit def unboxInstance(c: Option[MoeOpaque]) = c.getOrElse(unknownInstance)

def bootstrap() : Unit = {
if (!is_bootstrapped) {

//val unboxInstance: (Option[MoeOpaque]) => MoeOpaque = { _.getOrElse(unknownInstance) }
//val unboxClass: (Option[MoeClass]) => MoeClass = { _.getOrElse(unknownClass) }

// setup the root package
rootEnv.setCurrentPackage(rootPackage) // bind it to env

// set up the core package
rootPackage.addSubPackage(corePackage) // bind it to the root
corePackage.getEnv.setCurrentPackage(corePackage) // bind it to the env

// bootstrap builtin methods
classClass.addMethod(
new MoeMethod(
"new",
{ (invocant, _) => invocant.getAssociatedClass.newInstance }
)
)
classClass.addMethod(
new MoeMethod(
"getClass", // XXX
{ (invocant, _) => invocant.getAssociatedClass }
)
)

// tie the knot
objectClass.setAssociatedClass(Some(classClass)) // Object is a class
classClass.setAssociatedClass(Some(classClass)) // Class is a class
Expand All @@ -57,12 +87,12 @@ class MoeRuntime (
*/

val anyClass = new MoeClass("Any", Some(VERSION), Some(AUTHORITY), Some(objectClass))

val scalarClass = new MoeClass("Scalar", Some(VERSION), Some(AUTHORITY), Some(anyClass))
val arrayClass = new MoeClass("Array", Some(VERSION), Some(AUTHORITY), Some(anyClass))
val hashClass = new MoeClass("Hash", Some(VERSION), Some(AUTHORITY), Some(anyClass))
val pairClass = new MoeClass("Pair", Some(VERSION), Some(AUTHORITY), Some(anyClass))

val nullClass = new MoeClass("Null", Some(VERSION), Some(AUTHORITY), Some(scalarClass))
val boolClass = new MoeClass("Bool", Some(VERSION), Some(AUTHORITY), Some(scalarClass))
val strClass = new MoeClass("Str", Some(VERSION), Some(AUTHORITY), Some(scalarClass))
Expand All @@ -71,21 +101,21 @@ class MoeRuntime (
val exceptionClass = new MoeClass("Exception", Some(VERSION), Some(AUTHORITY), Some(scalarClass))

// add all these classes to the corePackage
corePackage.addClass(objectClass)
corePackage.addClass(classClass)

corePackage.addClass(anyClass)
corePackage.addClass(scalarClass)
corePackage.addClass(arrayClass)
corePackage.addClass(hashClass)
corePackage.addClass(pairClass)

corePackage.addClass(nullClass)
corePackage.addClass(boolClass)
corePackage.addClass(strClass)
corePackage.addClass(intClass)
corePackage.addClass(numClass)
corePackage.addClass(exceptionClass)
corePackage.addClass(objectClass.newInstance)
corePackage.addClass(classClass.newInstance)

corePackage.addClass(anyClass.newInstance)
corePackage.addClass(scalarClass.newInstance)
corePackage.addClass(arrayClass.newInstance)
corePackage.addClass(hashClass.newInstance)
corePackage.addClass(pairClass.newInstance)

corePackage.addClass(nullClass.newInstance)
corePackage.addClass(boolClass.newInstance)
corePackage.addClass(strClass.newInstance)
corePackage.addClass(intClass.newInstance)
corePackage.addClass(numClass.newInstance)
corePackage.addClass(exceptionClass.newInstance)

/*
TODO:
Expand All @@ -97,31 +127,32 @@ class MoeRuntime (
}
}

def getCoreClassFor (name: String): Option[MoeClass] = corePackage.getClass(name)
def getCoreClassFor (name: String): Option[MoeOpaque] = corePackage.getClass(name)
def ensureCoreClassFor (name: String): MoeOpaque = corePackage.getClass(name).getOrElse(unknownClass.newInstance)

object NativeObjects {

private lazy val Undef = new MoeNullObject(getCoreClassFor("Null"))
private lazy val True = new MoeBooleanObject(true, getCoreClassFor("Bool"))
private lazy val False = new MoeBooleanObject(false, getCoreClassFor("Bool"))
private lazy val Undef = new MoeNullObject(ensureCoreClassFor("Null").getAssociatedClass)
private lazy val True = new MoeBooleanObject(true, ensureCoreClassFor("Bool").getAssociatedClass)
private lazy val False = new MoeBooleanObject(false, ensureCoreClassFor("Bool").getAssociatedClass)

def getUndef = Undef
def getTrue = True
def getFalse = False

def getInt (value: Int) = new MoeIntObject(value, getCoreClassFor("Int"))
def getFloat (value: Double) = new MoeFloatObject(value, getCoreClassFor("Num"))
def getString (value: String) = new MoeStringObject(value, getCoreClassFor("Str"))
def getInt (value: Int) = new MoeIntObject(value, ensureCoreClassFor("Int").getAssociatedClass)
def getFloat (value: Double) = new MoeFloatObject(value, ensureCoreClassFor("Num").getAssociatedClass)
def getString (value: String) = new MoeStringObject(value, ensureCoreClassFor("Str").getAssociatedClass)
def getBool (value: Boolean) = if (value) { True } else { False }

def getHash (value: Map[String, MoeObject]) = new MoeHashObject(value, getCoreClassFor("Hash"))
def getHash () = new MoeHashObject(Map(), getCoreClassFor("Hash"))
def getArray (value: List[MoeObject]) = new MoeArrayObject(value, getCoreClassFor("Array"))
def getArray () = new MoeArrayObject(List(), getCoreClassFor("Array"))
def getHash (value: Map[String, MoeObject]) = new MoeHashObject(value, ensureCoreClassFor("Hash").getAssociatedClass)
def getHash () = new MoeHashObject(Map(), ensureCoreClassFor("Hash").getAssociatedClass)
def getArray (value: List[MoeObject]) = new MoeArrayObject(value, ensureCoreClassFor("Array").getAssociatedClass)
def getArray () = new MoeArrayObject(List(), ensureCoreClassFor("Array").getAssociatedClass)
def getPair (value: (MoeObject, MoeObject)) = new MoePairObject(
(value._1.asInstanceOf[MoeStringObject].getNativeValue, value._2),
getCoreClassFor("Pair")
(value._1.asInstanceOf[MoeStringObject].getNativeValue, value._2),
ensureCoreClassFor("Pair").getAssociatedClass
)
}

}
}
37 changes: 21 additions & 16 deletions src/test/scala/org/moe/interpreter/ClassMatchers.scala
Expand Up @@ -21,17 +21,20 @@ import org.scalatest.matchers._
}
def haveClass(klass: String) = new PackageHasClassMatcher(klass)

class ClassExtendsClassMatcher[A](superclass: A) extends Matcher[MoeClass] {
def apply(left: MoeClass) = {
class ClassExtendsClassMatcher[A](superclass: A) extends Matcher[MoeOpaque] {
def apply(left: MoeOpaque) = {
val klass = left.getAssociatedClass.getOrElse(throw new Exception("Missing class"))

val superclass_name = superclass match {
case c: MoeClass => c.getName
case Some(c: MoeClass) => c.getName
case s: String => s
}
val failure_msg = left.getName + " was not a class of " + superclass_name
val neg_failure_msg = left.getName + " was a class of " + superclass_name
val failure_msg = klass.getName + " was not a class of " + superclass_name
val neg_failure_msg = klass.getName + " was a class of " + superclass_name
val check = superclass match {
case c: MoeClass => left.isClassOf(c)
case s: String => left.isClassOf(s)
case c: MoeClass => klass.isClassOf(c)
case s: String => klass.isClassOf(s)
case _ => false
}
MatchResult(
Expand All @@ -47,11 +50,12 @@ import org.scalatest.matchers._
def extendClass(superclass: MoeClass) = new ClassExtendsClassMatcher[MoeClass](superclass)
def extendClass(superclass: String) = new ClassExtendsClassMatcher[String](superclass)

class ClassHasAttributeMatcher(attr: String) extends Matcher[MoeClass] {
def apply(left: MoeClass) = {
val failure_msg = left.getName + " did not have attribute " + attr
val neg_failure_msg = left.getName + " had attribute " + attr
val check = left.hasAttribute(attr)
class ClassHasAttributeMatcher(attr: String) extends Matcher[MoeOpaque] {
def apply(left: MoeOpaque) = {
val klass = left.getAssociatedClass.getOrElse(throw new Exception("Missing class"))
val failure_msg = klass.getName + " did not have attribute " + attr
val neg_failure_msg = klass.getName + " had attribute " + attr
val check = klass.hasAttribute(attr)
MatchResult(
check,
"Class " + failure_msg,
Expand All @@ -64,11 +68,12 @@ import org.scalatest.matchers._

def haveAttribute(attr: String) = new ClassHasAttributeMatcher(attr)

class ClassHasMethodMatcher(meth: String) extends Matcher[MoeClass] {
def apply(left: MoeClass) = {
val failure_msg = left.getName + " did not have method " + meth
val neg_failure_msg = left.getName + " had method " + meth
val check = left.hasMethod(meth)
class ClassHasMethodMatcher(meth: String) extends Matcher[MoeOpaque] {
def apply(left: MoeOpaque) = {
val klass = left.getAssociatedClass.getOrElse(throw new Exception("Missing class"))
val failure_msg = klass.getName + " did not have method " + meth
val neg_failure_msg = klass.getName + " had method " + meth
val check = klass.hasMethod(meth)
MatchResult(
check,
"Class " + failure_msg,
Expand Down
5 changes: 4 additions & 1 deletion src/test/scala/org/moe/interpreter/ClassNodeTestSuite.scala
Expand Up @@ -92,7 +92,10 @@ class ClassNodeTestSuite
)

point_class should haveAttribute("x")
point_class.getAttribute("x") match {
val point_class_class = point_class.getAssociatedClass.getOrElse(
throw new Exception("Class expected") // This has been tested
)
point_class_class.getAttribute("x") match {
case Some(attr) =>
attr.getDefault match {
case Some(attr) => attr.asInstanceOf[MoeIntObject].getNativeValue should equal (0)
Expand Down
2 changes: 1 addition & 1 deletion src/test/scala/org/moe/runtime/MoePackageTestSuite.scala
Expand Up @@ -23,7 +23,7 @@ class MoePackageTestSuite extends FunSuite with BeforeAndAfter {
}

test("... basic package w/ class") {
pkg.addClass(new MoeClass("Foo"))
pkg.addClass((new MoeClass("Foo")).newInstance)
assert(pkg.hasClass("Foo"))
}

Expand Down

0 comments on commit ab1b44b

Please sign in to comment.