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

commonMain.org.luaj.vm2.ast.NameResolver.kt Maven / Gradle / Ivy

package org.luaj.vm2.ast

import org.luaj.vm2.LuaValue
import org.luaj.vm2.ast.Exp.Constant
import org.luaj.vm2.ast.Exp.NameExp
import org.luaj.vm2.ast.Exp.VarExp
import org.luaj.vm2.ast.Stat.Assign
import org.luaj.vm2.ast.Stat.FuncDef
import org.luaj.vm2.ast.Stat.GenericFor
import org.luaj.vm2.ast.Stat.LocalAssign
import org.luaj.vm2.ast.Stat.LocalFuncDef
import org.luaj.vm2.ast.Stat.NumericFor

/**
 * Visitor that resolves names to scopes.
 * Each Name is resolved to a NamedVarible, possibly in a NameScope
 * if it is a local, or in no named scope if it is a global.
 */
class NameResolver : Visitor() {

    private var scope: NameScope? = null

    private fun pushScope() {
        scope = NameScope(scope)
    }

    private fun popScope() {
        scope = scope!!.outerScope
    }

    override fun visit(scope: NameScope?) {}

    override fun visit(block: Block) {
        pushScope()
        block.scope = scope
        super.visit(block)
        popScope()
    }

    override fun visit(body: FuncBody) {
        pushScope()
        scope!!.functionNestingCount++
        body.scope = scope
        super.visit(body)
        popScope()
    }

    override fun visit(stat: LocalFuncDef) {
        defineLocalVar(stat.name)
        super.visit(stat)
    }

    override fun visit(stat: NumericFor) {
        pushScope()
        stat.scope = scope
        defineLocalVar(stat.name)
        super.visit(stat)
        popScope()
    }

    override fun visit(stat: GenericFor) {
        pushScope()
        stat.scope = scope
        defineLocalVars(stat.names)
        super.visit(stat)
        popScope()
    }

    override fun visit(exp: NameExp) {
        exp.name.variable = resolveNameReference(exp.name)
        super.visit(exp)
    }

    override fun visit(stat: FuncDef) {
        stat.name.name.variable = resolveNameReference(stat.name.name)
        stat.name.name.variable!!.hasassignments = true
        super.visit(stat)
    }

    override fun visit(stat: Assign) {
        super.visit(stat)
        var i = 0
        val n = stat.vars.size
        while (i < n) {
            val v = stat.vars[i] as VarExp
            v.markHasAssignment()
            i++
        }
    }

    override fun visit(stat: LocalAssign) {
        visitExps(stat.values)
        defineLocalVars(stat.names)
        val n = stat.names.size
        val m = if (stat.values != null) stat.values.size else 0
        val isvarlist = m > 0 && m < n && (stat.values!![m - 1] as Exp).isvarargexp()
        run {
            var i = 0
            while (i < n && i < if (isvarlist) m - 1 else m) {
                if (stat.values!![i] is Constant)
                    (stat.names[i] as Name).variable!!.initialValue = (stat.values!![i] as Constant).value
                i++
            }
        }
        if (!isvarlist)
            for (i in m until n)
                (stat.names[i] as Name).variable!!.initialValue = LuaValue.NIL
    }

    override fun visit(pars: ParList) {
        if (pars.names != null)
            defineLocalVars(pars.names)
        if (pars.isvararg)
            scope!!.define("arg")
        super.visit(pars)
    }

    protected fun defineLocalVars(names: List) {
        var i = 0
        val n = names.size
        while (i < n) {
            defineLocalVar(names[i])
            i++
        }
    }

    protected fun defineLocalVar(name: Name) {
        name.variable = scope!!.define(name.name)
    }

    protected fun resolveNameReference(name: Name): Variable {
        val v = scope!!.find(name.name)
        if (v.isLocal && scope!!.functionNestingCount != v.definingScope!!.functionNestingCount)
            v.isupvalue = true
        return v
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy