// Copyright (c) 1995  David Engberg  All rights reserved
// $Id: VariableDeclaration.C,v 1.6 1997/08/21 16:30:12 geppetto Exp $
#include "VariableDeclaration.h"
#include "Expression.h"
#include "CompileError.h"
#include "JavaMethodInfo.h"
#include "JavaClassFile.h"
#include "Compiler.h"
#include "BinaryExpression.h"
#include "CompileContext.h"

//
//  Method name : CVariableDeclaration
//  Description : Default constructor.
//
CVariableDeclaration::CVariableDeclaration()
  : fInitializer(0),
    fFinal(false)
{
}

//
//  Method name : CVariableDeclaration
//  Description : Constructs a variable declaration out of its name, type, and
//    optional initializer.
//
CVariableDeclaration::CVariableDeclaration(const CJavaTypeSignature& type,
 	         const unicode_string& name, CExpression* adoptInitializer,
		 bool final)
  : fSignature(type, name),
    fInitializer(adoptInitializer),
    fFinal(final)
{
}

//
//  Method name : CVariableDeclaration
//  Description : Copy constructor.
//
CVariableDeclaration::CVariableDeclaration(const CVariableDeclaration& source)
  : fSignature(source.fSignature),
    fInitializer(0),
    fFinal(source.fFinal)
{
  if (source.fInitializer != 0) {
    fInitializer = source.fInitializer->Clone();
  }
}

//
//  Method name : ~CVariableDeclaration
//  Description : Destructor
//
CVariableDeclaration::~CVariableDeclaration()
{
  delete fInitializer;
}

//
//  Method name : GetType
//  Description : Returns the type of this variable.
//
CJavaTypeSignature
CVariableDeclaration::GetType() const
{
  return fSignature.GetType();
}

//
//  Method name : SetType
//  Description : Sets the type of this variable.
//
void
CVariableDeclaration::SetType(const CJavaTypeSignature& type)
{
  fSignature = CJavaFieldSignature(type, fSignature.GetFieldName());
}

//
//  Method name : GenerateCode
//  Description : Appends the generated bytecode for this statement onto the
//    code parameter, using the other parameters to help get the
//    needed information.  In addition, the 'stackUsed' parameter is set to
//    the maximum expression stack depth incurred by this statement.
//    If this operation is successful, 0 is returned, otherwise a compile
//    error structure is created and returned to the caller to explain what
//    went wrong.
//
CCompileError*
CVariableDeclaration::GenerateCode(CCodeSequence& code,
		 CCompileContext& context, const CJavaAccessFlags& modifiers,
		 unsigned short& stackUsed)
{
  CCompileError* error = 0;
  CJavaTypeSignature type;
  stackUsed = 0;
  if (fInitializer != 0) {
    error = CExpression::EvaluateType(fInitializer, context, type);
    if (error == 0) {
      bool skipFinalConstant = false;
      if (context.GetCompiler().InClassInitializers() &&
	  modifiers.fFinal != 0) {
	CExpression* constantExpression = 0;
	error = GetConstantValue(constantExpression, context);
	if (constantExpression != 0) {
	  delete constantExpression;
	  skipFinalConstant = true;
	}
      }
      if (!skipFinalConstant && error == 0) {
	error =
	  fInitializer->GenerateCode(code, context, stackUsed, true);
      }
    }
  }
  return error;
}

//
//  Method name : GetConstantValue
//  Description : This method is used to try to extract a constant literal
//    value associated with this variable declaration's initializer.  If
//    no initializer exists, or if the initializer can't be resolved to
//    a constant value, then the intoPointer is set to 0, otherwise it is
//    filled with the appropriate constant value.
//    If a problem occurs during assesment, an error is created and returned
//    to the caller, otherwise 0 is returned.
//
CCompileError*
CVariableDeclaration::GetConstantValue(CExpression*& intoPointer,
				       CCompileContext& context)
{
  CCompileError* error = 0;
  intoPointer = 0;
  if (fInitializer != 0) {
    CJavaTypeSignature type;
    error =
      CExpression::EvaluateType(fInitializer, context, type, false);
    CBinaryExpression* initializer =
      DYNAMIC_CAST(CBinaryExpression, fInitializer);
    if (initializer != 0 && error == 0) {
      const CExpression* initializerValue = initializer->GetRightArgument();
      assert(initializerValue != 0);
      error = initializerValue->CreateConstantExpression(intoPointer, context);
    }
  }
  return error;
}

//
//  Method name : SetFinal
//  Description : Specifies whether this variable is final or not. 
//
void
CVariableDeclaration::SetFinal(bool final)
{
  fFinal = final;
}

//
//  Method name : GetName
//  Description : Spits out the name of this declared field.
//
unicode_string
CVariableDeclaration::GetName() const
{
  return fSignature.GetFieldName();
}
