Skip to main content
Jump to: navigation, search

Difference between revisions of "RoadmapOAW5"

(Functions)
(Redirecting to OAW)
 
(18 intermediate revisions by 8 users not shown)
Line 1: Line 1:
{| border=0
+
#REDIRECT [[OAW]]
| width=90% |
+
== Successor to Xpand/Xtend (Work in progress - feedback is highly appreciated) ==
+
 
+
It's time to think about a possible successor to Xpand/Xtend. Although the languages have proven well compared to alternatives there are a number of things which can be better and clearer based on our two years of experience with Xpand and Xtend.
+
The main improvements we want to incorporate are:
+
 
+
=== Imports ===
+
The import mechanism should be reworked, so that every import is explicit.
+
We won't need any metamodel configuration in the workflow nor in the editors anymore.
+
This will not only make the setup simpler but will also improve the performance.
+
 
+
The syntax would change to something like the following:
+
 
+
import org:openarchitectureware:Extension; // native import
+
import EMF "my/package/model.ecore"; // non-native import
+
import UML "my/test.profile.uml" as profile; // non-native import with name space definition
+
import Java "my.test.Class"; // non-native import introduces java types and features form my.test.Class
+
import XSD "http://www.mywebsite.org/xsd/metamodel.xsd" // non-native import importing the types from an XSD file
+
... (think of Hibernate mapping files, Groovy, etc.)
+
 
+
==== Native import ====
+
A native import refers to another extension file imports all public members (types, functions, extensions).
+
 
+
==== Non-native Import ====
+
A non native import starts with an identifier pointing to an installed adapter.
+
The adapter is responsible for loading and converting the type information from the given string. The syntax in the string is defined by the adapter. The token directly after the
+
import keyword defines which adapter to use.
+
 
+
==== Namespace definition ====
+
All members are included without namespace information. If you need a namespace you can explicitely define one per import.
+
 
+
==== Reexport ====
+
The reexport keyword will be supported, so that
+
imported stuff (types and functions) will be reexported.
+
 
+
Example:
+
 
+
myext1.ext
+
 
+
  foo() : 'foo';
+
 
+
myext2.ext
+
 
+
  reexported import myext1;
+
  bar() : 'bar';
+
 
+
client.ext
+
 
+
  import myext2;
+
  fooBar() : foo()+bar();
+
 
+
=== Generics ===
+
We need full-fledged generics, which can conceptually be copied from Java's generics.
+
 
+
(complicated) Example:
+
  List<M> sort<T extends Comparable<T>, M>(List<M> toSort, (M)=>T closure)
+
 
+
which can be used like this
+
  ['aa','b'].sort(e|e.size); 
+
 
+
You don't have to deal with this complexity if you don't want to define functions which uses generics ;-)
+
 
+
=== Closures ===
+
We'll have real closures, not the built-in stuff we (or all OCL-based languages) have now.
+
This provides for much greater flexibility. In addition we can put all the higher-order functions into the standard library instead of hard code them into the framework.
+
Closure syntax:
+
 
+
  { parameterList '|' expression-using-parameters-and-scope }
+
 
+
Where parameter list must be typed, either implicitly or explicitly.
+
 
+
Example:
+
 
+
  {
+
    String myText := "test";
+
    (Attribute)=>Boolean myClosure := {e|e.name==myText};    // e is inferred from the declared type of the assignee
+
    myList.select(myClosure);
+
  }
+
 
+
alternatively declare the parameter types explicitly
+
  {
+
    var myText := "test";
+
    var myClosure := {Attribute e|e.name==myText};
+
    myList.select(myClosure);
+
  }
+
 
+
  // type of e is inferred from the declaration of the 'select()' function, you don't have to use the curly brackets.
+
  myList.select(e|e.name == "test")
+
 
+
MV: Very nice!
+
 
+
==== Type signatures of functions ====
+
The syntax for of a function's type signature looks as follows:
+
 
+
  (parameterTypes)=>returnType
+
 
+
MV: Just like in Scala :-)
+
 
+
Examples:
+
 
+
  ()=>Object
+
  (String)=>Boolean
+
  (String, Entity)=>Entity
