summaryrefslogtreecommitdiff
path: root/src/LispData.kt
blob: 11a2451e8773feddbb4e350903ada8fea3b55967 (plain)
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
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()
    sealed class LispExecutable() : LispData() {
        abstract fun execute(
            executionContext: LispExecutionContext,
            callsite: LispAst.LispNode,
            stackFrame: StackFrame,
            args: List<LispAst.LispNode>
        ): LispData
    }

    abstract class JavaExecutable : 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 {
            if (argNames.size != args.size) {
                return executionContext.reportError(
                    "Expected ${argNames.size} arguments, got ${args.size} instead",
                    callsite
                )
            }
            val invocationFrame = declarationStackFrame.fork()

            for ((name, value) in argNames.zip(args)) {
                invocationFrame.setValueLocal(name, executionContext.resolveValue(stackFrame, value))
            }
            return executionContext.executeLisp(invocationFrame, body)
        }
    }


    companion object {
        fun externalRawCall(callable: (context: LispExecutionContext, callsite: LispAst.LispNode, stackFrame: StackFrame, args: List<LispAst.LispNode>) -> LispData): LispExecutable {
            return object : JavaExecutable() {
                override fun execute(
                    executionContext: LispExecutionContext,
                    callsite: LispAst.LispNode,
                    stackFrame: StackFrame,
                    args: List<LispAst.LispNode>
                ): LispData {
                    return callable.invoke(executionContext, callsite, stackFrame, args)
                }
            }
        }

        fun externalCall(callable: (args: List<LispData>, reportError: (String) -> LispData) -> LispData): LispExecutable {
            return object : JavaExecutable() {
                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)
        }
    }
}