Skip to content

Commit

Permalink
Implement mapToArray
Browse files Browse the repository at this point in the history
This function returns a map as an array
  • Loading branch information
lokedhs committed Dec 31, 2020
1 parent 5f70d35 commit 026fe6a
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 7 deletions.
6 changes: 3 additions & 3 deletions array/src/commonMain/kotlin/array/builtins/div_functions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ class SleepFunction : APLFunctionDescriptor {
override fun make(pos: Position) = SleepFunctionImpl(pos)
}

class TagCatch(val tag: APLValue, val data: APLValue) : RuntimeException()
class TagCatch(val tag: APLValue, val data: APLValue, pos: Position? = null) : APLEvalException(data.formatted(FormatStyle.PLAIN), pos)

class ThrowFunction : APLFunctionDescriptor {
class ThrowFunctionImpl(pos: Position) : NoAxisAPLFunction(pos) {
override fun eval1Arg(context: RuntimeContext, a: APLValue): APLValue {
val engine = context.engine
throw TagCatch(APLSymbol(engine.internSymbol("error", engine.coreNamespace)), a)
throwAPLException(TagCatch(APLSymbol(engine.internSymbol("error", engine.coreNamespace)), a, pos))
}

override fun eval2Arg(context: RuntimeContext, a: APLValue, b: APLValue): APLValue {
throw TagCatch(a, b)
throwAPLException(TagCatch(a, b, pos))
}
}

Expand Down
16 changes: 16 additions & 0 deletions array/src/commonMain/kotlin/array/builtins/map.kt
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,19 @@ class MapRemoveAPLFunction : APLFunctionDescriptor {

override fun make(pos: Position) = MapRemoveAPLFunctionImpl(pos)
}

class MapKeyValuesFunction : APLFunctionDescriptor {
class MapKeyValuesFunctionImpl(pos: Position) : NoAxisAPLFunction(pos) {
override fun eval1Arg(context: RuntimeContext, a: APLValue): APLValue {
val map = a.ensureMap(pos)
val content = ArrayList<APLValue>()
map.content.forEach { (key, value) ->
content.add(key.value)
content.add(value)
}
return APLArrayImpl(dimensionsOfSize(content.size / 2, 2), content.toTypedArray())
}
}

override fun make(pos: Position) = MapKeyValuesFunctionImpl(pos)
}
1 change: 1 addition & 0 deletions array/src/commonMain/kotlin/array/engine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ class Engine {
registerNativeFunction("mapGet", MapGetAPLFunction())
registerNativeFunction("mapPut", MapPutAPLFunction())
registerNativeFunction("mapRemove", MapRemoveAPLFunction())
registerNativeFunction("mapToArray", MapKeyValuesFunction())

// io functions
registerNativeFunction("print", PrintAPLFunction(), "io")
Expand Down
21 changes: 17 additions & 4 deletions array/src/commonMain/kotlin/array/types.kt
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ interface APLValue {

fun ensureNumber(pos: Position? = null): APLNumber {
val v = unwrapDeferredValue()
if (v == this) {
if (v === this) {
throwAPLException(IncompatibleTypeException("Value $this is not a numeric value (type=${aplValueType.typeName})", pos))
} else {
return v.ensureNumber(pos)
Expand All @@ -124,7 +124,7 @@ interface APLValue {

fun ensureSymbol(pos: Position? = null): APLSymbol {
val v = unwrapDeferredValue()
if (v == this) {
if (v === this) {
throwAPLException(IncompatibleTypeException("Value $this is not a symbol (type=${aplValueType.typeName})", pos))
} else {
return v.ensureSymbol(pos)
Expand All @@ -133,13 +133,22 @@ interface APLValue {

fun ensureList(pos: Position? = null): APLList {
val v = unwrapDeferredValue()
if (v == this) {
if (v === this) {
throwAPLException(IncompatibleTypeException("Value $this is not a list (type=${aplValueType.typeName})", pos))
} else {
return v.ensureList(pos)
}
}

fun ensureMap(pos: Position): APLMap {
val v = unwrapDeferredValue()
if (v === this) {
throwAPLException(IncompatibleTypeException("Value $this is not a map (type=${aplValueType.typeName})", pos))
} else {
return v.ensureMap(pos)
}
}

fun toIntArray(pos: Position): IntArray {
return IntArray(size) { i ->
valueAt(i).ensureNumber(pos).asInt()
Expand Down Expand Up @@ -193,7 +202,7 @@ fun APLValue.listify(): APLList {
fun APLValue.asByteArray(pos: Position? = null): ByteArray {
val v = this.collapse().arrayify()
if (v.dimensions.size != 1) {
throwAPLException(InvalidDimensionsException("Value must be a scalar or a one-dimensional array"))
throwAPLException(InvalidDimensionsException("Value must be a scalar or a one-dimensional array", pos))
}
val size = v.dimensions[0]
if (size == 0) {
Expand Down Expand Up @@ -393,6 +402,10 @@ class APLMap(val content: ImmutableMap2<APLValue.APLValueKey, APLValue>) : APLSi
return APLValue.APLValueKeyImpl(this, content)
}

override fun ensureMap(pos: Position): APLMap {
return this
}

fun lookupValue(key: APLValue): APLValue {
return content[key.makeKey()] ?: APLNullValue()
}
Expand Down
22 changes: 22 additions & 0 deletions array/src/commonTest/kotlin/array/MapTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package array
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.test.fail

class MapTest : APLTest() {
@Test
Expand Down Expand Up @@ -147,4 +148,25 @@ class MapTest : APLTest() {
""".trimMargin())
assertAPLNull(result)
}

@Test
fun readKeyValues() {
parseAPLExpression("a ← map 2 2 ⍴ \"foo\" \"abc\" \"bar\" \"bcd\" ◊ mapToArray a").let { result ->
fun findKeyAndValue(v: APLValue, findKey: String, findValue: String) {
for (i in 0 until v.dimensions[0]) {
val key = v.valueAt(v.dimensions.indexFromPosition(intArrayOf(i, 0))).toStringValue()
val value = v.valueAt(v.dimensions.indexFromPosition(intArrayOf(i, 1))).toStringValue()
if (key == findKey) {
assertEquals(findValue, value, "Value for key does not match")
return
}
}
fail("Could not find key: '${findKey}'")
}

assertDimension(dimensionsOfSize(2, 2), result)
findKeyAndValue(result, "foo", "abc")
findKeyAndValue(result, "bar", "bcd")
}
}
}

0 comments on commit 026fe6a

Please sign in to comment.