Home » Archived » B3 » b3 build files DSL in XText - annotaded sample b3 file
| |
Re: b3 build files DSL in XText - annotaded sample b3 file [message #491333 is a reply to message #491290] |
Wed, 14 October 2009 07:52 |
|
Hi Henrik,
Lots of questions :-)
Properties:
property foo= "hello";
// a property can be set to null (but not immutable properties)
property foo;
Wouldn't it be better to explicitly assign null in this case? It looks like an uninitialized variable. So
property foo = null;
or
property foo = empty; // Since empty apparently is a keyword?
Expressions:
You have this expression in the file:
when (!target.platform != "sparc" && target.platform < "hpUx")
which I interpret as a not operation on a string which probably would result in an
UnsupportedOperationException?
How do we plan to handle expression type priorities? I.e. which one of these are true:
"4" + 2 == 6
"4" + 2 == "42"
"4" + 2 == Exception, different types of operands.
What does:
target.platform < "hpUx"
mean? If it's a lexical compare, is it sensitive to Locale? I can see use cases for both locale sensitive compare and
plain ASCII. Do we need additional operators for this?
Artifacts:
** Standard XText implementation allows a unary ^ before a keyword as an escape (Remove?)
I'd vote yes to that. I'd prefer if we quote keywords where needed (paths, requirements, etc.) and prohibits the use of
keywords as names in other places. Like Java.
You have an example:
"my.unit", "my.unit"; // unit is a keyword
my.^unit; // unit is keyword - standard XText grammar escape of keywords in ID
I understand why 'unit' needs to be quoted, but why do I need to quote 'my.unit'? Isn't that one single token? Can I write:
my . "unit" // (with spaces surrounding the dot)
?
NLS:
"aŒŠš"; // has NLS characters
What character encoding is used (related to the locale sensitive compare)?
Artifact paths:
/ a / b ; // is equivalent to /a/b - not /" a"/" b"
That looks really odd to me. I haven't seen any language to date that does that and I don't think we should either. It's
an incomprehensible syntax to most people. Perhaps you can have PATH recognized by the lexer and then specializations of
that (REFERENCE and REQUEST for instance, allowing a version and version range) also recognized? I.e. that:
requestElement:
PATH
| REFERENCE
| REQUEST
;
referenceElement:
PATH
| REFERENCE
;
artifactElement:
PATH
etc.
Group:
Regarding parallel or sequential execution. You have
// The keyword 'syncronized' declares that parallell execution of any part is dissallowed
this confuses me. synchronized usually mean that two threads cannot execute the same piece simultaneously. One must wait
for the other. So a synchronized group would be a group that you expect multiple threads to call on for execution and
that the threads must wait in line when that happens.
I would like to turn things around and say:
private sequential group foo {} // Execute the parts of this group sequentially (the default)
private parallel group foo {} // Allow parallel execution of the parts of this group
I.e. executing things in parallel is a conscious decision. We can have synchronized too of course, but I think it's
unusual that you'd want actions or groups that are not synchronized (in my sense of the word).
Action:
Your non-working example:
action test3 actor Test(test="test") provides a/b/"1"
{
// NON working example - need help with parser
// group input to one results
group {
a;
}
result b { b.txt; }
}
*/
How about turning it inside out, like this:
action test3 actor Test(test="test") provides a/b/"1"
{
result b { b.txt } with { group { a; } }
}
Since the result is at top, nested groups wouldn't work so your example:
action Test actor Test(test="test") provides a/b/"1"
{
group { a;
} {
group { x; } { result b { b; } }
result b {b;}
group { x; } { result b { b; } }
}
}
would need to be rewritten as:
action Test actor Test(test="test") provides a/b/"1"
{
result b { b; } with { group { a; x; } }
result b { b; } with { group { a } }
result b { b; } with { group { a; x; } }
}
which in my opinion vastly increases the readability. It becomes even more clear when you mix groups and properties:
action Test actor Test(test="test") provides a/b/"1"
{
result b { b; } with { group { a; x; } property foo="z80" }
result b { b; } with { group { a } }
result b { b; } with { group { a; x; } property foo="i8080" }
}
One argument in favor of your syntax is that repeating 'a' is cumbersome if it is complex. The counter argument to that
is; when that happens, just make 'a' a private group outside of the action.
Regards,
Thomas Hallgren
|
|
|
Re: b3 build files DSL in XText - annotaded sample b3 file [message #491335 is a reply to message #491322] |
Wed, 14 October 2009 07:55 |
|
Hi Matthias,
Here it is, in plain ISO8859-1 encoded text:
/*
** A .b3 file
** consists of import statements followed by a single "unit". This is analogous with a .java file having imports
** and a single language element (class, interface).
**
** This file is a sampler used to test syntax. The examples are not realistic (you will find plenty of a, b, c, fee and
foo...)
*/
/*
** COMMENTS
** Both single line and multi line comments are supported.
*/
// Single line comment
/* Multi line comment
*/
/*
** IMPORT
** Is used to import classes (just like in java). This is done so non qualified names can be used for classes
** DISCUSS: Imports are probably translated to meta requirements when resolving. As they are requirements on the
environment.
*/
import org.eclipse.b3.default.Resolvers.*;
/*
** UNIT
** A Unit is a Build Unit. It is used for several purposes:
** - as a file that describes "top level" requirements (what to import into a workspace, resolvers to use etc.)
** - as advice that extends meta data translation
** - as the meta data that describes a unit, when there is no other meta data
**
** A Unit has:
** - Properties
** - Provided Capabilities
** - Required Capabilities (and Meta Required Capabilities)
** - Parts (analogous with members in a class). There are four kinds of parts:
** - Artifacts (existing files)
** - Group (Aggregation of other parts)
** - Action (Production of new files (or side effect)
** - Result (A set of files produced by an Action ~= generated Artifacts)
** - Advice (Path/Predicate based access to elements that do not yet exist in the model). Used to set options, make
** overrides, etc.
** - Repositories - a configuration that is used to resolve (look up) units.
** - Synchronization - defines monitors across units that help solve issues in parallel builds
**
** A unit can be marked as synchronized - this means that requests to its parts are serialized.
** A unit can implement interfaces. These interfaces are "build time interfaces" and tells b3 about
** which parts it can expect. This also helps an author of extended components, and freshly created components
** comply with known build interfaces - i.e. this thing builds like an osgi.bundle.
*/
synchronized unit "my.unit" version 2.3 implements osgi.bundle, eclipe.ecore.model {
/* PROPERTIES
** Properties supports strings, integers, booleans, expressions and references to properties
*/
property foo= "hello";
// a property can be set to null (but not immutable properties)
property foo;
immutable property bar = 32;
immutable property bar = 32+10;
// checks if a calculation has the same value as a property
immutable property meaningful = 32+10 == the.meaning.of.life;
// a property can be "unset", that means that if it was set in this context, it will revert to
// it's value (if any) in an enclosing context.
//
unset property yellow.banana;
// Several properties can be set in a compound "properties" clause. It also works for unset.
// Note that the "property" keyword is no longer required per setting.
properties {
bar = "bar";
immutable politician = "oxymoron";
unset yellow.banana;
}
/* PROVIDES
** Provides clause is used to declare that the BuildUnit provides capabilities.
** A capability consists of interface/unitname and an optional /version at the end.
** If an interface, unitname or version requires use of reserved words or characters, the corresponding
** part is entered as a string (i.e. within " ").
** As with properties, there is a compound provides clause.
**
** Provide Capabilities can be filtered - some capabilities may only be provided under certain circumstances.
** This is declared with a leading when(BooleanExpression).
*/
provides osgi.bundle/bundlebar;
provides osgi.bundle/bundlebar/1.0;
provides {
osgi.bundle/barbara.bundle/2.0;
eclipse.feature/inflateable.pleasure/6.6.6;
when(target.platform == platforms.win32) native.thing/windowsInstaller/12.23.r1234;
}
provides when(target.platform == platforms.win32) native.thing/windowsInstaller/12.23.r1234;
/* REQUIRES
** Requires clause is used to declare that the BuildUnit requires certain capabilities.
** The differences between required and provided capabilities are that:
** - the version is always a range (althoug a single version means >= version
*/
requires osgi.bundle/air/1.0;
requires when (!target.platform != "sparc" && target.platform < "hpUx") osgi.bundle/pillow/3.0 ;
requires {
osgi.bundle/pillow/1.0;
when (a == b) osgi.bundle/blanket/1.0;
}
/* META REQUIRES
** With a leading meta keyword, the requiremens are requirements on the environment (i.e. on b3 itself)
** As an example, a meta requirement may be that a certain meta data provider is installed or it will be impossible to
** use this definition.
*/
meta requires osgi.bundle/air/1.0;
meta requires when (42 >= 32) osgi.bundle/pillow/"3.0";
meta requires {
osgi.bundle/pillow/1.0;
when (myorg.foo ~= "[a-z].*") osgi.bundle/blanket/1.0;
}
/* ARTIFACTS
** Artifact is a vector of path groups.
** A group of paths may have a base path - the rest of the paths in the group are relative to the
** base path.
** File names that include reserved words or reserved characters are entered within " "
** File names containing spaces must always be quoted, as the compiler removes whitespace from non strings.
** Standard XText implementation allows a unary ^ before a keyword as an escape (Remove?)
** Inclusion of a vector can be controlled with a leading when(BooleanExpression).
**
** VISIBILITY
** Visibility is either private or public (the default). Private means that the part is only accesable
** from within the b3 unit whene the part is declared.
**
** PROPERTIES
** It is possible to set (and unset) properties in the list using basic or compound property statements.
** These properties are set on the resulting path group vector and are available to the user of the
** set of files.
** Since file group vectors are merged, so will the properties. Use of immutable properties will guarantee
** that the property values set will surface (or an error will be generated if merging causes the value
** to change), but is ok if multiple vectors are tagged the same way.
**
** Note that individual property settings per file is not supported. To flag an individual file it is
** recommended to use dottiefied properties - example - mark the path /a/b as being little endian
** property org.myorg.fileinfo.endian.a.b=little.
**
** DISCUSS - is it of value to have properties/annotations per file?
**
*/
private artifacts test.a1 provides myorg.food/fruit.sallad/2.0, myorg.projectiles/fruit.salad
{
a; // a vector with one entry
a, b; // a vector with two entries
a [ b, c]; // a base path (a), with two relative paths in a vector
/a/b;
/ a / b ; // is equivalent to /a/b - not /" a"/" b"
// names that must be quoted
"unit"; // a keyword
"1a"; // does not look like a qualified name
"a b"; // has space in name
"aŒŠš"; // has NLS characters
"//f"; // looks like a comment
"123"; // is an integer
"my.unit", "my.unit"; // unit is a keyword
my.^unit; // unit is keyword - standard XText grammar escape of keywords in ID
when(target.platform == "osx") MacApp.app ;
when(true) banana.txt, pineapple.txt, mango.txt;
when (true) exotic [ rambustan.txt, tamarind.txt ];
a1 [apple.txt, "ban ana.txt"];
fee/apa.boo [ a/b/c.d, a.b.c.d, o/b/d ];
property apa="banan";
property defaultsToNull;
properties { a; b; }
}
// An empty artifacts vecor
artifacts empty {
}
/* ARTIFACTS PROVIDING CAPABILITIES
** It is possible to declare that the resulting path group vector is a capability layed out on disk.
** They layout can represent many capabilities at the same time.
*/
artifacts providesMany provides a/b/1.0, c/d/2.0, x/y/3.0 {a;}
/* GROUP
** A group is similar to artifacts in that it creates a path group vector, but it creates this
** by aggregating path group vectors from other parts.
** Just as with artifacts; the resulting path group vector can represent capabilities.
**
** The group consists of a list of required capabilities. The syntax is the same as for
** the units requires { } clause, with the following additions:
** - A trailing '#partname' is used after the requirement to pick a particular part.
** - A reference can be made to parts in the same build unit by using a single identifier
** - A reference to a required capability without a trailing '#partname' is taken as a reference to '#self', meaning the
** aggregation of all its public parts.
** - It is possible to define a closure where properties and advise are declared. They have downstream effect
** (i.e. when evaluating the part). The closure is defined using a trailing with { } statement.
** - A closure can be defined for several requirements at the same time by enclosing the requirements in curly
** brackets {r r r} with { }
** - A leading void keyword indicates that the resulting path group vector from the evaluation of the part should
** not be included in the resulting path group vector.
** - The result of individual part evaluation, or evaluation of a group of requirements can be assigned to an alias.
** The alias is a property that is included in the resulting path group vector. This makes it possible for a user
** of the vector to reference a particular part of the set.
** - void and alias can be used at the same time, but for a group that represents a part (as in this case), neither the
** property nor its value survive the group's context. For other types of grouping (in actions), this is very
** valuable, but in a group part, this construct simply has no effect.
**
** WITH CLOSURE
** In the with closure, properties can be set using the single or compound properties statements.
** Advice can be set using advice syntax.
**
*/
private synchronized group "foo/bar" provides myorg.food/fruit.coctail/2.0, a / b / "2.3"
{
a; // referense to part in self
foo/bar; // reference to #self in interface foo, name bar
a/a#b; // reference to #b in interface a, name a
fubbla= osgi.bundle/foo.bar/1.0; // sets the property fubbla to to the pathGroup reference in runtime - typically not
used in groups
osgi.bundle/fee.fum/1.0#jars;
osgi.bundle/zeBundle/1.0#jars;
void a/a#b; // only performed for side effect
void alias.nbr1 = b; // only performed for side effect, but sets a property to the result (that is then ignored)
a/a#b with { property nice = "yes"; }; // sets and passes the property nice downsteam
a/a#b with { // passes several properties downstream.
properties {
a="2"; b="2"; c="3";
}
};
// includes result of three references, all with the same set of downstream properties
{ a/a#b; a/b#c; a/c#d; } with { property target.platform="sparc"; };
// sets an alias on a non included result, result is a group of items with downstream properties
void aliasedButNotIncluded = { a/a#b; a/b#c; a/c#d; } with { property foo="hpux"; };
// sets an alias on an included item, result is a group of items with downstream properties, a nested alias is set
aliasedAndIncluded = { alias.nbr3=a/a#b; a/b#c; a/c#d; } with { property foo="hpux"; };
// inclusion can be filtered with a boolean expression - here "true" makes it always included
when (true) { a/a#b; a/b#c; a/c#d; } with { property foo="z80"; };
// filtering - here, never ever included because boolean value is false
when (false) a/a#b;
// a non included and filtered reference to a/a#b
void when (true) a/a#b;
}
// The keyword 'syncronized' declares that parallell execution of any part is dissallowed
private synchronized group foo {}
public synchronized group foo {}
private group foo {}
group foo {}
synchronized group foo {}
/*
** ACTION
** An action has an embedded group declaration that defines the input to an actor. The actor is told to
** produce the result(s) decalred for the input group. Input groups and results can be nested.
** This is used to decalre common input, input for a group of results (such as input to actions for linux),
** and then specific input for building a linx flavor, for different windowing systems etc.
**
** The result can consist be declared with public or private visibility, or follow the visibility of the action.
** Public result are available as first class members of the unit (even if the enclosing action is private).
** Public result must be named. Private result must be named if it should be referenced individually (and not as
** part of the action's result).
**
** The actor is declared in the preamble of the action part and is instantiated once.
** Parameters to the actor instantiation can be passed with parentheses using named parameters
** (order is not important).
** - An action can provide the resulting path group vector as provided capabilities
**
** Aliases
** Aliases for input parts have an additional meaning in actions - these properties are available to the actor.
** This means that the combination of void alias={ } is meaningful (as opposed to when used in a group part).
**
** RESULT
** Result clauses behave like artifact parts, but they typically refer to files that were produce by the actor.
** Properties in these sets may be set by the actor. This means that an actor can pass information back - such as
** a version qualifier, location of certain files on disk etc.
**
*/
private synchronized action foo
actor ZipActor(serviceKey="WooHoo - woot")
provides myorg.food/fruit.coctail/2.0
{
group {
a; // defaults to #self
when (apa > 11) a/a#b;
osgi.bundle/foo.bar/"1.2.3.qualifier#,./"#jars; // defaults to #self
osgi.bundle/fee.fum/1.0#jars;
osgi.bundle/zeBundle#jars;
void a/a#b; // only performed for side effect
void alias.nbr1 = a/a#b; // only performed for side effect
a/a#b with { property nice = "yes"; };
a/a#b with {
properties {
a="2"; b="2"; c="3";
}
};
{ a/a#b; a/b#c; a/c#d; } with { property target.platform="sparc"; };
void { a/a#b; a/b#c; a/c#d; } with { property foo="hpux"; };
void alias.nbr2 = { alias.nbr3=a/a#b; a/b#c; a/c#d; } with { property foo="hpux"; };
when (true) { a/a#b; a/b#c; a/c#d; } with { property foo="z80"; };
when (false) a/a#b;
void when (true) a/a#b;
}{
result a { a; }
}
}
action test1 actor Test(test="test") provides a/b/"1"
{ // no dependencies, no special input, just "do it and produce result"
result b { b.txt; }
}
action test2 actor Test(test="test") provides a/b/"1"
{ // no dependencies, no special input, just "do it and produce result"
// but set a properties
//
result b { b.txt; } with { property target.platform = "win32"; }
}
/* NON WORKING SYNTAX, due to problems in language specification. Help Wanted.
action test3 actor Test(test="test") provides a/b/"1"
{
// NON working example - need help with parser
// group input to one results
group {
a;
}
result b { b.txt; }
}
*/
action test3 actor Test(test="test") provides a/b/"1"
{
// group input to one or several results
group { a; }
{
result b { b.txt; }
}
}
action Test actor Test(test="test") provides a/b/"1"
{
group { a;
} {
result b { b; }
result b { b; }
result b { b; }
}
}
action Test actor Test(test="test") provides a/b/"1"
{
group { a;
} {
group { x; } { result b { b; } }
result b {b;}
group { x; } { result b { b; } }
}
}
action makeWin32Zip
actor ZipActor(serviceKey="tjoho")
provides foodstuff.sallad/fruitsallad/1.0, x/b/"23"
{
group {
{ site = createSite; } with { property target.platform="win32";};
}{
group {
extraInput = a/a/2.0#jarFiles;
}{
public result makeSomeoneHappy {
apa/banan.zip ;
when(true) chimp/banan.zip ;
} with { properties { target.platform = "win32"; prerequisite.flag = "a#b"; }}
group {
special;
}{
when (true) private result a { a;} with { /* for a only */ }
when (true) result b {} with { /* for b only */ }
} with { /* for a and b */ }
}
}
}
/** Synchronize clauses allows syncronization to be specified across units/actions.
** When executing a build in parallell, an engine should serialize the evaluation (build) of the
** specified elements. Serialization of execution may serialize more than what is specified but never less.
** Each synchronized list specifies a group that will be serialized. References are to part names in this unit, or
** to part names in other units.
**
** DISCUSS: although very useful, statements that synchronized on interface/*, and on actors are also useful.
** Syntax should probably be xpath/query like.
*/
synchronize a,b,c;
synchronize a/a#x,b/b#x,c/c;
synchronize { a,b,c; d,e,f; }
/** REPOSITORIES
** The repository clause defines the order in which repositories are searched.
** There are two forms of entries - the most common is expected to be the short form, where
** both the location, and repository type is specified with a URI. The URI scheme is used to select
** a resolver. For cases where this is not possible, the longer form is to declare that a resolver should be
** used, and the location (a general URL) is then set using advice (if indeed the selected resolver needs a location).
**
**
*/
repositories {
"http://bar/fee" { };
"http://bar/foo";
"http://bar/fum";
resolver foo.bar {
// Statements here are advice relative to a resolver. (i.e. '.' is a resolver)
//
location="http:://www.somewhere.com";
apa = 10;
booleanFlag = 10;
options/advanced[featureA ~="[a-z]*"]/?[a>23]/b/?? {
option1 = 10;
option2 = 20;
option3 = "hello";
};
};
}
advice import_Advice {
/requests[name~="org.myorg.*"]/options {
source=true;
mutable=true;
};
/resolutions[name~="org.eclipse.*"]/options {
location = "platform:/plugin/";
};
}
}
|
|
|
Re: b3 build files DSL in XText - annotaded sample b3 file [message #491365 is a reply to message #491333] |
Wed, 14 October 2009 11:02 |
Henrik Lindberg Messages: 2509 Registered: July 2009 |
Senior Member |
|
|
Hi,
comments in-line...
- henrik
On 10/14/09 9:52 AM, Thomas Hallgren wrote:
> Lots of questions :-)
>
Feedback apreciated :-)
> Properties:
> property foo= "hello";
> // a property can be set to null (but not immutable properties)
> property foo;
>
> Wouldn't it be better to explicitly assign null in this case? It looks
> like an uninitialized variable. So
>
You suggested having uninitialized properties. The rationale was to use
them as part of result path group vectors. You agreed that that they
could be set to null in that case. I agree that it is not very good...
(read on)...
> property foo = null;
>
> or
> property foo = empty; // Since empty apparently is a keyword?
>
I think we should not allow uninitialized properties.
We can use "null" if we want to, "empty" is not a keyword, it is the
name of a property in the sample :-).
However, there is one more option that also increases quality, and that
is to set the property to a special keyword that indicates that it is
expected to be set by an action. Then, on return from the actor, a check
can be made that the property was actually set.
For instance, if there is an expectancy that the actor will assign a
revision number or similar and it doesn't - then sometimes later, things
will appear broken as the property is uninitialized.
One possibility, would be to allow the following in result path group
vector (but only there):
immutable property revision;
Since immutable means it can't be changed - it is clear that this is not
allowed, and hence, that a value must be provided. The above is
different from:
immutable property revision = "r101010";
Since this forbids the actor to change the value. And it is different from:
property revision = "r101010";
which specifies revision with a default value, that the actor may
override. If specifying:
property revision;
Then, this would mean - revision implicetly set to null, actor may or
may not set it. I think this is likely to cause problems (that are much
harder to find), and suggest that we do not support this at all anywhere.
>
> Expressions:
> You have this expression in the file:
>
> when (!target.platform != "sparc" && target.platform < "hpUx")
>
> which I interpret as a not operation on a string which probably would
> result in an
> UnsupportedOperationException?
>
Yes, the expression would throw an exception. I made it like that in the
sample on purpose to trigger the discussion on how to handle such issues :)
> How do we plan to handle expression type priorities? I.e. which one of
> these are true:
>
> "4" + 2 == 6
> "4" + 2 == "42"
> "4" + 2 == Exception, different types of operands.
>
We can:
- Have generality on types and convert to the more general type -
int/string becomes int. Since we don't have float, double and other
types (although we may add collections) it is not that hard.
- Only use string. (Don't like this solution though).
So, I opt for:
"4" + 2 = "42"
It is more an issue of interpreting properties set in properties files,
or from the command line. How is the distinction made between a string
and an int property there?
A related question. Should we support "real" (i.e. double). ?
> What does:
>
> target.platform < "hpUx"
>
> mean? If it's a lexical compare, is it sensitive to Locale? I can see
> use cases for both locale sensitive compare and plain ASCII. Do we need
> additional operators for this?
>
Very good question(s):
a) It would mean lexical compare if we implement it ;)
b) I see two ways of implementing specification of NLS
- having a bunch of operators that say that the compare is NLS, say @<
@> @<= @>= @== @!= (ugly, and makes it hard to specify locale).
- handle NLS strings as a type more general than string.
@ "This is a NLS String in current locale"
@us_EN "This is a NLS String in US English"
@se_SE "En svensk tiger"
The following would then apply:
"x" < @ "y"
"x" is converted to NLS in current locale before compare.
@ca_FR "Je suis une ficelle rouge"
==
@fi_FI "Olen punainen merkkijono"
Would throw an exception since the locale's are different. The fact that
the two strings mean the same thing could possibly be detected by
feeding them to google translator :) - but lets leave this feature
outside the scope of b3 :)
Any Babel people reading this... suggestions?
>
> Artifacts:
>
> ** Standard XText implementation allows a unary ^ before a keyword as an
> escape (Remove?)
>
> I'd vote yes to that. I'd prefer if we quote keywords where needed
> (paths, requirements, etc.) and prohibits the use of keywords as names
> in other places. Like Java.
>
I think so too.
> You have an example:
>
> "my.unit", "my.unit"; // unit is a keyword
> my.^unit; // unit is keyword - standard XText grammar escape of keywords
> in ID
>
> I understand why 'unit' needs to be quoted, but why do I need to quote
> 'my.unit'? Isn't that one single token? Can I write:
>
> my . "unit" // (with spaces surrounding the dot)
>
yes, since there is a bug when letting the parser do the lexing.
The use of hidden() in parser rules prohibits WS globbing in the lexer,
and thus spaces in the QualifiedName will generate syntax errors.
However, since the parser handles this instead of the lexer, it will see
"unit" as a keyword token.
Handling QualifiedName as a lexer token solves this. It however has
other consequences as it will gobble all occurrences of ID('.' ID)*
which makes it mask ID - there are places where a non Qualified ID is
wanted. The check could perhaps be deferred to data type checking, but
may cause problems. Currently there is the need to use ID (instead of
Qualified ID) in two places:
- in version which makes use of:
AlfanumSym : (ID | INT) (Separator|ID|INT)* ;
- in expressions where (Expression '.' ID) is a method call on
a LHS expression.
So, right now - I handle QualifiedName including WS globbing, since if I
turn it on, things are screwed up. If I solve it in the lexer I get
other problems.
Would prefer a solution where keywords in subparts of QualifiedName are
not recognized as keywords, provided we solve parsing of version and
method call (subject to debate if method call should be supported).
> NLS:
> "aŒŠš"; // has NLS characters
>
> What character encoding is used (related to the locale sensitive compare)?
>
Good question. What do you propose?
a) That we support one, and only one encoding of b3 files (like UTF8).
If so, which one?
b) That encoding is declared in the file, but with a default of a
standard encoding?
>
> Artifact paths:
>
> / a / b ; // is equivalent to /a/b - not /" a"/" b"
>
> That looks really odd to me. I haven't seen any language to date that
> does that and I don't think we should either.
Agree - it is a consequence of the hidden() bug in xtext. Should not be
allowed IMO.
> It's an incomprehensible
> syntax to most people. Perhaps you can have PATH recognized by the lexer
> and then specializations of that (REFERENCE and REQUEST for instance,
> allowing a version and version range) also recognized? I.e. that:
>
As stated above, the problem is coming up with lexer rules that makes it
possible to parse:
- versions
- version ranges
- qualified names
- unqualified names
- ints
- file paths
- advice paths
I think this is quite difficult. If hidden() works, then the only
consequence is that user must string quote if a keyword token is found
inside the element.
BTW - if anyone happens to be a lexer guru, feel free to come up with a
sequence of lex rules that handles all of the above. Free Beer offered :)
> Group:
> Regarding parallel or sequential execution. You have
>
> // The keyword 'syncronized' declares that parallell execution of any
> part is dissallowed
>
> this confuses me. synchronized usually mean that two threads cannot
> execute the same piece simultaneously. One must wait for the other. So a
> synchronized group would be a group that you expect multiple threads to
> call on for execution and that the threads must wait in line when that
> happens.
>
That is how I also thought of this.
> I would like to turn things around and say:
>
> private sequential group foo {} // Execute the parts of this group
> sequentially (the default)
> private parallel group foo {} // Allow parallel execution of the parts
> of this group
>
> I.e. executing things in parallel is a conscious decision. We can have
> synchronized too of course, but I think it's unusual that you'd want
> actions or groups that are not synchronized (in my sense of the word).
>
I can replace synchronized with sequential, and have that be the
default. That works for me language wise. BUT - in practice it makes the
mechanism useless as every component would then be specified to be
sequential (if that is the default).
So - I propose the following: It is parallel by default, and the
keywords are sequential and parallel.
And, agree that java synchronized semantics is always on. It is quite
meaningless to have a compiler compile the same thing to the same
location more than once at the same time. The only exception would be
some special actions - but that would be very special, and they can just
as well always be synchronized too.
> Action:
> Your non-working example:
>
> action test3 actor Test(test="test") provides a/b/"1"
> {
> // NON working example - need help with parser
>
> // group input to one results
> group {
> a;
> }
> result b { b.txt; }
> }
> */
>
> How about turning it inside out, like this:
>
> action test3 actor Test(test="test") provides a/b/"1"
> {
> result b { b.txt } with { group { a; } }
> }
>
I like that, and will make the changes. Agree with your reasoning.
The complex structure one has to write to get nested groups is not easy
to read anyway. Prefer the slight overhead for the complex case as it is
much clearer what you are doing. And, it removes the confusion over how
many times the actor should be invoked.
One addition is that it should be possible to specify several results
with a following with clause - i.e.:
{ result{} result{} } with { }
|
|
| | |
Re: b3 build files DSL in XText - annotaded sample b3 file [message #491404 is a reply to message #491365] |
Wed, 14 October 2009 12:58 |
|
More comments inline...
On 10/14/2009 01:02 PM, Henrik Lindberg wrote:
>> Properties:
>> property foo= "hello";
>> // a property can be set to null (but not immutable properties)
>> property foo;
>>
>> Wouldn't it be better to explicitly assign null in this case? It looks
>> like an uninitialized variable. So
>>
> You suggested having uninitialized properties. The rationale was to use
> them as part of result path group vectors. You agreed that that they
> could be set to null in that case. I agree that it is not very good...
> (read on)...
>
I remember that discussion. There's a subtle difference between declaring an expectation that a property will be part of
a result and actually declaring one (read on)...
> However, there is one more option that also increases quality, and that
> is to set the property to a special keyword that indicates that it is
> expected to be set by an action. Then, on return from the actor, a check
> can be made that the property was actually set.
>
> For instance, if there is an expectancy that the actor will assign a
> revision number or similar and it doesn't - then sometimes later, things
> will appear broken as the property is uninitialized.
>
> One possibility, would be to allow the following in result path group
> vector (but only there):
>
> immutable property revision;
>
> Since immutable means it can't be changed - it is clear that this is not
> allowed, and hence, that a value must be provided. The above is
> different from:
>
> immutable property revision = "r101010";
>
> Since this forbids the actor to change the value. And it is different from:
>
> property revision = "r101010";
>
> which specifies revision with a default value, that the actor may
> override. If specifying:
>
> property revision;
>
> Then, this would mean - revision implicetly set to null, actor may or
> may not set it. I think this is likely to cause problems (that are much
> harder to find), and suggest that we do not support this at all anywhere.
>
That would mean that we have to allow:
immutable property revision;
but not
property revision;
in a result. I think that is hard to understand. In that case it's better to say that the lack of assignment means that
the actor will (and must) provide a value. Even better perhaps using a keyword as you suggest.
property revision = derived;
or similar but then it becomes unclear how to set a default. Perhaps it could look like this:
property revision = derived("r101010");
alternatively, we turn it around:
derived property revision;
and with a default:
derived property revision = "r101010";
>> How do we plan to handle expression type priorities? I.e. which one of
>> these are true:
>>
>> "4" + 2 == 6
>> "4" + 2 == "42"
>> "4" + 2 == Exception, different types of operands.
>>
> We can:
> - Have generality on types and convert to the more general type -
> int/string becomes int. Since we don't have float, double and other
> types (although we may add collections) it is not that hard.
> - Only use string. (Don't like this solution though).
>
> So, I opt for:
>
> "4" + 2 = "42"
>
Agree. That's also what Java does.
> It is more an issue of interpreting properties set in properties files,
> or from the command line. How is the distinction made between a string
> and an int property there?
>
> A related question. Should we support "real" (i.e. double). ?
>
I believe we should. It's simple enough.
>> NLS:
>> "aŒŠš"; // has NLS characters
>>
>> What character encoding is used (related to the locale sensitive
>> compare)?
>>
> Good question. What do you propose?
> a) That we support one, and only one encoding of b3 files (like UTF8).
> If so, which one?
> b) That encoding is declared in the file, but with a default of a
> standard encoding?
>
a) sounds simpler. We can always implement b) later should there be a demand for it.
>>
>> Artifact paths:
>>
>> / a / b ; // is equivalent to /a/b - not /" a"/" b"
>>
>> That looks really odd to me. I haven't seen any language to date that
>> does that and I don't think we should either.
>
> Agree - it is a consequence of the hidden() bug in xtext. Should not be
> allowed IMO.
>
OK, let's revisit all issues related to WS once we have a better understanding on how to deal with this bug.
> I can replace synchronized with sequential, and have that be the
> default. That works for me language wise. BUT - in practice it makes the
> mechanism useless as every component would then be specified to be
> sequential (if that is the default).
>
Why? There's nothing stopping you from running different actions in parallel even though these actions in themselves are
both synchronized and sequential. It works as long as you don't try to run the same group or action simultaneously using
different threads.
> So - I propose the following: It is parallel by default, and the
> keywords are sequential and parallel.
>
Not too fond of having things running in parallel by default. I think most builds are inherently sequential and will
break when running things in parallel. Some specific tasks can execute in parallel but IMO, that's the exception and you
should declare them if needed, not the opposite.
- thomas
|
|
|
Re: action - group - result syntax [message #491406 is a reply to message #491374] |
Wed, 14 October 2009 13:04 |
|
On 10/14/2009 01:42 PM, Henrik Lindberg wrote:
> From the b3 DSL discussion... breaking it out...
>
> On 10/14/09 9:52 AM, Thomas Hallgren wrote:
>
>> Action:
>> action Test actor Test(test="test") provides a/b/"1"
>> {
>> result b { b; } with { group { a; x; } property foo="z80" }
>> result b { b; } with { group { a } }
>> result b { b; } with { group { a; x; } property foo="i8080" }
>> }
>>
> After thinking a bit, I think this syntax is slightly confusing. The
> properties set would have no effect on the evaluation of the group.
>
> For example:
> result b { b; } with {
> property bar="10";
> group { a; x; }
> property foo="i8080"
> }
>
> ... may be interpreted as the property bar being set in the scope of
> group evaluation. Are you ok with this potential confusion?
>
Perhaps my proposed 'derived' keyword would make the distinction clearer?
> The alternative would be to keep the group outside of the with clause.
> In that case it would make most sense to do it as follows:
>
> result {} with {} group {}
>
> Since
> result {} group {} with {}
>
> Looks like the with clause sets the properties for the group closure.
> Currently, a with clause on the group is not supported - you would have
> to use the following
>
> group { {x; y; z;} with {} }
>
> to set a closure on all the stuff in the group. An alternative is
>
> result {} with {} group {} with {}
>
> where the closures are optional.
>
> I think that is a better solution.
>
The keyword 'with' suggests that whatever is enclosed is input to the actor. That includes the group IMO. An alternative
to my 'derived' keyword that would solve the input/output property issue would be:
result {} with { group{} property ... } defines { property ... }
- thomas
|
|
| |
Re: action - group - result syntax [message #491447 is a reply to message #491406] |
Wed, 14 October 2009 15:45 |
Henrik Lindberg Messages: 2509 Registered: July 2009 |
Senior Member |
|
|
On 10/14/09 3:04 PM, Thomas Hallgren wrote:
> On 10/14/2009 01:42 PM, Henrik Lindberg wrote:
>> From the b3 DSL discussion... breaking it out...
>>
>> On 10/14/09 9:52 AM, Thomas Hallgren wrote:
>>
>>> Action:
>>> action Test actor Test(test="test") provides a/b/"1"
>>> {
>>> result b { b; } with { group { a; x; } property foo="z80" }
>>> result b { b; } with { group { a } }
>>> result b { b; } with { group { a; x; } property foo="i8080" }
>>> }
>>>
>> After thinking a bit, I think this syntax is slightly confusing. The
>> properties set would have no effect on the evaluation of the group.
>>
>> For example:
>> result b { b; } with {
>> property bar="10";
>> group { a; x; }
>> property foo="i8080"
>> }
>>
>> ... may be interpreted as the property bar being set in the scope of
>> group evaluation. Are you ok with this potential confusion?
>>
> Perhaps my proposed 'derived' keyword would make the distinction clearer?
>
Well, it helps with a different issue - the distinction between
properties set inside the result body (that was not shown in this
example). I was pointing out a closure problem.
The mix of group and properties inside the with is what is causing the
trouble. The properties set there are in the closure of the result, and
not in the closure of evaluating the group.
> The keyword 'with' suggests that whatever is enclosed is input to the
> actor. That includes the group IMO. An alternative to my 'derived'
> keyword that would solve the input/output property issue would be:
>
> result {} with { group{} property ... } defines { property ... }
I don't like the with{ group{} } construct, as it mixes properties,
advice and group - it is confusing what exactly the apply to. Also not
fond of the "defines property" at the end as I want to have the same
mechanism everywhere, and it would have an effect on artifacts. I like
it the way it is.
If with{} should apply to both result and group, and always do so, then
I suggest
result{} group{} with{}
Then, it is not possible to have different sets of properties and advice
for the group and the result. (Which could be useful to specify
"agnostic group", "specific result" for instance).
An alternative, if we want to support this - i.e.
result{} with {} group with{}
Then we just need to specify that the group closure surrounds the result
closure.
Example:
result {}
with {target.platform="sparc"}
group { buildSite }
with {target.platform = "*" useBuild="N12345" }
Which works well with a compound result
{ result a {} with { target.platform="sparc" }
result b {} with { target.platform="z80"
} group { buildSite } with {target.platform="*" }
This would present target.platform = "*" and useBuild="N12345" to the
closure when evaluating the group. And present target.platform="sparc"
useBuild="N12345" when calling the actor for a, and with
target.platform="z80" useBuild="N12345" when calling the actor for b.
Most commonly used would be:
result{} group{} with {}
As you most likely would want the same properties in both cases.
Regards
- henrik
|
|
| |
Re: action - group - result syntax [message #491463 is a reply to message #491451] |
Wed, 14 October 2009 17:17 |
|
On 10/14/2009 05:56 PM, Henrik Lindberg wrote:
>
> Typo - sorry
>> { result a {} with { target.platform="sparc" }
>> result b {} with { target.platform="z80"
>> } group { buildSite } with {target.platform="*" }
>>
>
> { result a {} with { target.platform="sparc" }
> result b {} with { target.platform="z80"}
> } group { buildSite } with {target.platform="*" }
>
I think one thing that confuses me with this syntax is the fact that a group is also a closure (a property scope). Let's
remove that for a second (I'll come back to that).
I like the idea that the actor produces a 'result' 'with' given input. The input being both groups and properties. So to
me, the 'result' and 'with' are tightly bound.
I think that:
action products ... {
result a{} with { group { buildSite }, property target.platform="sparc" }
result b{} with { group { buildSite }, property target.platform="z80" }
}
is much clearer than:
action products ... {
{ result a {} with { target.platform="sparc" }
result b {} with { target.platform="z80"}
} group { buildSite }
}
even if the latter is more compact. The closure for the 'buildSite' group is lost here however. What happens if we
introduce that as separate specialization? I.e.
closure a {
group { buildSite }
property target.platform="*"
}
or
closure a {
group { buildSite }
properties { target.platform="*"; ... }
}
I think that is more clear than:
group a { buildSite }
with { target.platform="*" }
Using the former syntax, we can also establish one important difference between 'closure' and 'with':
- The 'closure' propagates the properties to the 'group' that it contains.
- The 'with' just defines groups and properties that are input to the actor. The properties are *not* propagated to the
group. This means that we can express:
result a{} with { property target.platform="sparc"; closure { group { buildSite }; property target.platform="*" } };
OR, spelled out:
closure buildSiteEnvelope {
group { buildSite }
property targetPlatform="*"
}
result a{} with { property target.platform="sparc" group { buildSiteEnvelope } }
Another thought that strikes me when I read that syntax is that perhaps 'using' is a better keyword then 'with'. The
full products example could then be written as:
action buildSite ... {
result using { properties { target.platform="*"; ... } group { <whatever artifacts needed> } }
}
action products ... {
result a using { group { buildSite }; properties { target.platform="sparc"; ... }; }
result b using { group { buildSite }; properties { target.platform="z80"; ... }; }
}
OR
action buildSite ... {
result using { group { <whatever groups needed> } } // Look mum, no properties
}
action products ... {
// We overrided the target.platform for the actor invocation only. Not propagated to the buildSite group.
result a using { group { buildSite } properties { target.platform="sparc"; ... } }
result b using { group { buildSite } properties { target.platform="z80"; ... } }
}
closure buildAll {
group { products; }
properties { target.platform="*"; ... } // Here we set the default TP
}
Thoughs?
- thomas
|
|
|
Re: b3 build files DSL in XText - annotaded sample b3 file [message #491507 is a reply to message #491365] |
Wed, 14 October 2009 20:03 |
Sven Efftinge Messages: 1823 Registered: July 2009 |
Senior Member |
|
|
Hi all,
some comments inlined.
Henrik Lindberg wrote:
>> Artifacts:
>>
>> ** Standard XText implementation allows a unary ^ before a keyword as an
>> escape (Remove?)
>>
>> I'd vote yes to that. I'd prefer if we quote keywords where needed
>> (paths, requirements, etc.) and prohibits the use of keywords as names
>> in other places. Like Java.
>>
> I think so too.
Why do you want to constrain that?
It would just make your language more complicated because you need two
different versions of an identifier (an escapeable an a non-escapeable).
What kind of harm could one do with the escape character?
>
>> You have an example:
>>
>> "my.unit", "my.unit"; // unit is a keyword
>> my.^unit; // unit is keyword - standard XText grammar escape of keywords
>> in ID
>>
>> I understand why 'unit' needs to be quoted, but why do I need to quote
>> 'my.unit'? Isn't that one single token? Can I write:
>>
>> my . "unit" // (with spaces surrounding the dot)
>>
> yes, since there is a bug when letting the parser do the lexing.
> The use of hidden() in parser rules prohibits WS globbing in the lexer,
> and thus spaces in the QualifiedName will generate syntax errors.
> However, since the parser handles this instead of the lexer, it will see
> "unit" as a keyword token.
>
> Handling QualifiedName as a lexer token solves this. It however has
> other consequences as it will gobble all occurrences of ID('.' ID)*
> which makes it mask ID - there are places where a non Qualified ID is
> wanted. The check could perhaps be deferred to data type checking, but
> may cause problems. Currently there is the need to use ID (instead of
> Qualified ID) in two places:
>
> - in version which makes use of:
> AlfanumSym : (ID | INT) (Separator|ID|INT)* ;
> - in expressions where (Expression '.' ID) is a method call on
> a LHS expression.
>
> So, right now - I handle QualifiedName including WS globbing, since if I
> turn it on, things are screwed up. If I solve it in the lexer I get
> other problems.
>
> Would prefer a solution where keywords in subparts of QualifiedName are
> not recognized as keywords, provided we solve parsing of version and
> method call (subject to debate if method call should be supported).
I highly recommend to stick with parser rules here.
Are you aware of the fact that in most programming languages (Java
incl.) qualified names are parsed exactly like that?
I.e. you can write
package foo . /* fddfdf */ stuff;
but can't
package foo.bar.class;
But is this really a problem?
That said, we'll of course fix the hidden()-bug ASAP.
>
>> It's an incomprehensible
>> syntax to most people. Perhaps you can have PATH recognized by the lexer
>> and then specializations of that (REFERENCE and REQUEST for instance,
>> allowing a version and version range) also recognized? I.e. that:
>>
> As stated above, the problem is coming up with lexer rules that makes it
> possible to parse:
> - versions
> - version ranges
> - qualified names
> - unqualified names
> - ints
> - file paths
> - advice paths
>
> I think this is quite difficult. If hidden() works, then the only
> consequence is that user must string quote if a keyword token is found
> inside the element.
>
> BTW - if anyone happens to be a lexer guru, feel free to come up with a
> sequence of lex rules that handles all of the above. Free Beer offered :)
The problem with implementing all these as lexer rules is not defining
the rule, but that the lexing is completely context free. Having lots of
lexer rules, which don't shadow each other is often just impossible and
can't be solved.
For no beer in the world, unfortunately ;-)
So my advice here is again, to use parser rules and I'ld even allow
whitespace and comments inbetween if it is not ambigous.
People are usually smart enough to layout their scripts in a readable way.
If you want to guide the user you can add warnings or even errors in te
validation phase. That also allows for nicer error messages.
if you have any technical questions regarding Xtext, just use our
newsgroup.
We're looking forward to b3 :-)
Cheers,
Sven
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
|
|
|
Re: action - group - result syntax [message #491542 is a reply to message #491463] |
Wed, 14 October 2009 22:54 |
Henrik Lindberg Messages: 2509 Registered: July 2009 |
Senior Member |
|
|
On 10/14/09 7:17 PM, Thomas Hallgren wrote:
> On 10/14/2009 05:56 PM, Henrik Lindberg wrote:
>> { result a {} with { target.platform="sparc" }
>> result b {} with { target.platform="z80"}
>> } group { buildSite } with {target.platform="*" }
>>
> I think one thing that confuses me with this syntax is the fact that a
> group is also a closure (a property scope). Let's remove that for a
> second (I'll come back to that).
>
> I like the idea that the actor produces a 'result' 'with' given input.
> The input being both groups and properties. So to me, the 'result' and
> 'with' are tightly bound.
>
> I think that:
>
> action products ... {
> result a{} with { group { buildSite }, property target.platform="sparc" }
> result b{} with { group { buildSite }, property target.platform="z80" }
> }
>
I don't like that because the group is out of band wrt. the order in the
with clause. The rest of the statements, when executed, are done in the
order they are presented.
with { property a = 10; property b = a + 10; }
Makes property b have the value 20.
If you mix this with a group, which may have when() filters that
references properties, you may think that properties have the values as
computed in the sequence.
result a with {
property a = 10;
group {
derived property a = 10;
when(a == 10) x;
when(a == 20) y;
when(a == 30) z;
derived property a = a + 20;
}
property a = 20;
}
This will result in a == 20 to the actor.
What is the content of the group? x or y?
I can argue all three cases depending on the order the engine performs
the evaluations.
I also think it is wrong to place "derived properties" in the group -
they should not be derived. Derived properties should only be used in
the result. There is confusion there as well with the mixture of
statement sequence and declarative "requirements". I think we need to
revisit the decision to place properties directly in the group and
artifacts lists.
> is much clearer than:
>
> action products ... {
> { result a {} with { target.platform="sparc" }
> result b {} with { target.platform="z80"}
> } group { buildSite }
> }
>
Not really, I think it replaces one problem with another,
> even if the latter is more compact. The closure for the 'buildSite'
> group is lost here however. What happens if we introduce that as
> separate specialization? I.e.
>
> closure a {
> group { buildSite }
> property target.platform="*"
> }
>
I don't like the mix of statement sequence with group.
> closure a {
> group { buildSite }
> properties { target.platform="*"; ... }
> }
>
That is already possible by doing as follows:
group { {buildSite} with { property target.platform="*"; }}
As it is possible to set closures around selected parts in the group,
instead of just around an individual part. Wrapping all of the parts in
the group like eliminates the need for a with outside of the group. The
following two syntax examples are equivalent:
group { {} with{} ) === group { } with {}.
> Using the former syntax, we can also establish one important difference
> between 'closure' and 'with':
>
> - The 'closure' propagates the properties to the 'group' that it contains.
> - The 'with' just defines groups and properties that are input to the
> actor. The properties are *not* propagated to the group. This means that
> we can express:
>
The same concept is used throughout the syntax. Where it is possible
"with" allows setting properties, and advice that takes effect in the
closure the with clause is advising. It is always "around" something.
Why an additional concept - this just makes it more difficult to understand.
> result a{} with{ property target.platform="sparc"; closure { group {
> buildSite }; property target.platform="*" } };
>
> OR, spelled out:
>
> closure buildSiteEnvelope {
> group { buildSite }
> property targetPlatform="*"
> }
>
> result a{} with { property target.platform="sparc" group {
> buildSiteEnvelope } }
>
> Another thought that strikes me when I read that syntax is that perhaps
> 'using' is a better keyword then 'with'. The full products example could
> then be written as:
>
You are only looking at actions. The word "using" works less well
elsewhere. Maybe we should pick a different word - but lets keep the
ones we have been using until we know in what order we are going to have
the darned clauses :)
I will see if I can come up with an improvement that solves all of the
above issues:
- properties in the path group vectors
- understandable nesting of result, group and closures
- understandable order of evaluation of properties.
- henrik
|
|
|
Re: b3 build files DSL in XText - annotaded sample b3 file [message #491550 is a reply to message #491507] |
Thu, 15 October 2009 00:05 |
Henrik Lindberg Messages: 2509 Registered: July 2009 |
Senior Member |
|
|
Hi Sven,
Thanks for helping out. Much appreciated. Comments inline.
On 10/14/09 10:03 PM, Sven Efftinge wrote:
> Henrik Lindberg wrote:
>>> ** Standard XText implementation allows a unary ^ before a keyword as an
>>> escape (Remove?)
>> I think so too.
>
> Why do you want to constrain that?
> It would just make your language more complicated because you need two
> different versions of an identifier (an escapeable an a non-escapeable).
> What kind of harm could one do with the escape character?
>
We need to handle strange names anyway - names with NLS, spaces, and all
sorts of delimiters, or names that starts with digits. We opted for
quoting all non 'ID (. ID)*' names. So ^ adds a second escape mechanism
- just one more concept to explain. We are not in full control over the
naming standard as we map from other domains, hence the construct. And
to keep it simple - "if names include funny or reserved characters/words
- escape the name as a string". These names are not used as typical
variables in the language (so does not clash with expressions), but user
deals with them in many places, so it is nice to be able to write
typical names without having to handle them as strings at all times.
I also have an issue with ^keyword as I keep reading it as "raised to
the power of keyword" :)
> I highly recommend to stick with parser rules here.
> Are you aware of the fact that in most programming languages (Java
> incl.) qualified names are parsed exactly like that?
> I.e. you can write
>
> package foo . /* fddfdf */ stuff;
>
> but can't
>
> package foo.bar.class;
>
> But is this really a problem?
>
I have only found esoteric issues - I doubt anyone will ever have an
issue with those.
> That said, we'll of course fix the hidden()-bug ASAP.
>
Ah - great. That makes things so much easier since the parser rules
makes it possible to deal with "lexing in context" - I prefer that.
What I want to avoid is that someone thinks they entered a name with a
space in it. I.e entering "Program Files" as Program Files (only to get
white space sucked out of it). Better to spank them with a syntax error
- to allow them to enter either Program%20Files, "Program Files", (or
"Program%20Files"). (We will need to use the %nn notation in URLs, and
some names will be derived from URLs).
>> As stated above, the problem is coming up with lexer rules that makes
>> it possible to parse:
>> - versions
>> - version ranges
>> - qualified names
>> - unqualified names
>> - ints
>> - file paths
>> - advice paths
>>
>> I think this is quite difficult. If hidden() works, then the only
>> consequence is that user must string quote if a keyword token is found
>> inside the element.
>>
>> BTW - if anyone happens to be a lexer guru, feel free to come up with
>> a sequence of lex rules that handles all of the above. Free Beer
>> offered :)
>
> The problem with implementing all these as lexer rules is not defining
> the rule, but that the lexing is completely context free. Having lots of
> lexer rules, which don't shadow each other is often just impossible and
> can't be solved.
> For no beer in the world, unfortunately ;-)
>
If you have all the beer in the world, you won't care :)
> So my advice here is again, to use parser rules and I'ld even allow
> whitespace and comments inbetween if it is not ambigous.
> People are usually smart enough to layout their scripts in a readable way.
>
I will not even attempt to write the lexer rules, and instead use the
parser. I don't mind the embedded comments - if someone was smart enough
to figure out that it is possible and use it for some reason, they
probably know what they are doing.
> If you want to guide the user you can add warnings or even errors in te
> validation phase. That also allows for nicer error messages.
>
Yep - I got that. There are many things we need to handle there that can
not be solved by parsing alone.
> if you have any technical questions regarding Xtext, just use our
> newsgroup.
Thanks.
> We're looking forward to b3 :-)
>
I am very excited about b3 - have been able to make a lot of progress on
a very short time thanks to EMF, and XText.
Starting to ues XText was a very pleasant experience! Kudos. I wrote a
java like language 20 years ago using lex, yacc, and C++ - and I
probably produced as much in 1 week with Xtext (and got an editor with
syntax coloring at no extra effort) as I did in several months with the
lex, yacc, C++ combo. Kudos for a fantastic tool!
The only thing that causes me headache is when my grammar introduces
indirect left recursion. Precedence and associativity was easier to deal
with in yacc. Read that it is possible to make a packrat parser support
left recursion - http://www.vpri.org/pdf/tr2007002_packrat.pdf any
chance anything like that will make it into the XText packrat parser ?
Regards
- henrik
|
|
|
Re: action - group - result syntax [message #491559 is a reply to message #491542] |
Thu, 15 October 2009 02:38 |
Henrik Lindberg Messages: 2509 Registered: July 2009 |
Senior Member |
|
|
I wrote :)
> I will see if I can come up with an improvement that solves all of the
> above issues:
> - properties in the path group vectors
> - understandable nesting of result, group and closures
> - understandable order of evaluation of properties.
I started hacking at syntax... but realized that we probably are talking
past each other.
So, to reset the thinking I came up with an alternative way to describe
what it is we are trying to cover with the b3 syntax.
I think it is as follows:
DEFINE ARTIFACTS =
PATHS (p0, ... pn)
WHEN(EFFECTIVE CLOSURE EXPR == TRUE) PATHS (p0, ... pn)
WITH 'NEW' ANNOTATIONS (a0 = v0 ... an = vn) ;
DEFINE GROUP =
DEFINE PROPERTIES (p0, .. pn) IN GROUP'S CLOSURE
APPLY ADVICE (a0 .. an) IN GROUP'S CLOSURE
COLLECT 'PARTS AND ANNOTATIONS' (p0, p1, .. pa)
WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
ASSERT THESE ANNOTATIONS HAVE VALUE (a0 .. an)
POP THE GROUP'S CLOSURE
RETURN 'COLLECTED PARTS AND RESULTING ANNOTATIONS'
;
DEFINE ACTION =
DEFINE PROPERTIES (p0, .. pn) IN ACTION'S CLOSURE
APPLY ADVICE (a0 .. an) IN ACTION'S CLOSURE
CALL ACTOR (A) // initialized earlier
WITH THE FOLLOWING INPUT:
COLLECTED 'PARTS AND ANNOTATIONS' (p0, .. pn)
WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
ASSERT ANNOTATIONS HAVE A VALUE (a0 .. an)
'CONVERT ANNOTATIONS TO PROPERTIES' IN ACTION'S CLOSURE
DEFINE PART x =
PATHS(xp0, ... xpn)
WHEN(EFFECTIVE CLOSURE EXPR == TRUE) PATHS (p0, ... pn)
"COLLECT" ANNOTATIONS FROM THE ACTOR
WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
ASSERT ANNOTATIONS HAVE VALUE (a0 .. an)
COLLECT ALL PARTS AND ANNOTATIONS DEFINED IN THE ACTION
POP THE ACTION'S CLOSURE
RETURN 'COLLECTED PARTS AND ANNOTATIONS DEFINED IN THE ACTION'
;
I left out compound variants to make sure we have the basic steps
described first. (I deliberately left out when() in the description of
collecting parts and annotations, but that should be possible).
I hope my pseudo syntax is understandable, and that it is clear how I
think the various concepts interact.
- henrik
|
|
|
Re: action - group - result syntax [message #491598 is a reply to message #491559] |
Thu, 15 October 2009 07:59 |
|
Hi Henrik,
Yes this makes sense to me. One thing that I've been thinking about is if we don't need defaults for parts as well, i.e.
WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
becomes
WITH DEFAULT 'PARTS AND ANNOTATIONS' (a0 = v0 ... an = vn)
to cover cases like "This actor might optionally produce a configuration file. If it doesn't, this is the default".
Another thing I've been thinking about is asserts. I think that we need them on the artifacts as well. Perhaps a bit
esoteric but it could be used in cases where you want to make sure that at least 1 of 2 files is present in a folder.
I see that you place the assert before you pop the closure. Why is that? Shouldn't the assert execute as the absolute
last thing to avoid side-effects from the closure?
- thomas
On 10/15/2009 04:38 AM, Henrik Lindberg wrote:
> I wrote :)
>> I will see if I can come up with an improvement that solves all of the
>> above issues:
>> - properties in the path group vectors
>> - understandable nesting of result, group and closures
>> - understandable order of evaluation of properties.
>
> I started hacking at syntax... but realized that we probably are talking
> past each other.
>
> So, to reset the thinking I came up with an alternative way to describe
> what it is we are trying to cover with the b3 syntax.
>
> I think it is as follows:
>
> DEFINE ARTIFACTS =
> PATHS (p0, ... pn)
> WHEN(EFFECTIVE CLOSURE EXPR == TRUE) PATHS (p0, ... pn)
> WITH 'NEW' ANNOTATIONS (a0 = v0 ... an = vn) ;
>
> DEFINE GROUP =
> DEFINE PROPERTIES (p0, .. pn) IN GROUP'S CLOSURE
> APPLY ADVICE (a0 .. an) IN GROUP'S CLOSURE
> COLLECT 'PARTS AND ANNOTATIONS' (p0, p1, .. pa)
> WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
> ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
> ASSERT THESE ANNOTATIONS HAVE VALUE (a0 .. an)
> POP THE GROUP'S CLOSURE
> RETURN 'COLLECTED PARTS AND RESULTING ANNOTATIONS'
> ;
>
> DEFINE ACTION =
>
> DEFINE PROPERTIES (p0, .. pn) IN ACTION'S CLOSURE
> APPLY ADVICE (a0 .. an) IN ACTION'S CLOSURE
>
> CALL ACTOR (A) // initialized earlier
> WITH THE FOLLOWING INPUT:
> COLLECTED 'PARTS AND ANNOTATIONS' (p0, .. pn)
> WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
> ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
> ASSERT ANNOTATIONS HAVE A VALUE (a0 .. an)
> 'CONVERT ANNOTATIONS TO PROPERTIES' IN ACTION'S CLOSURE
>
> DEFINE PART x =
> PATHS(xp0, ... xpn)
> WHEN(EFFECTIVE CLOSURE EXPR == TRUE) PATHS (p0, ... pn)
> "COLLECT" ANNOTATIONS FROM THE ACTOR
> WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
> ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
> ASSERT ANNOTATIONS HAVE VALUE (a0 .. an)
>
>
> COLLECT ALL PARTS AND ANNOTATIONS DEFINED IN THE ACTION
> POP THE ACTION'S CLOSURE
> RETURN 'COLLECTED PARTS AND ANNOTATIONS DEFINED IN THE ACTION'
> ;
>
> I left out compound variants to make sure we have the basic steps
> described first. (I deliberately left out when() in the description of
> collecting parts and annotations, but that should be possible).
>
> I hope my pseudo syntax is understandable, and that it is clear how I
> think the various concepts interact.
>
> - henrik
|
|
|
Re: b3 build files DSL in XText - annotaded sample b3 file [message #491604 is a reply to message #491550] |
Thu, 15 October 2009 08:27 |
|
On 10/15/2009 02:05 AM, Henrik Lindberg wrote:
> I also have an issue with ^keyword as I keep reading it as "raised to
> the power of keyword" :)
>
x=a^b; // Binary op: x equals a XOR b
>> I highly recommend to stick with parser rules here.
>> Are you aware of the fact that in most programming languages (Java
>> incl.) qualified names are parsed exactly like that?
>> I.e. you can write
>>
>> package foo . /* fddfdf */ stuff;
>>
>> but can't
>>
>> package foo.bar.class;
>>
>> But is this really a problem?
>>
> I have only found esoteric issues - I doubt anyone will ever have an
> issue with those.
>
One less esoteric issue is that the path:
/ a/ b/
silently becomes:
/a/b/
The desired behavior is a syntax error, making the user aware that he must write:
/%20a/%20b/
Regards,
Thomas Hallgren
|
|
| |
Re: b3 build files DSL in XText - annotaded sample b3 file [message #491861 is a reply to message #491550] |
Fri, 16 October 2009 09:04 |
Sven Efftinge Messages: 1823 Registered: July 2009 |
Senior Member |
|
|
Hi
Henrik Lindberg wrote:
>
> I also have an issue with ^keyword as I keep reading it as "raised to
> the power of keyword" :)
The '^' is just a default.
See the ID rule in TerminalRules. Just override it and remove or change
the escape character.
>> I have only found esoteric issues - I doubt anyone will ever have an
>> issue with those.
>>
> One less esoteric issue is that the path:
>
> / a/ b/
>
> silently becomes:
>
> /a/b/
>
> The desired behavior is a syntax error, making the user aware that he
> must write:
>
Agreed.
>
> What I want to avoid is that someone thinks they entered a name with a
> space in it. I.e entering "Program Files" as Program Files (only to get
> white space sucked out of it). Better to spank them with a syntax error
> - to allow them to enter either Program%20Files, "Program Files", (or
> "Program%20Files"). (We will need to use the %nn notation in URLs, and
> some names will be derived from URLs).
For the time beeing (as long as the hidden() bug exists) you could
raise an error using the validation hook, when there's whitespace.
You get access to the underlying text of an EMF model by obtaining the
attached node model.
org.eclipse.xtext.parsetree.NodeUtil.getNodeAdapter(EObject)
> I will not even attempt to write the lexer rules, and instead use the
> parser. I don't mind the embedded comments - if someone was smart enough
> to figure out that it is possible and use it for some reason, they
> probably know what they are doing.
Exactly. Frameworks and languages shouldn't constrain users but guide them.
If they want to shoot their own foot, let them do it.
But we need to avoid any suggestions in that direction :-)
>
>> We're looking forward to b3 :-)
>>
> I am very excited about b3 - have been able to make a lot of progress on
> a very short time thanks to EMF, and XText.
>
> Starting to ues XText was a very pleasant experience! Kudos. I wrote a
> java like language 20 years ago using lex, yacc, and C++ - and I
> probably produced as much in 1 week with Xtext (and got an editor with
> syntax coloring at no extra effort) as I did in several months with the
> lex, yacc, C++ combo. Kudos for a fantastic tool!
Very nice words. Thank you very much.
>
> The only thing that causes me headache is when my grammar introduces
> indirect left recursion. Precedence and associativity was easier to deal
> with in yacc. Read that it is possible to make a packrat parser support
> left recursion - http://www.vpri.org/pdf/tr2007002_packrat.pdf any
> chance anything like that will make it into the XText packrat parser ?
Actually, Antlr is a very nice and sophisticated parser generator. We
don't want to reinvent the wheel here. The packrat parser was mainly
developed in order to solve some IP-problems. And we don't have plans to
improve it much in future.
Cheers,
Sven
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
|
|
| |
Re: b3 build files DSL in XText - annotaded sample b3 file [message #581669 is a reply to message #491290] |
Wed, 14 October 2009 07:52 |
|
Hi Henrik,
Lots of questions :-)
Properties:
property foo= "hello";
// a property can be set to null (but not immutable properties)
property foo;
Wouldn't it be better to explicitly assign null in this case? It looks like an uninitialized variable. So
property foo = null;
or
property foo = empty; // Since empty apparently is a keyword?
Expressions:
You have this expression in the file:
when (!target.platform != "sparc" && target.platform < "hpUx")
which I interpret as a not operation on a string which probably would result in an
UnsupportedOperationException?
How do we plan to handle expression type priorities? I.e. which one of these are true:
"4" + 2 == 6
"4" + 2 == "42"
"4" + 2 == Exception, different types of operands.
What does:
target.platform < "hpUx"
mean? If it's a lexical compare, is it sensitive to Locale? I can see use cases for both locale sensitive compare and
plain ASCII. Do we need additional operators for this?
Artifacts:
** Standard XText implementation allows a unary ^ before a keyword as an escape (Remove?)
I'd vote yes to that. I'd prefer if we quote keywords where needed (paths, requirements, etc.) and prohibits the use of
keywords as names in other places. Like Java.
You have an example:
"my.unit", "my.unit"; // unit is a keyword
my.^unit; // unit is keyword - standard XText grammar escape of keywords in ID
I understand why 'unit' needs to be quoted, but why do I need to quote 'my.unit'? Isn't that one single token? Can I write:
my . "unit" // (with spaces surrounding the dot)
?
NLS:
"aŒŠš"; // has NLS characters
What character encoding is used (related to the locale sensitive compare)?
Artifact paths:
/ a / b ; // is equivalent to /a/b - not /" a"/" b"
That looks really odd to me. I haven't seen any language to date that does that and I don't think we should either. It's
an incomprehensible syntax to most people. Perhaps you can have PATH recognized by the lexer and then specializations of
that (REFERENCE and REQUEST for instance, allowing a version and version range) also recognized? I.e. that:
requestElement:
PATH
| REFERENCE
| REQUEST
;
referenceElement:
PATH
| REFERENCE
;
artifactElement:
PATH
etc.
Group:
Regarding parallel or sequential execution. You have
// The keyword 'syncronized' declares that parallell execution of any part is dissallowed
this confuses me. synchronized usually mean that two threads cannot execute the same piece simultaneously. One must wait
for the other. So a synchronized group would be a group that you expect multiple threads to call on for execution and
that the threads must wait in line when that happens.
I would like to turn things around and say:
private sequential group foo {} // Execute the parts of this group sequentially (the default)
private parallel group foo {} // Allow parallel execution of the parts of this group
I.e. executing things in parallel is a conscious decision. We can have synchronized too of course, but I think it's
unusual that you'd want actions or groups that are not synchronized (in my sense of the word).
Action:
Your non-working example:
action test3 actor Test(test="test") provides a/b/"1"
{
// NON working example - need help with parser
// group input to one results
group {
a;
}
result b { b.txt; }
}
*/
How about turning it inside out, like this:
action test3 actor Test(test="test") provides a/b/"1"
{
result b { b.txt } with { group { a; } }
}
Since the result is at top, nested groups wouldn't work so your example:
action Test actor Test(test="test") provides a/b/"1"
{
group { a;
} {
group { x; } { result b { b; } }
result b {b;}
group { x; } { result b { b; } }
}
}
would need to be rewritten as:
action Test actor Test(test="test") provides a/b/"1"
{
result b { b; } with { group { a; x; } }
result b { b; } with { group { a } }
result b { b; } with { group { a; x; } }
}
which in my opinion vastly increases the readability. It becomes even more clear when you mix groups and properties:
action Test actor Test(test="test") provides a/b/"1"
{
result b { b; } with { group { a; x; } property foo="z80" }
result b { b; } with { group { a } }
result b { b; } with { group { a; x; } property foo="i8080" }
}
One argument in favor of your syntax is that repeating 'a' is cumbersome if it is complex. The counter argument to that
is; when that happens, just make 'a' a private group outside of the action.
Regards,
Thomas Hallgren
|
|
|
Re: b3 build files DSL in XText - annotaded sample b3 file [message #581690 is a reply to message #491322] |
Wed, 14 October 2009 07:55 |
|
Hi Matthias,
Here it is, in plain ISO8859-1 encoded text:
/*
** A .b3 file
** consists of import statements followed by a single "unit". This is analogous with a .java file having imports
** and a single language element (class, interface).
**
** This file is a sampler used to test syntax. The examples are not realistic (you will find plenty of a, b, c, fee and
foo...)
*/
/*
** COMMENTS
** Both single line and multi line comments are supported.
*/
// Single line comment
/* Multi line comment
*/
/*
** IMPORT
** Is used to import classes (just like in java). This is done so non qualified names can be used for classes
** DISCUSS: Imports are probably translated to meta requirements when resolving. As they are requirements on the
environment.
*/
import org.eclipse.b3.default.Resolvers.*;
/*
** UNIT
** A Unit is a Build Unit. It is used for several purposes:
** - as a file that describes "top level" requirements (what to import into a workspace, resolvers to use etc.)
** - as advice that extends meta data translation
** - as the meta data that describes a unit, when there is no other meta data
**
** A Unit has:
** - Properties
** - Provided Capabilities
** - Required Capabilities (and Meta Required Capabilities)
** - Parts (analogous with members in a class). There are four kinds of parts:
** - Artifacts (existing files)
** - Group (Aggregation of other parts)
** - Action (Production of new files (or side effect)
** - Result (A set of files produced by an Action ~= generated Artifacts)
** - Advice (Path/Predicate based access to elements that do not yet exist in the model). Used to set options, make
** overrides, etc.
** - Repositories - a configuration that is used to resolve (look up) units.
** - Synchronization - defines monitors across units that help solve issues in parallel builds
**
** A unit can be marked as synchronized - this means that requests to its parts are serialized.
** A unit can implement interfaces. These interfaces are "build time interfaces" and tells b3 about
** which parts it can expect. This also helps an author of extended components, and freshly created components
** comply with known build interfaces - i.e. this thing builds like an osgi.bundle.
*/
synchronized unit "my.unit" version 2.3 implements osgi.bundle, eclipe.ecore.model {
/* PROPERTIES
** Properties supports strings, integers, booleans, expressions and references to properties
*/
property foo= "hello";
// a property can be set to null (but not immutable properties)
property foo;
immutable property bar = 32;
immutable property bar = 32+10;
// checks if a calculation has the same value as a property
immutable property meaningful = 32+10 == the.meaning.of.life;
// a property can be "unset", that means that if it was set in this context, it will revert to
// it's value (if any) in an enclosing context.
//
unset property yellow.banana;
// Several properties can be set in a compound "properties" clause. It also works for unset.
// Note that the "property" keyword is no longer required per setting.
properties {
bar = "bar";
immutable politician = "oxymoron";
unset yellow.banana;
}
/* PROVIDES
** Provides clause is used to declare that the BuildUnit provides capabilities.
** A capability consists of interface/unitname and an optional /version at the end.
** If an interface, unitname or version requires use of reserved words or characters, the corresponding
** part is entered as a string (i.e. within " ").
** As with properties, there is a compound provides clause.
**
** Provide Capabilities can be filtered - some capabilities may only be provided under certain circumstances.
** This is declared with a leading when(BooleanExpression).
*/
provides osgi.bundle/bundlebar;
provides osgi.bundle/bundlebar/1.0;
provides {
osgi.bundle/barbara.bundle/2.0;
eclipse.feature/inflateable.pleasure/6.6.6;
when(target.platform == platforms.win32) native.thing/windowsInstaller/12.23.r1234;
}
provides when(target.platform == platforms.win32) native.thing/windowsInstaller/12.23.r1234;
/* REQUIRES
** Requires clause is used to declare that the BuildUnit requires certain capabilities.
** The differences between required and provided capabilities are that:
** - the version is always a range (althoug a single version means >= version
*/
requires osgi.bundle/air/1.0;
requires when (!target.platform != "sparc" && target.platform < "hpUx") osgi.bundle/pillow/3.0 ;
requires {
osgi.bundle/pillow/1.0;
when (a == b) osgi.bundle/blanket/1.0;
}
/* META REQUIRES
** With a leading meta keyword, the requiremens are requirements on the environment (i.e. on b3 itself)
** As an example, a meta requirement may be that a certain meta data provider is installed or it will be impossible to
** use this definition.
*/
meta requires osgi.bundle/air/1.0;
meta requires when (42 >= 32) osgi.bundle/pillow/"3.0";
meta requires {
osgi.bundle/pillow/1.0;
when (myorg.foo ~= "[a-z].*") osgi.bundle/blanket/1.0;
}
/* ARTIFACTS
** Artifact is a vector of path groups.
** A group of paths may have a base path - the rest of the paths in the group are relative to the
** base path.
** File names that include reserved words or reserved characters are entered within " "
** File names containing spaces must always be quoted, as the compiler removes whitespace from non strings.
** Standard XText implementation allows a unary ^ before a keyword as an escape (Remove?)
** Inclusion of a vector can be controlled with a leading when(BooleanExpression).
**
** VISIBILITY
** Visibility is either private or public (the default). Private means that the part is only accesable
** from within the b3 unit whene the part is declared.
**
** PROPERTIES
** It is possible to set (and unset) properties in the list using basic or compound property statements.
** These properties are set on the resulting path group vector and are available to the user of the
** set of files.
** Since file group vectors are merged, so will the properties. Use of immutable properties will guarantee
** that the property values set will surface (or an error will be generated if merging causes the value
** to change), but is ok if multiple vectors are tagged the same way.
**
** Note that individual property settings per file is not supported. To flag an individual file it is
** recommended to use dottiefied properties - example - mark the path /a/b as being little endian
** property org.myorg.fileinfo.endian.a.b=little.
**
** DISCUSS - is it of value to have properties/annotations per file?
**
*/
private artifacts test.a1 provides myorg.food/fruit.sallad/2.0, myorg.projectiles/fruit.salad
{
a; // a vector with one entry
a, b; // a vector with two entries
a [ b, c]; // a base path (a), with two relative paths in a vector
/a/b;
/ a / b ; // is equivalent to /a/b - not /" a"/" b"
// names that must be quoted
"unit"; // a keyword
"1a"; // does not look like a qualified name
"a b"; // has space in name
"aŒŠš"; // has NLS characters
"//f"; // looks like a comment
"123"; // is an integer
"my.unit", "my.unit"; // unit is a keyword
my.^unit; // unit is keyword - standard XText grammar escape of keywords in ID
when(target.platform == "osx") MacApp.app ;
when(true) banana.txt, pineapple.txt, mango.txt;
when (true) exotic [ rambustan.txt, tamarind.txt ];
a1 [apple.txt, "ban ana.txt"];
fee/apa.boo [ a/b/c.d, a.b.c.d, o/b/d ];
property apa="banan";
property defaultsToNull;
properties { a; b; }
}
// An empty artifacts vecor
artifacts empty {
}
/* ARTIFACTS PROVIDING CAPABILITIES
** It is possible to declare that the resulting path group vector is a capability layed out on disk.
** They layout can represent many capabilities at the same time.
*/
artifacts providesMany provides a/b/1.0, c/d/2.0, x/y/3.0 {a;}
/* GROUP
** A group is similar to artifacts in that it creates a path group vector, but it creates this
** by aggregating path group vectors from other parts.
** Just as with artifacts; the resulting path group vector can represent capabilities.
**
** The group consists of a list of required capabilities. The syntax is the same as for
** the units requires { } clause, with the following additions:
** - A trailing '#partname' is used after the requirement to pick a particular part.
** - A reference can be made to parts in the same build unit by using a single identifier
** - A reference to a required capability without a trailing '#partname' is taken as a reference to '#self', meaning the
** aggregation of all its public parts.
** - It is possible to define a closure where properties and advise are declared. They have downstream effect
** (i.e. when evaluating the part). The closure is defined using a trailing with { } statement.
** - A closure can be defined for several requirements at the same time by enclosing the requirements in curly
** brackets {r r r} with { }
** - A leading void keyword indicates that the resulting path group vector from the evaluation of the part should
** not be included in the resulting path group vector.
** - The result of individual part evaluation, or evaluation of a group of requirements can be assigned to an alias.
** The alias is a property that is included in the resulting path group vector. This makes it possible for a user
** of the vector to reference a particular part of the set.
** - void and alias can be used at the same time, but for a group that represents a part (as in this case), neither the
** property nor its value survive the group's context. For other types of grouping (in actions), this is very
** valuable, but in a group part, this construct simply has no effect.
**
** WITH CLOSURE
** In the with closure, properties can be set using the single or compound properties statements.
** Advice can be set using advice syntax.
**
*/
private synchronized group "foo/bar" provides myorg.food/fruit.coctail/2.0, a / b / "2.3"
{
a; // referense to part in self
foo/bar; // reference to #self in interface foo, name bar
a/a#b; // reference to #b in interface a, name a
fubbla= osgi.bundle/foo.bar/1.0; // sets the property fubbla to to the pathGroup reference in runtime - typically not
used in groups
osgi.bundle/fee.fum/1.0#jars;
osgi.bundle/zeBundle/1.0#jars;
void a/a#b; // only performed for side effect
void alias.nbr1 = b; // only performed for side effect, but sets a property to the result (that is then ignored)
a/a#b with { property nice = "yes"; }; // sets and passes the property nice downsteam
a/a#b with { // passes several properties downstream.
properties {
a="2"; b="2"; c="3";
}
};
// includes result of three references, all with the same set of downstream properties
{ a/a#b; a/b#c; a/c#d; } with { property target.platform="sparc"; };
// sets an alias on a non included result, result is a group of items with downstream properties
void aliasedButNotIncluded = { a/a#b; a/b#c; a/c#d; } with { property foo="hpux"; };
// sets an alias on an included item, result is a group of items with downstream properties, a nested alias is set
aliasedAndIncluded = { alias.nbr3=a/a#b; a/b#c; a/c#d; } with { property foo="hpux"; };
// inclusion can be filtered with a boolean expression - here "true" makes it always included
when (true) { a/a#b; a/b#c; a/c#d; } with { property foo="z80"; };
// filtering - here, never ever included because boolean value is false
when (false) a/a#b;
// a non included and filtered reference to a/a#b
void when (true) a/a#b;
}
// The keyword 'syncronized' declares that parallell execution of any part is dissallowed
private synchronized group foo {}
public synchronized group foo {}
private group foo {}
group foo {}
synchronized group foo {}
/*
** ACTION
** An action has an embedded group declaration that defines the input to an actor. The actor is told to
** produce the result(s) decalred for the input group. Input groups and results can be nested.
** This is used to decalre common input, input for a group of results (such as input to actions for linux),
** and then specific input for building a linx flavor, for different windowing systems etc.
**
** The result can consist be declared with public or private visibility, or follow the visibility of the action.
** Public result are available as first class members of the unit (even if the enclosing action is private).
** Public result must be named. Private result must be named if it should be referenced individually (and not as
** part of the action's result).
**
** The actor is declared in the preamble of the action part and is instantiated once.
** Parameters to the actor instantiation can be passed with parentheses using named parameters
** (order is not important).
** - An action can provide the resulting path group vector as provided capabilities
**
** Aliases
** Aliases for input parts have an additional meaning in actions - these properties are available to the actor.
** This means that the combination of void alias={ } is meaningful (as opposed to when used in a group part).
**
** RESULT
** Result clauses behave like artifact parts, but they typically refer to files that were produce by the actor.
** Properties in these sets may be set by the actor. This means that an actor can pass information back - such as
** a version qualifier, location of certain files on disk etc.
**
*/
private synchronized action foo
actor ZipActor(serviceKey="WooHoo - woot")
provides myorg.food/fruit.coctail/2.0
{
group {
a; // defaults to #self
when (apa > 11) a/a#b;
osgi.bundle/foo.bar/"1.2.3.qualifier#,./"#jars; // defaults to #self
osgi.bundle/fee.fum/1.0#jars;
osgi.bundle/zeBundle#jars;
void a/a#b; // only performed for side effect
void alias.nbr1 = a/a#b; // only performed for side effect
a/a#b with { property nice = "yes"; };
a/a#b with {
properties {
a="2"; b="2"; c="3";
}
};
{ a/a#b; a/b#c; a/c#d; } with { property target.platform="sparc"; };
void { a/a#b; a/b#c; a/c#d; } with { property foo="hpux"; };
void alias.nbr2 = { alias.nbr3=a/a#b; a/b#c; a/c#d; } with { property foo="hpux"; };
when (true) { a/a#b; a/b#c; a/c#d; } with { property foo="z80"; };
when (false) a/a#b;
void when (true) a/a#b;
}{
result a { a; }
}
}
action test1 actor Test(test="test") provides a/b/"1"
{ // no dependencies, no special input, just "do it and produce result"
result b { b.txt; }
}
action test2 actor Test(test="test") provides a/b/"1"
{ // no dependencies, no special input, just "do it and produce result"
// but set a properties
//
result b { b.txt; } with { property target.platform = "win32"; }
}
/* NON WORKING SYNTAX, due to problems in language specification. Help Wanted.
action test3 actor Test(test="test") provides a/b/"1"
{
// NON working example - need help with parser
// group input to one results
group {
a;
}
result b { b.txt; }
}
*/
action test3 actor Test(test="test") provides a/b/"1"
{
// group input to one or several results
group { a; }
{
result b { b.txt; }
}
}
action Test actor Test(test="test") provides a/b/"1"
{
group { a;
} {
result b { b; }
result b { b; }
result b { b; }
}
}
action Test actor Test(test="test") provides a/b/"1"
{
group { a;
} {
group { x; } { result b { b; } }
result b {b;}
group { x; } { result b { b; } }
}
}
action makeWin32Zip
actor ZipActor(serviceKey="tjoho")
provides foodstuff.sallad/fruitsallad/1.0, x/b/"23"
{
group {
{ site = createSite; } with { property target.platform="win32";};
}{
group {
extraInput = a/a/2.0#jarFiles;
}{
public result makeSomeoneHappy {
apa/banan.zip ;
when(true) chimp/banan.zip ;
} with { properties { target.platform = "win32"; prerequisite.flag = "a#b"; }}
group {
special;
}{
when (true) private result a { a;} with { /* for a only */ }
when (true) result b {} with { /* for b only */ }
} with { /* for a and b */ }
}
}
}
/** Synchronize clauses allows syncronization to be specified across units/actions.
** When executing a build in parallell, an engine should serialize the evaluation (build) of the
** specified elements. Serialization of execution may serialize more than what is specified but never less.
** Each synchronized list specifies a group that will be serialized. References are to part names in this unit, or
** to part names in other units.
**
** DISCUSS: although very useful, statements that synchronized on interface/*, and on actors are also useful.
** Syntax should probably be xpath/query like.
*/
synchronize a,b,c;
synchronize a/a#x,b/b#x,c/c;
synchronize { a,b,c; d,e,f; }
/** REPOSITORIES
** The repository clause defines the order in which repositories are searched.
** There are two forms of entries - the most common is expected to be the short form, where
** both the location, and repository type is specified with a URI. The URI scheme is used to select
** a resolver. For cases where this is not possible, the longer form is to declare that a resolver should be
** used, and the location (a general URL) is then set using advice (if indeed the selected resolver needs a location).
**
**
*/
repositories {
"http://bar/fee" { };
"http://bar/foo";
"http://bar/fum";
resolver foo.bar {
// Statements here are advice relative to a resolver. (i.e. '.' is a resolver)
//
location="http:://www.somewhere.com";
apa = 10;
booleanFlag = 10;
options/advanced[featureA ~="[a-z]*"]/?[a>23]/b/?? {
option1 = 10;
option2 = 20;
option3 = "hello";
};
};
}
advice import_Advice {
/requests[name~="org.myorg.*"]/options {
source=true;
mutable=true;
};
/resolutions[name~="org.eclipse.*"]/options {
location = "platform:/plugin/";
};
}
}
|
|
|
Re: b3 build files DSL in XText - annotaded sample b3 file [message #581728 is a reply to message #491333] |
Wed, 14 October 2009 11:02 |
Henrik Lindberg Messages: 2509 Registered: July 2009 |
Senior Member |
|
|
Hi,
comments in-line...
- henrik
On 10/14/09 9:52 AM, Thomas Hallgren wrote:
> Lots of questions :-)
>
Feedback apreciated :-)
> Properties:
> property foo= "hello";
> // a property can be set to null (but not immutable properties)
> property foo;
>
> Wouldn't it be better to explicitly assign null in this case? It looks
> like an uninitialized variable. So
>
You suggested having uninitialized properties. The rationale was to use
them as part of result path group vectors. You agreed that that they
could be set to null in that case. I agree that it is not very good...
(read on)...
> property foo = null;
>
> or
> property foo = empty; // Since empty apparently is a keyword?
>
I think we should not allow uninitialized properties.
We can use "null" if we want to, "empty" is not a keyword, it is the
name of a property in the sample :-).
However, there is one more option that also increases quality, and that
is to set the property to a special keyword that indicates that it is
expected to be set by an action. Then, on return from the actor, a check
can be made that the property was actually set.
For instance, if there is an expectancy that the actor will assign a
revision number or similar and it doesn't - then sometimes later, things
will appear broken as the property is uninitialized.
One possibility, would be to allow the following in result path group
vector (but only there):
immutable property revision;
Since immutable means it can't be changed - it is clear that this is not
allowed, and hence, that a value must be provided. The above is
different from:
immutable property revision = "r101010";
Since this forbids the actor to change the value. And it is different from:
property revision = "r101010";
which specifies revision with a default value, that the actor may
override. If specifying:
property revision;
Then, this would mean - revision implicetly set to null, actor may or
may not set it. I think this is likely to cause problems (that are much
harder to find), and suggest that we do not support this at all anywhere.
>
> Expressions:
> You have this expression in the file:
>
> when (!target.platform != "sparc" && target.platform < "hpUx")
>
> which I interpret as a not operation on a string which probably would
> result in an
> UnsupportedOperationException?
>
Yes, the expression would throw an exception. I made it like that in the
sample on purpose to trigger the discussion on how to handle such issues :)
> How do we plan to handle expression type priorities? I.e. which one of
> these are true:
>
> "4" + 2 == 6
> "4" + 2 == "42"
> "4" + 2 == Exception, different types of operands.
>
We can:
- Have generality on types and convert to the more general type -
int/string becomes int. Since we don't have float, double and other
types (although we may add collections) it is not that hard.
- Only use string. (Don't like this solution though).
So, I opt for:
"4" + 2 = "42"
It is more an issue of interpreting properties set in properties files,
or from the command line. How is the distinction made between a string
and an int property there?
A related question. Should we support "real" (i.e. double). ?
> What does:
>
> target.platform < "hpUx"
>
> mean? If it's a lexical compare, is it sensitive to Locale? I can see
> use cases for both locale sensitive compare and plain ASCII. Do we need
> additional operators for this?
>
Very good question(s):
a) It would mean lexical compare if we implement it ;)
b) I see two ways of implementing specification of NLS
- having a bunch of operators that say that the compare is NLS, say @<
@> @<= @>= @== @!= (ugly, and makes it hard to specify locale).
- handle NLS strings as a type more general than string.
@ "This is a NLS String in current locale"
@us_EN "This is a NLS String in US English"
@se_SE "En svensk tiger"
The following would then apply:
"x" < @ "y"
"x" is converted to NLS in current locale before compare.
@ca_FR "Je suis une ficelle rouge"
==
@fi_FI "Olen punainen merkkijono"
Would throw an exception since the locale's are different. The fact that
the two strings mean the same thing could possibly be detected by
feeding them to google translator :) - but lets leave this feature
outside the scope of b3 :)
Any Babel people reading this... suggestions?
>
> Artifacts:
>
> ** Standard XText implementation allows a unary ^ before a keyword as an
> escape (Remove?)
>
> I'd vote yes to that. I'd prefer if we quote keywords where needed
> (paths, requirements, etc.) and prohibits the use of keywords as names
> in other places. Like Java.
>
I think so too.
> You have an example:
>
> "my.unit", "my.unit"; // unit is a keyword
> my.^unit; // unit is keyword - standard XText grammar escape of keywords
> in ID
>
> I understand why 'unit' needs to be quoted, but why do I need to quote
> 'my.unit'? Isn't that one single token? Can I write:
>
> my . "unit" // (with spaces surrounding the dot)
>
yes, since there is a bug when letting the parser do the lexing.
The use of hidden() in parser rules prohibits WS globbing in the lexer,
and thus spaces in the QualifiedName will generate syntax errors.
However, since the parser handles this instead of the lexer, it will see
"unit" as a keyword token.
Handling QualifiedName as a lexer token solves this. It however has
other consequences as it will gobble all occurrences of ID('.' ID)*
which makes it mask ID - there are places where a non Qualified ID is
wanted. The check could perhaps be deferred to data type checking, but
may cause problems. Currently there is the need to use ID (instead of
Qualified ID) in two places:
- in version which makes use of:
AlfanumSym : (ID | INT) (Separator|ID|INT)* ;
- in expressions where (Expression '.' ID) is a method call on
a LHS expression.
So, right now - I handle QualifiedName including WS globbing, since if I
turn it on, things are screwed up. If I solve it in the lexer I get
other problems.
Would prefer a solution where keywords in subparts of QualifiedName are
not recognized as keywords, provided we solve parsing of version and
method call (subject to debate if method call should be supported).
> NLS:
> "aŒŠš"; // has NLS characters
>
> What character encoding is used (related to the locale sensitive compare)?
>
Good question. What do you propose?
a) That we support one, and only one encoding of b3 files (like UTF8).
If so, which one?
b) That encoding is declared in the file, but with a default of a
standard encoding?
>
> Artifact paths:
>
> / a / b ; // is equivalent to /a/b - not /" a"/" b"
>
> That looks really odd to me. I haven't seen any language to date that
> does that and I don't think we should either.
Agree - it is a consequence of the hidden() bug in xtext. Should not be
allowed IMO.
> It's an incomprehensible
> syntax to most people. Perhaps you can have PATH recognized by the lexer
> and then specializations of that (REFERENCE and REQUEST for instance,
> allowing a version and version range) also recognized? I.e. that:
>
As stated above, the problem is coming up with lexer rules that makes it
possible to parse:
- versions
- version ranges
- qualified names
- unqualified names
- ints
- file paths
- advice paths
I think this is quite difficult. If hidden() works, then the only
consequence is that user must string quote if a keyword token is found
inside the element.
BTW - if anyone happens to be a lexer guru, feel free to come up with a
sequence of lex rules that handles all of the above. Free Beer offered :)
> Group:
> Regarding parallel or sequential execution. You have
>
> // The keyword 'syncronized' declares that parallell execution of any
> part is dissallowed
>
> this confuses me. synchronized usually mean that two threads cannot
> execute the same piece simultaneously. One must wait for the other. So a
> synchronized group would be a group that you expect multiple threads to
> call on for execution and that the threads must wait in line when that
> happens.
>
That is how I also thought of this.
> I would like to turn things around and say:
>
> private sequential group foo {} // Execute the parts of this group
> sequentially (the default)
> private parallel group foo {} // Allow parallel execution of the parts
> of this group
>
> I.e. executing things in parallel is a conscious decision. We can have
> synchronized too of course, but I think it's unusual that you'd want
> actions or groups that are not synchronized (in my sense of the word).
>
I can replace synchronized with sequential, and have that be the
default. That works for me language wise. BUT - in practice it makes the
mechanism useless as every component would then be specified to be
sequential (if that is the default).
So - I propose the following: It is parallel by default, and the
keywords are sequential and parallel.
And, agree that java synchronized semantics is always on. It is quite
meaningless to have a compiler compile the same thing to the same
location more than once at the same time. The only exception would be
some special actions - but that would be very special, and they can just
as well always be synchronized too.
> Action:
> Your non-working example:
>
> action test3 actor Test(test="test") provides a/b/"1"
> {
> // NON working example - need help with parser
>
> // group input to one results
> group {
> a;
> }
> result b { b.txt; }
> }
> */
>
> How about turning it inside out, like this:
>
> action test3 actor Test(test="test") provides a/b/"1"
> {
> result b { b.txt } with { group { a; } }
> }
>
I like that, and will make the changes. Agree with your reasoning.
The complex structure one has to write to get nested groups is not easy
to read anyway. Prefer the slight overhead for the complex case as it is
much clearer what you are doing. And, it removes the confusion over how
many times the actor should be invoked.
One addition is that it should be possible to specify several results
with a following with clause - i.e.:
{ result{} result{} } with { }
|
|
| | |
Re: b3 build files DSL in XText - annotaded sample b3 file [message #581797 is a reply to message #491365] |
Wed, 14 October 2009 12:58 |
|
More comments inline...
On 10/14/2009 01:02 PM, Henrik Lindberg wrote:
>> Properties:
>> property foo= "hello";
>> // a property can be set to null (but not immutable properties)
>> property foo;
>>
>> Wouldn't it be better to explicitly assign null in this case? It looks
>> like an uninitialized variable. So
>>
> You suggested having uninitialized properties. The rationale was to use
> them as part of result path group vectors. You agreed that that they
> could be set to null in that case. I agree that it is not very good...
> (read on)...
>
I remember that discussion. There's a subtle difference between declaring an expectation that a property will be part of
a result and actually declaring one (read on)...
> However, there is one more option that also increases quality, and that
> is to set the property to a special keyword that indicates that it is
> expected to be set by an action. Then, on return from the actor, a check
> can be made that the property was actually set.
>
> For instance, if there is an expectancy that the actor will assign a
> revision number or similar and it doesn't - then sometimes later, things
> will appear broken as the property is uninitialized.
>
> One possibility, would be to allow the following in result path group
> vector (but only there):
>
> immutable property revision;
>
> Since immutable means it can't be changed - it is clear that this is not
> allowed, and hence, that a value must be provided. The above is
> different from:
>
> immutable property revision = "r101010";
>
> Since this forbids the actor to change the value. And it is different from:
>
> property revision = "r101010";
>
> which specifies revision with a default value, that the actor may
> override. If specifying:
>
> property revision;
>
> Then, this would mean - revision implicetly set to null, actor may or
> may not set it. I think this is likely to cause problems (that are much
> harder to find), and suggest that we do not support this at all anywhere.
>
That would mean that we have to allow:
immutable property revision;
but not
property revision;
in a result. I think that is hard to understand. In that case it's better to say that the lack of assignment means that
the actor will (and must) provide a value. Even better perhaps using a keyword as you suggest.
property revision = derived;
or similar but then it becomes unclear how to set a default. Perhaps it could look like this:
property revision = derived("r101010");
alternatively, we turn it around:
derived property revision;
and with a default:
derived property revision = "r101010";
>> How do we plan to handle expression type priorities? I.e. which one of
>> these are true:
>>
>> "4" + 2 == 6
>> "4" + 2 == "42"
>> "4" + 2 == Exception, different types of operands.
>>
> We can:
> - Have generality on types and convert to the more general type -
> int/string becomes int. Since we don't have float, double and other
> types (although we may add collections) it is not that hard.
> - Only use string. (Don't like this solution though).
>
> So, I opt for:
>
> "4" + 2 = "42"
>
Agree. That's also what Java does.
> It is more an issue of interpreting properties set in properties files,
> or from the command line. How is the distinction made between a string
> and an int property there?
>
> A related question. Should we support "real" (i.e. double). ?
>
I believe we should. It's simple enough.
>> NLS:
>> "aŒŠš"; // has NLS characters
>>
>> What character encoding is used (related to the locale sensitive
>> compare)?
>>
> Good question. What do you propose?
> a) That we support one, and only one encoding of b3 files (like UTF8).
> If so, which one?
> b) That encoding is declared in the file, but with a default of a
> standard encoding?
>
a) sounds simpler. We can always implement b) later should there be a demand for it.
>>
>> Artifact paths:
>>
>> / a / b ; // is equivalent to /a/b - not /" a"/" b"
>>
>> That looks really odd to me. I haven't seen any language to date that
>> does that and I don't think we should either.
>
> Agree - it is a consequence of the hidden() bug in xtext. Should not be
> allowed IMO.
>
OK, let's revisit all issues related to WS once we have a better understanding on how to deal with this bug.
> I can replace synchronized with sequential, and have that be the
> default. That works for me language wise. BUT - in practice it makes the
> mechanism useless as every component would then be specified to be
> sequential (if that is the default).
>
Why? There's nothing stopping you from running different actions in parallel even though these actions in themselves are
both synchronized and sequential. It works as long as you don't try to run the same group or action simultaneously using
different threads.
> So - I propose the following: It is parallel by default, and the
> keywords are sequential and parallel.
>
Not too fond of having things running in parallel by default. I think most builds are inherently sequential and will
break when running things in parallel. Some specific tasks can execute in parallel but IMO, that's the exception and you
should declare them if needed, not the opposite.
- thomas
|
|
|
Re: action - group - result syntax [message #581824 is a reply to message #491374] |
Wed, 14 October 2009 13:04 |
|
On 10/14/2009 01:42 PM, Henrik Lindberg wrote:
> From the b3 DSL discussion... breaking it out...
>
> On 10/14/09 9:52 AM, Thomas Hallgren wrote:
>
>> Action:
>> action Test actor Test(test="test") provides a/b/"1"
>> {
>> result b { b; } with { group { a; x; } property foo="z80" }
>> result b { b; } with { group { a } }
>> result b { b; } with { group { a; x; } property foo="i8080" }
>> }
>>
> After thinking a bit, I think this syntax is slightly confusing. The
> properties set would have no effect on the evaluation of the group.
>
> For example:
> result b { b; } with {
> property bar="10";
> group { a; x; }
> property foo="i8080"
> }
>
> ... may be interpreted as the property bar being set in the scope of
> group evaluation. Are you ok with this potential confusion?
>
Perhaps my proposed 'derived' keyword would make the distinction clearer?
> The alternative would be to keep the group outside of the with clause.
> In that case it would make most sense to do it as follows:
>
> result {} with {} group {}
>
> Since
> result {} group {} with {}
>
> Looks like the with clause sets the properties for the group closure.
> Currently, a with clause on the group is not supported - you would have
> to use the following
>
> group { {x; y; z;} with {} }
>
> to set a closure on all the stuff in the group. An alternative is
>
> result {} with {} group {} with {}
>
> where the closures are optional.
>
> I think that is a better solution.
>
The keyword 'with' suggests that whatever is enclosed is input to the actor. That includes the group IMO. An alternative
to my 'derived' keyword that would solve the input/output property issue would be:
result {} with { group{} property ... } defines { property ... }
- thomas
|
|
| |
Re: action - group - result syntax [message #581858 is a reply to message #491406] |
Wed, 14 October 2009 15:45 |
Henrik Lindberg Messages: 2509 Registered: July 2009 |
Senior Member |
|
|
On 10/14/09 3:04 PM, Thomas Hallgren wrote:
> On 10/14/2009 01:42 PM, Henrik Lindberg wrote:
>> From the b3 DSL discussion... breaking it out...
>>
>> On 10/14/09 9:52 AM, Thomas Hallgren wrote:
>>
>>> Action:
>>> action Test actor Test(test="test") provides a/b/"1"
>>> {
>>> result b { b; } with { group { a; x; } property foo="z80" }
>>> result b { b; } with { group { a } }
>>> result b { b; } with { group { a; x; } property foo="i8080" }
>>> }
>>>
>> After thinking a bit, I think this syntax is slightly confusing. The
>> properties set would have no effect on the evaluation of the group.
>>
>> For example:
>> result b { b; } with {
>> property bar="10";
>> group { a; x; }
>> property foo="i8080"
>> }
>>
>> ... may be interpreted as the property bar being set in the scope of
>> group evaluation. Are you ok with this potential confusion?
>>
> Perhaps my proposed 'derived' keyword would make the distinction clearer?
>
Well, it helps with a different issue - the distinction between
properties set inside the result body (that was not shown in this
example). I was pointing out a closure problem.
The mix of group and properties inside the with is what is causing the
trouble. The properties set there are in the closure of the result, and
not in the closure of evaluating the group.
> The keyword 'with' suggests that whatever is enclosed is input to the
> actor. That includes the group IMO. An alternative to my 'derived'
> keyword that would solve the input/output property issue would be:
>
> result {} with { group{} property ... } defines { property ... }
I don't like the with{ group{} } construct, as it mixes properties,
advice and group - it is confusing what exactly the apply to. Also not
fond of the "defines property" at the end as I want to have the same
mechanism everywhere, and it would have an effect on artifacts. I like
it the way it is.
If with{} should apply to both result and group, and always do so, then
I suggest
result{} group{} with{}
Then, it is not possible to have different sets of properties and advice
for the group and the result. (Which could be useful to specify
"agnostic group", "specific result" for instance).
An alternative, if we want to support this - i.e.
result{} with {} group with{}
Then we just need to specify that the group closure surrounds the result
closure.
Example:
result {}
with {target.platform="sparc"}
group { buildSite }
with {target.platform = "*" useBuild="N12345" }
Which works well with a compound result
{ result a {} with { target.platform="sparc" }
result b {} with { target.platform="z80"
} group { buildSite } with {target.platform="*" }
This would present target.platform = "*" and useBuild="N12345" to the
closure when evaluating the group. And present target.platform="sparc"
useBuild="N12345" when calling the actor for a, and with
target.platform="z80" useBuild="N12345" when calling the actor for b.
Most commonly used would be:
result{} group{} with {}
As you most likely would want the same properties in both cases.
Regards
- henrik
|
|
| |
Re: action - group - result syntax [message #581897 is a reply to message #491451] |
Wed, 14 October 2009 17:17 |
|
On 10/14/2009 05:56 PM, Henrik Lindberg wrote:
>
> Typo - sorry
>> { result a {} with { target.platform="sparc" }
>> result b {} with { target.platform="z80"
>> } group { buildSite } with {target.platform="*" }
>>
>
> { result a {} with { target.platform="sparc" }
> result b {} with { target.platform="z80"}
> } group { buildSite } with {target.platform="*" }
>
I think one thing that confuses me with this syntax is the fact that a group is also a closure (a property scope). Let's
remove that for a second (I'll come back to that).
I like the idea that the actor produces a 'result' 'with' given input. The input being both groups and properties. So to
me, the 'result' and 'with' are tightly bound.
I think that:
action products ... {
result a{} with { group { buildSite }, property target.platform="sparc" }
result b{} with { group { buildSite }, property target.platform="z80" }
}
is much clearer than:
action products ... {
{ result a {} with { target.platform="sparc" }
result b {} with { target.platform="z80"}
} group { buildSite }
}
even if the latter is more compact. The closure for the 'buildSite' group is lost here however. What happens if we
introduce that as separate specialization? I.e.
closure a {
group { buildSite }
property target.platform="*"
}
or
closure a {
group { buildSite }
properties { target.platform="*"; ... }
}
I think that is more clear than:
group a { buildSite }
with { target.platform="*" }
Using the former syntax, we can also establish one important difference between 'closure' and 'with':
- The 'closure' propagates the properties to the 'group' that it contains.
- The 'with' just defines groups and properties that are input to the actor. The properties are *not* propagated to the
group. This means that we can express:
result a{} with { property target.platform="sparc"; closure { group { buildSite }; property target.platform="*" } };
OR, spelled out:
closure buildSiteEnvelope {
group { buildSite }
property targetPlatform="*"
}
result a{} with { property target.platform="sparc" group { buildSiteEnvelope } }
Another thought that strikes me when I read that syntax is that perhaps 'using' is a better keyword then 'with'. The
full products example could then be written as:
action buildSite ... {
result using { properties { target.platform="*"; ... } group { <whatever artifacts needed> } }
}
action products ... {
result a using { group { buildSite }; properties { target.platform="sparc"; ... }; }
result b using { group { buildSite }; properties { target.platform="z80"; ... }; }
}
OR
action buildSite ... {
result using { group { <whatever groups needed> } } // Look mum, no properties
}
action products ... {
// We overrided the target.platform for the actor invocation only. Not propagated to the buildSite group.
result a using { group { buildSite } properties { target.platform="sparc"; ... } }
result b using { group { buildSite } properties { target.platform="z80"; ... } }
}
closure buildAll {
group { products; }
properties { target.platform="*"; ... } // Here we set the default TP
}
Thoughs?
- thomas
|
|
|
Re: b3 build files DSL in XText - annotaded sample b3 file [message #581916 is a reply to message #491365] |
Wed, 14 October 2009 20:03 |
Sven Efftinge Messages: 1823 Registered: July 2009 |
Senior Member |
|
|
Hi all,
some comments inlined.
Henrik Lindberg wrote:
>> Artifacts:
>>
>> ** Standard XText implementation allows a unary ^ before a keyword as an
>> escape (Remove?)
>>
>> I'd vote yes to that. I'd prefer if we quote keywords where needed
>> (paths, requirements, etc.) and prohibits the use of keywords as names
>> in other places. Like Java.
>>
> I think so too.
Why do you want to constrain that?
It would just make your language more complicated because you need two
different versions of an identifier (an escapeable an a non-escapeable).
What kind of harm could one do with the escape character?
>
>> You have an example:
>>
>> "my.unit", "my.unit"; // unit is a keyword
>> my.^unit; // unit is keyword - standard XText grammar escape of keywords
>> in ID
>>
>> I understand why 'unit' needs to be quoted, but why do I need to quote
>> 'my.unit'? Isn't that one single token? Can I write:
>>
>> my . "unit" // (with spaces surrounding the dot)
>>
> yes, since there is a bug when letting the parser do the lexing.
> The use of hidden() in parser rules prohibits WS globbing in the lexer,
> and thus spaces in the QualifiedName will generate syntax errors.
> However, since the parser handles this instead of the lexer, it will see
> "unit" as a keyword token.
>
> Handling QualifiedName as a lexer token solves this. It however has
> other consequences as it will gobble all occurrences of ID('.' ID)*
> which makes it mask ID - there are places where a non Qualified ID is
> wanted. The check could perhaps be deferred to data type checking, but
> may cause problems. Currently there is the need to use ID (instead of
> Qualified ID) in two places:
>
> - in version which makes use of:
> AlfanumSym : (ID | INT) (Separator|ID|INT)* ;
> - in expressions where (Expression '.' ID) is a method call on
> a LHS expression.
>
> So, right now - I handle QualifiedName including WS globbing, since if I
> turn it on, things are screwed up. If I solve it in the lexer I get
> other problems.
>
> Would prefer a solution where keywords in subparts of QualifiedName are
> not recognized as keywords, provided we solve parsing of version and
> method call (subject to debate if method call should be supported).
I highly recommend to stick with parser rules here.
Are you aware of the fact that in most programming languages (Java
incl.) qualified names are parsed exactly like that?
I.e. you can write
package foo . /* fddfdf */ stuff;
but can't
package foo.bar.class;
But is this really a problem?
That said, we'll of course fix the hidden()-bug ASAP.
>
>> It's an incomprehensible
>> syntax to most people. Perhaps you can have PATH recognized by the lexer
>> and then specializations of that (REFERENCE and REQUEST for instance,
>> allowing a version and version range) also recognized? I.e. that:
>>
> As stated above, the problem is coming up with lexer rules that makes it
> possible to parse:
> - versions
> - version ranges
> - qualified names
> - unqualified names
> - ints
> - file paths
> - advice paths
>
> I think this is quite difficult. If hidden() works, then the only
> consequence is that user must string quote if a keyword token is found
> inside the element.
>
> BTW - if anyone happens to be a lexer guru, feel free to come up with a
> sequence of lex rules that handles all of the above. Free Beer offered :)
The problem with implementing all these as lexer rules is not defining
the rule, but that the lexing is completely context free. Having lots of
lexer rules, which don't shadow each other is often just impossible and
can't be solved.
For no beer in the world, unfortunately ;-)
So my advice here is again, to use parser rules and I'ld even allow
whitespace and comments inbetween if it is not ambigous.
People are usually smart enough to layout their scripts in a readable way.
If you want to guide the user you can add warnings or even errors in te
validation phase. That also allows for nicer error messages.
if you have any technical questions regarding Xtext, just use our
newsgroup.
We're looking forward to b3 :-)
Cheers,
Sven
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
|
|
|
Re: action - group - result syntax [message #581940 is a reply to message #491463] |
Wed, 14 October 2009 22:54 |
Henrik Lindberg Messages: 2509 Registered: July 2009 |
Senior Member |
|
|
On 10/14/09 7:17 PM, Thomas Hallgren wrote:
> On 10/14/2009 05:56 PM, Henrik Lindberg wrote:
>> { result a {} with { target.platform="sparc" }
>> result b {} with { target.platform="z80"}
>> } group { buildSite } with {target.platform="*" }
>>
> I think one thing that confuses me with this syntax is the fact that a
> group is also a closure (a property scope). Let's remove that for a
> second (I'll come back to that).
>
> I like the idea that the actor produces a 'result' 'with' given input.
> The input being both groups and properties. So to me, the 'result' and
> 'with' are tightly bound.
>
> I think that:
>
> action products ... {
> result a{} with { group { buildSite }, property target.platform="sparc" }
> result b{} with { group { buildSite }, property target.platform="z80" }
> }
>
I don't like that because the group is out of band wrt. the order in the
with clause. The rest of the statements, when executed, are done in the
order they are presented.
with { property a = 10; property b = a + 10; }
Makes property b have the value 20.
If you mix this with a group, which may have when() filters that
references properties, you may think that properties have the values as
computed in the sequence.
result a with {
property a = 10;
group {
derived property a = 10;
when(a == 10) x;
when(a == 20) y;
when(a == 30) z;
derived property a = a + 20;
}
property a = 20;
}
This will result in a == 20 to the actor.
What is the content of the group? x or y?
I can argue all three cases depending on the order the engine performs
the evaluations.
I also think it is wrong to place "derived properties" in the group -
they should not be derived. Derived properties should only be used in
the result. There is confusion there as well with the mixture of
statement sequence and declarative "requirements". I think we need to
revisit the decision to place properties directly in the group and
artifacts lists.
> is much clearer than:
>
> action products ... {
> { result a {} with { target.platform="sparc" }
> result b {} with { target.platform="z80"}
> } group { buildSite }
> }
>
Not really, I think it replaces one problem with another,
> even if the latter is more compact. The closure for the 'buildSite'
> group is lost here however. What happens if we introduce that as
> separate specialization? I.e.
>
> closure a {
> group { buildSite }
> property target.platform="*"
> }
>
I don't like the mix of statement sequence with group.
> closure a {
> group { buildSite }
> properties { target.platform="*"; ... }
> }
>
That is already possible by doing as follows:
group { {buildSite} with { property target.platform="*"; }}
As it is possible to set closures around selected parts in the group,
instead of just around an individual part. Wrapping all of the parts in
the group like eliminates the need for a with outside of the group. The
following two syntax examples are equivalent:
group { {} with{} ) === group { } with {}.
> Using the former syntax, we can also establish one important difference
> between 'closure' and 'with':
>
> - The 'closure' propagates the properties to the 'group' that it contains.
> - The 'with' just defines groups and properties that are input to the
> actor. The properties are *not* propagated to the group. This means that
> we can express:
>
The same concept is used throughout the syntax. Where it is possible
"with" allows setting properties, and advice that takes effect in the
closure the with clause is advising. It is always "around" something.
Why an additional concept - this just makes it more difficult to understand.
> result a{} with{ property target.platform="sparc"; closure { group {
> buildSite }; property target.platform="*" } };
>
> OR, spelled out:
>
> closure buildSiteEnvelope {
> group { buildSite }
> property targetPlatform="*"
> }
>
> result a{} with { property target.platform="sparc" group {
> buildSiteEnvelope } }
>
> Another thought that strikes me when I read that syntax is that perhaps
> 'using' is a better keyword then 'with'. The full products example could
> then be written as:
>
You are only looking at actions. The word "using" works less well
elsewhere. Maybe we should pick a different word - but lets keep the
ones we have been using until we know in what order we are going to have
the darned clauses :)
I will see if I can come up with an improvement that solves all of the
above issues:
- properties in the path group vectors
- understandable nesting of result, group and closures
- understandable order of evaluation of properties.
- henrik
|
|
|
Re: b3 build files DSL in XText - annotaded sample b3 file [message #581954 is a reply to message #491507] |
Thu, 15 October 2009 00:05 |
Henrik Lindberg Messages: 2509 Registered: July 2009 |
Senior Member |
|
|
Hi Sven,
Thanks for helping out. Much appreciated. Comments inline.
On 10/14/09 10:03 PM, Sven Efftinge wrote:
> Henrik Lindberg wrote:
>>> ** Standard XText implementation allows a unary ^ before a keyword as an
>>> escape (Remove?)
>> I think so too.
>
> Why do you want to constrain that?
> It would just make your language more complicated because you need two
> different versions of an identifier (an escapeable an a non-escapeable).
> What kind of harm could one do with the escape character?
>
We need to handle strange names anyway - names with NLS, spaces, and all
sorts of delimiters, or names that starts with digits. We opted for
quoting all non 'ID (. ID)*' names. So ^ adds a second escape mechanism
- just one more concept to explain. We are not in full control over the
naming standard as we map from other domains, hence the construct. And
to keep it simple - "if names include funny or reserved characters/words
- escape the name as a string". These names are not used as typical
variables in the language (so does not clash with expressions), but user
deals with them in many places, so it is nice to be able to write
typical names without having to handle them as strings at all times.
I also have an issue with ^keyword as I keep reading it as "raised to
the power of keyword" :)
> I highly recommend to stick with parser rules here.
> Are you aware of the fact that in most programming languages (Java
> incl.) qualified names are parsed exactly like that?
> I.e. you can write
>
> package foo . /* fddfdf */ stuff;
>
> but can't
>
> package foo.bar.class;
>
> But is this really a problem?
>
I have only found esoteric issues - I doubt anyone will ever have an
issue with those.
> That said, we'll of course fix the hidden()-bug ASAP.
>
Ah - great. That makes things so much easier since the parser rules
makes it possible to deal with "lexing in context" - I prefer that.
What I want to avoid is that someone thinks they entered a name with a
space in it. I.e entering "Program Files" as Program Files (only to get
white space sucked out of it). Better to spank them with a syntax error
- to allow them to enter either Program%20Files, "Program Files", (or
"Program%20Files"). (We will need to use the %nn notation in URLs, and
some names will be derived from URLs).
>> As stated above, the problem is coming up with lexer rules that makes
>> it possible to parse:
>> - versions
>> - version ranges
>> - qualified names
>> - unqualified names
>> - ints
>> - file paths
>> - advice paths
>>
>> I think this is quite difficult. If hidden() works, then the only
>> consequence is that user must string quote if a keyword token is found
>> inside the element.
>>
>> BTW - if anyone happens to be a lexer guru, feel free to come up with
>> a sequence of lex rules that handles all of the above. Free Beer
>> offered :)
>
> The problem with implementing all these as lexer rules is not defining
> the rule, but that the lexing is completely context free. Having lots of
> lexer rules, which don't shadow each other is often just impossible and
> can't be solved.
> For no beer in the world, unfortunately ;-)
>
If you have all the beer in the world, you won't care :)
> So my advice here is again, to use parser rules and I'ld even allow
> whitespace and comments inbetween if it is not ambigous.
> People are usually smart enough to layout their scripts in a readable way.
>
I will not even attempt to write the lexer rules, and instead use the
parser. I don't mind the embedded comments - if someone was smart enough
to figure out that it is possible and use it for some reason, they
probably know what they are doing.
> If you want to guide the user you can add warnings or even errors in te
> validation phase. That also allows for nicer error messages.
>
Yep - I got that. There are many things we need to handle there that can
not be solved by parsing alone.
> if you have any technical questions regarding Xtext, just use our
> newsgroup.
Thanks.
> We're looking forward to b3 :-)
>
I am very excited about b3 - have been able to make a lot of progress on
a very short time thanks to EMF, and XText.
Starting to ues XText was a very pleasant experience! Kudos. I wrote a
java like language 20 years ago using lex, yacc, and C++ - and I
probably produced as much in 1 week with Xtext (and got an editor with
syntax coloring at no extra effort) as I did in several months with the
lex, yacc, C++ combo. Kudos for a fantastic tool!
The only thing that causes me headache is when my grammar introduces
indirect left recursion. Precedence and associativity was easier to deal
with in yacc. Read that it is possible to make a packrat parser support
left recursion - http://www.vpri.org/pdf/tr2007002_packrat.pdf any
chance anything like that will make it into the XText packrat parser ?
Regards
- henrik
|
|
|
Re: action - group - result syntax [message #581967 is a reply to message #491542] |
Thu, 15 October 2009 02:38 |
Henrik Lindberg Messages: 2509 Registered: July 2009 |
Senior Member |
|
|
I wrote :)
> I will see if I can come up with an improvement that solves all of the
> above issues:
> - properties in the path group vectors
> - understandable nesting of result, group and closures
> - understandable order of evaluation of properties.
I started hacking at syntax... but realized that we probably are talking
past each other.
So, to reset the thinking I came up with an alternative way to describe
what it is we are trying to cover with the b3 syntax.
I think it is as follows:
DEFINE ARTIFACTS =
PATHS (p0, ... pn)
WHEN(EFFECTIVE CLOSURE EXPR == TRUE) PATHS (p0, ... pn)
WITH 'NEW' ANNOTATIONS (a0 = v0 ... an = vn) ;
DEFINE GROUP =
DEFINE PROPERTIES (p0, .. pn) IN GROUP'S CLOSURE
APPLY ADVICE (a0 .. an) IN GROUP'S CLOSURE
COLLECT 'PARTS AND ANNOTATIONS' (p0, p1, .. pa)
WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
ASSERT THESE ANNOTATIONS HAVE VALUE (a0 .. an)
POP THE GROUP'S CLOSURE
RETURN 'COLLECTED PARTS AND RESULTING ANNOTATIONS'
;
DEFINE ACTION =
DEFINE PROPERTIES (p0, .. pn) IN ACTION'S CLOSURE
APPLY ADVICE (a0 .. an) IN ACTION'S CLOSURE
CALL ACTOR (A) // initialized earlier
WITH THE FOLLOWING INPUT:
COLLECTED 'PARTS AND ANNOTATIONS' (p0, .. pn)
WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
ASSERT ANNOTATIONS HAVE A VALUE (a0 .. an)
'CONVERT ANNOTATIONS TO PROPERTIES' IN ACTION'S CLOSURE
DEFINE PART x =
PATHS(xp0, ... xpn)
WHEN(EFFECTIVE CLOSURE EXPR == TRUE) PATHS (p0, ... pn)
"COLLECT" ANNOTATIONS FROM THE ACTOR
WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
ASSERT ANNOTATIONS HAVE VALUE (a0 .. an)
COLLECT ALL PARTS AND ANNOTATIONS DEFINED IN THE ACTION
POP THE ACTION'S CLOSURE
RETURN 'COLLECTED PARTS AND ANNOTATIONS DEFINED IN THE ACTION'
;
I left out compound variants to make sure we have the basic steps
described first. (I deliberately left out when() in the description of
collecting parts and annotations, but that should be possible).
I hope my pseudo syntax is understandable, and that it is clear how I
think the various concepts interact.
- henrik
|
|
|
Re: action - group - result syntax [message #581991 is a reply to message #491559] |
Thu, 15 October 2009 07:59 |
|
Hi Henrik,
Yes this makes sense to me. One thing that I've been thinking about is if we don't need defaults for parts as well, i.e.
WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
becomes
WITH DEFAULT 'PARTS AND ANNOTATIONS' (a0 = v0 ... an = vn)
to cover cases like "This actor might optionally produce a configuration file. If it doesn't, this is the default".
Another thing I've been thinking about is asserts. I think that we need them on the artifacts as well. Perhaps a bit
esoteric but it could be used in cases where you want to make sure that at least 1 of 2 files is present in a folder.
I see that you place the assert before you pop the closure. Why is that? Shouldn't the assert execute as the absolute
last thing to avoid side-effects from the closure?
- thomas
On 10/15/2009 04:38 AM, Henrik Lindberg wrote:
> I wrote :)
>> I will see if I can come up with an improvement that solves all of the
>> above issues:
>> - properties in the path group vectors
>> - understandable nesting of result, group and closures
>> - understandable order of evaluation of properties.
>
> I started hacking at syntax... but realized that we probably are talking
> past each other.
>
> So, to reset the thinking I came up with an alternative way to describe
> what it is we are trying to cover with the b3 syntax.
>
> I think it is as follows:
>
> DEFINE ARTIFACTS =
> PATHS (p0, ... pn)
> WHEN(EFFECTIVE CLOSURE EXPR == TRUE) PATHS (p0, ... pn)
> WITH 'NEW' ANNOTATIONS (a0 = v0 ... an = vn) ;
>
> DEFINE GROUP =
> DEFINE PROPERTIES (p0, .. pn) IN GROUP'S CLOSURE
> APPLY ADVICE (a0 .. an) IN GROUP'S CLOSURE
> COLLECT 'PARTS AND ANNOTATIONS' (p0, p1, .. pa)
> WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
> ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
> ASSERT THESE ANNOTATIONS HAVE VALUE (a0 .. an)
> POP THE GROUP'S CLOSURE
> RETURN 'COLLECTED PARTS AND RESULTING ANNOTATIONS'
> ;
>
> DEFINE ACTION =
>
> DEFINE PROPERTIES (p0, .. pn) IN ACTION'S CLOSURE
> APPLY ADVICE (a0 .. an) IN ACTION'S CLOSURE
>
> CALL ACTOR (A) // initialized earlier
> WITH THE FOLLOWING INPUT:
> COLLECTED 'PARTS AND ANNOTATIONS' (p0, .. pn)
> WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
> ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
> ASSERT ANNOTATIONS HAVE A VALUE (a0 .. an)
> 'CONVERT ANNOTATIONS TO PROPERTIES' IN ACTION'S CLOSURE
>
> DEFINE PART x =
> PATHS(xp0, ... xpn)
> WHEN(EFFECTIVE CLOSURE EXPR == TRUE) PATHS (p0, ... pn)
> "COLLECT" ANNOTATIONS FROM THE ACTOR
> WITH DEFAULT ANNOTATIONS (a0 = v0 ... an = vn)
> ADD 'NEW NON COLLECTED' ANNOTATIONS (a0 = v0 ... an = vn)
> ASSERT ANNOTATIONS HAVE VALUE (a0 .. an)
>
>
> COLLECT ALL PARTS AND ANNOTATIONS DEFINED IN THE ACTION
> POP THE ACTION'S CLOSURE
> RETURN 'COLLECTED PARTS AND ANNOTATIONS DEFINED IN THE ACTION'
> ;
>
> I left out compound variants to make sure we have the basic steps
> described first. (I deliberately left out when() in the description of
> collecting parts and annotations, but that should be possible).
>
> I hope my pseudo syntax is understandable, and that it is clear how I
> think the various concepts interact.
>
> - henrik
|
|
|
Re: b3 build files DSL in XText - annotaded sample b3 file [message #582013 is a reply to message #491550] |
Thu, 15 October 2009 08:27 |
|
On 10/15/2009 02:05 AM, Henrik Lindberg wrote:
> I also have an issue with ^keyword as I keep reading it as "raised to
> the power of keyword" :)
>
x=a^b; // Binary op: x equals a XOR b
>> I highly recommend to stick with parser rules here.
>> Are you aware of the fact that in most programming languages (Java
>> incl.) qualified names are parsed exactly like that?
>> I.e. you can write
>>
>> package foo . /* fddfdf */ stuff;
>>
>> but can't
>>
>> package foo.bar.class;
>>
>> But is this really a problem?
>>
> I have only found esoteric issues - I doubt anyone will ever have an
> issue with those.
>
One less esoteric issue is that the path:
/ a/ b/
silently becomes:
/a/b/
The desired behavior is a syntax error, making the user aware that he must write:
/%20a/%20b/
Regards,
Thomas Hallgren
|
|
| |
Re: b3 build files DSL in XText - annotaded sample b3 file [message #582052 is a reply to message #491550] |
Fri, 16 October 2009 09:04 |
Sven Efftinge Messages: 1823 Registered: July 2009 |
Senior Member |
|
|
Hi
Henrik Lindberg wrote:
>
> I also have an issue with ^keyword as I keep reading it as "raised to
> the power of keyword" :)
The '^' is just a default.
See the ID rule in TerminalRules. Just override it and remove or change
the escape character.
>> I have only found esoteric issues - I doubt anyone will ever have an
>> issue with those.
>>
> One less esoteric issue is that the path:
>
> / a/ b/
>
> silently becomes:
>
> /a/b/
>
> The desired behavior is a syntax error, making the user aware that he
> must write:
>
Agreed.
>
> What I want to avoid is that someone thinks they entered a name with a
> space in it. I.e entering "Program Files" as Program Files (only to get
> white space sucked out of it). Better to spank them with a syntax error
> - to allow them to enter either Program%20Files, "Program Files", (or
> "Program%20Files"). (We will need to use the %nn notation in URLs, and
> some names will be derived from URLs).
For the time beeing (as long as the hidden() bug exists) you could
raise an error using the validation hook, when there's whitespace.
You get access to the underlying text of an EMF model by obtaining the
attached node model.
org.eclipse.xtext.parsetree.NodeUtil.getNodeAdapter(EObject)
> I will not even attempt to write the lexer rules, and instead use the
> parser. I don't mind the embedded comments - if someone was smart enough
> to figure out that it is possible and use it for some reason, they
> probably know what they are doing.
Exactly. Frameworks and languages shouldn't constrain users but guide them.
If they want to shoot their own foot, let them do it.
But we need to avoid any suggestions in that direction :-)
>
>> We're looking forward to b3 :-)
>>
> I am very excited about b3 - have been able to make a lot of progress on
> a very short time thanks to EMF, and XText.
>
> Starting to ues XText was a very pleasant experience! Kudos. I wrote a
> java like language 20 years ago using lex, yacc, and C++ - and I
> probably produced as much in 1 week with Xtext (and got an editor with
> syntax coloring at no extra effort) as I did in several months with the
> lex, yacc, C++ combo. Kudos for a fantastic tool!
Very nice words. Thank you very much.
>
> The only thing that causes me headache is when my grammar introduces
> indirect left recursion. Precedence and associativity was easier to deal
> with in yacc. Read that it is possible to make a packrat parser support
> left recursion - http://www.vpri.org/pdf/tr2007002_packrat.pdf any
> chance anything like that will make it into the XText packrat parser ?
Actually, Antlr is a very nice and sophisticated parser generator. We
don't want to reinvent the wheel here. The packrat parser was mainly
developed in order to solve some IP-problems. And we don't have plans to
improve it much in future.
Cheers,
Sven
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
|
|
|
Goto Forum:
Current Time: Fri Apr 19 20:10:24 GMT 2024
Powered by FUDForum. Page generated in 0.07509 seconds
|