blob: 6d781c9b8bc1222a0faa91aa88c92f39439384c6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 CEA LIST.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Created on: 7 déc. 2011
*
* Contributors:
* Arnault Lapitre (CEA LIST) arnault.lapitre@cea.fr
* - Initial API and implementation
******************************************************************************/
#include "Routine.h"
#include <fml/common/BehavioralElement.h>
#include <fml/infrastructure/BehavioralPart.h>
#include <fml/infrastructure/Machine.h>
#include <fml/infrastructure/Variable.h>
#include <fml/expression/BuiltinArray.h>
#include <fml/operator/OperatorManager.h>
#include <fml/workflow/UniFormIdentifier.h>
namespace sep
{
/**
* CONSTRUCTOR
* Default
*/
Routine::Routine(Machine * aContainer,
const std::string & aNameID, const Modifier & aModifier,
const Specifier & aSpecifier, const BF & aModel)
: BehavioralElement( CLASS_KIND_T( Routine ) ,
aContainer, aModifier , aNameID ),
SpecifierImpl( aSpecifier ),
mModel( aModel ),
mParameters( ),
mReturns( ),
mCode( )
{
//!! NOTHING
}
Routine::Routine(const BehavioralPart & aBehavioralPart,
const std::string & aNameID, const Specifier & aSpecifier)
: BehavioralElement( CLASS_KIND_T( Routine ),
aBehavioralPart.getContainer(), aNameID ),
SpecifierImpl( aSpecifier ),
mModel( BF::REF_NULL ),
mParameters( ),
mReturns( ),
mCode( )
{
//!! NOTHING
}
Routine * Routine::newDefine(Machine * aContainer, const std::string & aNameID)
{
return( new Routine(aContainer, aNameID,
Specifier::DESIGN_MODEL_SPECIFIER) );
}
Routine * Routine::newInvoke(Machine * aContainer, const BF & aModel)
{
return( new Routine(aContainer,
aModel.as_ptr< Routine >()->getNameID(),
Specifier::DESIGN_INSTANCE_DYNAMIC_SPECIFIER, aModel) );
}
/**
* GETTER
* from vector of parameters / returns
*/
const BF & Routine::getByNameID(
const BFVector & params, const std::string & aNameID)
{
BFVector::const_iterator it = params.begin();
BFVector::const_iterator endIt = params.end();
for( ; it != endIt ; ++it )
{
if( (*it).is< Variable >() &&
((*it).to_ptr< Variable >()->getNameID() == aNameID) )
{
return( *it );
}
}
return( BF::REF_NULL );
}
avm_offset_t Routine::getOffsetByNameID(
const BFVector & params, const std::string & label)
{
BFVector::const_iterator it = params.begin();
BFVector::const_iterator endIt = params.end();
for( avm_offset_t offset ; it != endIt ; ++it , ++offset )
{
if( (*it).is< Variable >() &&
((*it).to_ptr< Variable >()->getNameID() == label) )
{
return( offset );
}
}
return( AVM_NO_OFFSET );
}
/**
* TESTER
* mParameters
* mReturns
*/
//!! Warning: Unused static function
//static bool isContained(const BFVector & params, Variable * aParam)
//{
// BFVector::const_iterator it = params.begin();
// BFVector::const_iterator endIt = params.end();
// for( avm_offset_t offset ; it != endIt ; ++it , ++offset )
// {
// if( (*it).isTEQ(aParam) )
// {
// return( true );
// }
// }
//
// return( false );
//}
bool Routine::hasParameterOffset(Variable * aParameter) const
{
return( (aParameter->getOffset() < mParameters.size()) &&
mParameters[ aParameter->getOffset() ].isTEQ(aParameter) );
}
void Routine::saveParameter(Variable * anInput)
{
mParameters.append( BF(anInput) );
}
bool Routine::hasReturnOffset(Variable * aReturn) const
{
return( (aReturn->getOffset() < mReturns.size()) &&
mReturns[ aReturn->getOffset() ].isTEQ(aReturn) );
}
void Routine::saveReturn(Variable * anOutput)
{
mReturns.append( BF(anOutput) );
}
/**
* MACRO
* INLINING
*/
BFCode Routine::inlineCode(const BFCode & aCode) const
{
if( aCode->isOpCode( AVM_OPCODE_RETURN ) )
{
return( BFCode::REF_NULL );
}
else
{
BFCode newCode( aCode->getOperator() );
BF substArg;
AvmCode::const_iterator itArg = aCode->begin();
AvmCode::const_iterator itEndArg = aCode->end();
for( ; itArg != itEndArg ; ++itArg )
{
if( (substArg = inlineCode(*itArg)).valid() )
{
newCode->append( substArg );
}
else
{
return( BFCode::REF_NULL );
}
}
return( newCode );
}
}
BF Routine::inlineCode(const BF & aCode) const
{
switch( aCode.classKind() )
{
case FORM_AVMCODE_KIND:
{
return( inlineCode( aCode.bfCode() ) );
}
case FORM_XFSP_VARIABLE_KIND:
{
Variable * aVar = aCode.to_ptr< Variable >();
if( getModel()->hasParameterOffset( aVar ) )
{
if( (aVar->getOffset() < mParameters.size()) &&
mParameters[ aVar->getOffset() ].valid() )
{
return( mParameters[ aVar->getOffset() ] );
}
else if( aVar->hasValue() )
{
return( aVar->getValue() );
}
else if( aVar->getModifier().hasNatureMacro()
&& aVar->hasBinding() )
{
return( aVar->getBinding() );
}
return( BFCode::REF_NULL );
}
else if( getModel()->hasReturnOffset( aVar ) )
{
if( (aVar->getOffset() < mReturns.size()) &&
mReturns[ aVar->getOffset() ].valid() )
{
return( mReturns[ aVar->getOffset() ] );
}
else if( aVar->hasValue() )
{
return( aVar->getValue() );
}
else if( aVar->getModifier().hasNatureMacro()
&& aVar->hasBinding() )
{
return( aVar->getBinding() );
}
return( BFCode::REF_NULL );
}
return( aCode );
}
case FORM_UFI_KIND:
{
UniFormIdentifier * anUFI = aCode.to_ptr< UniFormIdentifier >();
UniFormIdentifier::ListOfField::const_iterator itField = anUFI->begin();
UniFormIdentifier::ListOfField::const_iterator endField = anUFI->end();
BF newCode;
BF substArg;
if( (substArg = inlineCode(*itField)).valid() )
{
if( substArg.is< UniFormIdentifier >() )
{
newCode = anUFI = new UniFormIdentifier(
substArg.to_ref< UniFormIdentifier >() );
}
else
{
newCode = anUFI = new UniFormIdentifier(anUFI->getLocator());
anUFI->appendField( substArg , (*itField).getScheme() );
}
for( ++itField ; itField != endField ; ++itField )
{
if( (substArg = inlineCode(*itField)).valid() )
{
anUFI->appendField( substArg , (*itField).getScheme() );
}
else
{
return( BFCode::REF_NULL );
}
}
return( newCode );
}
else
{
return( BFCode::REF_NULL );
}
}
case FORM_ARRAY_BF_KIND:
{
ArrayBF * arrayIn = aCode.to_ptr< ArrayBF >();
ArrayBF * arrayOut = new ArrayBF(
arrayIn->getTypeSpecifier(), arrayIn->size());
BF newCode( arrayOut );
BF substArg;
for( avm_size_t idx = 0 ; idx < arrayIn->size() ; ++idx )
{
if( (substArg = inlineCode(arrayIn->at(idx))).valid() )
{
arrayOut->set(idx, substArg);
}
else
{
return( BFCode::REF_NULL );
}
}
return( newCode );
}
default:
{
return( aCode );
}
}
return( aCode );
}
/**
* Serialization
*/
void Routine::strParameters(OutStream & os, const std::string & sep) const
{
BFVector::const_iterator it = mParameters.begin();
BFVector::const_iterator endIt = mParameters.end();
os << "(";
if( (*it).is< Variable >() )
{
os << "$" << (*it).to_ptr< Variable >()->getOffset() << ": ";
(*it).to_ptr< Variable >()->strParameter(os);
}
else
{
os << (*it).str();
}
for( ++it ; it != endIt ; ++it )
{
os << ", ";
if( (*it).is< Variable >() )
{
os << "$" << (*it).to_ptr< Variable >()->getOffset() << ": ";
(*it).to_ptr< Variable >()->strParameter(os);
}
else
{
os << (*it).str();
}
}
os << ")";
}
void Routine::strReturns(OutStream & os, const std::string & sep) const
{
BFVector::const_iterator it = mReturns.begin();
BFVector::const_iterator endIt = mReturns.end();
os << "(";
if( (*it).is< Variable >() )
{
os << "$" << (*it).to_ptr< Variable >()->getOffset() << ": ";
(*it).to_ptr< Variable >()->strReturn(os);
}
else
{
os << (*it).str();
}
for( ++it ; it != endIt ; ++it )
{
os << ", ";
if( (*it).is< Variable >() )
{
os << "$" << (*it).to_ptr< Variable >()->getOffset() << ": ";
(*it).to_ptr< Variable >()->strReturn(os);
}
else
{
os << (*it).str();
}
}
os << ")";
}
void Routine::strHeader(OutStream & os) const
{
os << getModifier().toString();
if( getSpecifier().isDesignPrototypeStatic() )
{
os << getSpecifier().toString_not(
Specifier::DESIGN_PROTOTYPE_STATIC_KIND) << "@";
}
else
{
os << getSpecifier().toString() << "routine ";
}
os << getNameID();
if( mParameters.nonempty() )
{
strParameters(os);
}
if( mReturns.nonempty() )
{
os << " --> ";
strReturns(os);
}
}
void Routine::toStream(OutStream & os) const
{
strHeader( os << TAB );
os << "{";
if( mCode.valid() )
{
mCode->toStreamRoutine( os << INCR_INDENT ) << DECR_INDENT_TAB;
}
os << "}" << EOL_FLUSH;
}
void Routine::strInvokeParameters(OutStream & os, const std::string & sep) const
{
BFVector::const_iterator it = mParameters.begin();
BFVector::const_iterator endIt = mParameters.end();
os << "(";
AvmCode::toStream(os, *it);
for( ++it ; it != endIt ; ++it )
{
os << ", ";
AvmCode::toStream(os, *it);
}
os << ")";
}
void Routine::strInvokeReturns(OutStream & os, const std::string & sep) const
{
BFVector::const_iterator it = mReturns.begin();
BFVector::const_iterator endIt = mReturns.end();
os << "(";
AvmCode::toStream(os, *it);
for( ++it ; it != endIt ; ++it )
{
os << ", ";
AvmCode::toStream(os, *it);
}
os << ")";
}
void Routine::toStreamInvoke(OutStream & os, const std::string & sep) const
{
os << TAB << getNameID() << AVM_NO_INDENT;
if( mParameters.nonempty() )
{
strInvokeParameters(os, sep);
}
else
{
os << "()";
}
if( mReturns.nonempty() )
{
os << " --> ";
strInvokeReturns(os, sep);
}
AVM_DEBUG_REF_COUNTER(os);
os << END_INDENT << EOL_FLUSH;
}
} /* namespace sep */