summaryrefslogtreecommitdiff
path: root/src/CoreBindings.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/CoreBindings.kt')
-rw-r--r--src/CoreBindings.kt109
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