Compare commits
No commits in common. "7b70a37e90ea1dd524fe757485de97e8cc8a822c" and "3391da595f554edab236fa02a4822356e9ecb592" have entirely different histories.
7b70a37e90
...
3391da595f
@ -1,32 +0,0 @@
|
|||||||
# Bytecode Migration Plan
|
|
||||||
|
|
||||||
Goal: migrate :lynglib compiler/runtime so values live in frame slots and bytecode is the default execution path.
|
|
||||||
|
|
||||||
## Step 1: Imports as module slots (done)
|
|
||||||
- [x] Seed module slot plans from import bindings (lazy, unused imports do not allocate).
|
|
||||||
- [x] Avoid mutating scopes during compile-time imports; bind slots at runtime instead.
|
|
||||||
- [x] Make runtime member access honor extensions (methods + properties).
|
|
||||||
- [x] Ensure class members (ObjClass instances) resolve by slot id in bytecode runtime.
|
|
||||||
- [x] Expose `Iterator` in root scope so stdlib externs bind at runtime.
|
|
||||||
|
|
||||||
## Step 2: Class-scope member refs + qualified-this refs (pending)
|
|
||||||
- [ ] Bytecode-compile `ClassScopeMemberRef` (currently forced to AST in `Compiler.containsUnsupportedRef`).
|
|
||||||
- [ ] Bytecode-compile `QualifiedThisFieldSlotRef` / `QualifiedThisMethodSlotCallRef`.
|
|
||||||
- [ ] Ensure slot resolution uses class member ids, not scope lookup; no fallback opcodes.
|
|
||||||
- [ ] Add coverage for class static access + qualified-this access to keep JVM tests green.
|
|
||||||
|
|
||||||
## Step 3: Expand bytecode coverage for control flow + literals (pending)
|
|
||||||
- [ ] Add bytecode support for `TryStatement` (catch/finally) in `Compiler.containsUnsupportedForBytecode` and `BytecodeCompiler`.
|
|
||||||
- [ ] Support `WhenStatement` conditions beyond the current limited set.
|
|
||||||
- [ ] Add map literal spread support (currently throws in `BytecodeCompiler`).
|
|
||||||
- [ ] Remove remaining `BytecodeCompileException` cases for common member access (missing id paths).
|
|
||||||
|
|
||||||
## Known bytecode gaps (from current guards)
|
|
||||||
- [ ] `TryStatement` is always excluded by `Compiler.containsUnsupportedForBytecode`.
|
|
||||||
- [ ] `ClassScopeMemberRef` and qualified-this refs are excluded by `Compiler.containsUnsupportedRef`.
|
|
||||||
- [ ] `BytecodeCompiler` rejects map literal spreads and some argument expressions.
|
|
||||||
- [ ] Member access still fails when compile-time receiver class cannot be resolved.
|
|
||||||
|
|
||||||
## Validation
|
|
||||||
- [ ] `./gradlew :lynglib:jvmTest` (full suite) after each step; if failures pre-exist, run targeted tests tied to the change and record the gap in this file.
|
|
||||||
- [ ] Baseline full suite: currently 46 failures on `:lynglib:jvmTest` (run 2026-02-08); keep targeted tests green until the baseline is addressed.
|
|
||||||
@ -37,14 +37,8 @@ class BlockStatement(
|
|||||||
?: applyScope.callScope.resolveCaptureRecord(capture.name)
|
?: applyScope.callScope.resolveCaptureRecord(capture.name)
|
||||||
} else {
|
} else {
|
||||||
scope.resolveCaptureRecord(capture.name)
|
scope.resolveCaptureRecord(capture.name)
|
||||||
}
|
} ?: (applyScope?.callScope ?: scope)
|
||||||
if (rec == null) {
|
|
||||||
if (scope.getSlotIndexOf(capture.name) == null && scope.getLocalRecordDirect(capture.name) == null) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
(applyScope?.callScope ?: scope)
|
|
||||||
.raiseSymbolNotFound("symbol ${capture.name} not found")
|
.raiseSymbolNotFound("symbol ${capture.name} not found")
|
||||||
}
|
|
||||||
target.updateSlotFor(capture.name, rec)
|
target.updateSlotFor(capture.name, rec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -107,12 +107,6 @@ class Compiler(
|
|||||||
if (added && localDeclCountStack.isNotEmpty()) {
|
if (added && localDeclCountStack.isNotEmpty()) {
|
||||||
localDeclCountStack[localDeclCountStack.lastIndex] = currentLocalDeclCount + 1
|
localDeclCountStack[localDeclCountStack.lastIndex] = currentLocalDeclCount + 1
|
||||||
}
|
}
|
||||||
capturePlanStack.lastOrNull()?.let { plan ->
|
|
||||||
if (plan.captureMap.remove(name) != null) {
|
|
||||||
plan.captureOwners.remove(name)
|
|
||||||
plan.captures.removeAll { it.name == name }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
declareSlotName(name, isMutable, isDelegated)
|
declareSlotName(name, isMutable, isDelegated)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,20 +124,6 @@ class Compiler(
|
|||||||
plan.nextIndex += 1
|
plan.nextIndex += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun declareSlotNameAt(
|
|
||||||
plan: SlotPlan,
|
|
||||||
name: String,
|
|
||||||
slotIndex: Int,
|
|
||||||
isMutable: Boolean,
|
|
||||||
isDelegated: Boolean
|
|
||||||
) {
|
|
||||||
if (plan.slots.containsKey(name)) return
|
|
||||||
plan.slots[name] = SlotEntry(slotIndex, isMutable, isDelegated)
|
|
||||||
if (slotIndex >= plan.nextIndex) {
|
|
||||||
plan.nextIndex = slotIndex + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun moduleSlotPlan(): SlotPlan? = slotPlanStack.firstOrNull()
|
private fun moduleSlotPlan(): SlotPlan? = slotPlanStack.firstOrNull()
|
||||||
private val slotTypeByScopeId: MutableMap<Int, MutableMap<Int, ObjClass>> = mutableMapOf()
|
private val slotTypeByScopeId: MutableMap<Int, MutableMap<Int, ObjClass>> = mutableMapOf()
|
||||||
private val nameObjClass: MutableMap<String, ObjClass> = mutableMapOf()
|
private val nameObjClass: MutableMap<String, ObjClass> = mutableMapOf()
|
||||||
@ -231,20 +211,6 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun seedSlotPlanFromSeedScope(scope: Scope) {
|
|
||||||
val plan = moduleSlotPlan() ?: return
|
|
||||||
for ((name, slotIndex) in scope.slotNameToIndexSnapshot()) {
|
|
||||||
val record = scope.getSlotRecord(slotIndex)
|
|
||||||
declareSlotNameAt(
|
|
||||||
plan,
|
|
||||||
name,
|
|
||||||
slotIndex,
|
|
||||||
record.isMutable,
|
|
||||||
record.type == ObjRecord.Type.Delegated
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun predeclareTopLevelSymbols() {
|
private fun predeclareTopLevelSymbols() {
|
||||||
val plan = moduleSlotPlan() ?: return
|
val plan = moduleSlotPlan() ?: return
|
||||||
val saved = cc.savePos()
|
val saved = cc.savePos()
|
||||||
@ -482,11 +448,11 @@ class Compiler(
|
|||||||
val scopeRec = seedScope?.get(name) ?: importManager.rootScope.get(name)
|
val scopeRec = seedScope?.get(name) ?: importManager.rootScope.get(name)
|
||||||
val clsFromScope = scopeRec?.value as? ObjClass
|
val clsFromScope = scopeRec?.value as? ObjClass
|
||||||
val clsFromImports = if (clsFromScope == null) {
|
val clsFromImports = if (clsFromScope == null) {
|
||||||
importedModules.asReversed().firstNotNullOfOrNull { it.scope.get(name)?.value as? ObjClass }
|
importedScopes.asReversed().firstNotNullOfOrNull { it.get(name)?.value as? ObjClass }
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
val cls = clsFromScope ?: clsFromImports ?: resolveClassByName(name) ?: return null
|
val cls = clsFromScope ?: clsFromImports ?: return null
|
||||||
val fieldIds = cls.instanceFieldIdMap()
|
val fieldIds = cls.instanceFieldIdMap()
|
||||||
val methodIds = cls.instanceMethodIdMap(includeAbstract = true)
|
val methodIds = cls.instanceMethodIdMap(includeAbstract = true)
|
||||||
val baseNames = cls.directParents.map { it.className }
|
val baseNames = cls.directParents.map { it.className }
|
||||||
@ -870,12 +836,6 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
val moduleLoc = if (slotPlanStack.size == 1) lookupSlotLocation(name, includeModule = true) else null
|
val moduleLoc = if (slotPlanStack.size == 1) lookupSlotLocation(name, includeModule = true) else null
|
||||||
if (moduleLoc != null) {
|
if (moduleLoc != null) {
|
||||||
val moduleDeclaredNames = localNamesStack.firstOrNull()
|
|
||||||
if (moduleDeclaredNames == null || !moduleDeclaredNames.contains(name)) {
|
|
||||||
resolveImportBinding(name, pos)?.let { resolved ->
|
|
||||||
registerImportBinding(name, resolved.binding, pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val ref = LocalSlotRef(
|
val ref = LocalSlotRef(
|
||||||
name,
|
name,
|
||||||
moduleLoc.slot,
|
moduleLoc.slot,
|
||||||
@ -894,18 +854,28 @@ class Compiler(
|
|||||||
val ids = resolveMemberIds(name, pos, null)
|
val ids = resolveMemberIds(name, pos, null)
|
||||||
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, currentImplicitThisTypeName())
|
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, currentImplicitThisTypeName())
|
||||||
}
|
}
|
||||||
val implicitTypeFromFunc = implicitReceiverTypeForMember(name)
|
if (classCtx != null) {
|
||||||
val hasImplicitClassMember = classCtx != null && hasImplicitThisMember(name, classCtx.name)
|
val implicitType = classCtx.name
|
||||||
if (implicitTypeFromFunc == null && !hasImplicitClassMember) {
|
if (hasImplicitThisMember(name, implicitType)) {
|
||||||
|
resolutionSink?.referenceMember(name, pos, implicitType)
|
||||||
|
val ids = resolveImplicitThisMemberIds(name, pos, implicitType)
|
||||||
|
val preferredType = if (currentImplicitThisTypeName() == null) null else implicitType
|
||||||
|
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, preferredType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val implicitType = implicitReceiverTypeForMember(name)
|
||||||
|
if (implicitType != null) {
|
||||||
|
resolutionSink?.referenceMember(name, pos, implicitType)
|
||||||
|
val ids = resolveImplicitThisMemberIds(name, pos, implicitType)
|
||||||
|
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, implicitType)
|
||||||
|
}
|
||||||
|
if (classCtx != null && classCtx.classScopeMembers.contains(name)) {
|
||||||
|
resolutionSink?.referenceMember(name, pos, classCtx.name)
|
||||||
|
return ClassScopeMemberRef(name, pos, classCtx.name)
|
||||||
|
}
|
||||||
val modulePlan = moduleSlotPlan()
|
val modulePlan = moduleSlotPlan()
|
||||||
val moduleEntry = modulePlan?.slots?.get(name)
|
val moduleEntry = modulePlan?.slots?.get(name)
|
||||||
if (moduleEntry != null) {
|
if (moduleEntry != null) {
|
||||||
val moduleDeclaredNames = localNamesStack.firstOrNull()
|
|
||||||
if (moduleDeclaredNames == null || !moduleDeclaredNames.contains(name)) {
|
|
||||||
resolveImportBinding(name, pos)?.let { resolved ->
|
|
||||||
registerImportBinding(name, resolved.binding, pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val moduleLoc = SlotLocation(
|
val moduleLoc = SlotLocation(
|
||||||
moduleEntry.index,
|
moduleEntry.index,
|
||||||
slotPlanStack.size - 1,
|
slotPlanStack.size - 1,
|
||||||
@ -929,40 +899,19 @@ class Compiler(
|
|||||||
resolutionSink?.reference(name, pos)
|
resolutionSink?.reference(name, pos)
|
||||||
return ref
|
return ref
|
||||||
}
|
}
|
||||||
resolveImportBinding(name, pos)?.let { resolved ->
|
val rootRecord = importManager.rootScope.objects[name]
|
||||||
val sourceRecord = resolved.record
|
if (rootRecord != null && rootRecord.visibility.isPublic) {
|
||||||
if (modulePlan != null && !modulePlan.slots.containsKey(name)) {
|
modulePlan?.let { plan ->
|
||||||
val seedSlotIndex = if (resolved.binding.source is ImportBindingSource.Seed) {
|
declareSlotNameIn(plan, name, rootRecord.isMutable, rootRecord.type == ObjRecord.Type.Delegated)
|
||||||
seedScope?.getSlotIndexOf(name)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
if (seedSlotIndex != null) {
|
val rootSlot = lookupSlotLocation(name)
|
||||||
declareSlotNameAt(
|
if (rootSlot != null) {
|
||||||
modulePlan,
|
|
||||||
name,
|
|
||||||
seedSlotIndex,
|
|
||||||
sourceRecord.isMutable,
|
|
||||||
sourceRecord.type == ObjRecord.Type.Delegated
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
declareSlotNameIn(
|
|
||||||
modulePlan,
|
|
||||||
name,
|
|
||||||
sourceRecord.isMutable,
|
|
||||||
sourceRecord.type == ObjRecord.Type.Delegated
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
registerImportBinding(name, resolved.binding, pos)
|
|
||||||
val slot = lookupSlotLocation(name)
|
|
||||||
if (slot != null) {
|
|
||||||
val ref = LocalSlotRef(
|
val ref = LocalSlotRef(
|
||||||
name,
|
name,
|
||||||
slot.slot,
|
rootSlot.slot,
|
||||||
slot.scopeId,
|
rootSlot.scopeId,
|
||||||
slot.isMutable,
|
rootSlot.isMutable,
|
||||||
slot.isDelegated,
|
rootSlot.isDelegated,
|
||||||
pos,
|
pos,
|
||||||
strictSlotRefs
|
strictSlotRefs
|
||||||
)
|
)
|
||||||
@ -970,26 +919,6 @@ class Compiler(
|
|||||||
return ref
|
return ref
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (classCtx != null) {
|
|
||||||
val implicitType = classCtx.name
|
|
||||||
if (hasImplicitThisMember(name, implicitType)) {
|
|
||||||
resolutionSink?.referenceMember(name, pos, implicitType)
|
|
||||||
val ids = resolveImplicitThisMemberIds(name, pos, implicitType)
|
|
||||||
val preferredType = if (currentImplicitThisTypeName() == null) null else implicitType
|
|
||||||
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, preferredType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val implicitType = implicitTypeFromFunc
|
|
||||||
if (implicitType != null) {
|
|
||||||
resolutionSink?.referenceMember(name, pos, implicitType)
|
|
||||||
val ids = resolveImplicitThisMemberIds(name, pos, implicitType)
|
|
||||||
return ImplicitThisMemberRef(name, pos, ids.fieldId, ids.methodId, implicitType)
|
|
||||||
}
|
|
||||||
if (classCtx != null && classCtx.classScopeMembers.contains(name)) {
|
|
||||||
resolutionSink?.referenceMember(name, pos, classCtx.name)
|
|
||||||
return ClassScopeMemberRef(name, pos, classCtx.name)
|
|
||||||
}
|
|
||||||
val classContext = codeContexts.any { ctx -> ctx is CodeContext.ClassBody }
|
val classContext = codeContexts.any { ctx -> ctx is CodeContext.ClassBody }
|
||||||
if (classContext && extensionNames.contains(name)) {
|
if (classContext && extensionNames.contains(name)) {
|
||||||
resolutionSink?.referenceMember(name, pos)
|
resolutionSink?.referenceMember(name, pos)
|
||||||
@ -1031,10 +960,7 @@ class Compiler(
|
|||||||
private val seedScope: Scope? = settings.seedScope
|
private val seedScope: Scope? = settings.seedScope
|
||||||
private var resolutionScriptDepth = 0
|
private var resolutionScriptDepth = 0
|
||||||
private val resolutionPredeclared = mutableSetOf<String>()
|
private val resolutionPredeclared = mutableSetOf<String>()
|
||||||
private data class ImportedModule(val scope: ModuleScope, val pos: Pos)
|
private val importedScopes = mutableListOf<Scope>()
|
||||||
private data class ImportBindingResolution(val binding: ImportBinding, val record: ObjRecord)
|
|
||||||
private val importedModules = mutableListOf<ImportedModule>()
|
|
||||||
private val importBindings = mutableMapOf<String, ImportBinding>()
|
|
||||||
private val enumEntriesByName = mutableMapOf<String, List<String>>()
|
private val enumEntriesByName = mutableMapOf<String, List<String>>()
|
||||||
|
|
||||||
// --- Doc-comment collection state (for immediate preceding declarations) ---
|
// --- Doc-comment collection state (for immediate preceding declarations) ---
|
||||||
@ -1071,118 +997,6 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun seedNameObjClassFromScope(scope: Scope) {
|
|
||||||
var current: Scope? = scope
|
|
||||||
while (current != null) {
|
|
||||||
for ((name, record) in current.objects) {
|
|
||||||
if (!record.visibility.isPublic) continue
|
|
||||||
if (nameObjClass.containsKey(name)) continue
|
|
||||||
when (val value = record.value) {
|
|
||||||
is ObjClass -> nameObjClass[name] = value
|
|
||||||
is ObjInstance -> nameObjClass[name] = value.objClass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current = current.parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun resolveImportBinding(name: String, pos: Pos): ImportBindingResolution? {
|
|
||||||
val seedRecord = findSeedScopeRecord(name)?.takeIf { it.visibility.isPublic }
|
|
||||||
val rootRecord = importManager.rootScope.objects[name]?.takeIf { it.visibility.isPublic }
|
|
||||||
val moduleMatches = LinkedHashMap<String, Pair<ImportedModule, ObjRecord>>()
|
|
||||||
for (module in importedModules.asReversed()) {
|
|
||||||
val found = LinkedHashMap<String, Pair<ModuleScope, ObjRecord>>()
|
|
||||||
collectModuleRecordMatches(module.scope, name, mutableSetOf(), found)
|
|
||||||
for ((pkg, pair) in found) {
|
|
||||||
moduleMatches.putIfAbsent(pkg, ImportedModule(pair.first, module.pos) to pair.second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (seedRecord != null) {
|
|
||||||
val value = seedRecord.value
|
|
||||||
if (!nameObjClass.containsKey(name)) {
|
|
||||||
when (value) {
|
|
||||||
is ObjClass -> nameObjClass[name] = value
|
|
||||||
is ObjInstance -> nameObjClass[name] = value.objClass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ImportBindingResolution(ImportBinding(name, ImportBindingSource.Seed), seedRecord)
|
|
||||||
}
|
|
||||||
if (rootRecord != null) {
|
|
||||||
val value = rootRecord.value
|
|
||||||
if (!nameObjClass.containsKey(name)) {
|
|
||||||
when (value) {
|
|
||||||
is ObjClass -> nameObjClass[name] = value
|
|
||||||
is ObjInstance -> nameObjClass[name] = value.objClass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ImportBindingResolution(ImportBinding(name, ImportBindingSource.Root), rootRecord)
|
|
||||||
}
|
|
||||||
if (moduleMatches.isEmpty()) return null
|
|
||||||
if (moduleMatches.size > 1) {
|
|
||||||
val moduleNames = moduleMatches.keys.toList()
|
|
||||||
throw ScriptError(pos, "symbol $name is ambiguous between imports: ${moduleNames.joinToString(", ")}")
|
|
||||||
}
|
|
||||||
val (module, record) = moduleMatches.values.first()
|
|
||||||
val binding = ImportBinding(name, ImportBindingSource.Module(module.scope.packageName, module.pos))
|
|
||||||
val value = record.value
|
|
||||||
if (!nameObjClass.containsKey(name)) {
|
|
||||||
when (value) {
|
|
||||||
is ObjClass -> nameObjClass[name] = value
|
|
||||||
is ObjInstance -> nameObjClass[name] = value.objClass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ImportBindingResolution(binding, record)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectModuleRecordMatches(
|
|
||||||
scope: ModuleScope,
|
|
||||||
name: String,
|
|
||||||
visited: MutableSet<String>,
|
|
||||||
out: MutableMap<String, Pair<ModuleScope, ObjRecord>>
|
|
||||||
) {
|
|
||||||
if (!visited.add(scope.packageName)) return
|
|
||||||
val record = scope.objects[name]
|
|
||||||
if (record != null && record.visibility.isPublic) {
|
|
||||||
out.putIfAbsent(scope.packageName, scope to record)
|
|
||||||
}
|
|
||||||
for (child in scope.importedModules) {
|
|
||||||
collectModuleRecordMatches(child, name, visited, out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun registerImportBinding(name: String, binding: ImportBinding, pos: Pos) {
|
|
||||||
val existing = importBindings[name] ?: run {
|
|
||||||
importBindings[name] = binding
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!sameImportBinding(existing, binding)) {
|
|
||||||
throw ScriptError(pos, "symbol $name resolves to multiple imports")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun sameImportBinding(left: ImportBinding, right: ImportBinding): Boolean {
|
|
||||||
if (left.symbol != right.symbol) return false
|
|
||||||
val leftSrc = left.source
|
|
||||||
val rightSrc = right.source
|
|
||||||
return when (leftSrc) {
|
|
||||||
is ImportBindingSource.Module -> {
|
|
||||||
rightSrc is ImportBindingSource.Module && leftSrc.name == rightSrc.name
|
|
||||||
}
|
|
||||||
ImportBindingSource.Root -> rightSrc is ImportBindingSource.Root
|
|
||||||
ImportBindingSource.Seed -> rightSrc is ImportBindingSource.Seed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findSeedScopeRecord(name: String): ObjRecord? {
|
|
||||||
var current = seedScope
|
|
||||||
var hops = 0
|
|
||||||
while (current != null && hops++ < 1024) {
|
|
||||||
current.objects[name]?.let { return it }
|
|
||||||
current = current.parent
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun shouldSeedDefaultStdlib(): Boolean {
|
private fun shouldSeedDefaultStdlib(): Boolean {
|
||||||
if (seedScope != null) return false
|
if (seedScope != null) return false
|
||||||
if (importManager !== Script.defaultImportManager) return false
|
if (importManager !== Script.defaultImportManager) return false
|
||||||
@ -1402,25 +1216,15 @@ class Compiler(
|
|||||||
val needsSlotPlan = slotPlanStack.isEmpty()
|
val needsSlotPlan = slotPlanStack.isEmpty()
|
||||||
if (needsSlotPlan) {
|
if (needsSlotPlan) {
|
||||||
slotPlanStack.add(SlotPlan(mutableMapOf(), 0, nextScopeId++))
|
slotPlanStack.add(SlotPlan(mutableMapOf(), 0, nextScopeId++))
|
||||||
seedScope?.let { scope ->
|
declareSlotNameIn(slotPlanStack.last(), "__PACKAGE__", isMutable = false, isDelegated = false)
|
||||||
if (scope !is ModuleScope) {
|
declareSlotNameIn(slotPlanStack.last(), "$~", isMutable = true, isDelegated = false)
|
||||||
seedSlotPlanFromSeedScope(scope)
|
seedScope?.let { seedSlotPlanFromScope(it, includeParents = true) }
|
||||||
}
|
seedSlotPlanFromScope(importManager.rootScope)
|
||||||
}
|
|
||||||
val plan = slotPlanStack.last()
|
|
||||||
if (!plan.slots.containsKey("__PACKAGE__")) {
|
|
||||||
declareSlotNameIn(plan, "__PACKAGE__", isMutable = false, isDelegated = false)
|
|
||||||
}
|
|
||||||
if (!plan.slots.containsKey("$~")) {
|
|
||||||
declareSlotNameIn(plan, "$~", isMutable = true, isDelegated = false)
|
|
||||||
}
|
|
||||||
seedScope?.let { seedNameObjClassFromScope(it) }
|
|
||||||
seedNameObjClassFromScope(importManager.rootScope)
|
|
||||||
if (shouldSeedDefaultStdlib()) {
|
if (shouldSeedDefaultStdlib()) {
|
||||||
val stdlib = importManager.prepareImport(start, "lyng.stdlib", null)
|
val stdlib = importManager.prepareImport(start, "lyng.stdlib", null)
|
||||||
seedResolutionFromScope(stdlib, start)
|
seedResolutionFromScope(stdlib, start)
|
||||||
seedNameObjClassFromScope(stdlib)
|
seedSlotPlanFromScope(stdlib)
|
||||||
importedModules.add(ImportedModule(stdlib, start))
|
importedScopes.add(stdlib)
|
||||||
}
|
}
|
||||||
predeclareTopLevelSymbols()
|
predeclareTopLevelSymbols()
|
||||||
}
|
}
|
||||||
@ -1489,8 +1293,16 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val module = importManager.prepareImport(pos, name, null)
|
val module = importManager.prepareImport(pos, name, null)
|
||||||
importedModules.add(ImportedModule(module, pos))
|
importedScopes.add(module)
|
||||||
seedResolutionFromScope(module, pos)
|
seedResolutionFromScope(module, pos)
|
||||||
|
seedSlotPlanFromScope(module)
|
||||||
|
statements += object : Statement() {
|
||||||
|
override val pos: Pos = pos
|
||||||
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
|
module.importInto(scope, null)
|
||||||
|
return ObjVoid
|
||||||
|
}
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1524,8 +1336,7 @@ class Compiler(
|
|||||||
statements.isNotEmpty() &&
|
statements.isNotEmpty() &&
|
||||||
codeContexts.lastOrNull() is CodeContext.Module &&
|
codeContexts.lastOrNull() is CodeContext.Module &&
|
||||||
resolutionScriptDepth == 1 &&
|
resolutionScriptDepth == 1 &&
|
||||||
statements.none { containsUnsupportedForBytecode(it) } &&
|
statements.none { containsUnsupportedForBytecode(it) }
|
||||||
statements.none { containsDelegatedRefs(it) }
|
|
||||||
val finalStatements = if (wrapScriptBytecode) {
|
val finalStatements = if (wrapScriptBytecode) {
|
||||||
val unwrapped = statements.map { unwrapBytecodeDeep(it) }
|
val unwrapped = statements.map { unwrapBytecodeDeep(it) }
|
||||||
val block = InlineBlockStatement(unwrapped, start)
|
val block = InlineBlockStatement(unwrapped, start)
|
||||||
@ -1543,8 +1354,7 @@ class Compiler(
|
|||||||
} else {
|
} else {
|
||||||
statements
|
statements
|
||||||
}
|
}
|
||||||
val moduleRefs = importedModules.map { ImportBindingSource.Module(it.scope.packageName, it.pos) }
|
Script(start, finalStatements, modulePlan)
|
||||||
Script(start, finalStatements, modulePlan, importBindings.toMap(), moduleRefs)
|
|
||||||
}.also {
|
}.also {
|
||||||
// Best-effort script end notification (use current position)
|
// Best-effort script end notification (use current position)
|
||||||
miniSink?.onScriptEnd(
|
miniSink?.onScriptEnd(
|
||||||
@ -1605,23 +1415,8 @@ class Compiler(
|
|||||||
val candidates = mutableListOf(typeName)
|
val candidates = mutableListOf(typeName)
|
||||||
cls?.mro?.forEach { candidates.add(it.className) }
|
cls?.mro?.forEach { candidates.add(it.className) }
|
||||||
for (baseName in candidates) {
|
for (baseName in candidates) {
|
||||||
val wrapperNames = listOf(
|
val wrapperName = extensionCallableName(baseName, memberName)
|
||||||
extensionCallableName(baseName, memberName),
|
if (seedScope?.get(wrapperName) != null || importManager.rootScope.get(wrapperName) != null) {
|
||||||
extensionPropertyGetterName(baseName, memberName),
|
|
||||||
extensionPropertySetterName(baseName, memberName)
|
|
||||||
)
|
|
||||||
for (wrapperName in wrapperNames) {
|
|
||||||
val resolved = resolveImportBinding(wrapperName, Pos.builtIn) ?: continue
|
|
||||||
val plan = moduleSlotPlan()
|
|
||||||
if (plan != null && !plan.slots.containsKey(wrapperName)) {
|
|
||||||
declareSlotNameIn(
|
|
||||||
plan,
|
|
||||||
wrapperName,
|
|
||||||
resolved.record.isMutable,
|
|
||||||
resolved.record.type == ObjRecord.Type.Delegated
|
|
||||||
)
|
|
||||||
}
|
|
||||||
registerImportBinding(wrapperName, resolved.binding, Pos.builtIn)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1783,8 +1578,8 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
addScope(seedScope)
|
addScope(seedScope)
|
||||||
addScope(importManager.rootScope)
|
addScope(importManager.rootScope)
|
||||||
for (module in importedModules) {
|
for (scope in importedScopes) {
|
||||||
addScope(module.scope)
|
addScope(scope)
|
||||||
}
|
}
|
||||||
for (name in compileClassInfos.keys) {
|
for (name in compileClassInfos.keys) {
|
||||||
val cls = resolveClassByName(name) ?: continue
|
val cls = resolveClassByName(name) ?: continue
|
||||||
@ -1812,7 +1607,10 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
if (stmt is FunctionDeclStatement ||
|
if (stmt is FunctionDeclStatement ||
|
||||||
stmt is ClassDeclStatement ||
|
stmt is ClassDeclStatement ||
|
||||||
stmt is EnumDeclStatement
|
stmt is EnumDeclStatement ||
|
||||||
|
stmt is BreakStatement ||
|
||||||
|
stmt is ContinueStatement ||
|
||||||
|
stmt is ReturnStatement
|
||||||
) {
|
) {
|
||||||
return stmt
|
return stmt
|
||||||
}
|
}
|
||||||
@ -1935,11 +1733,8 @@ class Compiler(
|
|||||||
containsUnsupportedRef(ref.condition) || containsUnsupportedRef(ref.ifTrue) || containsUnsupportedRef(ref.ifFalse)
|
containsUnsupportedRef(ref.condition) || containsUnsupportedRef(ref.ifTrue) || containsUnsupportedRef(ref.ifFalse)
|
||||||
is ElvisRef -> containsUnsupportedRef(ref.left) || containsUnsupportedRef(ref.right)
|
is ElvisRef -> containsUnsupportedRef(ref.left) || containsUnsupportedRef(ref.right)
|
||||||
is FieldRef -> {
|
is FieldRef -> {
|
||||||
val receiverClass = resolveReceiverClassForMember(ref.target) ?: return true
|
val receiverClass = resolveReceiverClassForMember(ref.target)
|
||||||
if (receiverClass == ObjDynamic.type) return true
|
if (receiverClass == ObjDynamic.type) return true
|
||||||
val hasMember = receiverClass.instanceFieldIdMap()[ref.name] != null ||
|
|
||||||
receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name] != null
|
|
||||||
if (!hasMember && !hasExtensionFor(receiverClass.className, ref.name)) return true
|
|
||||||
containsUnsupportedRef(ref.target)
|
containsUnsupportedRef(ref.target)
|
||||||
}
|
}
|
||||||
is IndexRef -> containsUnsupportedRef(ref.targetRef) || containsUnsupportedRef(ref.indexRef)
|
is IndexRef -> containsUnsupportedRef(ref.targetRef) || containsUnsupportedRef(ref.indexRef)
|
||||||
@ -1955,24 +1750,12 @@ class Compiler(
|
|||||||
is net.sergeych.lyng.obj.MapLiteralEntry.Spread -> containsUnsupportedRef(it.ref)
|
is net.sergeych.lyng.obj.MapLiteralEntry.Spread -> containsUnsupportedRef(it.ref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is CallRef -> {
|
is CallRef -> containsUnsupportedRef(ref.target) || ref.args.any { containsUnsupportedForBytecode(it.value) }
|
||||||
val targetName = when (val target = ref.target) {
|
|
||||||
is LocalVarRef -> target.name
|
|
||||||
is LocalSlotRef -> target.name
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
if (targetName == "delay") return true
|
|
||||||
containsUnsupportedRef(ref.target) || ref.args.any { containsUnsupportedForBytecode(it.value) }
|
|
||||||
}
|
|
||||||
is MethodCallRef -> {
|
is MethodCallRef -> {
|
||||||
if (ref.name == "delay") return true
|
val receiverClass = resolveReceiverClassForMember(ref.receiver)
|
||||||
val receiverClass = resolveReceiverClassForMember(ref.receiver) ?: return true
|
|
||||||
if (receiverClass == ObjDynamic.type) return true
|
if (receiverClass == ObjDynamic.type) return true
|
||||||
val hasMember = receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name] != null
|
|
||||||
if (!hasMember && !hasExtensionFor(receiverClass.className, ref.name)) return true
|
|
||||||
containsUnsupportedRef(ref.receiver) || ref.args.any { containsUnsupportedForBytecode(it.value) }
|
containsUnsupportedRef(ref.receiver) || ref.args.any { containsUnsupportedForBytecode(it.value) }
|
||||||
}
|
}
|
||||||
is ImplicitThisMethodCallRef -> true
|
|
||||||
is QualifiedThisMethodSlotCallRef -> true
|
is QualifiedThisMethodSlotCallRef -> true
|
||||||
is QualifiedThisFieldSlotRef -> true
|
is QualifiedThisFieldSlotRef -> true
|
||||||
is ClassScopeMemberRef -> true
|
is ClassScopeMemberRef -> true
|
||||||
@ -1986,7 +1769,7 @@ class Compiler(
|
|||||||
is ExpressionStatement -> containsDelegatedRefs(target.ref)
|
is ExpressionStatement -> containsDelegatedRefs(target.ref)
|
||||||
is BlockStatement -> target.statements().any { containsDelegatedRefs(it) }
|
is BlockStatement -> target.statements().any { containsDelegatedRefs(it) }
|
||||||
is VarDeclStatement -> target.initializer?.let { containsDelegatedRefs(it) } ?: false
|
is VarDeclStatement -> target.initializer?.let { containsDelegatedRefs(it) } ?: false
|
||||||
is DelegatedVarDeclStatement -> true
|
is DelegatedVarDeclStatement -> containsDelegatedRefs(target.initializer)
|
||||||
is DestructuringVarDeclStatement -> containsDelegatedRefs(target.initializer)
|
is DestructuringVarDeclStatement -> containsDelegatedRefs(target.initializer)
|
||||||
is IfStatement -> {
|
is IfStatement -> {
|
||||||
containsDelegatedRefs(target.condition) ||
|
containsDelegatedRefs(target.condition) ||
|
||||||
@ -2032,18 +1815,6 @@ class Compiler(
|
|||||||
private fun containsDelegatedRefs(ref: ObjRef): Boolean {
|
private fun containsDelegatedRefs(ref: ObjRef): Boolean {
|
||||||
return when (ref) {
|
return when (ref) {
|
||||||
is LocalSlotRef -> ref.isDelegated
|
is LocalSlotRef -> ref.isDelegated
|
||||||
is ImplicitThisMemberRef -> {
|
|
||||||
val typeName = ref.preferredThisTypeName() ?: currentImplicitThisTypeName()
|
|
||||||
val targetClass = typeName?.let { resolveClassByName(it) }
|
|
||||||
val member = targetClass?.findFirstConcreteMember(ref.name)
|
|
||||||
member?.type == ObjRecord.Type.Delegated
|
|
||||||
}
|
|
||||||
is ImplicitThisMethodCallRef -> {
|
|
||||||
val typeName = ref.preferredThisTypeName() ?: currentImplicitThisTypeName()
|
|
||||||
val targetClass = typeName?.let { resolveClassByName(it) }
|
|
||||||
val member = targetClass?.findFirstConcreteMember(ref.methodName())
|
|
||||||
member?.type == ObjRecord.Type.Delegated
|
|
||||||
}
|
|
||||||
is BinaryOpRef -> containsDelegatedRefs(ref.left) || containsDelegatedRefs(ref.right)
|
is BinaryOpRef -> containsDelegatedRefs(ref.left) || containsDelegatedRefs(ref.right)
|
||||||
is UnaryOpRef -> containsDelegatedRefs(ref.a)
|
is UnaryOpRef -> containsDelegatedRefs(ref.a)
|
||||||
is CastRef -> containsDelegatedRefs(ref.castValueRef()) || containsDelegatedRefs(ref.castTypeRef())
|
is CastRef -> containsDelegatedRefs(ref.castValueRef()) || containsDelegatedRefs(ref.castTypeRef())
|
||||||
@ -2058,14 +1829,7 @@ class Compiler(
|
|||||||
is ConditionalRef ->
|
is ConditionalRef ->
|
||||||
containsDelegatedRefs(ref.condition) || containsDelegatedRefs(ref.ifTrue) || containsDelegatedRefs(ref.ifFalse)
|
containsDelegatedRefs(ref.condition) || containsDelegatedRefs(ref.ifTrue) || containsDelegatedRefs(ref.ifFalse)
|
||||||
is ElvisRef -> containsDelegatedRefs(ref.left) || containsDelegatedRefs(ref.right)
|
is ElvisRef -> containsDelegatedRefs(ref.left) || containsDelegatedRefs(ref.right)
|
||||||
is FieldRef -> {
|
is FieldRef -> containsDelegatedRefs(ref.target)
|
||||||
val receiverClass = resolveReceiverClassForMember(ref.target)
|
|
||||||
if (receiverClass != null) {
|
|
||||||
val member = receiverClass.findFirstConcreteMember(ref.name)
|
|
||||||
if (member?.type == ObjRecord.Type.Delegated) return true
|
|
||||||
}
|
|
||||||
containsDelegatedRefs(ref.target)
|
|
||||||
}
|
|
||||||
is IndexRef -> containsDelegatedRefs(ref.targetRef) || containsDelegatedRefs(ref.indexRef)
|
is IndexRef -> containsDelegatedRefs(ref.targetRef) || containsDelegatedRefs(ref.indexRef)
|
||||||
is ListLiteralRef -> ref.entries().any {
|
is ListLiteralRef -> ref.entries().any {
|
||||||
when (it) {
|
when (it) {
|
||||||
@ -2080,14 +1844,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is CallRef -> containsDelegatedRefs(ref.target) || ref.args.any { containsDelegatedRefs(it.value) }
|
is CallRef -> containsDelegatedRefs(ref.target) || ref.args.any { containsDelegatedRefs(it.value) }
|
||||||
is MethodCallRef -> {
|
is MethodCallRef -> containsDelegatedRefs(ref.receiver) || ref.args.any { containsDelegatedRefs(it.value) }
|
||||||
val receiverClass = resolveReceiverClassForMember(ref.receiver)
|
|
||||||
if (receiverClass != null) {
|
|
||||||
val member = receiverClass.findFirstConcreteMember(ref.name)
|
|
||||||
if (member?.type == ObjRecord.Type.Delegated) return true
|
|
||||||
}
|
|
||||||
containsDelegatedRefs(ref.receiver) || ref.args.any { containsDelegatedRefs(it.value) }
|
|
||||||
}
|
|
||||||
is StatementRef -> containsDelegatedRefs(ref.statement)
|
is StatementRef -> containsDelegatedRefs(ref.statement)
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
@ -4185,15 +3942,6 @@ class Compiler(
|
|||||||
if (targetClass == ObjInstant.type && (name == "distantFuture" || name == "distantPast")) {
|
if (targetClass == ObjInstant.type && (name == "distantFuture" || name == "distantPast")) {
|
||||||
return ObjInstant.type
|
return ObjInstant.type
|
||||||
}
|
}
|
||||||
if (targetClass == ObjInstant.type && name in listOf(
|
|
||||||
"truncateToMinute",
|
|
||||||
"truncateToSecond",
|
|
||||||
"truncateToMillisecond",
|
|
||||||
"truncateToMicrosecond"
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return ObjInstant.type
|
|
||||||
}
|
|
||||||
if (targetClass == ObjString.type && name == "re") {
|
if (targetClass == ObjString.type && name == "re") {
|
||||||
return ObjRegex.type
|
return ObjRegex.type
|
||||||
}
|
}
|
||||||
@ -4275,7 +4023,6 @@ class Compiler(
|
|||||||
if (isAllowedObjectMember(memberName)) return
|
if (isAllowedObjectMember(memberName)) return
|
||||||
throw ScriptError(pos, "member access requires compile-time receiver type: $memberName")
|
throw ScriptError(pos, "member access requires compile-time receiver type: $memberName")
|
||||||
}
|
}
|
||||||
registerExtensionWrapperBindings(receiverClass, memberName, pos)
|
|
||||||
if (receiverClass == Obj.rootObjectType) {
|
if (receiverClass == Obj.rootObjectType) {
|
||||||
val allowed = isAllowedObjectMember(memberName)
|
val allowed = isAllowedObjectMember(memberName)
|
||||||
if (!allowed && !hasExtensionFor(receiverClass.className, memberName)) {
|
if (!allowed && !hasExtensionFor(receiverClass.className, memberName)) {
|
||||||
@ -4284,29 +4031,6 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerExtensionWrapperBindings(receiverClass: ObjClass, memberName: String, pos: Pos) {
|
|
||||||
for (cls in receiverClass.mro) {
|
|
||||||
val wrapperNames = listOf(
|
|
||||||
extensionCallableName(cls.className, memberName),
|
|
||||||
extensionPropertyGetterName(cls.className, memberName),
|
|
||||||
extensionPropertySetterName(cls.className, memberName)
|
|
||||||
)
|
|
||||||
for (wrapperName in wrapperNames) {
|
|
||||||
val resolved = resolveImportBinding(wrapperName, pos) ?: continue
|
|
||||||
val plan = moduleSlotPlan()
|
|
||||||
if (plan != null && !plan.slots.containsKey(wrapperName)) {
|
|
||||||
declareSlotNameIn(
|
|
||||||
plan,
|
|
||||||
wrapperName,
|
|
||||||
resolved.record.isMutable,
|
|
||||||
resolved.record.type == ObjRecord.Type.Delegated
|
|
||||||
)
|
|
||||||
}
|
|
||||||
registerImportBinding(wrapperName, resolved.binding, pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isAllowedObjectMember(memberName: String): Boolean {
|
private fun isAllowedObjectMember(memberName: String): Boolean {
|
||||||
return when (memberName) {
|
return when (memberName) {
|
||||||
"toString",
|
"toString",
|
||||||
@ -4768,7 +4492,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val implicitThisTypeName = currentImplicitThisTypeName()
|
val implicitThisTypeName = currentImplicitThisTypeName()
|
||||||
val result = when (left) {
|
return when (left) {
|
||||||
is ImplicitThisMemberRef ->
|
is ImplicitThisMemberRef ->
|
||||||
if (left.methodId == null && left.fieldId != null) {
|
if (left.methodId == null && left.fieldId != null) {
|
||||||
CallRef(left, args, detectedBlockArgument, isOptional)
|
CallRef(left, args, detectedBlockArgument, isOptional)
|
||||||
@ -4829,7 +4553,6 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
else -> CallRef(left, args, detectedBlockArgument, isOptional)
|
else -> CallRef(left, args, detectedBlockArgument, isOptional)
|
||||||
}
|
}
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inferReceiverTypeFromArgs(args: List<ParsedArgument>): String? {
|
private fun inferReceiverTypeFromArgs(args: List<ParsedArgument>): String? {
|
||||||
@ -6210,14 +5933,6 @@ class Compiler(
|
|||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
// the main statement should create custom ObjClass instance with field
|
// the main statement should create custom ObjClass instance with field
|
||||||
// accessors, constructor registration, etc.
|
// 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
|
// Resolve parent classes by name at execution time
|
||||||
val parentClasses = baseSpecs.map { baseSpec ->
|
val parentClasses = baseSpecs.map { baseSpec ->
|
||||||
val rec = scope[baseSpec.name]
|
val rec = scope[baseSpec.name]
|
||||||
@ -6854,11 +6569,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val fnStatements = rawFnStatements?.let { stmt ->
|
val fnStatements = rawFnStatements?.let { stmt ->
|
||||||
if (useBytecodeStatements &&
|
if (useBytecodeStatements && !containsUnsupportedForBytecode(stmt)) {
|
||||||
parentContext !is CodeContext.ClassBody &&
|
|
||||||
!containsUnsupportedForBytecode(stmt) &&
|
|
||||||
!containsDelegatedRefs(stmt)
|
|
||||||
) {
|
|
||||||
val paramKnownClasses = mutableMapOf<String, ObjClass>()
|
val paramKnownClasses = mutableMapOf<String, ObjClass>()
|
||||||
for (param in argsDeclaration.params) {
|
for (param in argsDeclaration.params) {
|
||||||
val cls = resolveTypeDeclObjClass(param.type) ?: continue
|
val cls = resolveTypeDeclObjClass(param.type) ?: continue
|
||||||
@ -6922,19 +6633,6 @@ class Compiler(
|
|||||||
val fnCreateStatement = object : Statement() {
|
val fnCreateStatement = object : Statement() {
|
||||||
override val pos: Pos = start
|
override val pos: Pos = start
|
||||||
override suspend fun execute(context: Scope): Obj {
|
override suspend fun execute(context: Scope): Obj {
|
||||||
if (actualExtern && extTypeName == null && parentContext !is CodeContext.ClassBody) {
|
|
||||||
val existing = context.get(name)
|
|
||||||
if (existing != null) {
|
|
||||||
context.addItem(
|
|
||||||
name,
|
|
||||||
false,
|
|
||||||
existing.value,
|
|
||||||
visibility,
|
|
||||||
callSignature = existing.callSignature
|
|
||||||
)
|
|
||||||
return existing.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isDelegated) {
|
if (isDelegated) {
|
||||||
val accessType = ObjString("Callable")
|
val accessType = ObjString("Callable")
|
||||||
val initValue = delegateExpression!!.execute(context)
|
val initValue = delegateExpression!!.execute(context)
|
||||||
@ -7063,9 +6761,7 @@ class Compiler(
|
|||||||
)
|
)
|
||||||
execScope.currentClassCtx = cls
|
execScope.currentClassCtx = cls
|
||||||
compiledFnBody.execute(execScope)
|
compiledFnBody.execute(execScope)
|
||||||
} ?: run {
|
} ?: compiledFnBody.execute(thisObj.autoInstanceScope(this))
|
||||||
compiledFnBody.execute(thisObj.autoInstanceScope(this))
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
this.currentClassCtx = savedCtx
|
this.currentClassCtx = savedCtx
|
||||||
}
|
}
|
||||||
@ -7403,8 +7099,8 @@ class Compiler(
|
|||||||
private fun resolveClassByName(name: String): ObjClass? {
|
private fun resolveClassByName(name: String): ObjClass? {
|
||||||
val rec = seedScope?.get(name) ?: importManager.rootScope.get(name)
|
val rec = seedScope?.get(name) ?: importManager.rootScope.get(name)
|
||||||
(rec?.value as? ObjClass)?.let { return it }
|
(rec?.value as? ObjClass)?.let { return it }
|
||||||
for (module in importedModules.asReversed()) {
|
for (scope in importedScopes.asReversed()) {
|
||||||
val imported = module.scope.get(name)
|
val imported = scope.get(name)
|
||||||
(imported?.value as? ObjClass)?.let { return it }
|
(imported?.value as? ObjClass)?.let { return it }
|
||||||
}
|
}
|
||||||
val info = compileClassInfos[name] ?: return null
|
val info = compileClassInfos[name] ?: return null
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2026 Sergey S. Chernov
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.sergeych.lyng
|
|
||||||
|
|
||||||
sealed class ImportBindingSource {
|
|
||||||
data class Module(val name: String, val pos: Pos) : ImportBindingSource()
|
|
||||||
object Root : ImportBindingSource()
|
|
||||||
object Seed : ImportBindingSource()
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ImportBinding(
|
|
||||||
val symbol: String,
|
|
||||||
val source: ImportBindingSource,
|
|
||||||
)
|
|
||||||
@ -33,8 +33,6 @@ class ModuleScope(
|
|||||||
|
|
||||||
constructor(importProvider: ImportProvider, source: Source) : this(importProvider, source.startPos, source.fileName)
|
constructor(importProvider: ImportProvider, source: Source) : this(importProvider, source.startPos, source.fileName)
|
||||||
|
|
||||||
internal var importedModules: List<ModuleScope> = emptyList()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Import symbols into the scope. It _is called_ after the module is imported by [ImportProvider.prepareImport]
|
* Import symbols into the scope. It _is called_ after the module is imported by [ImportProvider.prepareImport]
|
||||||
* which checks symbol availability and accessibility prior to execution.
|
* which checks symbol availability and accessibility prior to execution.
|
||||||
@ -94,3 +92,4 @@ class ModuleScope(
|
|||||||
super.get(name)
|
super.get(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -463,24 +463,6 @@ open class Scope(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun applySlotPlanReset(plan: Map<String, Int>, records: Map<String, ObjRecord>) {
|
|
||||||
if (plan.isEmpty()) return
|
|
||||||
slots.clear()
|
|
||||||
nameToSlot.clear()
|
|
||||||
val maxIndex = plan.values.maxOrNull() ?: return
|
|
||||||
val targetSize = maxIndex + 1
|
|
||||||
repeat(targetSize) {
|
|
||||||
slots.add(ObjRecord(ObjUnset, isMutable = true))
|
|
||||||
}
|
|
||||||
for ((name, idx) in plan) {
|
|
||||||
nameToSlot[name] = idx
|
|
||||||
val record = records[name]
|
|
||||||
if (record != null && record.value !== ObjUnset) {
|
|
||||||
slots[idx] = record
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun applySlotPlanWithSnapshot(plan: Map<String, Int>): Map<String, Int?> {
|
fun applySlotPlanWithSnapshot(plan: Map<String, Int>): Map<String, Int?> {
|
||||||
if (plan.isEmpty()) return emptyMap()
|
if (plan.isEmpty()) return emptyMap()
|
||||||
val maxIndex = plan.values.maxOrNull() ?: return emptyMap()
|
val maxIndex = plan.values.maxOrNull() ?: return emptyMap()
|
||||||
|
|||||||
@ -33,51 +33,13 @@ class Script(
|
|||||||
override val pos: Pos,
|
override val pos: Pos,
|
||||||
private val statements: List<Statement> = emptyList(),
|
private val statements: List<Statement> = emptyList(),
|
||||||
private val moduleSlotPlan: Map<String, Int> = emptyMap(),
|
private val moduleSlotPlan: Map<String, Int> = emptyMap(),
|
||||||
private val importBindings: Map<String, ImportBinding> = emptyMap(),
|
|
||||||
private val importedModules: List<ImportBindingSource.Module> = emptyList(),
|
|
||||||
// private val catchReturn: Boolean = false,
|
// private val catchReturn: Boolean = false,
|
||||||
) : Statement() {
|
) : Statement() {
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val isModuleScope = scope is ModuleScope
|
if (moduleSlotPlan.isNotEmpty()) {
|
||||||
val shouldSeedModule = isModuleScope || scope.thisObj === ObjVoid
|
scope.applySlotPlan(moduleSlotPlan)
|
||||||
val moduleTarget = scope
|
seedModuleSlots(scope)
|
||||||
if (moduleSlotPlan.isNotEmpty() && shouldSeedModule) {
|
|
||||||
val hasPlanMapping = moduleSlotPlan.keys.any { moduleTarget.getSlotIndexOf(it) != null }
|
|
||||||
val needsReset = moduleTarget is ModuleScope ||
|
|
||||||
moduleTarget.slotCount() == 0 ||
|
|
||||||
moduleTarget.hasSlotPlanConflict(moduleSlotPlan) ||
|
|
||||||
(!hasPlanMapping && moduleTarget.slotCount() > 0)
|
|
||||||
if (needsReset) {
|
|
||||||
val preserved = LinkedHashMap<String, ObjRecord>()
|
|
||||||
for (name in moduleSlotPlan.keys) {
|
|
||||||
moduleTarget.getLocalRecordDirect(name)?.let { preserved[name] = it }
|
|
||||||
}
|
|
||||||
moduleTarget.applySlotPlanReset(moduleSlotPlan, preserved)
|
|
||||||
for (name in moduleSlotPlan.keys) {
|
|
||||||
if (preserved.containsKey(name)) continue
|
|
||||||
val inherited = findSeedRecord(moduleTarget.parent, name)
|
|
||||||
if (inherited != null && inherited.value !== ObjUnset) {
|
|
||||||
moduleTarget.updateSlotFor(name, inherited)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
moduleTarget.applySlotPlan(moduleSlotPlan)
|
|
||||||
for (name in moduleSlotPlan.keys) {
|
|
||||||
val local = moduleTarget.getLocalRecordDirect(name)
|
|
||||||
if (local != null && local.value !== ObjUnset) {
|
|
||||||
moduleTarget.updateSlotFor(name, local)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val inherited = findSeedRecord(moduleTarget.parent, name)
|
|
||||||
if (inherited != null && inherited.value !== ObjUnset) {
|
|
||||||
moduleTarget.updateSlotFor(name, inherited)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (shouldSeedModule) {
|
|
||||||
seedModuleSlots(moduleTarget)
|
|
||||||
}
|
}
|
||||||
var lastResult: Obj = ObjVoid
|
var lastResult: Obj = ObjVoid
|
||||||
for (s in statements) {
|
for (s in statements) {
|
||||||
@ -86,50 +48,24 @@ class Script(
|
|||||||
return lastResult
|
return lastResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun seedModuleSlots(scope: Scope) {
|
private fun seedModuleSlots(scope: Scope) {
|
||||||
if (importBindings.isEmpty() && importedModules.isEmpty()) return
|
val parent = scope.parent ?: return
|
||||||
seedImportBindings(scope)
|
for (name in moduleSlotPlan.keys) {
|
||||||
|
if (scope.objects.containsKey(name)) {
|
||||||
|
scope.updateSlotFor(name, scope.objects[name]!!)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
val seed = findSeedRecord(parent, name)
|
||||||
private suspend fun seedImportBindings(scope: Scope) {
|
if (seed != null) {
|
||||||
val provider = scope.currentImportProvider
|
if (name == "Exception" && seed.value !is ObjClass) {
|
||||||
val importedModules = LinkedHashSet<ModuleScope>()
|
|
||||||
for (moduleRef in this.importedModules) {
|
|
||||||
importedModules.add(provider.prepareImport(moduleRef.pos, moduleRef.name, null))
|
|
||||||
}
|
|
||||||
if (scope is ModuleScope) {
|
|
||||||
scope.importedModules = importedModules.toList()
|
|
||||||
}
|
|
||||||
for ((name, binding) in importBindings) {
|
|
||||||
val record = when (val source = binding.source) {
|
|
||||||
is ImportBindingSource.Module -> {
|
|
||||||
val module = provider.prepareImport(source.pos, source.name, null)
|
|
||||||
importedModules.add(module)
|
|
||||||
module.objects[binding.symbol]?.takeIf { it.visibility.isPublic }
|
|
||||||
?: scope.raiseSymbolNotFound("symbol ${source.name}.${binding.symbol} not found")
|
|
||||||
}
|
|
||||||
ImportBindingSource.Root -> {
|
|
||||||
provider.rootScope.objects[binding.symbol]?.takeIf { it.visibility.isPublic }
|
|
||||||
?: scope.raiseSymbolNotFound("symbol ${binding.symbol} not found")
|
|
||||||
}
|
|
||||||
ImportBindingSource.Seed -> {
|
|
||||||
findSeedRecord(scope, binding.symbol)
|
|
||||||
?: scope.raiseSymbolNotFound("symbol ${binding.symbol} not found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (name == "Exception" && record.value !is ObjClass) {
|
|
||||||
scope.updateSlotFor(name, ObjRecord(ObjException.Root, isMutable = false))
|
scope.updateSlotFor(name, ObjRecord(ObjException.Root, isMutable = false))
|
||||||
} else {
|
} else {
|
||||||
scope.updateSlotFor(name, record)
|
scope.updateSlotFor(name, seed)
|
||||||
}
|
|
||||||
}
|
|
||||||
for (module in importedModules) {
|
|
||||||
for ((cls, map) in module.extensions) {
|
|
||||||
for ((symbol, record) in map) {
|
|
||||||
if (record.visibility.isPublic) {
|
|
||||||
scope.addExtension(cls, symbol, record)
|
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
if (name == "Exception") {
|
||||||
|
scope.updateSlotFor(name, ObjRecord(ObjException.Root, isMutable = false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,15 +85,6 @@ class Script(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveModuleScope(scope: Scope): ModuleScope? {
|
|
||||||
var current: Scope? = scope
|
|
||||||
while (current != null) {
|
|
||||||
if (current is ModuleScope) return current
|
|
||||||
current = current.parent
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun debugStatements(): List<Statement> = statements
|
internal fun debugStatements(): List<Statement> = statements
|
||||||
|
|
||||||
suspend fun execute() = execute(
|
suspend fun execute() = execute(
|
||||||
@ -502,7 +429,6 @@ class Script(
|
|||||||
// interfaces
|
// interfaces
|
||||||
addConst("Iterable", ObjIterable)
|
addConst("Iterable", ObjIterable)
|
||||||
addConst("Collection", ObjCollection)
|
addConst("Collection", ObjCollection)
|
||||||
addConst("Iterator", ObjIterator)
|
|
||||||
addConst("Array", ObjArray)
|
addConst("Array", ObjArray)
|
||||||
addConst("RingBuffer", ObjRingBuffer.type)
|
addConst("RingBuffer", ObjRingBuffer.type)
|
||||||
addConst("Class", ObjClassType)
|
addConst("Class", ObjClassType)
|
||||||
|
|||||||
@ -99,23 +99,7 @@ class BytecodeCompiler(
|
|||||||
is net.sergeych.lyng.InlineBlockStatement -> compileInlineBlock(name, stmt)
|
is net.sergeych.lyng.InlineBlockStatement -> compileInlineBlock(name, stmt)
|
||||||
is VarDeclStatement -> compileVarDecl(name, stmt)
|
is VarDeclStatement -> compileVarDecl(name, stmt)
|
||||||
is DelegatedVarDeclStatement -> {
|
is DelegatedVarDeclStatement -> {
|
||||||
val value = emitDelegatedVarDecl(stmt) ?: return null
|
val value = emitStatementEval(stmt)
|
||||||
builder.emit(Opcode.RET, value.slot)
|
|
||||||
val localCount = maxOf(nextSlot, value.slot + 1) - scopeSlotCount
|
|
||||||
builder.build(
|
|
||||||
name,
|
|
||||||
localCount,
|
|
||||||
addrCount = nextAddrSlot,
|
|
||||||
returnLabels = returnLabels,
|
|
||||||
scopeSlotIndices,
|
|
||||||
scopeSlotNames,
|
|
||||||
scopeSlotIsModule,
|
|
||||||
localSlotNames,
|
|
||||||
localSlotMutables
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is DestructuringVarDeclStatement -> {
|
|
||||||
val value = emitDestructuringVarDecl(stmt) ?: return null
|
|
||||||
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(
|
||||||
@ -211,12 +195,6 @@ class BytecodeCompiler(
|
|||||||
|
|
||||||
private fun allocSlot(): Int = nextSlot++
|
private fun allocSlot(): Int = nextSlot++
|
||||||
|
|
||||||
private fun encodeMemberId(receiverClass: ObjClass, id: Int?): Int? {
|
|
||||||
if (id == null) return null
|
|
||||||
if (receiverClass == ObjClassType) return -(id + 2)
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun compileRef(ref: ObjRef): CompiledValue? {
|
private fun compileRef(ref: ObjRef): CompiledValue? {
|
||||||
return when (ref) {
|
return when (ref) {
|
||||||
is ConstRef -> compileConst(ref.constValue)
|
is ConstRef -> compileConst(ref.constValue)
|
||||||
@ -1626,13 +1604,13 @@ class BytecodeCompiler(
|
|||||||
Pos.builtIn
|
Pos.builtIn
|
||||||
)
|
)
|
||||||
val receiver = compileRefWithFallback(target.target, null, Pos.builtIn) ?: return null
|
val receiver = compileRefWithFallback(target.target, null, Pos.builtIn) ?: return null
|
||||||
val fieldId = receiverClass.instanceFieldIdMap()[target.name]
|
val fieldId = receiverClass.instanceFieldIdMap()[target.name] ?: -1
|
||||||
val methodId = if (fieldId == null) {
|
val methodId = if (fieldId < 0) {
|
||||||
receiverClass.instanceMethodIdMap(includeAbstract = true)[target.name]
|
receiverClass.instanceMethodIdMap(includeAbstract = true)[target.name] ?: -1
|
||||||
} else {
|
} else {
|
||||||
null
|
-1
|
||||||
}
|
}
|
||||||
if (fieldId == null && methodId == null) {
|
if (fieldId < 0 && methodId < 0) {
|
||||||
val extSlot = resolveExtensionSetterSlot(receiverClass, target.name)
|
val extSlot = resolveExtensionSetterSlot(receiverClass, target.name)
|
||||||
?: throw BytecodeCompileException(
|
?: throw BytecodeCompileException(
|
||||||
"Unknown member ${target.name} on ${receiverClass.className}",
|
"Unknown member ${target.name} on ${receiverClass.className}",
|
||||||
@ -1666,10 +1644,8 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
val encodedFieldId = encodeMemberId(receiverClass, fieldId) ?: -1
|
|
||||||
val encodedMethodId = encodeMemberId(receiverClass, methodId) ?: -1
|
|
||||||
if (!target.isOptional) {
|
if (!target.isOptional) {
|
||||||
builder.emit(Opcode.SET_MEMBER_SLOT, receiver.slot, encodedFieldId, encodedMethodId, value.slot)
|
builder.emit(Opcode.SET_MEMBER_SLOT, receiver.slot, fieldId, methodId, value.slot)
|
||||||
} else {
|
} else {
|
||||||
val nullSlot = allocSlot()
|
val nullSlot = allocSlot()
|
||||||
builder.emit(Opcode.CONST_NULL, nullSlot)
|
builder.emit(Opcode.CONST_NULL, nullSlot)
|
||||||
@ -1680,7 +1656,7 @@ class BytecodeCompiler(
|
|||||||
Opcode.JMP_IF_TRUE,
|
Opcode.JMP_IF_TRUE,
|
||||||
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(endLabel))
|
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(endLabel))
|
||||||
)
|
)
|
||||||
builder.emit(Opcode.SET_MEMBER_SLOT, receiver.slot, encodedFieldId, encodedMethodId, value.slot)
|
builder.emit(Opcode.SET_MEMBER_SLOT, receiver.slot, fieldId, methodId, value.slot)
|
||||||
builder.mark(endLabel)
|
builder.mark(endLabel)
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
@ -2056,13 +2032,11 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
val fieldId = receiverClass.instanceFieldIdMap()[ref.name]
|
val fieldId = receiverClass.instanceFieldIdMap()[ref.name]
|
||||||
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name]
|
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name]
|
||||||
val encodedFieldId = encodeMemberId(receiverClass, fieldId)
|
|
||||||
val encodedMethodId = encodeMemberId(receiverClass, methodId)
|
|
||||||
val receiver = compileRefWithFallback(ref.target, null, Pos.builtIn) ?: return null
|
val receiver = compileRefWithFallback(ref.target, null, Pos.builtIn) ?: return null
|
||||||
val dst = allocSlot()
|
val dst = allocSlot()
|
||||||
if (fieldId != null || methodId != null) {
|
if (fieldId != null || methodId != null) {
|
||||||
if (!ref.isOptional) {
|
if (!ref.isOptional) {
|
||||||
builder.emit(Opcode.GET_MEMBER_SLOT, receiver.slot, encodedFieldId ?: -1, encodedMethodId ?: -1, dst)
|
builder.emit(Opcode.GET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, dst)
|
||||||
} else {
|
} else {
|
||||||
val nullSlot = allocSlot()
|
val nullSlot = allocSlot()
|
||||||
builder.emit(Opcode.CONST_NULL, nullSlot)
|
builder.emit(Opcode.CONST_NULL, nullSlot)
|
||||||
@ -2074,7 +2048,7 @@ class BytecodeCompiler(
|
|||||||
Opcode.JMP_IF_TRUE,
|
Opcode.JMP_IF_TRUE,
|
||||||
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(nullLabel))
|
listOf(CmdBuilder.Operand.IntVal(cmpSlot), CmdBuilder.Operand.LabelRef(nullLabel))
|
||||||
)
|
)
|
||||||
builder.emit(Opcode.GET_MEMBER_SLOT, receiver.slot, encodedFieldId ?: -1, encodedMethodId ?: -1, dst)
|
builder.emit(Opcode.GET_MEMBER_SLOT, receiver.slot, fieldId ?: -1, methodId ?: -1, dst)
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
||||||
builder.mark(nullLabel)
|
builder.mark(nullLabel)
|
||||||
builder.emit(Opcode.CONST_NULL, dst)
|
builder.emit(Opcode.CONST_NULL, dst)
|
||||||
@ -2866,12 +2840,11 @@ class BytecodeCompiler(
|
|||||||
val dst = allocSlot()
|
val dst = allocSlot()
|
||||||
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name]
|
val methodId = receiverClass.instanceMethodIdMap(includeAbstract = true)[ref.name]
|
||||||
if (methodId != null) {
|
if (methodId != null) {
|
||||||
val encodedMethodId = encodeMemberId(receiverClass, methodId) ?: methodId
|
|
||||||
if (!ref.isOptional) {
|
if (!ref.isOptional) {
|
||||||
val args = compileCallArgs(ref.args, ref.tailBlock) ?: return null
|
val args = compileCallArgs(ref.args, ref.tailBlock) ?: return null
|
||||||
val encodedCount = encodeCallArgCount(args) ?: return null
|
val encodedCount = encodeCallArgCount(args) ?: return null
|
||||||
setPos(callPos)
|
setPos(callPos)
|
||||||
builder.emit(Opcode.CALL_MEMBER_SLOT, receiver.slot, encodedMethodId, args.base, encodedCount, dst)
|
builder.emit(Opcode.CALL_MEMBER_SLOT, receiver.slot, methodId, args.base, encodedCount, dst)
|
||||||
return CompiledValue(dst, SlotType.OBJ)
|
return CompiledValue(dst, SlotType.OBJ)
|
||||||
}
|
}
|
||||||
val nullSlot = allocSlot()
|
val nullSlot = allocSlot()
|
||||||
@ -2887,7 +2860,7 @@ class BytecodeCompiler(
|
|||||||
val args = compileCallArgs(ref.args, ref.tailBlock) ?: return null
|
val args = compileCallArgs(ref.args, ref.tailBlock) ?: return null
|
||||||
val encodedCount = encodeCallArgCount(args) ?: return null
|
val encodedCount = encodeCallArgCount(args) ?: return null
|
||||||
setPos(callPos)
|
setPos(callPos)
|
||||||
builder.emit(Opcode.CALL_MEMBER_SLOT, receiver.slot, encodedMethodId, args.base, encodedCount, dst)
|
builder.emit(Opcode.CALL_MEMBER_SLOT, receiver.slot, methodId, args.base, encodedCount, dst)
|
||||||
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
builder.emit(Opcode.JMP, listOf(CmdBuilder.Operand.LabelRef(endLabel)))
|
||||||
builder.mark(nullLabel)
|
builder.mark(nullLabel)
|
||||||
builder.emit(Opcode.CONST_NULL, dst)
|
builder.emit(Opcode.CONST_NULL, dst)
|
||||||
@ -3308,8 +3281,8 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
is BlockStatement -> emitBlock(target, true)
|
is BlockStatement -> emitBlock(target, true)
|
||||||
is VarDeclStatement -> emitVarDecl(target)
|
is VarDeclStatement -> emitVarDecl(target)
|
||||||
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
is DelegatedVarDeclStatement -> emitStatementEval(target)
|
||||||
is DestructuringVarDeclStatement -> emitDestructuringVarDecl(target)
|
is DestructuringVarDeclStatement -> emitStatementEval(target)
|
||||||
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
|
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
|
||||||
is net.sergeych.lyng.ClassDeclStatement -> emitStatementEval(target)
|
is net.sergeych.lyng.ClassDeclStatement -> emitStatementEval(target)
|
||||||
is net.sergeych.lyng.FunctionDeclStatement -> emitStatementEval(target)
|
is net.sergeych.lyng.FunctionDeclStatement -> emitStatementEval(target)
|
||||||
@ -3335,7 +3308,7 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is VarDeclStatement -> emitVarDecl(target)
|
is VarDeclStatement -> emitVarDecl(target)
|
||||||
is DelegatedVarDeclStatement -> emitDelegatedVarDecl(target)
|
is DelegatedVarDeclStatement -> emitStatementEval(target)
|
||||||
is IfStatement -> compileIfStatement(target)
|
is IfStatement -> compileIfStatement(target)
|
||||||
is net.sergeych.lyng.ForInStatement -> {
|
is net.sergeych.lyng.ForInStatement -> {
|
||||||
val resultSlot = emitForIn(target, false) ?: return null
|
val resultSlot = emitForIn(target, false) ?: return null
|
||||||
@ -3356,7 +3329,7 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is BlockStatement -> emitBlock(target, false)
|
is BlockStatement -> emitBlock(target, false)
|
||||||
is DestructuringVarDeclStatement -> emitDestructuringVarDecl(target)
|
is DestructuringVarDeclStatement -> emitStatementEval(target)
|
||||||
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
|
is net.sergeych.lyng.ExtensionPropertyDeclStatement -> emitExtensionPropertyDecl(target)
|
||||||
is net.sergeych.lyng.BreakStatement -> compileBreak(target)
|
is net.sergeych.lyng.BreakStatement -> compileBreak(target)
|
||||||
is net.sergeych.lyng.ContinueStatement -> compileContinue(target)
|
is net.sergeych.lyng.ContinueStatement -> compileContinue(target)
|
||||||
@ -3603,38 +3576,6 @@ class BytecodeCompiler(
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun emitDelegatedVarDecl(stmt: DelegatedVarDeclStatement): CompiledValue? {
|
|
||||||
val value = compileStatementValueOrFallback(stmt.initializer) ?: return null
|
|
||||||
val declId = builder.addConst(
|
|
||||||
BytecodeConst.DelegatedDecl(
|
|
||||||
stmt.name,
|
|
||||||
stmt.isMutable,
|
|
||||||
stmt.visibility,
|
|
||||||
stmt.isTransient
|
|
||||||
)
|
|
||||||
)
|
|
||||||
builder.emit(Opcode.DECL_DELEGATED, declId, value.slot)
|
|
||||||
updateSlotType(value.slot, SlotType.OBJ)
|
|
||||||
return CompiledValue(value.slot, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun emitDestructuringVarDecl(stmt: DestructuringVarDeclStatement): CompiledValue? {
|
|
||||||
val value = compileStatementValueOrFallback(stmt.initializer) ?: return null
|
|
||||||
val declId = builder.addConst(
|
|
||||||
BytecodeConst.DestructureDecl(
|
|
||||||
stmt.pattern,
|
|
||||||
stmt.names,
|
|
||||||
stmt.isMutable,
|
|
||||||
stmt.visibility,
|
|
||||||
stmt.isTransient,
|
|
||||||
stmt.pos
|
|
||||||
)
|
|
||||||
)
|
|
||||||
builder.emit(Opcode.DECL_DESTRUCTURE, declId, value.slot)
|
|
||||||
updateSlotType(value.slot, SlotType.OBJ)
|
|
||||||
return CompiledValue(value.slot, SlotType.OBJ)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateNameObjClass(name: String, initializer: Statement?, initializerObjClass: ObjClass? = null) {
|
private fun updateNameObjClass(name: String, initializer: Statement?, initializerObjClass: ObjClass? = null) {
|
||||||
val cls = initializerObjClass ?: objClassForInitializer(initializer)
|
val cls = initializerObjClass ?: objClassForInitializer(initializer)
|
||||||
if (cls != null) {
|
if (cls != null) {
|
||||||
@ -4670,17 +4611,43 @@ class BytecodeCompiler(
|
|||||||
?: resolveReceiverClass(ref.castValueRef())
|
?: resolveReceiverClass(ref.castValueRef())
|
||||||
is FieldRef -> {
|
is FieldRef -> {
|
||||||
val targetClass = resolveReceiverClass(ref.target) ?: return null
|
val targetClass = resolveReceiverClass(ref.target) ?: return null
|
||||||
inferFieldReturnClass(targetClass, ref.name)
|
if (targetClass == ObjString.type && ref.name == "re") {
|
||||||
|
ObjRegex.type
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is MethodCallRef -> {
|
is MethodCallRef -> {
|
||||||
val targetClass = resolveReceiverClass(ref.receiver) ?: return null
|
val targetClass = resolveReceiverClass(ref.receiver) ?: return null
|
||||||
if (targetClass == ObjString.type && ref.name == "re" && ref.args.isEmpty() && !ref.isOptional) {
|
if (targetClass == ObjString.type && ref.name == "re" && ref.args.isEmpty() && !ref.isOptional) {
|
||||||
ObjRegex.type
|
ObjRegex.type
|
||||||
} else {
|
} else {
|
||||||
inferMethodCallReturnClass(ref.name)
|
when (ref.name) {
|
||||||
|
"map",
|
||||||
|
"mapNotNull",
|
||||||
|
"filter",
|
||||||
|
"filterNotNull",
|
||||||
|
"drop",
|
||||||
|
"take",
|
||||||
|
"flatMap",
|
||||||
|
"flatten",
|
||||||
|
"sorted",
|
||||||
|
"sortedBy",
|
||||||
|
"sortedWith",
|
||||||
|
"reversed",
|
||||||
|
"toList",
|
||||||
|
"shuffle",
|
||||||
|
"shuffled" -> ObjList.type
|
||||||
|
"dropLast" -> ObjFlow.type
|
||||||
|
"takeLast" -> ObjRingBuffer.type
|
||||||
|
"count" -> ObjInt.type
|
||||||
|
"toSet" -> ObjSet.type
|
||||||
|
"toMap" -> ObjMap.type
|
||||||
|
"joinToString" -> ObjString.type
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is CallRef -> inferCallReturnClass(ref)
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4727,17 +4694,39 @@ class BytecodeCompiler(
|
|||||||
?: resolveReceiverClassForScopeCollection(ref.castValueRef())
|
?: resolveReceiverClassForScopeCollection(ref.castValueRef())
|
||||||
is FieldRef -> {
|
is FieldRef -> {
|
||||||
val targetClass = resolveReceiverClassForScopeCollection(ref.target) ?: return null
|
val targetClass = resolveReceiverClassForScopeCollection(ref.target) ?: return null
|
||||||
inferFieldReturnClass(targetClass, ref.name)
|
if (targetClass == ObjString.type && ref.name == "re") ObjRegex.type else null
|
||||||
}
|
}
|
||||||
is MethodCallRef -> {
|
is MethodCallRef -> {
|
||||||
val targetClass = resolveReceiverClassForScopeCollection(ref.receiver) ?: return null
|
val targetClass = resolveReceiverClassForScopeCollection(ref.receiver) ?: return null
|
||||||
if (targetClass == ObjString.type && ref.name == "re" && ref.args.isEmpty() && !ref.isOptional) {
|
if (targetClass == ObjString.type && ref.name == "re" && ref.args.isEmpty() && !ref.isOptional) {
|
||||||
ObjRegex.type
|
ObjRegex.type
|
||||||
} else {
|
} else {
|
||||||
inferMethodCallReturnClass(ref.name)
|
when (ref.name) {
|
||||||
|
"map",
|
||||||
|
"mapNotNull",
|
||||||
|
"filter",
|
||||||
|
"filterNotNull",
|
||||||
|
"drop",
|
||||||
|
"take",
|
||||||
|
"flatMap",
|
||||||
|
"flatten",
|
||||||
|
"sorted",
|
||||||
|
"sortedBy",
|
||||||
|
"sortedWith",
|
||||||
|
"reversed",
|
||||||
|
"toList",
|
||||||
|
"shuffle",
|
||||||
|
"shuffled" -> ObjList.type
|
||||||
|
"dropLast" -> ObjFlow.type
|
||||||
|
"takeLast" -> ObjRingBuffer.type
|
||||||
|
"count" -> ObjInt.type
|
||||||
|
"toSet" -> ObjSet.type
|
||||||
|
"toMap" -> ObjMap.type
|
||||||
|
"joinToString" -> ObjString.type
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is CallRef -> inferCallReturnClass(ref)
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4776,154 +4765,12 @@ class BytecodeCompiler(
|
|||||||
"Regex" -> ObjRegex.type
|
"Regex" -> ObjRegex.type
|
||||||
"RegexMatch" -> ObjRegexMatch.type
|
"RegexMatch" -> ObjRegexMatch.type
|
||||||
"MapEntry" -> ObjMapEntry.type
|
"MapEntry" -> ObjMapEntry.type
|
||||||
"Instant" -> ObjInstant.type
|
|
||||||
"DateTime" -> ObjDateTime.type
|
|
||||||
"Duration" -> ObjDuration.type
|
|
||||||
"Exception" -> ObjException.Root
|
"Exception" -> ObjException.Root
|
||||||
"Class" -> ObjClassType
|
|
||||||
"Callable" -> Statement.type
|
"Callable" -> Statement.type
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inferCallReturnClass(ref: CallRef): ObjClass? {
|
|
||||||
return when (val target = ref.target) {
|
|
||||||
is LocalSlotRef -> nameObjClass[target.name] ?: resolveTypeNameClass(target.name)
|
|
||||||
is LocalVarRef -> nameObjClass[target.name] ?: resolveTypeNameClass(target.name)
|
|
||||||
is ConstRef -> target.constValue as? ObjClass
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun inferMethodCallReturnClass(name: String): ObjClass? = when (name) {
|
|
||||||
"map",
|
|
||||||
"mapNotNull",
|
|
||||||
"filter",
|
|
||||||
"filterNotNull",
|
|
||||||
"drop",
|
|
||||||
"take",
|
|
||||||
"flatMap",
|
|
||||||
"flatten",
|
|
||||||
"sorted",
|
|
||||||
"sortedBy",
|
|
||||||
"sortedWith",
|
|
||||||
"reversed",
|
|
||||||
"toList",
|
|
||||||
"shuffle",
|
|
||||||
"shuffled" -> ObjList.type
|
|
||||||
"dropLast" -> ObjFlow.type
|
|
||||||
"takeLast" -> ObjRingBuffer.type
|
|
||||||
"iterator" -> ObjIterator
|
|
||||||
"count" -> ObjInt.type
|
|
||||||
"toSet" -> ObjSet.type
|
|
||||||
"toMap" -> ObjMap.type
|
|
||||||
"joinToString" -> ObjString.type
|
|
||||||
"now",
|
|
||||||
"truncateToSecond",
|
|
||||||
"truncateToMinute",
|
|
||||||
"truncateToMillisecond" -> ObjInstant.type
|
|
||||||
"toDateTime",
|
|
||||||
"toTimeZone",
|
|
||||||
"toUTC",
|
|
||||||
"parseRFC3339",
|
|
||||||
"addYears",
|
|
||||||
"addMonths",
|
|
||||||
"addDays",
|
|
||||||
"addHours",
|
|
||||||
"addMinutes",
|
|
||||||
"addSeconds" -> ObjDateTime.type
|
|
||||||
"toInstant" -> ObjInstant.type
|
|
||||||
"toRFC3339",
|
|
||||||
"toSortableString",
|
|
||||||
"toJsonString",
|
|
||||||
"decodeUtf8",
|
|
||||||
"toDump",
|
|
||||||
"toString" -> ObjString.type
|
|
||||||
"startsWith",
|
|
||||||
"matches" -> ObjBool.type
|
|
||||||
"toInt",
|
|
||||||
"toEpochSeconds" -> ObjInt.type
|
|
||||||
"toMutable" -> ObjMutableBuffer.type
|
|
||||||
"seq" -> ObjFlow.type
|
|
||||||
"encode" -> ObjBitBuffer.type
|
|
||||||
"assertThrows" -> ObjException.Root
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun inferFieldReturnClass(targetClass: ObjClass?, name: String): ObjClass? {
|
|
||||||
if (targetClass == null) return null
|
|
||||||
if (targetClass == ObjDynamic.type) return ObjDynamic.type
|
|
||||||
if (targetClass == ObjInstant.type && (name == "distantFuture" || name == "distantPast")) {
|
|
||||||
return ObjInstant.type
|
|
||||||
}
|
|
||||||
if (targetClass == ObjString.type && name == "re") {
|
|
||||||
return ObjRegex.type
|
|
||||||
}
|
|
||||||
if (targetClass == ObjInt.type || targetClass == ObjReal.type) {
|
|
||||||
return when (name) {
|
|
||||||
"day",
|
|
||||||
"days",
|
|
||||||
"hour",
|
|
||||||
"hours",
|
|
||||||
"minute",
|
|
||||||
"minutes",
|
|
||||||
"second",
|
|
||||||
"seconds",
|
|
||||||
"millisecond",
|
|
||||||
"milliseconds",
|
|
||||||
"microsecond",
|
|
||||||
"microseconds" -> ObjDuration.type
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (targetClass == ObjDuration.type) {
|
|
||||||
return when (name) {
|
|
||||||
"days",
|
|
||||||
"hours",
|
|
||||||
"minutes",
|
|
||||||
"seconds",
|
|
||||||
"milliseconds",
|
|
||||||
"microseconds" -> ObjReal.type
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (targetClass == ObjInstant.type) {
|
|
||||||
return when (name) {
|
|
||||||
"epochSeconds",
|
|
||||||
"epochWholeSeconds" -> ObjInt.type
|
|
||||||
"truncateToSecond",
|
|
||||||
"truncateToMinute",
|
|
||||||
"truncateToMillisecond" -> ObjInstant.type
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (targetClass == ObjDateTime.type) {
|
|
||||||
return when (name) {
|
|
||||||
"year",
|
|
||||||
"month",
|
|
||||||
"day",
|
|
||||||
"hour",
|
|
||||||
"minute",
|
|
||||||
"second",
|
|
||||||
"dayOfWeek",
|
|
||||||
"nanosecond" -> ObjInt.type
|
|
||||||
"timeZone" -> ObjString.type
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (targetClass == ObjException.Root || targetClass.allParentsSet.contains(ObjException.Root)) {
|
|
||||||
return when (name) {
|
|
||||||
"message" -> ObjString.type
|
|
||||||
"stackTrace" -> ObjList.type
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (targetClass == ObjRegex.type && name == "pattern") {
|
|
||||||
return ObjString.type
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun queueExtensionCallableNames(receiverClass: ObjClass, memberName: String) {
|
private fun queueExtensionCallableNames(receiverClass: ObjClass, memberName: String) {
|
||||||
for (cls in receiverClass.mro) {
|
for (cls in receiverClass.mro) {
|
||||||
val name = extensionCallableName(cls.className, memberName)
|
val name = extensionCallableName(cls.className, memberName)
|
||||||
|
|||||||
@ -18,7 +18,6 @@ package net.sergeych.lyng.bytecode
|
|||||||
|
|
||||||
import net.sergeych.lyng.Pos
|
import net.sergeych.lyng.Pos
|
||||||
import net.sergeych.lyng.Visibility
|
import net.sergeych.lyng.Visibility
|
||||||
import net.sergeych.lyng.obj.ListLiteralRef
|
|
||||||
import net.sergeych.lyng.obj.Obj
|
import net.sergeych.lyng.obj.Obj
|
||||||
import net.sergeych.lyng.obj.ObjProperty
|
import net.sergeych.lyng.obj.ObjProperty
|
||||||
|
|
||||||
@ -47,20 +46,6 @@ sealed class BytecodeConst {
|
|||||||
val visibility: Visibility,
|
val visibility: Visibility,
|
||||||
val isTransient: Boolean,
|
val isTransient: Boolean,
|
||||||
) : BytecodeConst()
|
) : BytecodeConst()
|
||||||
data class DelegatedDecl(
|
|
||||||
val name: String,
|
|
||||||
val isMutable: Boolean,
|
|
||||||
val visibility: Visibility,
|
|
||||||
val isTransient: Boolean,
|
|
||||||
) : BytecodeConst()
|
|
||||||
data class DestructureDecl(
|
|
||||||
val pattern: ListLiteralRef,
|
|
||||||
val names: List<String>,
|
|
||||||
val isMutable: Boolean,
|
|
||||||
val visibility: Visibility,
|
|
||||||
val isTransient: Boolean,
|
|
||||||
val pos: Pos,
|
|
||||||
) : BytecodeConst()
|
|
||||||
data class CallArgsPlan(val tailBlock: Boolean, val specs: List<CallArgSpec>) : BytecodeConst()
|
data class CallArgsPlan(val tailBlock: Boolean, val specs: List<CallArgSpec>) : BytecodeConst()
|
||||||
data class CallArgSpec(val name: String?, val isSplat: Boolean)
|
data class CallArgSpec(val name: String?, val isSplat: Boolean)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -144,7 +144,7 @@ class CmdBuilder {
|
|||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.PUSH_SCOPE, Opcode.PUSH_SLOT_PLAN ->
|
Opcode.PUSH_SCOPE, Opcode.PUSH_SLOT_PLAN ->
|
||||||
listOf(OperandKind.CONST)
|
listOf(OperandKind.CONST)
|
||||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE ->
|
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY ->
|
||||||
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,
|
||||||
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
||||||
@ -377,8 +377,6 @@ class CmdBuilder {
|
|||||||
Opcode.PUSH_SLOT_PLAN -> CmdPushSlotPlan(operands[0])
|
Opcode.PUSH_SLOT_PLAN -> CmdPushSlotPlan(operands[0])
|
||||||
Opcode.POP_SLOT_PLAN -> CmdPopSlotPlan()
|
Opcode.POP_SLOT_PLAN -> CmdPopSlotPlan()
|
||||||
Opcode.DECL_LOCAL -> CmdDeclLocal(operands[0], operands[1])
|
Opcode.DECL_LOCAL -> CmdDeclLocal(operands[0], operands[1])
|
||||||
Opcode.DECL_DELEGATED -> CmdDeclDelegated(operands[0], operands[1])
|
|
||||||
Opcode.DECL_DESTRUCTURE -> CmdDeclDestructure(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.CALL_MEMBER_SLOT -> CmdCallMemberSlot(operands[0], operands[1], operands[2], operands[3], operands[4])
|
Opcode.CALL_MEMBER_SLOT -> CmdCallMemberSlot(operands[0], operands[1], operands[2], operands[3], operands[4])
|
||||||
|
|||||||
@ -185,8 +185,6 @@ object CmdDisassembler {
|
|||||||
is CmdPushSlotPlan -> Opcode.PUSH_SLOT_PLAN to intArrayOf(cmd.planId)
|
is CmdPushSlotPlan -> Opcode.PUSH_SLOT_PLAN to intArrayOf(cmd.planId)
|
||||||
is CmdPopSlotPlan -> Opcode.POP_SLOT_PLAN to intArrayOf()
|
is CmdPopSlotPlan -> Opcode.POP_SLOT_PLAN to intArrayOf()
|
||||||
is CmdDeclLocal -> Opcode.DECL_LOCAL to intArrayOf(cmd.constId, cmd.slot)
|
is CmdDeclLocal -> Opcode.DECL_LOCAL to intArrayOf(cmd.constId, cmd.slot)
|
||||||
is CmdDeclDelegated -> Opcode.DECL_DELEGATED to intArrayOf(cmd.constId, cmd.slot)
|
|
||||||
is CmdDeclDestructure -> Opcode.DECL_DESTRUCTURE 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 CmdCallMemberSlot -> Opcode.CALL_MEMBER_SLOT to intArrayOf(cmd.recvSlot, cmd.methodId, cmd.argBase, cmd.argCount, cmd.dst)
|
is CmdCallMemberSlot -> Opcode.CALL_MEMBER_SLOT to intArrayOf(cmd.recvSlot, cmd.methodId, cmd.argBase, cmd.argCount, cmd.dst)
|
||||||
@ -242,7 +240,7 @@ object CmdDisassembler {
|
|||||||
listOf(OperandKind.CONST, OperandKind.SLOT)
|
listOf(OperandKind.CONST, OperandKind.SLOT)
|
||||||
Opcode.PUSH_SCOPE, Opcode.PUSH_SLOT_PLAN ->
|
Opcode.PUSH_SCOPE, Opcode.PUSH_SLOT_PLAN ->
|
||||||
listOf(OperandKind.CONST)
|
listOf(OperandKind.CONST)
|
||||||
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY, Opcode.DECL_DELEGATED, Opcode.DECL_DESTRUCTURE ->
|
Opcode.DECL_LOCAL, Opcode.DECL_EXT_PROPERTY ->
|
||||||
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,
|
||||||
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
Opcode.ADD_REAL, Opcode.SUB_REAL, Opcode.MUL_REAL, Opcode.DIV_REAL,
|
||||||
|
|||||||
@ -1187,59 +1187,6 @@ class CmdDeclLocal(internal val constId: Int, internal val slot: Int) : Cmd() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CmdDeclDelegated(internal val constId: Int, internal val slot: Int) : Cmd() {
|
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
|
||||||
val decl = frame.fn.constants[constId] as? BytecodeConst.DelegatedDecl
|
|
||||||
?: error("DECL_DELEGATED expects DelegatedDecl at $constId")
|
|
||||||
val initValue = frame.slotToObj(slot)
|
|
||||||
val accessType = ObjString(if (decl.isMutable) "Var" else "Val")
|
|
||||||
val finalDelegate = try {
|
|
||||||
initValue.invokeInstanceMethod(
|
|
||||||
frame.ensureScope(),
|
|
||||||
"bind",
|
|
||||||
Arguments(ObjString(decl.name), accessType, ObjNull)
|
|
||||||
)
|
|
||||||
} catch (_: Exception) {
|
|
||||||
initValue
|
|
||||||
}
|
|
||||||
val rec = frame.ensureScope().addItem(
|
|
||||||
decl.name,
|
|
||||||
decl.isMutable,
|
|
||||||
ObjNull,
|
|
||||||
decl.visibility,
|
|
||||||
recordType = ObjRecord.Type.Delegated,
|
|
||||||
isTransient = decl.isTransient
|
|
||||||
)
|
|
||||||
rec.delegate = finalDelegate
|
|
||||||
frame.storeObjResult(slot, finalDelegate)
|
|
||||||
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
|
|
||||||
?: error("DECL_DESTRUCTURE expects DestructureDecl at $constId")
|
|
||||||
val value = frame.slotToObj(slot)
|
|
||||||
val scope = frame.ensureScope()
|
|
||||||
for (name in decl.names) {
|
|
||||||
scope.addItem(name, true, ObjVoid, decl.visibility, isTransient = decl.isTransient)
|
|
||||||
}
|
|
||||||
decl.pattern.setAt(decl.pos, scope, value)
|
|
||||||
if (!decl.isMutable) {
|
|
||||||
for (name in decl.names) {
|
|
||||||
val rec = scope.objects[name] ?: continue
|
|
||||||
val immutableRec = rec.copy(isMutable = false)
|
|
||||||
scope.objects[name] = immutableRec
|
|
||||||
scope.localBindings[name] = immutableRec
|
|
||||||
scope.updateSlotFor(name, immutableRec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
frame.storeObjResult(slot, ObjVoid)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CmdDeclExtProperty(internal val constId: Int, internal val slot: Int) : Cmd() {
|
class CmdDeclExtProperty(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.ExtensionPropertyDecl
|
val decl = frame.fn.constants[constId] as? BytecodeConst.ExtensionPropertyDecl
|
||||||
@ -1321,8 +1268,7 @@ class CmdCallSlot(
|
|||||||
frame.ensureScope().withChildFrame(args) { child -> callee.callOn(child) }
|
frame.ensureScope().withChildFrame(args) { child -> callee.callOn(child) }
|
||||||
} else {
|
} else {
|
||||||
// Pooling for Statement-based callables (lambdas) can still alter closure semantics; keep safe path for now.
|
// Pooling for Statement-based callables (lambdas) can still alter closure semantics; keep safe path for now.
|
||||||
val scope = frame.ensureScope()
|
callee.callOn(frame.ensureScope().createChildScope(frame.ensureScope().pos, args = args))
|
||||||
callee.callOn(scope.createChildScope(scope.pos, args = args))
|
|
||||||
}
|
}
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
if (frame.fn.localSlotNames.isNotEmpty()) {
|
||||||
frame.syncScopeToFrame()
|
frame.syncScopeToFrame()
|
||||||
@ -1361,14 +1307,6 @@ class CmdListLiteral(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun decodeMemberId(id: Int): Pair<Int, Boolean> {
|
|
||||||
return if (id <= -2) {
|
|
||||||
Pair(-id - 2, true)
|
|
||||||
} else {
|
|
||||||
Pair(id, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CmdGetMemberSlot(
|
class CmdGetMemberSlot(
|
||||||
internal val recvSlot: Int,
|
internal val recvSlot: Int,
|
||||||
internal val fieldId: Int,
|
internal val fieldId: Int,
|
||||||
@ -1378,42 +1316,22 @@ class CmdGetMemberSlot(
|
|||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
val receiver = frame.slotToObj(recvSlot)
|
val receiver = frame.slotToObj(recvSlot)
|
||||||
val inst = receiver as? ObjInstance
|
val inst = receiver as? ObjInstance
|
||||||
val cls = receiver as? ObjClass
|
val fieldRec = if (fieldId >= 0) {
|
||||||
val (fieldIdResolved, fieldOnObjClass) = decodeMemberId(fieldId)
|
inst?.fieldRecordForId(fieldId) ?: receiver.objClass.fieldRecordForId(fieldId)
|
||||||
val (methodIdResolved, methodOnObjClass) = decodeMemberId(methodId)
|
|
||||||
val fieldRec = if (fieldIdResolved >= 0) {
|
|
||||||
when {
|
|
||||||
inst != null -> inst.fieldRecordForId(fieldIdResolved) ?: inst.objClass.fieldRecordForId(fieldIdResolved)
|
|
||||||
cls != null && fieldOnObjClass -> cls.objClass.fieldRecordForId(fieldIdResolved)
|
|
||||||
cls != null -> cls.fieldRecordForId(fieldIdResolved)
|
|
||||||
else -> receiver.objClass.fieldRecordForId(fieldIdResolved)
|
|
||||||
}
|
|
||||||
} else null
|
} else null
|
||||||
val rec = fieldRec ?: run {
|
val rec = fieldRec ?: run {
|
||||||
if (methodIdResolved >= 0) {
|
if (methodId >= 0) {
|
||||||
when {
|
inst?.methodRecordForId(methodId) ?: receiver.objClass.methodRecordForId(methodId)
|
||||||
inst != null -> inst.methodRecordForId(methodIdResolved) ?: inst.objClass.methodRecordForId(methodIdResolved)
|
|
||||||
cls != null && methodOnObjClass -> cls.objClass.methodRecordForId(methodIdResolved)
|
|
||||||
cls != null -> cls.methodRecordForId(methodIdResolved)
|
|
||||||
else -> receiver.objClass.methodRecordForId(methodIdResolved)
|
|
||||||
}
|
|
||||||
} else null
|
} else null
|
||||||
} ?: frame.ensureScope().raiseSymbolNotFound("member")
|
} ?: frame.ensureScope().raiseSymbolNotFound("member")
|
||||||
val name = rec.memberName ?: "<member>"
|
val name = rec.memberName ?: "<member>"
|
||||||
suspend fun autoCallIfMethod(resolved: ObjRecord, recv: Obj): Obj {
|
|
||||||
return if (resolved.type == ObjRecord.Type.Fun && !resolved.isAbstract) {
|
|
||||||
resolved.value.invoke(frame.ensureScope(), resolved.receiver ?: recv, Arguments.EMPTY, resolved.declaringClass)
|
|
||||||
} else {
|
|
||||||
resolved.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (receiver is ObjQualifiedView) {
|
if (receiver is ObjQualifiedView) {
|
||||||
val resolved = receiver.readField(frame.ensureScope(), name)
|
val resolved = receiver.readField(frame.ensureScope(), name)
|
||||||
frame.storeObjResult(dst, autoCallIfMethod(resolved, receiver))
|
frame.storeObjResult(dst, resolved.value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val resolved = receiver.resolveRecord(frame.ensureScope(), rec, name, rec.declaringClass)
|
val resolved = receiver.resolveRecord(frame.ensureScope(), rec, name, rec.declaringClass)
|
||||||
frame.storeObjResult(dst, autoCallIfMethod(resolved, receiver))
|
frame.storeObjResult(dst, resolved.value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1427,25 +1345,12 @@ class CmdSetMemberSlot(
|
|||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
val receiver = frame.slotToObj(recvSlot)
|
val receiver = frame.slotToObj(recvSlot)
|
||||||
val inst = receiver as? ObjInstance
|
val inst = receiver as? ObjInstance
|
||||||
val cls = receiver as? ObjClass
|
val fieldRec = if (fieldId >= 0) {
|
||||||
val (fieldIdResolved, fieldOnObjClass) = decodeMemberId(fieldId)
|
inst?.fieldRecordForId(fieldId) ?: receiver.objClass.fieldRecordForId(fieldId)
|
||||||
val (methodIdResolved, methodOnObjClass) = decodeMemberId(methodId)
|
|
||||||
val fieldRec = if (fieldIdResolved >= 0) {
|
|
||||||
when {
|
|
||||||
inst != null -> inst.fieldRecordForId(fieldIdResolved) ?: inst.objClass.fieldRecordForId(fieldIdResolved)
|
|
||||||
cls != null && fieldOnObjClass -> cls.objClass.fieldRecordForId(fieldIdResolved)
|
|
||||||
cls != null -> cls.fieldRecordForId(fieldIdResolved)
|
|
||||||
else -> receiver.objClass.fieldRecordForId(fieldIdResolved)
|
|
||||||
}
|
|
||||||
} else null
|
} else null
|
||||||
val rec = fieldRec ?: run {
|
val rec = fieldRec ?: run {
|
||||||
if (methodIdResolved >= 0) {
|
if (methodId >= 0) {
|
||||||
when {
|
inst?.methodRecordForId(methodId) ?: receiver.objClass.methodRecordForId(methodId)
|
||||||
inst != null -> inst.methodRecordForId(methodIdResolved) ?: inst.objClass.methodRecordForId(methodIdResolved)
|
|
||||||
cls != null && methodOnObjClass -> cls.objClass.methodRecordForId(methodIdResolved)
|
|
||||||
cls != null -> cls.methodRecordForId(methodIdResolved)
|
|
||||||
else -> receiver.objClass.methodRecordForId(methodIdResolved)
|
|
||||||
}
|
|
||||||
} else null
|
} else null
|
||||||
} ?: frame.ensureScope().raiseSymbolNotFound("member")
|
} ?: frame.ensureScope().raiseSymbolNotFound("member")
|
||||||
val name = rec.memberName ?: "<member>"
|
val name = rec.memberName ?: "<member>"
|
||||||
@ -1471,14 +1376,8 @@ class CmdCallMemberSlot(
|
|||||||
}
|
}
|
||||||
val receiver = frame.slotToObj(recvSlot)
|
val receiver = frame.slotToObj(recvSlot)
|
||||||
val inst = receiver as? ObjInstance
|
val inst = receiver as? ObjInstance
|
||||||
val cls = receiver as? ObjClass
|
val rec = inst?.methodRecordForId(methodId)
|
||||||
val (methodIdResolved, methodOnObjClass) = decodeMemberId(methodId)
|
?: receiver.objClass.methodRecordForId(methodId)
|
||||||
val rec = inst?.methodRecordForId(methodIdResolved)
|
|
||||||
?: when {
|
|
||||||
cls != null && methodOnObjClass -> cls.objClass.methodRecordForId(methodIdResolved)
|
|
||||||
cls != null -> cls.methodRecordForId(methodIdResolved)
|
|
||||||
else -> receiver.objClass.methodRecordForId(methodIdResolved)
|
|
||||||
}
|
|
||||||
?: frame.ensureScope().raiseError("member id $methodId not found on ${receiver.objClass.className}")
|
?: frame.ensureScope().raiseError("member id $methodId not found on ${receiver.objClass.className}")
|
||||||
val callArgs = frame.buildArguments(argBase, argCount)
|
val callArgs = frame.buildArguments(argBase, argCount)
|
||||||
val name = rec.memberName ?: "<member>"
|
val name = rec.memberName ?: "<member>"
|
||||||
@ -1653,51 +1552,15 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveModuleScope(scope: Scope): Scope {
|
private fun resolveModuleScope(scope: Scope): Scope {
|
||||||
val moduleSlotName = fn.scopeSlotNames.indices
|
var current: Scope? = scope
|
||||||
.firstOrNull { fn.scopeSlotIsModule.getOrNull(it) == true }
|
var last: Scope = scope
|
||||||
?.let { fn.scopeSlotNames[it] }
|
while (current != null) {
|
||||||
if (moduleSlotName != null) {
|
|
||||||
findScopeWithSlot(scope, moduleSlotName)?.let { return it }
|
|
||||||
}
|
|
||||||
findModuleScope(scope)?.let { return it }
|
|
||||||
return scope
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findScopeWithSlot(scope: Scope, slotName: String): Scope? {
|
|
||||||
val visited = HashSet<Scope>(16)
|
|
||||||
val queue = ArrayDeque<Scope>()
|
|
||||||
queue.add(scope)
|
|
||||||
while (queue.isNotEmpty()) {
|
|
||||||
val current = queue.removeFirst()
|
|
||||||
if (!visited.add(current)) continue
|
|
||||||
if (current.getSlotIndexOf(slotName) != null) return current
|
|
||||||
current.parent?.let { queue.add(it) }
|
|
||||||
if (current is ClosureScope) {
|
|
||||||
queue.add(current.closureScope)
|
|
||||||
} else if (current is ApplyScope) {
|
|
||||||
queue.add(current.applied)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findModuleScope(scope: Scope): Scope? {
|
|
||||||
val visited = HashSet<Scope>(16)
|
|
||||||
val queue = ArrayDeque<Scope>()
|
|
||||||
queue.add(scope)
|
|
||||||
while (queue.isNotEmpty()) {
|
|
||||||
val current = queue.removeFirst()
|
|
||||||
if (!visited.add(current)) continue
|
|
||||||
if (current is ModuleScope) return current
|
if (current is ModuleScope) return current
|
||||||
if (current.parent is ModuleScope) return current
|
if (current.parent is ModuleScope) return current
|
||||||
current.parent?.let { queue.add(it) }
|
last = current
|
||||||
if (current is ClosureScope) {
|
current = current.parent
|
||||||
queue.add(current.closureScope)
|
|
||||||
} else if (current is ApplyScope) {
|
|
||||||
queue.add(current.applied)
|
|
||||||
}
|
}
|
||||||
}
|
return last
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ensureScope(): Scope {
|
fun ensureScope(): Scope {
|
||||||
@ -1821,7 +1684,7 @@ class CmdFrame(
|
|||||||
scopeDepth -= 1
|
scopeDepth -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getObj(slot: Int): Obj {
|
fun getObj(slot: Int): Obj {
|
||||||
return if (slot < fn.scopeSlotCount) {
|
return if (slot < fn.scopeSlotCount) {
|
||||||
getScopeSlotValue(slot)
|
getScopeSlotValue(slot)
|
||||||
} else {
|
} else {
|
||||||
@ -1839,7 +1702,7 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getInt(slot: Int): Long {
|
fun getInt(slot: Int): Long {
|
||||||
return if (slot < fn.scopeSlotCount) {
|
return if (slot < fn.scopeSlotCount) {
|
||||||
getScopeSlotValue(slot).toLong()
|
getScopeSlotValue(slot).toLong()
|
||||||
} else {
|
} else {
|
||||||
@ -1870,7 +1733,7 @@ class CmdFrame(
|
|||||||
frame.setInt(local, value)
|
frame.setInt(local, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getReal(slot: Int): Double {
|
fun getReal(slot: Int): Double {
|
||||||
return if (slot < fn.scopeSlotCount) {
|
return if (slot < fn.scopeSlotCount) {
|
||||||
getScopeSlotValue(slot).toDouble()
|
getScopeSlotValue(slot).toDouble()
|
||||||
} else {
|
} else {
|
||||||
@ -1895,7 +1758,7 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getBool(slot: Int): Boolean {
|
fun getBool(slot: Int): Boolean {
|
||||||
return if (slot < fn.scopeSlotCount) {
|
return if (slot < fn.scopeSlotCount) {
|
||||||
getScopeSlotValue(slot).toBool()
|
getScopeSlotValue(slot).toBool()
|
||||||
} else {
|
} else {
|
||||||
@ -1934,7 +1797,7 @@ class CmdFrame(
|
|||||||
addrScopeSlots[addrSlot] = scopeSlot
|
addrScopeSlots[addrSlot] = scopeSlot
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getAddrObj(addrSlot: Int): Obj {
|
fun getAddrObj(addrSlot: Int): Obj {
|
||||||
return getScopeSlotValueAtAddr(addrSlot)
|
return getScopeSlotValueAtAddr(addrSlot)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1942,7 +1805,7 @@ class CmdFrame(
|
|||||||
setScopeSlotValueAtAddr(addrSlot, value)
|
setScopeSlotValueAtAddr(addrSlot, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getAddrInt(addrSlot: Int): Long {
|
fun getAddrInt(addrSlot: Int): Long {
|
||||||
return getScopeSlotValueAtAddr(addrSlot).toLong()
|
return getScopeSlotValueAtAddr(addrSlot).toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1950,7 +1813,7 @@ class CmdFrame(
|
|||||||
setScopeSlotValueAtAddr(addrSlot, ObjInt.of(value))
|
setScopeSlotValueAtAddr(addrSlot, ObjInt.of(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getAddrReal(addrSlot: Int): Double {
|
fun getAddrReal(addrSlot: Int): Double {
|
||||||
return getScopeSlotValueAtAddr(addrSlot).toDouble()
|
return getScopeSlotValueAtAddr(addrSlot).toDouble()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1958,7 +1821,7 @@ class CmdFrame(
|
|||||||
setScopeSlotValueAtAddr(addrSlot, ObjReal.of(value))
|
setScopeSlotValueAtAddr(addrSlot, ObjReal.of(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getAddrBool(addrSlot: Int): Boolean {
|
fun getAddrBool(addrSlot: Int): Boolean {
|
||||||
return getScopeSlotValueAtAddr(addrSlot).toBool()
|
return getScopeSlotValueAtAddr(addrSlot).toBool()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1966,18 +1829,11 @@ class CmdFrame(
|
|||||||
setScopeSlotValueAtAddr(addrSlot, if (value) ObjTrue else ObjFalse)
|
setScopeSlotValueAtAddr(addrSlot, if (value) ObjTrue else ObjFalse)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun slotToObj(slot: Int): Obj {
|
fun slotToObj(slot: Int): Obj {
|
||||||
if (slot < fn.scopeSlotCount) {
|
if (slot < fn.scopeSlotCount) {
|
||||||
return getScopeSlotValue(slot)
|
return getScopeSlotValue(slot)
|
||||||
}
|
}
|
||||||
val local = slot - fn.scopeSlotCount
|
val local = slot - fn.scopeSlotCount
|
||||||
val localName = fn.localSlotNames.getOrNull(local)
|
|
||||||
if (localName != null) {
|
|
||||||
val rec = scope.getLocalRecordDirect(localName) ?: scope.localBindings[localName]
|
|
||||||
if (rec != null && (rec.type == ObjRecord.Type.Delegated || rec.type == ObjRecord.Type.Property || rec.value is ObjProperty)) {
|
|
||||||
return scope.resolve(rec, localName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return when (frame.getSlotTypeCode(local)) {
|
return when (frame.getSlotTypeCode(local)) {
|
||||||
SlotType.INT.code -> ObjInt.of(frame.getInt(local))
|
SlotType.INT.code -> ObjInt.of(frame.getInt(local))
|
||||||
SlotType.REAL.code -> ObjReal.of(frame.getReal(local))
|
SlotType.REAL.code -> ObjReal.of(frame.getReal(local))
|
||||||
@ -2158,20 +2014,14 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getScopeSlotValue(slot: Int): Obj {
|
private fun getScopeSlotValue(slot: Int): Obj {
|
||||||
val target = scopeTarget(slot)
|
val target = scopeTarget(slot)
|
||||||
val index = ensureScopeSlot(target, slot)
|
val index = ensureScopeSlot(target, slot)
|
||||||
val record = target.getSlotRecord(index)
|
val record = target.getSlotRecord(index)
|
||||||
val direct = record.value
|
val direct = record.value
|
||||||
if (direct is FrameSlotRef) return direct.read()
|
if (direct is FrameSlotRef) return direct.read()
|
||||||
val name = fn.scopeSlotNames[slot]
|
if (direct !== ObjUnset) return direct
|
||||||
if (direct !== ObjUnset) {
|
val name = fn.scopeSlotNames[slot] ?: return record.value
|
||||||
if (name != null && (record.type == ObjRecord.Type.Delegated || record.type == ObjRecord.Type.Property || direct is ObjProperty)) {
|
|
||||||
return target.resolve(record, name)
|
|
||||||
}
|
|
||||||
return direct
|
|
||||||
}
|
|
||||||
if (name == null) return record.value
|
|
||||||
val resolved = target.get(name) ?: return record.value
|
val resolved = target.get(name) ?: return record.value
|
||||||
if (resolved.value !== ObjUnset) {
|
if (resolved.value !== ObjUnset) {
|
||||||
target.updateSlotFor(name, resolved)
|
target.updateSlotFor(name, resolved)
|
||||||
@ -2179,21 +2029,15 @@ class CmdFrame(
|
|||||||
return resolved.value
|
return resolved.value
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getScopeSlotValueAtAddr(addrSlot: Int): Obj {
|
private fun getScopeSlotValueAtAddr(addrSlot: Int): Obj {
|
||||||
val target = addrScopes[addrSlot] ?: error("Address slot $addrSlot is not resolved")
|
val target = addrScopes[addrSlot] ?: error("Address slot $addrSlot is not resolved")
|
||||||
val index = addrIndices[addrSlot]
|
val index = addrIndices[addrSlot]
|
||||||
val record = target.getSlotRecord(index)
|
val record = target.getSlotRecord(index)
|
||||||
val direct = record.value
|
val direct = record.value
|
||||||
if (direct is FrameSlotRef) return direct.read()
|
if (direct is FrameSlotRef) return direct.read()
|
||||||
|
if (direct !== ObjUnset) return direct
|
||||||
val slotId = addrScopeSlots[addrSlot]
|
val slotId = addrScopeSlots[addrSlot]
|
||||||
val name = fn.scopeSlotNames.getOrNull(slotId)
|
val name = fn.scopeSlotNames[slotId] ?: return record.value
|
||||||
if (direct !== ObjUnset) {
|
|
||||||
if (name != null && (record.type == ObjRecord.Type.Delegated || record.type == ObjRecord.Type.Property || direct is ObjProperty)) {
|
|
||||||
return target.resolve(record, name)
|
|
||||||
}
|
|
||||||
return direct
|
|
||||||
}
|
|
||||||
if (name == null) return record.value
|
|
||||||
val resolved = target.get(name) ?: return record.value
|
val resolved = target.get(name) ?: return record.value
|
||||||
if (resolved.value !== ObjUnset) {
|
if (resolved.value !== ObjUnset) {
|
||||||
target.updateSlotFor(name, resolved)
|
target.updateSlotFor(name, resolved)
|
||||||
|
|||||||
@ -125,8 +125,6 @@ enum class Opcode(val code: Int) {
|
|||||||
POP_SLOT_PLAN(0x88),
|
POP_SLOT_PLAN(0x88),
|
||||||
DECL_LOCAL(0x89),
|
DECL_LOCAL(0x89),
|
||||||
DECL_EXT_PROPERTY(0x8A),
|
DECL_EXT_PROPERTY(0x8A),
|
||||||
DECL_DELEGATED(0x8B),
|
|
||||||
DECL_DESTRUCTURE(0x8C),
|
|
||||||
|
|
||||||
CALL_DIRECT(0x90),
|
CALL_DIRECT(0x90),
|
||||||
CALL_MEMBER_SLOT(0x92),
|
CALL_MEMBER_SLOT(0x92),
|
||||||
|
|||||||
@ -65,8 +65,7 @@ open class Obj {
|
|||||||
fun isInstanceOf(someClass: Obj) = someClass === objClass ||
|
fun isInstanceOf(someClass: Obj) = someClass === objClass ||
|
||||||
objClass.allParentsSet.contains(someClass) ||
|
objClass.allParentsSet.contains(someClass) ||
|
||||||
someClass == rootObjectType ||
|
someClass == rootObjectType ||
|
||||||
(someClass is ObjClass && (objClass.allImplementingNames.contains(someClass.className) ||
|
(someClass is ObjClass && objClass.allImplementingNames.contains(someClass.className))
|
||||||
objClass.className == someClass.className))
|
|
||||||
|
|
||||||
fun isInstanceOf(className: String) =
|
fun isInstanceOf(className: String) =
|
||||||
objClass.mro.any { it.className == className } ||
|
objClass.mro.any { it.className == className } ||
|
||||||
@ -142,15 +141,6 @@ open class Obj {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scope.findExtension(objClass, name)?.let { ext ->
|
|
||||||
if (ext.type == ObjRecord.Type.Property) {
|
|
||||||
if (args.isEmpty()) {
|
|
||||||
return (ext.value as ObjProperty).callGetter(scope, this, ext.declaringClass)
|
|
||||||
}
|
|
||||||
} else if (ext.type != ObjRecord.Type.Delegated) {
|
|
||||||
return ext.value.invoke(scope, this, args, ext.declaringClass)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return onNotFoundResult?.invoke()
|
return onNotFoundResult?.invoke()
|
||||||
?: scope.raiseError(
|
?: scope.raiseError(
|
||||||
@ -482,14 +472,6 @@ open class Obj {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scope.findExtension(objClass, name)?.let { ext ->
|
|
||||||
return if (ext.type == ObjRecord.Type.Property) {
|
|
||||||
val prop = ext.value as ObjProperty
|
|
||||||
ObjRecord(prop.callGetter(scope, this, ext.declaringClass), isMutable = false)
|
|
||||||
} else {
|
|
||||||
ext.copy(value = ext.value.invoke(scope, this, Arguments.EMPTY, ext.declaringClass))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.raiseError(
|
scope.raiseError(
|
||||||
"no such field: $name on ${objClass.className}. Considered order: ${objClass.renderLinearization(true)}"
|
"no such field: $name on ${objClass.className}. Considered order: ${objClass.renderLinearization(true)}"
|
||||||
@ -504,7 +486,6 @@ open class Obj {
|
|||||||
if (getValueRec == null || getValueRec.declaringClass?.className == "Delegate") {
|
if (getValueRec == null || getValueRec.declaringClass?.className == "Delegate") {
|
||||||
val wrapper = object : Statement() {
|
val wrapper = object : Statement() {
|
||||||
override val pos: Pos = Pos.builtIn
|
override val pos: Pos = Pos.builtIn
|
||||||
|
|
||||||
override suspend fun execute(s: Scope): Obj {
|
override suspend fun execute(s: Scope): Obj {
|
||||||
val th2 = if (s.thisObj === ObjVoid) ObjNull else s.thisObj
|
val th2 = if (s.thisObj === ObjVoid) ObjNull else s.thisObj
|
||||||
val allArgs = (listOf(th2, ObjString(name)) + s.args.list).toTypedArray()
|
val allArgs = (listOf(th2, ObjString(name)) + s.args.list).toTypedArray()
|
||||||
@ -606,19 +587,16 @@ open class Obj {
|
|||||||
scope.raiseNotImplemented()
|
scope.raiseNotImplemented()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun invoke(scope: Scope, thisObj: Obj, args: Arguments, declaringClass: ObjClass? = null): Obj {
|
suspend fun invoke(scope: Scope, thisObj: Obj, args: Arguments, declaringClass: ObjClass? = null): Obj =
|
||||||
val usePool = PerfFlags.SCOPE_POOL && this !is Statement
|
if (PerfFlags.SCOPE_POOL)
|
||||||
return if (usePool) {
|
|
||||||
scope.withChildFrame(args, newThisObj = thisObj) { child ->
|
scope.withChildFrame(args, newThisObj = thisObj) { child ->
|
||||||
if (declaringClass != null) child.currentClassCtx = declaringClass
|
if (declaringClass != null) child.currentClassCtx = declaringClass
|
||||||
callOn(child)
|
callOn(child)
|
||||||
}
|
}
|
||||||
} else {
|
else
|
||||||
callOn(scope.createChildScope(scope.pos, args = args, newThisObj = thisObj).also {
|
callOn(scope.createChildScope(scope.pos, args = args, newThisObj = thisObj).also {
|
||||||
if (declaringClass != null) it.currentClassCtx = declaringClass
|
if (declaringClass != null) it.currentClassCtx = declaringClass
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun invoke(scope: Scope, thisObj: Obj, vararg args: Obj): Obj =
|
suspend fun invoke(scope: Scope, thisObj: Obj, vararg args: Obj): Obj =
|
||||||
callOn(
|
callOn(
|
||||||
|
|||||||
@ -92,24 +92,17 @@ open class ObjException(
|
|||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var stackTraceCaptureDepth = 0
|
|
||||||
|
|
||||||
suspend fun captureStackTrace(scope: Scope): ObjList {
|
suspend fun captureStackTrace(scope: Scope): ObjList {
|
||||||
val result = ObjList()
|
val result = ObjList()
|
||||||
val nestedCapture = stackTraceCaptureDepth > 0
|
val maybeCls = scope.get("StackTraceEntry")?.value as? ObjClass
|
||||||
stackTraceCaptureDepth += 1
|
|
||||||
val maybeCls = if (nestedCapture) null else scope.get("StackTraceEntry")?.value as? ObjClass
|
|
||||||
var s: Scope? = scope
|
var s: Scope? = scope
|
||||||
var lastPos: Pos? = null
|
var lastPos: Pos? = null
|
||||||
try {
|
|
||||||
while (s != null) {
|
while (s != null) {
|
||||||
val pos = s.pos
|
val pos = s.pos
|
||||||
if (pos != lastPos && !pos.currentLine.isEmpty()) {
|
if (pos != lastPos && !pos.currentLine.isEmpty()) {
|
||||||
if (lastPos == null || (lastPos.source != pos.source || lastPos.line != pos.line)) {
|
if( (lastPos == null || (lastPos.source != pos.source || lastPos.line != pos.line)) ) {
|
||||||
val fallback =
|
|
||||||
ObjString("#${pos.source.objSourceName}:${pos.line+1}:${pos.column+1}: ${pos.currentLine}")
|
|
||||||
if (maybeCls != null) {
|
if (maybeCls != null) {
|
||||||
try {
|
|
||||||
result.list += maybeCls.callWithArgs(
|
result.list += maybeCls.callWithArgs(
|
||||||
scope,
|
scope,
|
||||||
pos.source.objSourceName,
|
pos.source.objSourceName,
|
||||||
@ -117,13 +110,9 @@ open class ObjException(
|
|||||||
ObjInt(pos.column.toLong()),
|
ObjInt(pos.column.toLong()),
|
||||||
ObjString(pos.currentLine)
|
ObjString(pos.currentLine)
|
||||||
)
|
)
|
||||||
} catch (e: Throwable) {
|
|
||||||
// Fallback textual entry if StackTraceEntry fails to instantiate
|
|
||||||
result.list += fallback
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Fallback textual entry if StackTraceEntry class is not available in this scope
|
// Fallback textual entry if StackTraceEntry class is not available in this scope
|
||||||
result.list += fallback
|
result.list += ObjString("#${pos.source.objSourceName}:${pos.line+1}:${pos.column+1}: ${pos.currentLine}")
|
||||||
}
|
}
|
||||||
lastPos = pos
|
lastPos = pos
|
||||||
}
|
}
|
||||||
@ -131,9 +120,6 @@ open class ObjException(
|
|||||||
s = s.parent
|
s = s.parent
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
} finally {
|
|
||||||
stackTraceCaptureDepth -= 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExceptionClass(val name: String, vararg parents: ObjClass) : ObjClass(name, *parents) {
|
class ExceptionClass(val name: String, vararg parents: ObjClass) : ObjClass(name, *parents) {
|
||||||
|
|||||||
@ -174,7 +174,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
|||||||
if (getValueRec == null || getValueRec.declaringClass?.className == "Delegate") {
|
if (getValueRec == null || getValueRec.declaringClass?.className == "Delegate") {
|
||||||
val wrapper = object : Statement() {
|
val wrapper = object : Statement() {
|
||||||
override val pos: Pos = Pos.builtIn
|
override val pos: Pos = Pos.builtIn
|
||||||
|
|
||||||
override suspend fun execute(s: Scope): Obj {
|
override suspend fun execute(s: Scope): Obj {
|
||||||
val th2 = if (s.thisObj === ObjVoid) ObjNull else s.thisObj
|
val th2 = if (s.thisObj === ObjVoid) ObjNull else s.thisObj
|
||||||
val allArgs = (listOf(th2, ObjString(name)) + s.args.list).toTypedArray()
|
val allArgs = (listOf(th2, ObjString(name)) + s.args.list).toTypedArray()
|
||||||
@ -365,16 +364,6 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
|||||||
|
|
||||||
// Fast path for public members when outside any class context
|
// Fast path for public members when outside any class context
|
||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
objClass.members[name]?.let { rec ->
|
|
||||||
if (rec.visibility == Visibility.Public && !rec.isAbstract) {
|
|
||||||
val decl = rec.declaringClass
|
|
||||||
if (rec.type == ObjRecord.Type.Property) {
|
|
||||||
if (args.isEmpty()) return (rec.value as ObjProperty).callGetter(scope, this, decl)
|
|
||||||
} else if (rec.type == ObjRecord.Type.Fun) {
|
|
||||||
return rec.value.invoke(instanceScope, this, args, decl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
objClass.publicMemberResolution[name]?.let { key ->
|
objClass.publicMemberResolution[name]?.let { key ->
|
||||||
methodRecordForKey(key)?.let { rec ->
|
methodRecordForKey(key)?.let { rec ->
|
||||||
if (rec.visibility == Visibility.Public && !rec.isAbstract) {
|
if (rec.visibility == Visibility.Public && !rec.isAbstract) {
|
||||||
|
|||||||
@ -286,3 +286,5 @@ class ObjInstant(val instant: Instant,val truncateMode: LynonSettings.InstantTru
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -445,66 +445,40 @@ class CastRef(
|
|||||||
override suspend fun get(scope: Scope): ObjRecord {
|
override suspend fun get(scope: Scope): ObjRecord {
|
||||||
val v0 = valueRef.evalValue(scope)
|
val v0 = valueRef.evalValue(scope)
|
||||||
val t = typeRef.evalValue(scope)
|
val t = typeRef.evalValue(scope)
|
||||||
|
val target = (t as? ObjClass) ?: scope.raiseClassCastError("${t} is not the class instance")
|
||||||
// unwrap qualified views
|
// unwrap qualified views
|
||||||
val v = when (v0) {
|
val v = when (v0) {
|
||||||
is ObjQualifiedView -> v0.instance
|
is ObjQualifiedView -> v0.instance
|
||||||
else -> v0
|
else -> v0
|
||||||
}
|
}
|
||||||
return when (t) {
|
return if (v.isInstanceOf(target)) {
|
||||||
is ObjClass -> {
|
|
||||||
if (v.isInstanceOf(t)) {
|
|
||||||
// For instances, return a qualified view to enforce ancestor-start dispatch
|
// For instances, return a qualified view to enforce ancestor-start dispatch
|
||||||
if (v is ObjInstance) ObjQualifiedView(v, t).asReadonly else v.asReadonly
|
if (v is ObjInstance) ObjQualifiedView(v, target).asReadonly else v.asReadonly
|
||||||
} else {
|
} else {
|
||||||
if (isNullable) ObjNull.asReadonly else scope.raiseClassCastError(
|
if (isNullable) ObjNull.asReadonly else scope.raiseClassCastError(
|
||||||
"Cannot cast ${(v as? Obj)?.objClass?.className ?: v::class.simpleName} to ${t.className}"
|
"Cannot cast ${(v as? Obj)?.objClass?.className ?: v::class.simpleName} to ${target.className}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ObjTypeExpr -> {
|
|
||||||
if (matchesTypeDecl(scope, v, t.typeDecl)) {
|
|
||||||
v.asReadonly
|
|
||||||
} else {
|
|
||||||
if (isNullable) ObjNull.asReadonly else scope.raiseClassCastError(
|
|
||||||
"Cannot cast ${(v as? Obj)?.objClass?.className ?: v::class.simpleName} to ${t.typeDecl}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> scope.raiseClassCastError("${t} is not the class instance")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun evalValue(scope: Scope): Obj {
|
override suspend fun evalValue(scope: Scope): Obj {
|
||||||
val v0 = valueRef.evalValue(scope)
|
val v0 = valueRef.evalValue(scope)
|
||||||
val t = typeRef.evalValue(scope)
|
val t = typeRef.evalValue(scope)
|
||||||
|
val target = (t as? ObjClass) ?: scope.raiseClassCastError("${t} is not the class instance")
|
||||||
// unwrap qualified views
|
// unwrap qualified views
|
||||||
val v = when (v0) {
|
val v = when (v0) {
|
||||||
is ObjQualifiedView -> v0.instance
|
is ObjQualifiedView -> v0.instance
|
||||||
else -> v0
|
else -> v0
|
||||||
}
|
}
|
||||||
return when (t) {
|
return if (v.isInstanceOf(target)) {
|
||||||
is ObjClass -> {
|
|
||||||
if (v.isInstanceOf(t)) {
|
|
||||||
// For instances, return a qualified view to enforce ancestor-start dispatch
|
// For instances, return a qualified view to enforce ancestor-start dispatch
|
||||||
if (v is ObjInstance) ObjQualifiedView(v, t) else v
|
if (v is ObjInstance) ObjQualifiedView(v, target) else v
|
||||||
} else {
|
} else {
|
||||||
if (isNullable) ObjNull else scope.raiseClassCastError(
|
if (isNullable) ObjNull else scope.raiseClassCastError(
|
||||||
"Cannot cast ${(v as? Obj)?.objClass?.className ?: v::class.simpleName} to ${t.className}"
|
"Cannot cast ${(v as? Obj)?.objClass?.className ?: v::class.simpleName} to ${target.className}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ObjTypeExpr -> {
|
|
||||||
if (matchesTypeDecl(scope, v, t.typeDecl)) {
|
|
||||||
v
|
|
||||||
} else {
|
|
||||||
if (isNullable) ObjNull else scope.raiseClassCastError(
|
|
||||||
"Cannot cast ${(v as? Obj)?.objClass?.className ?: v::class.simpleName} to ${t.typeDecl}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> scope.raiseClassCastError("${t} is not the class instance")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Type expression reference used for `is` checks (including unions/intersections). */
|
/** Type expression reference used for `is` checks (including unions/intersections). */
|
||||||
@ -1201,10 +1175,6 @@ class FieldRef(
|
|||||||
if (rec.receiver != null && rec.declaringClass != null) {
|
if (rec.receiver != null && rec.declaringClass != null) {
|
||||||
return rec.receiver!!.resolveRecord(scope, rec, name, rec.declaringClass).value
|
return rec.receiver!!.resolveRecord(scope, rec, name, rec.declaringClass).value
|
||||||
}
|
}
|
||||||
if (rec.type == ObjRecord.Type.Fun && !rec.isAbstract) {
|
|
||||||
val receiver = rec.receiver ?: base
|
|
||||||
return rec.value.invoke(scope, receiver, Arguments.EMPTY, rec.declaringClass)
|
|
||||||
}
|
|
||||||
return rec.value
|
return rec.value
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2330,11 +2300,6 @@ class LocalSlotRef(
|
|||||||
scope.raiseError("slot index out of range for $name")
|
scope.raiseError("slot index out of range for $name")
|
||||||
}
|
}
|
||||||
val rec = owner.getSlotRecord(slotIndex)
|
val rec = owner.getSlotRecord(slotIndex)
|
||||||
val direct = owner.getLocalRecordDirect(name)
|
|
||||||
if (direct != null && direct !== rec) {
|
|
||||||
owner.updateSlotFor(name, direct)
|
|
||||||
return direct
|
|
||||||
}
|
|
||||||
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||||
scope.raiseError(ObjIllegalAccessException(scope, "private field access"))
|
scope.raiseError(ObjIllegalAccessException(scope, "private field access"))
|
||||||
}
|
}
|
||||||
@ -2359,11 +2324,6 @@ class LocalSlotRef(
|
|||||||
scope.raiseError("slot index out of range for $name")
|
scope.raiseError("slot index out of range for $name")
|
||||||
}
|
}
|
||||||
val rec = owner.getSlotRecord(slotIndex)
|
val rec = owner.getSlotRecord(slotIndex)
|
||||||
val direct = owner.getLocalRecordDirect(name)
|
|
||||||
if (direct != null && direct !== rec) {
|
|
||||||
owner.updateSlotFor(name, direct)
|
|
||||||
return scope.resolve(direct, name)
|
|
||||||
}
|
|
||||||
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
if (rec.declaringClass != null && !canAccessMember(rec.visibility, rec.declaringClass, scope.currentClassCtx, name)) {
|
||||||
scope.raiseError(ObjIllegalAccessException(scope, "private field access"))
|
scope.raiseError(ObjIllegalAccessException(scope, "private field access"))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,17 +68,11 @@ abstract class ImportProvider(
|
|||||||
|
|
||||||
suspend fun newStdScope(pos: Pos = Pos.builtIn): Scope =
|
suspend fun newStdScope(pos: Pos = Pos.builtIn): Scope =
|
||||||
cachedStdScope.get {
|
cachedStdScope.get {
|
||||||
val module = newModuleAt(pos)
|
newModuleAt(pos).also {
|
||||||
val stdlib = prepareImport(pos, "lyng.stdlib", null)
|
it.eval("import lyng.stdlib\n")
|
||||||
val plan = LinkedHashMap<String, Int>()
|
|
||||||
for ((name, record) in stdlib.objects) {
|
|
||||||
if (!record.visibility.isPublic) continue
|
|
||||||
plan[name] = plan.size
|
|
||||||
}
|
}
|
||||||
if (plan.isNotEmpty()) module.applySlotPlan(plan)
|
|
||||||
stdlib.importInto(module, null)
|
|
||||||
module
|
|
||||||
}.createChildScope()
|
}.createChildScope()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user