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.
|
- [ ] Step 25: Replace Statement-based declaration calls in bytecode.
|
||||||
- [x] Add bytecode const/op for enum declarations (no `Statement` objects in constants).
|
- [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] Add bytecode const/op for function declarations (no `Statement` objects in constants).
|
||||||
- [x] Replace `emitStatementCall` usage for `EnumDeclStatement`.
|
- [x] Replace `emitStatementCall` usage for `EnumDeclStatement`.
|
||||||
- [ ] Replace `emitStatementCall` usage for `ClassDeclStatement`.
|
- [x] Replace `emitStatementCall` usage for `ClassDeclStatement`.
|
||||||
- [x] Replace `emitStatementCall` usage for `FunctionDeclStatement`.
|
- [x] Replace `emitStatementCall` usage for `FunctionDeclStatement`.
|
||||||
- [ ] Add JVM disasm coverage to ensure module init has no `CALL_SLOT` to `Callable@...` for declarations.
|
- [ ] 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).
|
- [ ] Step 26: Bytecode-backed lambdas (remove `ValueFnRef` runtime execution).
|
||||||
|
|||||||
@ -17,20 +17,147 @@
|
|||||||
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.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(
|
class ClassDeclStatement(
|
||||||
val executable: DeclExecutable,
|
val spec: ClassDeclSpec,
|
||||||
private val startPos: Pos,
|
|
||||||
val declaredName: String?,
|
|
||||||
) : Statement() {
|
) : 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 {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return executable.execute(scope)
|
return executeClassDecl(scope, spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun callOn(scope: Scope): Obj {
|
override suspend fun callOn(scope: Scope): Obj {
|
||||||
val target = scope.parent ?: scope
|
val target = scope.parent ?: scope
|
||||||
return executable.execute(target)
|
return executeClassDecl(target, spec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5959,38 +5959,22 @@ class Compiler(
|
|||||||
|
|
||||||
val initScope = popInitScope()
|
val initScope = popInitScope()
|
||||||
|
|
||||||
val declStatement = object : Statement() {
|
val spec = ClassDeclSpec(
|
||||||
override val pos: Pos = startPos
|
declaredName = declaredName,
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
className = className,
|
||||||
val parentClasses = baseSpecs.map { baseSpec ->
|
typeName = className,
|
||||||
val rec = scope[baseSpec.name] ?: throw ScriptError(startPos, "unknown base class: ${baseSpec.name}")
|
startPos = startPos,
|
||||||
(rec.value as? ObjClass) ?: throw ScriptError(startPos, "${baseSpec.name} is not a class")
|
isExtern = false,
|
||||||
}
|
isAbstract = false,
|
||||||
|
isObject = true,
|
||||||
val newClass = ObjInstanceClass(className, *parentClasses.toTypedArray())
|
isAnonymous = nameToken == null,
|
||||||
newClass.isAnonymous = nameToken == null
|
baseSpecs = baseSpecs.map { ClassDeclBaseSpec(it.name, it.args) },
|
||||||
newClass.constructorMeta = ArgsDeclaration(emptyList(), Token.Type.RPAREN)
|
constructorArgs = null,
|
||||||
for (i in parentClasses.indices) {
|
constructorFieldIds = null,
|
||||||
val argsList = baseSpecs[i].args
|
bodyInit = bodyInit,
|
||||||
// In object, we evaluate parent args once at creation time
|
initScope = emptyList()
|
||||||
if (argsList != null) newClass.directParentArgs[parentClasses[i]] = argsList
|
)
|
||||||
}
|
return ClassDeclStatement(spec)
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun parseClassDeclaration(isAbstract: Boolean = false, isExtern: Boolean = false): Statement {
|
private suspend fun parseClassDeclaration(isAbstract: Boolean = false, isExtern: Boolean = false): Statement {
|
||||||
@ -6313,91 +6297,23 @@ class Compiler(
|
|||||||
// create instance constructor
|
// create instance constructor
|
||||||
// create custom objClass with all fields and 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 classInfo = compileClassInfos[className]
|
||||||
val classDeclStatement = object : Statement() {
|
val spec = ClassDeclSpec(
|
||||||
override val pos: Pos = startPos
|
declaredName = declaredName,
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
className = className,
|
||||||
// the main statement should create custom ObjClass instance with field
|
typeName = className,
|
||||||
// accessors, constructor registration, etc.
|
startPos = startPos,
|
||||||
if (isExtern) {
|
isExtern = isExtern,
|
||||||
val rec = scope[className]
|
isAbstract = isAbstract,
|
||||||
val existing = rec?.value as? ObjClass
|
isObject = false,
|
||||||
val resolved = existing ?: resolveClassByName(className)
|
isAnonymous = false,
|
||||||
val stub = resolved ?: ObjInstanceClass(className).apply { this.isAbstract = true }
|
baseSpecs = baseSpecs.map { ClassDeclBaseSpec(it.name, it.args) },
|
||||||
scope.addItem(declaredName, false, stub)
|
constructorArgs = constructorArgsDeclaration,
|
||||||
return stub
|
constructorFieldIds = classInfo?.fieldIds,
|
||||||
}
|
bodyInit = bodyInit,
|
||||||
// Resolve parent classes by name at execution time
|
initScope = initScope
|
||||||
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)
|
|
||||||
)
|
)
|
||||||
}
|
ClassDeclStatement(spec)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -7224,7 +7140,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unwrapped is ClassDeclStatement) {
|
if (unwrapped is ClassDeclStatement) {
|
||||||
unwrapped.declaredName?.let { return resolveClassByName(it) }
|
return resolveClassByName(unwrapped.typeName)
|
||||||
}
|
}
|
||||||
val directRef = unwrapDirectRef(unwrapped)
|
val directRef = unwrapDirectRef(unwrapped)
|
||||||
return when (directRef) {
|
return when (directRef) {
|
||||||
@ -7233,7 +7149,7 @@ class Compiler(
|
|||||||
is RangeRef -> ObjRange.type
|
is RangeRef -> ObjRange.type
|
||||||
is StatementRef -> {
|
is StatementRef -> {
|
||||||
val decl = directRef.statement as? ClassDeclStatement
|
val decl = directRef.statement as? ClassDeclStatement
|
||||||
decl?.declaredName?.let { resolveClassByName(it) }
|
decl?.let { resolveClassByName(it.typeName) }
|
||||||
}
|
}
|
||||||
is ValueFnRef -> lambdaReturnTypeByRef[directRef]
|
is ValueFnRef -> lambdaReturnTypeByRef[directRef]
|
||||||
is CastRef -> resolveTypeRefClass(directRef.castTypeRef())
|
is CastRef -> resolveTypeRefClass(directRef.castTypeRef())
|
||||||
|
|||||||
@ -161,7 +161,7 @@ class BytecodeCompiler(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
is net.sergeych.lyng.ClassDeclStatement -> {
|
is net.sergeych.lyng.ClassDeclStatement -> {
|
||||||
val value = emitStatementCall(stmt)
|
val value = emitDeclClass(stmt)
|
||||||
builder.emit(Opcode.RET, value.slot)
|
builder.emit(Opcode.RET, value.slot)
|
||||||
val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount
|
val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount
|
||||||
builder.build(
|
builder.build(
|
||||||
@ -4108,7 +4108,6 @@ class BytecodeCompiler(
|
|||||||
|
|
||||||
private fun emitDeclExec(stmt: Statement): CompiledValue {
|
private fun emitDeclExec(stmt: Statement): CompiledValue {
|
||||||
val executable = when (stmt) {
|
val executable = when (stmt) {
|
||||||
is net.sergeych.lyng.ClassDeclStatement -> stmt.executable
|
|
||||||
else -> throw BytecodeCompileException(
|
else -> throw BytecodeCompileException(
|
||||||
"Bytecode compile error: unsupported declaration ${stmt::class.simpleName}",
|
"Bytecode compile error: unsupported declaration ${stmt::class.simpleName}",
|
||||||
stmt.pos
|
stmt.pos
|
||||||
@ -4144,6 +4143,14 @@ class BytecodeCompiler(
|
|||||||
return CompiledValue(dst, SlotType.OBJ)
|
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? {
|
private fun compileStatementValueOrFallback(stmt: Statement, needResult: Boolean = true): CompiledValue? {
|
||||||
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
||||||
setPos(target.pos)
|
setPos(target.pos)
|
||||||
@ -4177,7 +4184,7 @@ class BytecodeCompiler(
|
|||||||
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
||||||
is DestructuringVarDeclStatement -> emitDestructuringVarDecl(target)
|
is DestructuringVarDeclStatement -> emitDestructuringVarDecl(target)
|
||||||
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(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.FunctionDeclStatement -> emitDeclFunction(target)
|
||||||
is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target)
|
is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target)
|
||||||
is net.sergeych.lyng.TryStatement -> emitTry(target, true)
|
is net.sergeych.lyng.TryStatement -> emitTry(target, true)
|
||||||
@ -4210,7 +4217,7 @@ class BytecodeCompiler(
|
|||||||
is VarDeclStatement -> emitVarDecl(target)
|
is VarDeclStatement -> emitVarDecl(target)
|
||||||
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
||||||
is IfStatement -> compileIfStatement(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.FunctionDeclStatement -> emitDeclFunction(target)
|
||||||
is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target)
|
is net.sergeych.lyng.EnumDeclStatement -> emitDeclEnum(target)
|
||||||
is net.sergeych.lyng.ForInStatement -> {
|
is net.sergeych.lyng.ForInStatement -> {
|
||||||
|
|||||||
@ -47,6 +47,9 @@ sealed class BytecodeConst {
|
|||||||
data class FunctionDecl(
|
data class FunctionDecl(
|
||||||
val spec: net.sergeych.lyng.FunctionDeclSpec,
|
val spec: net.sergeych.lyng.FunctionDeclSpec,
|
||||||
) : BytecodeConst()
|
) : 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 SlotPlan(val plan: Map<String, Int>, val captures: List<String> = emptyList()) : BytecodeConst()
|
||||||
data class CaptureTable(val entries: List<BytecodeCaptureEntry>) : BytecodeConst()
|
data class CaptureTable(val entries: List<BytecodeCaptureEntry>) : BytecodeConst()
|
||||||
data class ExtensionPropertyDecl(
|
data class ExtensionPropertyDecl(
|
||||||
|
|||||||
@ -157,7 +157,7 @@ class CmdBuilder {
|
|||||||
Opcode.PUSH_TRY ->
|
Opcode.PUSH_TRY ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
||||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
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 ->
|
Opcode.ASSIGN_DESTRUCTURE ->
|
||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
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_EXEC -> CmdDeclExec(operands[0], operands[1])
|
||||||
Opcode.DECL_ENUM -> CmdDeclEnum(operands[0], operands[1])
|
Opcode.DECL_ENUM -> CmdDeclEnum(operands[0], operands[1])
|
||||||
Opcode.DECL_FUNCTION -> CmdDeclFunction(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.DECL_EXT_PROPERTY -> CmdDeclExtProperty(operands[0], operands[1])
|
||||||
Opcode.CALL_DIRECT -> CmdCallDirect(operands[0], operands[1], operands[2], operands[3])
|
Opcode.CALL_DIRECT -> CmdCallDirect(operands[0], operands[1], operands[2], operands[3])
|
||||||
Opcode.ASSIGN_DESTRUCTURE -> CmdAssignDestructure(operands[0], operands[1])
|
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 CmdDeclExec -> Opcode.DECL_EXEC to intArrayOf(cmd.constId, cmd.slot)
|
||||||
is CmdDeclEnum -> Opcode.DECL_ENUM 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 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 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 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)
|
is CmdAssignDestructure -> Opcode.ASSIGN_DESTRUCTURE to intArrayOf(cmd.constId, cmd.slot)
|
||||||
@ -285,7 +286,7 @@ object CmdDisassembler {
|
|||||||
Opcode.PUSH_TRY ->
|
Opcode.PUSH_TRY ->
|
||||||
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
listOf(OperandKind.SLOT, OperandKind.IP, OperandKind.IP)
|
||||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE,
|
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 ->
|
Opcode.ASSIGN_DESTRUCTURE ->
|
||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.ADD_INT, Opcode.SUB_INT, Opcode.MUL_INT, Opcode.DIV_INT, Opcode.MOD_INT,
|
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() {
|
class CmdDeclDestructure(internal val constId: Int, internal val slot: Int) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
val decl = frame.fn.constants[constId] as? BytecodeConst.DestructureDecl
|
val decl = frame.fn.constants[constId] as? BytecodeConst.DestructureDecl
|
||||||
|
|||||||
@ -167,6 +167,7 @@ enum class Opcode(val code: Int) {
|
|||||||
DELEGATED_SET_LOCAL(0xC3),
|
DELEGATED_SET_LOCAL(0xC3),
|
||||||
BIND_DELEGATE_LOCAL(0xC4),
|
BIND_DELEGATE_LOCAL(0xC4),
|
||||||
DECL_FUNCTION(0xC5),
|
DECL_FUNCTION(0xC5),
|
||||||
|
DECL_CLASS(0xC6),
|
||||||
;
|
;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@ -260,7 +260,9 @@ class BytecodeRecentOpsTest {
|
|||||||
assertNotNull(moduleFn, "module bytecode missing")
|
assertNotNull(moduleFn, "module bytecode missing")
|
||||||
val disasm = CmdDisassembler.disassemble(moduleFn)
|
val disasm = CmdDisassembler.disassemble(moduleFn)
|
||||||
assertTrue(!disasm.contains("CALL_SLOT"), disasm)
|
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
|
@Test
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user