+
 
+
Example 2: declaration of higher-order functions using generics :
+
 
+
  List<T> select<T>(List<T> this, (T)=>Boolean closure) {
+
    ...
+
  }
+
 
+
=== Functions ===
+
 
+
Functions can be invoked either using the functional syntax or using the member syntax (operation like, aka extensions):
+
 
+
  myFunction(foo, bar) == foo.myFuntion(bar)
+
 
+
A function is declared as follows:
+
 
+
  (private|cached|final) ReturnType? functionName(declaredParameterList) ( guardExpression )? : bodyExpression ;
+
 
+
Example:
+
  private doStuff(Entity this) name!=null :
+
      name+"Stuff";
+
 
+
The detailed semantics of how the polymorphic resolution works (what role guards play here) and is described in the upcoming section.
+
 
+
or
+
  (private|cached) functionName(declaredParameterList) guardExpression blockExpression
+
 
+
Example:
+
  cached makeAbstract(Entity this) {
+
      abstract := true;
+
      name := 'Abstract'+name;
+
      this;
+
  }
+
 
+
Block expressions are explained in their own section.
+
 
+
==== Polymorphic Resolution with signatures and guards ====
+
Usually polymorphism is based on the types of parameters. The same applies for Xtend++.
+
In contrast to e.g. Java we use the dynamic types (actual types at runtime) of a given set of parameters in order to find the function which
+
best fits (has the most specific declared paramter types).
+
 
+
Example:
+
given the following two functions
+
 
+
  foo(String x) : "string";
+
  foo(Object o) : "object";
+
 
+
these assertions can be made:
+
 
+
  foo('S') == "string"
+
  foo(34)  == "object"
+
  foo((Object)'S') == "string" // would be "object" in Java
+
 
+
MV: do you want to explain what happens if
+
    you have more than one parameter? Is the
+
    "this" parameter in any way special?
+
+
In addition to these concept, commonly known as "multiple dispatch" or "multi methods", we introduce guards which can be used to controll the resolution based on the state of a given object not only the type.
+
 
+
Example:
+
 
+
  foo(String x) x.length>5 : "long";
+
  foo(String x) : "short";
+
+
this assertions can be made:
+
 
+
  foo('honolulu') == 'long'
+
  foo("bar") == 'short'
+
 
+
The semantics are as follows:
+
 
+
* First select all possible features (functions and operations), based on the name and the given parameter types.
+
* Then order those features by parameter types (best match first).Those functions with the same parameter type should be order so that the ones having a guard defined come first.
+
 
+
pseudo code
+
 
+
  for (Feature f : features)  {
+
      if (f.hasGuard()) {
+
        if (f.guard.evaluate())
+
            return f; // return the feature where the guard evaluates to true
+
      } else {
+
        return f; // return the feature without a guard
+
      }
+
  }
+
  return null; // no invocation
+
 
+
* if there are features, but the guards evaluate to false, return null:
+
 
+
The static semantics are straight forward:
+
* The guard must be of type boolean.
+
 
+
====Extensions overwrite semantics====
+
Functions and Operations can be overwritten.
+
The precedence is based on th order of imports.
+
Functions from later declared imports overwrite functions introduced before.
+
Local functions overwrite imported functions.
+
Consider overwriting the toString() Operation  (which is invoked on String concatenations) for arbitrary meta types.
+
This will allow very readable templates.
+
 
+
==== dynamically scoped extension overwriting ====
+
Another thing we want to address is the way one can extend generators provided by third parties (like the one shipped with GMF).
+
So far everybody used AOP to "weave" customization and implementation in. The problem is that the generator designer does not really develop for extensibility and every Join Point becomes public API.
+
We've been thinking about  a concept called "dynamic extensions" which is a way to register extensions for a specific call graph.
+
 
+
Example:
+
 
+
  with(&toString(Entity)) {
+
    callGMFCartridge(myEntity);
+
  }
+
 
