// Copyright (c) 1996-2002 Brian D. Carlstrom

package bdc.scheme.expression;

import bdc.scheme.Environment;
import bdc.scheme.Stack;
import bdc.scheme.VariableArray;
import bdc.scheme.compiler.CompileTimeEnvironment;
import bdc.util.FastStringBuffer;

public class Lambda extends Expression
{
    public CompileTimeEnvironment compileTimeEnvironment;
    public VariableArray          variables;
    public Expression[]           body;

    public int frameSize;
    public int localSize;

    public Lambda (CompileTimeEnvironment compileTimeEnvironment,
                   Begin                  body)
    {
        this.compileTimeEnvironment = compileTimeEnvironment;
        this.variables              = compileTimeEnvironment.variables();
        this.body                   = body.expressions;

        /*
            Count the arguments and local variables that are to be put
            in the frame
        */
        for (int i = 0; i < variables.inUse; i++) {
            if (variables.array()[i].heap) {
                variables.heap++;
            }
        }

        /*
            Count the true locals that are to be put on the stack
        */
        for (int i = variables.arguments; i < variables.inUse; i++) {
            if (!variables.array()[i].heap) {
                variables.local++;
            }
        }
    }

    public Object eval (Environment environment, Stack stack)
    {
        return new Compound(this, environment);
    }

    /**
        Fixup the body in our own compileTimeEnvironment
    */
    public Expression fixupVariables (CompileTimeEnvironment environment)
    {
            // recur with our environment, not the parent passed in one
        Begin.fixupVariables(body, compileTimeEnvironment);
        return this;
    }

    public String toString ()
    {
        FastStringBuffer result = new FastStringBuffer("(lambda (");
        for (int i = 0; i < variables.inUse; i++) {
            result.append(variables.array[i].toString());
            if (i+1 < variables.inUse) {
                result.append(' ');
            }
        }
        result.append(") ");
        result.append(Begin.backtrace(body));
        result.append(')');
        return result.toString();
    }
}
