Enforce bytecode-only statements and wrap defaults
This commit is contained in:
parent
489dae6604
commit
26564438e2
@ -28,21 +28,7 @@ class BlockStatement(
|
|||||||
override val pos: Pos = startPos
|
override val pos: Pos = startPos
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val target = if (scope.skipScopeCreation) scope else scope.createChildScope(startPos)
|
return interpreterDisabled(scope, "block statement")
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun statements(): List<Statement> = block.debugStatements()
|
fun statements(): List<Statement> = block.debugStatements()
|
||||||
|
|||||||
@ -17,20 +17,14 @@
|
|||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
import net.sergeych.lyng.obj.ObjClass
|
|
||||||
import net.sergeych.lyng.obj.ObjProperty
|
import net.sergeych.lyng.obj.ObjProperty
|
||||||
import net.sergeych.lyng.obj.ObjRecord
|
|
||||||
import net.sergeych.lyng.obj.ObjVoid
|
|
||||||
|
|
||||||
class ClassInstanceInitDeclStatement(
|
class ClassInstanceInitDeclStatement(
|
||||||
val initStatement: Statement,
|
val initStatement: Statement,
|
||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val cls = scope.thisObj as? ObjClass
|
return interpreterDisabled(scope, "class instance init declaration")
|
||||||
?: scope.raiseIllegalState("instance init declaration requires class scope")
|
|
||||||
cls.instanceInitializers += initStatement
|
|
||||||
return ObjVoid
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,24 +42,7 @@ class ClassInstanceFieldDeclStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val cls = scope.thisObj as? ObjClass
|
return interpreterDisabled(scope, "class instance field declaration")
|
||||||
?: 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,22 +61,7 @@ class ClassInstancePropertyDeclStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val cls = scope.thisObj as? ObjClass
|
return interpreterDisabled(scope, "class instance property declaration")
|
||||||
?: 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,23 +79,6 @@ class ClassInstanceDelegatedDeclStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val cls = scope.thisObj as? ObjClass
|
return interpreterDisabled(scope, "class instance delegated declaration")
|
||||||
?: 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1928,6 +1928,64 @@ class Compiler(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun wrapDefaultArgsBytecode(
|
||||||
|
args: ArgsDeclaration,
|
||||||
|
forcedLocalSlots: Map<String, Int>,
|
||||||
|
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<ParsedArgument>?,
|
||||||
|
forcedLocalSlots: Map<String, Int> = emptyMap(),
|
||||||
|
forcedLocalScopeId: Int? = null
|
||||||
|
): List<ParsedArgument>? {
|
||||||
|
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 {
|
private fun containsDelegatedRefs(stmt: Statement): Boolean {
|
||||||
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
||||||
return when (target) {
|
return when (target) {
|
||||||
@ -5827,6 +5885,7 @@ class Compiler(
|
|||||||
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true)) {
|
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true)) {
|
||||||
argsList = parseArgsNoTailBlock()
|
argsList = parseArgsNoTailBlock()
|
||||||
}
|
}
|
||||||
|
argsList = wrapParsedArgsBytecode(argsList)
|
||||||
baseSpecs += BaseSpec(baseId.value, argsList)
|
baseSpecs += BaseSpec(baseId.value, argsList)
|
||||||
} while (cc.skipTokenOfType(Token.Type.COMMA, isOptional = true))
|
} while (cc.skipTokenOfType(Token.Type.COMMA, isOptional = true))
|
||||||
}
|
}
|
||||||
@ -5978,7 +6037,7 @@ class Compiler(
|
|||||||
val classTypeParams = typeParamDecls.map { it.name }.toSet()
|
val classTypeParams = typeParamDecls.map { it.name }.toSet()
|
||||||
classCtx?.typeParams = classTypeParams
|
classCtx?.typeParams = classTypeParams
|
||||||
pendingTypeParamStack.add(classTypeParams)
|
pendingTypeParamStack.add(classTypeParams)
|
||||||
val constructorArgsDeclaration: ArgsDeclaration?
|
var constructorArgsDeclaration: ArgsDeclaration?
|
||||||
try {
|
try {
|
||||||
constructorArgsDeclaration =
|
constructorArgsDeclaration =
|
||||||
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true))
|
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true))
|
||||||
@ -6009,6 +6068,16 @@ class Compiler(
|
|||||||
val mutable = param.accessType?.isMutable ?: false
|
val mutable = param.accessType?.isMutable ?: false
|
||||||
declareSlotNameIn(classSlotPlan, param.name, mutable, isDelegated = false)
|
declareSlotNameIn(classSlotPlan, param.name, mutable, isDelegated = false)
|
||||||
}
|
}
|
||||||
|
val ctorForcedLocalSlots = LinkedHashMap<String, Int>()
|
||||||
|
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 ->
|
constructorArgsDeclaration?.params?.forEach { param ->
|
||||||
if (param.accessType != null) {
|
if (param.accessType != null) {
|
||||||
classCtx?.declaredMembers?.add(param.name)
|
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
|
// Parse args without consuming any following block so that a class body can follow safely
|
||||||
argsList = parseArgsNoTailBlock()
|
argsList = parseArgsNoTailBlock()
|
||||||
}
|
}
|
||||||
|
argsList = wrapParsedArgsBytecode(argsList, ctorForcedLocalSlots, classSlotPlan.id)
|
||||||
baseSpecs += BaseSpec(baseName, argsList)
|
baseSpecs += BaseSpec(baseName, argsList)
|
||||||
} while (cc.skipTokenOfType(Token.Type.COMMA, isOptional = true))
|
} while (cc.skipTokenOfType(Token.Type.COMMA, isOptional = true))
|
||||||
}
|
}
|
||||||
@ -6717,7 +6787,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
val typeParams = mergedTypeParamDecls.map { it.name }.toSet()
|
val typeParams = mergedTypeParamDecls.map { it.name }.toSet()
|
||||||
pendingTypeParamStack.add(typeParams)
|
pendingTypeParamStack.add(typeParams)
|
||||||
val argsDeclaration: ArgsDeclaration
|
var argsDeclaration: ArgsDeclaration
|
||||||
val returnTypeMini: MiniTypeRef?
|
val returnTypeMini: MiniTypeRef?
|
||||||
val returnTypeDecl: TypeDecl?
|
val returnTypeDecl: TypeDecl?
|
||||||
try {
|
try {
|
||||||
@ -6811,6 +6881,17 @@ class Compiler(
|
|||||||
val typeParamNames = mergedTypeParamDecls.map { it.name }
|
val typeParamNames = mergedTypeParamDecls.map { it.name }
|
||||||
val paramNames: Set<String> = paramNamesList.toSet()
|
val paramNames: Set<String> = paramNamesList.toSet()
|
||||||
val paramSlotPlan = buildParamSlotPlan(paramNamesList + typeParamNames)
|
val paramSlotPlan = buildParamSlotPlan(paramNamesList + typeParamNames)
|
||||||
|
val paramSlotPlanSnapshot = slotPlanIndices(paramSlotPlan)
|
||||||
|
val forcedLocalSlots = LinkedHashMap<String, Int>()
|
||||||
|
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 capturePlan = CapturePlan(paramSlotPlan, isFunction = true, propagateToParentFunction = false)
|
||||||
val rangeParamNames = argsDeclaration.params
|
val rangeParamNames = argsDeclaration.params
|
||||||
.filter { isRangeType(it.type) }
|
.filter { isRangeType(it.type) }
|
||||||
@ -6887,12 +6968,6 @@ class Compiler(
|
|||||||
inferredReturnClass
|
inferredReturnClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val paramSlotPlanSnapshot = slotPlanIndices(paramSlotPlan)
|
|
||||||
val forcedLocalSlots = LinkedHashMap<String, Int>()
|
|
||||||
for (name in paramNamesList) {
|
|
||||||
val idx = paramSlotPlanSnapshot[name] ?: continue
|
|
||||||
forcedLocalSlots[name] = idx
|
|
||||||
}
|
|
||||||
val fnStatements = rawFnStatements?.let { stmt ->
|
val fnStatements = rawFnStatements?.let { stmt ->
|
||||||
if (!compileBytecode) return@let stmt
|
if (!compileBytecode) return@let stmt
|
||||||
val paramKnownClasses = mutableMapOf<String, ObjClass>()
|
val paramKnownClasses = mutableMapOf<String, ObjClass>()
|
||||||
|
|||||||
@ -18,9 +18,6 @@
|
|||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
import net.sergeych.lyng.obj.Obj
|
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(
|
class DelegatedVarDeclStatement(
|
||||||
val name: String,
|
val name: String,
|
||||||
@ -35,23 +32,6 @@ class DelegatedVarDeclStatement(
|
|||||||
override val pos: Pos = startPos
|
override val pos: Pos = startPos
|
||||||
|
|
||||||
override suspend fun execute(context: Scope): Obj {
|
override suspend fun execute(context: Scope): Obj {
|
||||||
val initValue = initializer.execute(context)
|
return interpreterDisabled(context, "delegated var declaration")
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@ package net.sergeych.lyng
|
|||||||
|
|
||||||
import net.sergeych.lyng.obj.ListLiteralRef
|
import net.sergeych.lyng.obj.ListLiteralRef
|
||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
import net.sergeych.lyng.obj.ObjVoid
|
|
||||||
|
|
||||||
class DestructuringVarDeclStatement(
|
class DestructuringVarDeclStatement(
|
||||||
val pattern: ListLiteralRef,
|
val pattern: ListLiteralRef,
|
||||||
@ -30,20 +29,6 @@ class DestructuringVarDeclStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(context: Scope): Obj {
|
override suspend fun execute(context: Scope): Obj {
|
||||||
val value = initializer.execute(context)
|
return interpreterDisabled(context, "destructuring declaration")
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,8 +17,6 @@
|
|||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
import net.sergeych.lyng.obj.ObjEnumClass
|
|
||||||
import net.sergeych.lyng.obj.ObjRecord
|
|
||||||
|
|
||||||
class EnumDeclStatement(
|
class EnumDeclStatement(
|
||||||
val declaredName: String,
|
val declaredName: String,
|
||||||
@ -30,17 +28,7 @@ class EnumDeclStatement(
|
|||||||
override val pos: Pos = startPos
|
override val pos: Pos = startPos
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val enumClass = ObjEnumClass.createSimpleEnum(qualifiedName, entries)
|
return interpreterDisabled(scope, "enum declaration")
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun callOn(scope: Scope): Obj {
|
override suspend fun callOn(scope: Scope): Obj {
|
||||||
|
|||||||
@ -17,11 +17,7 @@
|
|||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
import net.sergeych.lyng.obj.Obj
|
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.ObjProperty
|
||||||
import net.sergeych.lyng.obj.ObjRecord
|
|
||||||
|
|
||||||
class ExtensionPropertyDeclStatement(
|
class ExtensionPropertyDeclStatement(
|
||||||
val extTypeName: String,
|
val extTypeName: String,
|
||||||
@ -33,28 +29,6 @@ class ExtensionPropertyDeclStatement(
|
|||||||
override val pos: Pos = startPos
|
override val pos: Pos = startPos
|
||||||
|
|
||||||
override suspend fun execute(context: Scope): Obj {
|
override suspend fun execute(context: Scope): Obj {
|
||||||
val type = context[extTypeName]?.value ?: context.raiseSymbolNotFound("class $extTypeName not found")
|
return interpreterDisabled(context, "extension property declaration")
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,8 +19,6 @@ package net.sergeych.lyng
|
|||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
import net.sergeych.lyng.obj.ObjClass
|
import net.sergeych.lyng.obj.ObjClass
|
||||||
import net.sergeych.lyng.obj.ObjException
|
import net.sergeych.lyng.obj.ObjException
|
||||||
import net.sergeych.lyng.obj.ObjUnknownException
|
|
||||||
import net.sergeych.lyng.obj.ObjVoid
|
|
||||||
|
|
||||||
class TryStatement(
|
class TryStatement(
|
||||||
val body: Statement,
|
val body: Statement,
|
||||||
@ -38,43 +36,7 @@ class TryStatement(
|
|||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
var result: Obj = ObjVoid
|
return interpreterDisabled(scope, "try statement")
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveExceptionClass(scope: Scope, name: String): ObjClass {
|
private fun resolveExceptionClass(scope: Scope, name: String): ObjClass {
|
||||||
|
|||||||
@ -18,9 +18,6 @@ package net.sergeych.lyng
|
|||||||
|
|
||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
import net.sergeych.lyng.obj.ObjClass
|
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(
|
class VarDeclStatement(
|
||||||
val name: String,
|
val name: String,
|
||||||
@ -36,15 +33,6 @@ class VarDeclStatement(
|
|||||||
override val pos: Pos = startPos
|
override val pos: Pos = startPos
|
||||||
|
|
||||||
override suspend fun execute(context: Scope): Obj {
|
override suspend fun execute(context: Scope): Obj {
|
||||||
val initValue = initializer?.execute(context)?.byValueCopy() ?: ObjUnset
|
return interpreterDisabled(context, "var declaration")
|
||||||
context.addItem(
|
|
||||||
name,
|
|
||||||
isMutable,
|
|
||||||
initValue,
|
|
||||||
visibility,
|
|
||||||
recordType = ObjRecord.Type.Other,
|
|
||||||
isTransient = isTransient
|
|
||||||
)
|
|
||||||
return initValue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,6 @@
|
|||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
import net.sergeych.lyng.obj.ObjVoid
|
|
||||||
|
|
||||||
sealed class WhenCondition(open val expr: Statement, open val pos: Pos) {
|
sealed class WhenCondition(open val expr: Statement, open val pos: Pos) {
|
||||||
abstract suspend fun matches(scope: Scope, value: Obj): Boolean
|
abstract suspend fun matches(scope: Scope, value: Obj): Boolean
|
||||||
@ -67,14 +66,6 @@ class WhenStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val whenValue = value.execute(scope)
|
return interpreterDisabled(scope, "when statement")
|
||||||
for (case in cases) {
|
|
||||||
for (condition in case.conditions) {
|
|
||||||
if (condition.matches(scope, whenValue)) {
|
|
||||||
return case.block.execute(scope)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return elseCase?.execute(scope) ?: ObjVoid
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,10 +19,10 @@ package net.sergeych.lyng
|
|||||||
|
|
||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
import net.sergeych.lyng.obj.ObjClass
|
import net.sergeych.lyng.obj.ObjClass
|
||||||
|
import net.sergeych.lyng.obj.ObjException
|
||||||
import net.sergeych.lyng.obj.ObjInt
|
import net.sergeych.lyng.obj.ObjInt
|
||||||
import net.sergeych.lyng.obj.ObjIterable
|
import net.sergeych.lyng.obj.ObjIterable
|
||||||
import net.sergeych.lyng.obj.ObjNull
|
import net.sergeych.lyng.obj.ObjNull
|
||||||
import net.sergeych.lyng.obj.ObjException
|
|
||||||
import net.sergeych.lyng.obj.ObjRange
|
import net.sergeych.lyng.obj.ObjRange
|
||||||
import net.sergeych.lyng.obj.ObjRecord
|
import net.sergeych.lyng.obj.ObjRecord
|
||||||
import net.sergeych.lyng.obj.ObjString
|
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)))
|
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(
|
class IfStatement(
|
||||||
@ -80,11 +84,7 @@ class IfStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return if (condition.execute(scope).toBool()) {
|
return interpreterDisabled(scope, "if statement")
|
||||||
ifBody.execute(scope)
|
|
||||||
} else {
|
|
||||||
elseBody?.execute(scope) ?: ObjVoid
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,89 +103,7 @@ class ForInStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val forContext = scope.createChildScope(pos)
|
return interpreterDisabled(scope, "for-in statement")
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loopIntRange(
|
private suspend fun loopIntRange(
|
||||||
@ -310,29 +228,7 @@ class WhileStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
var result: Obj = ObjVoid
|
return interpreterDisabled(scope, "while statement")
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,30 +241,7 @@ class DoWhileStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
var wasBroken = false
|
return interpreterDisabled(scope, "do-while statement")
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,12 +251,7 @@ class BreakStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val returnValue = resultExpr?.execute(scope)
|
return interpreterDisabled(scope, "break statement")
|
||||||
throw LoopBreakContinueException(
|
|
||||||
doContinue = false,
|
|
||||||
label = label,
|
|
||||||
result = returnValue ?: ObjVoid
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,10 +260,7 @@ class ContinueStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
throw LoopBreakContinueException(
|
return interpreterDisabled(scope, "continue statement")
|
||||||
doContinue = true,
|
|
||||||
label = label,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,8 +270,7 @@ class ReturnStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val returnValue = resultExpr?.execute(scope) ?: ObjVoid
|
return interpreterDisabled(scope, "return statement")
|
||||||
throw ReturnException(returnValue, label)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,28 +279,7 @@ class ThrowStatement(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
var errorObject = throwExpr.execute(scope)
|
return interpreterDisabled(scope, "throw statement")
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,7 +287,7 @@ class ExpressionStatement(
|
|||||||
val ref: net.sergeych.lyng.obj.ObjRef,
|
val ref: net.sergeych.lyng.obj.ObjRef,
|
||||||
override val pos: Pos
|
override val pos: Pos
|
||||||
) : Statement() {
|
) : 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 {
|
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 =
|
fun statement(pos: Pos, isStaticConst: Boolean = false, isConst: Boolean = false, f: suspend (Scope) -> Obj): Statement =
|
||||||
object : Statement(isStaticConst, isConst) {
|
object : Statement(isStaticConst, isConst) {
|
||||||
override val pos: Pos = pos
|
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 =
|
fun statement(isStaticConst: Boolean = false, isConst: Boolean = false, f: suspend Scope.() -> Obj): Statement =
|
||||||
object : Statement(isStaticConst, isConst) {
|
object : Statement(isStaticConst, isConst) {
|
||||||
override val pos: Pos = Pos.builtIn
|
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) {
|
object NopStatement: Statement(true, true, ObjType.Void) {
|
||||||
override val pos: Pos = Pos.builtIn
|
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")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -734,7 +734,7 @@ class ScriptTest {
|
|||||||
listOf(
|
listOf(
|
||||||
ArgsDeclaration.Item("a"),
|
ArgsDeclaration.Item("a"),
|
||||||
ArgsDeclaration.Item("b"),
|
ArgsDeclaration.Item("b"),
|
||||||
ArgsDeclaration.Item("c", defaultValue = statement { ObjInt(100) }),
|
ArgsDeclaration.Item("c", defaultValue = ObjExternCallable.fromBridge { ObjInt(100) }),
|
||||||
), ttEnd
|
), ttEnd
|
||||||
)
|
)
|
||||||
pa.assignToContext(c)
|
pa.assignToContext(c)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user