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
|
package moe.nea.lisp
sealed class LispData {
object LispNil : LispData()
data class Atom(val label: String) : LispData()
data class LispString(val string: String) : LispData()
data class LispNumber(val value: Double) : LispData()
data class LispNode(val node: LispAst.LispNode) : LispData()
class LispList(val elements: List<LispData>) : LispData()
sealed class LispExecutable() : LispData() {
abstract fun execute(
executionContext: LispExecutionContext,
callsite: LispAst.LispNode,
stackFrame: StackFrame,
args: List<LispAst.LispNode>
): LispData
}
abstract class JavaExecutable(val name: String) : LispExecutable()
data class LispInterpretedCallable(
val declarationStackFrame: StackFrame,
val argNames: List<String>,
val body: LispAst.Parenthesis,
val name: String?,
) : LispExecutable() {
override fun execute(
executionContext: LispExecutionContext,
callsite: LispAst.LispNode,
stackFrame: StackFrame,
args: List<LispAst.LispNode>
): LispData {
val invocationFrame = declarationStackFrame.fork()
if (argNames.lastOrNull() == "...") {
for ((name, value) in argNames.dropLast(1).zip(args)) {
invocationFrame.setValueLocal(name, executionContext.resolveValue(stackFrame, value))
}
invocationFrame.setValueLocal(
"...",
LispList(
args.drop(argNames.size - 1).map { executionContext.resolveValue(stackFrame, it) })
)
} else if (argNames.size != args.size) {
return executionContext.reportError(
"Expected ${argNames.size} arguments, got ${args.size} instead",
callsite
)
} else
for ((name, value) in argNames.zip(args)) {
invocationFrame.setValueLocal(name, executionContext.resolveValue(stackFrame, value))
}
return executionContext.executeLisp(invocationFrame, body)
}
}
companion object {
fun externalRawCall(
name: String,
callable: (context: LispExecutionContext, callsite: LispAst.LispNode, stackFrame: StackFrame, args: List<LispAst.LispNode>) -> LispData
): LispExecutable {
return object : JavaExecutable(name) {
override fun execute(
executionContext: LispExecutionContext,
callsite: LispAst.LispNode,
stackFrame: StackFrame,
args: List<LispAst.LispNode>
): LispData {
return callable.invoke(executionContext, callsite, stackFrame, args)
}
}
}
fun externalCall(
name: String,
callable: (args: List<LispData>, reportError: (String) -> LispData) -> LispData
): LispExecutable {
return object : JavaExecutable(name) {
override fun execute(
executionContext: LispExecutionContext,
callsite: LispAst.LispNode,
stackFrame: StackFrame,
args: List<LispAst.LispNode>
): LispData {
val mappedArgs = args.map { executionContext.resolveValue(stackFrame, it) }
return callable.invoke(mappedArgs) { executionContext.reportError(it, callsite) }
}
}
}
fun createLambda(
declarationStackFrame: StackFrame,
args: List<String>,
body: LispAst.Parenthesis,
nameHint: String? = null,
): LispExecutable {
return LispInterpretedCallable(declarationStackFrame, args, body, nameHint)
}
}
}
|