/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo 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 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.antar.expr.oldparser; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.io.StreamTokenizer; import java.io.StringReader; import java.util.Date; import java.util.Hashtable; import java.util.List; import java.util.Vector; import org.openflexo.antar.binding.Bindable; import org.openflexo.antar.expr.ArithmeticBinaryOperator; import org.openflexo.antar.expr.ArithmeticUnaryOperator; import org.openflexo.antar.expr.BinaryOperator; import org.openflexo.antar.expr.BinaryOperatorExpression; import org.openflexo.antar.expr.Constant; import org.openflexo.antar.expr.Expression; import org.openflexo.antar.expr.ExpressionGrammar; import org.openflexo.antar.expr.Function; import org.openflexo.antar.expr.Operator; import org.openflexo.antar.expr.OperatorNotSupportedException; import org.openflexo.antar.expr.SymbolicConstant; import org.openflexo.antar.expr.UnaryOperator; import org.openflexo.antar.expr.UnaryOperatorExpression; import org.openflexo.antar.expr.Variable; import org.openflexo.toolbox.Duration; import org.openflexo.toolbox.Duration.DurationStringConverter; import org.openflexo.xmlcode.StringEncoder.DateConverter; /* * Created on 4 janv. 2006 by sguerin * * Flexo Application Suite * (c) Denali 2003-2005 */ public class ExpressionParser { private ExpressionGrammar grammar; private DateConverter dateConverter = new DateConverter(); private DurationStringConverter durationConverter = new DurationStringConverter(); public ExpressionParser(ExpressionGrammar grammar) { super(); this.grammar = grammar; } public Expression parse(String aString, Bindable bindable) throws ParseException { String preprocessedString = preprocessString(aString); BufferedReader rdr = new BufferedReader(new StringReader(preprocessedString)); Token parsed = parse(rdr); return makeExpression(parsed, bindable); } // Perform some lexical checks... private String preprocessString(String aString) throws ParseException { StringBuffer returned = new StringBuffer(); if (aString.length() == 0) { throw new ParseException("Empty string"); } int parentLevel = 0; boolean escaping = false; char waitedEscapingEndChar = '?'; for (int i = 0; i < aString.length(); i++) { char c = aString.charAt(i); if (!escaping) { if (c == '\'') { escaping = true; waitedEscapingEndChar = '\''; } else if (c == '"') { escaping = true; waitedEscapingEndChar = '"'; } else if (c == '[') { escaping = true; waitedEscapingEndChar = ']'; } else if (c == '(') { parentLevel++; } else if (c == ')') { parentLevel--; } returned.append(c); } else { if (c == waitedEscapingEndChar) { escaping = false; } if (c == ']') { returned.append('['); // We use [] to embed date or duration representation } else { returned.append(c); } } } if (parentLevel != 0) { throw new ParseException("Unbalanced parenthesis: " + aString); } if (escaping) { throw new ParseException("Unbalanced escaping char : expecting " + waitedEscapingEndChar); } return returned.toString(); } /*public ParsedExpression parseExpression (String aString) throws ParseException { Token result = parse(aString); if (result instanceof ParsedExpression) return (ParsedExpression)result; throw new ParseException("Could not parse as an expression "+aString); } public Function parseFunction (String aString) throws ParseException { Token result = parse(aString); if (result instanceof Function) return (Function)result; throw new ParseException("Could not parse as an function "+aString); }*/ private StreamTokenizer initStreamTokenizer(Reader rdr) { // Always need to setup StreamTokenizer StreamTokenizer input = new StreamTokenizer(rdr); input.wordChars('_', '_'); input.quoteChar('['); for (UnaryOperator op : getAllSupportedUnaryOperators()) { try { considerAsOperator(getSymbol(op), input); considerAsOperator(getAlternativeSymbol(op), input); } catch (OperatorNotSupportedException e) { // Shoud not happen e.printStackTrace(); } } for (BinaryOperator op : getAllSupportedBinaryOperators()) { try { considerAsOperator(getSymbol(op), input); considerAsOperator(getAlternativeSymbol(op), input); } catch (OperatorNotSupportedException e) { // Shoud not happen e.printStackTrace(); } } /* input.ordinaryChar('/'); input.ordinaryChar('&'); input.ordinaryChar('!'); input.ordinaryChar('-');*/ return input; } private void considerAsOperator(String symbol, StreamTokenizer input) { if (symbol == null) { return; } // System.out.println("considerAsOperator: "+symbol); char firstChar = symbol.charAt(0); if (firstChar >= 'a' && firstChar <= 'z' || firstChar >= 'A' && firstChar <= 'Z') { // Ignore this } else { // System.out.println("Ordinary char: "+firstChar); input.ordinaryChar(firstChar); } } private Token parse(Reader rdr) throws ParseException { ListOfToken unparsedList = parseLevel(initStreamTokenizer(rdr)); if (unparsedList.size() == 1 && unparsedList.firstElement() instanceof Token) { return (Token) unparsedList.firstElement(); } try { return ParsedFunction.makeFunction(unparsedList); } catch (ParseException e) { return ParsedExpression.makeExpression(unparsedList); } } /** * Return a vector of AbstractToken (Operator,Word,Value) and Vector elements * * @return */ private ListOfToken parseLevel(StreamTokenizer input) throws ParseException { ListOfToken returned = new ListOfToken(); try { // Read input file and build array String currentInput = ""; boolean levelSeemsToBeFinished = false; boolean prefixedBy$ = false; while (!levelSeemsToBeFinished && input.nextToken() != StreamTokenizer.TT_EOF) { // System.out.println("currentInput="+currentInput+" input="+input); if (input.ttype == StreamTokenizer.TT_WORD) { // System.out.println("Found string: "+ input.sval); handlesCurrentInput(returned, currentInput); currentInput = ""; handlesWordAddition(returned, input.sval); } else if (input.ttype == StreamTokenizer.TT_NUMBER) { // System.out.println("Found double: "+ input.nval); handlesCurrentInput(returned, currentInput); currentInput = ""; double valueAsDouble = input.nval; if (valueAsDouble < 0) { if (returned.size() > 0 && returned.lastElement() != null && (returned.lastElement() instanceof Value || returned.lastElement() instanceof Word)) { returned.add(new ParsedOperator(ArithmeticBinaryOperator.SUBSTRACTION, this)); } else { returned.add(new ParsedOperator(ArithmeticUnaryOperator.UNARY_MINUS, this)); } valueAsDouble = -valueAsDouble; } Value value = Value.createValue(valueAsDouble); value.setPrefixedBy$(prefixedBy$); returned.add(value); prefixedBy$ = false; } // looks for quotes indicating delimited strings else if (input.ttype == '[') { // Then the string will be in the sval field // System.out.println("Found delimited string: "+ input.sval); handlesCurrentInput(returned, currentInput); currentInput = ""; // Is it a date or a duration ? String parseThis = input.sval; try { Date parsedDate = dateConverter.tryToConvertFromString(parseThis); DateValue value = DateValue.createDateValue(parsedDate); value.setPrefixedBy$(prefixedBy$); returned.add(value); prefixedBy$ = false; } catch (java.text.ParseException cannotParseAsADate) { // Lets continue... try { Duration parsedDuration = durationConverter.tryToConvertFromString(parseThis); DurationValue value = DurationValue.createDurationValue(parsedDuration); value.setPrefixedBy$(prefixedBy$); returned.add(value); prefixedBy$ = false; } catch (java.text.ParseException cannotParseAsADurationEither) { Value value = StringValue.createStringValue("<unparsable>"); value.setPrefixedBy$(prefixedBy$); returned.add(value); prefixedBy$ = false; } } } else if (input.ttype == '"') { // Then the string will be in the sval field // System.out.println("Found delimited string: "+ input.sval); handlesCurrentInput(returned, currentInput); currentInput = ""; // handlesWordAddition(returned,input.sval); Value value = StringValue.createStringValue(input.sval); value.setPrefixedBy$(prefixedBy$); returned.add(value); prefixedBy$ = false; } else if (input.ttype == '\'') { // Then the string will be in the sval field // System.out.println("Found delimited string: "+ input.sval); handlesCurrentInput(returned, currentInput); currentInput = ""; // handlesWordAddition(returned,input.sval); Value value; if (input.sval.length() == 0) { value = CharValue.createCharValue(input.sval.charAt(0)); } else { value = StringValue.createStringValue(input.sval); } value.setPrefixedBy$(prefixedBy$); returned.add(value); prefixedBy$ = false; } else if (input.ttype == '$') { // Then the string will be in the sval field // System.out.println("Found delimited string: "+ input.sval); handlesCurrentInput(returned, currentInput); currentInput = ""; prefixedBy$ = true; } else { char foundChar = (char) input.ttype; // System.out.println("Found Ordinry Character: "+ foundChar); if (foundChar == '(') { handlesCurrentInput(returned, currentInput); currentInput = ""; returned.add(parseLevel(input)); } else if (foundChar == ')') { levelSeemsToBeFinished = true; } else { currentInput = currentInput + foundChar; } } } handlesCurrentInput(returned, currentInput); currentInput = ""; // System.out.println("Done"); return returned; } catch (IOException exception) { throw new ParseException("IOException occured: " + exception.getMessage()); } } private void handlesCurrentInput(Vector<AbstractToken> returned, String currentInput) throws ParseException { if (currentInput.equals("")) { return; } if (currentInput.equals(",")) { returned.add(new Comma()); return; } ParsedOperator operator = matchOperator(currentInput); if (operator != null) { returned.add(operator); } else { throw new ParseException("Invalid characters : " + currentInput); } } private void handlesWordAddition(Vector<AbstractToken> returned, String word) throws ParseException { if (word.equals("")) { return; } if (word.equalsIgnoreCase("true") || word.equalsIgnoreCase("yes")) { returned.add(new BooleanValue(true)); } else if (word.equalsIgnoreCase("false") || word.equalsIgnoreCase("no")) { returned.add(new BooleanValue(false)); } else if (matchOperator(word) != null) { returned.add(matchOperator(word)); } else { returned.add(new Word(word)); } } private ParsedOperator matchOperator(String anInput) { UnaryOperator unaryOperator = matchUnaryOperator(anInput); BinaryOperator binaryOperator = matchBinaryOperator(anInput); if (unaryOperator != null) { if (binaryOperator != null) { // Ambigous operator return new ParsedOperator(unaryOperator, binaryOperator, this); } else { return new ParsedOperator(unaryOperator, this); } } else { if (binaryOperator != null) { return new ParsedOperator(binaryOperator, this); } } return null; } private UnaryOperator matchUnaryOperator(String anInput) { for (UnaryOperator operator : getAllSupportedUnaryOperators()) { try { if (anInput.toUpperCase().equalsIgnoreCase(getSymbol(operator)) || getAlternativeSymbol(operator) != null && anInput.toUpperCase().equalsIgnoreCase(getAlternativeSymbol(operator))) { return operator; } } catch (OperatorNotSupportedException e) { // This operator is not supported, skip tracking for this one } } return null; } private BinaryOperator matchBinaryOperator(String anInput) { for (BinaryOperator operator : getAllSupportedBinaryOperators()) { try { if (anInput.toUpperCase().equalsIgnoreCase(getSymbol(operator)) || getAlternativeSymbol(operator) != null && anInput.toUpperCase().equalsIgnoreCase(getAlternativeSymbol(operator))) { return operator; } } catch (OperatorNotSupportedException e) { // This operator is not supported, skip tracking for this one } } return null; } private Expression makeExpression(Token parsed, Bindable bindable) throws ParseException { if (parsed instanceof Word) { for (SymbolicConstant c : SymbolicConstant.allKnownSymbolicConstants) { if (((Word) parsed).getValue().equalsIgnoreCase(c.getSymbol())) { return (Constant) c; } } return _variableFactory.makeVariable((Word) parsed, bindable); } else if (parsed instanceof Value) { return _constantFactory.makeConstant((Value) parsed, bindable); } else if (parsed instanceof ParsedFunction) { ParsedFunction f = (ParsedFunction) parsed; Vector<Expression> args = new Vector<Expression>(); for (Token t : f.getParameters()) { args.add(makeExpression(t, bindable)); } return _functionFactory.makeFunction(f.getCall().getValue(), args, bindable); } else if (parsed instanceof ParsedBinaryExpression) { ParsedBinaryExpression e = (ParsedBinaryExpression) parsed; return new BinaryOperatorExpression(e.getBinaryOperator(), makeExpression(e.getLeftOperand(), bindable), makeExpression( e.getRightOperand(), bindable)); } else if (parsed instanceof ParsedUnaryExpression) { ParsedUnaryExpression e = (ParsedUnaryExpression) parsed; return new UnaryOperatorExpression(e.getUnaryOperator(), makeExpression(e.getOperand(), bindable)); } throw new ParseException("Parse error: unexpected token found"); } protected BinaryOperator[] getAllSupportedBinaryOperators() { return grammar.getAllSupportedBinaryOperators(); } protected UnaryOperator[] getAllSupportedUnaryOperators() { return grammar.getAllSupportedUnaryOperators(); } protected String getAlternativeSymbol(Operator operator) throws OperatorNotSupportedException { return grammar.getAlternativeSymbol(operator); } protected String getSymbol(Operator operator) throws OperatorNotSupportedException { return grammar.getSymbol(operator); } public static interface VariableFactory { public Expression makeVariable(Word value, Bindable bindable); } public static class DefaultVariableFactory implements VariableFactory { private Hashtable<String, Variable> hash = new Hashtable<String, Variable>(); @Override public Variable makeVariable(Word value, Bindable bindable) { Variable returned = hash.get(value.getValue()); if (returned == null) { returned = new Variable(value.getValue()); hash.put(value.getValue(), returned); } return returned; } } public static interface ConstantFactory { public Expression makeConstant(Value value, Bindable bindable); } public static class DefaultConstantFactory implements ConstantFactory { @Override public Constant makeConstant(Value value, Bindable bindable) { if (value == null) { return /*Constant.ObjectSymbolicConstant.NULL;*/new Constant.StringConstant("null"); } if (value instanceof BooleanValue) { if (((BooleanValue) value).getBooleanValue()) { return Constant.BooleanConstant.TRUE; } else { return Constant.BooleanConstant.FALSE; } } else if (value instanceof CharValue) { return new Constant.StringConstant(((CharValue) value).getStringValue()); } else if (value instanceof StringValue) { return new Constant.StringConstant(((StringValue) value).getStringValue()); } else if (value instanceof EnumValue) { return new Constant.EnumConstant(((EnumValue) value).getStringValue()); } else if (value instanceof FloatValue) { return new Constant.FloatConstant(((FloatValue) value).getDoubleValue()); } else if (value instanceof IntValue) { return new Constant.IntegerConstant(((IntValue) value).getIntValue()); } else if (value instanceof DateValue) { return new Constant.DateConstant(((DateValue) value).getDateValue()); } else if (value instanceof DurationValue) { return new Constant.DurationConstant(((DurationValue) value).getDurationValue()); } else if (value != null) { return new Constant.StringConstant(value.toString()); } return new Constant.StringConstant(""); } } public static interface FunctionFactory { public Expression makeFunction(String functionName, List<Expression> args, Bindable bindable); } public static class DefaultFunctionFactory implements FunctionFactory { @Override public Function makeFunction(String functionName, List<Expression> args, Bindable bindable) { return new Function(functionName, args); } } private ConstantFactory _constantFactory = new DefaultConstantFactory(); private VariableFactory _variableFactory = new DefaultVariableFactory(); private FunctionFactory _functionFactory = new DefaultFunctionFactory(); public ConstantFactory getConstantFactory() { return _constantFactory; } public void setConstantFactory(ConstantFactory constantFactory) { _constantFactory = constantFactory; } public FunctionFactory getFunctionFactory() { return _functionFactory; } public void setFunctionFactory(FunctionFactory functionFactory) { _functionFactory = functionFactory; } public VariableFactory getVariableFactory() { return _variableFactory; } public void setVariableFactory(VariableFactory variableFactory) { _variableFactory = variableFactory; } }