package org.matheclipse.core.convert;

import java.util.HashMap;
import java.util.Map;

import org.matheclipse.core.basic.Config;
import org.matheclipse.core.builtin.function.Blank;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IInteger;
import org.matheclipse.core.interfaces.ISymbol;
import org.matheclipse.core.reflection.system.Complex;
import org.matheclipse.core.reflection.system.Pattern;
import org.matheclipse.core.reflection.system.Rational;
import org.matheclipse.parser.client.ast.ASTNode;
import org.matheclipse.parser.client.ast.FloatNode;
import org.matheclipse.parser.client.ast.FractionNode;
import org.matheclipse.parser.client.ast.FunctionNode;
import org.matheclipse.parser.client.ast.IntegerNode;
import org.matheclipse.parser.client.ast.Pattern2Node;
import org.matheclipse.parser.client.ast.Pattern3Node;
import org.matheclipse.parser.client.ast.PatternNode;
import org.matheclipse.parser.client.ast.StringNode;
import org.matheclipse.parser.client.ast.SymbolNode;

/**
 * Converts a parsed org.matheclipse.parser.client.ast.ASTNode expression into an IExpr expression
 * 
 */
public class AST2Expr {

	private final static String[] FUNCTION_STRINGS = { "DirectedInfinity", "False", "Flat", "HoldAll", "HoldFirst", "HoldRest",
			"Indeterminate", "Integer", "List", "Listable", "Modulus", "Null", "NumericFunction", "OneIdentity", "Orderless", "Real",
			"Slot", "SlotSequence", "String", "Symbol", "True", "Abs", "AddTo", "And", "Apart", "Append", "AppendTo",
			"Apply", "ArcCos", "ArcCosh", "ArcCot", "ArcCoth", "ArcCsc", "ArcCsch", "ArcSec", "ArcSech", "ArcSin", "ArcSinh",
			"ArcTan", "ArcTanh", "Arg", "Array", "AtomQ", "Attributes", "BernoulliB", "Binomial", "Blank", "Block", "Boole",
			"BooleanMinimize", "Break", "Cancel", "CartesianProduct", "Cases", "Catalan", "CatalanNumber", "Catch", "Ceiling",
			"CharacteristicPolynomial", "ChessboardDistance", "Chop", "Clear", "ClearAll", "Coefficient", "CoefficientList",
			"Collect", "Complement", "Complex", "ComplexExpand", "ComplexInfinity", "ComposeList", "CompoundExpression",
			"Condition", "Conjugate", "ConjugateTranspose", "ConstantArray", "Continue", "ContinuedFraction", "CoprimeQ", "Cos",
			"Cosh", "Cot", "Coth", "Count", "Cross", "Csc", "Csch", "Curl", "D", "Decrement", "Default", "Defer", "Definition",
			"Degree", "Delete", "Denominator", "Depth", "Derivative", "Det", "DiagonalMatrix", "DigitQ", "Dimensions",
			"Discriminant", "Distribute", "Divergence", "DivideBy", "Do", "Dot", "Drop", "E", "Eliminate", "Eigenvalues",
			"Eigenvectors", "Equal", "Erf", "EuclidianDistance", "EulerE", "EulerGamma", "EulerPhi", "EvenQ", "Exp", "Expand",
			"ExpandAll", "Exponent", "ExtendedGCD", "Extract", "Factor", "Factorial", "Factorial2", "FactorInteger",
			"FactorSquareFree", "FactorSquareFreeList", "FactorTerms", "Flatten", "Fibonacci", "FindRoot", "First", "Fit",
			"FixedPoint", "Floor", "Fold", "FoldList", "For", "FractionalPart", "FreeQ", "FrobeniusSolve", "FromCharacterCode",
			"FromContinuedFraction", "FullForm", "FullSimplify", "Function", "Gamma", "GCD", "GeometricMean", "Glaisher",
			"GoldenRatio", "Graphics", "Graphics3D", "Graphics3D", "Greater", "GreaterEqual", "GroebnerBasis", "HarmonicNumber",
			"Head", "HilbertMatrix", "Hold", "Horner", "I", "IdentityMatrix", "If", "Im", "Increment", "Infinity", "Inner",
			"Insert", "IntegerPart", "IntegerPartitions", "IntegerQ", "Integrate", "InterpolatingFunction", "Intersection",
			"Inverse", "InverseErf", "InverseFunction", "JacobiMatrix", "JacobiSymbol", "JavaForm", "Join", "Khinchin",
			"KOrderlessPartitions", "KPartitions", "Last", "LCM", "LeafCount", "Length", "Less", "LessEqual", "LetterQ", "Level",
			"Limit", "Line", "LinearProgramming", "LinearSolve", "Log", "LowerCaseQ", "LUDecomposition", "ManhattanDistance",
			"Map", "MapAll", "MapThread", "MatchQ", "MatrixForm", "MatrixPower", "MatrixQ", "MatrixRank", "Max", "Mean", "Median",
			"MemberQ", "Min", "Mod", "Module", "MoebiusMu", "MonomialList", "Most", "Multinomial", "N", "Negative", "Nest",
			"NestList", "NestWhile", "NestWhileList", "NextPrime", "NIntegrate", "NonCommutativeMultiply", "NonNegative", "Norm",
			"Not", "NRoots", "NSolve", "NullSpace", "NumberQ", "Numerator", "NumericQ", "OddQ", "Or", "Order", "OrderedQ", "Out",
			"Outer", "Package", "PadLeft", "PadRight", "ParametricPlot", "Part", "Partition", "Pattern", "Permutations", "Pi",
			"Plot", "Plot3D", "Plus", "Pochhammer", "PolynomialExtendedGCD", "PolynomialGCD", "PolynomialLCM", "PolynomialQ",
			"PolynomialQuotient", "PolynomialQuotientRemainder", "PolynomialRemainder", "Position", "Positive", "PossibleZeroQ",
			"Power", "PowerExpand", "PowerMod", "PreDecrement", "PreIncrement", "Prepend", "PrependTo", "PrimeQ", "PrimitiveRoots",
			"Print", "Product", "Quiet", "Quotient", "RandomInteger", "RandomReal", "Range", "Rational", "Rationalize", "Re",
			"Reap", "ReplaceAll", "ReplacePart", "ReplaceRepeated", "Rest", "Resultant", "Return", "Reverse", "Riffle",
			"RootIntervals", "Roots", "RotateLeft", "RotateRight", "Round", "RowReduce", "Rule", "RuleDelayed", "SameQ", "Scan",
			"Sec", "Sech", "Select", "Set", "SetAttributes", "SetDelayed", "Show", "Sign", "SignCmp", "Simplify", "Sin",
			"SingularValueDecomposition", "Sinh", "Solve", "Sort", "Sow", "Sqrt", "SquaredEuclidianDistance", "SquareFreeQ",
			"StirlingS2", "StringDrop", "StringJoin", "StringLength", "StringTake", "Subsets", "SubtractFrom", "Sum", "Switch",
			"SyntaxLength", "SyntaxQ", "Table", "Take", "Tan", "Tanh", "Taylor", "Thread", "Through", "Throw", "TimeConstrained",
			"Times", "TimesBy", "Timing", "ToCharacterCode", "Together", "ToString", "Total", "ToUnicode", "Tr", "Trace",
			"Transpose", "TrigExpand", "TrigReduce", "TrigToExp", "TrueQ", "Tuples", "Unequal", "Unevaluated", "Union", "Unique",
			"UnitStep", "UnsameQ", "UpperCaseQ", "UpSet", "UpSetDelayed", "ValueQ", "VandermondeMatrix", "Variables", "VectorQ",
			"Which", "While" };

