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

commonMain.api.asm.asmSimpleBuilder.kt Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2021 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.api.asm

import net.akehurst.language.agl.default.GrammarTypeNamespaceFromGrammar
import net.akehurst.language.agl.default.ReferenceResolverDefault
import net.akehurst.language.agl.default.ResolveFunction
import net.akehurst.language.agl.grammar.scopes.ScopeModelAgl
import net.akehurst.language.agl.processor.IssueHolder
import net.akehurst.language.agl.syntaxAnalyser.ContextSimple
import net.akehurst.language.agl.syntaxAnalyser.ScopeSimple
import net.akehurst.language.agl.syntaxAnalyser.createReferenceLocalToScope
import net.akehurst.language.api.processor.LanguageProcessorPhase
import net.akehurst.language.typemodel.simple.TupleTypeSimple

@DslMarker
annotation class AsmSimpleBuilderMarker

fun asmSimple(scopeModel: ScopeModelAgl = ScopeModelAgl(), context: ContextSimple? = null, resolveReferences: Boolean = true, init: AsmSimpleBuilder.() -> Unit): AsmSimple {
    val b = AsmSimpleBuilder(scopeModel, context, resolveReferences)
    b.init()
    return b.build()
}

@AsmSimpleBuilderMarker
class AsmSimpleBuilder(
    private val _scopeModel: ScopeModelAgl,
    private val _context: ContextSimple?,
    private val resolveReferences: Boolean
) {

    private val _asm = AsmSimple()
    private val _scopeMap = mutableMapOf>()

    fun string(value: String) {
        _asm.addRoot(value)
    }

    fun element(typeName: String, init: AsmElementSimpleBuilder.() -> Unit): AsmElementSimple {
        val path = AsmElementPath.ROOT + (_asm.rootElements.size).toString()
        val b = AsmElementSimpleBuilder(_scopeModel, _scopeMap, this._asm, path, typeName, true, _context?.rootScope)
        b.init()
        return b.build()
    }

    fun tuple(init: AsmElementSimpleBuilder.() -> Unit): AsmElementSimple =
        element(TupleTypeSimple.NAME, init)

    fun listOfString(vararg items: String): List {
        val path = AsmElementPath.ROOT + (_asm.rootElements.size).toString()
        val list = items.asList()
        _asm.addRoot(list)
        return list
    }

    fun list(init: ListAsmElementSimpleBuilder.() -> Unit): List {
        val path = AsmElementPath.ROOT + (_asm.rootElements.size).toString()
        val b = ListAsmElementSimpleBuilder(_scopeModel, _scopeMap, this._asm, path, _context?.rootScope)
        b.init()
        val list = b.build()
        _asm.addRoot(list)
        return list
    }

//    private fun resolveReferences(issues: IssueHolder, o: Any?, locationMap: Map?, context: ScopeSimple?) {
//        when (o) {
//            is AsmElementSimple -> _scopeModel.resolveReferencesElement(issues, o, locationMap, context?.rootScope)
//            is List<*> -> o.forEach { resolveReferences(issues, it, locationMap, context) }
//        }
//    }

    fun build(): AsmSimple {
        val issues = IssueHolder(LanguageProcessorPhase.SEMANTIC_ANALYSIS)
        if (resolveReferences && null != _context) {
            val resolveFunction: ResolveFunction = { ref ->
                _asm.elementIndex[ref]
            }
            _asm.traverseDepthFirst(ReferenceResolverDefault(_scopeModel, _context.rootScope, resolveFunction, null, issues))
        }
        //       if (issues.all.isEmpty()) {
        return _asm
//        } else {
//            error("Issues building asm:\n${issues.all.joinToString(separator = "\n") { "$it" }}")
    }
    //   }
}

