Drive higher-order lambda inlining from call metadata
This commit is contained in:
1 parent
f4ab2ebab4
commit
fbb5688696
11 files changed
+401
-121
No files matched your search
@@ -20,5 +20,30 @@ package net.sergeych.lyng
|
||||
* Compile-time call metadata for known functions. Used to select lambda receiver semantics.
|
||||
*/
|
||||
data class CallSignature(
|
||||
val tailBlockReceiverType: String? = null
|
||||
)
|
||||
val tailBlockReceiverType: String? = null,
|
||||
val inlineHigherOrder: HigherOrderInline? = null
|
||||
) {
|
||||
data class HigherOrderInline(
|
||||
val kind: Kind,
|
||||
val result: ResultMode,
|
||||
val argCount: Int = 1,
|
||||
val lambdaArgIndex: Int = 0
|
||||
)
|
||||
|
||||
enum class Kind {
|
||||
UNARY_ARGUMENT,
|
||||
RECEIVER,
|
||||
ITERABLE,
|
||||
MAP_GET_OR_PUT
|
||||
}
|
||||
|
||||
enum class ResultMode {
|
||||
BLOCK_RESULT,
|
||||
RETURN_RECEIVER,
|
||||
FOR_EACH,
|
||||
MAP,
|
||||
FILTER,
|
||||
MAP_NOT_NULL,
|
||||
ASSOCIATE_BY
|
||||
}
|
||||
}
|
||||
@@ -187,6 +187,7 @@ class Compiler(
|
||||
private val callableReturnTypeByScopeId: MutableMap<Int, MutableMap<Int, ObjClass>> = mutableMapOf()
|
||||
private val callableReturnTypeByName: MutableMap<String, ObjClass> = mutableMapOf()
|
||||
private val callableReturnTypeDeclByName: MutableMap<String, TypeDecl> = mutableMapOf()
|
||||
private val callSignatureByName: MutableMap<String, CallSignature> = mutableMapOf()
|
||||
private val lambdaReturnTypeByRef: MutableMap<ObjRef, ObjClass> = mutableMapOf()
|
||||
private val exactLambdaRefByScopeId: MutableMap<Int, MutableMap<Int, LambdaFnRef>> = mutableMapOf()
|
||||
private val lambdaCaptureEntriesByRef: MutableMap<ValueFnRef, List<net.sergeych.lyng.bytecode.LambdaCaptureEntry>> =
|
||||
@@ -265,6 +266,11 @@ class Compiler(
|
||||
if (plan.slots.containsKey(name)) continue
|
||||
declareSlotNameIn(plan, name, record.isMutable, record.type == ObjRecord.Type.Delegated)
|
||||
scopeSeedNames.add(name)
|
||||
record.callSignature?.let { signature ->
|
||||
if (!callSignatureByName.containsKey(name)) {
|
||||
callSignatureByName[name] = signature
|
||||
}
|
||||
}
|
||||
if (record.typeDecl != null && nameTypeDecl[name] == null) {
|
||||
nameTypeDecl[name] = record.typeDecl
|
||||
if (nameObjClass[name] == null) {
|
||||
@@ -291,6 +297,11 @@ class Compiler(
|
||||
)
|
||||
scopeSeedNames.add(getterName)
|
||||
}
|
||||
record.callSignature?.let { signature ->
|
||||
if (!callSignatureByName.containsKey(getterName)) {
|
||||
callSignatureByName[getterName] = signature
|
||||
}
|
||||
}
|
||||
val prop = record.value as? ObjProperty
|
||||
if (prop?.setter != null) {
|
||||
val setterName = extensionPropertySetterName(cls.className, name)
|
||||
@@ -316,6 +327,11 @@ class Compiler(
|
||||
)
|
||||
scopeSeedNames.add(callableName)
|
||||
}
|
||||
record.callSignature?.let { signature ->
|
||||
if (!callSignatureByName.containsKey(callableName)) {
|
||||
callSignatureByName[callableName] = signature
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,6 +363,11 @@ class Compiler(
|
||||
record.type == ObjRecord.Type.Delegated
|
||||
)
|
||||
scopeSeedNames.add(name)
|
||||
record.callSignature?.let { signature ->
|
||||
if (!callSignatureByName.containsKey(name)) {
|
||||
callSignatureByName[name] = signature
|
||||
}
|
||||
}
|
||||
if (record.typeDecl != null && nameTypeDecl[name] == null) {
|
||||
nameTypeDecl[name] = record.typeDecl
|
||||
if (nameObjClass[name] == null) {
|
||||
@@ -762,6 +783,29 @@ class Compiler(
|
||||
?: importManager.rootScope.getLocalRecordDirect(name)?.callSignature
|
||||
}
|
||||
|
||||
private fun declaredCallSignature(name: String, extTypeName: String?, actualExtern: Boolean): CallSignature? {
|
||||
val imported = if (actualExtern) {
|
||||
importManager.rootScope.getLocalRecordDirect(name)?.callSignature
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val inferred = when {
|
||||
extTypeName == "Iterable" && name == "filter" -> CallSignature(
|
||||
inlineHigherOrder = CallSignature.HigherOrderInline(
|
||||
kind = CallSignature.Kind.ITERABLE,
|
||||
result = CallSignature.ResultMode.FILTER
|
||||
)
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
return when {
|
||||
imported == null -> inferred
|
||||
inferred == null -> imported
|
||||
imported.inlineHigherOrder != null -> imported
|
||||
else -> imported.copy(inlineHigherOrder = inferred.inlineHigherOrder)
|
||||
}
|
||||
}
|
||||
|
||||
internal data class MemberIds(val fieldId: Int?, val methodId: Int?)
|
||||
|
||||
private fun resolveMemberIds(name: String, pos: Pos, qualifier: String? = null): MemberIds {
|
||||
@@ -1429,6 +1473,11 @@ class Compiler(
|
||||
}
|
||||
|
||||
private fun seedImportTypeMetadata(name: String, record: ObjRecord) {
|
||||
record.callSignature?.let { signature ->
|
||||
if (!callSignatureByName.containsKey(name)) {
|
||||
callSignatureByName[name] = signature
|
||||
}
|
||||
}
|
||||
if (record.typeDecl != null && nameTypeDecl[name] == null) {
|
||||
nameTypeDecl[name] = record.typeDecl
|
||||
}
|
||||
@@ -1904,6 +1953,7 @@ class Compiler(
|
||||
enumEntriesByName = enumEntriesByName,
|
||||
callableReturnTypeByScopeId = callableReturnTypeByScopeId,
|
||||
callableReturnTypeByName = callableReturnTypeByName,
|
||||
callSignatureByName = callSignatureByName,
|
||||
externBindingNames = externBindingNames,
|
||||
preparedModuleBindingNames = importBindings.keys,
|
||||
scopeRefPosByName = moduleReferencePosByName,
|
||||
@@ -2260,6 +2310,7 @@ class Compiler(
|
||||
enumEntriesByName = enumEntriesByName,
|
||||
callableReturnTypeByScopeId = callableReturnTypeByScopeId,
|
||||
callableReturnTypeByName = callableReturnTypeByName,
|
||||
callSignatureByName = callSignatureByName,
|
||||
externCallableNames = externCallableNames,
|
||||
externBindingNames = externBindingNames,
|
||||
preparedModuleBindingNames = importBindings.keys,
|
||||
@@ -2294,6 +2345,7 @@ class Compiler(
|
||||
enumEntriesByName = enumEntriesByName,
|
||||
callableReturnTypeByScopeId = callableReturnTypeByScopeId,
|
||||
callableReturnTypeByName = callableReturnTypeByName,
|
||||
callSignatureByName = callSignatureByName,
|
||||
externCallableNames = externCallableNames,
|
||||
externBindingNames = externBindingNames,
|
||||
preparedModuleBindingNames = importBindings.keys,
|
||||
@@ -2353,6 +2405,7 @@ class Compiler(
|
||||
enumEntriesByName = enumEntriesByName,
|
||||
callableReturnTypeByScopeId = callableReturnTypeByScopeId,
|
||||
callableReturnTypeByName = callableReturnTypeByName,
|
||||
callSignatureByName = callSignatureByName,
|
||||
externCallableNames = externCallableNames,
|
||||
externBindingNames = externBindingNames,
|
||||
preparedModuleBindingNames = importBindings.keys,
|
||||
@@ -9208,7 +9261,7 @@ class Compiler(
|
||||
val extensionWrapperName = extTypeName?.let { extensionCallableName(it, name) }
|
||||
val classCtx = codeContexts.asReversed().firstOrNull { it is CodeContext.ClassBody } as? CodeContext.ClassBody
|
||||
var memberMethodId = if (extTypeName == null) classCtx?.memberMethodIds?.get(name) else null
|
||||
val externCallSignature = if (actualExtern) importManager.rootScope.getLocalRecordDirect(name)?.callSignature else null
|
||||
val externCallSignature = declaredCallSignature(name, extTypeName, actualExtern)
|
||||
|
||||
val declKind = if (parentContext is CodeContext.ClassBody) SymbolKind.MEMBER else SymbolKind.FUNCTION
|
||||
resolutionSink?.declareSymbol(name, declKind, isMutable = false, pos = nameStartPos, isOverride = isOverride)
|
||||
@@ -9230,7 +9283,9 @@ class Compiler(
|
||||
}
|
||||
if (extensionWrapperName != null) {
|
||||
declareLocalName(extensionWrapperName, isMutable = false)
|
||||
externCallSignature?.let { callSignatureByName[extensionWrapperName] = it }
|
||||
}
|
||||
externCallSignature?.let { callSignatureByName[name] = it }
|
||||
if (actualExtern && declKind != SymbolKind.MEMBER) {
|
||||
externCallableNames.add(name)
|
||||
}
|
||||
|
||||
@@ -118,7 +118,14 @@ internal suspend fun executeFunctionDecl(
|
||||
scope.addExtension(
|
||||
type,
|
||||
spec.name,
|
||||
ObjRecord(ObjUnset, isMutable = false, visibility = spec.visibility, declaringClass = null, type = ObjRecord.Type.Delegated).apply {
|
||||
ObjRecord(
|
||||
ObjUnset,
|
||||
isMutable = false,
|
||||
visibility = spec.visibility,
|
||||
declaringClass = null,
|
||||
type = ObjRecord.Type.Delegated,
|
||||
callSignature = spec.externCallSignature
|
||||
).apply {
|
||||
delegate = finalDelegate
|
||||
}
|
||||
)
|
||||
@@ -135,7 +142,8 @@ internal suspend fun executeFunctionDecl(
|
||||
null,
|
||||
spec.startPos,
|
||||
isTransient = spec.isTransient,
|
||||
type = ObjRecord.Type.Delegated
|
||||
type = ObjRecord.Type.Delegated,
|
||||
callSignature = spec.externCallSignature
|
||||
).apply {
|
||||
delegate = finalDelegate
|
||||
}
|
||||
@@ -204,6 +212,7 @@ internal suspend fun executeFunctionDecl(
|
||||
visibility = spec.visibility,
|
||||
pos = spec.startPos,
|
||||
type = ObjRecord.Type.Fun,
|
||||
callSignature = spec.externCallSignature,
|
||||
)
|
||||
} else {
|
||||
scope.addExtension(
|
||||
@@ -215,6 +224,7 @@ internal suspend fun executeFunctionDecl(
|
||||
visibility = spec.visibility,
|
||||
declaringClass = null,
|
||||
type = ObjRecord.Type.Fun,
|
||||
callSignature = spec.externCallSignature,
|
||||
typeDecl = spec.typeDecl
|
||||
)
|
||||
)
|
||||
@@ -227,6 +237,7 @@ internal suspend fun executeFunctionDecl(
|
||||
wrapper,
|
||||
spec.visibility,
|
||||
recordType = ObjRecord.Type.Fun,
|
||||
callSignature = spec.externCallSignature,
|
||||
typeDecl = spec.typeDecl
|
||||
)
|
||||
} ?: run {
|
||||
@@ -245,7 +256,8 @@ internal suspend fun executeFunctionDecl(
|
||||
isOverride = spec.isOverride,
|
||||
type = ObjRecord.Type.Fun,
|
||||
methodId = spec.memberMethodId,
|
||||
typeDecl = spec.typeDecl
|
||||
typeDecl = spec.typeDecl,
|
||||
callSignature = spec.externCallSignature
|
||||
)
|
||||
val memberValue = cls.members[spec.name]?.value ?: compiledFnBody
|
||||
scope.addItem(
|
||||
|
||||
@@ -42,6 +42,7 @@ class BytecodeCompiler(
|
||||
private val enumEntriesByName: Map<String, List<String>> = emptyMap(),
|
||||
private val callableReturnTypeByScopeId: Map<Int, Map<Int, ObjClass>> = emptyMap(),
|
||||
private val callableReturnTypeByName: Map<String, ObjClass> = emptyMap(),
|
||||
private val callSignatureByName: Map<String, CallSignature> = emptyMap(),
|
||||
private val externCallableNames: Set<String> = emptySet(),
|
||||
private val externBindingNames: Set<String> = emptySet(),
|
||||
private val preparedModuleBindingNames: Set<String> = emptySet(),
|
||||
@@ -4980,22 +4981,22 @@ class BytecodeCompiler(
|
||||
}
|
||||
|
||||
private fun compileInlineHigherOrderMethodCall(ref: MethodCallRef): CompiledValue? {
|
||||
val spec = inlineHigherOrderMethodSpec(ref.name) ?: return null
|
||||
val spec = inlineHigherOrderMethodSpec(ref) ?: return null
|
||||
if (ref.args.size != spec.argCount || ref.args.any { it.isSplat || it.name != null }) return null
|
||||
if (!ref.explicitTypeArgs.isNullOrEmpty()) return null
|
||||
val lambdaRef = extractExactLambdaRef(ref.args[spec.lambdaArgIndex].value) ?: return null
|
||||
val inlineRef = lambdaRef.inlineBodyRef ?: return null
|
||||
return when (spec.kind) {
|
||||
InlineHigherOrderMethodKind.UNARY_ARGUMENT -> {
|
||||
CallSignature.Kind.UNARY_ARGUMENT -> {
|
||||
if (!isMethodInlineSafe(lambdaRef, inlineRef, allowReceiverRefs = false, allowCaptures = true)) return null
|
||||
val receiver = compileRefWithFallback(ref.receiver, null, refPosOrCurrent(ref.receiver)) ?: return null
|
||||
val receiverObj = ensureObjSlot(receiver)
|
||||
compileOptionalInlineMethod(ref.isOptional, receiverObj) {
|
||||
val bindings = prepareInlineLambdaBindingsFromValues(lambdaRef, listOf(receiver)) ?: return@compileOptionalInlineMethod null
|
||||
when (spec.result) {
|
||||
InlineHigherOrderResultMode.BLOCK_RESULT ->
|
||||
CallSignature.ResultMode.BLOCK_RESULT ->
|
||||
compileInlineLambdaBody(lambdaRef, inlineRef, bindings)
|
||||
InlineHigherOrderResultMode.RETURN_RECEIVER -> {
|
||||
CallSignature.ResultMode.RETURN_RECEIVER -> {
|
||||
compileInlineLambdaBody(lambdaRef, inlineRef, bindings) ?: return@compileOptionalInlineMethod null
|
||||
CompiledValue(receiverObj.slot, SlotType.OBJ)
|
||||
}
|
||||
@@ -5003,7 +5004,7 @@ class BytecodeCompiler(
|
||||
}
|
||||
}
|
||||
}
|
||||
InlineHigherOrderMethodKind.RECEIVER -> {
|
||||
CallSignature.Kind.RECEIVER -> {
|
||||
val receiverInfo = receiverInlineInfo(lambdaRef) ?: return null
|
||||
if (!isMethodInlineSafe(lambdaRef, inlineRef, allowReceiverRefs = true, allowCaptures = true)) return null
|
||||
val receiver = compileRefWithFallback(ref.receiver, null, refPosOrCurrent(ref.receiver)) ?: return null
|
||||
@@ -5012,7 +5013,7 @@ class BytecodeCompiler(
|
||||
compileInlineReceiverLambdaInvocation(receiverObj, lambdaRef, spec.result, receiverInfo)
|
||||
}
|
||||
}
|
||||
InlineHigherOrderMethodKind.ITERABLE -> {
|
||||
CallSignature.Kind.ITERABLE -> {
|
||||
if (!isMethodInlineSafe(lambdaRef, inlineRef, allowReceiverRefs = false, allowCaptures = true)) return null
|
||||
val receiver = compileRefWithFallback(ref.receiver, null, refPosOrCurrent(ref.receiver)) ?: return null
|
||||
val receiverObj = ensureObjSlot(receiver)
|
||||
@@ -5020,7 +5021,7 @@ class BytecodeCompiler(
|
||||
compileInlineIterableLambdaLoop(receiverObj, ref, lambdaRef, inlineRef, spec.result)
|
||||
}
|
||||
}
|
||||
InlineHigherOrderMethodKind.MAP_GET_OR_PUT -> {
|
||||
CallSignature.Kind.MAP_GET_OR_PUT -> {
|
||||
val receiverClass = resolveReceiverClass(ref.receiver) ?: return null
|
||||
if (receiverClass != ObjMap.type) return null
|
||||
if (!isMethodInlineSafe(lambdaRef, inlineRef, allowReceiverRefs = false, allowCaptures = true)) return null
|
||||
@@ -5131,81 +5132,20 @@ class BytecodeCompiler(
|
||||
return slot
|
||||
}
|
||||
|
||||
private enum class InlineHigherOrderMethodKind {
|
||||
UNARY_ARGUMENT,
|
||||
RECEIVER,
|
||||
ITERABLE,
|
||||
MAP_GET_OR_PUT
|
||||
}
|
||||
|
||||
private enum class InlineHigherOrderResultMode {
|
||||
BLOCK_RESULT,
|
||||
RETURN_RECEIVER,
|
||||
FOR_EACH,
|
||||
MAP,
|
||||
FILTER,
|
||||
MAP_NOT_NULL,
|
||||
ASSOCIATE_BY
|
||||
}
|
||||
|
||||
private data class InlineHigherOrderMethodSpec(
|
||||
val kind: InlineHigherOrderMethodKind,
|
||||
val result: InlineHigherOrderResultMode,
|
||||
val argCount: Int = 1,
|
||||
val lambdaArgIndex: Int = 0
|
||||
)
|
||||
|
||||
private data class InlineReceiverInfo(
|
||||
val explicitBindings: List<Pair<String, Int>>,
|
||||
val thisTypeName: String?
|
||||
)
|
||||
|
||||
private fun inlineHigherOrderMethodSpec(name: String): InlineHigherOrderMethodSpec? {
|
||||
return when (name) {
|
||||
"let" -> InlineHigherOrderMethodSpec(
|
||||
InlineHigherOrderMethodKind.UNARY_ARGUMENT,
|
||||
InlineHigherOrderResultMode.BLOCK_RESULT
|
||||
)
|
||||
"also" -> InlineHigherOrderMethodSpec(
|
||||
InlineHigherOrderMethodKind.UNARY_ARGUMENT,
|
||||
InlineHigherOrderResultMode.RETURN_RECEIVER
|
||||
)
|
||||
"apply" -> InlineHigherOrderMethodSpec(
|
||||
InlineHigherOrderMethodKind.RECEIVER,
|
||||
InlineHigherOrderResultMode.RETURN_RECEIVER
|
||||
)
|
||||
"run" -> InlineHigherOrderMethodSpec(
|
||||
InlineHigherOrderMethodKind.RECEIVER,
|
||||
InlineHigherOrderResultMode.BLOCK_RESULT
|
||||
)
|
||||
"forEach" -> InlineHigherOrderMethodSpec(
|
||||
InlineHigherOrderMethodKind.ITERABLE,
|
||||
InlineHigherOrderResultMode.FOR_EACH
|
||||
)
|
||||
"map" -> InlineHigherOrderMethodSpec(
|
||||
InlineHigherOrderMethodKind.ITERABLE,
|
||||
InlineHigherOrderResultMode.MAP
|
||||
)
|
||||
"filter" -> InlineHigherOrderMethodSpec(
|
||||
InlineHigherOrderMethodKind.ITERABLE,
|
||||
InlineHigherOrderResultMode.FILTER
|
||||
)
|
||||
"mapNotNull" -> InlineHigherOrderMethodSpec(
|
||||
InlineHigherOrderMethodKind.ITERABLE,
|
||||
InlineHigherOrderResultMode.MAP_NOT_NULL
|
||||
)
|
||||
"associateBy" -> InlineHigherOrderMethodSpec(
|
||||
InlineHigherOrderMethodKind.ITERABLE,
|
||||
InlineHigherOrderResultMode.ASSOCIATE_BY
|
||||
)
|
||||
"getOrPut" -> InlineHigherOrderMethodSpec(
|
||||
InlineHigherOrderMethodKind.MAP_GET_OR_PUT,
|
||||
InlineHigherOrderResultMode.BLOCK_RESULT,
|
||||
argCount = 2,
|
||||
lambdaArgIndex = 1
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
private fun inlineHigherOrderMethodSpec(ref: MethodCallRef): CallSignature.HigherOrderInline? {
|
||||
resolveReceiverClass(ref.receiver)
|
||||
?.resolveInstanceMember(ref.name)
|
||||
?.record
|
||||
?.callSignature
|
||||
?.inlineHigherOrder
|
||||
?.let { return it }
|
||||
val receiverClass = resolveReceiverClass(ref.receiver) ?: return null
|
||||
return extensionCallableSignature(receiverClass, ref.name)?.inlineHigherOrder
|
||||
}
|
||||
|
||||
private fun compileOptionalInlineMethod(
|
||||
@@ -5329,7 +5269,7 @@ class BytecodeCompiler(
|
||||
private fun compileInlineReceiverLambdaInvocation(
|
||||
receiverObj: CompiledValue,
|
||||
lambdaRef: LambdaFnRef,
|
||||
behavior: InlineHigherOrderResultMode,
|
||||
behavior: CallSignature.ResultMode,
|
||||
receiverInfo: InlineReceiverInfo
|
||||
): CompiledValue? {
|
||||
val inlineRef = lambdaRef.inlineBodyRef ?: return null
|
||||
@@ -5338,9 +5278,9 @@ class BytecodeCompiler(
|
||||
inlineThisBindings.addLast(previousBinding)
|
||||
return try {
|
||||
when (behavior) {
|
||||
InlineHigherOrderResultMode.BLOCK_RESULT ->
|
||||
CallSignature.ResultMode.BLOCK_RESULT ->
|
||||
compileInlineLambdaBody(lambdaRef, inlineRef, receiverInfo.explicitBindings)
|
||||
InlineHigherOrderResultMode.RETURN_RECEIVER -> {
|
||||
CallSignature.ResultMode.RETURN_RECEIVER -> {
|
||||
compileInlineLambdaBody(lambdaRef, inlineRef, receiverInfo.explicitBindings) ?: return null
|
||||
CompiledValue(receiverSlot, SlotType.OBJ)
|
||||
}
|
||||
@@ -5372,7 +5312,7 @@ class BytecodeCompiler(
|
||||
ref: MethodCallRef,
|
||||
lambdaRef: LambdaFnRef,
|
||||
inlineRef: ObjRef,
|
||||
behavior: InlineHigherOrderResultMode
|
||||
behavior: CallSignature.ResultMode
|
||||
): CompiledValue? {
|
||||
val iterableMethods = ObjIterable.instanceMethodIdMap(includeAbstract = true)
|
||||
val iteratorMethodId = iterableMethods["iterator"]
|
||||
@@ -5388,17 +5328,17 @@ class BytecodeCompiler(
|
||||
builder.emit(Opcode.ITER_PUSH, iterSlot)
|
||||
|
||||
val result = when (behavior) {
|
||||
InlineHigherOrderResultMode.FOR_EACH -> CompiledValue(ensureVoidSlot(), SlotType.OBJ)
|
||||
InlineHigherOrderResultMode.MAP,
|
||||
InlineHigherOrderResultMode.FILTER,
|
||||
InlineHigherOrderResultMode.MAP_NOT_NULL -> createEmptyMutableList() ?: return null
|
||||
InlineHigherOrderResultMode.ASSOCIATE_BY -> createEmptyMutableMap() ?: return null
|
||||
CallSignature.ResultMode.FOR_EACH -> CompiledValue(ensureVoidSlot(), SlotType.OBJ)
|
||||
CallSignature.ResultMode.MAP,
|
||||
CallSignature.ResultMode.FILTER,
|
||||
CallSignature.ResultMode.MAP_NOT_NULL -> createEmptyMutableList() ?: return null
|
||||
CallSignature.ResultMode.ASSOCIATE_BY -> createEmptyMutableMap() ?: return null
|
||||
else -> return null
|
||||
}
|
||||
if (behavior == InlineHigherOrderResultMode.FILTER) {
|
||||
if (behavior == CallSignature.ResultMode.FILTER) {
|
||||
listElementClassFromReceiverRef(ref.receiver)?.let { listElementClassBySlot[result.slot] = it }
|
||||
}
|
||||
if (behavior == InlineHigherOrderResultMode.MAP) {
|
||||
if (behavior == CallSignature.ResultMode.MAP) {
|
||||
lambdaRef.inferredReturnClass?.let { listElementClassBySlot[result.slot] = it }
|
||||
}
|
||||
|
||||
@@ -5418,14 +5358,14 @@ class BytecodeCompiler(
|
||||
val nextObj = ensureObjSlot(CompiledValue(nextSlot, SlotType.UNKNOWN))
|
||||
val bindings = prepareInlineLambdaBindingsFromValues(lambdaRef, listOf(nextObj)) ?: return null
|
||||
when (behavior) {
|
||||
InlineHigherOrderResultMode.FOR_EACH -> {
|
||||
CallSignature.ResultMode.FOR_EACH -> {
|
||||
compileInlineLambdaBody(lambdaRef, inlineRef, bindings) ?: return null
|
||||
}
|
||||
InlineHigherOrderResultMode.MAP -> {
|
||||
CallSignature.ResultMode.MAP -> {
|
||||
val mapped = compileInlineLambdaBody(lambdaRef, inlineRef, bindings) ?: return null
|
||||
appendToList(result, mapped) ?: return null
|
||||
}
|
||||
InlineHigherOrderResultMode.FILTER -> {
|
||||
CallSignature.ResultMode.FILTER -> {
|
||||
val predicate = compileInlineLambdaBody(lambdaRef, inlineRef, bindings) ?: return null
|
||||
val predicateBool = compileValueAsBool(predicate)
|
||||
val skipLabel = builder.label()
|
||||
@@ -5436,7 +5376,7 @@ class BytecodeCompiler(
|
||||
appendToList(result, nextObj) ?: return null
|
||||
builder.mark(skipLabel)
|
||||
}
|
||||
InlineHigherOrderResultMode.MAP_NOT_NULL -> {
|
||||
CallSignature.ResultMode.MAP_NOT_NULL -> {
|
||||
val mapped = compileInlineLambdaBody(lambdaRef, inlineRef, bindings) ?: return null
|
||||
val mappedObj = ensureObjSlot(mapped)
|
||||
val nullSlot = allocSlot()
|
||||
@@ -5451,7 +5391,7 @@ class BytecodeCompiler(
|
||||
appendToList(result, mappedObj) ?: return null
|
||||
builder.mark(skipLabel)
|
||||
}
|
||||
InlineHigherOrderResultMode.ASSOCIATE_BY -> {
|
||||
CallSignature.ResultMode.ASSOCIATE_BY -> {
|
||||
val key = compileInlineLambdaBody(lambdaRef, inlineRef, bindings) ?: return null
|
||||
appendToMap(result, key, nextObj)
|
||||
}
|
||||
@@ -5986,11 +5926,11 @@ class BytecodeCompiler(
|
||||
return names
|
||||
}
|
||||
|
||||
private fun resolveExtensionSlotByReceiverNames(
|
||||
private fun resolveExtensionWrapperNameByReceiverNames(
|
||||
receiverClass: ObjClass,
|
||||
memberName: String,
|
||||
wrapperName: (String, String) -> String
|
||||
): CompiledValue? {
|
||||
): String? {
|
||||
for (receiverName in extensionReceiverTypeNames(receiverClass)) {
|
||||
val candidate = wrapperName(receiverName, memberName)
|
||||
if (allowedScopeNames != null &&
|
||||
@@ -5999,15 +5939,15 @@ class BytecodeCompiler(
|
||||
) {
|
||||
continue
|
||||
}
|
||||
resolveDirectNameSlot(candidate)?.let { return it }
|
||||
if (resolveDirectNameSlot(candidate) != null) return candidate
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun resolveUniqueExtensionWrapperSlot(
|
||||
private fun resolveUniqueExtensionWrapperName(
|
||||
memberName: String,
|
||||
wrapperPrefix: String
|
||||
): CompiledValue? {
|
||||
): String? {
|
||||
val suffix = "__$memberName"
|
||||
val candidates = LinkedHashSet<String>()
|
||||
for (name in localSlotIndexByName.keys) {
|
||||
@@ -6020,8 +5960,31 @@ class BytecodeCompiler(
|
||||
candidates.add(name)
|
||||
}
|
||||
}
|
||||
if (candidates.size != 1) return null
|
||||
return resolveDirectNameSlot(candidates.first())
|
||||
return candidates.singleOrNull()
|
||||
}
|
||||
|
||||
private fun resolveExtensionSlotByReceiverNames(
|
||||
receiverClass: ObjClass,
|
||||
memberName: String,
|
||||
wrapperName: (String, String) -> String
|
||||
): CompiledValue? {
|
||||
val resolvedName = resolveExtensionWrapperNameByReceiverNames(receiverClass, memberName, wrapperName) ?: return null
|
||||
return resolveDirectNameSlot(resolvedName)
|
||||
}
|
||||
|
||||
private fun resolveUniqueExtensionWrapperSlot(
|
||||
memberName: String,
|
||||
wrapperPrefix: String
|
||||
): CompiledValue? {
|
||||
val resolvedName = resolveUniqueExtensionWrapperName(memberName, wrapperPrefix) ?: return null
|
||||
return resolveDirectNameSlot(resolvedName)
|
||||
}
|
||||
|
||||
private fun extensionCallableSignature(receiverClass: ObjClass, memberName: String): CallSignature? {
|
||||
val wrapperName = resolveExtensionWrapperNameByReceiverNames(receiverClass, memberName, ::extensionCallableName)
|
||||
?: resolveUniqueExtensionWrapperName(memberName, "__ext__")
|
||||
?: return null
|
||||
return callSignatureByName[wrapperName]
|
||||
}
|
||||
|
||||
private fun resolveExtensionCallableSlot(receiverClass: ObjClass, memberName: String): CompiledValue? {
|
||||
|
||||
@@ -106,6 +106,7 @@ class BytecodeStatement private constructor(
|
||||
enumEntriesByName: Map<String, List<String>> = emptyMap(),
|
||||
callableReturnTypeByScopeId: Map<Int, Map<Int, ObjClass>> = emptyMap(),
|
||||
callableReturnTypeByName: Map<String, ObjClass> = emptyMap(),
|
||||
callSignatureByName: Map<String, CallSignature> = emptyMap(),
|
||||
externCallableNames: Set<String> = emptySet(),
|
||||
externBindingNames: Set<String> = emptySet(),
|
||||
preparedModuleBindingNames: Set<String> = emptySet(),
|
||||
@@ -146,6 +147,7 @@ class BytecodeStatement private constructor(
|
||||
enumEntriesByName = enumEntriesByName,
|
||||
callableReturnTypeByScopeId = callableReturnTypeByScopeId,
|
||||
callableReturnTypeByName = callableReturnTypeByName,
|
||||
callSignatureByName = callSignatureByName,
|
||||
externCallableNames = externCallableNames,
|
||||
externBindingNames = externBindingNames,
|
||||
preparedModuleBindingNames = preparedModuleBindingNames,
|
||||
|
||||
@@ -99,10 +99,11 @@ fun ObjClass.addFnDoc(
|
||||
visibility: Visibility = Visibility.Public,
|
||||
tags: Map<String, List<String>> = emptyMap(),
|
||||
moduleName: String? = null,
|
||||
callSignature: net.sergeych.lyng.CallSignature? = null,
|
||||
code: suspend ScopeFacade.() -> Obj
|
||||
) {
|
||||
// Register runtime method
|
||||
addFn(name, isOpen, visibility, code = code)
|
||||
addFn(name, isOpen, visibility, callSignature = callSignature, code = code)
|
||||
// Register docs for the member under this class
|
||||
BuiltinDocRegistry.module(moduleName ?: ownerModuleNameFromClassOrUnknown()) {
|
||||
classDoc(this@addFnDoc.className, doc = "") {
|
||||
@@ -137,9 +138,10 @@ fun ObjClass.addClassFnDoc(
|
||||
isOpen: Boolean = false,
|
||||
tags: Map<String, List<String>> = emptyMap(),
|
||||
moduleName: String? = null,
|
||||
callSignature: net.sergeych.lyng.CallSignature? = null,
|
||||
code: suspend ScopeFacade.() -> Obj
|
||||
) {
|
||||
addClassFn(name, isOpen, code)
|
||||
addClassFn(name, isOpen, callSignature, code)
|
||||
BuiltinDocRegistry.module(moduleName ?: ownerModuleNameFromClassOrUnknown()) {
|
||||
classDoc(this@addClassFnDoc.className, doc = "") {
|
||||
method(name = name, doc = doc, params = params, returns = returns, isStatic = true, tags = tags)
|
||||
|
||||
@@ -828,7 +828,13 @@ open class Obj {
|
||||
name = "let",
|
||||
doc = "Calls the specified function block with `this` value as its argument and returns its result.",
|
||||
params = listOf(ParamDoc("block")),
|
||||
moduleName = "lyng.stdlib"
|
||||
moduleName = "lyng.stdlib",
|
||||
callSignature = CallSignature(
|
||||
inlineHigherOrder = CallSignature.HigherOrderInline(
|
||||
kind = CallSignature.Kind.UNARY_ARGUMENT,
|
||||
result = CallSignature.ResultMode.BLOCK_RESULT
|
||||
)
|
||||
)
|
||||
) {
|
||||
call(args.firstAndOnly(), Arguments(thisObj))
|
||||
}
|
||||
@@ -836,7 +842,13 @@ open class Obj {
|
||||
name = "apply",
|
||||
doc = "Calls the specified function block with `this` value as its receiver and returns `this` value.",
|
||||
params = listOf(ParamDoc("block")),
|
||||
moduleName = "lyng.stdlib"
|
||||
moduleName = "lyng.stdlib",
|
||||
callSignature = CallSignature(
|
||||
inlineHigherOrder = CallSignature.HigherOrderInline(
|
||||
kind = CallSignature.Kind.RECEIVER,
|
||||
result = CallSignature.ResultMode.RETURN_RECEIVER
|
||||
)
|
||||
)
|
||||
) {
|
||||
val body = args.firstAndOnly()
|
||||
val scope = requireScope()
|
||||
@@ -852,7 +864,13 @@ open class Obj {
|
||||
name = "also",
|
||||
doc = "Calls the specified function block with `this` value as its argument and returns `this` value.",
|
||||
params = listOf(ParamDoc("block")),
|
||||
moduleName = "lyng.stdlib"
|
||||
moduleName = "lyng.stdlib",
|
||||
callSignature = CallSignature(
|
||||
inlineHigherOrder = CallSignature.HigherOrderInline(
|
||||
kind = CallSignature.Kind.UNARY_ARGUMENT,
|
||||
result = CallSignature.ResultMode.RETURN_RECEIVER
|
||||
)
|
||||
)
|
||||
) {
|
||||
call(args.firstAndOnly(), Arguments(thisObj))
|
||||
thisObj
|
||||
@@ -861,7 +879,13 @@ open class Obj {
|
||||
name = "run",
|
||||
doc = "Calls the specified function block with `this` value as its receiver and returns its result.",
|
||||
params = listOf(ParamDoc("block")),
|
||||
moduleName = "lyng.stdlib"
|
||||
moduleName = "lyng.stdlib",
|
||||
callSignature = CallSignature(
|
||||
inlineHigherOrder = CallSignature.HigherOrderInline(
|
||||
kind = CallSignature.Kind.RECEIVER,
|
||||
result = CallSignature.ResultMode.BLOCK_RESULT
|
||||
)
|
||||
)
|
||||
) {
|
||||
call(args.firstAndOnly())
|
||||
}
|
||||
|
||||
@@ -849,6 +849,7 @@ open class ObjClass(
|
||||
fieldId: Int? = null,
|
||||
methodId: Int? = null,
|
||||
typeDecl: net.sergeych.lyng.TypeDecl? = null,
|
||||
callSignature: net.sergeych.lyng.CallSignature? = null,
|
||||
): ObjRecord {
|
||||
// Validation of override rules: only for non-system declarations
|
||||
var existing: ObjRecord? = null
|
||||
@@ -949,6 +950,7 @@ open class ObjClass(
|
||||
isOverride = isOverride,
|
||||
isTransient = isTransient,
|
||||
type = type,
|
||||
callSignature = callSignature,
|
||||
typeDecl = typeDecl,
|
||||
memberName = name,
|
||||
fieldId = effectiveFieldId,
|
||||
@@ -975,7 +977,8 @@ open class ObjClass(
|
||||
isTransient: Boolean = false,
|
||||
type: ObjRecord.Type = ObjRecord.Type.Field,
|
||||
fieldId: Int? = null,
|
||||
methodId: Int? = null
|
||||
methodId: Int? = null,
|
||||
callSignature: net.sergeych.lyng.CallSignature? = null
|
||||
): ObjRecord {
|
||||
initClassScope()
|
||||
val existing = classScope!!.objects[name]
|
||||
@@ -1016,6 +1019,7 @@ open class ObjClass(
|
||||
writeVisibility,
|
||||
recordType = type,
|
||||
isTransient = isTransient,
|
||||
callSignature = callSignature,
|
||||
fieldId = effectiveFieldId,
|
||||
methodId = effectiveMethodId
|
||||
)
|
||||
@@ -1035,6 +1039,7 @@ open class ObjClass(
|
||||
isOverride: Boolean = false,
|
||||
pos: Pos = Pos.builtIn,
|
||||
methodId: Int? = null,
|
||||
callSignature: net.sergeych.lyng.CallSignature? = null,
|
||||
code: (suspend net.sergeych.lyng.ScopeFacade.() -> Obj)? = null
|
||||
) {
|
||||
val stmt = code?.let { ObjExternCallable.fromBridge { it() } } ?: ObjNull
|
||||
@@ -1042,7 +1047,8 @@ open class ObjClass(
|
||||
name, stmt, isMutable, visibility, writeVisibility, pos, declaringClass,
|
||||
isAbstract = isAbstract, isClosed = isClosed, isOverride = isOverride,
|
||||
type = ObjRecord.Type.Fun,
|
||||
methodId = methodId
|
||||
methodId = methodId,
|
||||
callSignature = callSignature
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1074,8 +1080,19 @@ open class ObjClass(
|
||||
}
|
||||
|
||||
fun addClassConst(name: String, value: Obj) = createClassField(name, value)
|
||||
fun addClassFn(name: String, isOpen: Boolean = false, code: suspend net.sergeych.lyng.ScopeFacade.() -> Obj) {
|
||||
createClassField(name, ObjExternCallable.fromBridge { code() }, isOpen, type = ObjRecord.Type.Fun)
|
||||
fun addClassFn(
|
||||
name: String,
|
||||
isOpen: Boolean = false,
|
||||
callSignature: net.sergeych.lyng.CallSignature? = null,
|
||||
code: suspend net.sergeych.lyng.ScopeFacade.() -> Obj
|
||||
) {
|
||||
createClassField(
|
||||
name,
|
||||
ObjExternCallable.fromBridge { code() },
|
||||
isOpen,
|
||||
type = ObjRecord.Type.Fun,
|
||||
callSignature = callSignature
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Arguments
|
||||
import net.sergeych.lyng.CallSignature
|
||||
import net.sergeych.lyng.miniast.ParamDoc
|
||||
import net.sergeych.lyng.miniast.addFnDoc
|
||||
import net.sergeych.lyng.miniast.addPropertyDoc
|
||||
@@ -189,7 +190,13 @@ val ObjIterable by lazy {
|
||||
doc = "Build a map from elements using the lambda result as key.",
|
||||
params = listOf(ParamDoc("keySelector")),
|
||||
returns = type("lyng.Map"),
|
||||
moduleName = "lyng.stdlib"
|
||||
moduleName = "lyng.stdlib",
|
||||
callSignature = CallSignature(
|
||||
inlineHigherOrder = CallSignature.HigherOrderInline(
|
||||
kind = CallSignature.Kind.ITERABLE,
|
||||
result = CallSignature.ResultMode.ASSOCIATE_BY
|
||||
)
|
||||
)
|
||||
) {
|
||||
val association = requireOnlyArg<Obj>()
|
||||
val result = ObjMap()
|
||||
@@ -204,7 +211,13 @@ val ObjIterable by lazy {
|
||||
doc = "Apply the lambda to each element in iteration order.",
|
||||
params = listOf(ParamDoc("action")),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
moduleName = "lyng.stdlib",
|
||||
callSignature = CallSignature(
|
||||
inlineHigherOrder = CallSignature.HigherOrderInline(
|
||||
kind = CallSignature.Kind.ITERABLE,
|
||||
result = CallSignature.ResultMode.FOR_EACH
|
||||
)
|
||||
)
|
||||
) {
|
||||
val scope = requireScope()
|
||||
val it = thisObj.invokeInstanceMethod(scope, "iterator")
|
||||
@@ -222,7 +235,13 @@ val ObjIterable by lazy {
|
||||
params = listOf(ParamDoc("transform")),
|
||||
returns = type("lyng.List"),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
moduleName = "lyng.stdlib",
|
||||
callSignature = CallSignature(
|
||||
inlineHigherOrder = CallSignature.HigherOrderInline(
|
||||
kind = CallSignature.Kind.ITERABLE,
|
||||
result = CallSignature.ResultMode.MAP
|
||||
)
|
||||
)
|
||||
) {
|
||||
val fn = requiredArg<Obj>(0)
|
||||
val result = mutableListOf<Obj>()
|
||||
@@ -238,7 +257,13 @@ val ObjIterable by lazy {
|
||||
params = listOf(ParamDoc("transform")),
|
||||
returns = type("lyng.List"),
|
||||
isOpen = true,
|
||||
moduleName = "lyng.stdlib"
|
||||
moduleName = "lyng.stdlib",
|
||||
callSignature = CallSignature(
|
||||
inlineHigherOrder = CallSignature.HigherOrderInline(
|
||||
kind = CallSignature.Kind.ITERABLE,
|
||||
result = CallSignature.ResultMode.MAP_NOT_NULL
|
||||
)
|
||||
)
|
||||
) {
|
||||
val fn = requiredArg<Obj>(0)
|
||||
val result = mutableListOf<Obj>()
|
||||
|
||||
@@ -19,6 +19,7 @@ package net.sergeych.lyng.obj
|
||||
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import net.sergeych.lyng.CallSignature
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.miniast.*
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
@@ -262,7 +263,15 @@ class ObjMap(val map: MutableMap<Obj, Obj> = mutableMapOf()) : Obj() {
|
||||
doc = "Get value by key or compute, store, and return the default from a lambda.",
|
||||
params = listOf(ParamDoc("key"), ParamDoc("default")),
|
||||
returns = type("lyng.Any"),
|
||||
moduleName = "lyng.stdlib"
|
||||
moduleName = "lyng.stdlib",
|
||||
callSignature = CallSignature(
|
||||
inlineHigherOrder = CallSignature.HigherOrderInline(
|
||||
kind = CallSignature.Kind.MAP_GET_OR_PUT,
|
||||
result = CallSignature.ResultMode.BLOCK_RESULT,
|
||||
argCount = 2,
|
||||
lambdaArgIndex = 1
|
||||
)
|
||||
)
|
||||
) {
|
||||
val key = requiredArg<Obj>(0)
|
||||
thisAs<ObjMap>().map.getOrPut(key) {
|
||||
|
||||
Reference in new issue
Block a user