ExpressionPrinter.hh 7.12 KB
#ifndef EXPRESSIONPRINTER_HH_
#define EXPRESSIONPRINTER_HH_

#include "ExpressionContainer.hh"

#include <sstream>

//#define ADD_DEBUG_TAG

namespace AMDA {
namespace parser {
namespace Expression {

class ExpressionPrinter : public boost::static_visitor<void>
{
public:
	ExpressionPrinter(std::ostream& os) : _os(os), _pParamsList(NULL) {}

	ExpressionPrinter(std::ostream& os, std::vector<std::string>* pParamsList) : _os(os), _pParamsList(pParamsList) {}

	std::ostream& _os;

	std::vector<std::string>* _pParamsList;

	void operator()(const var& v) const {
		#ifdef ADD_DEBUG_TAG
		_os << "@VAR@";
		#endif
		_os << v;
	}

	void operator()(const BinaryOperation& b) const {
		#ifdef ADD_DEBUG_TAG
		_os << "@BINOP@";
		#endif
		_os << "(";
		boost::apply_visitor(*this, b.l);
		_os << b.op.kernelSymbol;
		boost::apply_visitor(*this, b.r);
		_os << ")";
	}

	void operator()(const UnaryOperation& u) const{
		#ifdef ADD_DEBUG_TAG
		_os << "@UNOP@";
		#endif
		_os << u.op.kernelSymbol;
		boost::apply_visitor(*this, u.e);
	}

	void operator()(const PowerOperation& p) const{
		#ifdef ADD_DEBUG_TAG
		_os << "@POWER@";
		#endif
		_os << "pow(";
		boost::apply_visitor(*this, p.l);
		_os << ",";
		boost::apply_visitor(*this, p.r);
		_os << ")";
	}

	void operator()(const FunctionOperation& f) const{
		#ifdef ADD_DEBUG_TAG
		_os << "@FUNC@";
		#endif
		_os << f.func << "(";
		bool isProcess = (!f.func.empty() && (f.func[0] == '#'));
		for (unsigned int i = 0; i < f.args.size(); ++i) {
			if (i != 0) {
				_os << (isProcess ? ";" : ",");
			}
			boost::apply_visitor(*this, f.args[i]);
		}
		_os << ")";
	}

