Skip to main content
Jump to: navigation, search

Difference between revisions of "RoadmapOAW5"

(broke a very long line which caused the page to be too large to be readable)
(Redirecting to OAW)
 
(3 intermediate revisions by 2 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 evolution of oAW is being based on a separation between frontend (the actual syntax of the language) and backend (the runtime environment). While this document describes the frontend features being discussed and is specific to oAW, the backend is designed to be a stable, language independent platform (in analogy to the JVM as opposed to the Java language), and its design is described at [[M2TBackend]].
+
 
+
The main improvements we want to incorporate are:
+
 
+
=== Insertion points ===
+
A proposal to make M2T transformations with Xpand more flexible. I (Jos Warmer) have written doen a rationale for this feature, plus a proposal with exampls on how to use it.  It is rather long, so you can find it on a separate [[Insertion point proposal]] page.
+
 
+
=== 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")
+
 
+
==== Type signatures of functions ====
+
The syntax for of a function's type signature looks as follows:
+
 
+
  (parameterTypes)=>returnType
+
 
+
... 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 !JAVA! 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-function.
+
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 square brackets 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.
+
+
Examples:
+
 
+
  var paramPerOperationAndName := new Parameter [op,name] {
+
      this.name := name;
+
      type := aDatatype;
+
  }
+
 
+
  var localSingleton := new Foo [] {
+
      stuff := "bla";
+
  }
+
 
+
With this we can replace the create extensions introduced in Xtend 1.0.
+
 
+
*Xtend 1.0*
+
<pre>
+
  create Entity createEntity(Table t) :
+
      setName(t.name.toLowerCase().toFirstUpper()) ->
+
      fields.add(id(t));
+
 
+
  create Field id(Table t) :
+
      setName('id')->
+
      setType('Long');
+
</pre>
+
 
+
becomes
+
<pre>
+
  createEntity(Table t) {
+
      new Entity [t] {
+
        name := t.name.toLowerCase().toFirstUpper();
+
        fields += new Field {
+
            name := 'id';
+
            type := 'Long';
+
        }
+
      }
+
  }
+
</pre>
+
 
+
==== 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?
+
SE: No, you can't. We want to distinct functions and properties on syntax level. But you can define functions using the get... pattern if you want to use property style.
+
 
+
=== 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".
+
Example:
+
  myTemplate() :"
+
    package "packageName";
+
    public class "name" {
+
      "foreach (attributes as a)"
+
          "if (a.type!=null) then"
+
            public "a.type" "a.name";
+
          "endif"
+
      "endforeach"
+
    }
+
  ";
+
 
+
MV: I would 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»
+
    }
+
  ]];
+
 
+
SE: Yes, I was thinking of such an explicit Xtend-String-literal (similar to GString in Groovy) as wel, and still think it's a good way.
+
With the current approach one can use implict concatenation everywhere. So there's no distinction between 'interpolated string literal' and other expressions.
+
 
+
The FILE statement will be removed.
+
Files can be opened through extensions:
+
 
+
  generateCode(Entity e) :
+
    writeToFile(e.JavaFile(),e.toJava());
+
 
+
... where toJava() would be a template, as explained above and JavaFile() returns the qualified name relativ to a globally configured outlet (base dir).
+
 
