diff options
author | nea <nea@nea.moe> | 2023-08-21 18:15:40 +0200 |
---|---|---|
committer | nea <nea@nea.moe> | 2023-08-21 18:15:40 +0200 |
commit | 62244f488cf570471ecb9de919ecbf961508757c (patch) | |
tree | 187e9d651ac57533d29d96fcc77c61befaf415c7 | |
parent | 4bbfede4060d38083aafd8a6c7ab2847e0e55ebf (diff) | |
download | nealisp-62244f488cf570471ecb9de919ecbf961508757c.tar.gz nealisp-62244f488cf570471ecb9de919ecbf961508757c.tar.bz2 nealisp-62244f488cf570471ecb9de919ecbf961508757c.zip |
Better binding for more types
-rw-r--r-- | TestOutput.xml | 2 | ||||
-rw-r--r-- | src/bind/AutoBinder.kt | 79 | ||||
-rw-r--r-- | test/res/scratch.lisp | 2 | ||||
-rw-r--r-- | test/src/TestLisp.kt | 8 |
4 files changed, 49 insertions, 42 deletions
diff --git a/TestOutput.xml b/TestOutput.xml index aaef8ea..f935a7d 100644 --- a/TestOutput.xml +++ b/TestOutput.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" ?><testsuites><testsuite name="Test" tests="0" skipped="0" failures="0" errors="0" timestamp="2023-08-21T04:12:42"><properties></properties><system-out><![CDATA[Hello, World, here is an atom: :iamanatom +<?xml version="1.0" ?><testsuites><testsuite name="Test" tests="0" skipped="0" failures="0" errors="0" timestamp="2023-08-21T04:26:56"><properties></properties><system-out><![CDATA[Hello, World, here is an atom: :iamanatom :myfunworks :atom a :test diff --git a/src/bind/AutoBinder.kt b/src/bind/AutoBinder.kt index 83d5d86..53a4ebb 100644 --- a/src/bind/AutoBinder.kt +++ b/src/bind/AutoBinder.kt @@ -8,74 +8,80 @@ import java.lang.reflect.Parameter class AutoBinder { - private fun mapLispData(parameter: Parameter): ((Iterator<LispData>, ErrorReporter) -> Any)? { - if (LispData::class.java.isAssignableFrom(parameter.type)) return { a, b -> parameter.type.cast(a.next()) } + private fun mapLispData(parameter: Parameter): ((() -> LispData, () -> LispAst, ErrorReporter) -> Any)? { + if (LispData::class.java.isAssignableFrom(parameter.type)) return { a, b, c -> parameter.type.cast(a()) } return null } - private fun mapErrorReporter(parameter: Parameter): ((Iterator<LispData>, ErrorReporter) -> Any)? { - if (ErrorReporter::class.java.isAssignableFrom(parameter.type)) return { a, b -> b } + private fun mapErrorReporter(parameter: Parameter): ((() -> LispData, () -> LispAst, ErrorReporter) -> Any)? { + if (ErrorReporter::class.java.isAssignableFrom(parameter.type)) return { a, b, c -> c } return null } - private fun mapString(parameter: Parameter): ((Iterator<LispData>, ErrorReporter) -> Any?)? { - if (String::class.java == parameter.type) return { a, b -> - when (val x = a.next()) { + private fun mapString(parameter: Parameter): ((() -> LispData, () -> LispAst, ErrorReporter) -> Any?)? { + if (String::class.java == parameter.type) return { a, b, c -> + when (val x = a()) { is LispData.LispString -> x.string is LispData.Atom -> x.label - else -> null.also { b.reportError("Could not coerce $x to string") } + else -> null.also { c.reportError("Could not coerce $x to string") } } } return null } - private fun mapBoolean(parameter: Parameter): ((Iterator<LispData>, ErrorReporter) -> Any?)? { - if (Boolean::class.java.isAssignableFrom(parameter.type)) return { a, b -> - val x = a.next() + private fun mapBoolean(parameter: Parameter): ((() -> LispData, () -> LispAst, ErrorReporter) -> Any?)? { + if (Boolean::class.java.isAssignableFrom(parameter.type)) return { a, b, c -> + val x = a() val y = CoreBindings.isTruthy(x) if (y == null) { - b.reportError("Could not coerce $x to a boolean") + c.reportError("Could not coerce $x to a boolean") } y } return null } - private fun mapNumber(parameter: Parameter): ((Iterator<LispData>, ErrorReporter) -> Any?)? { - if (Double::class.java.isAssignableFrom(parameter.type)) return { a, b -> - when (val x = a.next()) { + private fun mapAST(parameter: Parameter): ((() -> LispData, () -> LispAst, ErrorReporter) -> Any?)? { + if (LispAst::class.java.isAssignableFrom(parameter.type)) return { a, b, c -> parameter.type.cast(b()) } + return null + } + + private fun mapNumber(parameter: Parameter): ((() -> LispData, () -> LispAst, ErrorReporter) -> Any?)? { + if (Double::class.java.isAssignableFrom(parameter.type)) return { a, b, c -> + when (val x = a()) { is LispData.LispNumber -> x.value - else -> null.also { b.reportError("Could not coerce $x to number") } + else -> null.also { c.reportError("Could not coerce $x to number") } } } - if (Float::class.java.isAssignableFrom(parameter.type)) return { a, b -> - when (val x = a.next()) { + if (Float::class.java.isAssignableFrom(parameter.type)) return { a, b, c -> + when (val x = a()) { is LispData.LispNumber -> x.value.toFloat() - else -> null.also { b.reportError("Could not coerce $x to number") } + else -> null.also { c.reportError("Could not coerce $x to number") } } } - if (Int::class.java.isAssignableFrom(parameter.type)) return { a, b -> - when (val x = a.next()) { + if (Int::class.java.isAssignableFrom(parameter.type)) return { a, b, c -> + when (val x = a()) { is LispData.LispNumber -> x.value.toInt() - else -> null.also { b.reportError("Could not coerce $x to number") } + else -> null.also { c.reportError("Could not coerce $x to number") } } } - if (Long::class.java.isAssignableFrom(parameter.type)) return { a, b -> - when (val x = a.next()) { + if (Long::class.java.isAssignableFrom(parameter.type)) return { a, b, c -> + when (val x = a()) { is LispData.LispNumber -> x.value.toLong() - else -> null.also { b.reportError("Could not coerce $x to number") } + else -> null.also { c.reportError("Could not coerce $x to number") } } } return null } - val objectMappers = mutableListOf<((Parameter) -> (((Iterator<LispData>, ErrorReporter) -> Any?)?))>( + val objectMappers = mutableListOf<((Parameter) -> (((() -> LispData, () -> LispAst, ErrorReporter) -> Any?)?))>( ::mapLispData, ::mapErrorReporter, ::mapNumber, ::mapString, ::mapBoolean, + ::mapAST, ) @@ -101,19 +107,22 @@ class AutoBinder { objectMappers.firstNotNullOfOrNull { it.invoke(param) } ?: error("Could not find object mapper for parameter $param") } - return LispData.externalCall(name) { args, fReportError -> + return LispData.externalRawCall(name) { context: LispExecutionContext, callsite: LispAst.LispNode, stackFrame: StackFrame, args: List<LispAst.LispNode> -> + val e = object : ErrorReporter { + override fun reportError(string: String): LispData { + return stackFrame.reportError(string, callsite) + } + } try { val iterator = args.iterator() - val e = object : ErrorReporter { - override fun reportError(string: String): LispData { - return fReportError(string) - } + val p = objectMappers.map { + it.invoke({ context.resolveValue(stackFrame, iterator.next()) }, { iterator.next() }, e) + ?: return@externalRawCall LispData.LispNil } - val p = objectMappers.map { it.invoke(iterator, e) ?: return@externalCall LispData.LispNil } - if (iterator.hasNext()) return@externalCall fReportError("Too many arguments") + if (iterator.hasNext()) return@externalRawCall e.reportError("Too many arguments") mh.invokeWithArguments(p) as LispData - } catch (e: Exception) { - fReportError("$name threw an exception: $e") + } catch (x: Exception) { + e.reportError("$name threw an exception", x) } } } diff --git a/test/res/scratch.lisp b/test/res/scratch.lisp index 667f903..00517a8 100644 --- a/test/res/scratch.lisp +++ b/test/res/scratch.lisp @@ -25,4 +25,4 @@ (debuglog "============") (debuglog "Running tests") -(debuglog "This should be 1.0" (funny-method 1.1 "test" false))
\ No newline at end of file +(debuglog "This should be 1.0" (funny-method 1.1 "test" false (test 1 2 3 4 /)))
\ No newline at end of file diff --git a/test/src/TestLisp.kt b/test/src/TestLisp.kt index 205bea2..5f56d68 100644 --- a/test/src/TestLisp.kt +++ b/test/src/TestLisp.kt @@ -1,7 +1,4 @@ -import moe.nea.lisp.LispData -import moe.nea.lisp.LispExecutionContext -import moe.nea.lisp.LispParser -import moe.nea.lisp.TestResultFormatter +import moe.nea.lisp.* import moe.nea.lisp.bind.AutoBinder import moe.nea.lisp.bind.LispBinding import java.io.File @@ -12,9 +9,10 @@ object T object TestBindings { @LispBinding("funny-method") - fun funnyMethod(arg: Int, test: String, boolean: Boolean): LispData { + fun funnyMethod(arg: Int, test: String, boolean: Boolean, ast: LispAst): LispData { if (boolean) println("From java: $test") + println(ast.toSource()) return LispData.LispNumber(arg.toDouble()) } |