summaryrefslogtreecommitdiff
path: root/src/LispData.kt
blob: 1f13ad3d52c8f94440d2f8b67769d2c152131df0 (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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package moe.nea.lisp

sealed class LispData {

    fun <T : Any> lispCastObject(lClass: LispClass<T>): LispObject<T>? {
        if (this !is LispObject<*>) return null
        if (this.handler != lClass) return null
        return this as LispObject<T>
    }

    object LispNil : LispData()
    data class Atom(val label: String) : LispData()
    data class LispNode(val node: LispAst.LispNode) : LispData()
    data class LispNumber(val number: Double) : LispData()
    data class LispObject<T : Any>(val data: T, val handler: LispClass<T>) : 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) {
                TODO("ERROR")
            }
            val invocationFrame = declarationStackFrame.fork()

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

    interface LispClass<T : Any> {
        fun access(obj: T, name: String): LispData
        fun instantiate(obj: T) = LispObject(obj, this)
    }

    object LispStringClass : LispClass<String> {
        override fun access(obj: String, name: String): LispData {
            return LispNil
        }
    }

    companion object {
        fun string(value: String): LispObject<String> =
            LispStringClass.instantiate(value)

        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)
        }
    }
}