From 361c1d5b1362d89bfd0f7c95c606133055da1ce7 Mon Sep 17 00:00:00 2001 From: sergeych Date: Mon, 26 May 2025 23:51:22 +0400 Subject: [PATCH] big refactoring: all tests passed --- .../kotlin/net/sergeych/ling/Compiler.kt | 50 +++++++++++++------ library/src/commonTest/kotlin/ScriptTest.kt | 15 ++++++ 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/library/src/commonMain/kotlin/net/sergeych/ling/Compiler.kt b/library/src/commonMain/kotlin/net/sergeych/ling/Compiler.kt index 261b1cc..8c25d1c 100644 --- a/library/src/commonMain/kotlin/net/sergeych/ling/Compiler.kt +++ b/library/src/commonMain/kotlin/net/sergeych/ling/Compiler.kt @@ -283,27 +283,49 @@ class Compiler { operand = Accessor { statement.execute(it) } + cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true) cc.skipTokenOfType(Token.Type.RPAREN, "missing ')'") } } Token.Type.ID -> { - operand?.let { left -> - // selector: , '.' , - // we replace operand with selector code, that - // is RW: - operand = Accessor({ - it.pos = t.pos - left.getter(it).readField(it, t.value) - }) { cxt, newValue -> - cxt.pos = t.pos - left.getter(cxt).writeField(cxt, t.value, newValue) + // there could be terminal operators or keywords:// variable to read or like + when (t.value) { + "else" -> { + cc.previous() + return operand?.let { op -> statement(startPos) { op.getter(it) } } + } + "if", "when", "do", "while", "return" -> { + if( operand != null ) throw ScriptError(t.pos, "unexpected keyword") + cc.previous() + val s = parseStatement(cc) ?: throw ScriptError(t.pos, "Expecting valid statement") + operand = Accessor { s.execute(it) } + } + "break", "continue" -> { + cc.previous() + return operand?.let { op -> statement(startPos) { op.getter(it) } } + + } + else -> operand?.let { left -> + // selector: , '.' , + // we replace operand with selector code, that + // is RW: + operand = Accessor({ + it.pos = t.pos + left.getter(it).readField(it, t.value) + }) { cxt, newValue -> + cxt.pos = t.pos + left.getter(cxt).writeField(cxt, t.value, newValue) + } + } ?: run { + // variable to read or like + cc.previous() + operand = parseAccessor(cc) } - } ?: run { - // variable to read or like - cc.previous() - operand = parseAccessor(cc) } + // selector: , '.' , + // we replace operand with selector code, that + // is RW: } Token.Type.PLUS2 -> { diff --git a/library/src/commonTest/kotlin/ScriptTest.kt b/library/src/commonTest/kotlin/ScriptTest.kt index 266e80d..e28ec50 100644 --- a/library/src/commonTest/kotlin/ScriptTest.kt +++ b/library/src/commonTest/kotlin/ScriptTest.kt @@ -443,6 +443,7 @@ class ScriptTest { """ val count = 3 val res = if( count > 10 ) "too much" else "just " + count + println(count) println(res) res """.trimIndent() @@ -549,4 +550,18 @@ class ScriptTest { // assertEquals( "4", c.eval("x+0").toString()) } + @Test + fun bookTest2() = runTest { + val src = """ + fn check(amount, prefix = "answer: ") { + prefix + if( amount > 100 ) + "enough" + else + "more" + + } + """.trimIndent() + eval(src) + } + } \ No newline at end of file