summaryrefslogtreecommitdiffstats
path: root/languages/cpp/cppevaluation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'languages/cpp/cppevaluation.cpp')
-rw-r--r--languages/cpp/cppevaluation.cpp483
1 files changed, 483 insertions, 0 deletions
diff --git a/languages/cpp/cppevaluation.cpp b/languages/cpp/cppevaluation.cpp
new file mode 100644
index 00000000..ff1f4ab9
--- /dev/null
+++ b/languages/cpp/cppevaluation.cpp
@@ -0,0 +1,483 @@
+/***************************************************************************
+ begin : Sat Jul 21 2001
+ copyright : (C) 2001 by Victor R�er
+ copyright : (C) 2002,2003 by Roberto Raggi
+ copyright : (C) 2005 by Adam Treat
+ copyright : (C) 2006 by David Nolden
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "cppevaluation.h"
+#include "simplecontext.h"
+#include "safetycounter.h"
+
+extern SafetyCounter safetyCounter;
+
+namespace CppEvaluation {
+
+void statusLog( const QString& str ) {
+ ifVerboseMajor( dbgMajor() << str << endl );
+ statusBarText( str, 2000 );
+}
+OperatorSet AllOperators;
+
+///These lines register the operators to the list of all operators
+RegisterOperator< DotOperator > DotReg( AllOperators );
+RegisterOperator< NestedTypeOperator > NestedReg( AllOperators );
+RegisterOperator< ArrowOperator > ArrowReg( AllOperators );
+RegisterOperator< StarOperator > StarReg( AllOperators );
+RegisterOperator< AddressOperator > AddressReg( AllOperators );
+RegisterOperator< IndexOperator > IndexReg( AllOperators );
+RegisterOperator< ParenOperator > ParenReg( AllOperators );
+
+template<class To, class From>
+QValueList<To> convertList( const QValueList<From>& from ) {
+ QValueList<To> ret;
+ for( typename QValueList<From>::const_iterator it = from.begin(); it != from.end(); ++it ) {
+ ret << (To)*it;
+ }
+ return ret;
+}
+
+QString nameFromType( SimpleType t ) {
+ return t->fullTypeResolved();
+}
+
+QString Operator::printTypeList( QValueList<EvaluationResult>& lst )
+{
+ QString ret;
+ for( QValueList<EvaluationResult>::iterator it = lst.begin(); it != lst.end(); ++it ) {
+ ret += "\"" + (*it)->fullNameChain() + "\", ";
+ }
+ ret.truncate( ret.length() - 3 );
+ return ret;
+}
+
+void Operator::log( const QString& msg ) {
+ statusLog( "\"" + name() + "\": " + msg );
+ //ifVerboseMajor( dbgMajor() << "\"" << name() << "\": " << msg << endl );
+}
+
+OperatorSet::~OperatorSet() {
+ for( QValueList< Operator* >::iterator it = m_operators.begin(); it != m_operators.end(); ++it ) {
+ delete *it;
+ }
+}
+
+OperatorIdentification OperatorSet::identifyOperator( const QString& str_ , Operator::BindingSide allowedBindings) {
+ QString str = str_.stripWhiteSpace();
+ for( OperatorList::iterator it = m_operators.begin(); it != m_operators.end(); ++it ) {
+ if( ((*it)->binding() & allowedBindings) == (*it)->binding() ) {
+ if( OperatorIdentification ident = (*it)->identify( str ) ) {
+ return ident;
+ }
+ }
+ }
+
+ return OperatorIdentification();
+}
+
+OperatorIdentification UnaryOperator::identify( QString& str ) {
+ OperatorIdentification ret;
+ if( str.startsWith( m_identString ) ) {
+ ret.start = 0;
+ ret.end = m_identString.length();
+ ret.found = true;
+ ret.op = this;
+ }
+ return ret;
+}
+
+EvaluationResult UnaryOperator::apply( QValueList<EvaluationResult> params, QValueList<EvaluationResult> innerParams ) {
+ if( !checkParams( params ) ) {
+ log( QString("parameter-check failed: %1 params: ").arg( params.size() ) + printTypeList( params ) );
+ return EvaluationResult();
+ } else {
+ EvaluationResult t = unaryApply( params.front(), innerParams );
+ if( !t ) {
+ if( params.front() )
+ log( "could not apply \"" + name() + "\" to \"" + nameFromType( params.front() ) + "\"");
+ else
+ log( "operator \"" + name() + "\" applied on \"" + nameFromType( params.front() ) + "\": returning unresolved type \"" + nameFromType( t ) + "\"");
+ }
+ return t;
+ }
+}
+
+EvaluationResult NestedTypeOperator::unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& /*innerParams*/ ) {
+ return param;
+}
+
+EvaluationResult DotOperator::unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& /*innerParams*/ ) {
+ if( param->totalPointerDepth() == 0 ) {
+ return param;
+ } else {
+ log( "failed to apply dot-operator to " + param->fullNameChain() + " because the pointer-depth is wrong" );
+ return EvaluationResult();
+ }
+}
+
+
+EvaluationResult ArrowOperator::unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& innerParams ) {
+ if( param->totalPointerDepth() == 1 ) {
+ param->setTotalPointerDepth( param->totalPointerDepth() - 1 );
+ return param;
+ } else {
+ if( param->resolved() ) {
+ if( param->totalPointerDepth() == 0 ) {
+ return param->resolved()->applyOperator( SimpleTypeImpl::ArrowOp , convertList<LocateResult, EvaluationResult>(innerParams) );
+ } else {
+ log("failed to apply arrow-operator to " + param->fullNameChain() + " because the pointer-depth is wrong" );
+ return EvaluationResult();
+ }
+ } else {
+ log( "failed to apply arrow-operator to unresolved type" );
+ return EvaluationResult();
+ }
+ };
+}
+
+EvaluationResult StarOperator::unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& /*innerParams*/ ) {
+ if( param->totalPointerDepth() > 0 ) {
+ param->setTotalPointerDepth( param->totalPointerDepth() - 1 );
+ return param;
+ } else {
+ if( param->resolved() ) {
+ return param->resolved()->applyOperator( SimpleTypeImpl::StarOp );
+ } else {
+ log( "failed to apply star-operator to unresolved type" );
+ return EvaluationResult();
+ }
+ };
+}
+
+EvaluationResult AddressOperator::unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& /*innerParams*/ ) {
+ param->setTotalPointerDepth( param->totalPointerDepth() + 1 );
+ return param;
+}
+
+OperatorIdentification UnaryParenOperator::identify( QString& str ) {
+ OperatorIdentification ret;
+ if( str.startsWith( QString( identString()[0] ) ) ) {
+ ret.start = 0;
+ ret.end = findClose( str, 0 );
+ if( ret.end == -1 ) {
+ ret.found = false;
+ ret.end = 0;
+ } else {
+ if( str[ret.end] == identString()[1] ) {
+ ret.found = true;
+ ret.end += 1;
+ ret.op = this;
+
+ ///Try to extract the parameter-strings.
+ ParamIterator it( identString(), str.mid( ret.start, ret.end - ret.start ) );
+
+ while( it ) {
+ ret.innerParams << (*it).stripWhiteSpace();
+
+ ++it;
+ }
+
+ } else {
+ ret.end = 0;
+ }
+ }
+ }
+ return ret;
+}
+
+
+EvaluationResult IndexOperator::unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& innerParams ) {
+ if( param->totalPointerDepth() > 0 ) {
+ param->setTotalPointerDepth( param->totalPointerDepth() - 1 );
+ return param;
+ } else {
+ if( param->resolved() ) {
+ return param->resolved()->applyOperator( SimpleTypeImpl::IndexOp, convertList<LocateResult>( innerParams ) );
+ } else {
+ log( "failed to apply index-operator to unresolved type" );
+ return EvaluationResult();
+ }
+ };
+}
+
+EvaluationResult ParenOperator::unaryApply( EvaluationResult param, const QValueList<EvaluationResult>& innerParams ) {
+ if( param ) {
+ if( param->resolved() ) {
+ return param->resolved()->applyOperator( SimpleTypeImpl::ParenOp, convertList<LocateResult>(innerParams) );
+ } else {
+ log( "failed to apply paren-operator to unresolved type" );
+ return EvaluationResult();
+ }
+
+ } else {
+ return innerParams[0];
+ }
+}
+
+ExpressionEvaluation::ExpressionEvaluation( CppCodeCompletion* data, ExpressionInfo expr, OperatorSet& operators, const HashedStringSet& includeFiles, SimpleContext* ctx ) : m_data( data ), m_ctx( ctx ), m_expr( expr ), m_global(false), m_operators( operators ), m_includeFiles( includeFiles ) {
+ safetyCounter.init();
+
+ ifVerboseMajor( dbgMajor( ) << "Initializing evaluation of expression " << expr << endl );
+
+ if ( expr.expr().startsWith( "::" ) )
+ {
+ expr.setExpr( expr.expr().mid( 2 ) );
+ m_global = true;
+ }
+
+ //m_expr = m_data->splitExpression( expr.expr() ).join("");
+}
+
+EvaluationResult ExpressionEvaluation::evaluate() {
+ EvaluationResult res;
+ res = evaluateExpressionInternal( m_expr.expr(), m_ctx->global(), m_ctx, m_ctx, /*m_expr.canBeTypeExpression() cannot be safely determined*/true );
+
+ ExpressionInfo ex = res.expr; ///backup and set the type which was chosen while the evaluation-process
+ res.expr = m_expr;
+ res.expr.t = ex.t;
+
+ return res;
+}
+
+EvaluationResult ExpressionEvaluation::evaluateExpressionInternal( QString expr, EvaluationResult scope, SimpleContext * ctx, SimpleContext* innerCtx , bool canBeTypeExpression) {
+ LogDebug d( "#evl#" );
+ if( expr.isEmpty() || !safetyCounter ) {
+ scope.expr.t = ExpressionInfo::NormalExpression;
+ return scope;
+ }
+
+ /*if( !scope->resolved() ) {
+ ifVerboseMajor( dbgMajor() << "evaluateExpressionInternal(\"" << expr << "\") scope: \"" << scope->fullTypeStructure() << "\" is unresolved " << endl );
+ return EvaluationResult();
+ }*/
+
+ ifVerboseMajor( dbgMajor() << "evaluateExpressionInternal(\"" << expr << "\") scope: \"" << scope->fullNameChain() << "\" context: " << ctx << endl );
+
+ expr = expr.stripWhiteSpace();
+
+ ///Find the rightmost operator with the lowest priority, for the first split.
+ QValueList<OperatorIdentification> idents;
+ for( uint a = 0; a < expr.length(); ++a ) {
+ QString part = expr.mid( a );
+ OperatorIdentification ident = m_operators.identifyOperator( part );
+ if( ident ) {
+ ifVerboseMajor( dbgMajor() << "identified \"" << ident.op->name() << "\" in string " << part << endl );
+ ident.start += a;
+ ident.end += a;
+ idents << ident;
+ a += ident.end;
+ } else {
+ if( isLeftParen( part[0] ) ) {
+ int jump = findClose( part, 0 );
+ if( jump != -1 )
+ a += jump;
+ }
+ }
+ }
+
+ if( !idents.isEmpty() ) {
+ OperatorIdentification lowest;
+
+ for( QValueList<OperatorIdentification>::iterator it = idents.begin(); it != idents.end(); ++it ) {
+ if( lowest ) {
+ if( lowest.op->priority() >= (*it).op->priority() )
+ lowest = *it;
+ } else {
+ lowest = *it;
+ }
+ }
+
+ if( lowest ) {
+ QString leftSide = expr.left( lowest.start ).stripWhiteSpace();
+ QString rightSide = expr.right( expr.length() - lowest.end ).stripWhiteSpace();
+
+ EvaluationResult left, right;
+ if( !leftSide.isEmpty() ) {
+ left = evaluateExpressionInternal( leftSide, scope, ctx, innerCtx, lowest.op->canBeType( Operator::Left ) );
+ } else {
+ left = scope;
+ }
+
+ if( !left && (lowest.op->binding() & Operator::Left) ) {
+ ifVerboseMajor( dbgMajor() << "problem while evaluating expression \"" << expr << "\", the operator \"" << lowest.op->name() << "\" has a binding to the left side, but no left side could be evaluated: \"" << leftSide << "\"" << endl );
+ }
+
+ if( !rightSide.isEmpty() && (lowest.op->binding() & Operator::Right) )
+ right = evaluateExpressionInternal( rightSide, SimpleType(), ctx, innerCtx, lowest.op->canBeType( Operator::Right ) );
+
+ if( !right && (lowest.op->binding() & Operator::Right) ) {
+ ifVerboseMajor( dbgMajor() << "problem while evaluating expression \"" << expr << "\", the operator \"" << lowest.op->name() << "\" has a binding to the right side, but no right side could be evaluated: \"" << rightSide << "\"" << endl );
+ }
+
+ QValueList<EvaluationResult> innerParams;
+ QValueList<EvaluationResult> params;
+ if( lowest.op->binding() & Operator::Left ) params << left;
+ if( lowest.op->binding() & Operator::Right ) params << right;
+
+ for( QValueList<QString>::iterator it = lowest.innerParams.begin(); it != lowest.innerParams.end(); ++it ) {
+ ifVerboseMajor(dbgMajor() << "evaluating inner parameter \"" + *it + "\"" );
+ innerParams << evaluateExpressionInternal( (*it), SimpleType(), innerCtx, innerCtx, lowest.op->canBeType( Operator::Neutral ) );
+ }
+
+ EvaluationResult applied = lowest.op->apply( params, innerParams );
+ if( !applied ) {
+ statusLog( "\"" + expr + "\": failed to apply the operator \"" + lowest.op->name() + "\"" );
+ }
+
+ if( ! (lowest.op->binding() & Operator::Left) && !leftSide.isEmpty() ) {
+ ///When the operator has no binding to the left, the left side should be empty.
+ statusLog( "\"" + expr + "\": problem with the operator \"" + lowest.op->name() + ", it has no binding to the left side, but the left side is \""+ leftSide + "\"" );
+ }
+
+ if( ! (lowest.op->binding() & Operator::Right) && !rightSide.isEmpty() ) {
+ ///When the operator has no binding to the right, we should continue evaluating the right side, using the left type as scope.
+ ///Think about this.
+ return evaluateExpressionInternal( rightSide, applied, 0, innerCtx, lowest.op->canBeType( Operator::Right ) );
+ }
+
+ return applied;
+ } else {
+ ifVerboseMajor( dbgMajor() << " could not find an operator in " << expr << endl );
+ return evaluateAtomicExpression( expr, scope, ctx );
+ }
+ }
+
+ //dbgMajor() << " could not evaluate " << expr << endl;
+ ifVerboseMajor( dbgMajor() << "evaluating \"" << expr << "\" as atomic expression" << endl );
+
+ TypeDesc exp = m_ctx->container()->resolveTemplateParams( TypeDesc(expr) );
+
+ ifVerboseMajor( dbgMajor() << "after template-parameter resolution: \"" << exp.fullNameChain() << "\"" << endl );
+
+ EvaluationResult res = evaluateAtomicExpression( exp, scope, ctx, canBeTypeExpression );
+ return res;
+}
+
+/**This function needs a clean workover.
+ * An atomic expression is one that only consists of a type-, function- or variable-name(may include '::')
+ */
+EvaluationResult ExpressionEvaluation::evaluateAtomicExpression( TypeDesc expr, EvaluationResult scope, SimpleContext * ctx, bool canBeTypeExpression ) {
+ LogDebug d( "#evt#");
+ if( !safetyCounter || !d ) return SimpleType();
+ bool canBeItemExpression = true; ///To be implemented
+
+ if( scope ) {
+ expr.setIncludeFiles( scope.resultType->includeFiles() );
+ } else {
+ expr.setIncludeFiles( m_includeFiles );
+ }
+
+
+ ifVerboseMajor( dbgMajor() << "evaluateAtomicExpression(\"" << expr.name() << "\") scope: \"" << scope->fullNameChain() << "\" context: " << ctx << endl );
+
+ EvaluationResult bestRet;
+ int bestDepth = 0;
+
+ if( expr.name().isEmpty() )
+ return scope;
+
+ TypePointer searchIn = scope->resolved();
+ if( !searchIn ) {
+ statusLog( "scope-type is not resolved" );
+ return EvaluationResult();
+ }
+
+ if( ctx )
+ searchIn = ctx->container().get();
+
+ if( ctx && canBeItemExpression ) {
+ ///Search for variables and functions, first in the current context, and then through the container-classes upwards.
+ // find the variable in the current context
+ SimpleVariable var = ctx->findVariable( expr.name() );
+
+ if ( var.type ) {
+ TypeDesc d( var.type );
+ d.setIncludeFiles( m_includeFiles );
+ EvaluationResult ret = EvaluationResult( ctx->container()->locateDecType( d ), var.toDeclarationInfo( "current_file" ));
+ ret.expr.t = ExpressionInfo::NormalExpression;
+ return ret;
+ }
+
+ SimpleType current = ctx->container();
+
+ SimpleTypeImpl::TypeOfResult type;
+
+ SafetyCounter s( 20 );
+ bool ready = false;
+ int depth = 0;
+
+ while( !ready && s )
+ {
+ if( !current ) ready = true;
+
+ type = current->typeOf( expr );
+ if ( type) {
+ bestRet = EvaluationResult( type.type, type.decl );
+ bestDepth = depth;
+ bestRet.expr = expr.fullNameChain();
+ bestRet.expr.t = ExpressionInfo::NormalExpression;
+ }
+
+ depth++;
+ if( !ready ) current = current->parent();
+ }
+ }
+ /*
+ if( scope.expr.t & ExpressionInfo::TypeExpression )
+ canBeTypeExpression = true;*/
+
+ if( canBeItemExpression && (!bestRet || bestDepth > 0 ) ) {
+ //SimpleTypeImpl::
+ SimpleTypeImpl::TypeOfResult res = searchIn->typeOf( expr );
+
+ if( res ) {
+ bestRet = EvaluationResult( res.type, res.decl );
+ bestDepth = 0;
+ }
+ }
+ if( canBeTypeExpression ) {
+ ///Search for Types
+ LocateResult type = searchIn->locateDecType( expr );
+
+ if( !bestRet ||
+ /** Did we find a constructor within a class? */
+ (type->resolved() && ( bestRet->resolved() && type->resolved()->desc() == bestRet->resolved()->parent()->desc() && bestRet->resolved()->asFunction() ) ) ) {
+ /*if ( type && type->resolved() )
+ {*/
+ EvaluationResult ret = type;
+ ret.expr = expr.fullNameChain();
+ ret.expr.t = ExpressionInfo::TypeExpression;
+ bestRet = ret;
+ }
+ /*} else {
+ bestRet = EvaluationResult( type );
+ QStringList s = split+exprList;
+ s.pop_front();
+ if( !s.isEmpty() )
+ bestRet->append( new TypeDescShared( s.join("::") ) );
+ }*/
+ }
+
+ if( bestRet )
+ return bestRet;
+
+ ifVerboseMajor( dbgMajor() << "evaluateAtomicExpression: \"" << scope.resultType->fullNameChain() << "\"could not locate " << expr.fullNameChain() << endl );
+ return bestRet;
+}
+}
+
+// kate: indent-mode csands; tab-width 2;