diff options
Diffstat (limited to 'src/CoreBindings.kt')
-rw-r--r-- | src/CoreBindings.kt | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/src/CoreBindings.kt b/src/CoreBindings.kt new file mode 100644 index 0000000..9213917 --- /dev/null +++ b/src/CoreBindings.kt @@ -0,0 +1,109 @@ +package moe.nea.lisp + +object CoreBindings { + val nil = LispData.LispNil + val def = LispData.externalRawCall { context, callsite, stackFrame, args -> + if (args.size != 2) { + return@externalRawCall context.reportError("Function define expects exactly two arguments", callsite) + } + val (name, value) = args + if (name !is LispAst.Reference) { + return@externalRawCall context.reportError("Define expects a name as first argument", name) + } + if (name.label in stackFrame.variables) { + return@externalRawCall context.reportError("Cannot redefine value in local context", name) + } + return@externalRawCall stackFrame.setValueLocal(name.label, context.resolveValue(stackFrame, value)) + } + + val pure = LispData.externalCall { args, reportError -> + return@externalCall args.singleOrNull()?.let { value -> + LispData.externalCall { args, reportError -> + if (args.isNotEmpty()) + reportError("Pure function does not expect arguments") + else + value + } + } ?: reportError("Function pure expects exactly one argument") + } + + val lambda = LispData.externalRawCall { context, callsite, stackFrame, args -> + if (args.size != 2) { + return@externalRawCall context.reportError("Lambda needs exactly 2 arguments", callsite) + } + val (argumentNames, body) = args + if (argumentNames !is LispAst.Parenthesis) { + return@externalRawCall context.reportError("Lambda has invalid argument declaration", argumentNames) + } + val argumentNamesString = argumentNames.items.map { + val ref = it as? LispAst.Reference + if (ref == null) { + return@externalRawCall context.reportError("Lambda has invalid argument declaration", it) + } + ref.label + } + if (body !is LispAst.Parenthesis) { + return@externalRawCall context.reportError("Lambda has invalid body declaration", body) + } + LispData.createLambda(stackFrame, argumentNamesString, body) + } + + val defun = LispData.externalRawCall { context, callSite, stackFrame, lispAsts -> + if (lispAsts.size != 3) { + return@externalRawCall context.reportError("Invalid function definition", callSite) + } + val (name, args, body) = lispAsts + if (name !is LispAst.Reference) { + return@externalRawCall context.reportError("Invalid function definition name", name) + } + if (name.label in stackFrame.variables) { + return@externalRawCall context.reportError("Cannot redefine function in local context", name) + } + if (args !is LispAst.Parenthesis) { + return@externalRawCall context.reportError("Invalid function definition arguments", args) + } + val argumentNames = args.items.map { + val ref = it as? LispAst.Reference + ?: return@externalRawCall context.reportError("Invalid function definition argument name", it) + ref.label + } + if (body !is LispAst.Parenthesis) { + return@externalRawCall context.reportError("Invalid function definition body", body) + } + return@externalRawCall stackFrame.setValueLocal( + name.label, + LispData.createLambda(stackFrame, argumentNames, body, name.label) + ) + } + val seq = LispData.externalRawCall { context, callsite, stackFrame, args -> + var lastResult: LispData? = null + for (arg in args) { + lastResult = context.executeLisp(stackFrame, arg) + } + lastResult ?: context.reportError("Seq cannot be invoked with 0 argumens", callsite) + } + val debuglog = LispData.externalRawCall { context, callsite, stackFrame, args -> + println(args.joinToString(" ") { arg -> + when (val resolved = context.resolveValue(stackFrame, arg)) { + is LispData.Atom -> ":${resolved.label}" + is LispData.JavaExecutable -> "<native code>" + LispData.LispNil -> "nil" + is LispData.LispNumber -> resolved.number.toString() + is LispData.LispNode -> resolved.node.toSource() + is LispData.LispObject<*> -> resolved.data.toString() + is LispData.LispInterpretedCallable -> "<function ${resolved.name ?: ""} ${resolved.argNames} ${resolved.body.toSource()}>" + } + }) + LispData.LispNil + } + + fun offerAllTo(bindings: StackFrame) { + bindings.setValueLocal("nil", nil) + bindings.setValueLocal("def", def) + bindings.setValueLocal("pure", pure) + bindings.setValueLocal("lambda", lambda) + bindings.setValueLocal("defun", defun) + bindings.setValueLocal("seq", seq) + bindings.setValueLocal("debuglog", debuglog) + } +}
\ No newline at end of file |