From 62244f488cf570471ecb9de919ecbf961508757c Mon Sep 17 00:00:00 2001 From: nea Date: Mon, 21 Aug 2023 18:15:40 +0200 Subject: Better binding for more types --- TestOutput.xml | 2 +- src/bind/AutoBinder.kt | 79 ++++++++++++++++++++++++++++---------------------- test/res/scratch.lisp | 2 +- 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 @@ -, 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, 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, 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, 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, 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, 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 -> + 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()) } -- cgit