/*  interp2.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
// Declare an object
/*  All Rights Reserved                    */

#include "baseio.h"
#include "hrdarth.h"
#include "newaloc.h"
#include "usercom.h"
#include "interp.h"
#include "lexhead.h"
#include "intfc.h"
#include "prsdrv.h"
#include "yacintfc.h"
#include "array.h"
#include "outtok.h"
#include "cgidbg.h"
#include "user.h"


static void DeclPtErr(const char * err)
{
	DbgError("Constructor",err);
} 

// Declare an object with parameters
static struct ValueType * Constructor(struct ValueType* Type,
	struct ValueType* Obj)
{
	if (State.IsError()) return 0 ;
	if (!Obj || !Type) DeclPtErr ("NULL") ;

	// Parser insures second object is not declared already

	// Check to see of Type has a parameter list
	if (Type->Class != DoDeclEntity) DbgError("Constructor", "bad type");
	InteractiveEntity * ThisEntity = Type->Declared.EntityClass ;
	UserEntity *  NewDeclaredEntity = ThisEntity->Declare(Obj) ;
	// Match consistency of parameters - prompt user to
	// supply missing parameters or ones that fails consistency
	// check
	// Do the actual declaration by appending object to appropraite
	// list
	if (!NewDeclaredEntity) {
		State.Error("declaration error");
		return 0;
	}
	State.DoingThis("Declared ",NewDeclaredEntity->GetName(), " as ",
		ThisEntity->GetClassName());
	// TestAlloc("after said declared");
	MakeDeclaredEntity(NewDeclaredEntity,ThisEntity) ;
	// TestAlloc("after make entity");
	/*
	* ValueType*temp=new ValueType(DecDspPP,0,DeclEntity,NewDeclaredEntity);
	* temp->ValueDefined=1;
	*/
	return NewDeclaredEntity->GetValue() ;
	
	
}

static void AllocateIfNeeded(ValueType& Val)
{
	if (!IsAllocationNeeded(Val.Type)) return ;
	Val.Value.ValBuiltInClass= DeclareObjectArray(Val.Type,1);
}


struct ValueType * Declare(struct ValueType* Type,struct ValueType* ObjTar,
	int ArraySize)
{
	// LogOut << "Declare\n" ;
	if (NoExecute()) return 0 ;
	for (;;) {
		if (State.IsError()) break ;
		if (!ObjTar || !Type) DeclPtErr ("NULL") ;

		// Check to see if first object is an entity and
		// call special routine for this
		if (Type->Class == DoDeclEntity) return Constructor(Type,ObjTar);
		// Check to make sure second object is not declared already
		if (ObjTar->Type != DecName) ObjTar = AlreadyDeclared(ObjTar);
		if (State.IsError()) return 0 ;
		if (!ObjTar) {
			State.SetError();
			break ;
		}
		for(;;) {
/*
 *			LogOut << "Before check in use \n" ;
 *			LogOut << "Checking name:" << ObjTar->Value.ValName
 *				<< "\n" ;
 */
			NameInUse InUse = AllEntityLists->
				CheckNameInUse(ObjTar->Value.ValName);
			// LogOut << "After check in use \n" ;
			if (InUse == InUseNo) break ;
			delete ObjTar ;
			ObjTar = 0;
			OutputType channel = OutputPrompt ;
			if (!State.IsInteractive()) channel = OutputCppHelp ;
			*Output + channel << "Name `" <<
				ObjTar->Value.ValName
				<< "' is used for " << InUseString[InUse]
				<< "\n" ;
			
			const char * Buf = CondGetName(
				"another name or RETURN", "illegal name");
			if (!Buf) break ;
			ObjTar = new ValueType(DecName,Buf) ;
		}
		if (State.IsError()) break ;
		// Declare object
		if (!Type) DeclPtErr("NULL 1");
	switch (Type->Class) {
case DeclNot:
case DeclEntity :
case DeclBasic :
			DbgError("Declare","invalid type first operand");	
case DoDeclEntity :
			DbgError("Declare","expecting basic object"); 
case DoDeclBasic :
			break;
		}
		if (State.IsError()) break ;
		UserBasicObjects * TheClass = Type->Declared.BasicClass ;
		// Get the class that this object is declared from
		if (!TheClass) DeclPtErr("NULL obj 1");
	
		SimpleUserObject * Simp = Type->Value.Obj ;
		// Get the partialy made up entry for this object that will
		// be added to the declaration list

		// Get the actual value for the object
		ValueType * RetVal = Simp->GetValue() ;
		if (!ArraySize) AllocateIfNeeded(*RetVal);

		RetVal->Class = DeclBasic ;
		// Set the field to indicate a declared object

		Simp->SetName(ObjTar->Value.ValName);
		// Transfer the object name to the declaration entry

		TheClass->ObjectAppend(Simp) ;
		// Declare the object by adding it to the declaration list

		RetVal->Declared.Basic = Simp ;
		// Set this field to be the declaration entry for the object
	
		State.DoingThis("Declared ",ObjTar->Value.ValName, " as ",
			Simp->GetTypeName());
		// Tell the user what we are doing

		ObjTar->Value.ValName=0; // don't delete this

		// clean up storage
		// delete ObjTar ;
		Type->Value.Obj = 0; // cannot delete this!!
		// delete Type ;
	
		return RetVal ;
	}
	// Error exit 
	Type->Value.Obj = 0; // cannot delete this!!
	// delete Type ;
	return 0;
}

