Step 25C: bytecode class declarations
This commit is contained in:
parent
b32a937636
commit
4e08339756
@ -114,10 +114,10 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
||||
|
||||
- [ ] Step 25: Replace Statement-based declaration calls in bytecode.
|
||||
- [x] Add bytecode const/op for enum declarations (no `Statement` objects in constants).
|
||||
- [ ] Add bytecode const/op for class declarations (no `Statement` objects in constants).
|
||||
- [x] Add bytecode const/op for class declarations (no `Statement` objects in constants).
|
||||
- [x] Add bytecode const/op for function declarations (no `Statement` objects in constants).
|
||||
- [x] Replace `emitStatementCall` usage for `EnumDeclStatement`.
|
||||
- [ ] Replace `emitStatementCall` usage for `ClassDeclStatement`.
|
||||
- [x] Replace `emitStatementCall` usage for `ClassDeclStatement`.
|
||||
- [x] Replace `emitStatementCall` usage for `FunctionDeclStatement`.
|
||||
- [ ] Add JVM disasm coverage to ensure module init has no `CALL_SLOT` to `Callable@...` for declarations.
|
||||
- [ ] Step 26: Bytecode-backed lambdas (remove `ValueFnRef` runtime execution).
|
||||
|
||||
@ -17,20 +17,147 @@
|
||||
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.ObjInstance
|
||||
import net.sergeych.lyng.obj.ObjInstanceClass
|
||||
import net.sergeych.lyng.obj.ObjNull
|
||||
import net.sergeych.lyng.obj.ObjRecord
|
||||
|
||||
data class ClassDeclBaseSpec(
|
||||
val name: String,
|
||||
val args: List<ParsedArgument>?
|
||||
)
|
||||
|
||||
data class ClassDeclSpec(
|
||||
val declaredName: String?,
|
||||
val className: String,
|
||||
val typeName: String,
|
||||
val startPos: Pos,
|
||||
val isExtern: Boolean,
|
||||
val isAbstract: Boolean,
|
||||
val isObject: Boolean,
|
||||
val isAnonymous: Boolean,
|
||||
val baseSpecs: List<ClassDeclBaseSpec>,
|
||||
val constructorArgs: ArgsDeclaration?,
|
||||
val constructorFieldIds: Map<String, Int>?,
|
||||
val bodyInit: Statement?,
|
||||
val initScope: List<Statement>,
|
||||
)
|
||||
|
||||
internal suspend fun executeClassDecl(scope: Scope, spec: ClassDeclSpec): Obj {
|
||||
if (spec.isObject) {
|
||||
val parentClasses = spec.baseSpecs.map { baseSpec ->
|
||||
val rec = scope[baseSpec.name] ?: throw ScriptError(spec.startPos, "unknown base class: ${baseSpec.name}")
|
||||
(rec.value as? ObjClass) ?: throw ScriptError(spec.startPos, "${baseSpec.name} is not a class")
|
||||
}
|
||||
|
||||
val newClass = ObjInstanceClass(spec.className, *parentClasses.toTypedArray())
|
||||
newClass.isAnonymous = spec.isAnonymous
|
||||
newClass.constructorMeta = ArgsDeclaration(emptyList(), Token.Type.RPAREN)
|
||||
for (i in parentClasses.indices) {
|
||||
val argsList = spec.baseSpecs[i].args
|
||||
if (argsList != null) newClass.directParentArgs[parentClasses[i]] = argsList
|
||||
}
|
||||
|
||||
val classScope = scope.createChildScope(newThisObj = newClass)
|
||||
classScope.currentClassCtx = newClass
|
||||
newClass.classScope = classScope
|
||||
classScope.addConst("object", newClass)
|
||||
|
||||
spec.bodyInit?.execute(classScope)
|
||||
|
||||
val instance = newClass.callOn(scope.createChildScope(Arguments.EMPTY))
|
||||
if (spec.declaredName != null) {
|
||||
scope.addItem(spec.declaredName, false, instance)
|
||||
}
|
||||
return instance
|
||||
}
|
||||
|
||||
if (spec.isExtern) {
|
||||
val rec = scope[spec.className]
|
||||
val existing = rec?.value as? ObjClass
|
||||
val resolved = if (existing != null) {
|
||||
existing
|
||||
} else if (spec.className.contains('.')) {
|
||||
scope.resolveQualifiedIdentifier(spec.className) as? ObjClass
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val stub = resolved ?: ObjInstanceClass(spec.className).apply { this.isAbstract = true }
|
||||
spec.declaredName?.let { scope.addItem(it, false, stub) }
|
||||
return stub
|
||||
}
|
||||
|
||||
val parentClasses = spec.baseSpecs.map { baseSpec ->
|
||||
val rec = scope[baseSpec.name]
|
||||
val cls = rec?.value as? ObjClass
|
||||
if (cls != null) return@map cls
|
||||
if (baseSpec.name == "Exception") return@map ObjException.Root
|
||||
if (rec == null) throw ScriptError(spec.startPos, "unknown base class: ${baseSpec.name}")
|
||||
throw ScriptError(spec.startPos, "${baseSpec.name} is not a class")
|
||||
}
|
||||
|
||||
val constructorCode = object : Statement() {
|
||||
override val pos: Pos = spec.startPos
|
||||
override suspend fun execute(scope: Scope): Obj {
|
||||
val instance = scope.thisObj as ObjInstance
|
||||
return instance
|
||||
}
|
||||
}
|
||||
|
||||
val newClass = ObjInstanceClass(spec.className, *parentClasses.toTypedArray()).also {
|
||||
it.isAbstract = spec.isAbstract
|
||||
it.instanceConstructor = constructorCode
|
||||
it.constructorMeta = spec.constructorArgs
|
||||
for (i in parentClasses.indices) {
|
||||
val argsList = spec.baseSpecs[i].args
|
||||
if (argsList != null) it.directParentArgs[parentClasses[i]] = argsList
|
||||
}
|
||||
spec.constructorArgs?.params?.forEach { p ->
|
||||
if (p.accessType != null) {
|
||||
it.createField(
|
||||
p.name,
|
||||
ObjNull,
|
||||
isMutable = p.accessType == AccessType.Var,
|
||||
visibility = p.visibility ?: Visibility.Public,
|
||||
declaringClass = it,
|
||||
pos = Pos.builtIn,
|
||||
isTransient = p.isTransient,
|
||||
type = ObjRecord.Type.ConstructorField,
|
||||
fieldId = spec.constructorFieldIds?.get(p.name)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spec.declaredName?.let { scope.addItem(it, false, newClass) }
|
||||
val classScope = scope.createChildScope(newThisObj = newClass)
|
||||
classScope.currentClassCtx = newClass
|
||||
newClass.classScope = classScope
|
||||
spec.bodyInit?.execute(classScope)
|
||||
if (spec.initScope.isNotEmpty()) {
|
||||
for (s in spec.initScope) {
|
||||
s.execute(classScope)
|
||||
}
|
||||
}
|
||||
newClass.checkAbstractSatisfaction(spec.startPos)
|
||||
return newClass
|
||||
}
|
||||
|
||||
class ClassDeclStatement(
|
||||
val executable: DeclExecutable,
|
||||
private val startPos: Pos,
|
||||
val declaredName: String?,
|
||||
val spec: ClassDeclSpec,
|
||||
) : Statement() {
|
||||
override val pos: Pos = startPos
|
||||
override val pos: Pos = spec.startPos
|
||||
val declaredName: String? get() = spec.declaredName
|
||||
val typeName: String get() = spec.typeName
|
||||
|
||||
override suspend fun execute(scope: Scope): Obj {
|
||||
return executable.execute(scope)
|
||||
return executeClassDecl(scope, spec)
|
||||
}
|
||||
|
||||
override suspend fun callOn(scope: Scope): Obj {
|
||||
val target = scope.parent ?: scope
|
||||
return executable.execute(target)
|
||||
return executeClassDecl(target, spec)
|
||||
}
|
||||
}
|
||||
|
||||
@ -5959,38 +5959,22 @@ class Compiler(
|
||||
|
||||
val initScope = popInitScope()
|
||||
|
||||
val declStatement = object : Statement() {
|
||||
override val pos: Pos = startPos
|
||||
override suspend fun execute(scope: Scope): Obj {
|
||||
val parentClasses = baseSpecs.map { baseSpec ->
|
||||
val rec = scope[baseSpec.name] ?: throw ScriptError(startPos, "unknown base class: ${baseSpec.name}")
|
||||
(rec.value as? ObjClass) ?: throw ScriptError(startPos, "${baseSpec.name} is not a class")
|
||||
}
|
||||
|
||||
val newClass = ObjInstanceClass(className, *parentClasses.toTypedArray())
|
||||
newClass.isAnonymous = nameToken == null
|
||||
newClass.constructorMeta = ArgsDeclaration(emptyList(), Token.Type.RPAREN)
|
||||
for (i in parentClasses.indices) {
|
||||
val argsList = baseSpecs[i].args
|
||||
// In object, we evaluate parent args once at creation time
|
||||
if (argsList != null) newClass.directParentArgs[parentClasses[i]] = argsList
|
||||
}
|
||||
|
||||
val classScope = scope.createChildScope(newThisObj = newClass)
|
||||
classScope.currentClassCtx = newClass
|
||||
newClass.classScope = classScope
|
||||
classScope.addConst("object", newClass)
|
||||
|
||||
bodyInit?.execute(classScope)
|
||||
|
||||
// Create instance (singleton)
|
||||
val instance = newClass.callOn(scope.createChildScope(Arguments.EMPTY))
|
||||
if (declaredName != null)
|
||||
scope.addItem(declaredName, false, instance)
|
||||
return instance
|
||||
}
|
||||
}
|
||||
return ClassDeclStatement(StatementDeclExecutable(declStatement), startPos, className)
|
||||
val spec = ClassDeclSpec(
|
||||
declaredName = declaredName,
|
||||
className = className,
|
||||
typeName = className,
|
||||
startPos = startPos,
|
||||
isExtern = false,
|
||||
isAbstract = false,
|
||||
isObject = true,
|
||||
isAnonymous = nameToken == null,
|
||||
baseSpecs = baseSpecs.map { ClassDeclBaseSpec(it.name, it.args) },
|
||||
constructorArgs = null,
|
||||
constructorFieldIds = null,
|
||||
bodyInit = bodyInit,
|
||||
initScope = emptyList()
|
||||
)
|
||||
return ClassDeclStatement(spec)
|
||||
}
|
||||
|
||||
private suspend fun parseClassDeclaration(isAbstract: Boolean = false, isExtern: Boolean = false): Statement {
|
||||
@ -6313,91 +6297,23 @@ class Compiler(
|
||||
// create instance constructor
|
||||
// create custom objClass with all fields and instance constructor
|
||||
|
||||
val constructorCode = object : Statement() {
|
||||
override val pos: Pos = startPos
|
||||
override suspend fun execute(scope: Scope): Obj {
|
||||
// constructor code is registered with class instance and is called over
|
||||
// new `thisObj` already set by class to ObjInstance.instanceContext
|
||||
val instance = scope.thisObj as ObjInstance
|
||||
// Constructor parameters have been assigned to instance scope by ObjClass.callOn before
|
||||
// invoking parent/child constructors.
|
||||
// IMPORTANT: do not execute class body here; class body was executed once in the class scope
|
||||
// to register methods and prepare initializers. Instance constructor should be empty unless
|
||||
// we later add explicit constructor body syntax.
|
||||
return instance
|
||||
}
|
||||
}
|
||||
val classInfo = compileClassInfos[className]
|
||||
val classDeclStatement = object : Statement() {
|
||||
override val pos: Pos = startPos
|
||||
override suspend fun execute(scope: Scope): Obj {
|
||||
// the main statement should create custom ObjClass instance with field
|
||||
// accessors, constructor registration, etc.
|
||||
if (isExtern) {
|
||||
val rec = scope[className]
|
||||
val existing = rec?.value as? ObjClass
|
||||
val resolved = existing ?: resolveClassByName(className)
|
||||
val stub = resolved ?: ObjInstanceClass(className).apply { this.isAbstract = true }
|
||||
scope.addItem(declaredName, false, stub)
|
||||
return stub
|
||||
}
|
||||
// Resolve parent classes by name at execution time
|
||||
val parentClasses = baseSpecs.map { baseSpec ->
|
||||
val rec = scope[baseSpec.name]
|
||||
val cls = rec?.value as? ObjClass
|
||||
if (cls != null) return@map cls
|
||||
if (baseSpec.name == "Exception") return@map ObjException.Root
|
||||
if (rec == null) throw ScriptError(nameToken.pos, "unknown base class: ${baseSpec.name}")
|
||||
throw ScriptError(nameToken.pos, "${baseSpec.name} is not a class")
|
||||
}
|
||||
|
||||
val newClass = ObjInstanceClass(className, *parentClasses.toTypedArray()).also {
|
||||
it.isAbstract = isAbstract
|
||||
it.instanceConstructor = constructorCode
|
||||
it.constructorMeta = constructorArgsDeclaration
|
||||
// Attach per-parent constructor args (thunks) if provided
|
||||
for (i in parentClasses.indices) {
|
||||
val argsList = baseSpecs[i].args
|
||||
if (argsList != null) it.directParentArgs[parentClasses[i]] = argsList
|
||||
}
|
||||
// Register constructor fields in the class members
|
||||
constructorArgsDeclaration?.params?.forEach { p ->
|
||||
if (p.accessType != null) {
|
||||
it.createField(
|
||||
p.name, ObjNull,
|
||||
isMutable = p.accessType == AccessType.Var,
|
||||
visibility = p.visibility ?: Visibility.Public,
|
||||
declaringClass = it,
|
||||
// Constructor fields are not currently supporting override/closed in parser
|
||||
// but we should pass Pos.builtIn to skip validation for now if needed,
|
||||
// or p.pos to allow it.
|
||||
pos = Pos.builtIn,
|
||||
isTransient = p.isTransient,
|
||||
type = ObjRecord.Type.ConstructorField,
|
||||
fieldId = classInfo?.fieldIds?.get(p.name)
|
||||
val spec = ClassDeclSpec(
|
||||
declaredName = declaredName,
|
||||
className = className,
|
||||
typeName = className,
|
||||
startPos = startPos,
|
||||
isExtern = isExtern,
|
||||
isAbstract = isAbstract,
|
||||
isObject = false,
|
||||
isAnonymous = false,
|
||||
baseSpecs = baseSpecs.map { ClassDeclBaseSpec(it.name, it.args) },
|
||||
constructorArgs = constructorArgsDeclaration,
|
||||
constructorFieldIds = classInfo?.fieldIds,
|
||||
bodyInit = bodyInit,
|
||||
initScope = initScope
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope.addItem(declaredName, false, newClass)
|
||||
// Prepare class scope for class-scope members (static) and future registrations
|
||||
val classScope = scope.createChildScope(newThisObj = newClass)
|
||||
// Set lexical class context for visibility tagging inside class body
|
||||
classScope.currentClassCtx = newClass
|
||||
newClass.classScope = classScope
|
||||
// Execute class body once in class scope to register instance methods and prepare instance field initializers
|
||||
bodyInit?.execute(classScope)
|
||||
if (initScope.isNotEmpty()) {
|
||||
for (s in initScope)
|
||||
s.execute(classScope)
|
||||
}
|
||||
newClass.checkAbstractSatisfaction(nameToken.pos)
|
||||
// Debug summary: list registered instance methods and class-scope functions for this class
|
||||
return newClass
|
||||
}
|
||||
}
|
||||
ClassDeclStatement(StatementDeclExecutable(classDeclStatement), startPos, qualifiedName)
|
||||
ClassDeclStatement(spec)
|
||||
}
|
||||
|
||||
}
|
||||
@ -7224,7 +7140,7 @@ class Compiler(
|
||||
}
|
||||
}
|
||||
if (unwrapped is ClassDeclStatement) {
|
||||
unwrapped.declaredName?.let { return resolveClassByName(it) }
|
||||
return resolveClassByName(unwrapped.typeName)
|
||||
}
|
||||
val directRef = unwrapDirectRef(unwrapped)
|
||||
return when (directRef) {
|
||||
@ -7233,7 +7149,7 @@ class Compiler(
|
||||
is RangeRef -> ObjRange.type
|
||||
is StatementRef -> {
|
||||
val decl = directRef.statement as? ClassDeclStatement
|
||||
decl?.declaredName?.let { resolveClassByName(it) }
|
||||
decl?.let { resolveClassByName(it.typeName) }
|
||||
}
|
||||
is ValueFnRef -> lambdaReturnTypeByRef[directRef]
|
||||
is CastRef -> resolveTypeRefClass(directRef.castTypeRef())
|
||||
|
||||
@ -161,7 +161,7 @@ class BytecodeCompiler(
|
||||
)
|
||||
}
|
||||
is net.sergeych.lyng.ClassDeclStatement -> {
|
||||
val value = emitStatementCall(stmt)
|
||||
val value = emitDeclClass(stmt)
|
||||
builder.emit(Opcode.RET, value.slot)
|
||||
val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount
|
||||
builder.build(
|
||||
@ -4108,7 +4108,6 @@ class BytecodeCompiler(
|
||||
|
||||
private fun emitDeclExec(stmt: Statement): CompiledValue {
|
||||
val executable = when (stmt) {
|
||||
is net.sergeych.lyng.ClassDeclStatement -> stmt.executable
|
||||
else -> throw BytecodeCompileException(
|
||||
"Bytecode compile error: unsupported declaration ${stmt::class.simpleName}",
|
||||
stmt.pos
|
||||
@ -4144,6 +4143,14 @@ class BytecodeCompiler(
|
||||
return CompiledValue(dst, SlotType.OBJ)
|
||||
}
|
||||
|
||||
private fun emitDeclClass(stmt: net.sergeych.lyng.ClassDeclStatement): CompiledValue {
|
||||
val constId = builder.addConst(BytecodeConst.ClassDecl(stmt.spec))
|
||||
val dst = allocSlot()
|
||||
builder.emit(Opcode.DECL_CLASS, constId, dst)
|
||||
updateSlotType(dst, SlotType.OBJ)
|
||||
return CompiledValue(dst, SlotType.OBJ)
|
||||
}
|
||||
|
||||
private fun compileStatementValueOrFallback(stmt: Statement, needResult: Boolean = true): CompiledValue? {
|
||||
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
||||
setPos(target.pos)
|
||||
@ -4177,7 +4184,7 @@ class BytecodeCompiler(
|
||||
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
||||
is DestructuringVarDeclStatement -> emitDestructuringVarDecl(target)
|
||||
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
|
||||
is net.sergeych.lyng.ClassDeclStatement -> emitDeclExec(target)
|
||||
is net.sergeych.lyng.ClassDeclStatement -> emitDeclClass(target)
|
||||
is net.sergeych.lyng.FunctionDeclStatement -> emitDeclFunction(target)
|
||||
is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target)
|
||||
is net.sergeych.lyng.TryStatement -> emitTry(target, true)
|
||||
@ -4210,7 +4217,7 @@ class BytecodeCompiler(
|
||||
is VarDeclStatement -> emitVarDecl(target)
|
||||
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
||||
is IfStatement -> compileIfStatement(target)
|
||||
is net.sergeych.lyng.ClassDeclStatement -> emitDeclExec(target)
|
||||
is net.sergeych.lyng.ClassDeclStatement -> emitDeclClass(target)
|
||||
is net.sergeych.lyng.FunctionDeclStatement -> emitDeclFunction(target)
|
||||
is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target)
|
||||
is net.sergeych.lyng.ForInStatement -> {
|
||||
|
||||
@ -47,6 +47,9 @@ sealed class BytecodeConst {
|
||||
data class FunctionDecl(
|
||||
val spec: net.sergeych.lyng.FunctionDeclSpec,
|
||||
) : BytecodeConst()
|
||||
data class ClassDecl(
|
||||
val spec: net.sergeych.lyng.ClassDeclSpec,
|
||||
) : BytecodeConst()
|
||||
data class SlotPlan(val plan: Map<String, Int>, val captures: List<String> = emptyList()) : BytecodeConst()
|
||||
data class CaptureTable(val entries: List<BytecodeCaptureEntry>) : BytecodeConst()
|
||||
data class ExtensionPropertyDecl(
|
||||
|
||||
@ -157,7 +157,7 @@ class CmdBuilder {
|
||||
Opcode.PUSH_TRY ->
|
||||
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
||||
Opcode.DECL_EXEC, Opcode.DECL_ENUM, Opcode.DECL_FUNCTION,
|
||||
Opcode.DECL_EXEC, Opcode.DECL_ENUM, Opcode.DECL_FUNCTION, Opcode.DECL_CLASS,
|
||||
Opcode.ASSIGN_DESTRUCTURE ->
|
||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
||||
@ -413,6 +413,7 @@ class CmdBuilder {
|
||||
Opcode.DECL_EXEC -> CmdDeclExec(operands[0], operands[1])
|
||||
Opcode.DECL_ENUM -> CmdDeclEnum(operands[0], operands[1])
|
||||
Opcode.DECL_FUNCTION -> CmdDeclFunction(operands[0], operands[1])
|
||||
Opcode.DECL_CLASS -> CmdDeclClass(operands[0], operands[1])
|
||||
Opcode.DECL_EXT_PROPERTY -> CmdDeclExtProperty(operands[0], operands[1])
|
||||
Opcode.CALL_DIRECT -> CmdCallDirect(operands[0], operands[1], operands[2], operands[3])
|
||||
Opcode.ASSIGN_DESTRUCTURE -> CmdAssignDestructure(operands[0], operands[1])
|
||||
|
||||
@ -214,6 +214,7 @@ object CmdDisassembler {
|
||||
is CmdDeclExec -> Opcode.DECL_EXEC to intArrayOf(cmd.constId, cmd.slot)
|
||||
is CmdDeclEnum -> Opcode.DECL_ENUM to intArrayOf(cmd.constId, cmd.slot)
|
||||
is CmdDeclFunction -> Opcode.DECL_FUNCTION to intArrayOf(cmd.constId, cmd.slot)
|
||||
is CmdDeclClass -> Opcode.DECL_CLASS to intArrayOf(cmd.constId, cmd.slot)
|
||||
is CmdDeclExtProperty -> Opcode.DECL_EXT_PROPERTY to intArrayOf(cmd.constId, cmd.slot)
|
||||
is CmdCallDirect -> Opcode.CALL_DIRECT to intArrayOf(cmd.id, cmd.argBase, cmd.argCount, cmd.dst)
|
||||
is CmdAssignDestructure -> Opcode.ASSIGN_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
||||
@ -285,7 +286,7 @@ object CmdDisassembler {
|
||||
Opcode.PUSH_TRY ->
|
||||
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
||||
Opcode.DECL_EXEC, Opcode.DECL_ENUM, Opcode.DECL_FUNCTION,
|
||||
Opcode.DECL_EXEC, Opcode.DECL_ENUM, Opcode.DECL_FUNCTION, Opcode.DECL_CLASS,
|
||||
Opcode.ASSIGN_DESTRUCTURE ->
|
||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
||||
|
||||
@ -1354,6 +1354,16 @@ class CmdDeclFunction(internal val constId: Int, internal val slot: Int) : Cmd()
|
||||
}
|
||||
}
|
||||
|
||||
class CmdDeclClass(internal val constId: Int, internal val slot: Int) : Cmd() {
|
||||
override suspend fun perform(frame: CmdFrame) {
|
||||
val decl = frame.fn.constants[constId] as? BytecodeConst.ClassDecl
|
||||
?: error("DECL_CLASS expects ClassDecl at $constId")
|
||||
val result = executeClassDecl(frame.ensureScope(), decl.spec)
|
||||
frame.storeObjResult(slot, result)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
class CmdDeclDestructure(internal val constId: Int, internal val slot: Int) : Cmd() {
|
||||
override suspend fun perform(frame: CmdFrame) {
|
||||
val decl = frame.fn.constants[constId] as? BytecodeConst.DestructureDecl
|
||||
|
||||
@ -167,6 +167,7 @@ enum class Opcode(val code: Int) {
|
||||
DELEGATED_SET_LOCAL(0xC3),
|
||||
BIND_DELEGATE_LOCAL(0xC4),
|
||||
DECL_FUNCTION(0xC5),
|
||||
DECL_CLASS(0xC6),
|
||||
;
|
||||
|
||||
companion object {
|
||||
|
||||
@ -260,7 +260,9 @@ class BytecodeRecentOpsTest {
|
||||
assertNotNull(moduleFn, "module bytecode missing")
|
||||
val disasm = CmdDisassembler.disassemble(moduleFn)
|
||||
assertTrue(!disasm.contains("CALL_SLOT"), disasm)
|
||||
assertTrue(disasm.contains("DECL_EXEC"), disasm)
|
||||
assertTrue(disasm.contains("DECL_CLASS"), disasm)
|
||||
assertTrue(disasm.contains("DECL_FUNCTION"), disasm)
|
||||
assertTrue(disasm.contains("DECL_ENUM"), disasm)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user