	public static final Map PREDEFINED_SYMBOLS_MAP = new HashMap(997);

	private final static String[] ALIASES_STRINGS = { "ACos", "ASin", "ATan", "ACosh", "ASinh", "ATanh", "Diff", "I", "Infinity",
			"Int", "Trunc" };

	private final static IExpr[] ALIASES_SYMBOLS = { F.ArcCos, F.ArcSin, F.ArcTan, F.ArcCosh, F.ArcSinh, F.ArcTanh, F.D, F.CI,
			F.CInfinity, F.Integrate, F.IntegerPart };

	/**
	 * Aliases which are mapped to the standard function symbols.
	 */
	private static final Map PREDEFINED_ALIASES_MAP = new HashMap(97);

	public static final String LIST_STRING = Config.PARSER_USE_LOWERCASE_SYMBOLS ? "list" : "List";
	public static final String POWER_STRING = Config.PARSER_USE_LOWERCASE_SYMBOLS ? "power" : "Power";
	public static final String PLUS_STRING = Config.PARSER_USE_LOWERCASE_SYMBOLS ? "plus" : "Plus";
	public static final String TIMES_STRING = Config.PARSER_USE_LOWERCASE_SYMBOLS ? "times" : "Times";
	public static final String FALSE_STRING = Config.PARSER_USE_LOWERCASE_SYMBOLS ? "false" : "False";
	public static final String TRUE_STRING = Config.PARSER_USE_LOWERCASE_SYMBOLS ? "true" : "True";
	// public static final String PART_STRING =
	// Config.PARSER_USE_LOWERCASE_SYMBOLS ? "part" : "Part";
	// public static final String SLOT_STRING =
	// Config.PARSER_USE_LOWERCASE_SYMBOLS ? "slot" : "Slot";
	// public static final String HOLD_STRING =
	// Config.PARSER_USE_LOWERCASE_SYMBOLS ? "hold" : "Hold";
	// public static final String DIRECTEDINFINITY_STRING =
	// Config.PARSER_USE_LOWERCASE_SYMBOLS ? "directedinfinity"
	// : "DirectedInfinity";
	static {
		for (String str : FUNCTION_STRINGS) {
			PREDEFINED_SYMBOLS_MAP.put(str.toLowerCase(), str);
		}
		if (Config.PARSER_USE_LOWERCASE_SYMBOLS) {
			for (int i = 0; i < ALIASES_STRINGS.length; i++) {
				PREDEFINED_ALIASES_MAP.put(ALIASES_STRINGS[i].toLowerCase(), ALIASES_SYMBOLS[i]);
			}
		}
	}
	/**
	 * Typical instance of an ASTNode to IExpr converter
	 */
	public final static AST2Expr CONST = new AST2Expr();