@AsmSimpleBuilderMarker
class AsmElementSimpleBuilder(
    private val _scopeModel: ScopeModelAgl,
    private val _scopeMap: MutableMap>,
    private val _asm: AsmSimple,
    _asmPath: AsmElementPath,
    _typeName: String,
    _isRoot: Boolean,
    _parentScope: ScopeSimple?
) {
    private val _element = _asm.createElement(_asmPath, _typeName).also {
        if (_isRoot) _asm.addRoot(it)
    }
    private val _elementScope by lazy {
        _parentScope?.let {
            if (_scopeModel.isScopeDefinition(_element.typeName)) {
                val refInParent = _scopeModel.createReferenceLocalToScope(_parentScope, _element)
                    ?: error("Trying to create child scope but cannot create a reference for $_element")
                val newScope = _parentScope.createOrGetChildScope(refInParent, _element.typeName, _element.asmPath)
                _scopeMap[_asmPath] = newScope
                newScope
            } else {
                _parentScope
            }
        }
    }

    private fun _property(name: String, value: Any?) {
        _element.setProperty(name, value, false, 0)//TODO childIndex
    }

    fun propertyUnnamedString(value: String?) = this._property(GrammarTypeNamespaceFromGrammar.UNNAMED_PRIMITIVE_PROPERTY_NAME, value)
    fun propertyString(name: String, value: String?) = this._property(name, value)
    fun propertyNull(name: String) = this._property(name, null)
    fun propertyUnnamedElement(typeName: String, init: AsmElementSimpleBuilder.() -> Unit): AsmElementSimple =
        propertyElementExplicitType(GrammarTypeNamespaceFromGrammar.UNNAMED_PRIMITIVE_PROPERTY_NAME, typeName, init)

    fun propertyTuple(name: String, init: AsmElementSimpleBuilder.() -> Unit): AsmElementSimple = propertyElementExplicitType(name, TupleTypeSimple.NAME, init)
    fun propertyElement(name: String, init: AsmElementSimpleBuilder.() -> Unit): AsmElementSimple = propertyElementExplicitType(name, name, init)
    fun propertyElementExplicitType(name: String, typeName: String, init: AsmElementSimpleBuilder.() -> Unit): AsmElementSimple {
        val newPath = _element.asmPath + name
        val b = AsmElementSimpleBuilder(_scopeModel, _scopeMap, this._asm, newPath, typeName, false, _elementScope)
        b.init()
        val el = b.build()
        this._element.setProperty(name, el, false, 0)//TODO childIndex
        return el
    }

    fun propertyUnnamedListOfString(list: List) = this._property(GrammarTypeNamespaceFromGrammar.UNNAMED_LIST_PROPERTY_NAME, list)
    fun propertyListOfString(name: String, list: List) = this._property(name, list)
    fun propertyUnnamedListOfElement(init: ListAsmElementSimpleBuilder.() -> Unit) = this.propertyListOfElement(GrammarTypeNamespaceFromGrammar.UNNAMED_LIST_PROPERTY_NAME, init)
    fun propertyListOfElement(name: String, init: ListAsmElementSimpleBuilder.() -> Unit): List {
        val newPath = _element.asmPath + name
        val b = ListAsmElementSimpleBuilder(_scopeModel, _scopeMap, this._asm, newPath, _elementScope)
        b.init()
        val list = b.build()
        this._element.setProperty(name, list, false, 0)//TODO childIndex
        return list
    }

    fun reference(name: String, elementReference: String) {
        _element.setProperty(name, elementReference, true, 0)//TODO childIndex
    }

    fun build(): AsmElementSimple {
        val es = _elementScope
        if (null == es) {
            //do nothing
        } else {
            val scopeFor = es.forTypeName
            val referablePropertyName = _scopeModel.getReferablePropertyNameFor(scopeFor, _element.typeName)
            val referableName = referablePropertyName?.let { _element.getPropertyAsStringOrNull(it) }
            if (null != referableName) {
                es.addToScope(referableName, _element.typeName, _element.asmPath)
            }
        }
        return _element
    }
}

@AsmSimpleBuilderMarker
class ListAsmElementSimpleBuilder(
    private val _scopeModel: ScopeModelAgl,
    private val _scopeMap: MutableMap>,
    private val _asm: AsmSimple,
    private val _asmPath: AsmElementPath,
    private val _parentScope: ScopeSimple?
) {

    private val _list = mutableListOf()

    fun string(value: String) {
        _list.add(value)
    }

    fun list(init: ListAsmElementSimpleBuilder.() -> Unit) {
        val newPath = _asmPath + (_list.size).toString()
        val b = ListAsmElementSimpleBuilder(_scopeModel, _scopeMap, _asm, newPath, _parentScope)
        b.init()
        val list = b.build()
        _list.add(list)
    }

    fun element(typeName: String, init: AsmElementSimpleBuilder.() -> Unit): AsmElementSimple {
        val newPath = _asmPath + (_list.size).toString()
        val b = AsmElementSimpleBuilder(_scopeModel, _scopeMap, this._asm, newPath, typeName, false, _parentScope)
        b.init()
        val el = b.build()
        _list.add(el)
        return el
    }

    fun tuple(init: AsmElementSimpleBuilder.() -> Unit): AsmElementSimple = element(TupleTypeSimple.NAME, init)


    fun build(): List {
        return this._list
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy