Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhirkevich Alexander Y authored and Zhirkevich Alexander Y committed Sep 5, 2024
1 parent ef7f406 commit d8598fd
Show file tree
Hide file tree
Showing 29 changed files with 1,004 additions and 556 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package io.github.alexzhirkevich.skriptie

public object DummyInterpretationContext : InterpretationContext {
override fun interpret(callable: String?, args: List<Expression>?): Expression? {
return null
}
}

public interface InterpretationContext : Expression {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ public fun ScriptEngine.invoke(script: String) : Any? {
}

public fun ScriptEngine(
context: ScriptRuntime,
runtime: ScriptRuntime,
interpreter: ScriptInterpreter
): ScriptEngine = object : ScriptEngine, ScriptInterpreter by interpreter {
override val runtime: ScriptRuntime
get() = context
override val runtime: ScriptRuntime get() = runtime
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package io.github.alexzhirkevich.skriptie

import io.github.alexzhirkevich.skriptie.common.SyntaxError
import io.github.alexzhirkevich.skriptie.common.TypeError
import io.github.alexzhirkevich.skriptie.common.unresolvedReference


public enum class VariableType {
Expand All @@ -15,11 +14,11 @@ public interface ScriptRuntime : LangContext {

public val comparator : Comparator<Any?>

public operator fun contains(variable: String): Boolean
public operator fun contains(variable: Any?): Boolean

public operator fun get(variable: String): Any?
public operator fun get(variable: Any?): Any?

public fun set(variable: String, value: Any?, type: VariableType?)
public fun set(variable: Any?, value: Any?, type: VariableType?)

public fun withScope(
extraVariables: Map<String, Pair<VariableType, Any?>> = emptyMap(),
Expand All @@ -29,7 +28,7 @@ public interface ScriptRuntime : LangContext {
public fun reset()
}

private class BlockScriptContext(
private class ScopedRuntime(
private val parent : ScriptRuntime
) : DefaultRuntime(), LangContext by parent {

Expand All @@ -39,19 +38,19 @@ private class BlockScriptContext(
override val comparator: Comparator<Any?>
get() = parent.comparator

override fun get(variable: String): Any? {
override fun get(variable: Any?): Any? {
return if (variable in variables) {
super.get(variable)
} else {
parent.get(variable)
}
}

override fun contains(variable: String): Boolean {
override fun contains(variable: Any?): Boolean {
return super.contains(variable) || parent.contains(variable)
}

override fun set(variable: String, value: Any?, type: VariableType?) {
override fun set(variable: Any?, value: Any?, type: VariableType?) {
when {
type == VariableType.Global -> parent.set(variable, value, type)
type != null || variable in variables -> super.set(variable, value, type)
Expand All @@ -62,30 +61,27 @@ private class BlockScriptContext(

public abstract class DefaultRuntime : ScriptRuntime {

protected val variables: MutableMap<String, Pair<VariableType, Any?>> = mutableMapOf()
protected val variables: MutableMap<Any?, Pair<VariableType, Any?>> = mutableMapOf()

private val child by lazy {
BlockScriptContext(this)
ScopedRuntime(this)
}

override fun contains(variable: String): Boolean {
override fun contains(variable: Any?): Boolean {
return variable in variables
}

override fun set(variable: String, value: Any?, type: VariableType?) {
if (type == null && variable !in variables) {
unresolvedReference(variable)
}
override fun set(variable: Any?, value: Any?, type: VariableType?) {
if (type != null && variable in variables) {
throw SyntaxError("Identifier '$variable' is already declared")
}
if (type == null && variables[variable]?.first == VariableType.Const) {
throw TypeError("Assignment to constant variable ('$variable')")
}
variables[variable] = (type ?: variables[variable]?.first)!! to value
variables[variable] = (type ?: variables[variable]?.first ?: VariableType.Global) to value
}

override fun get(variable: String): Any? {
override fun get(variable: Any?): Any? {
return if (contains(variable))
variables[variable]?.second
else Unit
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
package io.github.alexzhirkevich.skriptie.common

public sealed class SkriptieError(message : String?, cause : Throwable?) : Exception(message, cause)
import io.github.alexzhirkevich.skriptie.ecmascript.ESAny

public sealed class SkriptieError(message : String?, cause : Throwable?) : Exception(message, cause), ESAny {
override fun get(variable: Any?): Any? {
return when(variable){
"message" -> message
"stack" -> stackTraceToString()
"name" -> this::class.simpleName
else -> Unit
}
}
}

public class SyntaxError(message : String? = null, cause : Throwable? = null) : SkriptieError(message, cause)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,30 @@ package io.github.alexzhirkevich.skriptie.common
import io.github.alexzhirkevich.skriptie.Expression
import io.github.alexzhirkevich.skriptie.ScriptRuntime
import io.github.alexzhirkevich.skriptie.VariableType
import io.github.alexzhirkevich.skriptie.ecmascript.ESAny
import io.github.alexzhirkevich.skriptie.ecmascript.ESObject
import io.github.alexzhirkevich.skriptie.invoke

internal class OpAssign(
val type : VariableType? = null,
val variableName : String,
val receiver : Expression?=null,
val assignableValue : Expression,
private val merge : ((Any?, Any?) -> Any?)?
) : Expression {

override fun invokeRaw(context: ScriptRuntime): Any? {
val v = assignableValue.invoke(context)

val current = context.get(variableName)
val r = receiver?.invoke(context)

val current = if (receiver == null) {
context[variableName]
} else {
when (r){
is ESAny -> r[variableName]
else -> null
}
}

check(merge == null || current != null) {
"Cant modify $variableName as it is undefined"
Expand All @@ -25,11 +36,18 @@ internal class OpAssign(
merge.invoke(current, v)
} else v

context.set(
variable = variableName,
value = value,
type = type
)
if (receiver == null) {
context.set(
variable = variableName,
value = value,
type = type
)
} else {
when (r) {
is ESObject -> r[variableName] = value
else -> throw TypeError("Cannot set properties of ${if (r == Unit) "undefined" else r} (setting '$variableName')")
}
}

return value
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.github.alexzhirkevich.skriptie.common
import io.github.alexzhirkevich.skriptie.Expression
import io.github.alexzhirkevich.skriptie.ScriptRuntime
import io.github.alexzhirkevich.skriptie.VariableType
import io.github.alexzhirkevich.skriptie.ecmascript.ESObject
import io.github.alexzhirkevich.skriptie.invoke
import io.github.alexzhirkevich.skriptie.javascript.JsArray

Expand All @@ -26,17 +27,20 @@ internal class OpAssignByIndex(
context.set(variableName, mutableListOf<Any>(), scope)
return invoke(context)
} else {
val i = context.toNumber(index.invoke(context))

check(!i.toDouble().isNaN()) {
"Unexpected index: $i"
}

val index = i.toInt()
val idx = index(context)

return when (current) {

is JsArray-> {
val i = context.toNumber(idx)

check(!i.toDouble().isNaN()) {
"Unexpected index: $i"
}
val index = i.toInt()

while (current.value.lastIndex < index) {
current.value.add(Unit)
}
Expand All @@ -50,6 +54,18 @@ internal class OpAssignByIndex(
}
current.value[index]
}
is ESObject -> {
val idxNorm = when (idx){
is CharSequence -> idx.toString()
else -> idx
}

if (idxNorm in current && merge != null){
current[idxNorm] = merge.invoke(current[idxNorm], v)
} else {
current[idxNorm] = v
}
}
else -> error("Can't assign '$current' by index ($index)")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@ internal value class OpConstant(val value: Any?) : Expression {
}
}

private object UNINITIALIZED

internal class OpLazy(
private val init : (ScriptRuntime) -> Any?
) : Expression {

private var value : Any? = UNINITIALIZED

override fun invokeRaw(context: ScriptRuntime): Any? {

if (value is UNINITIALIZED){
value = init(context)
}

return value
}
}

internal class OpGetVariable(
val name : String,
val receiver : Expression?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@ import io.github.alexzhirkevich.skriptie.Expression
import io.github.alexzhirkevich.skriptie.invoke


internal fun OpIfCondition(
condition : Expression = OpConstant(true),
internal fun OpIfCondition(
condition : Expression,
onTrue : Expression? = null,
onFalse : Expression? = null
onFalse : Expression? = null,
expressible : Boolean = false
) = Expression {
val expr = if (condition(it) as Boolean){
onTrue
} else {
onFalse
}
val expr = if (it.isFalse(condition(it))) onFalse else onTrue

expr?.invoke(it)
val res = expr?.invoke(it)

Unit
if (expressible) {
res
} else {
Unit
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ internal class OpIndex(
val index : Expression,
) : Expression {

override fun invokeRaw(context: ScriptRuntime): Any {
override fun invokeRaw(context: ScriptRuntime): Any? {
return invoke(context, variable, index)
}

companion object {
fun invoke(context: ScriptRuntime, variable : Expression, index : Expression) : Any{
fun invoke(context: ScriptRuntime, variable : Expression, index : Expression) : Any? {
val v = checkNotEmpty(variable(context))
val idx = (index(context).let(context::toNumber)).toInt()
val idx = index(context)

return v.valueAtIndexOrUnit(idx)
return v.valueAtIndexOrUnit(idx, context.toNumber(idx).toInt())
}
}
}
Loading

0 comments on commit d8598fd

Please sign in to comment.