private Ref unaryOp() throws PageException { Ref ref = negateMinusOp(); if (cfml.forwardIfCurrent("--")) ref = _unaryOp(ref, false); else if (cfml.forwardIfCurrent("++")) ref = _unaryOp(ref, true); return ref; }
/** * Liest einen Identifier aus und gibt diesen als String zurck. <br> * EBNF:<br> * <code>(letter | "_") {letter | "_"|digit};</code> * * @param firstCanBeNumber * @return Identifier. */ private String identifier(boolean firstCanBeNumber) { // int start = cfml.getPos(); if (!cfml.isCurrentLetter() && !cfml.isCurrentSpecial()) { if (!firstCanBeNumber) return null; else if (!cfml.isCurrentDigit()) return null; } StringBuffer sb = new StringBuffer(); // if(CASE_TYPE_UPPER==caseType) sb.append(cfml.getCurrentUpper()); /*else if(CASE_TYPE_ORIGINAL==caseType) sb.append(cfml.getCurrent()); else sb.append(cfml.getCurrentLower());*/ do { cfml.next(); if (!(cfml.isCurrentLetter() || cfml.isCurrentDigit() || cfml.isCurrentSpecial())) { break; } // if(CASE_TYPE_UPPER==caseType) sb.append(cfml.getCurrentUpper()); /*else if(CASE_TYPE_ORIGINAL==caseType) sb.append(cfml.getCurrent()); else sb.append(cfml.getCurrentLower());*/ } while (cfml.isValidIndex()); return sb.toString(); // cfml.substringLower(start,cfml.getPos()-start); }
/** * Transfomiert eine Implication (imp) Operation. <br> * EBNF:<br> * <code>eqvOp {"imp" spaces eqvOp};</code> * * @return CFXD Element * @throws PageException */ private Ref impOp() throws PageException { Ref ref = eqvOp(); while (cfml.forwardIfCurrentAndNoWordAfter("imp")) { cfml.removeSpace(); ref = new Imp(ref, eqvOp()); } return ref; }
/** * Liest die reinen Zahlen innerhalb des CFMLString aus und gibt diese als Zeichenkette zurck. * <br> * EBNF:<br> * <code>"0"|..|"9";</code> * * @param rtn */ private void digit(StringBuffer rtn) { while (cfml.isValidIndex()) { if (!cfml.isCurrentDigit()) break; rtn.append(cfml.getCurrentLower()); cfml.next(); } }
/** * Transfomiert eine Xor (xor) Operation. <br> * EBNF:<br> * <code>orOp {"xor" spaces orOp};</code> * * @return CFXD Element * @throws PageException */ private Ref xorOp() throws PageException { Ref ref = orOp(); while (cfml.forwardIfCurrent("xor")) { cfml.removeSpace(); ref = new Xor(ref, orOp()); } return ref; }
/** * Transfomiert eine Or (or) Operation. Im Gegensatz zu CFMX , werden "||" Zeichen auch als Or * Operatoren anerkannt. <br> * EBNF:<br> * <code>andOp {("or" | "||") spaces andOp}; (* "||" Existiert in CFMX nicht *)</code> * * @return CFXD Element * @throws PageException */ private Ref orOp() throws PageException { Ref ref = andOp(); while (cfml.isValidIndex() && (cfml.forwardIfCurrent("||") || cfml.forwardIfCurrent("or"))) { cfml.removeSpace(); ref = new Or(ref, andOp()); } return ref; }
/** * Transfomiert eine And (and) Operation. Im Gegensatz zu CFMX , werden "&&" Zeichen auch als And * Operatoren anerkannt. <br> * EBNF:<br> * <code>notOp {("and" | "&&") spaces notOp}; (* "&&" Existiert in CFMX nicht *)</code> * * @return CFXD Element * @throws PageException */ private Ref andOp() throws PageException { Ref ref = notOp(); while (cfml.isValidIndex() && (cfml.forwardIfCurrent("&&") || cfml.forwardIfCurrent("and"))) { cfml.removeSpace(); ref = new And(ref, notOp()); } return ref; }
/** * Liest einen gelableten Funktionsparamter ein <br> * EBNF:<br> * <code>assignOp [":" spaces assignOp];</code> * * @return CFXD Element * @throws PageException */ private Ref functionArgDeclaration() throws PageException { Ref ref = impOp(); if (cfml.forwardIfCurrent(':') || cfml.forwardIfCurrent('=')) { cfml.removeSpace(); ref = new LFunctionValue(ref, assignOp()); } return ref; }
/** * Transfomiert eine Equivalence (eqv) Operation. <br> * EBNF:<br> * <code>xorOp {"eqv" spaces xorOp};</code> * * @return CFXD Element * @throws PageException */ private Ref eqvOp() throws PageException { Ref ref = xorOp(); while (cfml.forwardIfCurrent("eqv")) { cfml.removeSpace(); ref = new EQV(ref, xorOp()); } return ref; }
/** * Transfomiert den Exponent Operator (^,exp). Im Gegensatz zu CFMX , werden die Zeichen " exp " * auch als Exponent anerkannt. <br> * EBNF:<br> * <code>clip {("exp"|"^") spaces clip};</code> * * @return CFXD Element * @throws PageException */ private Ref expoOp() throws PageException { Ref ref = unaryOp(); while (cfml.isValidIndex() && (cfml.forwardIfCurrent('^') || cfml.forwardIfCurrent("exp"))) { cfml.removeSpace(); ref = new Exp(ref, unaryOp()); } return ref; }
/** * Transfomiert einen numerische Wert. Die L¦nge des numerischen Wertes interessiert nicht zu * ᅵbersetzungszeit, ein "Overflow" fhrt zu einem Laufzeitfehler. Da die zu erstellende CFXD, * bzw. dieser Transfomer, keine Vorwegnahme des Laufzeitsystems vornimmt. <br> * EBNF:<br> * <code>["+"|"-"] digit {digit} {"." digit {digit}};</code> * * @return CFXD Element * @throws PageException */ private Ref number() throws PageException { // check first character is a number literal representation // if(!cfml.isCurrentDigit()) return null; StringBuffer rtn = new StringBuffer(6); // get digit on the left site of the dot if (cfml.isCurrent('.')) rtn.append('0'); else digit(rtn); // read dot if exist if (cfml.forwardIfCurrent('.')) { rtn.append('.'); int before = cfml.getPos(); digit(rtn); if (before < cfml.getPos() && cfml.forwardIfCurrent('e')) { if (cfml.isCurrentDigit()) { rtn.append('e'); digit(rtn); } else { cfml.previous(); } } // read right side of the dot if (before == cfml.getPos()) throw new ExpressionException("Number can't end with [.]"); // rtn.append(rightSite); } cfml.removeSpace(); mode = STATIC; return new LNumber(rtn.toString()); }
/** * Transfomiert eine Modulus Operation. Im Gegensatz zu CFMX , wird das "%" Zeichen auch als * Modulus Operator anerkannt. <br> * EBNF:<br> * <code> * divMultiOp {("mod" | "%") spaces divMultiOp}; (* modulus operator , "%" Existiert in CFMX nicht *) * </code> * * @return CFXD Element * @throws PageException */ private Ref modOp() throws PageException { Ref ref = divMultiOp(); while (cfml.isValidIndex() && (cfml.forwardIfCurrent('%') || cfml.forwardIfCurrent("mod"))) { ref = _mod(ref); // cfml.removeSpace(); // ref=new Mod(ref,divMultiOp()); } return ref; }
/** * Sharps (#) die innerhalb von Expressions auftauchen haben in CFML keine weitere Beteutung und * werden durch diese Methode einfach entfernt. <br> * Beispiel:<br> * <code>arrayLen(#arr#)</code> und <code>arrayLen(arr)</code> sind identisch. EBNF:<br> * <code>"#" checker "#";</code> * * @return CFXD Element * @throws PageException */ private Ref sharp() throws PageException { if (!cfml.forwardIfCurrent('#')) return null; Ref ref; cfml.removeSpace(); ref = assignOp(); cfml.removeSpace(); if (!cfml.forwardIfCurrent('#')) throw new ExpressionException("Syntax Error, Invalid Construct"); cfml.removeSpace(); return ref; }
/** * Transfomiert eine Konkatinations-Operator (&) Operation. Im Gegensatz zu CFMX , wird das "!" * Zeichen auch als Not Operator anerkannt. <br> * EBNF:<br> * <code>plusMinusOp {"&" spaces concatOp};</code> * * @return CFXD Element * @throws PageException */ private Ref concatOp() throws PageException { Ref ref = plusMinusOp(); while (cfml.isCurrent('&') && !cfml.isNext('&')) { cfml.next(); ref = _concat(ref); // cfml.removeSpace(); // ref=new Concat(pc,ref,plusMinusOp()); } return ref; }
private Ref _concat(Ref ref) throws PageException { // &= if (cfml.forwardIfCurrent('=')) { cfml.removeSpace(); Ref right = assignOp(); Ref res = new Concat(pc, ref, right); ref = new Assign(ref, res); } else { cfml.removeSpace(); ref = new Concat(pc, ref, plusMinusOp()); } return ref; }
/** * Transfomiert Zuweisungs Operation. <br> * EBNF:<br> * <code>eqvOp ["=" spaces assignOp];</code> * * @return CFXD Element * @throws PageException */ protected Ref assignOp() throws PageException { Ref ref = contOp(); if (cfml.forwardIfCurrent('=')) { cfml.removeSpace(); if (mode == STATIC || ref instanceof Literal) { ref = new DynAssign(pc, ref, assignOp()); } else { ref = new Assign(ref, assignOp()); } } return ref; }
private Ref _multi(Ref ref) throws PageException { // \= if (cfml.forwardIfCurrent('=')) { cfml.removeSpace(); Ref right = assignOp(); Ref res = new Multi(ref, right); ref = new Assign(ref, res); } else { cfml.removeSpace(); ref = new Multi(ref, expoOp()); } return ref; }
private Ref contOp() throws PageException { Ref ref = impOp(); while (cfml.forwardIfCurrent('?')) { cfml.removeSpace(); Ref left = assignOp(); if (!cfml.forwardIfCurrent(':')) throw new ExpressionException( "Syntax Error, invalid conditional operator [" + cfml.toString() + "]"); cfml.removeSpace(); Ref right = assignOp(); ref = new Cont(ref, left, right); } return ref; }
/** * Liest den folgenden idetifier ein und prft ob dieser ein boolscher Wert ist. Im Gegensatz zu * CFMX wird auch "yes" und "no" als bolscher <wert akzeptiert, was bei CFMX nur beim Umwandeln * einer Zeichenkette zu einem boolschen Wert der Fall ist.<br> * Wenn es sich um keinen bolschen Wert handelt wird der folgende Wert eingelesen mit seiner * ganzen Hirarchie. <br> * EBNF:<br> * <code>"true" | "false" | "yes" | "no" | startElement * {("." identifier | "[" structElement "]" )[function] };</code> * * @return CFXD Element * @throws PageException */ private Ref dynamic() throws PageException { // Die Implementation weicht ein wenig von der Grammatik ab, // aber nicht in der Logik sondern rein wie es umgesetzt wurde. // get First Element of the Variable String name = identifier(false); if (name == null) { if (!cfml.forwardIfCurrent('(')) return null; cfml.removeSpace(); Ref ref = assignOp(); if (!cfml.forwardIfCurrent(')')) throw new ExpressionException("Invalid Syntax Closing [)] not found"); cfml.removeSpace(); return subDynamic(ref); } // Element el; cfml.removeSpace(); char first = name.charAt(0); // Boolean constant if (first == 'T' && name.equals("TRUE")) { cfml.removeSpace(); return LBoolean.TRUE; } else if (first == 'F' && name.equals("FALSE")) { cfml.removeSpace(); return LBoolean.FALSE; } else if (first == 'Y' && name.equals("YES")) { cfml.removeSpace(); return LBoolean.TRUE; } else if (first == 'N') { if (name.equals("NO")) { cfml.removeSpace(); return LBoolean.FALSE; } else if (allowNullConstant && name.equals("NULL")) { cfml.removeSpace(); return new LString(null); } else if (name.equals("NEW")) { Ref res = newOp(); if (res != null) return res; } } // Extract Scope from the Variable // Object value = startElement(name); return subDynamic(startElement(name)); }
private Ref subDynamic(Ref ref) throws PageException { String name = null; // Loop over nested Variables while (cfml.isValidIndex()) { // . if (cfml.forwardIfCurrent('.')) { // Extract next Var String cfml.removeSpace(); name = identifier(true); if (name == null) throw new ExpressionException("Invalid identifier"); cfml.removeSpace(); ref = new Variable(pc, ref, name); } // [] else if (cfml.forwardIfCurrent('[')) { cfml.removeSpace(); ref = new Variable(pc, ref, assignOp()); cfml.removeSpace(); if (!cfml.forwardIfCurrent(']')) throw new ExpressionException("Invalid Syntax Closing []] not found"); } // finish else { break; } cfml.removeSpace(); if (cfml.isCurrent('(')) { if (!(ref instanceof Set)) throw new ExpressionException( "invalid syntax " + ref.getTypeName() + " can't called as function"); Set set = (Set) ref; ref = new UDFCall(pc, set.getParent(), set.getKey(), functionArg(name, false, null, ')')); } } if (ref instanceof railo.runtime.interpreter.ref.var.Scope) { railo.runtime.interpreter.ref.var.Scope s = (railo.runtime.interpreter.ref.var.Scope) ref; if (s.getScope() == Scope.SCOPE_ARGUMENTS || s.getScope() == Scope.SCOPE_LOCAL || s.getScope() == ScopeSupport.SCOPE_VAR) { ref = new Bind(s); } } return ref; }
/** * Wird aufgerufen um aus dem bergebenen CFMLString einen Ausdruck auszulesen und diese zu * interpretieren. <br> * Beispiel eines bergebenen String:<br> * <code>session.firstName</code> oder <code>trim(left('test'&var1,3))</code> <br> * EBNF:<br> * <code>spaces impOp;</code> * * @param pc * @param cfml * @return * @throws PageException */ public Object interpret(PageContext pc, ParserString cfml) throws PageException { this.cfml = cfml; this.pc = pc; if (pc != null) fld = ((ConfigImpl) pc.getConfig()).getCombinedFLDs(); if (JSON_ARRAY == null) JSON_ARRAY = fld.getFunction("_jsonArray"); if (JSON_STRUCT == null) JSON_STRUCT = fld.getFunction("_jsonStruct"); cfml.removeSpace(); Ref ref = assignOp(); cfml.removeSpace(); if (cfml.isAfterLast()) { return ref.getValue(); } throw new ExpressionException("Syntax Error, invalid Expression [" + cfml.toString() + "]"); }
protected Object interpretPart(PageContext pc, ParserString cfml) throws PageException { this.cfml = cfml; this.pc = pc; if (pc != null) fld = ((ConfigImpl) pc.getConfig()).getCombinedFLDs(); cfml.removeSpace(); return assignOp().getValue(); }
/** * Transfomiert die mathematischen Operatoren Mal und Durch (*,/). <br> * EBNF:<br> * <code>expoOp {("*"|"/") spaces expoOp};</code> * * @return CFXD Element * @throws PageException */ private Ref divMultiOp() throws PageException { Ref ref = expoOp(); while (!cfml.isLast()) { // Multiply Operation if (cfml.forwardIfCurrent('*')) { ref = _multi(ref); // cfml.removeSpace(); // ref=new Multi(ref,expoOp()); } // Divide Operation else if (cfml.isCurrent('/') && (!cfml.isCurrent("/>"))) { cfml.next(); ref = _div(ref); // cfml.removeSpace(); // ref=new Div(ref,expoOp()); } // Divide Operation else if (cfml.isCurrent('\\')) { cfml.next(); ref = _intdiv(ref); // cfml.removeSpace(); // ref=new IntDiv(ref,expoOp()); } else { break; } } return ref; }
/** * Transfomiert die mathematischen Operatoren Plus und Minus (1,-). <br> * EBNF:<br> * <code>modOp [("-"|"+") spaces plusMinusOp];</code> * * @return CFXD Element * @throws PageException */ private Ref plusMinusOp() throws PageException { Ref ref = modOp(); while (!cfml.isLast()) { // Plus Operation if (cfml.forwardIfCurrent('+')) { ref = _plus(ref); // cfml.removeSpace(); // ref=new Plus(ref,modOp()); } // Minus Operation else if (cfml.forwardIfCurrent('-')) { ref = _minus(ref); // cfml.removeSpace(); // ref=new Minus(ref,modOp()); } else break; } return ref; }
protected Ref json(FunctionLibFunction flf, char start, char end) throws PageException { // print.out("start:"+start+":"+cfml.getCurrent()); if (!cfml.isCurrent(start)) return null; Ref[] args = functionArg(flf.getName(), false, flf, end); // if (!cfml.forwardIfCurrent(end)) // throw new ExpressionException("Invalid Syntax Closing ["+end+"] not found"); return new BIFCall(pc, flf, args); }
private Ref _minus(Ref ref) throws PageException { // -= if (cfml.isCurrent('=')) { cfml.next(); cfml.removeSpace(); Ref right = assignOp(); Ref res = new Minus(ref, right); ref = new Assign(ref, res); } /*/ -- else if (cfml.isCurrent('-')) { cfml.next(); cfml.removeSpace(); Ref res = new Minus(ref,new LNumber(new Double(1))); ref=new Assign(ref,res); ref=new Plus(ref,new LNumber(new Double(1))); }*/ else { cfml.removeSpace(); ref = new Minus(ref, modOp()); } return ref; }
/** * Transfomiert eine Not (not) Operation. Im Gegensatz zu CFMX , wird das "!" Zeichen auch als Not * Operator anerkannt. <br> * EBNF:<br> * <code>[("not"|"!") spaces] decsionOp; (* "!" Existiert in CFMX nicht *)</code> * * @return CFXD Element * @throws PageException */ private Ref notOp() throws PageException { if (cfml.isValidIndex()) { if (cfml.isCurrent('!') && !cfml.isCurrent("!=")) { cfml.next(); cfml.removeSpace(); return new Not(decsionOp()); } else if (cfml.forwardIfCurrentAndNoWordAfter("not")) { cfml.removeSpace(); return new Not(decsionOp()); } } return decsionOp(); }
/** * Extrahiert den Start Element einer Variale, dies ist entweder eine Funktion, eine Scope * Definition oder eine undefinierte Variable. <br> * EBNF:<br> * <code>identifier "(" functionArg ")" | scope | identifier;</code> * * @param name Einstiegsname * @return CFXD Element * @throws PageException */ private Ref startElement(String name) throws PageException { // check function if (cfml.isCurrent('(')) { FunctionLibFunction function = fld.getFunction(name); Ref[] arguments = functionArg(name, true, function, ')'); // print.out(name+":"+(function!=null)); if (function != null) return new BIFCall(pc, function, arguments); Ref ref = new railo.runtime.interpreter.ref.var.Scope(pc, Scope.SCOPE_UNDEFINED); return new UDFCall(pc, ref, name, arguments); } // check scope return scope(name); }
/** * Liest einen CFML Scope aus, falls der folgende identifier keinem Scope entspricht, gibt die * Variable null zurck. <br> * EBNF:<br> * <code> * "variable" | "cgi" | "url" | "form" | "session" | "application" | "arguments" | "cookie" | " client"; * </code> * * @param idStr String identifier, wird aus Optimierungszwechen nicht innerhalb dieser Funktion * ausgelsen. * @return CFXD Variable Element oder null */ private Ref scope(String idStr) { if (idStr.equals("var")) { String name = identifier(false); if (name != null) { cfml.removeSpace(); return new Variable( pc, new railo.runtime.interpreter.ref.var.Scope(pc, ScopeSupport.SCOPE_VAR), name); } } int scope = VariableInterpreter.scopeString2Int(idStr); if (scope == Scope.SCOPE_UNDEFINED) { return new Variable( pc, new railo.runtime.interpreter.ref.var.Scope(pc, Scope.SCOPE_UNDEFINED), idStr); } return new railo.runtime.interpreter.ref.var.Scope(pc, scope); }
/** * Liest einen gelableten Funktionsparamter ein <br> * EBNF:<br> * <code>assignOp [":" spaces assignOp];</code> * * @return CFXD Element * @throws PageException */ private Ref functionArgDeclarationVarString() throws PageException { cfml.removeSpace(); StringBuffer str = new StringBuffer(); String id = null; while ((id = identifier(false)) != null) { if (str.length() > 0) str.append('.'); str.append(id); cfml.removeSpace(); if (!cfml.forwardIfCurrent('.')) break; cfml.removeSpace(); } cfml.removeSpace(); if (str.length() > 0 && cfml.charAt(cfml.getPos() - 1) != '.') return new LString(str.toString()); throw new ExpressionException("invalid variable name definition"); }