DSL status

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

DSL status

Vadim Chekan
Hi all,
I've made some progress on DSL and syntax covers some basic needs (see
below, all use cases are working now).
I'm working on including more advanced features like splitter, delay, etc.
Let me know what do you think about the syntax.

Vadim.

Here is my current test file:
/*
                route from 'timer://kickoff?period=10000&delay=1' to 'mock:output1'
                */
               
                /*route from {
                        'timer://kickoff_1?period=10000&delay=1'
                        // buggy: CAMEL-927
                        'timer://kickoff_2?period=10000&delay=1'
                }*/
               
                /*route from {
                        'timer://kickoff_3?period=10000&delay=1'
                        'timer://kickoff_4?period=5000&delay=1'
                } to {
                        'mock:output_3'
                        'mock:output_4'
                }
                */
               
                /*route from 'timer://kickoff_6?period=10000'
                        to if(true)
                                'mock:true'
                */

                /*route from 'timer://kickoff_5?period=10000'
                        to if(false)
                                'mock:true'
                        else
                                'mock:false'
                */
               
                /*route from 'timer://kickoff_5?period=10000'
                to if(el:'in.headers.myHeader=="aaa"')
                                'mock:output_5'
                        else
                                'mock:output_6'
                */
               
                /*
                route from 'timer://kickoff_5?period=10000'
                set header.a='aa'
                set body='bbb'
                if(groovy:"request.headers.a == 'aa'") {
                        to 'mock:true'
                }
                else
                        to 'mock:false'
                */
               
               
                route from 'timer://kickoff_5?period=10000'
                //set header['myHeader']='aaa'
                set header.c="c"
                set header['d']="d"
                set body='the body'
                if(groovy:'request.headers.myHeader=="aaa"') {
                                to 'mock:output_5'
                                to 'mock:output_6'
                } else if(groovy:'request.headers["c"] == "c"') {
                                if(groovy:"request.headers.d == 'd'")
                                        to 'mock:output_7'
                                else
                                        to 'mock:output_8'
                } else {
                                to 'mock:b5'
                }
Reply | Threaded
Open this post in threaded view
|

Re: DSL status

jstrachan
Looks great :). Want to submit a patch and we can commit it to trunk?

2008/10/9 Vadim Chekan <[hidden email]>:

> Hi all,
> I've made some progress on DSL and syntax covers some basic needs (see
> below, all use cases are working now).
> I'm working on including more advanced features like splitter, delay, etc.
> Let me know what do you think about the syntax.
>
> Vadim.
>
> Here is my current test file:
> /*
>                route from 'timer://kickoff?period=10000&delay=1' to
> 'mock:output1'
>                */
>
>                /*route from {
>                        'timer://kickoff_1?period=10000&delay=1'
>                        // buggy: CAMEL-927
>                        'timer://kickoff_2?period=10000&delay=1'
>                }*/
>
>                /*route from {
>                        'timer://kickoff_3?period=10000&delay=1'
>                        'timer://kickoff_4?period=5000&delay=1'
>                } to {
>                        'mock:output_3'
>                        'mock:output_4'
>                }
>                */
>
>                /*route from 'timer://kickoff_6?period=10000'
>                        to if(true)
>                                'mock:true'
>                */
>
>                /*route from 'timer://kickoff_5?period=10000'
>                        to if(false)
>                                'mock:true'
>                        else
>                                'mock:false'
>                */
>
>                /*route from 'timer://kickoff_5?period=10000'
>                to if(el:'in.headers.myHeader=="aaa"')
>                                'mock:output_5'
>                        else
>                                'mock:output_6'
>                */
>
>                /*
>                route from 'timer://kickoff_5?period=10000'
>                set header.a='aa'
>                set body='bbb'
>                if(groovy:"request.headers.a == 'aa'") {
>                        to 'mock:true'
>                }
>                else
>                        to 'mock:false'
>                */
>
>
>                route from 'timer://kickoff_5?period=10000'
>                //set header['myHeader']='aaa'
>                set header.c="c"
>                set header['d']="d"
>                set body='the body'
>                if(groovy:'request.headers.myHeader=="aaa"') {
>                                to 'mock:output_5'
>                                to 'mock:output_6'
>                } else if(groovy:'request.headers["c"] == "c"') {
>                                if(groovy:"request.headers.d == 'd'")
>                                        to 'mock:output_7'
>                                else
>                                        to 'mock:output_8'
>                } else {
>                                to 'mock:b5'
>                }
>