+
==== 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:
+
<pre>
+
  toJava(Entity this) :"""
+
      package «packageName()»;
+
      «imports()»     
+
      public class  ...     
+
          »assertImported("java.math.*")«
+
      }
+
  «;
+
 
+
  cached imports() : »
+
      import java.util.*;
+
  «;
+
 
+
  assertImported(String import) :
+
      if !imports().contains(import) then
+
          imports().append("import "import";");
+
  ;
+
</pre>
+
The imports function is cached, so it will always return the reference to the same XString instance.
+
This instance is inlined within the template like any other String (or XString) but can be modified later on (assertImported).
+
 
+
=== 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.
+
 
+
== Feedback ==
+
 
+
=== Achim Demelt ===
+
Very nice! Looks promising to me! Here are some additional thoughts and ideas. Some may be a bit controversial, and I am aware that some of my ideas overshoot the mark, so feel free to comment ;-)
+
 
+
==== Function Declaration ====
+
I would prefer only one way to declare functions instead of two. Since the ":" notation is a subset of the "{ ... }" notation, the latter is enough. Or am I missing something?
+
 
+
==== Template Declaration ====
+
Although similar, templates are somewhat different from regular functions. The » and « syntax (or <code>[[</code> and <code>]]</code> as Markus suggested) and handling guillemots within the template make this clear. So I could live with a <code>template</code> keyword to make them more explicit.
+
 
+
Moreover, I feel that some users may still not like the guillemots to separate literal text from expressions. But for that matter, ''any'' token we might think of will be either cumbersome to type on your keyboard, or simply be inappropriate since you might want to produce exactly that token in your output (think of a meta-generator that generates template files). I don't know if this is too much to ask for, but can the token be configurable (per generator invocation, or per Eclipse project for validation purposes, or maybe even per file)? So you can come up with a syntax like this:
+
 
+
<pre>
+
// one token used for beginning and end
+
expressiontoken $$ ;
+
 
+
context Entity {
+
template interface() {{
+
  public interface $$name$$ {
+
      ...
+
  }
+
}}
+
}
+
</pre>
+
 
+
or
+
 
+
<pre>
+
// separate tokens for beginning and end
+
expressiontoken < > ;
+
 
+
context Entity {
+
template interface() {{
+
  public interface <name> {
+
      ...
+
  }
+
}}
+
}
+
</pre>
+
 
+
 
+
==== AO ====
+
When declaring this:
+
 
+
<pre>
+
func(Foo foo, Bar bar) { ... }
+
</pre>
+
 
+
and invoking this:
+
 
+
<pre>
+
someFoo.func(someBar)
+
</pre>
+
 
+
We have basically introduced a new function to type Foo. Typically, this is one part of what AO is doing, so why don't we "sell" this feature with an "AO" label? The <code>context</code> syntax makes it even more clear that we're doing some serious AO here. Lending from AspectJ syntax, I could also image another notation: <code>Entity::doStuff(Foo bar) { ... }</code>, meaning that we introduce function <code>doStuff</code> with a <code>Foo</code> parameter into the type <code>Entity</code>
+
 
+
So, and to bring the AO point home: Isn't generating something a kind of concern? Why not name it so? We may end up with this:
+
 
+
<pre>
+
concern JavaCode {
+
Package::fullyQualifiedName() {
+
  if owningPackage == null then
+
  name
+
  else
+
  owningPackage.fullyQualifiedName() + name
+
  endif
+
}
+
 
+
Entity::javaName() {
+
  name.toFirstUpper()
+
}
+
 
+
Entity::fullyQualifiedName() {
+
  owningPackage.fullyQualifiedName() + javaName()
+
}
+
 
+
template Entity::interface() {{
+
  package $$owningPackage.fullyQualifiedName()$$;
+
 
+
  public interface $$javaName$$ {
+
    $$members()$$
+
  }
+
}}
+
 
+
public template Entity::members() {{
+
    $$attributes.forAll(a | a.getter())$$
+
    $$attributes.forAll(a | a.setter())$$
+
}}
+
 
+
template Attribute::getter() {{
+
  public $$javaTypeName()$$ blablubb youknowwhatimean
+
}}
+
}
+
</pre>
+
 
+
and
+
 
+
<pre>
+
import JavaCode;
+
 
+
concern Hibernate {
+
Entity::tableName() {
+
  name.toUpper()
+
}
+
 
+
template Entity::mapping() {{
+
  <hibernate-mapping>
+
    <class name="$$fullyQualifiedName()$$" table="$$tableName()$$">
+
    ...
+
    </class>
+
}}
+
}
+
</pre>
+
 
+
My last point regarding AO: I didn't find any syntax replacement for the "old" AO concepts. So what about this:
+
 
+
<pre>
+
import JavaCode;
+
 
+
concern StaticAccess {
+
around template Entity::members() {{
+
  $$attributes.forAll(a | a.staticConstant())$$
+
  $$proceed()$$
+
}}
+
 
+
Attribute::constantName {
+
  $$name.toUpper()$$
+
}
+
 
+
template Attribute::staticConstant() {{
+
  static final String $$constantName()$$ = "$$owningEntity.fullyQualifiedName() + "::" + name$$";
+
}}
+
}
+
</pre>
+
 
+
Of course, advising templates or functions should be more or less the same. In both cases, it should only be possible to advise <code>public</code> features of a concern.
+
 
+
==== Misc ====
+
* I failed to understand the "dynamically scoped extension overwriting".
+
* I like closures and function types :-)
+
 
+
=== Artem Tikhomirov ===
+
Here's the copy-paste of the email I sent to Sven:
+
+
Honestly, I've got mixed feeling regarding the changes proposed. I do understand your desire to bring new and nice features into the language, however, not all of them seem fruitful to me, nor do I think language improvements should be the primary goal at the moment. Rather, I'd spend efforts improving tools - error reporting, editors, build infrastructure.
+
 
+
Nevertheless, few points:
+
# Imports, Java - is it import of functions (i.e. all members of specified class are accesible as functions) or it's types/metamodel (and in that case, it should be rather package then class)
+
# Generics. What's the reason to add Generics? There are really few usecases for generics outside of structure/algorith library space, and since Xtend is not the language for such libraries, I doubt there gonna be real value for generics. And they are so easy to misuse and quite tricky to implement... Count mine -1.
+
# Closures. Fancy, trendy, all-time-modern... but is the Xtend's primary goal to become a full-fledged programing language? I thought of Xpand as mostly supportive for models - primitive enough operations that are mostly generation-oriented and hence unreasonable to keep in the model. If I'd need composite logic, I'd rather do it in the model, than with Xtend.
+
#:Another important point missed is whether regular functions are closures as well, so that I could pass it where closure is expected and if I could stack them (i.e. function as an object).
+
# Guards. First, 'guard' term makes me think it's sort of 'assert', rather than 'when'. Falls to "syntactic sugar" category.
+
# Extension overwite. First, explicit mark of extension points/functions seems very desirable. I'd say 'final'(especially, if only 'final') is much worse - there are cases one might need to override even finals, and rather than forbidding to do that would be reasonable to still allow overrides, but warn user (think of exported and friends packages in MANIFEST.MF). With explicit indication what is supposed to be overriden you hint your clients and helps them to look into right direction when extending your templates.
+
# Grouping/Context. "Syntactic sugar" that I'd really like, +1 ;)
+
# Code blocks. Again, Xtend's power is in its simplicity and focus. Alternative syntaxes, variable declarations - seems to bring anarchy which doesn't help to focus one's mind
+
# Operator overloading. Just -10! Go for it, if you wanna drive your users nuts.
+
# Overloading accessors. I wonder if the new syntax won't bring confusion with old .ext/.xpt, would be better to carefully describe the precedence and resolution for any name conflict.
+
# Templates - function with Xpand syntax. Again, -1, as it's not Xtend purpose. Those willing to generate some text should use Xpand, those that need StringBuffer - give'em string buffer, not "xpand-within-xtend"
+
#: Somewhat related feature that might be really cool is to be able generate and evaluate Xpand template from within Xpand template. Sort of <METADEFINE> within which I generate series of <DEFINE>s that could be invoked afterwards.
+
# XString. 'X' means nothing, give it better name. Meaningful. StringBuffer, whatever.
+
# Creation expressions. And not only these, but in general - perhaps, instead of inventing yet another language it's worth using existing one? I mean, why won't we use QVT/OCL for the purposes of Xtend. It's much easier to learn single language, to make tools for it, to fix bugs and to evolve.
+
 
+
 
+
 
+
=== Meinte Boersma ===
+
 
+
Some not-so-detailed feedback for the moment: I think there's a lot of focus on expanding language features and somehow merging Xpand, Xtend en Xtext, but I can't help to dread that such a combined language would suffer from language bloat. Incidentally, I think the separation between Xpand and Xtend is a very happy "accident", since it forces developers to separate metamodel extensions from template code. I concur with (most of) Artem Tikhomirov's remarks.
+
 
+
Also, I think the current itch does not lie with language features as such but with the runtime and plugin-time behaviour of oAW, and the difference between those two. I gather from the roadmap of the MWE and from remarks by Sven on the oAW message board that there's going to be a movement towards a workflow DSL and that will be much welcomed. However, I hope the actual runtime and plugin-time behaviour will also gain some priority. Some sub-itches I have here:
+
# It's difficult to "see" the typing system. A plugin visualizing contributed metamodels would help here.
+
# The lifecycle of workflow components and the wiring of workflow components depending on beans and on each other is a bit simplistic, which results in more special-purpose, one-shot workflow components in my project than I'd like.
+
# A model manager plugin which can manage an arbitrary amount of models in-memory and provide runtime access to them would drastically reduce cycle time in development of M2M and M2T artifacts. This would also enable an interactive console (e.g., which could evaluate the expression sublanguage with respect to the in-memory models), which would be very useful.
+
I guess most of this should go in the MWE roadmap (or feedback on that), but seeing that that roadmap is not very verbose yet...
+
 
+
Also, a bit more documentation (in the form of Javadoc and otherwise, in that order) would often come in handy.
+
 
+
My 0.02USD...
+
 
+
== 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