// Copyright (c) 1996-2002 Brian D. Carlstrom

package bdc.scheme;

import bdc.scheme.expression.LexicalAddress;

/**
    Environments are used to represent the run time lexical environments.
*/
public final class Environment
{
    /**
        The enclosing lexical environment
    */
    public Environment enclosing;

    /**
        The variables in this environment for debugging purposes
    */
    public VariableArray variables;

    /**
        The values of variables in this environment
    */
    public Object[] values;

    /**
        private constructor for Environments
        public interface is via extend below
    */
    private Environment (Environment   enclosing,
                         VariableArray variables,
                         Object        values[])
    {
        this.enclosing = enclosing;
        this.variables = variables;
        this.values    = values;
    }

    /**
        Extend environment with variables and values to create a new one.

        This is static because environment can be null in the top
        level case of the global environment.
    */
    public static Environment extend (Environment   environment,
                                      VariableArray variables,
                                      Object        values[]) {
        return new Environment(environment, variables, values);
    }

    /**
        Return a value by doing a lookup on the lexical environment.

        The LexicalAddress was computed at compile time from the
        CompileTimeEnvironment. The address specifies a number of
        frames to go up and the index in the frame at that location.
    */
    public Object lexicalAddressLookup (LexicalAddress lexicalAddress)
      throws SchemeException
    {
        Environment environment = this;
        int frame = lexicalAddress.frame;
        while (frame != 0) {
            environment = environment.enclosing;
            frame--;
        }
        return environment.values[lexicalAddress.displacement];
    }

    /**
        Set a value by doing a lookup on the lexical environment.

        The LexicalAddress was computed at compile time from the
        CompileTimeEnvironment. The address specifies a number of
        frames to go up and the index in the frame at that location.
    */
    public void lexicalAddressSet (LexicalAddress lexicalAddress,
                                   Object object)
    {
        Environment environment = this;
        int frame = lexicalAddress.frame;
        while (frame != 0) {
            environment = environment.enclosing;
            frame--;
        }
        environment.values[lexicalAddress.displacement] = object;
    }
}