+
To explain: '&toString(Entity) is a literal pointing to the 'toString(Entity)'-function. So one could write '&toString(Entity).evaluate(myEntity)' instead of 'myEntity.toString()' for example. The implementation of the function will be used whenever such a function is invoked within the callGMFCartridge(Entity) function (the third party cartridge).
+
In other words  one overwrites the toString() function for Entities for the following block.
+
So what you as a generator developer could do is, provide a list of function which can be overwritten. In addition there is a final keyword, which prevents overwriting the corresponding function.
+
 
+
TO BE DISCUSSED: Do we need a keyword 'extendable' to formally mark functions? So far we have to use 'final' in order to forbid extending a function.
+
 
+
This won't be a replacement for AOP.
+
 
+
==== Grouping Functions / Context syntax ====
+
A file full of extensions always looks very unstructured so it is hard to find a certain function within such files.
+
Many times a set of functions is made for a specific type. We want to come up with a special syntax to define such functions within one context and remove duplicate information (the first parameter).
+
For example, this
+
<pre>
+
context Entity {
+
  Model getModel() : eContainer ;
+
 
+
  getAttributes() : fields.typeSelect(Attribute);
+
 
+
  getReferences() : fields.typeSelect(Reference);
+
}
+
</pre>
+
is the same as:
+
 
+
<pre>
+
Model getModel(Entity this) : eContainer ;
+
 
+
getAttributes(Entity this) : fields.typeSelect(Attribute);
+
 
+
getReferences(Entity this) : fields.typeSelect(Reference);
+
</pre>
+
 
+
The editor of course will be able to collapse those different contexts using standard folding mechanism.
+
 
+
=== Code blocks ===
+
 
+
A code block is the replacement for chain expressions ( a-> b-> x) with the additional features:
+
* provides variable declarations (Expression returning the assigned value)
+
 
+
It's something like a pseudo imperative syntax (but still is an expression!).
+
 
+
Variables are assign-once!
+
 
+
Example:
+
 
+
  myExtension(String stuff) {
+
    def x := stuff.length();
+
    if x>56 then
+
        "Foo"
+
    else
+
        "Bar";
+
    endif
+
  }
+
 
+
A code block is itself an expression consisting of a list of expressions.
+
It returns the value returned by the last expression.
+
 
+
It is possible to overwrite the scope.
+
Example:
+
 
+
  doStuff() {
+
    def x := "Foo";
+
    {
+
      def x:= "Bar";
+
      x;
+
    }
+
  }
+
 
+
will return "Bar"
+
 
+
 
+
=== Object creation expression ===
+
We are thinking about a syntax to create model graphs inline.
+
We need this not only for model transformations but also for writing model transformation tests.
+
 
+
Example:
+
 
+
  new Entity {
+
      name := "Person";
+
      references += new Reference {
+
          name := "someRef"
+
          type := anotherEntity
+
      }
+
  }
+
 
+
==== Assignment Expressions ====
+
They are just another syntax for invoking a setter resp. adder-operation.
+
They return the assigned value.
+
 
+
==== create / cache semantics ====
+
The creation expression should replace the "create extension" mechanism from Xtend 1.0.
+
A creation of an Object is cached if the type name is suffixed with parenthesis containing any number of arguments.
+
The arguments act as a key.
+
 
+
The scope of the caching is per execution context, which can be reused in several invocations?
+
 
+
MV: Why the question mark above?
+
+
Examples:
+
 
+
  var paramPerOperationAndName := new Parameter cachedwith op,name {
+
      this.name := name;
+
      type := aDatatype;
+
  }
+
 
+
  var localSingleton := new Foo cachedwith {
+
      stuff := "bla";
+
  }
+
 
+
MV: The examples given above are inconsistent with the explanation earlier. The
+
    examples use the cachedwith keyword, the explanation talks about using parens
+
    for keys.
+
 
+
==== Cross Referencing ====
+
 
+
We need a way to specify cross references within a declared tree. The problem is that we need a reference to a created type after it has been created and before it will be initialized. This can be accomplished by adding a special assignment construct:
+
 
+
  var x := new Entity as localRef {
+
      // x is not visible here, because the right hand expression has not been evaluated so far.
+
      // localRef holds a reference to the created but not yet initialized entity.
+
        name := "Person";
+
        references += new Reference {
+
            name := "partner"
+
            type := localRef
+
        }
+
      }
+
 
+
=== Operator Overloading ===
+
There will be predefined operators which can be used instead of the usual function invocation syntax if there is an operator for a name and a specific number of parameters.
+
 
+
Some examples:
+
 
+
  add(Object a, Object b) => a + b
+
  subtract(Object a, Object b) => a- b
+
  not(Object a) => !a
+
 
+
The && and || operators are not overwriteable because of there special semantics wrt lazy evaluation.
+
 
+
MV: Why do we need operator overloading? Seems to me
+
    as not too relevant...
+
 
+
=== Overloading accessors ===
+
If a function's signature follows the pattern
+
  String getFoo()
+
 
+
it can be invoked using property syntax:
+
  this.foo
+
 
+
If a function's signature follows the pattern
+
  void setFoo(String)
+
 
+
it overwrites the modify of the 'foo' property, hence it will be used within assignments:
+
  foo := 'Holla'
+
 
+
It is also possible to use such functions without having a corresponding property like:
+
 
+
  getJavaName(Entity this) {
+
      if abstract then
+
        'Abstract'name
+
      else
+
        name
+
      endif
+
  }
+
 
+
which can be used like:
+
<pre>
+
myTemplate(Entity this) :»
+
  public class «javaName» {
+
  }
+
«;
+
</pre>
+
 
+
MV: Nice, finally without the parens. However, you seem to say that only a
+
    function getXxy be called via xyz. True? What happens if I have a function
+
    bla(Type)? can I also call it via type.bla?
+
 
+
=== Templates ===
+
A template is essentially a function returning a String. I always disliked that it is not possible to mix functions and templates within one file. I also find the invocation of templates (EXPAND bla FOR foo) too verbose.
+
 
+
Example:
+
  myTemplate() :»
+
    package «packageName»;
+
    public class «name» {
+
      «foreach (attributes as a)»
+
          «if (a.type!=null) then»
+
            public «a.type» «a.name»;
+
          «endif»
+
      «endforeach»
+
    }
+
  «;
+
 
+
It's just a string literal with the xpand syntax within. Instead of '«' and '»' one can also use the common literal syntax 'foo' and "bar".
+
 
+
MV: I don't understand the the explanation here: "Instead of ... and "bar"."
+
 
+
MV: I would also prefer not to use the inverse french guillemots. Why don't we use
+
    another escape to highlight the "magic strings", like the example below. I find
+
    this way more readable!
+
 
+
  myTemplate() : [[
+
    package «packageName»;
+
    public class «name» {
+
      «foreach (attributes as a)»
+
          «if (a.type!=null) then»
+
            public «a.type» «a.name»;
+
          «endif»
+
      «endforeach»
+
    }
+
  ]];
+
 
+
 
+
The FILE statement will be removed.
+
Files can be opened through extensions:
+
 
+
  generateCode(Entity e) :
+
    writeToFile(e.JavaFile(),e.toJava());
+
 
+
MV: ... where toJava() would be a template, as explained above.
+
 
+
==== XString - mutable, streamable, lazy string ====
+
We want to come up with a special datatype called XString, which is mutable, streamable and evaluated lazy (on invocation of toString()).
+
Because XStrings are mutable and are converted to a string late, it is possible to create a tree structure containing XStrings, where
+
you can add XStrings (or normal Strings) later on.
+
 
+
MV: Comment: this is much like frames....
+
 
+
Example:
+
  toJava(Entity this) :"""
+
      package «packageName()»;
+
      «(def imports:=»
+
        import java.util.*;
+
      «)»     
+
      public class  ...     
+
          »assertImported(imports,"java.math.*")«
+
      }
+
  «;
+
 
+
  assertImported(XString this, String import) :
+
      if !this.contains(import) then
+
          this.append("import "import";");
+
  ;
+
 
+
MV: What's the relationship between the two code snippets above? What does the
+
    "def imports :=" do in the XString?
+
 
+
=== if expression ===
+
As seen in the previous example, we want an if-expression. using if, else keywords.
+
 
+
if (predicate) expression (else if (predicate) expression)* (else expression)? endif
+
 
+
The else part is optional and will return null if not defined.
+
 
+
Example:
+
  // The following expression will return null:
+
  if (false) "Holla" endif
+
 
+
'endif' is optional.
+
 
+
=== switch expression ===
+
 
+
The switch expression's syntax is as follows:
+
<pre>
+
  'switch' expression?
+
    ('case' expression ':' expression)+
+
    ('default' ':' expression)? // defaults to 'default : null'
+
  'endswitch'? // optional endswitch mostly used within template syntax
+
</pre>
+
 
+
=== foreach expression ===
+
Within templates we want to write someting like this:
+
<pre>
+
«foreach a in foobar separator ','»
+
    «a.bla»
+
«endforeach»
+
</pre>
+
 
+
Which is essentially a 'concatEach'-expression, i.e. concat the result of each invocation within the body.
+
So far the keywords are 'foreach' and 'endforeach', but maybe we should change them to 'concat' 'endconcat', just not to confuse this with foreach known from general purpose languages.
+
 
+
=== BK added --- To be discussed ===
+
 
+
==== AOP for Checks ====
+
When modifying an expression using AOP, there might be the situation that a check is no longer valid. It has to be modified as well
+
 
+
SE: We can't modify expressions using AOP. We just can wave an Advice around a function call.
+
Shouldn't the designer of a cartridge have this in mind when declaring Join Points to be adviced by clients?
+
I think if an advice breaks an existing constraint it breaks the contract of the adviced function.
+
 
+
 
+
=== PF added --- to be discussed ===
+
==== Add a FOLDER keyword ====
+
In order to create empty directory structures, it would be nice to have a FOLDER keyword.
+
Syntax:
+
«FOLDER expression»
+
 
+
SE: I think such things should be implemented using library functions.
+
MV: Agree.
+
 
+
 
+
== Examples, etc. ==
+
 
+
<pre>
+
  context Entity {
+
  private String doStuff(Foo bar) {
+
      def x := 'holla';
+
      x + bar;
+
  }
+
 
+
  cached Entity<T> foo<T extends Comparable<T>>(Entity<T> bla)
+
guard bla.abstract && bla.name.startsWith('Abstract')
+
{
+
      new Entity<T> [bla] as myEntity {
+
        bla.address := new Address as address {
+
            address.street := 'Holla Strasse 42';
+
        };
+
        bla.adress.zip := bla.zip;
+
      };
+
  }
+
 
+
  private myTemplate(Entity this) :»
+
      package «packageName()»
+
 
+
      public class «name» «if ^extends!=null then»extends «^extends.name»«endif» {
+
        «foreach (x := fields)»
+
            private «x.type» «x.name»;
+
        «endforeach»
+
      }
+
  «;
+
  }
+
</pre>
+
 
+
== Grammar ==
+
<pre>
+
grammar Xtend;
+
options{backtrack=true; memoize=true;}
+
 
+
@lexer::header {
+
package org.eclipse.m2t.xtend.frontend.parser;
+
}
+
 
+
@parser::header {
+
package org.eclipse.m2t.xtend.frontend.parser;
+
}
+
 
+
parse :
+
  ruleXtendFile EOF
+
;
+
 
+
ruleXtendFile  :
+
(ruleImport)*
+
(ruleConcept)*
+
;
+
 
+
ruleImport  :
+
('reexported')? 'import' (RULE_ID)? RULE_STRING ';'
+
;
+
 
+
ruleConcept  :
+
  ruleContext  |  ruleFunction  ;
+
 
+
ruleContext  :
+
'context' ruleTypeRef '{'
+
ruleFunction+
+
'}'
+
;
+
 
+
ruleFunction  :
+
        RULE_DOCUMENTATION?
+
( 'private'|'final'|'cached')* (ruleTypeRef)? RULE_ID('<' ruleTypeParamDeclaration (',' ruleTypeParamDeclaration )*'>')? '(' (ruleDeclaredParameter (',' ruleDeclaredParameter )*)? ')'
+
('if' ruleExpression )?
+
(':' ruleExpression ';' | ruleBlockExpression)
+
;
+
 
+
ruleTypeParamDeclaration  :
+
RULE_ID
+
(('extends' ruleTypeRef ('&' ruleTypeRef )*) |
+
('super' ruleTypeRef))?
+
;
+
 
+
ruleDeclaredParameter  :
+
ruleTypeRef ? RULE_ID
+
;
+
 
+
ruleExpression :
+
ruleAssignment;
+
+
ruleAssignment :
+
        ruleOrExpression  (':=' ruleOrExpression)? |
+
('def' | ruleTypeRef ) RULE_ID ':=' ruleOrExpression
+
;
+
 
+
ruleOrExpression  :
+
ruleAndExpression ( '||'  ruleAndExpression )*
+
;
+
 
+
ruleAndExpression  :
+
ruleRelationalExpression ('&&' ruleRelationalExpression)*    
+
;
+
 
+
ruleRelationalExpression  :
+
ruleAdditiveExpression (('=='|'!='|'>='|'<='|'>'|'<' ) ruleAdditiveExpression )*
+
;
+
 
+
ruleAdditiveExpression  :
+
ruleMultiplicativeExpression (('+'|'-') ruleMultiplicativeExpression )*    
+
;
+
 
+
ruleMultiplicativeExpression  :
+
ruleOtherOperatorExpression (('*'|'/') ruleOtherOperatorExpression )*
+
;
+
 
+
ruleOtherOperatorExpression  :
+
ruleUnaryExpression (('+='|'..') ruleUnaryExpression )*
+
;
+
 
+
ruleUnaryExpression  :
+
ruleInfixExpression
+
| (('!'|'-') ruleInfixExpression)
+
;
+
 
+
ruleInfixExpression  :
+
rulePrimaryExpression ('.' ruleFeatureCall )*
+
;
+
 
+
rulePrimaryExpression  :
+
  ruleFeatureCall  | 
+
  ruleBooleanLiteral  | 
+
  ruleNumberLiteral  | 
+
  ruleNullLiteral  | 
+
  ruleConstructorCall  |
+
  ruleParanthesizedExpression  | 
+
  ruleBlockExpression  | 
+
  ruleWithExpression  | 
+
  ruleParanthesizedClosure    | 
+
  ruleCollectionLiteral  |
+
  ruleTemplateExpression |
+
  ruleIfExpression |
+
  ruleSwitchExpression |
+
  ruleConstructLiteral |
+
  ruleCast |
+
  ruleCurryingWildcard;
+
 
+
ruleCast :
+
'(' ruleTypeRef ')' ruleExpression;
+
 
+
 
+
ruleCurryingWildcard
+
:
+
'_';
+
 
+
ruleConstructLiteral :
+
'&' RULE_ID ('::' RULE_ID)* ('('('..'|(ruleTypeRef (',' ruleTypeRef)*)?)')')?;
+
 
+
ruleIfExpression :
+
'if' ruleExpression 'then'
+
ruleExpression
+
('elseif' ruleExpression 'then' ruleExpression)*
+
('else' ruleExpression)?
+
'endif'?
+
;
+
 
+
ruleSwitchExpression :
+
'switch' ruleExpression?
+
('case' ruleExpression ':' ruleExpression)+
+
('default' ':' ruleExpression)?
+
'endswitch'?
+
;
+
 
+
ruleWithExpression  :
+
'with' '(' ruleFunctionMapping (',' ruleFunctionMapping)* ')' ruleBlockExpression
+
;
+
 
+
ruleFunctionMapping  :
+
ruleExpression ('as' RULE_ID )?
+
;
+
 
+
ruleBlockExpression  :
+
'{'
+
(ruleExpression ';')*
+
'}'    
+
;
+
 
+
ruleParanthesizedClosure  :
+
'{'
+
ruleClosure
+
'}'    
+
;
+
 
+
ruleClosure  :
+
(ruleDeclaredParameter (',' ruleDeclaredParameter)*)? '|' ruleExpression
+
;
+
 
+
ruleParanthesizedExpression  :
+
'(' ruleExpression ')'    
+
;
+
 
+
ruleFeatureCall  :
+
  ruleOperationCall  |
+
  rulePropertyCall;
+
 
+
rulePropertyCall  : 
+
RULE_ID
+
;
+
 
+
ruleOperationCall  :
+
RULE_ID '('(ruleExpression (','ruleExpression )* | ruleClosure)?')'
+
;
+
 
+
ruleConstructorCall  :
+
'new' ruleTypeRef ('['(ruleExpression (','ruleExpression)*)?']')?
+
('as' RULE_ID)?
+
ruleBlockExpression
+
;
+
 
+
ruleBooleanLiteral  :
+
'false'|'true'
+
;
+
 
+
ruleNullLiteral  :
+
'null'
+
;
+
 
+
ruleNumberLiteral  :
+
  ruleIntLiteral  | 
+
  ruleDoubleLiteral;
+
 
+
ruleCollectionLiteral
+
: ruleListLiteral |
+
ruleMapLiteral;
+
 
+
ruleListLiteral :
+
'['(ruleExpression(',' ruleExpression)*)? ']'
+
('<' ruleTypeRef '>')?;
+
 
+
ruleMapLiteral  :
+
'['(':' | ruleMapEntry (',' ruleMapEntry)*)']'
+
('<' ruleTypeRef  ',' ruleTypeRef  '>')?
+
;
+
 
+
ruleMapEntry  :
+
ruleExpression ':' ruleExpression    
+
;
+
 
+
ruleIntLiteral  :
+
RULE_INT
+
;
+
 
+
ruleDoubleLiteral  :
+
RULE_REAL
+
;
+
 
+
ruleTypeRef  :
+
  ruleSimpleTypeRef  | 
+
  ruleClosureTypeRef  ;
+
 
+
ruleClosureTypeRef  :
+
('('ruleTypeRef (',' ruleTypeRef )*')')? '=>' ruleTypeRef
+
;
+
 
+
ruleSimpleTypeRef  :
+
RULE_ID ('::' RULE_ID)* ('<'ruleTypeParam (',' ruleTypeParam)*'>')?
+
;
+
 
+
ruleTypeParam  :
+
  ruleTypeRefParam  |  ruleWildcardParam  ;
+
 
+
ruleTypeRefParam  :
+
ruleTypeRef
+
;
+
 
+
ruleWildcardParam  :
+
'?'
+
(('extends' ruleTypeRef (',' ruleTypeRef )*) |
+
('super' ruleTypeRef))?
+
;
+
 
+
ruleTemplateExpression :
+
(ruleStaticText
+
((ruleExpressionStatement |
+
ruleForeachStatement)?))+
+
;
+
+
ruleStaticText :
+
RULE_STRING
+
;
+
+
ruleExpressionStatement :
+
ruleExpression
+
;
+
+
ruleForeachStatement :
+
'foreach' '('? ruleExpression 'as' RULE_ID ')'? ('separator' ruleExpression)?
+
ruleTemplateExpression
+
'endforeach'
+
;
+
 
+
RULE_REAL :
+
  ('0'..'9')*'.'('0'..'9')+
+
;
+
 
+
RULE_ID :
+
  ('^')?('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
+
;
+
 
+
RULE_STRING :
+
  '"' ( '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') | ~('\\'|'"') )* '"' |
+
  '\'' ( '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') | ~('\\'|'\'') )* '\''|
+
  '»' ( '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') | ~('\\'|'«') )* '«'
+
;
+
+
RULE_INT :
+
  ('0'..'9')+
+
;
+
 
+
RULE_WS :
+
  (WS)+ {$channel=HIDDEN;}
+
;
+
fragment WS
+
: ' '|'\t'|'\r'|'\n';
+
 
+
RULE_ML_COMMENT :
+
  '/*' WS ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;} 
+
;
+
 
+
RULE_DOCUMENTATION :
+
  '/**' ( options {greedy=false;} : . )*  '*/'
+
;
+
 
+
 
+
 
+
RULE_SL_COMMENT :
+
  '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
+
;
+
RULE_ANYTHINGELSE :
+
  .
+
;
+
</pre>
+

Latest revision as of 08:59, 9 December 2008

Redirect to:

Back to the top