Foam::scalar Foam::equationReader::getScalarSrcEquationCircRefDetect
(
    const equationReader * eqnReader,
    const label equationIndex,
    const label equationOperationIndex,
    const label maxStoreIndex,
    const label storageOffset
) const
{
    const equation& eqn(operator[](equationIndex));
    equationOperation& eqOp(eqn[equationOperationIndex]);
    label zeroSourceIndex = mag(eqOp.sourceIndex()) - 1;

    // Check for circular references
    dependents_.setSize(dependents_.size() + 1);
    dependents_[dependents_.size() - 1] = equationIndex;
    forAll(dependents_, i)
    {
        if (dependents_[i] == zeroSourceIndex)
        {
            // Circular reference detected
            
            string dependencies;
            for (label j(i); j < dependents_.size(); j++)
            {
                dependencies.append
                (
                    operator[](dependents_[j]).name()
                );
                dependencies.append("-->");
            }
            dependencies.append(operator[](dependents_[i]).name());
            FatalErrorIn("equationReader::getScalarSrcEquationCircRefDetect")
                << "Circular reference detected when evaluating "
                << "the equation for " << eqn.name()
                << ", given by:" << token::NL << token::TAB
                << eqn.rawText() << token::NL << "The circular "
                << "dependency is:" << token::NL << token::TAB
                << dependencies
                << abort(FatalError);
        }
    }
    // Launch the reportEmbeddedDispatchFunction:
    //  if (debug)
    //  {
    //      reportEmbeddedDispatchEnabled;
    //      // or: Info << "Embedded equation dispatch." << endl;
    //  }
    //  else
    //  {
    //      reportEmbeddedDispatchDisabled();
    //      // does nothing
    //  }
    scalar returnMe
    (
        internalEvaluateScalar(zeroSourceIndex, maxStoreIndex + 1)
    );
    eqOp.assignSourceScalarFunction
    (
        &Foam::equationReader::getScalarSrcEquation
    );
    eqOp.assignSourceScalarFieldFunction
    (
        &Foam::equationReader::getScalarFieldSrcEquation
    );
    // Launch the reportEmbeddedReturnFunction:
    //  if (debug)
    //  {
    //      reportEmbeddedReturnEnabled;
    //      // or: Info << "Return from equation equation." << endl;
    //  }
    //  else
    //  {
    //      reportEmbeddedReturnDisabled();
    //      // does nothing
    //  }
    (*this.*reportEmbeddedReturnFunction_)();
    
    //Move one level back up on the dependents_ list
    if (dependents_.size())
    {
        dependents_.setSize(dependents_.size() - 1);
    }    
    
    returnMe *= sign(eqOp.sourceIndex());
    return returnMe;
}
示例#2
0
RSourceIndex::RSourceIndex(const std::string& context,
                           const std::string& code)
   : context_(context)
{
   // convert code to wide
   std::wstring wCode = string_utils::utf8ToWide(code, context);

   // determine where the linebreaks are and initialize an iterator
   // used for scanning them
   std::vector<std::size_t> newlineLocs;
   std::size_t nextNL = 0;
   while ( (nextNL = wCode.find(L'\n', nextNL)) != std::string::npos )
      newlineLocs.push_back(nextNL++);
   std::vector<std::size_t>::const_iterator newlineIter = newlineLocs.begin();
   std::vector<std::size_t>::const_iterator endNewlines = newlineLocs.end();

   // tokenize
   RTokens rTokens(wCode, RTokens::StripWhitespace | RTokens::StripComments);

   // scan for function, method, and class definitions (track indent level)
   int braceLevel = 0;
   std::wstring function(L"function");
   std::wstring set(L"set");
   std::wstring setGeneric(L"setGeneric");
   std::wstring setGroupGeneric(L"setGroupGeneric");
   std::wstring setMethod(L"setMethod");
   std::wstring setClass(L"setClass");
   std::wstring setClassUnion(L"setClassUnion");
   std::wstring setRefClass(L"setRefClass");
   std::wstring eqOp(L"=");
   std::wstring assignOp(L"<-");
   std::wstring parentAssignOp(L"<<-");
   for (std::size_t i=0; i<rTokens.size(); i++)
   {
      // initial name, qualifer, and type are nil
      RSourceItem::Type type = RSourceItem::None;
      std::wstring name;
      std::size_t tokenOffset = -1;
      bool isSetMethod = false;
      std::vector<RS4MethodParam> signature;

      // alias the token
      const RToken& token = rTokens.at(i);

      // see if this is a begin or end brace and update the level
      if (token.type() == RToken::LBRACE)
      {
         braceLevel++;
         continue;
      }

      else if (token.type() == RToken::RBRACE)
      {
         braceLevel--;
         continue;
      }
      // bail for non-identifiers
      else if (token.type() != RToken::ID)
      {
         continue;
      }

      // is this a potential method or class definition?
      if (token.contentStartsWith(set))
      {
         RSourceItem::Type setType = RSourceItem::None;

         if (token.contentEquals(setMethod))
         {
            isSetMethod = true;
            setType = RSourceItem::Method;
         }
         else if (token.contentEquals(setGeneric) ||
                  token.contentEquals(setGroupGeneric))
         {
            setType = RSourceItem::Method;
         }
         else if (token.contentEquals(setClass) ||
                  token.contentEquals(setClassUnion) ||
                  token.contentEquals(setRefClass))
         {
            setType = RSourceItem::Class;
         }
         else
         {
            continue;
         }

         // make sure there are at least 4 more tokens
         if ( (i + 3) >= rTokens.size())
            continue;

         // check for the rest of the token sequene for a valid call to set*
         if ( (rTokens.at(i+1).type() != RToken::LPAREN) ||
              (rTokens.at(i+2).type() != RToken::STRING) ||
              (rTokens.at(i+3).type() != RToken::COMMA))
            continue;

         // found a class or method definition (will find location below)
         type = setType;
         name = removeQuoteDelims(rTokens.at(i+2).content());
         tokenOffset = token.offset();

         // if this was a setMethod then try to lookahead for the signature
         if (isSetMethod)
         {
            parseSignature(rTokens.begin() + (i+4),
                           rTokens.end(),
                           &signature);
         }
      }

      // is this a function?
      else if (token.contentEquals(function))
      {
         // if there is no room for an operator and identifier prior
         // to the function then bail
         if (i < 2)
            continue;

         // check for an assignment operator
         const RToken& opToken = rTokens.at(i-1);
         if ( opToken.type() != RToken::OPER)
            continue;
         if (!opToken.isOperator(eqOp) &&
             !opToken.isOperator(assignOp) &&
             !opToken.isOperator(parentAssignOp))
            continue;

         // check for an identifier
         const RToken& idToken = rTokens.at(i-2);
         if ( idToken.type() != RToken::ID )
            continue;

         // if there is another previous token make sure it isn't a
         // comma or an open paren
         if ( i > 2 )
         {
            const RToken& prevToken = rTokens.at(i-3);
            if (prevToken.type() == RToken::LPAREN ||
                prevToken.type() == RToken::COMMA)
               continue;
         }

         // if we got this far then this is a function definition
         type = RSourceItem::Function;
         name = idToken.content();
         tokenOffset = idToken.offset();
      }
      else
      {
         continue;
      }

      // compute the line by starting at the current line index and
      // finding the first newline which is after the idToken offset
      newlineIter = std::upper_bound(newlineIter,
                                     endNewlines,
                                     tokenOffset);
      std::size_t line = newlineIter - newlineLocs.begin() + 1;

      // compute column by comparing the offset to the PREVIOUS newline
      // (guard against no previous newline)
      std::size_t column;
      if (line > 1)
         column = tokenOffset - *(newlineIter - 1);
      else
         column = tokenOffset;

      // add to index
      items_.push_back(RSourceItem(type,
                                   string_utils::wideToUtf8(name),
                                   signature,
                                   braceLevel,
                                   line,
                                   column));
   }
}
/*** Evaluate this object ***/
Object* SpecialFunction::evaluate()
{
	if(args.size() == 0)
		throw Excep(getLineNumber(), getColumnNumber(), "Expected argument to special function!");

	std::auto_ptr<Object> arg1(args.at(0)->evaluate());

	if(id == SPF_INDEX)
	{
		if(args.size() != 2)
			throw Excep(getLineNumber(), getColumnNumber(), "Invalid number of arguments passed to special function!");

		std::auto_ptr<Object> arg2(args.at(1)->evaluate());

		if(arg2->getType() == OBJ_TEXT)
		{
			if(arg1->getType() != OBJ_TEXT)
				throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_TEXT, arg1->getType(), 1);

			Text* cast1 = static_cast<Text*>(arg1.get());
			Text* cast2 = static_cast<Text*>(arg2.get());

			size_t index = cast2->getValue().find(cast1->getValue());

			if(index != std::string::npos)
				return new Integer(index + 1);

			return new Integer(0);
		}

		if(arg2->getType() == OBJ_SEQUENCE)
		{
				Sequence* cast = dynamic_cast<Sequence*>(arg2.get());

				for(unsigned int i = 0; i < cast->getLength(); i++)
				{
					std::auto_ptr<Logical> eqOp(static_cast<Logical*>(Equal(arg1->clone(), cast->getObject(i)->clone()).evaluate()));
					if(eqOp->getValue() == true)
						return new Integer(i + 1);
				}

				return new Integer(0);
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_TEXT | OBJ_SEQUENCE, arg2->getType(), 2);
	}

	if(args.size() > 1)
		throw Excep(getLineNumber(), getColumnNumber(), "Invalid number of arguments passed to special function!");

	if(id == SPF_ABS)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			if(cast->getValue() < 0)
				return new Integer(-cast->getValue());
			return new Integer(cast->getValue());
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			if(cast->getValue() < 0)
				return new Real(-cast->getValue());
			return new Real(cast->getValue());
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_SIGN)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			if(cast->getValue() < 0)
				return new Integer(-1);
			if(cast->getValue() > 0)
				return new Integer(1);
			return new Integer(0);
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			if(cast->getValue() < 0)
				return new Integer(-1);
			if(cast->getValue() > 0)
				return new Integer(1);
			return new Integer(0);
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_SQRT)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());

			if(cast->getValue() < 0)
				throw NegativeValueException(getLineNumber(), getColumnNumber(), cast->getValue(), 1);

			double res = sqrt((double) cast->getValue());
			if((long) res == res)
				return new Integer((long) res);
			return new Real(res);
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());

			if(cast->getValue() < 0)
				throw NegativeValueException(getLineNumber(), getColumnNumber(), cast->getValue(), 1);

			double res = sqrt((double) cast->getValue());
			return new Real(res);
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_ENTIER)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			return new Integer(cast->getValue());
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			return new Integer(floor(cast->getValue()));
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_ROUND)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			return new Integer(cast->getValue());
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			long rounded = cast->getValue() < 0.0 ? ceil(cast->getValue() - 0.5) : floor(cast->getValue() + 0.5);
			return new Integer(rounded);
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_RAND)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());

			if(cast->getValue() < 0)
				throw NegativeValueException(getLineNumber(), getColumnNumber(), cast->getValue(), 1);

			double f = (double) rand() / RAND_MAX;
			return new Real( f * cast->getValue() );
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());

			if(cast->getValue() < 0)
				throw NegativeValueException(getLineNumber(), getColumnNumber(), cast->getValue(), 1);

			double f = (double) rand() / RAND_MAX;
			return new Real( f * cast->getValue() );
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_INTRAND)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			if(cast->getValue() < 0)
				throw NegativeValueException(getLineNumber(), getColumnNumber(), cast->getValue(), 1);
			return new Integer( rand() % cast->getValue() + 1 );
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			if(cast->getValue() < 0)
				throw NegativeValueException(getLineNumber(), getColumnNumber(), cast->getValue(), 1);
			return new Integer( rand() % (long) cast->getValue() + 1 );
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_ISEMPTY)
	{
		return new Logical(arg1->getType() == OBJ_EMPTY);
	}

	if(id == SPF_ISLOG)
	{
		return new Logical(arg1->getType() == OBJ_LOGICAL);
	}

	if(id == SPF_ISINT)
	{
		return new Logical(arg1->getType() == OBJ_INTEGER);
	}

	if(id == SPF_ISREAL)
	{
		return new Logical(arg1->getType() == OBJ_REAL);
	}

	if(id == SPF_ISTEXT)
	{
		return new Logical(arg1->getType() == OBJ_TEXT);
	}

	if(id == SPF_ISSEQ)
	{
		return new Logical(arg1->getType() == OBJ_SEQUENCE);
	}

	if(id == SPF_ISPROC)
	{
		return new Logical(arg1->getType() == OBJ_PROCEDURE);
	}

	if(id == SPF_ISFUN)
	{
		return new Logical(arg1->getType() == OBJ_FUNCTION || arg1->getType() == OBJ_SPFUNCTION);
	}

	if(id == SPF_SIN)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			return new Real(sin((double) cast->getValue()));
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			return new Real(sin(cast->getValue()));
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_COS)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			return new Real(cos((double) cast->getValue()));
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			return new Real(cos(cast->getValue()));
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_TG)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			return new Real(tan((double) cast->getValue()));
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			return new Real(tan(cast->getValue()));
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_ARCSIN)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			if(errno == EDOM)
				throw new Excep(getLineNumber(), getColumnNumber(), "Invalid value passed to special function!");
			return new Real(exp((double) cast->getValue()));
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			if(errno == EDOM)
				throw new Excep(getLineNumber(), getColumnNumber(), "Invalid value passed to special function!");
			return new Real(exp(cast->getValue()));
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_ARCTG)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			if(errno == EDOM)
				throw new Excep(getLineNumber(), getColumnNumber(), "Invalid value passed to special function!");
			return new Real(exp((double) cast->getValue()));
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			if(errno == EDOM)
				throw new Excep(getLineNumber(), getColumnNumber(), "Invalid value passed to special function!");
			return new Real(exp(cast->getValue()));
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_EXP)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			return new Real(exp((double) cast->getValue()));
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			return new Real(exp(cast->getValue()));
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_LN)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			return new Real(log((double) cast->getValue()));
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			return new Real(log(cast->getValue()));
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	if(id == SPF_LG)
	{
		if(arg1->getType() == OBJ_INTEGER)
		{
			Integer* cast = static_cast<Integer*>(arg1.get());
			return new Real(log10((double) cast->getValue()));
		}

		if(arg1->getType() == OBJ_REAL)
		{
			Real* cast = static_cast<Real*>(arg1.get());
			return new Real(log10(cast->getValue()));
		}

		throw InvalidTypeException(getLineNumber(), getColumnNumber(), OBJ_INTEGER | OBJ_REAL, arg1->getType(), 1);
	}

	throw Excep(getLineNumber(), getColumnNumber(), "Invalid special function!");
}
Foam::dimensionSet Foam::equationReader::getDimsSrcEquationCircRefDetect
(
    const equationReader * eqnReader,
    const label equationIndex,
    const label equationOperationIndex,
    const label maxStoreIndex,
    const label storageOffset
) const
{
    const equation& eqn(operator[](equationIndex));
    equationOperation& eqOp(eqn[equationOperationIndex]);
    label zeroSourceIndex = mag(eqOp.sourceIndex()) - 1;

    // Check for circular references
    dependents_.setSize(dependents_.size() + 1);
    dependents_[dependents_.size() - 1] = equationIndex;
    forAll(dependents_, i)
    {
        if (dependents_[i] == zeroSourceIndex)
        {
            // Circular reference detected
            string dependencies;
            for (label j(i); j < dependents_.size(); j++)
            {
                dependencies.append
                (
                    operator[](dependents_[j]).name()
                );
                dependencies.append("-->");
            }
            dependencies.append(operator[](dependents_[i]).name());
            FatalErrorIn
            (
                "equationReader::getDimsSrcEquationCircRefDetect"
            )
                << "Circular reference detected when evaluating "
                << "the equation for " << eqn.name()
                << ", given by:" << token::NL << token::TAB
                << eqn.rawText() << token::NL << "The circular "
                << "dependency is:" << token::NL << token::TAB
                << dependencies
                << abort(FatalError);
        }
    }

    // Launch the reportEmbeddedDispatchFunction:
    //  if (debug)
    //  {
    //      reportEmbeddedDispatchEnabled;
    //      // or: Info << "Embedded equation dispatch." << endl;
    //  }
    //  else
    //  {
    //      reportEmbeddedDispatchDisabled();
    //      // does nothing
    //  }
    (*this.*reportEmbeddedDispatchFunction_)();

    // Call the associated evaluateDimensions function pointer - has the same
    // effect as this:
    //
    //  const equation& eqn(operator[](zeroSourceIndex));
    //  if (eqn.changeDimensions())
    //  {
    //      evaluateDimsDisabled(zeroSourceIndex, maxStoreIndex + 1);
    //      // which in turn does: return eqn.overrideDimensions();
    //  }
    //  else
    //  {
    //      evaluadeDimsEnabled(zeroSourceIndex, maxStoreIndex + 1);
    //      // which in turn does:
    //      // return internalEvaluateDimensions
    //      // (zeroSourceIndex, maxStoreIndex + 1);
    //  }
    dimensionSet returnMe
    (
        (*this.*evaluateDimsFunctions_[zeroSourceIndex])
        (zeroSourceIndex, maxStoreIndex + 1)
    );

    // Launch the reportEmbeddedReturnFunction:
    //  if (debug)
    //  {
    //      reportEmbeddedReturnEnabled;
    //      // or: Info << "Return from equation equation." << endl;
    //  }
    //  else
    //  {
    //      reportEmbeddedReturnDisabled();
    //      // does nothing
    //  }
    (*this.*reportEmbeddedReturnFunction_)();

    //Move one level back up on the dependents_ list
    if (dependents_.size())
    {
        dependents_.setSize(dependents_.size() - 1);
    }

    return returnMe;
}