grammar SLQ; // "@mysql_db1 | .user, .address | join(.user.uid == .address.uid) | .[0:3] | .uid, .username, .country" stmtList: ';'* query ( ';'+ query)* ';'*; query: segment ('|' segment)*; segment: (element) (',' element)*; element: dsTblElement | dsElement | selElement | join | group | rowRange | fn | expr; cmpr: LT_EQ | LT | GT_EQ | GT | EQ | NEQ; //whereExpr // : expr ; fn: fnName '(' ( expr ( ',' expr)* | '*')? ')'; join: ('join' | 'JOIN' | 'j') '(' joinConstraint ')'; joinConstraint: SEL cmpr SEL // .user.uid == .address.userid | SEL ; // .uid group: ('group' | 'GROUP' | 'g') '(' SEL (',' SEL)* ')'; selElement: SEL; dsTblElement: DATASOURCE SEL; // data source table element, e.g. @my1.user dsElement: DATASOURCE; // data source element, e.g. @my1 // [] select all rows [10] select row 10 [10:15] select rows 10 thru 15 [0:15] select rows 0 thru 15 // [:15] same as above (0 thru 15) [10:] select all rows from 10 onwards rowRange: '.[' ( NN COLON NN // [10:15] | NN COLON // [10:] | COLON NN // [:15] | NN // [10] )? ']'; fnName: 'sum' | 'SUM' | 'avg' | 'AVG' | 'count' | 'COUNT' | 'where' | 'WHERE'; expr: SEL | literal | unaryOperator expr | expr '||' expr | expr ( '*' | '/' | '%') expr | expr ( '+' | '-') expr | expr ( '<<' | '>>' | '&') expr | expr ( '<' | '<=' | '>' | '>=') expr | expr ( '==' | '!=' |) expr | expr '&&' expr | fn ; // | fnName '(' ( expr ( ',' expr )* | '*' )? ')' literal: NN | NUMBER | STRING | NULL; unaryOperator: '-' | '+' | '~' | '!'; ID: [a-zA-Z_][a-zA-Z0-9_]*; WS: [ \t\r\n]+ -> skip; LPAR: '('; RPAR: ')'; LBRA: '['; RBRA: ']'; COMMA: ','; PIPE: '|'; COLON: ':'; NULL: 'null' | 'NULL'; NN: INTF; // NN: Natural Number {0,1,2,3, ...} NUMBER: NN | '-'? INTF '.' [0-9]+ EXP? // 1.35, 1.35E-9, 0.3, -4.5 | '-'? INTF EXP // 1e10 -3e4 | '-'? INTF ; // -3, 45 fragment INTF: '0' | [1-9] [0-9]*; // no leading zeros fragment EXP: [Ee] [+\-]? INTF; // \- since - means "range" inside [...] LT_EQ: '<='; LT: '<'; GT_EQ: '>='; GT: '>'; NEQ: '!='; EQ: '=='; SEL: '.' ID ('.' ID)*; // SEL can be .THING or .THING.OTHERTHING etc. DATASOURCE: '@' ID; // DS (Data Source): @mydb1 or @postgres_db2 etc. STRING: '"' (ESC | ~["\\])* '"'; fragment ESC: '\\' (["\\/bfnrt] | UNICODE); fragment UNICODE: 'u' HEX HEX HEX HEX; fragment HEX: [0-9a-fA-F]; //NUMERIC_LITERAL // : DIGIT+ ( '.' DIGIT* )? ( E [-+]? DIGIT+ )? | '.' DIGIT+ ( E [-+]? DIGIT+ )? ; fragment DIGIT: [0-9]; fragment A: [aA]; fragment B: [bB]; fragment C: [cC]; fragment D: [dD]; fragment E: [eE]; fragment F: [fF]; fragment G: [gG]; fragment H: [hH]; fragment I: [iI]; fragment J: [jJ]; fragment K: [kK]; fragment L: [lL]; fragment M: [mM]; fragment N: [nN]; fragment O: [oO]; fragment P: [pP]; fragment Q: [qQ]; fragment R: [rR]; fragment S: [sS]; fragment T: [tT]; fragment U: [uU]; fragment V: [vV]; fragment W: [wW]; fragment X: [xX]; fragment Y: [yY]; fragment Z: [zZ]; LINECOMMENT: '//' .*? '\n' -> skip;