	public final static AST2Expr CONST_LC = new AST2Expr(true);

	private boolean fLowercaseEnabled;

	/**
	 * 
	 * @param sType
	 * @param tType
	 * @deprecated
	 */
	public AST2Expr(final Class sType, final Class tType) {
		this(false);
	}

	public AST2Expr() {
		this(false);
	}

	public AST2Expr(boolean lowercaseEnabled) {
		super();
		fLowercaseEnabled = lowercaseEnabled;
	}

	/**
	 * Converts a parsed FunctionNode expression into an IAST expression
	 */
	public IAST convert(IAST ast, FunctionNode functionNode) throws ConversionException {
		ast.set(0, convert(functionNode.get(0)));
		for (int i = 1; i < functionNode.size(); i++) {
			ast.add(convert(functionNode.get(i)));
		}
		return ast;
	}

	/**
	 * Converts a parsed ASTNode expression into an IExpr expression
	 */
	public IExpr convert(ASTNode node) throws ConversionException {
		if (node == null) {
			return null;
		}
		// if (node instanceof Pattern2Node) {
		// throw new
		// UnsupportedOperationException("'__' pattern-matching expression not implemented");
		// }
		if (node instanceof Pattern3Node) {
			throw new UnsupportedOperationException("'___' pattern-matching expression not implemented");
		}
		if (node instanceof FunctionNode) {
			final FunctionNode functionNode = (FunctionNode) node;
			final IAST ast = F.ast(convert(functionNode.get(0)), functionNode.size(), false);
			for (int i = 1; i < functionNode.size(); i++) {
				ast.add(convert(functionNode.get(i)));
			}
			IExpr head = ast.head();
			if (ast.isASTSizeGE(F.GreaterEqual, 3)) {
				ISymbol compareHead = F.Greater;
				return rewriteLessGreaterAST(ast, compareHead);
			} else if (ast.isASTSizeGE(F.Greater, 3)) {
				ISymbol compareHead = F.GreaterEqual;
				return rewriteLessGreaterAST(ast, compareHead);
			} else if (ast.isASTSizeGE(F.LessEqual, 3)) {
				ISymbol compareHead = F.Less;
				return rewriteLessGreaterAST(ast, compareHead);
			} else if (ast.isASTSizeGE(F.Less, 3)) {
				ISymbol compareHead = F.LessEqual;
				return rewriteLessGreaterAST(ast, compareHead);
			} else if (head.equals(F.PatternHead)) {
				final IExpr expr = Pattern.CONST.evaluate(ast);
				if (expr != null) {
					return expr;
				}
			} else if (head.equals(F.BlankHead)) {
				final IExpr expr = Blank.CONST.evaluate(ast);
				if (expr != null) {
					return expr;
				}
			} else if (head.equals(F.Complex)) {
				final IExpr expr = Complex.CONST.evaluate(ast);
				if (expr != null) {
					return expr;
				}
			} else if (head.equals(F.Rational)) {
				final IExpr expr = Rational.CONST.evaluate(ast);
				if (expr != null) {
					return expr;
				}
			}
			return ast;
		}
		if (node instanceof SymbolNode) {
			String nodeStr = node.getString();
			if (Config.PARSER_USE_LOWERCASE_SYMBOLS) {
				nodeStr = nodeStr.toLowerCase();
				IExpr temp = PREDEFINED_ALIASES_MAP.get(nodeStr);
				if (temp != null) {
					return temp;
				}
				return F.$s(nodeStr);
			} else {
				if (fLowercaseEnabled) {
					nodeStr = nodeStr.toLowerCase();
					String temp = PREDEFINED_SYMBOLS_MAP.get(nodeStr);
					if (temp != null) {
						nodeStr = temp;
					}
				}

				if (nodeStr.equals("I")) {
					// special - convert on input
					return F.CI;
				} else if (nodeStr.equals("Infinity")) {
					// special - convert on input
					return F.CInfinity;
				}
				return F.$s(nodeStr);
			}
		}
		// because of inheritance check Pattern2Node before PatternNode
		if (node instanceof Pattern2Node) {
			final Pattern2Node p2n = (Pattern2Node) node;
			return F.$ps((ISymbol) convert(p2n.getSymbol()), convert(p2n.getConstraint()), p2n.isDefault());
		}
		if (node instanceof PatternNode) {
			final PatternNode pn = (PatternNode) node;
			return F.$p((ISymbol) convert(pn.getSymbol()), convert(pn.getConstraint()), pn.isDefault());
		}

		if (node instanceof IntegerNode) {
			final IntegerNode integerNode = (IntegerNode) node;
			final String iStr = integerNode.getString();
			if (iStr != null) {
				return F.integer(iStr, integerNode.getNumberFormat());
			}
			return F.integer(integerNode.getIntValue());
		}
		if (node instanceof FractionNode) {
			FractionNode fr = (FractionNode) node;
			if (fr.isSign()) {
				return F.fraction((IInteger) convert(fr.getNumerator()), (IInteger) convert(fr.getDenominator())).negate();
			}
			IInteger numerator = (IInteger) convert(((FractionNode) node).getNumerator());
			IInteger denominator = (IInteger) convert(((FractionNode) node).getDenominator());
			return F.Rational(numerator, denominator);
		}
		if (node instanceof StringNode) {
			return F.stringx(node.getString());
		}
		if (node instanceof FloatNode) {
			return F.num(node.getString());
		}

		return F.$s(node.toString());
	}

	/**
	 * Convert less or greter relations on input. Example: convert expressions like a to
	 * Less[a,b]&&LessEqual[b,c].
	 * 
	 * @param ast
	 * @param compareHead
	 * @return
	 */
	private IExpr rewriteLessGreaterAST(final IAST ast, ISymbol compareHead) {
		IExpr temp;
		boolean evaled = false;
		IAST andAST = F.ast(F.And);
		for (int i = 1; i < ast.size(); i++) {
			temp = ast.get(i);
			if (temp.isASTSizeGE(compareHead, 3)) {
				IAST lt = (IAST) temp;
				andAST.add(lt);
				ast.set(i, lt.get(lt.size() - 1));
				evaled = true;
			}
		}
		if (evaled) {
			andAST.add(ast);
			return andAST;
		} else {
			return ast;
		}
	}
}

 

Ads help maintain this website.