187 lines
5.3 KiB
Kotlin
187 lines
5.3 KiB
Kotlin
package net.sergeych.ling
|
|
|
|
fun String.toSource(name: String = "eval"): Source = Source(name, this)
|
|
|
|
|
|
@Suppress("unused")
|
|
abstract class Statement(
|
|
val isStaticConst: Boolean = false,
|
|
val isConst: Boolean = false,
|
|
val returnType: Type = Type.Any
|
|
) : Obj() {
|
|
|
|
abstract val pos: Pos
|
|
abstract suspend fun execute(context: Context): Obj
|
|
|
|
override fun compareTo(other: Obj): Int {
|
|
throw UnsupportedOperationException("not comparable")
|
|
}
|
|
|
|
}
|
|
|
|
fun Statement.raise(text: String): Nothing {
|
|
throw ScriptError(pos, text)
|
|
}
|
|
|
|
@Suppress("unused")
|
|
fun Statement.require(cond: Boolean, message: () -> String) {
|
|
if (!cond) raise(message())
|
|
}
|
|
|
|
fun statement(pos: Pos, isStaticConst: Boolean = false, f: suspend (Context) -> Obj): Statement =
|
|
object : Statement(isStaticConst) {
|
|
override val pos: Pos = pos
|
|
override suspend fun execute(context: Context): Obj = f(context)
|
|
}
|
|
|
|
class LogicalAndStatement(
|
|
override val pos: Pos,
|
|
val left: Statement, val right: Statement
|
|
) : Statement() {
|
|
override suspend fun execute(context: Context): Obj {
|
|
|
|
val l = left.execute(context).let {
|
|
(it as? ObjBool) ?: raise("left operand is not boolean: $it")
|
|
}
|
|
val r = right.execute(context).let {
|
|
(it as? ObjBool) ?: raise("right operand is not boolean: $it")
|
|
}
|
|
return ObjBool(l.value && r.value)
|
|
}
|
|
}
|
|
|
|
class LogicalOrStatement(
|
|
override val pos: Pos,
|
|
val left: Statement, val right: Statement
|
|
) : Statement() {
|
|
override suspend fun execute(context: Context): Obj {
|
|
|
|
val l = left.execute(context).let {
|
|
(it as? ObjBool) ?: raise("left operand is not boolean: $it")
|
|
}
|
|
val r = right.execute(context).let {
|
|
(it as? ObjBool) ?: raise("right operand is not boolean: $it")
|
|
}
|
|
return ObjBool(l.value || r.value)
|
|
}
|
|
}
|
|
|
|
class PlusStatement(
|
|
override val pos: Pos,
|
|
val left: Statement, val right: Statement
|
|
) : Statement() {
|
|
override suspend fun execute(context: Context): Obj {
|
|
// todo: implement also classes with 'plus' operator
|
|
val l = left.execute(context)
|
|
|
|
if (l is ObjString)
|
|
return ObjString(l.toString() + right.execute(context).asStr)
|
|
|
|
if (l !is Numeric)
|
|
raise("left operand is not number: $l")
|
|
|
|
val r = right.execute(context)
|
|
if (r !is Numeric)
|
|
raise("right operand is not boolean: $r")
|
|
|
|
return if (l is ObjInt && r is ObjInt)
|
|
ObjInt(l.longValue + r.longValue)
|
|
else
|
|
ObjReal(l.doubleValue + r.doubleValue)
|
|
}
|
|
}
|
|
|
|
class MinusStatement(
|
|
override val pos: Pos,
|
|
val left: Statement, val right: Statement
|
|
) : Statement() {
|
|
override suspend fun execute(context: Context): Obj {
|
|
// todo: implement also classes with 'minus' operator
|
|
val l = left.execute(context)
|
|
if (l !is Numeric)
|
|
raise("left operand is not number: $l")
|
|
|
|
val r = right.execute(context)
|
|
if (r !is Numeric)
|
|
raise("right operand is not number: $r")
|
|
|
|
return if (l is ObjInt && r is ObjInt)
|
|
ObjInt(l.longValue - r.longValue)
|
|
else
|
|
ObjReal(l.doubleValue - r.doubleValue)
|
|
}
|
|
}
|
|
|
|
class MulStatement(
|
|
override val pos: Pos,
|
|
val left: Statement, val right: Statement
|
|
) : Statement() {
|
|
override suspend fun execute(context: Context): Obj {
|
|
val l = left.execute(context)
|
|
if (l !is Numeric)
|
|
raise("left operand is not number: $l")
|
|
|
|
val r = right.execute(context)
|
|
if (r !is Numeric)
|
|
raise("right operand is not number: $r")
|
|
|
|
return if (l is ObjInt && r is ObjInt)
|
|
ObjInt(l.longValue * r.longValue)
|
|
else
|
|
ObjReal(l.doubleValue * r.doubleValue)
|
|
}
|
|
}
|
|
|
|
class DivStatement(
|
|
override val pos: Pos,
|
|
val left: Statement, val right: Statement
|
|
) : Statement() {
|
|
override suspend fun execute(context: Context): Obj {
|
|
val l = left.execute(context)
|
|
if (l !is Numeric)
|
|
raise("left operand is not number: $l")
|
|
|
|
val r = right.execute(context)
|
|
if (r !is Numeric)
|
|
raise("right operand is not number: $r")
|
|
|
|
return if (l is ObjInt && r is ObjInt)
|
|
ObjInt(l.longValue / r.longValue)
|
|
else
|
|
ObjReal(l.doubleValue / r.doubleValue)
|
|
}
|
|
}
|
|
|
|
class ModStatement(
|
|
override val pos: Pos,
|
|
val left: Statement, val right: Statement
|
|
) : Statement() {
|
|
override suspend fun execute(context: Context): Obj {
|
|
val l = left.execute(context)
|
|
if (l !is Numeric)
|
|
raise("left operand is not number: $l")
|
|
|
|
val r = right.execute(context)
|
|
if (r !is Numeric)
|
|
raise("right operand is not number: $r")
|
|
|
|
return if (l is ObjInt && r is ObjInt)
|
|
ObjInt(l.longValue % r.longValue)
|
|
else
|
|
ObjReal(l.doubleValue % r.doubleValue)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
class AssignStatement(override val pos: Pos, val name: String, val value: Statement) : Statement() {
|
|
override suspend fun execute(context: Context): Obj {
|
|
val variable = context[name] ?: raise("can't assign: variable does not exist: $name")
|
|
if (!variable.isMutable)
|
|
throw ScriptError(pos, "can't reassign val $name")
|
|
variable.value = value.execute(context)
|
|
return ObjVoid
|
|
}
|
|
}
|
|
|