1 6 package tests.jfun.parsec.mssql; 7 import jfun.parsec.Parser; 8 import jfun.parsec.Parsers; 9 import jfun.parsec.tokens.TokenQuoted; 10 import jfun.parsec.DefaultPositionMap; 12 import jfun.parsec.Map; 13 import jfun.parsec.Map2; 14 import jfun.parsec.Mapn; 15 import jfun.parsec.Scanners; 16 import jfun.parsec.Lexers; 17 import jfun.parsec.Terms; 18 import jfun.parsec.FromString; 19 import jfun.parsec.FromString3; 20 import jfun.parsec.Tokenizer; 21 22 23 import jfun.parsec.ParserEval; 24 import jfun.parsec.ToParser; 25 import jfun.parsec.OperatorTable; 26 import jfun.parsec.Expressions; 27 32 public final class SqlParser { 33 private static final Terms words = Terms.getCaseInsensitiveInstance( 37 new String []{ 38 ".", ",", "(", ")", "+", "-", "*", "/", "%", "&", "|", 39 "<", ">", ">=", "<=", "=", "<>", "!=" 40 }, 41 new String []{ 42 "null", "Is", "and", "or", "not", "NOT", "case", "when", "case", "then", "else", "end", 44 "select", "begin", "set", "update", "insert", 45 "values", "from", "where", "order", "by", 46 "group", "having", "inner", "outer", "left", 47 "right", "full", "join", "on", "in", 48 "between", "exists", "if", "as", "cross", 49 "desc", "asc", "like", "escape" 50 51 } 52 ); 53 public static Parser word(String n){ 54 return words.getParser(n); 55 } 56 public static Parser expr(){return ExprP.parser;} 57 58 public static Parser bool_expr(){return BoolExprP.parser;} 59 60 private static final Parser dot = word("."); 61 private static final Parser lparen = word("("); 62 private static final Parser rparen = word(")"); 63 private static final Parser comma = word(","); 64 private static final Parser word_select = word("select"); 65 private static final Parser id = Parsers.plus( 67 Terms.wordParser(new FromString(){ 68 public Object fromString(int from, int len, final String name){ 69 return Id.instance(name.toString()); 70 } 71 }), 72 Terms.quotedWordParser(new FromString3(){ 73 public Object fromString3(int from, int len, 74 final String open, final String name, final String close){ 75 if(open.equals("[")) 76 return Id.bracketed(name.toString()); 77 else if(open.equals("\"")) 78 return Id.quoted(name.toString()); 79 else return null; 80 } 81 }) 82 ); 83 private static final Parser qualifiedId = Parsers.sepBy1("qualifiedId", Id.class, dot, id); 85 private static final Parser qualifiedName = qualifiedId.map(new Map(){ 87 public Object map(final Object o){ 88 final Id[] names = (Id[])o; 89 return new QualifiedName(names); 90 } 91 }); 92 93 94 95 96 97 98 99 private static final Parser lazy_expr = Parsers.lazy("lazy_expr", new ParserEval(){ 100 public Parser eval(){return ExprP.parser;} 101 }); 102 private static final Parser lazy_bool_expr = Parsers.lazy("lazy_bool_expr", new ParserEval(){ 103 public Parser eval(){return BoolExprP.parser;} 104 }); 105 106 private static final Parser lazy_relation = Parsers.lazy(new ParserEval(){ 107 public Parser eval(){return parseRelation();} 108 }); 109 110 113 114 private static Map2 toMap2(final LogicalBinaryOp op){ 115 return new Map2(){ 116 public Object map(final Object o1, final Object o2){ 117 return op.apply((Expression)o1, (Expression)o2); 118 } 119 }; 120 } 121 private static Map2 toMap2(final BoolBinaryOp op){ 122 return new Map2(){ 123 public Object map(final Object o1, final Object o2){ 124 return op.apply((BoolExpression)o1, (BoolExpression)o2); 125 } 126 }; 127 } 128 129 private static Parser lretnMap2(final LogicalBinaryOp op){ 130 return Parsers.retn(toMap2(op)); 131 } 132 private static Parser bretnMap2(final BoolBinaryOp op){ 133 return Parsers.retn(toMap2(op)); 134 } 135 private static final Parser subquery = Parsers.lazy(new ParserEval(){ 136 public Parser eval(){ 137 return Parsers.between(lparen, rparen, parseSelectStmt()); 138 } 139 }).map(new Map(){ 140 public Object map(final Object o){ 141 final Select sel = (Select)o; 142 return Table.select(sel); 143 } 144 }); 145 146 147 private static final class ExprP{ 148 private static final Parser bar = word("|"); 149 private static final Parser ampersand = word("&"); 150 private static final Parser plus = word("+"); 151 private static final Parser minus = word("-"); 152 private static final Parser mul = word("*"); 153 private static final Parser div = word("/"); 154 private static final Parser mod = word("%"); 155 156 private static final Parser word_case = word("case"); 157 private static final Parser word_when = word("when"); 158 private static final Parser word_then = word("then"); 159 private static final Parser word_else = word("else"); 160 private static final Parser word_end = word("end"); 161 private static final Parser word_null = word("null"); 162 163 164 private static Map2 toMap2(final BinaryOp op){ 165 return new Map2(){ 166 public Object map(final Object o1, final Object o2){ 167 return op.apply((Expression)o1, (Expression)o2); 168 } 169 }; 170 } 171 private static Map toMap(final UnaryOp op){ 172 return new Map(){ 173 public Object map(final Object o){ 174 return op.apply((Expression)o); 175 } 176 }; 177 } 178 private static Parser retnMap2(final BinaryOp op){ 179 return Parsers.retn(toMap2(op)); 180 } 181 private static Parser retnMap(final UnaryOp op){ 182 return Parsers.retn(toMap(op)); 183 } 184 private static Parser parse(){ 185 final Parser decimalLiteral = Terms.decimalParser(new FromString(){ 186 public Object fromString(int from, int len, final String s){ 187 return new DecimalLiteral(s.toString()); 188 } 189 }); 190 final Parser stringLiteral = Terms.stringParser(new FromString(){ 191 public Object fromString(int from, int len, final String s){ 192 return new StringLiteral(s.toString()); 193 } 194 }); 195 final Parser name_fun = qualifiedId.bind(new ToParser(){ 196 public Parser toParser(final Object o){ 197 final QualifiedName qn = new QualifiedName((Id[])o); 198 final Parser fun = Parsers.between(lparen, rparen, 199 Parsers.sepBy(Expression.class, comma, expr())).map(new Map(){ 200 public Object map(final Object a){ 201 return new FunctionCall(qn, (Expression[])a); 202 } 203 }); 204 return Parsers.plus(fun, Parsers.retn(new QualifiedNameLiteral(qn))); 205 } 206 }); 207 208 final Map2 _make_whenthen1 = new Map2(){ 209 public Object map(final Object o1, final Object o2){ 210 final Expression e1 = (Expression)o1; 211 final Expression e2 = (Expression)o2; 212 return new WhenThen(e1, e2); 213 } 214 }; 215 final Parser whenthen1 = 216 word_when.seq(lazy_expr.followedBy(word_then).and(lazy_expr, _make_whenthen1)); 217 218 final Map2 _make_whenthen2 = new Map2(){ 219 public Object map(final Object o1, final Object o2){ 220 final BoolExpression e1 = (BoolExpression)o1; 221 final Expression e2 = (Expression)o2; 222 return new BoolWhenThen(e1, e2); 223 } 224 }; 225 final Parser whenthen2 = 226 word_when.seq(lazy_bool_expr.followedBy(word_then).and(lazy_expr, _make_whenthen2)); 227 final Parser default_case = word_else.seq(lazy_expr); 228 final ToParser _case1_rest = new ToParser(){ 230 public Parser toParser(final Object o){ 231 final Expression e = (Expression)o; 232 final Parser whenthens = whenthen1.many1(WhenThen.class); 233 final Parser def = Parsers.option(null, default_case); 234 235 236 return whenthens.and(def, new Map2(){ 237 public Object map(final Object o1, final Object o2){ 238 final WhenThen[] wts = (WhenThen[])o1; 239 final Expression d = (Expression)o2; 240 return new ExpressionCase(e, wts, d); 241 } 242 }); 243 } 244 }; 245 final Parser case1 = word_case.seq(lazy_expr.bind(_case1_rest)).followedBy(word_end); 246 247 final Parser casewhen_ind = word_case.seq(word_when.peek()).atomize(); 248 final Map2 _make_case2 = new Map2(){ 249 public Object map(final Object o1, final Object o2){ 250 final BoolWhenThen[] bwts = (BoolWhenThen[])o1; 251 final Expression d = (Expression)o2; 252 return new ExpressionCaseWhen(bwts, d); 253 } 254 }; 255 final Parser _case2_rest = Parsers.lazy("case when", new ParserEval(){ 256 public Parser eval(){ 257 final Parser whenthens = whenthen2.many1(BoolWhenThen.class); 258 final Parser def = Parsers.option(null, default_case); 259 return whenthens.and(def, _make_case2); 260 } 261 }); 262 final Parser case2 = casewhen_ind.seq(_case2_rest).followedBy(word_end); 263 final Parser retn_null = Parsers.retn(NullLiteral.instance()); 264 final Parser expr_null = word_null.seq(retn_null); 265 final Parser op_plus = plus.seq(retnMap2(PlusOp.instance())); 266 final Parser op_minus = minus.seq(retnMap2(MinusOp.instance())); 267 final Parser op_mul = mul.seq(retnMap2(MulOp.instance())); 268 final Parser op_div = div.seq(retnMap2(DivOp.instance())); 269 final Parser op_positive = plus.seq(retnMap(PositiveOp.instance())); 270 final Parser op_negative = minus.seq(retnMap(NegativeOp.instance())); 271 final Parser op_bitand = ampersand.seq(retnMap2(BitAndOp.instance())); 272 final Parser op_bitor = bar.seq(retnMap2(BitOrOp.instance())); 273 final Parser op_mod = mod.seq(retnMap2(ModOp.instance())); 274 294 295 final Parser atom_expr= Parsers.sum( 296 new Parser[]{ 297 expr_null, 298 stringLiteral, 299 decimalLiteral, 300 name_fun, 301 case2, 302 case1 303 } 304 ); 305 final Parser term = Parsers.plus( 306 Parsers.between(lparen, rparen, lazy_expr), 307 atom_expr 308 ); 309 final OperatorTable operators = new OperatorTable(); 310 operators.prefix(op_positive, Precedences.positive()) 311 .prefix(op_negative, Precedences.negative()) 312 .infixl(op_bitand, Precedences.bitand()) 313 .infixl(op_bitor, Precedences.bitor()) 314 .infixl(op_plus, Precedences.plus()) 315 .infixl(op_minus, Precedences.minus()) 316 .infixl(op_mul, Precedences.mul()) 317 .infixl(op_div, Precedences.div()) 318 .infixl(op_mod, Precedences.mod()); 319 return Expressions.buildExpressionParser("expression", term, operators); 320 332 } 333 private static final Parser parser = parse(); 334 } 335 336 337 338 339 340 private static final class BoolExprP{ 341 private static final Parser word_and = word("and"); 342 private static final Parser word_or = word("or"); 343 private static final Parser eq = word("="); 344 private static final Parser ne = Parsers.plus(word("<>"), word("!=")); 345 private static final Parser word_is = word("is"); 346 private static final Parser word_not = word("not"); 347 private static final Parser word_null = word("null"); 348 private static final Parser word_between = word("between"); 349 private static final Parser word_in = word("in"); 350 private static final Parser word_exists = word("exists"); 351 private static final Parser word_like = word("like"); 352 private static final Parser word_escape = word("escape"); 353 354 private static final Parser lt = word("<"); 355 private static final Parser le = word("<="); 356 private static final Parser gt = word(">"); 357 private static final Parser ge = word(">="); 358 private static final Parser expr = expr(); 359 private static Parser parse(){ 360 final Parser word_notlike = word_not.seq(word_like).atomize(); 361 final Parser word_notin = word_not.seq(word_in).atomize(); 362 final Parser word_notnull = word_not.seq(word_null); 363 final Parser op_not = word_not.seq(Parsers.retn(new Map(){ 364 public Object map(final Object o){ 365 final BoolExpression e = (BoolExpression)o; 366 return new ExpressionNot(e); 367 } 368 })); 369 final Parser logical_infix = Parsers.sum(new Parser[]{ 371 eq.seq(lretnMap2(EqOp.instance())), 372 ne.seq(lretnMap2(NeOp.instance())), 373 le.seq(lretnMap2(LeOp.instance())), 374 ge.seq(lretnMap2(GeOp.instance())), 375 lt.seq(lretnMap2(LtOp.instance())), 376 gt.seq(lretnMap2(GtOp.instance())) 377 }); 378 380 final ToParser _bool_atom_rest = new ToParser(){ 381 public Parser toParser(final Object obj){ 382 final Expression e1 = (Expression)obj; 383 final Parser compare = 384 logical_infix.and(expr, new Map2(){ 385 public Object map(final Object oop, final Object oe2){ 386 final Map2 op = (Map2)oop; 387 return op.map(e1, oe2); 388 } 389 }); 390 final Parser nulls = word_is.seq( 391 Parsers.plus( 392 word_notnull 393 .seq(Parsers.retn(new IsNotNull(e1))), 394 word_null 395 .seq(Parsers.retn(new IsNull(e1))) 396 ) 397 ); 398 final Parser between = word_between.seq( 399 expr.followedBy(word_and).and(expr, new Map2(){ 400 public Object map(final Object o1, final Object o2){ 401 final Expression a = (Expression)o1; 402 final Expression b = (Expression)o2; 403 return new ExpressionBetween(e1, a, b); 404 } 405 }) 406 ); 407 final Parser expr_list = Parsers.between(lparen, rparen, 408 Parsers.sepEndBy1(Expression.class, comma, expr)); 409 410 final Parser in = word_in.seq(expr_list) 411 .map(new Map(){ 412 public Object map(final Object a){ 413 return new ExpressionIn(e1, (Expression[])a); 414 } 415 }); 416 final Parser not_in = word_notin.seq(expr_list).map(new Map(){ 417 public Object map(final Object o){ 418 return BoolExpressions.notIn(e1, (Expression[])o); 419 } 420 }); 421 423 final Parser in_relation = word_in.seq(subquery) 424 .map(new Map(){ 425 public Object map(final Object o){ 426 final Table tab = (Table)o; 427 return BoolExpressions.inQuery(e1, tab.getStmt()); 428 } 429 }); 430 431 432 final Parser not_in_relation = word_notin.seq(subquery) 433 .map(new Map(){ 434 public Object map(final Object o){ 435 final Table tab = (Table)o; 436 return BoolExpressions.notInQuery(e1, tab.getStmt()); 437 } 438 }); 439 final Parser like = word_like.seq(expr) 440 .and(word_escape.seq(expr).option(null), new Map2(){ 441 public Object map(final Object a, final Object b){ 442 return BoolExpressions.like(e1, (Expression)a, (Expression)b); 443 } 444 }); 445 final Parser notlike = word_notlike.seq(expr) 446 .and(word_escape.seq(expr).option(null), new Map2(){ 447 public Object map(final Object a, final Object b){ 448 return BoolExpressions.notLike(e1, (Expression)a, (Expression)b); 449 } 450 }); 451 452 453 return Parsers.sum(new Parser[]{ 454 compare, nulls, between, like, notlike, 455 Parsers.plus(in_relation, in).lookahead(3), 456 Parsers.plus(not_in_relation, not_in).lookahead(3)}); 457 } 458 }; 459 final Map _make_exists = new Map(){ 460 public Object map(final Object o){ 461 final Table tab = (Table)o; 462 return BoolExpressions.exists(tab.getStmt()); 463 } 464 }; 465 final Parser bool_atom = 466 Parsers.plus(word_exists.seq(subquery).map(_make_exists), expr.bind(_bool_atom_rest)); 469 470 final Parser bool_term = Parsers.plus( 471 Parsers.between(lparen, rparen, lazy_bool_expr) 472 ,bool_atom 473 ); 474 final OperatorTable logical_operators = new OperatorTable() 475 .prefix(op_not, Precedences.not()) 476 .infixl(word_or.seq(bretnMap2(OrOp.instance())), Precedences.or()) 477 .infixl(word_and.seq(bretnMap2(AndOp.instance())), Precedences.and()); 478 return Expressions.buildExpressionParser("bool_expr", bool_term, logical_operators); 479 486 } 487 private static final Parser parser = parse(); 488 } 489 490 510 511 512 public static final Parser word_from = word("from"); 513 public static final Parser word_where = word("where"); 514 public static final Parser word_group = word("group"); 515 public static final Parser word_having = word("having"); 516 public static final Parser word_order = word("order"); 517 public static final Parser word_by = word("by"); 518 public static final Parser word_desc = word("desc"); 519 public static final Parser word_asc = word("asc"); 520 public static final Parser word_inner = word("inner"); 521 public static final Parser word_outer = word("outer"); 522 public static final Parser word_left = word("left"); 523 public static final Parser word_right = word("right"); 524 public static final Parser word_full = word("full"); 525 public static final Parser word_join = word("join"); 526 public static final Parser word_cross = word("cross"); 527 public static final Parser word_as = word("as"); 528 public static final Parser word_on = word("on"); 529 public static final Parser word_wildcard = word("*"); 530 final static Map fromAlias = new Map(){ 531 public Object map(final Object o){ 532 return TableName.alias((Alias)o); 533 } 534 }; 535 final static Map fromQname = new Map(){ 536 public Object map(final Object o){ 537 return TableName.qname((QualifiedName)o); 538 } 539 }; 540 private static Map2 joinMap2(final int type){ 541 return new Map2(){ 542 public Object map(final Object o1, final Object o2){ 543 return new Map(){ 544 public Object map(final Object o){ 545 return Relations.join((Relation)o, type, (Relation)o1, (BoolExpression)o2); 546 } 547 }; 548 } 549 }; 550 } 551 552 final static Parser naked_table_name = qualifiedName.bind(new ToParser(){ 554 public Parser toParser(final Object o){ 555 final QualifiedName qn = (QualifiedName)o; 556 return aliased(Parsers.retn(Table.qname(qn))).map(fromAlias) 557 .option(TableName.qname(qn)); 558 } 559 }); 560 private static final Parser alias_as = word_as.optional().seq(id); 561 private static final Map2 _make_alias = new Map2(){ 562 public Object map(final Object o1, final Object o2){ 563 return new Alias((Id)o2, (Table)o1); 564 } 565 }; 566 private static final Parser optional_alias = alias_as.option(null); 567 public static Parser aliased(final Parser p){ return p.and(alias_as, _make_alias); 569 } 570 private static final Parser table_name = Parsers.plus( 571 aliased(subquery).map(fromAlias), naked_table_name 572 ); 573 574 final static Parser inner = word_inner.optional(); 576 final static Parser left = word_left.seq(word_outer.optional()); 577 final static Parser right = word_right.seq(word_outer.optional()); 578 final static Parser full = word_full.seq(word_outer.optional()); 579 private static final Parser join_op = Parsers.lazy("lazy join", new ParserEval(){ 580 public Parser eval(){ 581 return Parsers.plus( 582 parseJoinRest(inner, Join.INNER), 583 parseJoinRest(left, Join.LEFT), 584 parseJoinRest(right, Join.RIGHT), 585 parseJoinRest(full, Join.FULL) 586 ); 587 } 588 }); 589 590 private static final Parser relation_term = 591 Parsers.plus( 592 table_name.map("table name", new Map(){ 593 public Object map(final Object o){ 594 return Relations.tablename((TableName)o); 595 } 596 }), 597 Parsers.between("joined relations", lparen, rparen, 598 lazy_relation 599 ).atomize() 600 ).lookahead(2); 601 private static final Parser lazy_relation_term = Parsers.lazy(new ParserEval(){ 604 public Parser eval(){return relation_term;} 605 }); 606 private static final Parser crossjoin = word_cross.seq(word_join); 607 private static final Parser cross_op = crossjoin.seq(lazy_relation_term) 608 .map(new Map(){ 609 public Object map(final Object o){ 610 return new Map(){ 611 public Object map(final Object o1){ 612 return Relations.product((Relation)o1, (Relation)o); 613 } 614 }; 615 } 616 }); 617 private static final Parser parseRelation = 618 Parsers.postfix("relation", 619 Parsers.plus(join_op, cross_op), 620 relation_term 621 ); 622 private static Parser parseRelation(){return parseRelation;} 623 private static Parser parseJoinRest(final Parser p, final int type){ 624 return p.seq(word_join).seq(parseRelation) 625 .and(word_on.seq(bool_expr()), joinMap2(type)); 626 } 627 628 629 631 632 633 private static final Parser expr1 = Parsers.sepEndBy1("expr+", Expression.class, comma, expr()); 634 private static final Parser whereClause = word_where.seq("where", bool_expr()); 636 private static final Parser having = word_having.seq("having", bool_expr()); 637 private static final Parser word_groupby = word_group.seq(word_by); 639 private static final Map2 to_group_by = new Map2(){ 640 public Object map(final Object o1, final Object o2){ 641 return new GroupBy((Expression[])o1, (BoolExpression)o2); 642 } 643 }; 644 private static final Parser groupbyClause = word_groupby 645 .seq("group by", expr1) 646 .and(having.option(null), to_group_by); 647 private static Parser defaultValue(final Parser p, final Parser v){ 649 return Parsers.plus(p.seq(v), v); 650 } 651 private static final Parser order_expr = 652 Parsers.map2(expr(), 653 Parsers.plus(word_desc.seq(Parsers.retn(Boolean.valueOf(false))), 654 defaultValue(word_asc, Parsers.retn(Boolean.valueOf(true))) 655 ), 656 new Map2(){ 657 public Object map(final Object a, final Object b){ 658 final Expression e = (Expression)a; 659 final Boolean ord = (Boolean )b; 660 return new OrderExpr(e, ord.booleanValue()); 661 } 662 } 663 ); 664 private static final Parser order_expr1 = 665 Parsers.sepEndBy1("order_expr+", OrderExpr.class, comma, order_expr); 666 private static final Parser word_orderby = word_order.seq(word_by); 668 private static final Parser orderbyClause = 669 word_orderby.seq(order_expr1); 670 671 private static final Parser fromClause = 673 word_from.seq( 674 Parsers.sepEndBy1("from", Relation.class, comma, 675 parseRelation() 676 ) 677 ); 678 private static final Parser retn_asterisk = Parsers.retn(SelectExpr.asterisk()); 680 private static final Map2 _make_select_expr = new Map2(){ 681 public Object map(final Object a, final Object b){ 682 return SelectExpr.expr((Expression)a, (Id)b); 683 } 684 }; 685 private static final Parser select_expr = 686 Parsers.plus("*|expr [[as] id]", 687 word_wildcard.seq(retn_asterisk), 688 expr().and(optional_alias, _make_select_expr) 689 ); 690 private static final Parser select_expr1 = 692 Parsers.sepEndBy1("(*|select_expr)+", SelectExpr.class, comma, select_expr); 693 private static Parser parseSelectStmt(){ 694 final Parser sel = word_select.seq(select_expr1); 695 final Parser from = fromClause.option(null); 696 final Parser where = whereClause.option(null); 697 final Parser group = groupbyClause.option(null); 698 final Parser order = orderbyClause.option(null); 699 return Parsers.mapn(new Parser[]{ 700 sel, from, where, group, order 701 }, new Mapn(){ 702 public Object map(final Object [] arr){ 703 return new Select((SelectExpr[])arr[0], (Relation[])arr[1], (BoolExpression)arr[2], 704 (GroupBy)arr[3], (OrderExpr[])arr[4]); 705 } 706 }); 707 } 708 709 private static final Parser selectStmt = parseSelectStmt(); 710 public static Expression parse_expr( 711 final CharSequence src, String module){ 712 return (Expression)parse( 713 src, 714 getSqlLexer(), 715 expr().followedBy(Parsers.eof()), 716 module); 717 } 718 public static Object parse(final Parser p, 719 final CharSequence src, String module){ 720 return parse( 721 src, 722 getSqlLexer(), 723 p.followedBy(Parsers.eof()), 724 module 725 ); 726 } 727 public static Select parse_select( 728 final CharSequence src, String module){ 729 return (Select)parse( 730 src, 731 getSqlLexer(), 732 selectStmt.followedBy(Parsers.eof()), 733 module 734 ); 735 } 736 private static Object parse(final CharSequence src, final Parser lexer, 737 final Parser p, String module){ 738 return Parsers.runParser(src, Parsers.parseTokens(lexer, p, module), 739 new DefaultPositionMap(src, 1, 1), module); 740 } 741 private static Parser getSqlLexer(){ 742 return Lexers.lexeme(Scanners.sqlDelimiter(), 743 Parsers.plus(Lexers.sqlStringLiteral(), Lexers.decimal(), words.getLexer(), 744 quotedId('"', '"'), 745 quotedId('[', ']') 746 )); 747 } 748 private static Parser quotedId(final char open, final char close){ 749 return Lexers.lexer(Scanners.quoted(open, close), TokenQuoted.getTokenizer(open, close)); 751 } 752 private static Parser toLexer(Parser s, Tokenizer tn){ 753 return Lexers.lexer(s, tn); 754 } 755 } | Popular Tags |