summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornea <nea@nea.moe>2023-08-09 17:05:46 +0200
committernea <nea@nea.moe>2023-08-09 17:05:46 +0200
commitf3600dacea3e38cd541bf57076f8a7141987e10b (patch)
treec22645458e388a39a8d3a1e77cb261b4b69c1db2
parentb530d6360308ac1f68cf2508fa5bd4a085a8bec0 (diff)
downloadnealisp-f3600dacea3e38cd541bf57076f8a7141987e10b.tar.gz
nealisp-f3600dacea3e38cd541bf57076f8a7141987e10b.tar.bz2
nealisp-f3600dacea3e38cd541bf57076f8a7141987e10b.zip
Add addition
-rw-r--r--src/CoreBindings.kt19
-rw-r--r--src/LispAst.kt6
-rw-r--r--src/LispData.kt32
-rw-r--r--src/LispExecutionContext.kt11
-rw-r--r--src/LispParser.kt15
-rw-r--r--test/res/test.lisp5
6 files changed, 50 insertions, 38 deletions
diff --git a/src/CoreBindings.kt b/src/CoreBindings.kt
index 9213917..13c6de3 100644
--- a/src/CoreBindings.kt
+++ b/src/CoreBindings.kt
@@ -82,20 +82,34 @@ object CoreBindings {
}
lastResult ?: context.reportError("Seq cannot be invoked with 0 argumens", callsite)
}
+
val debuglog = LispData.externalRawCall { context, callsite, stackFrame, args ->
println(args.joinToString(" ") { arg ->
when (val resolved = context.resolveValue(stackFrame, arg)) {
is LispData.Atom -> ":${resolved.label}"
is LispData.JavaExecutable -> "<native code>"
LispData.LispNil -> "nil"
- is LispData.LispNumber -> resolved.number.toString()
is LispData.LispNode -> resolved.node.toSource()
- is LispData.LispObject<*> -> resolved.data.toString()
+ is LispData.LispString -> resolved.string
+ is LispData.LispNumber -> resolved.value.toString()
is LispData.LispInterpretedCallable -> "<function ${resolved.name ?: ""} ${resolved.argNames} ${resolved.body.toSource()}>"
}
})
LispData.LispNil
}
+ val add = LispData.externalCall { args, reportError ->
+ if (args.size == 0) {
+ return@externalCall reportError("Cannot call add without at least 1 argument")
+ }
+ LispData.LispNumber(args.fold(0.0) { a, b ->
+ a + (b as? LispData.LispNumber
+ ?: return@externalCall reportError("Unexpected argument $b, expected number")).value
+ })
+ }
+
+ fun offerArithmeticTo(bindings: StackFrame) {
+ bindings.setValueLocal("+", add)
+ }
fun offerAllTo(bindings: StackFrame) {
bindings.setValueLocal("nil", nil)
@@ -105,5 +119,6 @@ object CoreBindings {
bindings.setValueLocal("defun", defun)
bindings.setValueLocal("seq", seq)
bindings.setValueLocal("debuglog", debuglog)
+ offerArithmeticTo(bindings)
}
} \ No newline at end of file
diff --git a/src/LispAst.kt b/src/LispAst.kt
index 79fee8a..6ac7032 100644
--- a/src/LispAst.kt
+++ b/src/LispAst.kt
@@ -33,6 +33,12 @@ sealed class LispAst : HasLispPosition {
}
}
+ data class NumberLiteral(override val position: LispPosition, val numberValue: Double) : LispNode() {
+ override fun toSource(): String {
+ return numberValue.toString()
+ }
+ }
+
data class StringLiteral(override val position: LispPosition, val parsedString: String) : LispNode() {
override fun toSource(): String {
return "\"${parsedString.replace("\\", "\\\\").replace("\"", "\\\"")}\"" // TODO: better escaping
diff --git a/src/LispData.kt b/src/LispData.kt
index 1f13ad3..11a2451 100644
--- a/src/LispData.kt
+++ b/src/LispData.kt
@@ -2,17 +2,11 @@ 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 LispString(val string: String) : LispData()
+ data class LispNumber(val value: Double) : 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,
@@ -22,9 +16,7 @@ sealed class LispData {
): LispData
}
-
- abstract class JavaExecutable : LispExecutable() {
- }
+ abstract class JavaExecutable : LispExecutable()
data class LispInterpretedCallable(
val declarationStackFrame: StackFrame,
@@ -39,7 +31,10 @@ sealed class LispData {
args: List<LispAst.LispNode>
): LispData {
if (argNames.size != args.size) {
- TODO("ERROR")
+ return executionContext.reportError(
+ "Expected ${argNames.size} arguments, got ${args.size} instead",
+ callsite
+ )
}
val invocationFrame = declarationStackFrame.fork()
@@ -50,21 +45,8 @@ sealed class LispData {
}
}
- 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(
diff --git a/src/LispExecutionContext.kt b/src/LispExecutionContext.kt
index f169ba9..20d581e 100644
--- a/src/LispExecutionContext.kt
+++ b/src/LispExecutionContext.kt
@@ -31,14 +31,11 @@ class LispExecutionContext() {
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 -> reportError("Cannot evaluate expression of type $resolvedValue", node)
}
}
@@ -53,8 +50,8 @@ class LispExecutionContext() {
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)
+ is LispAst.NumberLiteral -> LispData.LispNumber(node.numberValue)
+ is LispAst.StringLiteral -> LispData.LispString(node.parsedString)
}
}
}
diff --git a/src/LispParser.kt b/src/LispParser.kt
index 1117397..e005c2d 100644
--- a/src/LispParser.kt
+++ b/src/LispParser.kt
@@ -49,6 +49,9 @@ class LispParser private constructor(filename: String, string: String) {
if (paren == "\"") {
return parseString()
}
+ if (paren in digits) {
+ return parseNumber()
+ }
if (paren == ":") {
return parseAtom()
}
@@ -56,6 +59,18 @@ class LispParser private constructor(filename: String, string: String) {
return LispAst.Reference(racer.span(start), ident)
}
+ fun parseNumber(): LispAst.NumberLiteral {
+ val start = racer.idx
+ racer.pushState()
+ val number = racer.consumeWhile { it.last().let { it in digits || it == '.' } }
+ val double = number.toDoubleOrNull()
+ if (double == null) {
+ racer.popState()
+ racer.error("Could not parse number")
+ }
+ racer.discardState()
+ return LispAst.NumberLiteral(racer.span(start), double)
+ }
fun parseAtom(): LispAst.Atom {
val start = racer.idx
diff --git a/test/res/test.lisp b/test/res/test.lisp
index f3d21d9..06e9f43 100644
--- a/test/res/test.lisp
+++ b/test/res/test.lisp
@@ -5,7 +5,4 @@
(debuglog a)
(def helloworld (pure "hello world"))
(debuglog helloworld (helloworld))
-(defun + () (seq
- (debuglog "also multiplication")
- (debuglog "addition")))
-(debuglog +)
+(debuglog + (+ 1.2 15))