diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/BlockStatement.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/BlockStatement.kt index 74c2395..7f9bd22 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/BlockStatement.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/BlockStatement.kt @@ -28,21 +28,7 @@ class BlockStatement( override val pos: Pos = startPos override suspend fun execute(scope: Scope): Obj { - val target = if (scope.skipScopeCreation) scope else scope.createChildScope(startPos) - if (slotPlan.isNotEmpty()) target.applySlotPlan(slotPlan) - if (captureSlots.isNotEmpty()) { - val captureRecords = scope.captureRecords - if (captureRecords == null) { - scope.raiseIllegalState("missing bytecode capture records") - } - for (i in captureSlots.indices) { - val capture = captureSlots[i] - val rec = captureRecords.getOrNull(i) - ?: scope.raiseSymbolNotFound("capture ${capture.name} not found") - target.updateSlotFor(capture.name, rec) - } - } - return block.execute(target) + return interpreterDisabled(scope, "block statement") } fun statements(): List = block.debugStatements() diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ClassInstanceDeclStatements.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ClassInstanceDeclStatements.kt index 8208c90..5740f2c 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ClassInstanceDeclStatements.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ClassInstanceDeclStatements.kt @@ -17,20 +17,14 @@ package net.sergeych.lyng import net.sergeych.lyng.obj.Obj -import net.sergeych.lyng.obj.ObjClass import net.sergeych.lyng.obj.ObjProperty -import net.sergeych.lyng.obj.ObjRecord -import net.sergeych.lyng.obj.ObjVoid class ClassInstanceInitDeclStatement( val initStatement: Statement, override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - val cls = scope.thisObj as? ObjClass - ?: scope.raiseIllegalState("instance init declaration requires class scope") - cls.instanceInitializers += initStatement - return ObjVoid + return interpreterDisabled(scope, "class instance init declaration") } } @@ -48,24 +42,7 @@ class ClassInstanceFieldDeclStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - val cls = scope.thisObj as? ObjClass - ?: scope.raiseIllegalState("instance field declaration requires class scope") - cls.createField( - name, - net.sergeych.lyng.obj.ObjNull, - isMutable = isMutable, - visibility = visibility, - writeVisibility = writeVisibility, - isAbstract = isAbstract, - isClosed = isClosed, - isOverride = isOverride, - isTransient = isTransient, - declaringClass = cls, - type = ObjRecord.Type.Field, - fieldId = fieldId - ) - if (!isAbstract) initStatement?.let { cls.instanceInitializers += it } - return ObjVoid + return interpreterDisabled(scope, "class instance field declaration") } } @@ -84,22 +61,7 @@ class ClassInstancePropertyDeclStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - val cls = scope.thisObj as? ObjClass - ?: scope.raiseIllegalState("instance property declaration requires class scope") - cls.addProperty( - name = name, - visibility = visibility, - writeVisibility = writeVisibility, - declaringClass = cls, - isAbstract = isAbstract, - isClosed = isClosed, - isOverride = isOverride, - pos = pos, - prop = prop, - methodId = methodId - ) - if (!isAbstract) initStatement?.let { cls.instanceInitializers += it } - return ObjVoid + return interpreterDisabled(scope, "class instance property declaration") } } @@ -117,23 +79,6 @@ class ClassInstanceDelegatedDeclStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - val cls = scope.thisObj as? ObjClass - ?: scope.raiseIllegalState("instance delegated declaration requires class scope") - cls.createField( - name, - net.sergeych.lyng.obj.ObjUnset, - isMutable = isMutable, - visibility = visibility, - writeVisibility = writeVisibility, - isAbstract = isAbstract, - isClosed = isClosed, - isOverride = isOverride, - isTransient = isTransient, - declaringClass = cls, - type = ObjRecord.Type.Delegated, - methodId = methodId - ) - if (!isAbstract) initStatement?.let { cls.instanceInitializers += it } - return ObjVoid + return interpreterDisabled(scope, "class instance delegated declaration") } } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt index e71b2ba..61391c0 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Compiler.kt @@ -1928,6 +1928,64 @@ class Compiler( ) } + private fun wrapDefaultArgsBytecode( + args: ArgsDeclaration, + forcedLocalSlots: Map, + forcedLocalScopeId: Int + ): ArgsDeclaration { + if (!compileBytecode) return args + if (args.params.none { it.defaultValue is Statement }) return args + val updated = args.params.map { param -> + val defaultValue = param.defaultValue + val stmt = defaultValue as? Statement + if (stmt == null) return@map param + val bytecode = when (stmt) { + is BytecodeStatement -> stmt + is BytecodeBodyProvider -> stmt.bytecodeBody() + else -> null + } + if (bytecode != null) { + param + } else { + val wrapped = wrapFunctionBytecode( + stmt, + "argDefault@${param.name}", + forcedLocalSlots = forcedLocalSlots, + forcedLocalScopeId = forcedLocalScopeId + ) + param.copy(defaultValue = wrapped) + } + } + return if (updated == args.params) args else args.copy(params = updated) + } + + private fun wrapParsedArgsBytecode( + args: List?, + forcedLocalSlots: Map = emptyMap(), + forcedLocalScopeId: Int? = null + ): List? { + if (!compileBytecode || args == null || args.isEmpty()) return args + var changed = false + val updated = args.mapIndexed { index, arg -> + val stmt = arg.value as? Statement ?: return@mapIndexed arg + val bytecode = when (stmt) { + is BytecodeStatement -> stmt + is BytecodeBodyProvider -> stmt.bytecodeBody() + else -> null + } + if (bytecode != null) return@mapIndexed arg + val wrapped = wrapFunctionBytecode( + stmt, + "arg@${index}", + forcedLocalSlots = forcedLocalSlots, + forcedLocalScopeId = forcedLocalScopeId + ) + changed = true + arg.copy(value = wrapped) + } + return if (changed) updated else args + } + private fun containsDelegatedRefs(stmt: Statement): Boolean { val target = if (stmt is BytecodeStatement) stmt.original else stmt return when (target) { @@ -5827,6 +5885,7 @@ class Compiler( if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true)) { argsList = parseArgsNoTailBlock() } + argsList = wrapParsedArgsBytecode(argsList) baseSpecs += BaseSpec(baseId.value, argsList) } while (cc.skipTokenOfType(Token.Type.COMMA, isOptional = true)) } @@ -5978,7 +6037,7 @@ class Compiler( val classTypeParams = typeParamDecls.map { it.name }.toSet() classCtx?.typeParams = classTypeParams pendingTypeParamStack.add(classTypeParams) - val constructorArgsDeclaration: ArgsDeclaration? + var constructorArgsDeclaration: ArgsDeclaration? try { constructorArgsDeclaration = if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true)) @@ -6009,6 +6068,16 @@ class Compiler( val mutable = param.accessType?.isMutable ?: false declareSlotNameIn(classSlotPlan, param.name, mutable, isDelegated = false) } + val ctorForcedLocalSlots = LinkedHashMap() + if (constructorArgsDeclaration != null) { + val snapshot = slotPlanIndices(classSlotPlan) + for (param in constructorArgsDeclaration!!.params) { + val idx = snapshot[param.name] ?: continue + ctorForcedLocalSlots[param.name] = idx + } + constructorArgsDeclaration = + wrapDefaultArgsBytecode(constructorArgsDeclaration!!, ctorForcedLocalSlots, classSlotPlan.id) + } constructorArgsDeclaration?.params?.forEach { param -> if (param.accessType != null) { classCtx?.declaredMembers?.add(param.name) @@ -6036,6 +6105,7 @@ class Compiler( // Parse args without consuming any following block so that a class body can follow safely argsList = parseArgsNoTailBlock() } + argsList = wrapParsedArgsBytecode(argsList, ctorForcedLocalSlots, classSlotPlan.id) baseSpecs += BaseSpec(baseName, argsList) } while (cc.skipTokenOfType(Token.Type.COMMA, isOptional = true)) } @@ -6717,7 +6787,7 @@ class Compiler( } val typeParams = mergedTypeParamDecls.map { it.name }.toSet() pendingTypeParamStack.add(typeParams) - val argsDeclaration: ArgsDeclaration + var argsDeclaration: ArgsDeclaration val returnTypeMini: MiniTypeRef? val returnTypeDecl: TypeDecl? try { @@ -6811,6 +6881,17 @@ class Compiler( val typeParamNames = mergedTypeParamDecls.map { it.name } val paramNames: Set = paramNamesList.toSet() val paramSlotPlan = buildParamSlotPlan(paramNamesList + typeParamNames) + val paramSlotPlanSnapshot = slotPlanIndices(paramSlotPlan) + val forcedLocalSlots = LinkedHashMap() + for (name in paramNamesList) { + val idx = paramSlotPlanSnapshot[name] ?: continue + forcedLocalSlots[name] = idx + } + for (name in typeParamNames) { + val idx = paramSlotPlanSnapshot[name] ?: continue + forcedLocalSlots[name] = idx + } + argsDeclaration = wrapDefaultArgsBytecode(argsDeclaration, forcedLocalSlots, paramSlotPlan.id) val capturePlan = CapturePlan(paramSlotPlan, isFunction = true, propagateToParentFunction = false) val rangeParamNames = argsDeclaration.params .filter { isRangeType(it.type) } @@ -6887,12 +6968,6 @@ class Compiler( inferredReturnClass } } - val paramSlotPlanSnapshot = slotPlanIndices(paramSlotPlan) - val forcedLocalSlots = LinkedHashMap() - for (name in paramNamesList) { - val idx = paramSlotPlanSnapshot[name] ?: continue - forcedLocalSlots[name] = idx - } val fnStatements = rawFnStatements?.let { stmt -> if (!compileBytecode) return@let stmt val paramKnownClasses = mutableMapOf() diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/DelegatedVarDeclStatement.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/DelegatedVarDeclStatement.kt index 1c63adb..1ac1bce 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/DelegatedVarDeclStatement.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/DelegatedVarDeclStatement.kt @@ -18,9 +18,6 @@ package net.sergeych.lyng import net.sergeych.lyng.obj.Obj -import net.sergeych.lyng.obj.ObjNull -import net.sergeych.lyng.obj.ObjRecord -import net.sergeych.lyng.obj.ObjString class DelegatedVarDeclStatement( val name: String, @@ -35,23 +32,6 @@ class DelegatedVarDeclStatement( override val pos: Pos = startPos override suspend fun execute(context: Scope): Obj { - val initValue = initializer.execute(context) - val accessTypeStr = if (isMutable) "Var" else "Val" - val accessType = ObjString(accessTypeStr) - val finalDelegate = try { - initValue.invokeInstanceMethod(context, "bind", Arguments(ObjString(name), accessType, ObjNull)) - } catch (e: Exception) { - initValue - } - val rec = context.addItem( - name, - isMutable, - ObjNull, - visibility, - recordType = ObjRecord.Type.Delegated, - isTransient = isTransient - ) - rec.delegate = finalDelegate - return finalDelegate + return interpreterDisabled(context, "delegated var declaration") } } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/DestructuringVarDeclStatement.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/DestructuringVarDeclStatement.kt index c0f9533..45066e3 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/DestructuringVarDeclStatement.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/DestructuringVarDeclStatement.kt @@ -18,7 +18,6 @@ package net.sergeych.lyng import net.sergeych.lyng.obj.ListLiteralRef import net.sergeych.lyng.obj.Obj -import net.sergeych.lyng.obj.ObjVoid class DestructuringVarDeclStatement( val pattern: ListLiteralRef, @@ -30,20 +29,6 @@ class DestructuringVarDeclStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(context: Scope): Obj { - val value = initializer.execute(context) - for (name in names) { - context.addItem(name, true, ObjVoid, visibility, isTransient = isTransient) - } - pattern.setAt(pos, context, value) - if (!isMutable) { - for (name in names) { - val rec = context.objects[name]!! - val immutableRec = rec.copy(isMutable = false) - context.objects[name] = immutableRec - context.localBindings[name] = immutableRec - context.updateSlotFor(name, immutableRec) - } - } - return ObjVoid + return interpreterDisabled(context, "destructuring declaration") } } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/EnumDeclStatement.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/EnumDeclStatement.kt index 1fe5a60..54b536f 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/EnumDeclStatement.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/EnumDeclStatement.kt @@ -17,8 +17,6 @@ package net.sergeych.lyng import net.sergeych.lyng.obj.Obj -import net.sergeych.lyng.obj.ObjEnumClass -import net.sergeych.lyng.obj.ObjRecord class EnumDeclStatement( val declaredName: String, @@ -30,17 +28,7 @@ class EnumDeclStatement( override val pos: Pos = startPos override suspend fun execute(scope: Scope): Obj { - val enumClass = ObjEnumClass.createSimpleEnum(qualifiedName, entries) - scope.addItem(declaredName, false, enumClass, recordType = ObjRecord.Type.Enum) - if (lifted) { - for (entry in entries) { - val rec = enumClass.getInstanceMemberOrNull(entry, includeAbstract = false, includeStatic = true) - if (rec != null) { - scope.addItem(entry, false, rec.value) - } - } - } - return enumClass + return interpreterDisabled(scope, "enum declaration") } override suspend fun callOn(scope: Scope): Obj { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ExtensionPropertyDeclStatement.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ExtensionPropertyDeclStatement.kt index 458c39b..477fbfd 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ExtensionPropertyDeclStatement.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/ExtensionPropertyDeclStatement.kt @@ -17,11 +17,7 @@ package net.sergeych.lyng import net.sergeych.lyng.obj.Obj -import net.sergeych.lyng.obj.ObjClass -import net.sergeych.lyng.obj.ObjExtensionPropertyGetterCallable -import net.sergeych.lyng.obj.ObjExtensionPropertySetterCallable import net.sergeych.lyng.obj.ObjProperty -import net.sergeych.lyng.obj.ObjRecord class ExtensionPropertyDeclStatement( val extTypeName: String, @@ -33,28 +29,6 @@ class ExtensionPropertyDeclStatement( override val pos: Pos = startPos override suspend fun execute(context: Scope): Obj { - val type = context[extTypeName]?.value ?: context.raiseSymbolNotFound("class $extTypeName not found") - if (type !is ObjClass) context.raiseClassCastError("$extTypeName is not the class instance") - context.addExtension( - type, - property.name, - ObjRecord( - property, - isMutable = false, - visibility = visibility, - writeVisibility = setterVisibility, - declaringClass = null, - type = ObjRecord.Type.Property - ) - ) - val getterName = extensionPropertyGetterName(extTypeName, property.name) - val getterWrapper = ObjExtensionPropertyGetterCallable(property.name, property) - context.addItem(getterName, false, getterWrapper, visibility, recordType = ObjRecord.Type.Fun) - if (property.setter != null) { - val setterName = extensionPropertySetterName(extTypeName, property.name) - val setterWrapper = ObjExtensionPropertySetterCallable(property.name, property) - context.addItem(setterName, false, setterWrapper, visibility, recordType = ObjRecord.Type.Fun) - } - return property + return interpreterDisabled(context, "extension property declaration") } } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/TryStatement.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/TryStatement.kt index d9bacf9..e067428 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/TryStatement.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/TryStatement.kt @@ -19,8 +19,6 @@ package net.sergeych.lyng import net.sergeych.lyng.obj.Obj import net.sergeych.lyng.obj.ObjClass import net.sergeych.lyng.obj.ObjException -import net.sergeych.lyng.obj.ObjUnknownException -import net.sergeych.lyng.obj.ObjVoid class TryStatement( val body: Statement, @@ -38,43 +36,7 @@ class TryStatement( ) override suspend fun execute(scope: Scope): Obj { - var result: Obj = ObjVoid - try { - result = body.execute(scope) - } catch (e: ReturnException) { - throw e - } catch (e: LoopBreakContinueException) { - throw e - } catch (e: Exception) { - val caughtObj = when (e) { - is ExecutionError -> e.errorObject - else -> ObjUnknownException(scope, e.message ?: e.toString()) - } - var isCaught = false - for (cdata in catches) { - var match: Obj? = null - for (exceptionClassName in cdata.classNames) { - val exObj = resolveExceptionClass(scope, exceptionClassName) - if (caughtObj.isInstanceOf(exObj)) { - match = caughtObj - break - } - } - if (match != null) { - val catchContext = scope.createChildScope(pos = cdata.catchVarPos).apply { - skipScopeCreation = true - } - catchContext.addItem(cdata.catchVarName, false, caughtObj) - result = cdata.block.execute(catchContext) - isCaught = true - break - } - } - if (!isCaught) throw e - } finally { - finallyClause?.execute(scope) - } - return result + return interpreterDisabled(scope, "try statement") } private fun resolveExceptionClass(scope: Scope, name: String): ObjClass { diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/VarDeclStatement.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/VarDeclStatement.kt index d9a1d6e..03d312f 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/VarDeclStatement.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/VarDeclStatement.kt @@ -18,9 +18,6 @@ package net.sergeych.lyng import net.sergeych.lyng.obj.Obj import net.sergeych.lyng.obj.ObjClass -import net.sergeych.lyng.obj.ObjNull -import net.sergeych.lyng.obj.ObjRecord -import net.sergeych.lyng.obj.ObjUnset class VarDeclStatement( val name: String, @@ -36,15 +33,6 @@ class VarDeclStatement( override val pos: Pos = startPos override suspend fun execute(context: Scope): Obj { - val initValue = initializer?.execute(context)?.byValueCopy() ?: ObjUnset - context.addItem( - name, - isMutable, - initValue, - visibility, - recordType = ObjRecord.Type.Other, - isTransient = isTransient - ) - return initValue + return interpreterDisabled(context, "var declaration") } } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/WhenStatement.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/WhenStatement.kt index cb04d8c..ea2edb9 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/WhenStatement.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/WhenStatement.kt @@ -17,7 +17,6 @@ package net.sergeych.lyng import net.sergeych.lyng.obj.Obj -import net.sergeych.lyng.obj.ObjVoid sealed class WhenCondition(open val expr: Statement, open val pos: Pos) { abstract suspend fun matches(scope: Scope, value: Obj): Boolean @@ -67,14 +66,6 @@ class WhenStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - val whenValue = value.execute(scope) - for (case in cases) { - for (condition in case.conditions) { - if (condition.matches(scope, whenValue)) { - return case.block.execute(scope) - } - } - } - return elseCase?.execute(scope) ?: ObjVoid + return interpreterDisabled(scope, "when statement") } } diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/statements.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/statements.kt index 5f0458b..39d3f7a 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/statements.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/statements.kt @@ -19,10 +19,10 @@ package net.sergeych.lyng import net.sergeych.lyng.obj.Obj import net.sergeych.lyng.obj.ObjClass +import net.sergeych.lyng.obj.ObjException import net.sergeych.lyng.obj.ObjInt import net.sergeych.lyng.obj.ObjIterable import net.sergeych.lyng.obj.ObjNull -import net.sergeych.lyng.obj.ObjException import net.sergeych.lyng.obj.ObjRange import net.sergeych.lyng.obj.ObjRecord import net.sergeych.lyng.obj.ObjString @@ -71,6 +71,10 @@ abstract class Statement( suspend fun call(scope: Scope, vararg args: Obj) = execute(scope.createChildScope(args = Arguments(*args))) + protected fun interpreterDisabled(scope: Scope, label: String): Nothing { + return scope.raiseIllegalState("interpreter execution is not supported; $label requires bytecode") + } + } class IfStatement( @@ -80,11 +84,7 @@ class IfStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - return if (condition.execute(scope).toBool()) { - ifBody.execute(scope) - } else { - elseBody?.execute(scope) ?: ObjVoid - } + return interpreterDisabled(scope, "if statement") } } @@ -103,89 +103,7 @@ class ForInStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - val forContext = scope.createChildScope(pos) - if (loopSlotPlan.isNotEmpty()) { - forContext.applySlotPlan(loopSlotPlan) - } - - val loopSO = forContext.addItem(loopVarName, true, ObjNull) - val loopSlotIndex = forContext.getSlotIndexOf(loopVarName) ?: -1 - - if (constRange != null && PerfFlags.PRIMITIVE_FASTOPS) { - return loopIntRange( - forContext, - constRange.start, - constRange.endExclusive, - loopSO, - loopSlotIndex, - body, - elseStatement, - label, - canBreak - ) - } - - val sourceObj = source.execute(forContext) - return if (sourceObj is ObjRange && sourceObj.isIntRange && !sourceObj.hasExplicitStep && PerfFlags.PRIMITIVE_FASTOPS) { - loopIntRange( - forContext, - sourceObj.start!!.toLong(), - if (sourceObj.isEndInclusive) sourceObj.end!!.toLong() + 1 else sourceObj.end!!.toLong(), - loopSO, - loopSlotIndex, - body, - elseStatement, - label, - canBreak - ) - } else if (sourceObj.isInstanceOf(ObjIterable)) { - loopIterable(forContext, sourceObj, loopSO, body, elseStatement, label, canBreak) - } else { - val size = runCatching { sourceObj.readField(forContext, "size").value.toInt() } - .getOrElse { - throw ScriptError( - pos, - "object is not enumerable: no size in $sourceObj", - it - ) - } - - var result: Obj = ObjVoid - var breakCaught = false - - if (size > 0) { - var current = runCatching { sourceObj.getAt(forContext, ObjInt.of(0)) } - .getOrElse { - throw ScriptError( - pos, - "object is not enumerable: no index access for ${sourceObj.inspect(scope)}", - it - ) - } - var index = 0 - while (true) { - loopSO.value = current - try { - result = body.execute(forContext) - } catch (lbe: LoopBreakContinueException) { - if (lbe.label == label || lbe.label == null) { - breakCaught = true - if (lbe.doContinue) continue - result = lbe.result - break - } else { - throw lbe - } - } - if (++index >= size) break - current = sourceObj.getAt(forContext, ObjInt.of(index.toLong())) - } - } - if (!breakCaught && elseStatement != null) { - result = elseStatement.execute(scope) - } - result - } + return interpreterDisabled(scope, "for-in statement") } private suspend fun loopIntRange( @@ -310,29 +228,7 @@ class WhileStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - var result: Obj = ObjVoid - var wasBroken = false - while (condition.execute(scope).toBool()) { - val loopScope = scope.createChildScope().apply { skipScopeCreation = true } - if (canBreak) { - try { - result = body.execute(loopScope) - } catch (lbe: LoopBreakContinueException) { - if (lbe.label == label || lbe.label == null) { - if (lbe.doContinue) continue - result = lbe.result - wasBroken = true - break - } else { - throw lbe - } - } - } else { - result = body.execute(loopScope) - } - } - if (!wasBroken) elseStatement?.let { s -> result = s.execute(scope) } - return result + return interpreterDisabled(scope, "while statement") } } @@ -345,30 +241,7 @@ class DoWhileStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - var wasBroken = false - var result: Obj = ObjVoid - while (true) { - val doScope = scope.createChildScope().apply { skipScopeCreation = true } - try { - result = body.execute(doScope) - } catch (e: LoopBreakContinueException) { - if (e.label == label || e.label == null) { - if (!e.doContinue) { - result = e.result - wasBroken = true - break - } - // continue: fall through to condition check - } else { - throw e - } - } - if (!condition.execute(doScope).toBool()) { - break - } - } - if (!wasBroken) elseStatement?.let { s -> result = s.execute(scope) } - return result + return interpreterDisabled(scope, "do-while statement") } } @@ -378,12 +251,7 @@ class BreakStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - val returnValue = resultExpr?.execute(scope) - throw LoopBreakContinueException( - doContinue = false, - label = label, - result = returnValue ?: ObjVoid - ) + return interpreterDisabled(scope, "break statement") } } @@ -392,10 +260,7 @@ class ContinueStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - throw LoopBreakContinueException( - doContinue = true, - label = label, - ) + return interpreterDisabled(scope, "continue statement") } } @@ -405,8 +270,7 @@ class ReturnStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - val returnValue = resultExpr?.execute(scope) ?: ObjVoid - throw ReturnException(returnValue, label) + return interpreterDisabled(scope, "return statement") } } @@ -415,28 +279,7 @@ class ThrowStatement( override val pos: Pos, ) : Statement() { override suspend fun execute(scope: Scope): Obj { - var errorObject = throwExpr.execute(scope) - val throwScope = scope.createChildScope(pos = pos) - if (errorObject is ObjString) { - errorObject = ObjException(throwScope, errorObject.value).apply { getStackTrace() } - } - if (!errorObject.isInstanceOf(ObjException.Root)) { - throwScope.raiseError("this is not an exception object: $errorObject") - } - if (errorObject is ObjException) { - errorObject = ObjException( - errorObject.exceptionClass, - throwScope, - errorObject.message, - errorObject.extraData, - errorObject.useStackTrace - ).apply { getStackTrace() } - throwScope.raiseError(errorObject) - } else { - val msg = errorObject.invokeInstanceMethod(scope, "message").toString(scope).value - throwScope.raiseError(errorObject, pos, msg) - } - return ObjVoid + return interpreterDisabled(scope, "throw statement") } } @@ -444,7 +287,7 @@ class ExpressionStatement( val ref: net.sergeych.lyng.obj.ObjRef, override val pos: Pos ) : Statement() { - override suspend fun execute(scope: Scope): Obj = ref.evalValue(scope) + override suspend fun execute(scope: Scope): Obj = interpreterDisabled(scope, "expression statement") } fun Statement.raise(text: String): Nothing { @@ -459,17 +302,17 @@ fun Statement.require(cond: Boolean, message: () -> String) { fun statement(pos: Pos, isStaticConst: Boolean = false, isConst: Boolean = false, f: suspend (Scope) -> Obj): Statement = object : Statement(isStaticConst, isConst) { override val pos: Pos = pos - override suspend fun execute(scope: Scope): Obj = f(scope) + override suspend fun execute(scope: Scope): Obj = interpreterDisabled(scope, "statement bridge") } fun statement(isStaticConst: Boolean = false, isConst: Boolean = false, f: suspend Scope.() -> Obj): Statement = object : Statement(isStaticConst, isConst) { override val pos: Pos = Pos.builtIn - override suspend fun execute(scope: Scope): Obj = f(scope) + override suspend fun execute(scope: Scope): Obj = interpreterDisabled(scope, "statement bridge") } object NopStatement: Statement(true, true, ObjType.Void) { override val pos: Pos = Pos.builtIn - override suspend fun execute(scope: Scope): Obj = ObjVoid + override suspend fun execute(scope: Scope): Obj = interpreterDisabled(scope, "nop statement") } diff --git a/lynglib/src/commonTest/kotlin/ScriptTest.kt b/lynglib/src/commonTest/kotlin/ScriptTest.kt index 1f0bcba..956dcdd 100644 --- a/lynglib/src/commonTest/kotlin/ScriptTest.kt +++ b/lynglib/src/commonTest/kotlin/ScriptTest.kt @@ -734,7 +734,7 @@ class ScriptTest { listOf( ArgsDeclaration.Item("a"), ArgsDeclaration.Item("b"), - ArgsDeclaration.Item("c", defaultValue = statement { ObjInt(100) }), + ArgsDeclaration.Item("c", defaultValue = ObjExternCallable.fromBridge { ObjInt(100) }), ), ttEnd ) pa.assignToContext(c)