static void BadPtr(const char * msg)
{
	DbgError("CommaDeclare",msg);
}

InteractiveEntity * GetIntEntFromObj(ValueType * Obj)
{
/*
 *	LogOut << "Obj->Class = " << Obj->Class << "\n" ;
 *	LogOut << "Obj->Declared.EntityClass = " <<
 *		hex((long) Obj->Declared.EntityClass) << "\n" ;
 */
	if (Obj->Class != DoDeclEntity) return 0;
	return Obj->Declared.EntityClass ;
}


ValueType * GetTypeFromObj(ValueType * Obj)
{
	InteractiveEntity * IntEnt = GetIntEntFromObj(Obj) ;
	if (!IntEnt) return 0;
	return IntEnt->GetValue() ;
}

ValueType * CommaDeclare(ValueType* Prev,ValueType* Curr)
{
// multiple declared values separated with a ,
// make the first parameter like that needed for Declare then call Declare
	if (NoExecute()) return 0 ;
	if (!Prev) BadPtr("Prev");
	if (Prev->Class == DeclBasic) {
		if (!Prev->Declared.Basic) BadPtr("Prev:Declared");
		if (!Prev->Declared.Basic->GetTypeName())
			BadPtr("Prev:Declared:TypeName");
		ValueType * Type =
			CheckDeclarator(Prev->Declared.Basic->GetTypeName());
		if (!Type) BadPtr("Bad declare");
		ValueType * RetVal = Declare (Type,Curr);
		return RetVal ;
	} else if (Prev->Type == DecEnt) {
/*
 *		if (!Prev->Value.ValEnt) BadPtr("Prev:Val.Ent");
 *		const char * LastName = Prev->Value.ValEnt->GetName();
 *		if (!LastName) BadPtr("Prev:Declared:Entity Name");
 *
 *		ValueType * Type = AllEntityLists->GetType(LastName);
 */
		ValueType * Type = GetTypeFromObj(Prev) ;
		if (!Type) BadPtr("Bad Entity Type") ;
		ValueType * RetVal = Declare(Type,Curr) ;
		return RetVal ;
	} else BadPtr("Prev:Class") ;
	return 0 ;
}

ValueType * CheckDeclarator(const char * name)
{
	return AllEntityLists->CheckDeclarator( name) ;
}

ValueType * CheckDeclared(const char * name)
{
	return AllEntityLists->CheckDeclaration( name) ;
}

