1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
package moe.nea.lisp
class LispExecutionContext() {
val rootStackFrame = StackFrame(null)
val unloadedModules = mutableMapOf<String, LispAst.Program>()
val modules = mutableMapOf<String, Map<String, LispData>>()
fun genBindings(): StackFrame {
return StackFrame(rootStackFrame)
}
fun setupStandardBindings() {
CoreBindings.offerAllTo(rootStackFrame)
registerModule("builtins", Builtins.builtinProgram)
registerModule("test", Builtins.testProgram)
modules["ntest"] = TestFramework.realizedTestModule
importModule("builtins", rootStackFrame, object : HasLispPosition {
override val position: LispPosition
get() = error("Builtin import failed")
})
}
fun runTests(
program: LispAst.Program,
name: String,
stackFrame: StackFrame = genBindings(),
testList: List<String> = emptyList(),
isWhitelist: Boolean = false
): TestFramework.TestSuite {
val testSuite = TestFramework.setup(stackFrame, name, testList, isWhitelist)
val output = OutputCapture.captureOutput(stackFrame)
executeProgram(stackFrame, program)
testSuite.isTesting = false
testSuite.otherOutput = output.asString
return testSuite
}
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) {
into.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("export") { context, callsite, stackFrame, args ->
args.forEach { name ->
if (name !is LispAst.Reference) {
stackFrame.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? {
var lastValue: LispData? = null
for (node in program.nodes) {
lastValue = executeLisp(stackFrame, node)
}
return lastValue
}
fun executeLisp(stackFrame: StackFrame, node: LispAst.LispNode): LispData {
when (node) {
is LispAst.Parenthesis -> {
val first = node.items.firstOrNull()
?: return stackFrame.reportError("Cannot execute empty parenthesis ()", node)
val rest = node.items.drop(1)
return when (val resolvedValue = resolveValue(stackFrame, first)) {
is LispData.LispExecutable -> {
resolvedValue.execute(this, node, stackFrame, rest)
}
else -> stackFrame.reportError("Cannot evaluate expression of type $resolvedValue", node)
}
}
else -> return stackFrame.reportError("Expected invocation", node)
}
}
fun resolveValue(stackFrame: StackFrame, node: LispAst.LispNode): LispData {
return when (node) {
is LispAst.Atom -> LispData.Atom(node.label)
is LispAst.Parenthesis -> executeLisp(stackFrame, node)
is LispAst.Reference -> stackFrame.resolveReference(node.label)
?: stackFrame.reportError("Could not resolve variable ${node.label}", node)
is LispAst.NumberLiteral -> LispData.LispNumber(node.numberValue)
is LispAst.StringLiteral -> LispData.LispString(node.parsedString)
}
}
}
|