summaryrefslogtreecommitdiff
path: root/src/LispExecutionContext.kt
blob: f169ba939a5c4697035812fab78fbb23ed1c8867 (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
package moe.nea.lisp

class LispExecutionContext() {

    private val errorReporter = LispErrorReporter()
    private val rootStackFrame = StackFrame(null)


    fun reportError(name: String, position: HasLispPosition): LispData.LispNil {
        println("Error: $name ${position.position}")
        return LispData.LispNil
    }


    fun genBindings(): StackFrame {
        return StackFrame(rootStackFrame)
    }

    fun executeProgram(stackFrame: StackFrame, program: LispAst.Program) {
        for (node in program.nodes) {
            executeLisp(stackFrame, node)
        }
    }


    fun executeLisp(stackFrame: StackFrame, node: LispAst.LispNode): LispData {
        when (node) {
            is LispAst.Parenthesis -> {
                val first = node.items.firstOrNull()
                    ?: return reportError("Cannot execute empty parenthesis ()", node)

                val rest = node.items.drop(1)
                return when (val resolvedValue = resolveValue(stackFrame, first)) {
                    is LispData.Atom -> reportError("Cannot execute atom", node)
                    LispData.LispNil -> reportError("Cannot execute nil", node)
                    is LispData.LispNumber -> reportError("Cannot execute number", node)
                    is LispData.LispNode -> reportError("Cannot execute node", node)
                    is LispData.LispObject<*> -> reportError("Cannot execute object-value", node)
                    is LispData.LispExecutable -> {
                        resolvedValue.execute(this, node, stackFrame, rest)
                    }
                }

            }

            else -> return 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)
                ?: reportError("Could not resolve variable ${node.label}", node)

            is LispAst.StringLiteral -> LispData.string(node.parsedString)
        }
    }
}