blob: 6a5073921f9c9399edb7782601603dc8c0dcf818 [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: 12 avr. 2011
*
* Contributors:
* Arnault Lapitre (CEA LIST) arnault.lapitre@cea.fr
* - Initial API and implementation
******************************************************************************/
#include "AvmcodeInvokeCompiler.h"
#include <parser/model/ParserUtil.h>
#include <fml/executable/AvmLambda.h>
#include <fml/executable/AvmProgram.h>
#include <fml/executable/AvmTransition.h>
#include <fml/executable/ExecutableForm.h>
#include <fml/expression/AvmCode.h>
#include <fml/expression/ExpressionConstructor.h>
#include <fml/expression/StatementConstructor.h>
#include <fml/lib/AvmOperationFactory.h>
#include <fml/operator/OperatorManager.h>
#include <fml/infrastructure/Machine.h>
namespace sep
{
////////////////////////////////////////////////////////////////////////////////
// AVMCODE INVOKE NEW INSTANCE COMPILATION
////////////////////////////////////////////////////////////////////////////////
BF AvmcodeInvokeNewCompiler::compileExpression(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
return( AbstractAvmcodeCompiler::compileExpressionCode(aCTX, aCode) );
//[REGRESSION]!TODO
// return( compileStatement(aCTX, aCode) );
}
BF AvmcodeInvokeNewCompiler::optimizeExpression(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
//[REGRESSION]!TODO
// BFCode newCode = optimizeStatement(aCTX, aCode);
//
// newCode->getInstruction()->setMainBytecode(
// /*context */ AVM_ARG_RETURN_CTX,
// /*processor*/ AVM_ARG_MEMORY_MACHINE_CPU,
// /*operation*/ AVM_ARG_SEVAL_RVALUE,
// /*operand */ AVM_ARG_EXPRESSION_KIND,
// /*dtype */ newCode->getInstruction()->at(0).dtype);
//
// return( aCode );
BFCode optimizedCode( aCode->getOperator() );
AvmCode::const_iterator it = aCode->begin();
AvmCode::const_iterator endIt = aCode->end();
AvmInstruction * argsInstruction =
optimizedCode->newInstruction( aCode->size() );
InstanceOfMachine * dynamicInstance = NULL;
BF arg = (*it);
optimizedCode->append( arg );
if( arg.is< InstanceOfMachine >() )
{
dynamicInstance = arg.to_ptr< InstanceOfMachine >();
argsInstruction->at(0).set(
/*context */ AVM_ARG_ARGUMENT_CTX,
/*processor*/ AVM_ARG_NOP_CPU,
/*operation*/ AVM_ARG_NOP_RVALUE,
/*operand */ AVM_ARG_MACHINE_RID,
/*type */ dynamicInstance->getTypeSpecifier()
);
}
else
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "optimizeStatement :> Unexpected << " << str_header( arg )
<< " >> as invoke#new first argument in << "
<< aCode->str() << " >> !!!" << std::endl;
return( aCode );
}
avm_size_t paramCount = dynamicInstance->getParamCount();
for( avm_size_t offset = 1 ;
(++it != endIt) && (offset <= paramCount) ; ++offset )
{
arg = AVMCODE_COMPILER.decode_optimizeExpression(aCTX, (*it));
optimizedCode->append( arg );
argsInstruction->at(offset).dtype =
dynamicInstance->getParamType( offset-1 );
setArgcodeRValue(aCTX, argsInstruction->at(offset), arg);
}
argsInstruction->computeMainBytecode(
/*context */ AVM_ARG_ARGUMENT_CTX,
/*processor*/ AVM_ARG_MEMORY_MACHINE_CPU,
/*operation*/ AVM_ARG_SEVAL_RVALUE,
/*operand */ AVM_ARG_EXPRESSION_KIND);
return( optimizedCode );
}
BFCode AvmcodeInvokeNewCompiler::compileStatement(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
if( aCode->size() != 1 )
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "Unexpected INVOKE#NEW without only one runnable "
"#dynamic instance machine !!!"
<< std::endl << aCode.toString()
<< SEND_EXIT;
}
BFCode newCode = AbstractAvmcodeCompiler::compileExpressionCode(aCTX, aCode);
const BF & arg = newCode->first();
if( arg.is< InstanceOfMachine >() )
{
if( arg.to_ptr< InstanceOfMachine >()->
getSpecifier().isDesignInstanceDynamic() )
{
//!![MIGRATION]: see Compiler::precompileExecutableInstanceDynamique(...)
// modelMachine->incrPossibleDynamicInstanciationCount(1);
}
else
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "Unexpected INVOKE#NEW with one runnable "
"#dynamic instance machine !!!"
<< std::endl << newCode.toString()
<< SEND_EXIT;
}
}
else
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "Unexpected INVOKE#NEW without one "
"runnable #dynamic #instance machine !!!"
<< std::endl << newCode.toString()
<< SEND_EXIT;
}
return( newCode );
}
BFCode AvmcodeInvokeNewCompiler::optimizeStatement(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
const BF & arg = aCode->first();
if( arg.is< InstanceOfMachine >()
&& arg.to_ptr< InstanceOfMachine >()->
getSpecifier().isDesignInstanceDynamic() )
{
AvmInstruction * argsInstruction = aCode->newInstruction( aCode->size() );
InstanceOfMachine * dynamicInstance = arg.to_ptr< InstanceOfMachine >();
argsInstruction->at(0).set(
/*context */ AVM_ARG_ARGUMENT_CTX,
/*processor*/ AVM_ARG_NOP_CPU,
/*operation*/ AVM_ARG_NOP_RVALUE,
/*operand */ AVM_ARG_MACHINE_RID,
/*type */ dynamicInstance->getTypeSpecifier()
);
argsInstruction->setMainBytecode(
/*context */ AVM_ARG_STANDARD_CTX,
/*processor*/ AVM_ARG_NOPS_CPU,
/*operation*/ AVM_ARG_NOPS_RVALUE,
/*operand */ AVM_ARG_STATEMENT_KIND,
/*dtype */ argsInstruction->at(0).dtype);
}
else
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "optimizeStatement: Unexpected statement << invoke#new >> "
"argument !!!\n\t" << str_header( arg )
<< std::endl << to_stream( aCode ) << std::endl;
return( aCode );
}
return( aCode );
}
////////////////////////////////////////////////////////////////////////////////
// AVMCODE INVOKE ROUTINE COMPILATION
////////////////////////////////////////////////////////////////////////////////
BF AvmcodeInvokeRoutineCompiler::compileExpression(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
return( compileStatement(aCTX, aCode) );
}
BFCode AvmcodeInvokeRoutineCompiler::compileStatement(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
// if( aCode->singleton && aCode->first().is< Routine >() )
// {
// return( ParserUtil::invokeRoutineExpression(
// aCode->first().to_ptr< Routine >() ) );
// }
// else
if( aCode->size() < 2 )
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "Expected invokable expression like "
"(: form invokable ...) << " << aCode.str() << " >>"
<< std::endl << std::endl;
return( AbstractAvmcodeCompiler::compileStatement(aCTX, aCode) );
}
BFCode newCode;
BF arg = AVMCODE_COMPILER.decode_compileStatement(aCTX, aCode->first());
if( arg.invalid() )
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "AvmCode< statement > compilation error << (: "
<< aCode->first().str() << " ...) >>"
<< std::endl << std::endl;
return( aCode );
}
if( aCode->second().is< Operator >() )
{
newCode = StatementConstructor::newCode(
aCode->second().to_ptr< Operator >(), arg);
}
else if( aCode->second().isIdentifier() )
{
Operator * op = AvmOperationFactory::get(arg,
aCode->second().toIdentifier());
if( op != NULL )
{
newCode = StatementConstructor::newCode(op, arg);
}
else
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "AvmCode< statement > compilation error << (: "
<< arg.str() << " " << aCode->second().str() << " ...) >>"
<< std::endl << std::endl;
return( aCode );
}
}
AvmCode::iterator itArg = aCode->begin() + 2;
AvmCode::iterator itEndArg = aCode->end();
for( ; itArg != itEndArg ; ++itArg )
{
arg = AVMCODE_COMPILER.decode_compileStatement(aCTX, *itArg);
if( arg.valid() )
{
newCode->append( arg );
}
else
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "AvmCode< statement > compilation error << "
<< (*itArg).str() << " >>"
<< std::endl << std::endl;
newCode->append( *itArg );
continue;
}
}
return( newCode );
}
////////////////////////////////////////////////////////////////////////////////
// AVMCODE INVOKE TRANSITION COMPILATION
////////////////////////////////////////////////////////////////////////////////
BFCode AvmcodeInvokeTransitionCompiler::compileStatement(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
if( aCode->size() != 1 )
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "Unexpected more than one argument for invoke#transition << "
<< aCode.str() << " >>"
<< std::endl << std::endl;
return( AbstractAvmcodeCompiler::compileStatement(aCTX, aCode) );
}
BF arg = AVMCODE_COMPILER.decode_compileStatement(aCTX, aCode->first());
if( arg.invalid() || arg.isnot< AvmTransition >() )
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "AvmCode< statement > compilation error << (: "
<< aCode->first().str() << " ...) >>"
<< std::endl << std::endl;
return( aCode );
}
return( StatementConstructor::newCode(aCode->getOperator(), arg) );
}
////////////////////////////////////////////////////////////////////////////////
// AVMCODE INVOKE METHOD COMPILATION
////////////////////////////////////////////////////////////////////////////////
BF AvmcodeInvokeMethodCompiler::compileExpression(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
if( aCode->size() < 2 )
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "Expected invokable expression like (: form invokable ...) << "
<< aCode.str() << " >>"
<< std::endl << std::endl;
return( AbstractAvmcodeCompiler::compileExpression(aCTX, aCode) );
}
BFCode newCode;
BF arg = AVMCODE_COMPILER.decode_compileExpression(aCTX, aCode->first());
if( arg.invalid() )
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "AvmCode< statement > compilation error << (: "
<< aCode->first().str() << " ...) >>"
<< std::endl << std::endl;
return( aCode );
}
if( aCode->second().is< Operator >() )
{
newCode = StatementConstructor::newCode(
aCode->second().to_ptr< Operator >(), arg);
}
else if( aCode->second().isIdentifier() )
{
Operator * op = AvmOperationFactory::get(arg,
aCode->second().toIdentifier());
if( op != NULL )
{
newCode = StatementConstructor::newCode(op, arg);
}
else
{
// TypeManager::get
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "AvmCode< statement > compilation error << (: "
<< arg.str() << " " << aCode->second().str() << " ...) >>"
<< std::endl << std::endl;
return( aCode );
}
}
AvmCode::iterator itArg = aCode->begin() + 2;
AvmCode::iterator itEndArg = aCode->end();
for( ; itArg != itEndArg ; ++itArg )
{
arg = AVMCODE_COMPILER.decode_compileExpression(aCTX, *itArg);
if( arg.valid() )
{
newCode->append( arg );
}
else
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "AvmCode< statement > compilation error << "
<< (*itArg).str() << " >>"
<< std::endl << std::endl;
newCode->append( *itArg );
continue;
}
}
return( AVMCODE_COMPILER.compileExpression(aCTX, newCode) );
}
BFCode AvmcodeInvokeMethodCompiler::compileStatement(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
if( aCode->size() < 2 )
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "Expected invokable expression like "
"(: form invokable ...) << " << aCode.str() << " >>"
<< std::endl << std::endl;
return( AbstractAvmcodeCompiler::compileStatement(aCTX, aCode) );
}
BFCode newCode;
BF arg = AVMCODE_COMPILER.decode_compileExpression(aCTX, aCode->first());
if( arg.invalid() )
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "AvmCode< statement > compilation error << (: "
<< aCode->first().str() << " ...) >>"
<< std::endl << std::endl;
return( aCode );
}
if( aCode->second().is< Operator >() )
{
newCode = StatementConstructor::newCode(
aCode->second().to_ptr< Operator >(), arg);
}
else if( aCode->second().isIdentifier() )
{
Operator * op = AvmOperationFactory::get(arg,
aCode->second().toIdentifier());
if( op != NULL )
{
newCode = StatementConstructor::newCode(op, arg);
}
else
{
// TypeManager::get
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "AvmCode< statement > compilation error << (: "
<< arg.str() << " " << aCode->second().str() << " ...) >>"
<< std::endl << std::endl;
return( aCode );
}
}
AvmCode::iterator itArg = aCode->begin() + 2;
AvmCode::iterator itEndArg = aCode->end();
for( ; itArg != itEndArg ; ++itArg )
{
arg = AVMCODE_COMPILER.decode_compileExpression(aCTX, *itArg);
if( arg.valid() )
{
newCode->append( arg );
}
else
{
getCompilerTable().incrErrorCount();
aCTX->errorContext( AVM_OS_WARN )
<< "AvmCode< statement > compilation error << "
<< (*itArg).str() << " >>"
<< std::endl << std::endl;
newCode->append( *itArg );
continue;
}
}
return( AVMCODE_COMPILER.compileStatement(aCTX, newCode) );
}
////////////////////////////////////////////////////////////////////////////////
// AVMCODE INVOKE PROGRAM COMPILATION
////////////////////////////////////////////////////////////////////////////////
BF AvmcodeInvokeProgramCompiler::compileExpression(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
return( compileStatement(aCTX, aCode) );
}
BFCode AvmcodeInvokeProgramCompiler::compileStatement(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
return( AbstractAvmcodeCompiler::compileStatement(aCTX, aCode) );
}
////////////////////////////////////////////////////////////////////////////////
// AVMCODE INVOKE FUNCTION COMPILATION
////////////////////////////////////////////////////////////////////////////////
BF AvmcodeInvokeFunctionCompiler::compileExpression(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
return( compileStatement(aCTX, aCode) );
}
BFCode AvmcodeInvokeFunctionCompiler::compileStatement(
COMPILE_CONTEXT * aCTX, const BFCode & aCode)
{
return( AbstractAvmcodeCompiler::compileStatement(aCTX, aCode) );
}
}