All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.agl.syntaxAnalyser.SyntaxAnalyserSimpleAbstract.kt Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2020 Dr. David H. Akehurst (http://dr.david.h.akehurst.net)
 *
 * 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.akehurst.language.agl.syntaxAnalyser

import net.akehurst.language.agl.api.runtime.Rule
import net.akehurst.language.agl.collections.toSeparatedList
import net.akehurst.language.agl.runtime.structure.RulePosition
import net.akehurst.language.agl.runtime.structure.RuntimeRule
import net.akehurst.language.agl.runtime.structure.RuntimeRuleRhsEmbedded
import net.akehurst.language.agl.runtime.structure.RuntimeRuleRhsListSeparated
import net.akehurst.language.agl.sppt.TreeDataComplete
import net.akehurst.language.agl.util.Debug
import net.akehurst.language.api.analyser.ScopeModel
import net.akehurst.language.api.asm.AsmElementPath
import net.akehurst.language.api.asm.AsmElementSimple
import net.akehurst.language.api.asm.AsmSimple
import net.akehurst.language.api.grammar.GrammarItem
import net.akehurst.language.api.grammarTypeModel.GrammarTypeNamespace
import net.akehurst.language.api.processor.LanguageIssue
import net.akehurst.language.api.processor.SentenceContext
import net.akehurst.language.api.sppt.*
import net.akehurst.language.collections.mutableStackOf
import net.akehurst.language.typemodel.api.*
import net.akehurst.language.typemodel.simple.SimpleTypeModelStdLib

data class NodeTypes(
    val forNode: TypeInstance,
    val forChildren: TypeInstance
) {
    constructor(t: TypeInstance) : this(t, t)
}

data class DownData(
    val path: AsmElementPath,
    val typeUse: NodeTypes
)

data class ChildData(
    val nodeInfo: SpptDataNodeInfo,
    val value: Any?
)

/**
 * TypeName <=> RuleName
 *
 * @param scopeDefinition TypeNameDefiningScope -> Map
 * @param references ReferencingTypeName, referencingPropertyName  -> ??
 */
abstract class SyntaxAnalyserSimpleAbstract(
    val grammarNamespaceQualifiedName: String,
    val typeModel: TypeModel,
    val scopeModel: ScopeModel
) : SyntaxAnalyserFromTreeDataAbstract() {

    companion object {
        private const val ns = "net.akehurst.language.agl.syntaxAnalyser"
        const val CONFIGURATION_KEY_AGL_SCOPE_MODEL = "$ns.scope.model"

        val PropertyDeclaration.isTheSingleProperty get() = this.owner.property.size == 1

        val Rule.hasOnyOneRhsItem get() = this.rhsItems.size == 1 && this.rhsItems[0].size == 1
    }

    private var _asm: AsmSimple? = null
    override val asm: A get() = _asm as A

    private fun findTypeUsageForRule(ruleName: String): TypeInstance? {
        val ns = this.typeModel.namespace[grammarNamespaceQualifiedName] as GrammarTypeNamespace?
        return ns?.findTypeUsageForRule(ruleName)
    }

    override fun clear() {
        super.clear()
        this._asm = null
    }

    override fun configure(configurationContext: SentenceContext, configuration: Map): List {
        return emptyList()
    }

    override fun walkTree(sentence: Sentence, treeData: TreeDataComplete, skipDataAsTree: Boolean) {
        val syntaxAnalyserStack = mutableStackOf(this)
        val downStack = mutableStackOf() //when null don't use branch
        val stack = mutableStackOf()
        val walker = object : SpptWalker {
            var isRoot = true
            override fun beginTree() {
                // use same asm for all embedded trees
                // otherwise need to combine and adjust indexes
                // faster to use same asm in first place
                syntaxAnalyserStack.peek().setAsm(_asm ?: AsmSimple())
                isRoot = true
            }

            override fun endTree() {
                val root = stack.pop()
                syntaxAnalyserStack.peek().addAsmRoot(root.value!!)
                //do not pop the asm, leave it here, so it can be retrieved when wanted.
                // embedded ASMs are popped in endEmbedded
            }

            override fun leaf(nodeInfo: SpptDataNodeInfo) {
                val value = syntaxAnalyserStack.peek().createValueFromLeaf(sentence, nodeInfo)
                stack.push(ChildData(nodeInfo, value))
            }

            override fun beginBranch(nodeInfo: SpptDataNodeInfo) {
                val parentDownData = downStack.peekOrNull()
                val p = when {
                    downStack.isEmpty -> AsmElementPath.ROOT + (asm.rootElements.size).toString()
                    null == parentDownData -> AsmElementPath.ROOT.plus("")  // property unused
                    isRoot -> parentDownData.path
                    else -> syntaxAnalyserStack.peek().pathFor(parentDownData.path, parentDownData.typeUse.forChildren.type, nodeInfo)
                }
                val tu = when {
                    isRoot -> {
                        isRoot = false
                        val typeUse = syntaxAnalyserStack.peek().findTypeUsageForRule(nodeInfo.node.rule.tag)
                            ?: error("Type not found for ${nodeInfo.node.rule.tag}")
                        typeUse
                    }

                    else -> syntaxAnalyserStack.peek().typeForNode(parentDownData?.typeUse?.forChildren, nodeInfo)
                }
                val ddcomp = resolveCompressed(p, tu, nodeInfo)
                downStack.push(ddcomp)
            }

            override fun endBranch(nodeInfo: SpptDataNodeInfo) {
                val opt = nodeInfo.alt.option
                val numChildren = nodeInfo.numChildrenAlternatives[opt]!!
                val children = stack.pop(numChildren)
                val adjChildren = children.reversed()
                val downData = downStack.pop()
                val value = when {
                    typeModel.NothingType == downData.typeUse.forNode.type -> null //branch not used for element property value, push null for correct num children on stack
                    else -> syntaxAnalyserStack.peek().createValueFromBranch(sentence, downData, nodeInfo, adjChildren)
                }
                value?.let { locationMap[it] = sentence.locationFor(nodeInfo.node) }
                stack.push(ChildData(nodeInfo, value))
                // path = path.parent!!
            }

            override fun beginEmbedded(nodeInfo: SpptDataNodeInfo) {
                val embeddedRhs = (nodeInfo.node.rule as RuntimeRule).rhs as RuntimeRuleRhsEmbedded
                val embRuleName = embeddedRhs.embeddedStartRule.tag
                val embGrmName = embeddedRhs.embeddedRuntimeRuleSet.qualifiedName
                val embSyntaxAnalyser = embeddedSyntaxAnalyser[embGrmName] as SyntaxAnalyserSimpleAbstract?
                    ?: error("Embedded SyntaxAnalyser not found for '$embGrmName' in SyntaxAnalyser for '${grammarNamespaceQualifiedName}'")
                syntaxAnalyserStack.push(embSyntaxAnalyser)
                val parentDownData = downStack.peek()!!
                val p = syntaxAnalyserStack.peek().pathFor(parentDownData.path, parentDownData.typeUse.forChildren.type, nodeInfo)
                val tu = syntaxAnalyserStack.peek().findTypeUsageForRule(embRuleName)
                    ?: error("Type not found for $embRuleName")
                val dd = resolveCompressed(p, tu, nodeInfo)
                downStack.push(dd)
            }

            override fun endEmbedded(nodeInfo: SpptDataNodeInfo) {
                val embSyntaxAnalyser = syntaxAnalyserStack.pop()
                val embeddedAsm = embSyntaxAnalyser._asm!!
                downStack.pop()
                val value = embeddedAsm.rootElements.last()
                removeAsmRoot(value)
                value?.let { locationMap[it] = sentence.locationFor(nodeInfo.node) }
                stack.push(ChildData(nodeInfo, value))
            }

            override fun skip(startPosition: Int, nextInputPosition: Int) {
                // do nothing
            }

            override fun error(msg: String, path: () -> List) {
                issues.error(null, "Error 'msg' at '${path().joinToString(separator = "/")}'")
            }

        }
        treeData.traverseTreeDepthFirst(walker, false)
    }

    private fun setAsm(value: AsmSimple) {
        this._asm = value
    }

    private fun addAsmRoot(value: Any) {
        this._asm!!.addRoot(value)
    }

    private fun removeAsmRoot(value: Any) {
        this._asm!!.removeRoot(value)
    }

    private fun createAsmElement(path: AsmElementPath, name: String): AsmElementSimple =
        this._asm!!.createElement(path, name)

    private fun pathFor(parentPath: AsmElementPath, parentType: TypeDefinition, nodeInfo: SpptDataNodeInfo): AsmElementPath {
        return when (parentType) {
            is PrimitiveType -> parentPath
            is UnnamedSuperTypeType -> parentPath
            is CollectionType -> parentPath.plus(nodeInfo.child.index.toString())
            is TupleType -> {
                val prop = parentType.getPropertyByIndex(nodeInfo.child.propertyIndex)
                prop?.let { parentPath.plus(prop.name) } ?: parentPath.plus("")
            }

            is DataType -> {
                when {
                    parentType.subtypes.isNotEmpty() -> parentPath
                    else -> {
                        val prop = parentType.getPropertyByIndex(nodeInfo.child.propertyIndex)
                        prop?.let { parentPath.plus(prop.name) } ?: parentPath.plus("")
                    }
                }
            }

            else -> when (parentType) {

                typeModel.NothingType -> parentPath.plus("")
                typeModel.AnyType -> TODO()
                else -> error("Should not happen")
            }
        }
    }

    private fun typeForNode(parentTypeUsage: TypeInstance?, nodeInfo: SpptDataNodeInfo): TypeInstance {
        return when {
            null == parentTypeUsage -> typeModel.NothingType.instance() // property unused
            parentTypeUsage.isNullable -> typeForParentOptional(parentTypeUsage, nodeInfo)
            nodeInfo.node.rule.isEmbedded -> typeForEmbedded(parentTypeUsage, nodeInfo)
            else -> {
                val parentType = parentTypeUsage.type
                when (parentType) {
                    is PrimitiveType -> parentTypeUsage
                    is UnnamedSuperTypeType -> typeForParentUnnamedSuperType(parentTypeUsage, nodeInfo)
                    is CollectionType -> when (parentType) {
                        SimpleTypeModelStdLib.List -> typeForParentListSimple(parentTypeUsage, nodeInfo)
                        SimpleTypeModelStdLib.ListSeparated -> typeForParentListSeparated(parentTypeUsage, nodeInfo)
                        else -> error("Should not happen")
                    }

                    is TupleType -> typeForParentTuple(parentType, nodeInfo)
                    is DataType -> typeForParentElement(parentType, nodeInfo)
                    else -> when (parentType) {
                        typeModel.NothingType -> typeModel.NothingType.instance()
                        typeModel.AnyType -> TODO()
                        else -> error("Shold not happen")
                    }
                }
            }
        }
    }

    private fun typeForParentOptional(parentTypeUsage: TypeInstance, nodeInfo: SpptDataNodeInfo): TypeInstance {
        // nodes map to runtime-rules, not user-rules
        // if user-rule only had one optional item, then runtime-rule is 'compressed, i.e. no pseudo rule for the option
        if (Debug.CHECK) check(parentTypeUsage.isNullable)
        return parentTypeUsage.notNullable()
    }

    private fun typeForEmbedded(parentTypeUsage: TypeInstance, nodeInfo: SpptDataNodeInfo): TypeInstance {
        // need to skip over the embedded node and use type of its child
        if (Debug.CHECK) check(nodeInfo.node.rule.isEmbedded)
        val type = parentTypeUsage.type
        return when (type) {
            is DataType -> {
                val prop = type.getPropertyByIndex(nodeInfo.child.propertyIndex)
                prop?.typeInstance ?: typeModel.NothingType.instance()
            }

            else -> parentTypeUsage
        }
    }

    private fun typeForParentListSimple(parentTypeUsage: TypeInstance, nodeInfo: SpptDataNodeInfo): TypeInstance {
        // nodes map to runtime-rules, not user-rules
        // if user-rule only had one list item, then runtime-rule is 'compressed, i.e. no pseudo rule for the list
        if (Debug.CHECK) check(parentTypeUsage.type == SimpleTypeModelStdLib.List)
        val itemTypeUse = parentTypeUsage.typeArguments[0]
        return itemTypeUse
    }

    private fun typeForParentListSeparated(parentTypeUsage: TypeInstance, nodeInfo: SpptDataNodeInfo): TypeInstance {
        // nodes map to runtime-rules, not user-rules
        // if user-rule only had one slist item, then runtime-rule is 'compressed, i.e. no pseudo rule for the slist
        if (Debug.CHECK) check(parentTypeUsage.type == SimpleTypeModelStdLib.ListSeparated)
        val index = nodeInfo.child.index % 2
        val childTypeUse = parentTypeUsage.typeArguments[index]
        return childTypeUse
    }

    private fun typeForParentUnnamedSuperType(parentTypeUsage: TypeInstance, nodeInfo: SpptDataNodeInfo): TypeInstance {
        if (Debug.CHECK) check(parentTypeUsage.isNullable)
        val tu = (parentTypeUsage.type as UnnamedSuperTypeType).subtypes[nodeInfo.parentAlt.option]
        return tu
    }

    private fun typeForParentTuple(parentType: TupleType, nodeInfo: SpptDataNodeInfo): TypeInstance {
        val prop = parentType.getPropertyByIndex(nodeInfo.child.propertyIndex)
        return typeForProperty(prop, nodeInfo)
    }

    private fun typeForParentElement(parentType: DataType, nodeInfo: SpptDataNodeInfo): TypeInstance {
        return when {
            parentType.subtypes.isNotEmpty() -> {
                val t = parentType.subtypes[nodeInfo.parentAlt.option]
                return t
            }

            else -> {
                val prop = parentType.getPropertyByIndex(nodeInfo.child.propertyIndex)
                typeForProperty(prop, nodeInfo)
            }
        }
    }

    private fun resolveElementSubtype(typeUse: TypeInstance, nodeInfo: SpptDataNodeInfo): TypeInstance {
        val type = typeUse.type
        return when {
            type is DataType && type.subtypes.isNotEmpty() -> {
                val t = type.subtypes[nodeInfo.alt.option]
                t
            }

            else -> typeUse
        }
    }

    private fun typeForProperty(prop: PropertyDeclaration?, nodeInfo: SpptDataNodeInfo): TypeInstance {
        return when {
            null == prop -> typeModel.NothingType.instance() // property unused
            prop.typeInstance.isNullable -> prop.typeInstance//typeForOptional(propTypeUse, nodeInfo)
            else -> {
                val propType = prop.typeInstance.type
                when (propType) {
                    is PrimitiveType -> (prop.typeInstance)
                    is UnnamedSuperTypeType -> {
                        val tu = resolveUnnamedSuperTypeSubtype(prop.typeInstance, nodeInfo)
                        when (tu.type) {
                            is TupleType -> (tu)
                            else -> (prop.typeInstance)
                        }
                        //NodeTypes(tu)
                        //NodeTypes(prop.typeUse)//typeForUnnamedSuperType(propTypeUse, nodeInfo)
                    }

                    is CollectionType -> (prop.typeInstance)
                    is TupleType -> (prop.typeInstance)
                    is DataType -> (prop.typeInstance)
                    else -> when (propType) {
                        typeModel.NothingType -> typeModel.NothingType.instance()
                        typeModel.AnyType -> TODO()
                        else -> error("Should not happen")
                    }
                }
            }
        }
    }

    private fun resolveCompressed(p: AsmElementPath, typeUsage: TypeInstance, nodeInfo: SpptDataNodeInfo): DownData {
        val type = typeUsage.type
        return when {
            type is StructuredType && nodeInfo.node.rule.isOptional && nodeInfo.node.rule.hasOnyOneRhsItem && nodeInfo.node.rule.rhsItems[0][0].isTerminal -> {
                DownData(p, NodeTypes(typeUsage, SimpleTypeModelStdLib.String))
            }

            type is DataType && type.property.size == 1 -> {
                // special cases where PT is compressed for lists (and optionals)
                when {
                    type.property.values.first().typeInstance.isNullable -> {
                        val fProp = type.property.values.first()
                        val pp = p.plus(fProp.name)
                        DownData(pp, NodeTypes(typeUsage, fProp.typeInstance))
                    }

                    nodeInfo.node.rule.isOptional -> DownData(p, NodeTypes(typeUsage))
                    nodeInfo.node.rule.isList -> {
                        val fProp = type.property.values.first()
                        val pp = p.plus(fProp.name)
                        DownData(pp, NodeTypes(typeUsage, fProp.typeInstance))
                    }

                    else -> DownData(p, NodeTypes(typeUsage))
                }
            }

            type is UnnamedSuperTypeType -> when {
                // special cases where PT is compressed for choice of concats
                nodeInfo.node.rule.isChoice -> when {
                    type.subtypes[nodeInfo.alt.option].type is TupleType -> DownData(p, NodeTypes(typeUsage, type.subtypes[nodeInfo.alt.option]))
                    else -> DownData(p, NodeTypes(typeUsage))
                }

                else -> DownData(p, NodeTypes(typeUsage))
            }

            else -> DownData(p, NodeTypes(typeUsage))
        }
    }

    private fun resolveUnnamedSuperTypeSubtype(typeUse: TypeInstance, nodeInfo: SpptDataNodeInfo): TypeInstance {
        val type = typeUse.type
        return when {
            type is UnnamedSuperTypeType -> when {
                nodeInfo.node.rule.isChoice && type.subtypes.isNotEmpty() -> {
                    val t = type.subtypes[nodeInfo.alt.option]
                    t
                }

                else -> typeUse
            }

            else -> typeUse
        }
    }

    private fun createValueFromLeaf(sentence: Sentence, target: SpptDataNodeInfo): String? = when {
        target.node.rule.isEmptyTerminal -> null
        else -> sentence.matchedTextNoSkip(target.node)
    }

    private fun createValueFromBranch(sentence: Sentence, downData: DownData, target: SpptDataNodeInfo, children: List): Any? {
        val targetType = findTypeUsageForRule(target.node.rule.tag)

        return when {
            //target.node.rule.isOptional && null == targetType -> {
            //    val child = children[0]
            //    child.value
            //}
            downData.typeUse.forNode.isNullable && target.node.rule.isOptional -> {
                val child = children[0]
                when {
                    null == child.value -> null
                    else -> {
                        val nonOptChildren = listOf(ChildData(child.nodeInfo, child.value))
                        child.value
                    }
                }
            }

            target.node.rule.isEmbedded -> children[0].value
            else -> {
                val type = downData.typeUse.forNode.type
                when (type) {
                    is PrimitiveType -> {
                        createStringValueFromBranch(sentence, target)
                    }

                    is UnnamedSuperTypeType -> {
                        val actualType = type.subtypes[target.alt.option].type
                        when (actualType) {
                            is TupleType -> createValueFor(sentence, actualType, downData.path, ChildData(target, children))
                            else -> children[0].value
                        }

                    }

                    is CollectionType -> when (type) {

                        SimpleTypeModelStdLib.List -> {
                            when {
                                null != targetType && targetType.type != SimpleTypeModelStdLib.List && targetType.type is DataType -> {
                                    val propValue = when {
                                        target.node.rule.isListSeparated -> createListSimpleValueFromBranch(
                                            target,
                                            downData.path,
                                            children.map { it.value },
                                            type
                                        ).toSeparatedList().items

                                        else -> createListSimpleValueFromBranch(target, downData.path, children.map { it.value }, type)
                                    }
                                    val propDecl = (targetType.type as DataType).property.values.first()
                                    val el = createAsmElement(downData.path, targetType.type.name)
                                    setPropertyOrReferenceFromDeclaration(el, propDecl, propValue)
                                    el
                                }

                                else -> createListSimpleValueFromBranch(target, downData.path, children.map { it.value }, type)
                            }
                        }

                        SimpleTypeModelStdLib.ListSeparated -> {
                            when {
                                null != targetType && targetType.type != SimpleTypeModelStdLib.ListSeparated && targetType.type is DataType -> {
                                    val propValue = createListSeparatedValueFromBranch(target, downData.path, children.map { it.value }, type)
                                    val propDecl = (targetType.type as DataType).property.values.first()
                                    val el = createAsmElement(downData.path, targetType.type.name)
                                    setPropertyOrReferenceFromDeclaration(el, propDecl, propValue)
                                    el
                                }

                                else -> createListSeparatedValueFromBranch(target, downData.path, children.map { it.value }, type)
                            }
                        }

                        else -> error("Should not happen")
                    }

                    is TupleType -> {
                        createTupleFrom(sentence, type, downData.path, ChildData(target, children))
                    }

                    is DataType -> {
                        if (type.subtypes.isNotEmpty()) {
                            if (Debug.CHECK) check(1 == children.size)
                            children[0].value
                        } else {
                            val el = createAsmElement(downData.path, type.name)
                            for (propDecl in type.property.values) {
                                val propType = propDecl.typeInstance.type
                                val propValue: Any? = when (propType) {
                                    is PrimitiveType -> {
                                        val childData = children[propDecl.index]
                                        createStringValueFromBranch(sentence, childData.nodeInfo)
                                    }

                                    is CollectionType -> when (propType) {
                                        SimpleTypeModelStdLib.List -> {
                                            when {
                                                target.node.rule.isListSimple && target.node.option == RulePosition.OPTION_MULTI_EMPTY -> emptyList()
                                                target.node.rule.isList -> createList(target, children.map { it.value })
                                                else -> {
                                                    val childData = children[propDecl.index]
                                                    when {
                                                        childData.nodeInfo.node.rule.isList -> when {
                                                            null == childData.value -> emptyList()
                                                            childData.value is List<*> -> createList(childData.nodeInfo, childData.value as List)
                                                            childData.value is AsmElementSimple -> childData.value.properties.values.first().value as List
                                                            else -> listOf(childData.value)
                                                        }

                                                        else -> error("Internal Error: cannot create a ListSimple from '$childData'")
                                                    }
                                                }
                                            }
                                        }

                                        SimpleTypeModelStdLib.ListSeparated -> {
                                            val childData = children[propDecl.index]
                                            when {
                                                childData.nodeInfo.node.rule.isEmptyTerminal -> emptyList()
                                                target.node.rule.isList -> children.map { it.value }.toSeparatedList()
                                                childData.nodeInfo.node.rule.isList -> when {
                                                    childData.value is List<*> -> childData.value
                                                    childData.value is AsmElementSimple -> childData.value.properties.values.first().value as List
                                                    else -> TODO()
                                                }

                                                else -> error("Internal Error: cannot create a ListSeparated from '$childData'")
                                            }
                                        }

                                        else -> error("Should not happen")
                                    }

                                    else -> {
                                        val childData = children[propDecl.index]
                                        childData.value
                                    }
                                }
                                setPropertyOrReferenceFromDeclaration(el, propDecl, propValue)
                            }
                            el
                        }
                    }

                    else -> when (type) {
                        typeModel.NothingType -> error("Internal Error: items should not have type 'NothingType'")
                        typeModel.AnyType -> {
                            TODO()
                            /*
                    val actualType = this.findTypeForRule(target.name) ?: error("Internal Error: cannot find actual type for ${target.name}")
                    when (actualType.type) {
                        is AnyType -> {// when {
                            //must be a choice in a group
                            val choice = _mapToGrammar(target.runtimeRuleSetNumber, target.runtimeRuleNumber) as Choice
                            when (choice.alternative.size) {
                                1 -> {
                                    val ch = target.children[0]
                                    val childType = this.findTypeForRule(ch.name) ?: error("Internal Error: cannot find type for ${ch.name}")
                                    val chPath = path
                                    //val childsScope = scope
                                    createValue(ch, chPath, childType)//, childsScope)
                                }

                                else -> {
                                    TODO()
                                }
                            }
                            //else -> error("Internal Error: cannot find actual type for ${target.name}")
                        }

                        else -> createValue(target, path, actualType)//, scope)
                    }
                     */
                        }

                        else -> error("Shold not happen")
                    }
                }
            }
        }
    }

    private fun createValueFor(sentence: Sentence, type: TypeDefinition, path: AsmElementPath, childData: ChildData): Any? = when (type) {
        is PrimitiveType -> createStringValueFromBranch(sentence, childData.nodeInfo)
        is UnnamedSuperTypeType -> TODO()
        is CollectionType -> TODO()
        is TupleType -> createTupleFrom(sentence, type, path, childData)
        is DataType -> createElementFrom(sentence, type, path, childData.value as List)
        else -> when (type) {
            typeModel.NothingType -> TODO()
            typeModel.AnyType -> TODO()
            else -> error("Shold not happen")
        }
    }

    private fun createStringValueFromBranch(sentence: Sentence, target: SpptDataNodeInfo): String? = when {
        target.node.startPosition == target.node.nextInputNoSkip -> null
        else -> sentence.matchedTextNoSkip(target.node)
    }

    private fun createList(nodeData: SpptDataNodeInfo, list: List): List {
        return when {
            nodeData.node.rule.isListSimple -> list
            nodeData.node.rule.isListSeparated -> {
                val rhs = (nodeData.node.rule as RuntimeRule).rhs as RuntimeRuleRhsListSeparated
                when {
                    rhs.separatorRhsItem.isTerminal -> list.toSeparatedList().items
                    else -> list.toSeparatedList().separators
                }
            }

            else -> error("Internal error: List kind not handled")
        }
    }

    private fun createListSimpleValueFromBranch(target: SpptDataNodeInfo, path: AsmElementPath, children: List, type: TypeDefinition): List<*> {
        if (Debug.CHECK) check(type == SimpleTypeModelStdLib.List)
        return when {
            target.node.rule.isEmptyTerminal -> emptyList()
            target.node.rule.isList -> children.filterNotNull()
            else -> error("Internal Error: cannot create a List from '$target'")
        }
    }

    private fun createListSeparatedValueFromBranch(target: SpptDataNodeInfo, path: AsmElementPath, children: List, type: TypeDefinition): List<*> {
        if (Debug.CHECK) check(type == SimpleTypeModelStdLib.ListSeparated)
        return when {
            target.node.rule.isEmptyTerminal -> emptyList()
            target.node.rule.isList -> {
                val sList = children.toSeparatedList()
                sList
            }

            else -> error("Internal Error: cannot create a List from '$target'")
        }
    }

    private fun createTupleFrom(sentence: Sentence, type: TupleType, path: AsmElementPath, childData: ChildData): AsmElementSimple {
        val el = createAsmElement(path, type.name) // TODO: should have a createTuple method
        val v = childData.value
        for (propDecl in type.property.values) {
            val propType = propDecl.typeInstance
            when (v) {
                is List<*> -> {
                    val propChildData = (childData.value as List)[propDecl.index]
                    val propValue = propChildData.value //createValueFor(sentence, propType.type, path, propChildData)
                    setPropertyOrReferenceFromDeclaration(el, propDecl, propValue)
                }

                else -> TODO()
            }


        }
        return el
    }

    private fun createElementFrom(sentence: Sentence, type: DataType, path: AsmElementPath, children: List) {
        if (type.subtypes.isNotEmpty()) {
            if (Debug.CHECK) check(1 == children.size)
            //if (Debug.CHECK) {
            //var actualType: ElementType = type
            // while (actualType.subtypes.isNotEmpty()) {
            //     actualType = actualType.subtypes[actualTarget.option]
            // }
            // check(1 == children.size)
            // }
            children[0].value
        } else {
            val el = createAsmElement(path, type.name)
            for (propDecl in type.property.values) {
                val propPath = path + propDecl.name
                val propType = propDecl.typeInstance.type
                val childData = children[propDecl.index]
                val propValue: Any? = when (propType) {
                    is PrimitiveType -> {
                        createStringValueFromBranch(sentence, childData.nodeInfo)
                    }

                    is CollectionType -> when (propType) {
                        SimpleTypeModelStdLib.List -> {
                            when {
                                childData.nodeInfo.node.rule.isEmptyTerminal -> emptyList()
//                            target.rule.isList -> children.map { it.value }
                                childData.nodeInfo.node.rule.isList -> when {
                                    childData.value is List<*> -> childData.value
                                    childData.value is AsmElementSimple -> childData.value.properties.values.first().value as List

                                    else -> TODO()
                                }

                                else -> error("Internal Error: cannot create a List from '$childData'")
                            }
                        }

                        SimpleTypeModelStdLib.ListSeparated -> {
                            TODO()
                            // val listNode = when {
                            //     actualTarget.isList -> actualTarget
                            //     else -> actualTarget.asBranch.nonSkipChildren[propDecl.childIndex]
                            // }
                            // createListSeparatedValueFromBranch(listNode, path, propType)
                        }

                        else -> error("Should not happen")
                    }

                    is TupleType -> createTupleFrom(sentence, propType, path, childData)

                    is UnnamedSuperTypeType -> {
                        val actualType = propType.subtypes[childData.nodeInfo.parentAlt.option].type
                        when (actualType) {
                            is TupleType -> createTupleFrom(sentence, actualType as TupleType, path, childData)
                            else -> {
                                TODO()
                            }
                        }

                    }

                    else -> children[propDecl.index]
                }
                setPropertyOrReferenceFromDeclaration(el, propDecl, propValue)
            }
            el
        }
    }

    private fun isReference(el: AsmElementSimple, name: String): Boolean {
        return scopeModel?.isReference(el.typeName, name) ?: false
    }

    private fun setPropertyOrReferenceFromDeclaration(el: AsmElementSimple, declaration: PropertyDeclaration, value: Any?) {
        val isRef = this.isReference(el, declaration.name)
        when {
            isRef -> el.setPropertyFromDeclaration(declaration, value, true)
            else -> el.setPropertyFromDeclaration(declaration, value, false)
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy