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

src.org.kiama.util.Environments.scala Maven / Gradle / Ivy

/*
 * This file is part of Kiama.
 *
 * Copyright (C) 2012 Anthony M Sloane, Macquarie University.
 *
 * Kiama is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * Kiama is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Kiama.  (See files COPYING and COPYING.LESSER.)  If not, see
 * .
 */

package org.kiama
package util

import scala.collection.immutable.{HashMap, Stack}

/**
 * General implementation of environments as stacked scopes.  The objects
 * associated with names in environments are of type Entity.
 */
trait Environments {

    /**
     * An entity that represents some program object.
     */
    abstract class Entity

    /**
     * Reset the environment module.
     */
    def resetEnvironments {
        Named.resetCount
    }

    /**
     * Static support for entity names.
     */
    object Named {

        /**
         * Count of the named things that have been produced so far.
         */
        var count = 0

        /**
         * Reset the entity count.
         */
        def resetCount {
            count = 0
        }

    }

    /**
     * Support for unique ids for named things.
     */
    trait Named {

        import Named.count

        /**
         * The underlying name of this thing.
         */
        def ident : String

        /**
         * A unique number to represent this thing.
         */
        private val num = {
            count = count + 1
            count
        }

        /**
         * A unique identifier for this thing, incorporating the underlying
         * name and its unique number.
         */
        val id = ident + num

        /**
         * Still print named things as their underlying name.
         */
        override def toString = ident

    }

    /**
     * A named entity.
     */
    trait NamedEntity extends Entity with Named

    /**
     * An entity that represents an error situation.  These entities are
     * usually accepted in most situations to avoid cascade errors.
     */
    trait ErrorEntity extends Entity
    
    /**
     * A entity represented by names for whom we have seen more than one
     * declaration so we are unsure what is being represented.
     */
    case object MultipleEntity extends ErrorEntity {
        lazy val ident = "multiple"
    }

    /**
     * An unknown entity, represented by names whose declarations are missing.
     */
    case object UnknownEntity extends ErrorEntity {
        lazy val ident = "unknown"
    }

    /**
     * A scope maps identifiers to entities.
     */
    type Scope = Map[String,Entity]

    /**
     * An environment is a stack of scopes with the innermost scope on the top.
     */
    type Environment = Stack[Scope]
    
    /**
     * Create a root environment, i.e., one that has a single scope containing
     * the given bindings.
     */
    def rootenv (bindings : (String,Entity)*) : Environment =
        Stack (HashMap (bindings : _*))
    
    /**
     * Enter a new empty scope nested within the given environment.
     */
    def enter (env : Environment) : Environment =
        env.push (new HashMap[String,Entity])

    /**
     * Leave the outermost scope of the given environment, raising an error if
     * the environment is empty.
     */
    def leave (env : Environment) : Environment =
        if (env.isEmpty)
            sys.error ("leave called on empty environment")
        else
            env.pop

    /**
     * Define i to be e in the current scope of env, raising an error if the
     * environment is empty.
     */
    def define (env : Environment, i : String, e : Entity) : Environment = {
        if (env.isEmpty)
            sys.error ("define called on empty environment")
        else {
            val s = env.top
            env.pop.push (s + ((i, e)))
        }
    }

    /**
     * Say whether i is defined in the current scope of env.
     */
    def isDefinedInScope (env : Environment, i : String) : Boolean =
        !(env.isEmpty) && ((env.top) contains i)

    /**
     * Say whether i is defined in the given scope.
     */
    def isDefinedInScope (scope : Scope, i : String) : Boolean =
        scope contains i

    /**
     * Say whether i is defined in any scope of env.
     */
    def isDefinedInEnv (env : Environment, i : String) : Boolean =
        env.exists (s => isDefinedInScope (s, i))

    /**
     * Say whether i is defined in an innermost scope of env (i.e., in the 
     * current scope).
     */
    def isDefinedInInner (env : Environment, i : String) : Boolean =
        isDefinedInScope (env.top, i)

    /**
     * Say whether i is defined in an outer scope of env (i.e., not in the 
     * current scope).
     */
    def isDefinedInOuter (env : Environment, i : String) : Boolean =
        isDefinedInEnv (env.pop, i)

    /**
     * Look up i in env, returning the mapped Entity if there is one, otherwise
     * return e.  If scope is true, just search the innermost scope, otherwise
     * search outwards in all scopes, returning the first Entity found, if any.
     */
    def lookup (env : Environment, i : String, e : Entity, scope : Boolean = false) : Entity = {

        def lookupscope (s : Scope) : Entity =
            s.getOrElse (i, e)

        if (env.isEmpty)
            e
        else if (scope)
            lookupscope (env.top)
        else {
            for (s <- env)
                if (s contains i)
                    return s (i)
            e
        }
        
    }    

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy