Finished metadata
authorJavier Fernandez-Ivern <javier.fernandezivern@availity.com>
Mon, 26 Oct 2015 18:31:36 +0000 (13:31 -0500)
committerJavier Fernandez-Ivern <javier.fernandezivern@availity.com>
Mon, 26 Oct 2015 18:31:36 +0000 (13:31 -0500)
kotlin/src/mal/core.kt
kotlin/src/mal/stepA_mal.kt
kotlin/src/mal/types.kt

index 869ec1a..9d1a27a 100644 (file)
@@ -162,7 +162,7 @@ val ns = hashMapOf(
         })),
         Pair(MalSymbol("sequential?"), MalFunction({ a: ISeq -> if (a.nth(0) is ISeq) TRUE else FALSE })),
 
-        Pair(MalSymbol("meta"), MalFunction({ a: ISeq -> (a.first() as? MalFunction)?.metadata ?: NIL })),
+        Pair(MalSymbol("meta"), MalFunction({ a: ISeq -> a.first().metadata })),
         Pair(MalSymbol("conj"), MalFunction({ a: ISeq -> (a.first() as ISeq).conj(a.rest()) }))
 )
 
index dbf6349..3a5336a 100644 (file)
@@ -69,9 +69,9 @@ fun eval(_ast: MalType, _env: Env): MalType {
                     return eval(catchBody, catchEnv)
                 }
             } else if (first is MalSymbol && first.value == "with-meta") {
-                val function = eval(ast.nth(1), env) as MalFunction
-                function.metadata = eval(ast.nth(2), env)
-                return function
+                val obj = eval(ast.nth(1), env)
+                val metadata = eval(ast.nth(2), env)
+                return obj.with_meta(metadata)
             } else {
                 val evaluated = eval_ast(ast, env) as ISeq
                 val firstEval = evaluated.first()
index ca81093..5ddfe8a 100644 (file)
@@ -3,22 +3,46 @@ package mal
 import java.util.*
 
 // TODO clean up exception hierarchy
-open class MalException(message: String?) : Exception(message), MalType { }
+open class MalException(message: String?) : Exception(message), MalType {
+    override var metadata: MalType = NIL
+    override fun with_meta(meta: MalType): MalType {
+        val exception = MalException(message)
+        exception.metadata = meta
+        return exception
+    }
+}
 class MalContinue() : MalException("continue") { }
 class MalReaderException(message: String) : MalException(message) { }
 class MalPrinterException(message: String) : MalException(message) { }
-
-class MalCoreException(message: String, val value: MalType) : MalException(message) // TODO rename
+class MalCoreException(message: String, val value: MalType) : MalException(message) { // TODO rename
+    override fun with_meta(meta: MalType): MalType {
+        val exception = MalCoreException(message as String, value)
+        exception.metadata = meta
+        return exception
+    }
+}
 
 interface MalType {
+    var metadata: MalType // TODO make immutable
+    fun with_meta(meta: MalType): MalType
 }
 
 open class MalConstant(val value: String) : MalType {
+    override var metadata: MalType = NIL
+
     override fun equals(other: Any?): Boolean = other is MalConstant && value.equals(other.value)
     override fun hashCode(): Int = value.hashCode()
+
+    override fun with_meta(meta: MalType): MalType {
+        val obj = MalConstant(value)
+        obj.metadata = meta
+        return obj
+    }
 }
 
 class MalInteger(val value: Int) : MalType {
+    override var metadata: MalType = NIL
+
     operator fun plus(a: MalInteger): MalInteger = MalInteger(value + a.value)
     operator fun minus(a: MalInteger): MalInteger = MalInteger(value - a.value)
     operator fun times(a: MalInteger): MalInteger = MalInteger(value * a.value)
@@ -26,15 +50,41 @@ class MalInteger(val value: Int) : MalType {
     operator fun compareTo(a: MalInteger): Int = value.compareTo(a.value)
 
     override fun equals(other: Any?): Boolean = other is MalInteger && value.equals(other.value)
+
+    override fun with_meta(meta: MalType): MalType {
+        val obj = MalInteger(value)
+        obj.metadata = meta
+        return obj
+    }
 }
 
 class MalSymbol(val value: String) : MalType {
+    override var metadata: MalType = NIL
+
     override fun equals(other: Any?): Boolean = other is MalSymbol && value.equals(other.value)
+
+    override fun with_meta(meta: MalType): MalType {
+        val obj = MalSymbol(value)
+        obj.metadata = meta
+        return obj
+    }
 }
 
-open class MalString(value: String) : MalConstant(value)
+open class MalString(value: String) : MalConstant(value) {
+    override fun with_meta(meta: MalType): MalType {
+        val obj = MalString(value)
+        obj.metadata = meta
+        return obj
+    }
+}
 
-class MalKeyword(value: String) : MalString("\u029E" + value)
+class MalKeyword(value: String) : MalString("\u029E" + value) {
+    override fun with_meta(meta: MalType): MalType {
+        val obj = MalKeyword(value)
+        obj.metadata = meta
+        return obj
+    }
+}
 
 interface ILambda : MalType {
     fun apply(seq: ISeq): MalType
@@ -43,12 +93,24 @@ interface ILambda : MalType {
 open class MalFunction(val lambda: (ISeq) -> MalType) : MalType, ILambda {
     // TODO make this stuff immutable?
     var is_macro: Boolean = false
-    var metadata: MalType = NIL
+    override var metadata: MalType = NIL
 
     override fun apply(seq: ISeq): MalType = lambda(seq)
+
+    override fun with_meta(meta: MalType): MalType {
+        val obj = MalFunction(lambda)
+        obj.metadata = meta
+        return obj
+    }
 }
 
-class MalFnFunction(val ast: MalType, val params: Sequence<MalSymbol>, val env: Env, lambda: (ISeq) -> MalType) : MalFunction(lambda)
+class MalFnFunction(val ast: MalType, val params: Sequence<MalSymbol>, val env: Env, lambda: (ISeq) -> MalType) : MalFunction(lambda) {
+    override fun with_meta(meta: MalType): MalType {
+        val obj = MalFnFunction(ast, params, env, lambda)
+        obj.metadata = meta
+        return obj
+    }
+}
 
 interface ISeq : MalType {
     fun seq(): Sequence<MalType>
@@ -65,6 +127,8 @@ interface IMutableSeq : ISeq {
 }
 
 class MalSequence(val elements : Sequence<MalType>) : MalType, ISeq {
+    override var metadata: MalType = NIL
+
     override fun seq(): Sequence<MalType> = elements
     override fun first(): MalType = elements.first()
     override fun rest(): ISeq = MalSequence(elements.drop(1))
@@ -74,9 +138,17 @@ class MalSequence(val elements : Sequence<MalType>) : MalType, ISeq {
             MalList(elements.toLinkedList().subList(fromIndex, toIndex))
 
     override fun conj(s: ISeq): ISeq = MalList(elements.toLinkedList()).conj(s)
+
+    override fun with_meta(meta: MalType): MalType {
+        val obj = MalSequence(elements)
+        obj.metadata = meta
+        return obj
+    }
 }
 
 class MalList(val elements: MutableList<MalType>) : MalType, IMutableSeq {
+    override var metadata: MalType = NIL
+
     constructor() : this(LinkedList<MalType>())
     constructor(s: ISeq) : this(s.seq().toLinkedList())
 
@@ -102,9 +174,17 @@ class MalList(val elements: MutableList<MalType>) : MalType, IMutableSeq {
         s.seq().forEach({ it -> list.addFirst(it) })
         return MalList(list)
     }
+
+    override fun with_meta(meta: MalType): MalType {
+        val obj = MalList(elements)
+        obj.metadata = meta
+        return obj
+    }
 }
 
 class MalVector(val elements: MutableList<MalType>) : MalType, IMutableSeq {
+    override var metadata: MalType = NIL
+
     constructor() : this(ArrayList<MalType>())
     constructor(s: ISeq) : this(s.seq().toArrayList())
 
@@ -126,9 +206,17 @@ class MalVector(val elements: MutableList<MalType>) : MalType, IMutableSeq {
             MalVector(elements.subList(fromIndex, toIndex))
 
     override fun conj(s: ISeq): ISeq = MalVector(elements.plus(s.seq()).toArrayList())
+
+    override fun with_meta(meta: MalType): MalType {
+        val obj = MalVector(elements)
+        obj.metadata = meta
+        return obj
+    }
 }
 
 class MalHashMap() : MalType {
+    override var metadata: MalType = NIL
+
     val elements = HashMap<MalString, MalType>()
 
     constructor(other: MalHashMap) : this() {
@@ -139,6 +227,12 @@ class MalHashMap() : MalType {
     fun dissoc_BANG(key: MalString) {
         elements.remove(key)
     }
+
+    override fun with_meta(meta: MalType): MalType {
+        val obj = MalHashMap(this)
+        obj.metadata = meta
+        return obj
+    }
 }
 
 // TODO add truthiness checking