--
James
-------
http://macstrac.blogspot.com/

Open Source Integration
http://open.iona.com
Reply | Threaded
Open this post in threaded view
|

Re: DSL status

Oisin Hurley
In reply to this post by Vadim Chekan
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
Reply | Threaded
Open this post in threaded view
|

Re: DSL status

jstrachan
2008/10/9 Oisin Hurley <[hidden email]>:
> 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 :)

Yay! Go Oisin! :)

> Unless anyone else has made a start...?

I made a crappy start a long time ago - probably with an old XText
version. Its currently here...
https://svn.apache.org/repos/asf/activemq/camel/ide/camel-eclipse/

the antlr grammar goes here...
https://svn.apache.org/repos/asf/activemq/camel/ide/camel-eclipse/camel.routing/src/camel.xtxt

there's even my failed attempt at turning the XText generated EMF
model into a graphic visualisation in there too :)

--
James
-------
http://macstrac.blogspot.com/

Open Source Integration
http://open.iona.com
Reply | Threaded
Open this post in threaded view
|

Re: DSL status

Vadim Chekan
In reply to this post by jstrachan
Sure,
It is not in the camel source tree yet, I'd need to add it and learn
maven. I'll do it soon.

Vadim.

James Strachan wrote:

> Looks great :). Want to submit a patch and we can commit it to trunk?
>
> 2008/10/9 Vadim Chekan <[hidden email]>:
>> Hi all,
>> I've made some progress on DSL and syntax covers some basic needs (see
>> below, all use cases are working now).
>> I'm working on including more advanced features like splitter, delay, etc.
>> Let me know what do you think about the syntax.
>>
>> Vadim.
>>
>> Here is my current test file:
>> /*
>>                route from 'timer://kickoff?period=10000&delay=1' to
>> 'mock:output1'
>>                */
>>
>>                /*route from {
>>                        'timer://kickoff_1?period=10000&delay=1'
>>                        // buggy: CAMEL-927
>>                        'timer://kickoff_2?period=10000&delay=1'
>>                }*/
>>
>>                /*route from {
>>                        'timer://kickoff_3?period=10000&delay=1'
>>                        'timer://kickoff_4?period=5000&delay=1'
>>                } to {
>>                        'mock:output_3'
>>                        'mock:output_4'
>>                }
>>                */
>>
>>                /*route from 'timer://kickoff_6?period=10000'
>>                        to if(true)
>>                                'mock:true'
>>                */
>>
>>                /*route from 'timer://kickoff_5?period=10000'
>>                        to if(false)
>>                                'mock:true'
>>                        else
>>                                'mock:false'
>>                */
>>
>>                /*route from 'timer://kickoff_5?period=10000'
>>                to if(el:'in.headers.myHeader=="aaa"')
>>                                'mock:output_5'
>>                        else
>>                                'mock:output_6'
>>                */
>>
>>                /*
>>                route from 'timer://kickoff_5?period=10000'
>>                set header.a='aa'
>>                set body='bbb'
>>                if(groovy:"request.headers.a == 'aa'") {
>>                        to 'mock:true'
>>                }
>>                else
>>                        to 'mock:false'
>>                */
>>
>>
>>                route from 'timer://kickoff_5?period=10000'
>>                //set header['myHeader']='aaa'
>>                set header.c="c"
>>                set header['d']="d"
>>                set body='the body'
>>                if(groovy:'request.headers.myHeader=="aaa"') {
>>                                to 'mock:output_5'
>>                                to 'mock:output_6'
>>                } else if(groovy:'request.headers["c"] == "c"') {
>>                                if(groovy:"request.headers.d == 'd'")
>>                                        to 'mock:output_7'
>>                                else
>>                                        to 'mock:output_8'
>>                } else {
>>                                to 'mock:b5'
>>                }
>>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: DSL status

Vadim Chekan
In reply to this post by Oisin Hurley
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;}
     ;