	void operator()(const ParameterDef& p) const{
		#ifdef ADD_DEBUG_TAG
		_os << "@PARAM@";
		#endif

		if (_pParamsList != NULL) {
			if (std::find(_pParamsList->begin(), _pParamsList->end(), p.param) == _pParamsList->end()) {
				_pParamsList->push_back(p.param);
			}
		}

		if (
			p.components.empty() ||
			((p.components.size() == 1) && (p.components[0].type == ParameterDef::ComponentType::CT_ALL)) ||
			((p.components.size() == 2) && (p.components[0].type == ParameterDef::ComponentType::CT_ALL) && (p.components[1].type == ParameterDef::ComponentType::CT_ALL)))
		{
			// All components
			_os << printParam(p.param);
		}
		else if ((p.components.size() == 1) ||
			((p.components.size() == 2) && (p.components[1].type == ParameterDef::ComponentType::CT_ALL)))
		{
			//only first component defined
			switch (p.components[0].type) {
			case ParameterDef::ComponentType::CT_INDEX:
				_os << printParam(p.param);
				_os << printComponentIndex(p.components[0].index);
				break;
			case ParameterDef::CT_RANGE_VALUES:
			case ParameterDef::CT_RANGE_INDEXES:
				{
					std::stringstream ss;
					ss << printParam(p.param);
					_os << printSumIntoTable(p.components[0].type, ss.str(), 0, p.components[0].min, p.components[0].max);
					break;
				}
			default:
				//Unknown case => return parameter
				_os << printParam(p.param);
			}
		}
		else if ((p.components.size() == 2) && (p.components[0].type == ParameterDef::ComponentType::CT_ALL))
		{
			//only second component defined
			switch (p.components[1].type) {
			case ParameterDef::ComponentType::CT_INDEX:
				{
				_os << printParamColumn(p.param, p.components[1].index);
				break;
				}
			case ParameterDef::CT_RANGE_VALUES:
			case ParameterDef::CT_RANGE_INDEXES:
				{
					std::stringstream ss;
					ss << printParam(p.param);
					_os << printSumIntoTable(p.components[1].type, ss.str(), 1, p.components[1].min, p.components[1].max);
				}
				break;
			default:
				//Unknown case => return parameter
				_os << printParam(p.param);
			}
		}
		else {
			//two components defined
			switch (p.components[0].type) {
			case ParameterDef::ComponentType::CT_INDEX:
				{
					switch (p.components[1].type) {
					case ParameterDef::ComponentType::CT_INDEX:
						_os << printParam(p.param);
						_os << printComponentIndex(p.components[0].index);
						_os << printComponentIndex(p.components[1].index);
						break;
					case ParameterDef::CT_RANGE_VALUES:
					case ParameterDef::CT_RANGE_INDEXES:
						{
							std::stringstream ss;
							ss << printParam(p.param);
							ss << printComponentIndex(p.components[0].index);
							_os << printSumIntoTable(p.components[1].type, ss.str(), 1, p.components[1].min, p.components[1].max);
						}
						break;
					default:
						//Unknown case => return parameter
						_os << printParam(p.param);
					}
				}
				break;
			case ParameterDef::CT_RANGE_VALUES:
			case ParameterDef::CT_RANGE_INDEXES:
				{
					switch (p.components[1].type) {
					case ParameterDef::ComponentType::CT_INDEX:
						{
							std::stringstream ss;
							ss << printParamColumn(p.param,p.components[1].index);
							_os << printSumIntoTable(p.components[0].type, ss.str(), 0, p.components[0].min, p.components[0].max);
						}
						break;
					case ParameterDef::CT_RANGE_VALUES:
					case ParameterDef::CT_RANGE_INDEXES:
						if (p.components[0].type != p.components[1].type) {
							//Cannot mix range values and range indexes => return parameter
							_os << printParam(p.param);
						}
						else {
							std::stringstream ss;
							ss << printParam(p.param);
							_os << printSumIntoTable(p.components[0].type, ss.str(), 0, p.components[0].min, p.components[0].max, p.components[1].min, p.components[1].max);
						}
						break;
					default:
						//Unknown case => return parameter
						_os << printParam(p.param);
					}
				}
				break;
			default:
				//Unknown case => return parameter
				_os << printParam(p.param);
			}
		}
	}

private:
	std::string printParam(std::string name) const {
		std::stringstream ss;
		ss << "$";
		ss << name;
		return ss.str();
	}

	std::string printParamColumn(std::string name, int col) const {
		std::stringstream ss;
		ss << "(";
		ss << printParam(name);
		ss << ").getColumn(";
		ss << col;
		ss << ")";
		return ss.str();
	}

	std::string printComponentIndex(int index) const {
		std::stringstream ss;
		ss << "[";
		ss << index;
		ss << "]";
		return ss.str();
	}

	

	std::string printSumIntoTable(ParameterDef::ComponentType type, std::string expression, int relatedDim1, float min, float max, float min2 = NAN, float max2 = NAN) const {
		std::stringstream ss;
		bool forceInt = false;
		if (type == ParameterDef::ComponentType::CT_RANGE_INDEXES) {
			ss << "#sum_into_table_indexes";
			forceInt = true;
		}
		else {
			ss << "#sum_into_table_range";
		}
		ss << "(";
		ss << expression;
		ss << ";";
		ss << relatedDim1;
		ss << ";";
		ss << (forceInt ? (int)min : min);
		ss << ";";
		ss << (forceInt ? (int)max : max);
		if (!std::isnan(min2) && !std::isnan(max2)) {
			ss << ";";
			ss << (forceInt ? (int)min2 : min2);
			ss << ";";
			ss << (forceInt ? (int)max2 : max2);
		}
		ss << ")";
		return ss.str();
	}
};

std::ostream& operator<<(std::ostream& os, const ExpressionContainer& e)
{
	boost::apply_visitor(ExpressionPrinter(os), e);
	return os;
}

void getExpressionInfo(const ExpressionContainer& e, std::string& kernelExpression, std::vector<std::string>& paramsList) {
	std::stringstream ss;
        boost::apply_visitor(ExpressionPrinter(ss, &paramsList), e);
	kernelExpression = ss.str();
}
    
} /* namespace Expression */
} /* namespace parser */
} /* namespace AMDA */


#endif