Oisin Hurley wrote:
Hi Vadim,
Have you got an ANTLR grammar, or BNF of some kind for the DSL?  This
is probably a good opportunity for me to learn how to use XText at
long last :)  Unless anyone else has made a start...?

 --oh


Hi Oisin,

That would be great!
Here is the current grammar (antlr v-3.1):

================================================================
grammar Camel;
options { output = AST; }

tokens {
        ROUTES; FUNCTION; PARAMS; THEN; PROCESS; TEXT;
}

@header { package org.mycompany.test; }
@lexer::header { package org.mycompany.test; }

routes :
        route+ -> ^(ROUTES route+)
        ;

/* TODO:
        Dead Letter Channel
        TransactionErrorHandler
        loggingErrorHandler
        exception
        BAM
        Recipient List: to el:'new string[] {'a','b'}' or whatever el syntax is
        splitter
        aggregator
        resequencer
        routingSlip
        throttler
        delayer
        loadBalance
        multicast
        loop
        policy/transactions
        DelayPolicy
        idempotentConsumer
        
*/
route :
        ROUTE from process* -> ^(ROUTE from process*)
        ;
        
from :
        FROM fromTarget -> ^(FROM fromTarget)
        | FROM '{' fromTarget+ '}' -> ^(FROM fromTarget+)
        ;
        
fromTarget
        : endpoint // TODO: can it be multiple endpoints?
        ;

to
        : TO toTarget -> ^(TO toTarget)
        | TO '{' toTarget+ '}' -> ^(TO toTarget+)
        ;

toTarget
        : endpoint
        | process
        ;

/*endpoints :   
        endpoint
        | LCUR_PAREN endpoint+ RCUR_PAREN -> ^(endpoint)+
        ;
*/

endpoint
        : singleLineString
        //| ifExpr
        ;
        
// TODO: nested IF
ifExpr
options {backtrack=true;} // TODO: make sure that "sliding else" works correctly : IF '(' boolExpression ')' p1=processes ELSE p2=processes -> ^(IF boolExpression ^(THEN $p1) ^(ELSE $p2))
        | IF '(' boolExpression ')' processes -> ^(IF boolExpression processes)
        ;

boolExpression :        
        //orExpression
        boolValue
        ;

boolFunction:
        LITERAL ':' anyString -> ^(FUNCTION LITERAL anyString)
        ;

boolValue :     
        boolFunction
        | value compare value
        | TRUE
        | FALSE
        ;
        
value   
        : header
        | XPATH singleLineString -> ^(XPATH singleLineString)
        | singleLineString
        | BODY
        ;
        
header  
        : HEADER  singleLineString -> ^(HEADER LITERAL[$singleLineString.text])
        | HEADER '.' LITERAL -> ^(HEADER LITERAL[$LITERAL.text])
| HEADER '[' singleLineString ']' -> ^(HEADER LITERAL[$singleLineString.text])
        ;

        
compare :       
        LT
        | GT
        | EQ
        | LE
        | GE
        | NE
        ;

boolOperator :  
        OR
        | AND
        | NOT
        ;

        
process :
        to
        |ifExpr
        | SET header '=' singleLineString -> ^(SET header singleLineString)
        | SET BODY '=' anyString -> ^(SET BODY anyString)
        | splitter
        | BEAN SINGLE_Q_STRING -> ^(BEAN SINGLE_Q_STRING)
        //| MULTICAST '{' process* '}' -> ^(MULTICAST process*)
        //| PIPELINE '{' process_list '}'
        | SPLIT SINGLE_Q_STRING
        //| AGGREGATE expression
        | AGGREGATE
        //| resequence
        ;
        
processes:
        process -> ^(PROCESS process)
        | '{' process+ '}' -> ^(PROCESS process+)
        ;

splitter:       
SPLITTER '(' list=value token=singleLineString? ')' /*aggregationStrategy? TODO: */
                -> ^(SPLITTER $list $token)
        ;
/* TODO */
/*aggregationStrategy
        :       
        ;*/
        
/*resequence :
        RESEQUENCE BATCH
        //| BATCH RESEQUENCE expression
        | BATCH RESEQUENCE NUMBER NUMBER
        //| BATCH RESEQUENCE NUMBER NUMBER '(' expression_list ')'
        //| STREAM RESEQUENCE resequence_options
        //| STREAM RESEQUENCE resequence_options '(' expression ')'
        ;
*/
        
anyString       :       
        SINGLE_Q_STRING -> ^(TEXT[$SINGLE_Q_STRING.text])
        | SINGLE_Q_MULTILINE_STRING -> ^(TEXT[$SINGLE_Q_MULTILINE_STRING.text])
        | DOUBLE_Q_STRING -> ^(TEXT[$DOUBLE_Q_STRING.text])
        | DOUBLE_Q_MULTILINE_STRING -> ^(TEXT[$DOUBLE_Q_MULTILINE_STRING.text])
        ;
        
singleLineString :
        SINGLE_Q_STRING
        | DOUBLE_Q_STRING
        ;

/*********************************************
                Lexer
*********************************************/

ROUTE   :       'route';
FROM    :       'from';
TO      :       'to';
BEAN    :       'bean';
MULTICAST:      'multicast';
PIPELINE:       'pipeline';
SPLIT   :       'split';
AGGREGATE:      'aggregate';
RESEQUENCE:     'resequence';
BATCH   :       'batch';
STREAM  :       'stream';
SET     :       'set';
HEADER  :       'header';
BODY    :       'body';
XPATH   :       'xpath';
SPLITTER:       'splitter';

IF      :       'if';
ELSE    :       'else';

LT      :       '<';
GT      :       '>';
EQ      :       '==';
LE      :       '<=';
GE      :       '>=';
NE      :       ('!='|'<>');

OR      :       '||'|'or';
AND     :       '&&'|'and';
NOT     :       '!'|'not';
TRUE    :       'true';
FALSE   :       'false';

NUMBER  :       '0'..'9'+;

SINGLE_Q_STRING : '\'' ~('\''|'\n'|'\r')* '\'' {setText(getText().substring(1, getText().length()-1));} ; SINGLE_Q_MULTILINE_STRING : '\'' ~('\'')* '\'' {setText(getText().substring(1, getText().length()-1));} ; DOUBLE_Q_STRING : '"' ~('"'|'\n'|'\r')* '"' {setText(getText().substring(1, getText().length()-1));} ; DOUBLE_Q_MULTILINE_STRING : '"' ~('"')* '"' {setText(getText().substring(1, getText().length()-1));} ;


LITERAL :       ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*;
WS  : (' '|'\r'|'\n'|'\t')+ {$channel = HIDDEN;} ;
COMMENT
    :   '/*' .* '*/' {$channel=HIDDEN;}
    ;
LINE_COMMENT
    : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    ;

Reply via email to