summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authornea <nea@nea.moe>2023-08-10 02:26:42 +0200
committernea <nea@nea.moe>2023-08-10 02:26:42 +0200
commitf345fadd492ea5bb09e515d007be438fc08c9b93 (patch)
tree2b2b99dc7e75387ba16cdb43d107bcedf84d4938 /src
parente4661bf1fecf5a214a020a56b9658dc49565e162 (diff)
downloadnealisp-f345fadd492ea5bb09e515d007be438fc08c9b93.tar.gz
nealisp-f345fadd492ea5bb09e515d007be438fc08c9b93.tar.bz2
nealisp-f345fadd492ea5bb09e515d007be438fc08c9b93.zip
Add imports
Diffstat (limited to 'src')
-rw-r--r--src/Builtins.kt13
-rw-r--r--src/CoreBindings.kt14
-rw-r--r--src/LispExecutionContext.kt50
3 files changed, 62 insertions, 15 deletions
diff --git a/src/Builtins.kt b/src/Builtins.kt
index 6ca60e9..f9bf329 100644
--- a/src/Builtins.kt
+++ b/src/Builtins.kt
@@ -3,17 +3,4 @@ package moe.nea.lisp
object Builtins {
val builtinSource = Builtins::class.java.getResourceAsStream("/builtins.lisp")!!.bufferedReader().readText()
val builtinProgram = LispParser.parse("builtins.lisp", builtinSource)
- fun loadBuiltins(
- lispExecutionContext: LispExecutionContext,
- consumer: (String, LispData) -> Unit,
- ) {
- val stackFrame = lispExecutionContext.genBindings()
- stackFrame.setValueLocal("export", LispData.externalRawCall { context, callsite, stackFrame, args ->
- args.forEach { name ->
- consumer((name as LispAst.Reference).label, context.resolveValue(stackFrame, name))
- }
- return@externalRawCall LispData.LispNil
- })
- lispExecutionContext.executeProgram(stackFrame, builtinProgram)
- }
} \ No newline at end of file
diff --git a/src/CoreBindings.kt b/src/CoreBindings.kt
index f139e2e..b344dc7 100644
--- a/src/CoreBindings.kt
+++ b/src/CoreBindings.kt
@@ -172,6 +172,19 @@ object CoreBindings {
?: return@externalCall reportError("Unexpected argument $b, expected number")).value
})
}
+ val import = LispData.externalRawCall { context, callsite, stackFrame, args ->
+ if (args.size != 1) {
+ return@externalRawCall context.reportError("import needs at least one argument", callsite)
+ }
+ // TODO: aliased / namespaced imports
+ val moduleName = when (val moduleObject = context.resolveValue(stackFrame, args[0])) {
+ is LispData.Atom -> moduleObject.label
+ is LispData.LispString -> moduleObject.string
+ else -> return@externalRawCall context.reportError("import needs a string or atom as argument", callsite)
+ }
+ context.importModule(moduleName, stackFrame, callsite)
+ return@externalRawCall LispData.LispNil
+ }
fun offerArithmeticTo(bindings: StackFrame) {
bindings.setValueLocal("+", add)
@@ -188,6 +201,7 @@ object CoreBindings {
bindings.setValueLocal("lambda", lambda)
bindings.setValueLocal("defun", defun)
bindings.setValueLocal("seq", seq)
+ bindings.setValueLocal("import", import)
bindings.setValueLocal("debuglog", debuglog)
offerArithmeticTo(bindings)
}
diff --git a/src/LispExecutionContext.kt b/src/LispExecutionContext.kt
index f85cc4b..181c06b 100644
--- a/src/LispExecutionContext.kt
+++ b/src/LispExecutionContext.kt
@@ -4,7 +4,8 @@ class LispExecutionContext() {
private val errorReporter = LispErrorReporter()
val rootStackFrame = StackFrame(null)
-
+ val unloadedModules = mutableMapOf<String, LispAst.Program>()
+ val modules = mutableMapOf<String, Map<String, LispData>>()
fun reportError(name: String, position: HasLispPosition): LispData.LispNil {
println("Error: $name ${position.position}")
@@ -18,7 +19,51 @@ class LispExecutionContext() {
fun setupStandardBindings() {
CoreBindings.offerAllTo(rootStackFrame)
- Builtins.loadBuiltins(this, rootStackFrame::setValueLocal)
+ registerModule("builtins", Builtins.builtinProgram)
+ importModule("builtins", rootStackFrame, object : HasLispPosition {
+ override val position: LispPosition
+ get() = error("Builtin import failed")
+
+ })
+ }
+
+ fun registerModule(moduleName: String, program: LispAst.Program) {
+ if (moduleName in unloadedModules || moduleName in modules) {
+ error("Cannot register already registered module $moduleName")
+ }
+ unloadedModules[moduleName] = program
+ }
+
+ fun importModule(moduleName: String, into: StackFrame, position: HasLispPosition) {
+ var exports = modules[moduleName]
+ if (exports == null) {
+ val module = unloadedModules[moduleName]
+ if (module == null) {
+ reportError("Could not find module $moduleName", position)
+ return
+ }
+ exports = realizeModule(moduleName)
+ }
+ into.variables.putAll(exports)
+ }
+
+ private fun realizeModule(moduleName: String): Map<String, LispData> {
+ val map = mutableMapOf<String, LispData>()
+ modules[moduleName] = map
+ val module = unloadedModules.remove(moduleName) ?: error("Could not find module $moduleName")
+ val stackFrame = genBindings()
+ stackFrame.setValueLocal("export", LispData.externalRawCall { context, callsite, stackFrame, args ->
+ args.forEach { name ->
+ if (name !is LispAst.Reference) {
+ context.reportError("Invalid export", name)
+ return@forEach
+ }
+ map[name.label] = context.resolveValue(stackFrame, name)
+ }
+ return@externalRawCall LispData.LispNil
+ })
+ executeProgram(stackFrame, module)
+ return map
}
fun executeProgram(stackFrame: StackFrame, program: LispAst.Program): LispData? {
@@ -57,6 +102,7 @@ class LispExecutionContext() {
is LispAst.Parenthesis -> executeLisp(stackFrame, node)
is LispAst.Reference -> stackFrame.resolveReference(node.label)
?: reportError("Could not resolve variable ${node.label}", node)
+
is LispAst.NumberLiteral -> LispData.LispNumber(node.numberValue)
is LispAst.StringLiteral -> LispData.LispString(node.parsedString)
}