You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049
  1. /*
  2. Copyright (c) 2016 James Ahlborn
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package com.healthmarketscience.jackcess.impl.expr;
  14. import java.math.BigDecimal;
  15. import java.text.DateFormat;
  16. import java.text.SimpleDateFormat;
  17. import java.util.ArrayList;
  18. import java.util.Arrays;
  19. import java.util.Collections;
  20. import java.util.Date;
  21. import java.util.Deque;
  22. import java.util.HashMap;
  23. import java.util.HashSet;
  24. import java.util.Iterator;
  25. import java.util.LinkedList;
  26. import java.util.List;
  27. import java.util.Map;
  28. import java.util.Set;
  29. import java.util.regex.Pattern;
  30. import java.util.regex.PatternSyntaxException;
  31. import com.healthmarketscience.jackcess.DatabaseBuilder;
  32. import com.healthmarketscience.jackcess.expr.EvalContext;
  33. import com.healthmarketscience.jackcess.expr.Expression;
  34. import com.healthmarketscience.jackcess.expr.Function;
  35. import com.healthmarketscience.jackcess.expr.TemporalConfig;
  36. import com.healthmarketscience.jackcess.expr.ParseException;
  37. import com.healthmarketscience.jackcess.expr.Value;
  38. import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.Token;
  39. import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.TokenType;
  40. /**
  41. *
  42. * @author James Ahlborn
  43. */
  44. public class Expressionator
  45. {
  46. // Useful links:
  47. // - syntax: https://support.office.com/en-us/article/Guide-to-expression-syntax-ebc770bc-8486-4adc-a9ec-7427cce39a90
  48. // - examples: https://support.office.com/en-us/article/Examples-of-expressions-d3901e11-c04e-4649-b40b-8b6ec5aed41f
  49. // - validation rule usage: https://support.office.com/en-us/article/Restrict-data-input-by-using-a-validation-rule-6c0b2ce1-76fa-4be0-8ae9-038b52652320
  50. public enum Type {
  51. DEFAULT_VALUE, EXPRESSION, FIELD_VALIDATOR, RECORD_VALIDATOR;
  52. }
  53. public interface ParseContext {
  54. public TemporalConfig getTemporalConfig();
  55. public SimpleDateFormat createDateFormat(String formatStr);
  56. public Function getExpressionFunction(String name);
  57. }
  58. public static final ParseContext DEFAULT_PARSE_CONTEXT = new ParseContext() {
  59. public TemporalConfig getTemporalConfig() {
  60. return TemporalConfig.US_TEMPORAL_CONFIG;
  61. }
  62. public SimpleDateFormat createDateFormat(String formatStr) {
  63. return DatabaseBuilder.createDateFormat(formatStr);
  64. }
  65. public Function getExpressionFunction(String name) {
  66. return DefaultFunctions.getFunction(name);
  67. }
  68. };
  69. private enum WordType {
  70. OP, COMP, LOG_OP, CONST, SPEC_OP_PREFIX, DELIM;
  71. }
  72. private static final String FUNC_START_DELIM = "(";
  73. private static final String FUNC_END_DELIM = ")";
  74. private static final String OPEN_PAREN = "(";
  75. private static final String CLOSE_PAREN = ")";
  76. private static final String FUNC_PARAM_SEP = ",";
  77. private static final Map<String,WordType> WORD_TYPES =
  78. new HashMap<String,WordType>();
  79. static {
  80. setWordType(WordType.OP, "+", "-", "*", "/", "\\", "^", "&", "mod");
  81. setWordType(WordType.COMP, "<", "<=", ">", ">=", "=", "<>");
  82. setWordType(WordType.LOG_OP, "and", "or", "eqv", "xor", "imp");
  83. setWordType(WordType.CONST, "true", "false", "null");
  84. setWordType(WordType.SPEC_OP_PREFIX, "is", "like", "between", "in", "not");
  85. // "X is null", "X is not null", "X like P", "X between A and B",
  86. // "X not between A and B", "X in (A, B, C...)", "X not in (A, B, C...)",
  87. // "not X"
  88. setWordType(WordType.DELIM, ".", "!", ",", "(", ")");
  89. }
  90. private interface OpType {}
  91. private enum UnaryOp implements OpType {
  92. NEG("-", false) {
  93. @Override public Value eval(EvalContext ctx, Value param1) {
  94. return BuiltinOperators.negate(ctx, param1);
  95. }
  96. @Override public UnaryOp getUnaryNumOp() {
  97. return UnaryOp.NEG_NUM;
  98. }
  99. },
  100. POS("+", false) {
  101. @Override public Value eval(EvalContext ctx, Value param1) {
  102. // basically a no-op
  103. return param1;
  104. }
  105. @Override public UnaryOp getUnaryNumOp() {
  106. return UnaryOp.POS_NUM;
  107. }
  108. },
  109. NOT("Not", true) {
  110. @Override public Value eval(EvalContext ctx, Value param1) {
  111. return BuiltinOperators.not(param1);
  112. }
  113. },
  114. // when a '-' immediately precedes a number, it needs "highest" precedence
  115. NEG_NUM("-", false) {
  116. @Override public Value eval(EvalContext ctx, Value param1) {
  117. return BuiltinOperators.negate(ctx, param1);
  118. }
  119. },
  120. // when a '+' immediately precedes a number, it needs "highest" precedence
  121. POS_NUM("+", false) {
  122. @Override public Value eval(EvalContext ctx, Value param1) {
  123. // basically a no-op
  124. return param1;
  125. }
  126. };
  127. private final String _str;
  128. private final boolean _needSpace;
  129. private UnaryOp(String str, boolean needSpace) {
  130. _str = str;
  131. _needSpace = needSpace;
  132. }
  133. public boolean needsSpace() {
  134. return _needSpace;
  135. }
  136. @Override
  137. public String toString() {
  138. return _str;
  139. }
  140. public UnaryOp getUnaryNumOp() {
  141. return null;
  142. }
  143. public abstract Value eval(EvalContext ctx, Value param1);
  144. }
  145. private enum BinaryOp implements OpType {
  146. PLUS("+") {
  147. @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
  148. return BuiltinOperators.add(ctx, param1, param2);
  149. }
  150. },
  151. MINUS("-") {
  152. @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
  153. return BuiltinOperators.subtract(ctx, param1, param2);
  154. }
  155. },
  156. MULT("*") {
  157. @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
  158. return BuiltinOperators.multiply(param1, param2);
  159. }
  160. },
  161. DIV("/") {
  162. @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
  163. return BuiltinOperators.divide(param1, param2);
  164. }
  165. },
  166. INT_DIV("\\") {
  167. @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
  168. return BuiltinOperators.intDivide(param1, param2);
  169. }
  170. },
  171. EXP("^") {
  172. @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
  173. return BuiltinOperators.exp(param1, param2);
  174. }
  175. },
  176. CONCAT("&") {
  177. @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
  178. return BuiltinOperators.concat(param1, param2);
  179. }
  180. },
  181. MOD("Mod") {
  182. @Override public Value eval(EvalContext ctx, Value param1, Value param2) {
  183. return BuiltinOperators.mod(param1, param2);
  184. }
  185. };
  186. private final String _str;
  187. private BinaryOp(String str) {
  188. _str = str;
  189. }
  190. @Override
  191. public String toString() {
  192. return _str;
  193. }
  194. public abstract Value eval(EvalContext ctx, Value param1, Value param2);
  195. }
  196. private enum CompOp implements OpType {
  197. LT("<") {
  198. @Override public Value eval(Value param1, Value param2) {
  199. return BuiltinOperators.lessThan(param1, param2);
  200. }
  201. },
  202. LTE("<=") {
  203. @Override public Value eval(Value param1, Value param2) {
  204. return BuiltinOperators.lessThanEq(param1, param2);
  205. }
  206. },
  207. GT(">") {
  208. @Override public Value eval(Value param1, Value param2) {
  209. return BuiltinOperators.greaterThan(param1, param2);
  210. }
  211. },
  212. GTE(">=") {
  213. @Override public Value eval(Value param1, Value param2) {
  214. return BuiltinOperators.greaterThanEq(param1, param2);
  215. }
  216. },
  217. EQ("=") {
  218. @Override public Value eval(Value param1, Value param2) {
  219. return BuiltinOperators.equals(param1, param2);
  220. }
  221. },
  222. NE("<>") {
  223. @Override public Value eval(Value param1, Value param2) {
  224. return BuiltinOperators.notEquals(param1, param2);
  225. }
  226. };
  227. private final String _str;
  228. private CompOp(String str) {
  229. _str = str;
  230. }
  231. @Override
  232. public String toString() {
  233. return _str;
  234. }
  235. public abstract Value eval(Value param1, Value param2);
  236. }
  237. private enum LogOp implements OpType {
  238. AND("And") {
  239. @Override public Value eval(Value param1, Value param2) {
  240. return BuiltinOperators.and(param1, param2);
  241. }
  242. },
  243. OR("Or") {
  244. @Override public Value eval(Value param1, Value param2) {
  245. return BuiltinOperators.or(param1, param2);
  246. }
  247. },
  248. EQV("Eqv") {
  249. @Override public Value eval(Value param1, Value param2) {
  250. return BuiltinOperators.eqv(param1, param2);
  251. }
  252. },
  253. XOR("Xor") {
  254. @Override public Value eval(Value param1, Value param2) {
  255. return BuiltinOperators.xor(param1, param2);
  256. }
  257. },
  258. IMP("Imp") {
  259. @Override public Value eval(Value param1, Value param2) {
  260. return BuiltinOperators.imp(param1, param2);
  261. }
  262. };
  263. private final String _str;
  264. private LogOp(String str) {
  265. _str = str;
  266. }
  267. @Override
  268. public String toString() {
  269. return _str;
  270. }
  271. public abstract Value eval(Value param1, Value param2);
  272. }
  273. private enum SpecOp implements OpType {
  274. // note, "NOT" is not actually used as a special operation, always
  275. // replaced with UnaryOp.NOT
  276. NOT("Not") {
  277. @Override public Value eval(Value param1, Object param2, Object param3) {
  278. throw new UnsupportedOperationException();
  279. }
  280. },
  281. IS_NULL("Is Null") {
  282. @Override public Value eval(Value param1, Object param2, Object param3) {
  283. return BuiltinOperators.isNull(param1);
  284. }
  285. },
  286. IS_NOT_NULL("Is Not Null") {
  287. @Override public Value eval(Value param1, Object param2, Object param3) {
  288. return BuiltinOperators.isNotNull(param1);
  289. }
  290. },
  291. LIKE("Like") {
  292. @Override public Value eval(Value param1, Object param2, Object param3) {
  293. return BuiltinOperators.like(param1, (Pattern)param2);
  294. }
  295. },
  296. BETWEEN("Between") {
  297. @Override public Value eval(Value param1, Object param2, Object param3) {
  298. return BuiltinOperators.between(param1, (Value)param2, (Value)param3);
  299. }
  300. },
  301. NOT_BETWEEN("Not Between") {
  302. @Override public Value eval(Value param1, Object param2, Object param3) {
  303. return BuiltinOperators.notBetween(param1, (Value)param2, (Value)param3);
  304. }
  305. },
  306. IN("In") {
  307. @Override public Value eval(Value param1, Object param2, Object param3) {
  308. return BuiltinOperators.in(param1, (Value[])param2);
  309. }
  310. },
  311. NOT_IN("Not In") {
  312. @Override public Value eval(Value param1, Object param2, Object param3) {
  313. return BuiltinOperators.notIn(param1, (Value[])param2);
  314. }
  315. };
  316. private final String _str;
  317. private SpecOp(String str) {
  318. _str = str;
  319. }
  320. @Override
  321. public String toString() {
  322. return _str;
  323. }
  324. public abstract Value eval(Value param1, Object param2, Object param3);
  325. }
  326. private static final Map<OpType, Integer> PRECENDENCE =
  327. buildPrecedenceMap(
  328. new OpType[]{UnaryOp.NEG_NUM, UnaryOp.POS_NUM},
  329. new OpType[]{BinaryOp.EXP},
  330. new OpType[]{UnaryOp.NEG, UnaryOp.POS},
  331. new OpType[]{BinaryOp.MULT, BinaryOp.DIV},
  332. new OpType[]{BinaryOp.INT_DIV},
  333. new OpType[]{BinaryOp.MOD},
  334. new OpType[]{BinaryOp.PLUS, BinaryOp.MINUS},
  335. new OpType[]{BinaryOp.CONCAT},
  336. new OpType[]{CompOp.LT, CompOp.GT, CompOp.NE, CompOp.LTE, CompOp.GTE,
  337. CompOp.EQ, SpecOp.LIKE, SpecOp.IS_NULL, SpecOp.IS_NOT_NULL},
  338. new OpType[]{UnaryOp.NOT},
  339. new OpType[]{LogOp.AND},
  340. new OpType[]{LogOp.OR},
  341. new OpType[]{LogOp.XOR},
  342. new OpType[]{LogOp.EQV},
  343. new OpType[]{LogOp.IMP},
  344. new OpType[]{SpecOp.IN, SpecOp.NOT_IN, SpecOp.BETWEEN,
  345. SpecOp.NOT_BETWEEN});
  346. private static final Set<Character> REGEX_SPEC_CHARS = new HashSet<Character>(
  347. Arrays.asList('\\','.','%','=','+', '$','^','|','(',')','{','}','&'));
  348. // this is a regular expression which will never match any string
  349. private static final Pattern UNMATCHABLE_REGEX = Pattern.compile("(?!)");
  350. private static final Expr THIS_COL_VALUE = new EThisValue();
  351. private static final Expr NULL_VALUE = new EConstValue(
  352. BuiltinOperators.NULL_VAL, "Null");
  353. private static final Expr TRUE_VALUE = new EConstValue(
  354. BuiltinOperators.TRUE_VAL, "True");
  355. private static final Expr FALSE_VALUE = new EConstValue(
  356. BuiltinOperators.FALSE_VAL, "False");
  357. private Expressionator()
  358. {
  359. }
  360. static String testTokenize(Type exprType, String exprStr,
  361. ParseContext context) {
  362. if(context == null) {
  363. context = DEFAULT_PARSE_CONTEXT;
  364. }
  365. List<Token> tokens = trimSpaces(
  366. ExpressionTokenizer.tokenize(exprType, exprStr, context));
  367. if(tokens == null) {
  368. // FIXME, NULL_EXPR?
  369. return null;
  370. }
  371. return tokens.toString();
  372. }
  373. public static Expression parse(Type exprType, String exprStr,
  374. ParseContext context) {
  375. if(context == null) {
  376. context = DEFAULT_PARSE_CONTEXT;
  377. }
  378. // FIXME,restrictions:
  379. // - default value only accepts simple exprs, otherwise becomes literal text
  380. // - def val cannot refer to any columns
  381. // - field validation cannot refer to other columns
  382. // - record validation cannot refer to outside columns
  383. List<Token> tokens = trimSpaces(
  384. ExpressionTokenizer.tokenize(exprType, exprStr, context));
  385. if(tokens == null) {
  386. // FIXME, NULL_EXPR?
  387. return null;
  388. }
  389. Expr expr = parseExpression(new TokBuf(exprType, tokens, context), false);
  390. if((exprType == Type.FIELD_VALIDATOR) && !expr.isConditionalExpr()) {
  391. // a non-conditional expression for a FIELD_VALIDATOR treats the result
  392. // as an equality comparison with the field in question. so, transform
  393. // the expression accordingly
  394. expr = new EImplicitCompOp(expr);
  395. }
  396. return (expr.isConstant() ?
  397. // for now, just cache at top-level for speed (could in theory cache
  398. // intermediate values?)
  399. new MemoizedExprWrapper(exprType, expr) :
  400. new ExprWrapper(exprType, expr));
  401. }
  402. private static List<Token> trimSpaces(List<Token> tokens) {
  403. if(tokens == null) {
  404. return null;
  405. }
  406. // for the most part, spaces are superfluous except for one situation(?).
  407. // when they appear between a string literal and '(' they help distinguish
  408. // a function call from another expression form
  409. for(int i = 1; i < (tokens.size() - 1); ++i) {
  410. Token t = tokens.get(i);
  411. if(t.getType() == TokenType.SPACE) {
  412. if((tokens.get(i - 1).getType() == TokenType.STRING) &&
  413. isDelim(tokens.get(i + 1), FUNC_START_DELIM)) {
  414. // we want to keep this space
  415. } else {
  416. tokens.remove(i);
  417. --i;
  418. }
  419. }
  420. }
  421. return tokens;
  422. }
  423. private static Expr parseExpression(TokBuf buf, boolean singleExpr)
  424. {
  425. while(buf.hasNext()) {
  426. Token t = buf.next();
  427. switch(t.getType()) {
  428. case OBJ_NAME:
  429. parseObjectRefExpression(t, buf);
  430. break;
  431. case LITERAL:
  432. buf.setPendingExpr(new ELiteralValue(t.getValueType(), t.getValue(),
  433. t.getDateFormat()));
  434. break;
  435. case OP:
  436. WordType wordType = getWordType(t);
  437. if(wordType == null) {
  438. // shouldn't happen
  439. throw new ParseException("Invalid operator " + t);
  440. }
  441. // this can only be an OP or a COMP (those are the only words that the
  442. // tokenizer would define as TokenType.OP)
  443. switch(wordType) {
  444. case OP:
  445. parseOperatorExpression(t, buf);
  446. break;
  447. case COMP:
  448. parseCompOpExpression(t, buf);
  449. break;
  450. default:
  451. throw new ParseException("Unexpected OP word type " + wordType);
  452. }
  453. break;
  454. case DELIM:
  455. parseDelimExpression(t, buf);
  456. break;
  457. case STRING:
  458. // see if it's a special word?
  459. wordType = getWordType(t);
  460. if(wordType == null) {
  461. // is it a function call?
  462. if(!maybeParseFuncCallExpression(t, buf)) {
  463. // is it an object name?
  464. Token next = buf.peekNext();
  465. if((next != null) && isObjNameSep(next)) {
  466. parseObjectRefExpression(t, buf);
  467. } else {
  468. // FIXME maybe bare obj name, maybe string literal?
  469. throw new UnsupportedOperationException("FIXME");
  470. }
  471. }
  472. } else {
  473. // this could be anything but COMP or DELIM (all COMPs would be
  474. // returned as TokenType.OP and all DELIMs would be TokenType.DELIM)
  475. switch(wordType) {
  476. case OP:
  477. parseOperatorExpression(t, buf);
  478. break;
  479. case LOG_OP:
  480. parseLogicalOpExpression(t, buf);
  481. break;
  482. case CONST:
  483. parseConstExpression(t, buf);
  484. break;
  485. case SPEC_OP_PREFIX:
  486. parseSpecOpExpression(t, buf);
  487. break;
  488. default:
  489. throw new ParseException("Unexpected STRING word type "
  490. + wordType);
  491. }
  492. }
  493. break;
  494. case SPACE:
  495. // top-level space is irrelevant (and we strip them anyway)
  496. break;
  497. default:
  498. throw new ParseException("unknown token type " + t);
  499. }
  500. if(singleExpr && buf.hasPendingExpr()) {
  501. break;
  502. }
  503. }
  504. Expr expr = buf.takePendingExpr();
  505. if(expr == null) {
  506. throw new ParseException("No expression found? " + buf);
  507. }
  508. return expr;
  509. }
  510. private static void parseObjectRefExpression(Token firstTok, TokBuf buf) {
  511. // object references may be joined by '.' or '!'. access syntac docs claim
  512. // object identifiers can be formatted like:
  513. // "[Collection name]![Object name].[Property name]"
  514. // However, in practice, they only ever seem to be (at most) two levels
  515. // and only use '.'.
  516. Deque<String> objNames = new LinkedList<String>();
  517. objNames.add(firstTok.getValueStr());
  518. Token t = null;
  519. boolean atSep = false;
  520. while((t = buf.peekNext()) != null) {
  521. if(!atSep) {
  522. if(isObjNameSep(t)) {
  523. buf.next();
  524. atSep = true;
  525. continue;
  526. }
  527. } else {
  528. if((t.getType() == TokenType.OBJ_NAME) ||
  529. (t.getType() == TokenType.STRING)) {
  530. buf.next();
  531. // always insert at beginning of list so names are in reverse order
  532. objNames.addFirst(t.getValueStr());
  533. atSep = false;
  534. continue;
  535. }
  536. }
  537. break;
  538. }
  539. if(atSep || (objNames.size() > 3)) {
  540. throw new ParseException("Invalid object reference " + buf);
  541. }
  542. // names are in reverse order
  543. String fieldName = objNames.poll();
  544. String objName = objNames.poll();
  545. String collectionName = objNames.poll();
  546. buf.setPendingExpr(
  547. new EObjValue(collectionName, objName, fieldName));
  548. }
  549. private static void parseDelimExpression(Token firstTok, TokBuf buf) {
  550. // the only "top-level" delim we expect to find is open paren, and
  551. // there shouldn't be any pending expression
  552. if(!isDelim(firstTok, OPEN_PAREN) || buf.hasPendingExpr()) {
  553. throw new ParseException("Unexpected delimiter " +
  554. firstTok.getValue() + " " + buf);
  555. }
  556. Expr subExpr = findParenExprs(buf, false).get(0);
  557. buf.setPendingExpr(new EParen(subExpr));
  558. }
  559. private static boolean maybeParseFuncCallExpression(
  560. Token firstTok, TokBuf buf) {
  561. int startPos = buf.curPos();
  562. boolean foundFunc = false;
  563. try {
  564. Token t = buf.peekNext();
  565. if(!isDelim(t, FUNC_START_DELIM)) {
  566. // not a function call
  567. return false;
  568. }
  569. buf.next();
  570. List<Expr> params = findParenExprs(buf, true);
  571. String funcName = firstTok.getValueStr();
  572. Function func = buf.getFunction(funcName);
  573. if(func == null) {
  574. throw new ParseException("Could not find function '" +
  575. funcName + "' " + buf);
  576. }
  577. buf.setPendingExpr(new EFunc(func, params));
  578. foundFunc = true;
  579. return true;
  580. } finally {
  581. if(!foundFunc) {
  582. buf.reset(startPos);
  583. }
  584. }
  585. }
  586. private static List<Expr> findParenExprs(
  587. TokBuf buf, boolean allowMulti) {
  588. if(allowMulti) {
  589. // simple case, no nested expr
  590. Token t = buf.peekNext();
  591. if(isDelim(t, CLOSE_PAREN)) {
  592. buf.next();
  593. return Collections.emptyList();
  594. }
  595. }
  596. // find closing ")", handle nested parens
  597. List<Expr> exprs = new ArrayList<Expr>(3);
  598. int level = 1;
  599. int startPos = buf.curPos();
  600. while(buf.hasNext()) {
  601. Token t = buf.next();
  602. if(isDelim(t, OPEN_PAREN)) {
  603. ++level;
  604. } else if(isDelim(t, CLOSE_PAREN)) {
  605. --level;
  606. if(level == 0) {
  607. TokBuf subBuf = buf.subBuf(startPos, buf.prevPos());
  608. exprs.add(parseExpression(subBuf, false));
  609. return exprs;
  610. }
  611. } else if(allowMulti && (level == 1) && isDelim(t, FUNC_PARAM_SEP)) {
  612. TokBuf subBuf = buf.subBuf(startPos, buf.prevPos());
  613. exprs.add(parseExpression(subBuf, false));
  614. startPos = buf.curPos();
  615. }
  616. }
  617. throw new ParseException("Missing closing '" + CLOSE_PAREN
  618. + " " + buf);
  619. }
  620. private static void parseOperatorExpression(Token t, TokBuf buf) {
  621. // most ops are two argument except that '-' could be negation, "+" could
  622. // be pos-ation
  623. if(buf.hasPendingExpr()) {
  624. parseBinaryOpExpression(t, buf);
  625. } else if(isEitherOp(t, "-", "+")) {
  626. parseUnaryOpExpression(t, buf);
  627. } else {
  628. throw new ParseException(
  629. "Missing left expression for binary operator " + t.getValue() +
  630. " " + buf);
  631. }
  632. }
  633. private static void parseBinaryOpExpression(Token firstTok, TokBuf buf) {
  634. BinaryOp op = getOpType(firstTok, BinaryOp.class);
  635. Expr leftExpr = buf.takePendingExpr();
  636. Expr rightExpr = parseExpression(buf, true);
  637. buf.setPendingExpr(new EBinaryOp(op, leftExpr, rightExpr));
  638. }
  639. private static void parseUnaryOpExpression(Token firstTok, TokBuf buf) {
  640. UnaryOp op = getOpType(firstTok, UnaryOp.class);
  641. UnaryOp numOp = op.getUnaryNumOp();
  642. if(numOp != null) {
  643. // if this operator is immediately preceding a number, it has a higher
  644. // precedence
  645. Token nextTok = buf.peekNext();
  646. if((nextTok != null) && (nextTok.getType() == TokenType.LITERAL) &&
  647. nextTok.getValueType().isNumeric()) {
  648. op = numOp;
  649. }
  650. }
  651. Expr val = parseExpression(buf, true);
  652. buf.setPendingExpr(new EUnaryOp(op, val));
  653. }
  654. private static void parseCompOpExpression(Token firstTok, TokBuf buf) {
  655. if(!buf.hasPendingExpr()) {
  656. if(buf.getExprType() == Type.FIELD_VALIDATOR) {
  657. // comparison operators for field validators can implicitly use
  658. // the current field value for the left value
  659. buf.setPendingExpr(THIS_COL_VALUE);
  660. } else {
  661. throw new ParseException(
  662. "Missing left expression for comparison operator " +
  663. firstTok.getValue() + " " + buf);
  664. }
  665. }
  666. CompOp op = getOpType(firstTok, CompOp.class);
  667. Expr leftExpr = buf.takePendingExpr();
  668. Expr rightExpr = parseExpression(buf, true);
  669. buf.setPendingExpr(new ECompOp(op, leftExpr, rightExpr));
  670. }
  671. private static void parseLogicalOpExpression(Token firstTok, TokBuf buf) {
  672. if(!buf.hasPendingExpr()) {
  673. throw new ParseException(
  674. "Missing left expression for logical operator " +
  675. firstTok.getValue() + " " + buf);
  676. }
  677. LogOp op = getOpType(firstTok, LogOp.class);
  678. Expr leftExpr = buf.takePendingExpr();
  679. Expr rightExpr = parseExpression(buf, true);
  680. buf.setPendingExpr(new ELogicalOp(op, leftExpr, rightExpr));
  681. }
  682. private static void parseSpecOpExpression(Token firstTok, TokBuf buf) {
  683. SpecOp specOp = getSpecialOperator(firstTok, buf);
  684. if(specOp == SpecOp.NOT) {
  685. // this is the unary prefix operator
  686. parseUnaryOpExpression(firstTok, buf);
  687. return;
  688. }
  689. if(!buf.hasPendingExpr()) {
  690. if(buf.getExprType() == Type.FIELD_VALIDATOR) {
  691. // comparison operators for field validators can implicitly use
  692. // the current field value for the left value
  693. buf.setPendingExpr(THIS_COL_VALUE);
  694. } else {
  695. throw new ParseException(
  696. "Missing left expression for comparison operator " +
  697. specOp + " " + buf);
  698. }
  699. }
  700. Expr expr = buf.takePendingExpr();
  701. Expr specOpExpr = null;
  702. switch(specOp) {
  703. case IS_NULL:
  704. case IS_NOT_NULL:
  705. specOpExpr = new ENullOp(specOp, expr);
  706. break;
  707. case LIKE:
  708. Token t = buf.next();
  709. if((t.getType() != TokenType.LITERAL) ||
  710. (t.getValueType() != Value.Type.STRING)) {
  711. throw new ParseException("Missing Like pattern " + buf);
  712. }
  713. String patternStr = t.getValueStr();
  714. specOpExpr = new ELikeOp(specOp, expr, patternStr);
  715. break;
  716. case BETWEEN:
  717. case NOT_BETWEEN:
  718. // the "rest" of a between expression is of the form "X And Y". we are
  719. // going to speculatively parse forward until we find the "And"
  720. // operator.
  721. Expr startRangeExpr = null;
  722. while(true) {
  723. Expr tmpExpr = parseExpression(buf, true);
  724. Token tmpT = buf.peekNext();
  725. if(tmpT == null) {
  726. // ran out of expression?
  727. throw new ParseException(
  728. "Missing 'And' for 'Between' expression " + buf);
  729. }
  730. if(isString(tmpT, "and")) {
  731. buf.next();
  732. startRangeExpr = tmpExpr;
  733. break;
  734. }
  735. // put the pending expression back and try parsing some more
  736. buf.restorePendingExpr(tmpExpr);
  737. }
  738. Expr endRangeExpr = parseExpression(buf, true);
  739. specOpExpr = new EBetweenOp(specOp, expr, startRangeExpr, endRangeExpr);
  740. break;
  741. case IN:
  742. case NOT_IN:
  743. // there might be a space before open paren
  744. t = buf.next();
  745. if(t.getType() == TokenType.SPACE) {
  746. t = buf.next();
  747. }
  748. if(!isDelim(t, OPEN_PAREN)) {
  749. throw new ParseException("Malformed In expression " + buf);
  750. }
  751. List<Expr> exprs = findParenExprs(buf, true);
  752. specOpExpr = new EInOp(specOp, expr, exprs);
  753. break;
  754. default:
  755. throw new ParseException("Unexpected special op " + specOp);
  756. }
  757. buf.setPendingExpr(specOpExpr);
  758. }
  759. private static SpecOp getSpecialOperator(Token firstTok, TokBuf buf) {
  760. String opStr = firstTok.getValueStr().toLowerCase();
  761. if("is".equals(opStr)) {
  762. Token t = buf.peekNext();
  763. if(isString(t, "null")) {
  764. buf.next();
  765. return SpecOp.IS_NULL;
  766. } else if(isString(t, "not")) {
  767. buf.next();
  768. t = buf.peekNext();
  769. if(isString(t, "null")) {
  770. return SpecOp.IS_NOT_NULL;
  771. }
  772. }
  773. } else if("like".equals(opStr)) {
  774. return SpecOp.LIKE;
  775. } else if("between".equals(opStr)) {
  776. return SpecOp.BETWEEN;
  777. } else if("in".equals(opStr)) {
  778. return SpecOp.IN;
  779. } else if("not".equals(opStr)) {
  780. Token t = buf.peekNext();
  781. if(isString(t, "between")) {
  782. buf.next();
  783. return SpecOp.NOT_BETWEEN;
  784. } else if(isString(t, "in")) {
  785. buf.next();
  786. return SpecOp.NOT_IN;
  787. }
  788. return SpecOp.NOT;
  789. }
  790. throw new ParseException(
  791. "Malformed special operator " + opStr + " " + buf);
  792. }
  793. private static void parseConstExpression(Token firstTok, TokBuf buf) {
  794. Expr constExpr = null;
  795. if("true".equalsIgnoreCase(firstTok.getValueStr())) {
  796. constExpr = TRUE_VALUE;
  797. } else if("false".equalsIgnoreCase(firstTok.getValueStr())) {
  798. constExpr = FALSE_VALUE;
  799. } else if("null".equalsIgnoreCase(firstTok.getValueStr())) {
  800. constExpr = NULL_VALUE;
  801. } else {
  802. throw new ParseException("Unexpected CONST word "
  803. + firstTok.getValue());
  804. }
  805. buf.setPendingExpr(constExpr);
  806. }
  807. private static boolean isObjNameSep(Token t) {
  808. return (isDelim(t, ".") || isDelim(t, "!"));
  809. }
  810. private static boolean isOp(Token t, String opStr) {
  811. return ((t != null) && (t.getType() == TokenType.OP) &&
  812. opStr.equalsIgnoreCase(t.getValueStr()));
  813. }
  814. private static boolean isEitherOp(Token t, String opStr1, String opStr2) {
  815. return ((t != null) && (t.getType() == TokenType.OP) &&
  816. (opStr1.equalsIgnoreCase(t.getValueStr()) ||
  817. opStr2.equalsIgnoreCase(t.getValueStr())));
  818. }
  819. private static boolean isDelim(Token t, String opStr) {
  820. return ((t != null) && (t.getType() == TokenType.DELIM) &&
  821. opStr.equalsIgnoreCase(t.getValueStr()));
  822. }
  823. private static boolean isString(Token t, String opStr) {
  824. return ((t != null) && (t.getType() == TokenType.STRING) &&
  825. opStr.equalsIgnoreCase(t.getValueStr()));
  826. }
  827. private static WordType getWordType(Token t) {
  828. return WORD_TYPES.get(t.getValueStr().toLowerCase());
  829. }
  830. private static void setWordType(WordType type, String... words) {
  831. for(String w : words) {
  832. WORD_TYPES.put(w, type);
  833. }
  834. }
  835. private static <T extends Enum<T>> T getOpType(Token t, Class<T> opClazz) {
  836. String str = t.getValueStr();
  837. for(T op : opClazz.getEnumConstants()) {
  838. if(str.equalsIgnoreCase(op.toString())) {
  839. return op;
  840. }
  841. }
  842. throw new ParseException("Unexpected op string " + t.getValueStr());
  843. }
  844. private static final class TokBuf
  845. {
  846. private final Type _exprType;
  847. private final List<Token> _tokens;
  848. private final TokBuf _parent;
  849. private final int _parentOff;
  850. private final ParseContext _context;
  851. private int _pos;
  852. private Expr _pendingExpr;
  853. private final boolean _simpleExpr;
  854. private TokBuf(Type exprType, List<Token> tokens, ParseContext context) {
  855. this(exprType, false, tokens, null, 0, context);
  856. }
  857. private TokBuf(List<Token> tokens, TokBuf parent, int parentOff) {
  858. this(parent._exprType, parent._simpleExpr, tokens, parent, parentOff,
  859. parent._context);
  860. }
  861. private TokBuf(Type exprType, boolean simpleExpr, List<Token> tokens,
  862. TokBuf parent, int parentOff, ParseContext context) {
  863. _exprType = exprType;
  864. _tokens = tokens;
  865. _parent = parent;
  866. _parentOff = parentOff;
  867. _context = context;
  868. if(parent == null) {
  869. // "top-level" expression, determine if it is a simple expression or not
  870. simpleExpr = isSimpleExpression();
  871. }
  872. _simpleExpr = simpleExpr;
  873. }
  874. private boolean isSimpleExpression() {
  875. if(_exprType != Type.DEFAULT_VALUE) {
  876. return false;
  877. }
  878. // a leading "=" indicates "full" expression handling for a DEFAULT_VALUE
  879. Token t = peekNext();
  880. if(isOp(t, "=")) {
  881. next();
  882. return false;
  883. }
  884. // this is a "simple" DEFAULT_VALUE
  885. return true;
  886. }
  887. public Type getExprType() {
  888. return _exprType;
  889. }
  890. public boolean isSimpleExpr() {
  891. return _simpleExpr;
  892. }
  893. public boolean isTopLevel() {
  894. return (_parent == null);
  895. }
  896. public int curPos() {
  897. return _pos;
  898. }
  899. public int prevPos() {
  900. return _pos - 1;
  901. }
  902. public boolean hasNext() {
  903. return (_pos < _tokens.size());
  904. }
  905. public Token peekNext() {
  906. if(!hasNext()) {
  907. return null;
  908. }
  909. return _tokens.get(_pos);
  910. }
  911. public Token next() {
  912. if(!hasNext()) {
  913. throw new ParseException(
  914. "Unexpected end of expression " + this);
  915. }
  916. return _tokens.get(_pos++);
  917. }
  918. public void reset(int pos) {
  919. _pos = pos;
  920. }
  921. public TokBuf subBuf(int start, int end) {
  922. return new TokBuf(_tokens.subList(start, end), this, start);
  923. }
  924. public void setPendingExpr(Expr expr) {
  925. if(_pendingExpr != null) {
  926. throw new ParseException(
  927. "Found multiple expressions with no operator " + this);
  928. }
  929. _pendingExpr = expr.resolveOrderOfOperations();
  930. }
  931. public void restorePendingExpr(Expr expr) {
  932. // this is an expression which was previously set, so no need to re-resolve
  933. _pendingExpr = expr;
  934. }
  935. public Expr takePendingExpr() {
  936. Expr expr = _pendingExpr;
  937. _pendingExpr = null;
  938. return expr;
  939. }
  940. public boolean hasPendingExpr() {
  941. return (_pendingExpr != null);
  942. }
  943. private Map.Entry<Integer,List<Token>> getTopPos() {
  944. int pos = _pos;
  945. List<Token> toks = _tokens;
  946. TokBuf cur = this;
  947. while(cur._parent != null) {
  948. pos += cur._parentOff;
  949. cur = cur._parent;
  950. toks = cur._tokens;
  951. }
  952. return ExpressionTokenizer.newEntry(pos, toks);
  953. }
  954. public Function getFunction(String funcName) {
  955. return _context.getExpressionFunction(funcName);
  956. }
  957. @Override
  958. public String toString() {
  959. Map.Entry<Integer,List<Token>> e = getTopPos();
  960. // TODO actually format expression?
  961. StringBuilder sb = new StringBuilder()
  962. .append("[token ").append(e.getKey()).append("] (");
  963. for(Iterator<Token> iter = e.getValue().iterator(); iter.hasNext(); ) {
  964. Token t = iter.next();
  965. sb.append("'").append(t.getValueStr()).append("'");
  966. if(iter.hasNext()) {
  967. sb.append(",");
  968. }
  969. }
  970. sb.append(")");
  971. if(_pendingExpr != null) {
  972. sb.append(" [pending '").append(_pendingExpr.toDebugString())
  973. .append("']");
  974. }
  975. return sb.toString();
  976. }
  977. }
  978. private static boolean isHigherPrecendence(OpType op1, OpType op2) {
  979. int prec1 = PRECENDENCE.get(op1);
  980. int prec2 = PRECENDENCE.get(op2);
  981. // higher preceendence ops have lower numbers
  982. return (prec1 < prec2);
  983. }
  984. private static final Map<OpType, Integer> buildPrecedenceMap(
  985. OpType[]... opArrs) {
  986. Map<OpType, Integer> prec = new HashMap<OpType, Integer>();
  987. int level = 0;
  988. for(OpType[] ops : opArrs) {
  989. for(OpType op : ops) {
  990. prec.put(op, level);
  991. }
  992. ++level;
  993. }
  994. return prec;
  995. }
  996. private static void exprListToString(
  997. List<Expr> exprs, String sep, StringBuilder sb, boolean isDebug) {
  998. Iterator<Expr> iter = exprs.iterator();
  999. iter.next().toString(sb, isDebug);
  1000. while(iter.hasNext()) {
  1001. sb.append(sep);
  1002. iter.next().toString(sb, isDebug);
  1003. }
  1004. }
  1005. private static Value[] exprListToValues(
  1006. List<Expr> exprs, EvalContext ctx) {
  1007. Value[] paramVals = new Value[exprs.size()];
  1008. for(int i = 0; i < exprs.size(); ++i) {
  1009. paramVals[i] = exprs.get(i).eval(ctx);
  1010. }
  1011. return paramVals;
  1012. }
  1013. private static Value[] exprListToDelayedValues(
  1014. List<Expr> exprs, EvalContext ctx) {
  1015. Value[] paramVals = new Value[exprs.size()];
  1016. for(int i = 0; i < exprs.size(); ++i) {
  1017. paramVals[i] = new DelayedValue(exprs.get(i), ctx);
  1018. }
  1019. return paramVals;
  1020. }
  1021. private static boolean areConstant(List<Expr> exprs) {
  1022. for(Expr expr : exprs) {
  1023. if(!expr.isConstant()) {
  1024. return false;
  1025. }
  1026. }
  1027. return true;
  1028. }
  1029. private static boolean areConstant(Expr... exprs) {
  1030. for(Expr expr : exprs) {
  1031. if(!expr.isConstant()) {
  1032. return false;
  1033. }
  1034. }
  1035. return true;
  1036. }
  1037. private static void literalStrToString(String str, StringBuilder sb) {
  1038. sb.append("\"")
  1039. .append(str.replace("\"", "\"\""))
  1040. .append("\"");
  1041. }
  1042. private static Pattern likePatternToRegex(String pattern) {
  1043. StringBuilder sb = new StringBuilder(pattern.length());
  1044. // Access LIKE pattern supports (note, matching is case-insensitive):
  1045. // - '*' -> 0 or more chars
  1046. // - '?' -> single character
  1047. // - '#' -> single digit
  1048. // - '[...]' -> character class, '[!...]' -> not in char class
  1049. for(int i = 0; i < pattern.length(); ++i) {
  1050. char c = pattern.charAt(i);
  1051. if(c == '*') {
  1052. sb.append(".*");
  1053. } else if(c == '?') {
  1054. sb.append('.');
  1055. } else if(c == '#') {
  1056. sb.append("\\d");
  1057. } else if(c == '[') {
  1058. // find closing brace
  1059. int startPos = i + 1;
  1060. int endPos = -1;
  1061. for(int j = startPos; j < pattern.length(); ++j) {
  1062. if(pattern.charAt(j) == ']') {
  1063. endPos = j;
  1064. break;
  1065. }
  1066. }
  1067. // access treats invalid expression like "unmatchable"
  1068. if(endPos == -1) {
  1069. return UNMATCHABLE_REGEX;
  1070. }
  1071. String charClass = pattern.substring(startPos, endPos);
  1072. if((charClass.length() > 0) && (charClass.charAt(0) == '!')) {
  1073. // this is a negated char class
  1074. charClass = '^' + charClass.substring(1);
  1075. }
  1076. sb.append('[').append(charClass).append(']');
  1077. i += (endPos - startPos) + 1;
  1078. } else if(REGEX_SPEC_CHARS.contains(c)) {
  1079. // this char is special in regexes, so escape it
  1080. sb.append('\\').append(c);
  1081. } else {
  1082. sb.append(c);
  1083. }
  1084. }
  1085. try {
  1086. return Pattern.compile(sb.toString(),
  1087. Pattern.CASE_INSENSITIVE | Pattern.DOTALL |
  1088. Pattern.UNICODE_CASE);
  1089. } catch(PatternSyntaxException ignored) {
  1090. return UNMATCHABLE_REGEX;
  1091. }
  1092. }
  1093. private static Value toLiteralValue(Value.Type valType, Object value,
  1094. DateFormat sdf)
  1095. {
  1096. switch(valType) {
  1097. case STRING:
  1098. return new StringValue((String)value);
  1099. case DATE:
  1100. return new DateValue((Date)value, sdf);
  1101. case TIME:
  1102. return new TimeValue((Date)value, sdf);
  1103. case DATE_TIME:
  1104. return new DateTimeValue((Date)value, sdf);
  1105. case LONG:
  1106. return new LongValue((Integer)value);
  1107. case DOUBLE:
  1108. return new DoubleValue((Double)value);
  1109. case BIG_DEC:
  1110. return new BigDecimalValue((BigDecimal)value);
  1111. default:
  1112. throw new ParseException("unexpected literal type " + valType);
  1113. }
  1114. }
  1115. private interface LeftAssocExpr {
  1116. public OpType getOp();
  1117. public Expr getLeft();
  1118. public void setLeft(Expr left);
  1119. }
  1120. private interface RightAssocExpr {
  1121. public OpType getOp();
  1122. public Expr getRight();
  1123. public void setRight(Expr right);
  1124. }
  1125. private static final class DelayedValue extends BaseDelayedValue
  1126. {
  1127. private final Expr _expr;
  1128. private final EvalContext _ctx;
  1129. private DelayedValue(Expr expr, EvalContext ctx) {
  1130. _expr = expr;
  1131. _ctx = ctx;
  1132. }
  1133. @Override
  1134. public Value eval() {
  1135. return _expr.eval(_ctx);
  1136. }
  1137. }
  1138. private static abstract class Expr
  1139. {
  1140. @Override
  1141. public String toString() {
  1142. StringBuilder sb = new StringBuilder();
  1143. toString(sb, false);
  1144. return sb.toString();
  1145. }
  1146. public String toDebugString() {
  1147. StringBuilder sb = new StringBuilder();
  1148. toString(sb, true);
  1149. return sb.toString();
  1150. }
  1151. protected boolean isConditionalExpr() {
  1152. return false;
  1153. }
  1154. protected void toString(StringBuilder sb, boolean isDebug) {
  1155. if(isDebug) {
  1156. sb.append("<").append(getClass().getSimpleName()).append(">{");
  1157. }
  1158. toExprString(sb, isDebug);
  1159. if(isDebug) {
  1160. sb.append("}");
  1161. }
  1162. }
  1163. protected Expr resolveOrderOfOperations() {
  1164. if(!(this instanceof LeftAssocExpr)) {
  1165. // nothing we can do
  1166. return this;
  1167. }
  1168. // in order to get the precedence right, we need to first associate this
  1169. // expression with the "rightmost" expression preceding it, then adjust
  1170. // this expression "down" (lower precedence) as the precedence of the
  1171. // operations dictates. since we parse from left to right, the initial
  1172. // "left" value isn't the immediate left expression, instead it's based
  1173. // on how the preceding operator precedence worked out. we need to
  1174. // adjust "this" expression to the closest preceding expression before
  1175. // we can correctly resolve precedence.
  1176. Expr outerExpr = this;
  1177. final LeftAssocExpr thisExpr = (LeftAssocExpr)this;
  1178. final Expr thisLeft = thisExpr.getLeft();
  1179. // current: <this>{<left>{A op1 B} op2 <right>{C}}
  1180. if(thisLeft instanceof RightAssocExpr) {
  1181. RightAssocExpr leftOp = (RightAssocExpr)thisLeft;
  1182. // target: <left>{A op1 <this>{B op2 <right>{C}}}
  1183. thisExpr.setLeft(leftOp.getRight());
  1184. // give the new version of this expression an opportunity to further
  1185. // swap (since the swapped expression may itself be a binary
  1186. // expression)
  1187. leftOp.setRight(resolveOrderOfOperations());
  1188. outerExpr = thisLeft;
  1189. // at this point, this expression has been pushed all the way to the
  1190. // rightmost preceding expression (we artifically gave "this" the
  1191. // highest precedence). now, we want to adjust precedence as
  1192. // necessary (shift it back down if the operator precedence is
  1193. // incorrect). note, we only need to check precedence against "this",
  1194. // as all other precedence has been resolved in previous parsing
  1195. // rounds.
  1196. if((leftOp.getRight() == this) &&
  1197. !isHigherPrecendence(thisExpr.getOp(), leftOp.getOp())) {
  1198. // doh, "this" is lower (or the same) precedence, restore the
  1199. // original order of things
  1200. leftOp.setRight(thisExpr.getLeft());
  1201. thisExpr.setLeft(thisLeft);
  1202. outerExpr = this;
  1203. }
  1204. }
  1205. return outerExpr;
  1206. }
  1207. public abstract boolean isConstant();
  1208. public abstract Value eval(EvalContext ctx);
  1209. protected abstract void toExprString(StringBuilder sb, boolean isDebug);
  1210. }
  1211. private static final class EConstValue extends Expr
  1212. {
  1213. private final Value _val;
  1214. private final String _str;
  1215. private EConstValue(Value val, String str) {
  1216. _val = val;
  1217. _str = str;
  1218. }
  1219. @Override
  1220. public boolean isConstant() {
  1221. return true;
  1222. }
  1223. @Override
  1224. public Value eval(EvalContext ctx) {
  1225. return _val;
  1226. }
  1227. @Override
  1228. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1229. sb.append(_str);
  1230. }
  1231. }
  1232. private static final class EThisValue extends Expr
  1233. {
  1234. @Override
  1235. public boolean isConstant() {
  1236. return false;
  1237. }
  1238. @Override
  1239. public Value eval(EvalContext ctx) {
  1240. return ctx.getThisColumnValue();
  1241. }
  1242. @Override
  1243. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1244. sb.append("<THIS_COL>");
  1245. }
  1246. }
  1247. private static final class ELiteralValue extends Expr
  1248. {
  1249. private final Value _val;
  1250. private ELiteralValue(Value.Type valType, Object value,
  1251. DateFormat sdf) {
  1252. _val = toLiteralValue(valType, value, sdf);
  1253. }
  1254. @Override
  1255. public boolean isConstant() {
  1256. return true;
  1257. }
  1258. @Override
  1259. public Value eval(EvalContext ctx) {
  1260. return _val;
  1261. }
  1262. @Override
  1263. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1264. if(_val.getType() == Value.Type.STRING) {
  1265. literalStrToString((String)_val.get(), sb);
  1266. } else if(_val.getType().isTemporal()) {
  1267. sb.append("#").append(_val.getAsString()).append("#");
  1268. } else {
  1269. sb.append(_val.get());
  1270. }
  1271. }
  1272. }
  1273. private static final class EObjValue extends Expr
  1274. {
  1275. private final String _collectionName;
  1276. private final String _objName;
  1277. private final String _fieldName;
  1278. private EObjValue(String collectionName, String objName, String fieldName) {
  1279. _collectionName = collectionName;
  1280. _objName = objName;
  1281. _fieldName = fieldName;
  1282. }
  1283. @Override
  1284. public boolean isConstant() {
  1285. return false;
  1286. }
  1287. @Override
  1288. public Value eval(EvalContext ctx) {
  1289. return ctx.getRowValue(_collectionName, _objName, _fieldName);
  1290. }
  1291. @Override
  1292. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1293. if(_collectionName != null) {
  1294. sb.append("[").append(_collectionName).append("].");
  1295. }
  1296. if(_objName != null) {
  1297. sb.append("[").append(_objName).append("].");
  1298. }
  1299. sb.append("[").append(_fieldName).append("]");
  1300. }
  1301. }
  1302. private static class EParen extends Expr
  1303. {
  1304. private final Expr _expr;
  1305. private EParen(Expr expr) {
  1306. _expr = expr;
  1307. }
  1308. @Override
  1309. public boolean isConstant() {
  1310. return _expr.isConstant();
  1311. }
  1312. @Override
  1313. protected boolean isConditionalExpr() {
  1314. return _expr.isConditionalExpr();
  1315. }
  1316. @Override
  1317. public Value eval(EvalContext ctx) {
  1318. return _expr.eval(ctx);
  1319. }
  1320. @Override
  1321. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1322. sb.append("(");
  1323. _expr.toString(sb, isDebug);
  1324. sb.append(")");
  1325. }
  1326. }
  1327. private static class EFunc extends Expr
  1328. {
  1329. private final Function _func;
  1330. private final List<Expr> _params;
  1331. private EFunc(Function func, List<Expr> params) {
  1332. _func = func;
  1333. _params = params;
  1334. }
  1335. @Override
  1336. public boolean isConstant() {
  1337. return _func.isPure() && areConstant(_params);
  1338. }
  1339. @Override
  1340. public Value eval(EvalContext ctx) {
  1341. return _func.eval(ctx, exprListToValues(_params, ctx));
  1342. }
  1343. @Override
  1344. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1345. sb.append(_func.getName()).append("(");
  1346. if(!_params.isEmpty()) {
  1347. exprListToString(_params, ",", sb, isDebug);
  1348. }
  1349. sb.append(")");
  1350. }
  1351. }
  1352. private static abstract class EBaseBinaryOp extends Expr
  1353. implements LeftAssocExpr, RightAssocExpr
  1354. {
  1355. protected final OpType _op;
  1356. protected Expr _left;
  1357. protected Expr _right;
  1358. private EBaseBinaryOp(OpType op, Expr left, Expr right) {
  1359. _op = op;
  1360. _left = left;
  1361. _right = right;
  1362. }
  1363. @Override
  1364. public boolean isConstant() {
  1365. return areConstant(_left, _right);
  1366. }
  1367. public OpType getOp() {
  1368. return _op;
  1369. }
  1370. public Expr getLeft() {
  1371. return _left;
  1372. }
  1373. public void setLeft(Expr left) {
  1374. _left = left;
  1375. }
  1376. public Expr getRight() {
  1377. return _right;
  1378. }
  1379. public void setRight(Expr right) {
  1380. _right = right;
  1381. }
  1382. @Override
  1383. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1384. _left.toString(sb, isDebug);
  1385. sb.append(" ").append(_op).append(" ");
  1386. _right.toString(sb, isDebug);
  1387. }
  1388. }
  1389. private static class EBinaryOp extends EBaseBinaryOp
  1390. {
  1391. private EBinaryOp(BinaryOp op, Expr left, Expr right) {
  1392. super(op, left, right);
  1393. }
  1394. @Override
  1395. public Value eval(EvalContext ctx) {
  1396. return ((BinaryOp)_op).eval(ctx, _left.eval(ctx), _right.eval(ctx));
  1397. }
  1398. }
  1399. private static class EUnaryOp extends Expr
  1400. implements RightAssocExpr
  1401. {
  1402. private final OpType _op;
  1403. private Expr _expr;
  1404. private EUnaryOp(UnaryOp op, Expr expr) {
  1405. _op = op;
  1406. _expr = expr;
  1407. }
  1408. @Override
  1409. public boolean isConstant() {
  1410. return _expr.isConstant();
  1411. }
  1412. public OpType getOp() {
  1413. return _op;
  1414. }
  1415. public Expr getRight() {
  1416. return _expr;
  1417. }
  1418. public void setRight(Expr right) {
  1419. _expr = right;
  1420. }
  1421. @Override
  1422. public Value eval(EvalContext ctx) {
  1423. return ((UnaryOp)_op).eval(ctx, _expr.eval(ctx));
  1424. }
  1425. @Override
  1426. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1427. sb.append(_op);
  1428. if(isDebug || ((UnaryOp)_op).needsSpace()) {
  1429. sb.append(" ");
  1430. }
  1431. _expr.toString(sb, isDebug);
  1432. }
  1433. }
  1434. private static class ECompOp extends EBaseBinaryOp
  1435. {
  1436. private ECompOp(CompOp op, Expr left, Expr right) {
  1437. super(op, left, right);
  1438. }
  1439. @Override
  1440. protected boolean isConditionalExpr() {
  1441. return true;
  1442. }
  1443. @Override
  1444. public Value eval(EvalContext ctx) {
  1445. return ((CompOp)_op).eval(_left.eval(ctx), _right.eval(ctx));
  1446. }
  1447. }
  1448. private static class EImplicitCompOp extends ECompOp
  1449. {
  1450. private EImplicitCompOp(Expr right) {
  1451. super(CompOp.EQ, THIS_COL_VALUE, right);
  1452. }
  1453. @Override
  1454. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1455. // only output the full "implicit" comparison in debug mode
  1456. if(isDebug) {
  1457. super.toExprString(sb, isDebug);
  1458. } else {
  1459. // just output the explicit part of the expression
  1460. _right.toString(sb, isDebug);
  1461. }
  1462. }
  1463. }
  1464. private static class ELogicalOp extends EBaseBinaryOp
  1465. {
  1466. private ELogicalOp(LogOp op, Expr left, Expr right) {
  1467. super(op, left, right);
  1468. }
  1469. @Override
  1470. public Value eval(final EvalContext ctx) {
  1471. // logical operations do short circuit evaluation, so we need to delay
  1472. // computing results until necessary
  1473. return ((LogOp)_op).eval(new DelayedValue(_left, ctx),
  1474. new DelayedValue(_right, ctx));
  1475. }
  1476. }
  1477. private static abstract class ESpecOp extends Expr
  1478. implements LeftAssocExpr
  1479. {
  1480. protected final SpecOp _op;
  1481. protected Expr _expr;
  1482. private ESpecOp(SpecOp op, Expr expr) {
  1483. _op = op;
  1484. _expr = expr;
  1485. }
  1486. @Override
  1487. public boolean isConstant() {
  1488. return _expr.isConstant();
  1489. }
  1490. public OpType getOp() {
  1491. return _op;
  1492. }
  1493. public Expr getLeft() {
  1494. return _expr;
  1495. }
  1496. public void setLeft(Expr left) {
  1497. _expr = left;
  1498. }
  1499. @Override
  1500. protected boolean isConditionalExpr() {
  1501. return true;
  1502. }
  1503. }
  1504. private static class ENullOp extends ESpecOp
  1505. {
  1506. private ENullOp(SpecOp op, Expr expr) {
  1507. super(op, expr);
  1508. }
  1509. @Override
  1510. public Value eval(EvalContext ctx) {
  1511. return _op.eval(_expr.eval(ctx), null, null);
  1512. }
  1513. @Override
  1514. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1515. _expr.toString(sb, isDebug);
  1516. sb.append(" ").append(_op);
  1517. }
  1518. }
  1519. private static class ELikeOp extends ESpecOp
  1520. {
  1521. private final String _patternStr;
  1522. private Pattern _pattern;
  1523. private ELikeOp(SpecOp op, Expr expr, String patternStr) {
  1524. super(op, expr);
  1525. _patternStr = patternStr;
  1526. }
  1527. private Pattern getPattern()
  1528. {
  1529. if(_pattern == null) {
  1530. _pattern = likePatternToRegex(_patternStr);
  1531. }
  1532. return _pattern;
  1533. }
  1534. @Override
  1535. public Value eval(EvalContext ctx) {
  1536. return _op.eval(_expr.eval(ctx), getPattern(), null);
  1537. }
  1538. @Override
  1539. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1540. _expr.toString(sb, isDebug);
  1541. sb.append(" ").append(_op).append(" ");
  1542. literalStrToString(_patternStr, sb);
  1543. if(isDebug) {
  1544. sb.append("(").append(getPattern()).append(")");
  1545. }
  1546. }
  1547. }
  1548. private static class EInOp extends ESpecOp
  1549. {
  1550. private final List<Expr> _exprs;
  1551. private EInOp(SpecOp op, Expr expr, List<Expr> exprs) {
  1552. super(op, expr);
  1553. _exprs = exprs;
  1554. }
  1555. @Override
  1556. public boolean isConstant() {
  1557. return super.isConstant() && areConstant(_exprs);
  1558. }
  1559. @Override
  1560. public Value eval(EvalContext ctx) {
  1561. return _op.eval(_expr.eval(ctx),
  1562. exprListToDelayedValues(_exprs, ctx), null);
  1563. }
  1564. @Override
  1565. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1566. _expr.toString(sb, isDebug);
  1567. sb.append(" ").append(_op).append(" (");
  1568. exprListToString(_exprs, ",", sb, isDebug);
  1569. sb.append(")");
  1570. }
  1571. }
  1572. private static class EBetweenOp extends ESpecOp
  1573. implements RightAssocExpr
  1574. {
  1575. private final Expr _startRangeExpr;
  1576. private Expr _endRangeExpr;
  1577. private EBetweenOp(SpecOp op, Expr expr, Expr startRangeExpr,
  1578. Expr endRangeExpr) {
  1579. super(op, expr);
  1580. _startRangeExpr = startRangeExpr;
  1581. _endRangeExpr = endRangeExpr;
  1582. }
  1583. @Override
  1584. public boolean isConstant() {
  1585. return _expr.isConstant() && areConstant(_startRangeExpr, _endRangeExpr);
  1586. }
  1587. public Expr getRight() {
  1588. return _endRangeExpr;
  1589. }
  1590. public void setRight(Expr right) {
  1591. _endRangeExpr = right;
  1592. }
  1593. @Override
  1594. public Value eval(EvalContext ctx) {
  1595. return _op.eval(_expr.eval(ctx),
  1596. new DelayedValue(_startRangeExpr, ctx),
  1597. new DelayedValue(_endRangeExpr, ctx));
  1598. }
  1599. @Override
  1600. protected void toExprString(StringBuilder sb, boolean isDebug) {
  1601. _expr.toString(sb, isDebug);
  1602. sb.append(" ").append(_op).append(" ");
  1603. _startRangeExpr.toString(sb, isDebug);
  1604. sb.append(" And ");
  1605. _endRangeExpr.toString(sb, isDebug);
  1606. }
  1607. }
  1608. /**
  1609. * Expression wrapper for an Expr which caches the result of evaluation.
  1610. */
  1611. private static class ExprWrapper implements Expression
  1612. {
  1613. private final Type _type;
  1614. private final Expr _expr;
  1615. private ExprWrapper(Type type, Expr expr) {
  1616. _type = type;
  1617. _expr = expr;
  1618. }
  1619. public Object eval(EvalContext ctx) {
  1620. switch(_type) {
  1621. case DEFAULT_VALUE:
  1622. case EXPRESSION:
  1623. return evalValue(ctx);
  1624. case FIELD_VALIDATOR:
  1625. case RECORD_VALIDATOR:
  1626. return evalCondition(ctx);
  1627. default:
  1628. throw new ParseException("unexpected expression type " + _type);
  1629. }
  1630. }
  1631. public String toDebugString() {
  1632. return _expr.toDebugString();
  1633. }
  1634. public boolean isConstant() {
  1635. return _expr.isConstant();
  1636. }
  1637. @Override
  1638. public String toString() {
  1639. return _expr.toString();
  1640. }
  1641. private Object evalValue(EvalContext ctx) {
  1642. Value val = _expr.eval(ctx);
  1643. if(val.isNull()) {
  1644. return null;
  1645. }
  1646. Value.Type resultType = ctx.getResultType();
  1647. if(resultType == null) {
  1648. // return as "native" type
  1649. return val.get();
  1650. }
  1651. // FIXME possibly do some type coercion. are there conversions here which don't work elsewhere? (string -> date, string -> number)?
  1652. switch(resultType) {
  1653. case STRING:
  1654. return val.getAsString();
  1655. case DATE:
  1656. case TIME:
  1657. case DATE_TIME:
  1658. return val.getAsDateTime(ctx);
  1659. case LONG:
  1660. return val.getAsLongInt();
  1661. case DOUBLE:
  1662. return val.getAsDouble();
  1663. case BIG_DEC:
  1664. return val.getAsBigDecimal();
  1665. default:
  1666. throw new IllegalStateException("unexpected result type " + resultType);
  1667. }
  1668. }
  1669. private Boolean evalCondition(EvalContext ctx) {
  1670. Value val = _expr.eval(ctx);
  1671. if(val.isNull()) {
  1672. return null;
  1673. }
  1674. // FIXME, access seems to type coerce all "fields" (including <this>), but not constants
  1675. return val.getAsBoolean();
  1676. }
  1677. }
  1678. /**
  1679. * Expression wrapper for a <i>pure</i> Expr which caches the result of
  1680. * evaluation.
  1681. */
  1682. private static final class MemoizedExprWrapper extends ExprWrapper
  1683. {
  1684. private Object _val;
  1685. private MemoizedExprWrapper(Type type, Expr expr) {
  1686. super(type, expr);
  1687. }
  1688. @Override
  1689. public Object eval(EvalContext ctx) {
  1690. if(_val == null) {
  1691. _val = super.eval(ctx);
  1692. }
  1693. return _val;
  1694. }
  1695. }
  1696. }