Language Specification

From Furcas Wiki

Jump to: navigation, search

This page serves as very rudimentary language specification for the TCS language as implemented by FURCAS.



Contents

Basic Language Features

Textual syntaxes are specified in files of the following form. The different sections will be described throughout the remainder of this language specifications. For a complete example see the Getting Started Tutorial.

syntax MyLanguage {

  -- place templates here (at least one main template)

  -- place keywords here (optional, seldom used)

  -- place symbols here (optional)

  -- place operatorLists here (optional)

  -- place tokens here (optional, except for COMMENT)

    token COMMENT	: endOfLine(start = "--");

  -- place lexer here (optional)

}
  


PrimitiveTemplates

PrimitiveTemplates describe how primitive data types are going to be used. Primitive types are types such as EString, EInt, EIntegerObject or any other (even self-defined) EDataTypes.

Examples:

primitiveTemplate integerSymbol for ecore::EInt default using INT
  :  value = "Integer.valueOf(%token%)"
  ;
  
primitiveTemplate floatSymbol for ecore::EDouble default using FLOAT
  :  value = "Double.valueOf(%token%)"
  ;
  


PrimitiveTemplates consist of a name (e.g., identifier, integerSymbol), the datatype (e.g., EDouble) and the token type that this primitiveTemplate is associated to. The default lexer provides the token types NAME, STRING, INT and FLOAT.

For each DataType used by the metamodel, there must be exactly one default primitive template, denoted by the default keyword. This is required, as in some cases one has to define more than one PrimitiveTemplate for a single datatype. A common example are strings, which can be used to hold identifiers (simple names, no spaces) but may also be contain quoted char sequences including spaces.

-- e.g. MyJavaClass
primitiveTemplate identifier for ecore::EString using NAME
  :  value = "%token%"
  ;

-- e.g. "That is a string"
primitiveTemplate stringSymbol for ecore::EString default using STRING
  :  value = "unescapeString(%token%)",
     serializer="\"%value%\"";
  ;
  

To use alternative PrimitiveTemplates one can specify to use them using the as property argument.

template SomeType
  : -- will use the stringSymbol template
    someStringField

    -- will use the identifier template
    someStringField{as=identifier}
  ;


There are two different possibilties to map boolean types:

-- explicit primitive template
primitiveTemplate boolean for ecore::EBoolean default using INT:
  value = "Boolean.valueOf(%token%)";

-- alternative, usage local declaration 
template SomeType
  : (someBooleanField ? "true" : "false")
  ;
  

ClassTemplates

For each classifier in your metamodel, you may define (atleast) one ClassTemplate. The ClassTemplate defines how the class will be represented as text.

You can refer to attributes and references of the metaclass by their name. Their appearance in the syntax is defined by the other templates:

  • If the attribute has a primitive type, then a suitable PrimitiveTemplate will be used.
  • If it is a normal model element, then the ClassTemplate associated to the type of the model element will be used.

Here are examples with simple attributes.

template Person
  : "Person" "=" firstname lastname "."
  ;
  
template Year
  : "year" "=" value
  ;
  


Exactly one ClassTemplate must be declared as main template. A main template serves as root element for the textual syntax.

template Person main
  : "Person" "=" firstname lastname "."
  ;
  


ClassTemplate Options

Option: Multi Main Template

In some cases, one may wish to declare for the main element of a syntax to be present in the syntax more than once. For example, the main template could be Person, but one may wish to allow declaring more than one Person in a DSL. In that case, it is possible to add the "multi" keyword to the main template:

template Person multi main ...
  

Mind that this is only required for the main template.

Option: Abstract Template

If the metamodel contains abstract model elements and a concrete subclass shall be decorated with text, is is required to specify all levels of the inheritance hierarchy.

template Person abstract;

-- if MalePerson does extend Person in metamodel
template MalePerson
  : "Mr." lastname
  ;
  

However, it is also possible to use the abstract keyword for non abstract model elements. (This is probably for historic reasons, and the "abstract" keyword should maybe be replaced with something less confusing for such cases). For any non-abstract model element having subclasses, it may be necessary in the syntax to allow for both the superclass or a subclass to appear in a given text. This is achieved by using the abstract keyword in the ClassTemplate of the superclass along with a template body like with non-abstract classes.

template MalePerson abstract
  :  "Mr." lastname
  ;

-- if GoodMaleFrienddoes extend MalePerson in metamodel
template GoodMaleFriend
  : "Dear" "Mr." lastname
  ;
  

Option: Moded Template

If there is need to have separate templates for a model element depending on some context, it is possible to use the mode concept. This requires for a template to be marked with a mode, and to be invoked using the mode. The mode for a template is expressed with a '#' symbol, and invocation happens using the mode keyword.

template Person #male 
  :  "Dear" "Mr." name ","
  ;

template Person #female
  : "Dear" "Ms." name ","
  ;

template Letter 
  :  (male ? person{mode=male} : person{mode=female}) name;
  ;
  


Option: Qualified Meta-References

The decorated classifier can be referenced using full qualified name, using the package names as prefixes. If the unqualified name is unique in the metamodel, it is possible to omit the packages. Instead of using the package it is also possible to directly reference the namespace URI of a package, as show below.

-- unqualified class name
template Year
  : "year" "=" value
  ;

-- qualified class name
template Package::SubPackage::Year
  :  "year" "=" value
  ;

-- qualified class name using the package URI
template "http://www.example.com/myPackage"#Year
  :  "year" "=" value
  ;
  

Option: ReferenceOnly Template

In some DSLs, you may need to refer to existing model elements outside the context of the DSL artifact. As an example, considering the FURCAS language as a DSL itself, in any FURCAS Syntax Definition you refer to metamodel elements and their packages in

template MyPackage::MyClassifier
  : ...
  ;
  

In this case the intention is to first refer to a package with the name "MyPackage" without any parent package (as opposed to SomeOtherPackage::MyPackage), and then to a classifier within that package with the name "MyClassifier" (as opposed to SomeOtherPackage::MyClassifier).

In the syntax definition for FURCAS itself, this is solved using the referenceOnly keyword.

template Model::Classifier referenceOnly
	: ( isDefined(container) 
          ? container "::" name -- only prefix with container if defined
          : name)
	;
  

"referenceOnly" indicates that this template merely serves to define a complex syntax for a multivalued reference, and should never lead to the creation of a model element of type Model::Classifier.

This is roughly similar to having primary keys on a table in a relational database which spans multiple attributes, and one wishes to make a foreign key on that table. In a DSL Syntax, you'd have to specify all the relevant key attributes to resolve a reference, rather than merely one. If however you can reference model elements in your DSL using a signle and unique properties, you should do so using the #referenceBy property argument.

Option: Context

ClassTemplates may define a context. A context is then basically a label for an element decorated by such a template. Contexts can be used in conjuction with #referenceBy and #ocl property inits to refer to elements that have been created within the parse run, but which are not directly connected within the metamodel.

Contexts can be nested, according to the lexical structure, forming a context stack. As an example, for a syntax for a Java class, the class could be a context object, and each method could be a sub-context. This forms a tree, but in the context of a parse process, the parser will be in one node of the tree at any given point in time, and the ancestors then would be the context stack. The lookup for a context element starts in the inner most context and, if not found, in the containing contexts transitively.


Optionally contexts can be tagged. ClassTemplates defining context elements can give these elements a number of tags, to be referenced by these tags from deeper down the context hierarchy. As said before, the contexts define a tree structure on a document, where contexts are being created for all elements being declared with the context keyword. By default, during the parsing process there is only one current context, and that one is sufficient for most usages of contexts. However in some cases contexts higher up in the context hierarchy (=earlier in the context Stack) may be required for reference lookups when setting properties, meaning in lookIn or the createIn PropertyArguments.

As an example, consider Java classes again and this time the class, any method, and any method body could be defined as contexts.

The context tree at the end of parsing could then look like this

 context(Class:Foo) 
     context (Method:bar1) 
         context (methodBody)
     context (Method:bar2) 
         context (methodBody) 

Every node in this tree is a context, and has a context element (in brackets). The context stack for any declaration is the context it was parsed in and all the ancestor contexts. So within method body of Foo.bar2(Type value3) {...here...} the context stack is the [Class, Method, MethodBody], where the current context would be MethodBody. Now if for elements within the method body we need to syntactically refer to elements to which we can best navigate starting from the method context (not the current context), we need to use tagged contexts. This mean we need not only to make method a context element adding "context" to the template, we need to give it a tag to refer to this level of context, such as delcaring it with

template Method context(methodLevel):...;

The syntax in FURCAS is:

template Something context(tag1, tag2) :
    ...
    ;
template OtherThing :
  {{ someFeature = 'OCL:#context(tag1).prop1.prop2' }}
;
  

Only non-abstract ClassTemplates can be defined as context.

Conditionals

Sometimes you may wish for certain elements to appear in the syntax depending on a condition:

With boolean attributes of a model element, the following is possible:

template Person
:  (isProfessor ? "Prof") firstname lastname
;
  

You may also make a comparison, and specify "else" parts

template Person
:  (gender="male" ? "Mr" : "Ms") firstname lastname
;
  

Or for optional attributes you may use the isDefined() function:

template Person
:  (isDefined(title) ? title) firstname lastname
;
  

If you want to refer to an enumeration literal you need to preceed the value with a "#". Example for enumeration Status(#married, #single):

template Person
:  (status=#married ? "married" : "single") firstname lastname
;
  

A special conditional is the instanceOf conditional. It can be used when you want to constrain the classes that are allowed as the type of a property. In the example below this means that two different alternatives are tried to be matched during parsing depending on the type of job that is specified in the concrete syntax.

Metamodel: Person references Job NotUnemployed extends Job Unemployed extends Job Programmer extends Job

template Person
:  (job instanceOf NotUnemployed ? job : job{mode=unemployed})
;
  

Alternatives

If your syntax allows alternatives, this is denoted by [[ alternative1 | alternative2 | alternative3 ]]. Note the difference to EBNF, where the double brackets "[[" and "]]" would not be required. An alternative can contain anything that can be placed directly within a ClassTemplates. This also implies that alternatives can be nested.

If you want to allow the syntax to accept intermingled elements for multi valued properties you can use the * at the end of the alternatives to denote that. Note that this construct is only possible if the properties referenced in the alternatives have an upper bound of UNBOUNDED.

template AlternatingProperties :
"Alternating elements:"
[[ altA | altB ]]* ;

template AltA : "a" ;
template AltA : "b" ;

This will allow to write something like:

Alternating elements: a b a a b b

If the multi-valued properties have a lower multiplicity of 0 it is recommended to add {forcedLower=1} to the feature, as in

template AlternatingProperties :
"Alternating elements:"
[[ altA{forcedLower=1} | altB{forcedLower=1} ]]* ;

template AltA : "a" ;
template AltA : "b" ;

Otherwise, the empty string could be matched by each alternative. Repeating this by the appended "*" can lead to undesirable effects in the grammar and subsequently in the parser.

Properties

Properties are attributes or references of a model element to be represented in a syntax. Properties are referenced by merely using them by their name within a template body. The serialization of properties can be configures using so-called property arguments. Property arguments are written in curly brackets directly after a property.

template MyClassifier
  :  property {one, or, more, property, arguments}
  ;
  


The following table show the existing property arguments, and in what combinations they may be used.

Property Argument Syntax
Property Argument Allowed Values Examples
separator separator sequence to be used between separate values separator = "," / separator = "::"
as ID of (non-default) primitive template as=stringSymbol / as=currencyDouble
mode mode ID were moded template exists mode='myMode'
referenceBy OCL query returning the name of the element bound to this property referenceBy="name" / referenceBy="OCL: self.calucalteName()."
lookupScope OCL query returning all potential candidates to be bound to this property lookupScope = 'OCL: self.parent.decalarations' / lookupScope = 'OCL: Decalarations.allInstances()'


Property Argument Combinations allowed
Condition Allowed combinations
Propertie with primitive type as
Propertie with non-primitive type mode
Multi-value property separator, forcedLower, forcedUpper (all combinations allowed)
Single-value property referenceBy, lookupScope, as (optional)

The other properties arguments are explained in the following.

Argument: Multivalued Properties

For multi valued properties, you may specify a separator sequence, and a forced minimum (if higher than metamodel minimum). A separator sequence is very much like a template body, and thus allows all the elements as well, though typically a "," would be used.

template Article
  :  "article" "{"
       attributes{separator = ","}
     "}"
  ;
  
template SoccerTeam
  :  "{" teamMates {forcedLower = 11, separator = ","}
     "}"
  ;
  

Argument: Specialized Template Calls

For primitive dataTypes it is possible to define more than one PrimitveTemplate defining different formats in which the same datatype may be represented in the DSL in different places. To use a specific non-default primitiveTemplate for a primitive property, "{as=primitiveTemplateName}" may be used.

Somewhat similar, there may be cases where specialized ClassTemplates exist, these are called moded ClassTemplates. To ensure a Property of a non-primitive type is textually represented using a special moded ClassTemplate, the mode can be specified using {mode=modeName}. If a specialized Template (e.g., Template for a subclass) should be called it is also possible to directly specify this in the "as" clause. To be able to resolve nameconflicts it is possible to use the fully qualified name of the class template here: "{as=myPackage::MyClass}".


Argument: Reference Model Elements by Name

Model elements may reference each other by a name or another unique identifier. For example, given a language with method declarations, methods will be referenced by call-sites using the method name. At the call-site, the key for the lookup of the refenced method is provided in the text in form of a primitive feature (commonly an identifier).

This is demonstrated in the following: Metamodel: [Metaclass Declaration] <- boundDeclaration ------ [Metaclass Usage]

template Usage
  : "use" boundDeclaration {
          referenceBy="name", 
          lookupScope="OCL:self.getNamedDecarationsInScope()"} ";" 
  ;

template Declaration
  :  "declare" name ";"
  ;
  

It would now be possible to write the following. Mind that only the name of the declaration shows up in the usage and not the whole template content (including "declare"...)

  declare MyDeclaration
  declare MyOtherDeclaration
  ....
  use MyDeclaration -- binds to the first declaration
  use UnknownDeclaration -- property "boundDeclaration" remains unbound as there is no such declaration    
  

The idea is that the lookupScope OCL query yields a list of potential candiates that might be bound to the property at hand. ReferenceBy, an OCL expression on its own, is used calculate a name for all candidates in the lookup scope. These names are then compared to the text that shall be used for referencing the elment (e.g. UnknownDeclaration). The element within the lookupScope that has exactly this name is then set as value for the property. The referenceBy query has to return a primitive type.

Within the lookupScopeit is furthermore possible to use a "#context" (with or without tag, see Option: Context) statement instead of "self" within a query. Notice that this is only one of both (self or #context) can be used and not both at the same time. When using #context within an OCL expression you need to specify the type of the #context by adding an .oclAsType(<TYPE>) after the #context expression.

Sometimes model elements are not supposed to be referenced by their real name, as used within the metmodel, but by a slightly different one. All this logic can be encoded into the referenceBy OCL expression. However, as it is a somewhat common case that the name in the metamodel has a fixed prefix or postfix that shall not be represented within the text, FURCAS supports the following:

template Usage:
  : "use" boundDeclaration {
          referenceBy="name",
          prefix = "__",  postfix = "__",
          lookupScope="OCL:self.getNamedDecarationsInScope()"} ";" 
  ;
  

This would allow to find a declaration named __X__ simply by using X.

An alternative way to achieve a reference using complex mechanisms is to use the referenceOnly keyword in a ClassTemplate, allowing ClassTemplates to resolve references from text in complex ways.

Argument: Partial Property References

Propertiy references can contain the "partial" property argument.

This will cause the pretty-printer to ignore PropertyInit- and ForcedUpper/ForcedLower- mismatches of the model and syntax and print nothing for these elements instead of aborting the whole serialization. For collection-properties this will apply per element, meaning that one unprintable element will not cause the whole property to fail. Printable elements will just be printed as normal, un-printable ones will output nothing.

Example:

  template Library :
    books{partial}
  ;

  template Book :
    name {{printThis='true'}}
  ;

If a Library is going to be pretty-printed, but some books' printThis property was changed to false, those books will be omitted from the print. Note that, if the model was generated again from the output, those books would then be missing.

However, a situation may arise in which one model element is created through different path's in the syntax and even though they belong to the same collection should be printed in different places. If the propertyInits of one path cause the model element created though the other path to fail and vice versa, a partial property can be used to solve this instead of having to use a query filtering out the actual elements of the collection to be printed.

Property Inits

Within a template sequence, it may be desirable to perform certain actions on the ModelElement to be created. PropertyInits are declarations to initialize features of ModelElements which have no representation in the syntax, similar to default values. Currently 3 kinds of PropertyInits are supported: initialization using primitives, initialization using OCL queries and the foreach construct.

Primitive Property Inits

Primitives use Java types to assign values to properties, it is up to the language designer to ensure they fit. For Strings, double quotes within single quotes are therefore required.

template Wife
: "Mrs." name {{gender='"female"', isAdult=true, isMarried=true}}
;
  

It is also possible to use look ups similar to the notation of the lookIn and createIn porperty arguments.

template Something
: {{property = lookIn('#context.property')}}
;
  

The same path notation as for lookIn is possible, meaning steps are separated by dots and steps are feature names of modelElements, the default starting point is the current ModelElement, but alternatively the current context may be used as starting point using #context or a tagged context using #context(tagname).

OCL Property Inits

For more complex queries it is furthermore possible to write an OCL query within the lookIn() statement. This can for example be useful if you want to do filtering on the result. An OCL query is specified by prefixing the lookIn argument with 'OCL:'. The '#context' element within the query will then be substituted with the corresponding element it refers to through the #context expression.

Important: When using #context within an OCL expression you need to specify the type of the #context by adding an .oclAsType(<TYPE>) after the #context expression.

template Something
: {{property = lookIn('OCL:#context.oclAsType(MyType).multiProperty->select(elem | elem.speecialProperty = true)')}}
;
  

Predicate Property Inits

At the moment there is only one Predicate available: foreach

Use-cases for foreach

template Something
: {{propery = foreach("OCL:arbitrary OCL query", mode=mymode,
                when="boolean OCL query", mode=mylocalmode, as=template)}}
;

It can take several options, some of them are optional.

  • OCL query: This query secifies the model elements on which the predicate is evaluated. Possible OCL queries are the same as described in "PropertyInits with OCL Queries" above. The results could be several types.
    • RefObject: These are Model elements. They are used as base template, meaning that a model element of the same type will be produced. If the OCL expressions returns more than one object, the evaluation will be done for every element.
    • Boolean: This is a decision predicate. You have to specify the template in at least one as parameter. It will only be called if the boolean value is true.
    • Other base types (Number, String): You have to specify the template in at least one as parameter. This rule will always be called.
  • mode (optional): This is a "global" mode argument. It is only used if you don't specify a mode in the when/as parameters.

For each of the elements computed by the OCL expression, at most one template is executed to produce an element according to the following rules:

  • when/mode/as: This could be a list of arbitrary length of the three parameters. The when and mode elements are optional. If a when clause is provided and evaluates to true or the when clause is omitted, an element is created using the template specified by as/mode. Only the first template matched by this rule will be executed.
  • if no when clause matches and no as clause without a when clause has been specified, an element is constructed using the template corresponding with the type of the current element from the initial OCL query, optionally with the global mode, if specified.

Note, that when providing an as clause without a when, no when clauses following this as occurrence are considered because the as without when will always be used.

Furthermore note, that it may be necessary to fully qualify the argument of the as clause to reference a template by its full name. E.g., as = myPackage::MyClass.

If the template in which the foreach property init occurs defines a context, each element produced by the foreach OCL query will be assigned to a new child context which can be accessed inside the templates invoked by the foreach construct.

Caveat: The context created for the elements matched by the foreach OCL expression in case the template holding the foreach clause defines a context will overwrite any context that may exist for that particular element. This can lead to unpredictable results in case that context was used to store elements in it using addToContext clauses in subordinate templates. It is highly recommended not to use such a combination.

This is a very flexible predicate with many possible usages. The following TCS code snippet is taken from the ForeachPredicatePropertyInit testcase, which can be found in package com.sap.furcas.parsergenerator.tcs.featuretests:

template Author context addToContext
  : 
    "author" "=" name "."
    {{ revenues=foreach("OCL:self.articles", as=RevenueLedger) }}
  ;

template RevenueLedger
  : 
    {{ article=lookIn("OCL:#foreach(BibText::Article)"),
    revenueInEUR=lookIn("OCL:#foreach(BibText::Article).author.name.size()") }}
  ;

The revenues feature is defined using the foreach predicate. Thus, for each article an author has written a new RevenueLedger model element is created and added to revenues feature. As can be seen in the RevenueLedger template, each time the template is executed, the feature definition of revenueInEUR and article are evaluated. #foreach is used inside an OCL expression to refer to the element currently processed by the foreach-loop. Therefore, the expression OCL:#foreach(BibText::Article) is used to refer to the article that is currently processed by the foreach-loop. Thus article is set to the currently processed article, while the OCL expression OCL:#foreach(BibText::Article).author.name.size() sets revenueInEUR to the lenght of the name of the person, who is the author of the currently processed article.

Restrictions

A few limitations currently apply for the use of the #foreach reference to the current value processed by the template "invoked" by the foreach construct. The #foreach reference may only be used in the template immediately invoked by the foreach clause, not in a function template transitively invoked, and not in a subtemplate that is invoked by the template that is immediately invoked by the foreach clause.

Furthermore, the #foreach reference should not be combined with semantic predicates because FURCAS currently doesn't record for a semantic predicate which alternative was executed. Hence, FURCAS cannot determine whether or not the property initialization using the #foreach reference was actually executed before.

Default-only vs Mandadory Property Inits

PropertyInits can either be mandatory, using the
=
sign, or default-only, using the
<-
sign. The effect is that the pretty printer will ignore the default only PropertyInits when deriving a syntax from an existing model.

When the PropertyInit is mandatory, is is evaluated while traversing the mapping definition and that path through the mapping is discarded, if the query does not match. This can be used to link an alternative to the state of the model. If no valid path is found, a SyntaxAndModelMismatchException is thrown by the PrettyPrinter.

Example default-only:

template Person
  : {{ age <- '22' }} name
;

Example mandatory:

template Person
  : [[ "Lord" name
       {{ aristocratic = 'true' }} 
    |
       "Mr" name
       {{ aristocratic = 'false' }}
    ]]
;

FunctionTemplate

If you have a metaclass with many subclasses, chances are that for all subclasses, there will be common syntax elements. In order to reduce the copy and paste effort to redundantly specify this in all ClassTemplates, you may use a FuntionTemplate instead. Within the body of a FunctionTemplate, you may use the same constructs as in a ClassTemplate, and the properties of the superclass.

Example:

template MalePerson -- does extend Person in metamodel
  : Mr $names
  ;

template femalePerson -- does extend Person in metamodel
  : Ms $names
  ;

function names(Person)
  : firstname lastname
  ;
  

OperatorTemplate

Operator templates are required whenever a language needs to provide left-recursion.

These concepts are required together:

  • an abstract operatored ClassTemplate
  • an OperatorTemplate referencing a subclass of the referenced operatored Classtemplate
  • At least one ClassTemplate referencing another subclass of the referenced operatored Classtemplate
  • an OperatorList of unary (prefix or postfix) or binary operators

For binary operators, this structure usually matches the following metamodel structure:

  • an abstract classifier A
  • a non-abtract classifier B subtype of A (as non-atomic expression) having 2 features (one for the left side of the operator, one for the right side.)
  • another non-abtract classifier C subtype of A (as atomic expression without operator, such as variable or value in an arithmetic expression)

For operatored templates using several symbols (+, -, *, /) the classifier B usually also has a String feature to store the operator used in the model.

Note that contrary to the usual class template requirements it is not permitted to provide abstract templates for classes that inherit from the abstract operatored class and from which the operatorTemplate-referenced classes inherit (the "in-between" classes). If you violate this rule, empty production rules may result in the grammar, causing confusion and grammar errors.

Operator templates will also always use lexer rules LPAREN and RPAREN for parentheses, these are included in the default lexer, and should be kept in custom lexers.

It is a limitation and known issue of FURCAS that left recursion can only be implemented through the operator templates (even when it is not intuitive), and that this always involves optional round parentheses notation.

OperatorLists

OperatorLists define and categorize several operators with symbols into priorities, and specify their arity (1 or 2) and Associativity. OperatorLists may have a name. It is possible to have one anonymous OperatorList per Syntax, but that is bad practice.

Example:

symbols {
  lt = "<";
  gt = ">";
}

operators Sample{
  priority 0 {
    opGt = gt, 2;
    opLt = lt, 2;
    opEq = "=", 2;
    opDec = "var", 1;
  }
}
  

The example shows the declaration of 2 symbols, and 4 operators. 2 of the operators reuse the given symbols, two operators define new symbols. 3 operators have arity of 2, meaning the operator will connect 2 elements, while one operator has an arity of one, meaning it will prefix some single element.

Different priorities help building up the syntax tree in ambigous situations such as 1 + 3 * 4, where the precedence of the operators "+" and "*" must be specified. The following example defines priorities as in arithmetics.

Arithmetic example:

operators Arithmethic {
  priority 0 {	
    opMinus1 = "-", 1;
  }

  priority 1 {
    opStar = "*", 2;
    opSlash = "/", 2;
  }
  
  priority 3 {
    opPlus = "+", 2;
    opMinus2 = "-", 2;
  }
  
  priority 4 {
    opEq = "=", 2;
    opGt = ">", 2;
    opLt = "<", 2;
    opGe = ">=", 2;
    opLe = "<=", 2;
    opNe = "!=", 2;
  }
}
  

Note how the unary minus for negative numbers takes precedence over the common binary minus operation.

TODO: Associativity, postfix

Operatored ClassTemplates

Any abstract ClassTemplate can be made operatored using the operatored keyword.

template Expression abstract operatored(MyOperatorList)
:...
;
  

In the resulting ANTLR grammar, this will create a series of rules for each of the priorities defined in the given OperatorList. Within each of these priorities, there are a number of operators, and for each of these operators, operatorTemplates must exist.

  • One operatored ClassTemplate refers to one OperatorList
  • One OperatorList has n Operators
  • One Operator has n OperatorTemplates

BUT: In reasonably simple or complex examples, one operator will only be used in one operatorTemplate, and all operators in one OperatorList will be used by the same operatorTemplate, so that usually one operatored ClassTemplate will only relate to one OperatorTemplate.

TODO explain relationship to operatorTemplates

Operator Templates

OperatorTemplates are defined for metamodel elements occuring in the syntax with operators in left recursive ways. The metamodel element for which to create an operator template must have features for storing the arguments of the operator. These are called 'source' and 'storeRightTo' in the FURCAS syntax, 'source' being the sole argument for unary operators as well as the left side for binary operators. 'storeRightTo' obviously only applies to binary operators.

It is necessary to list the intended operator symbols in the template after operators=, separated by spaces. Operators are defined in operator lists where they are categorized according to priority.

The operatorTemplate then is minimally defined for a unary operator as:

operatorTemplate MinusExp(operators = opMinus, source = 'value');

operators {
  priority 0 {
    opMinus = "-", 1;
  }
}
  

The Classifier MinusExp in the metamodel would need a feature "value" in this case. As mentioned above, operatored templates always support parenthesizing, such that the above would parse -(-(-(-5))).

For a binary operator, the default looks like this

operatorTemplate PlusExp(operators = opPlus, source = 'leftside', storeRightTo = 'rightside');

operators {
  priority 0 {
    opPlus = "+", 2;
  }
}
  

Note the classifier in the metamodel for this template would in this case require features "leftside" and "rightside", to store the expressions parsed.

For an expression like "3+4", the parser would first parse "3" as ModelElement A, then create a ModelElement B of type "PlusExp", set feature "leftside" of B to A, parse "4" as modelElement C, and then set feature "rightside" of B to C. The result is one modelElement B{type="PlusExp", leftside="3", rightside="4"} (Pseudo Model notation)


As an alternative, the above can also be written as:

operatorTemplate PlusExp(operators = opPlus, source = 'leftside'):
    rightside
;
  

the sequence between ":" and ";" is what the parser will expect after the operator.


Operator Templates can additionally have a sequence to be present on the right side after the operator.

operatorTemplate MinusExp(operators = opMinus, source = 'value')
  :
    "[" value "]"
  ;
  

This would enforce hard brackets after the operator symbol, meaning for a binary operator minus, the above would parse "1-[9]", but not "1-9" (not a real world example). Also note that there is a slight semantic difference in specifying a feature as storeRightTo versus providing it in the template body. When using storeRightTo, the same precedence rules are applied for left and right operand. If you use a feature of the operatored abstract class in the operatorTemplate's body, the abstract class's production rule will be used instead, leading to different precedence rules.

Often an operatoredTemplate would be used for several operators at once, then the operator names need to be listed with blanks separating them. In such cases, it is also usually required to save which operator was used in a feature of the metamodel element, using the storeOpTo keyword (Else it would be impossible later to tell which operator was used in the parsed bit).

Example:

operatorTemplate OperatorExp(operators =
  opPoint opRarrow opNot opMinus1
  opStar opSlash opPlus opMinus2
  opEq opGt opLt opGe opLe opNe
  opAnd opOr
  opMatch opNoMatch, 
  source = leftExp, storeOpTo = opName, storeRightTo = rightExp);
  

The value stored in storeOpTo will be the operator symbol as a String, such as "+" or "->".

So with the above, the expression "x > 3" would in the end create a ModelElement X{type=OperatorExp, leftExp="x", opName=">", rightExp="3"}

Note again that if there are superclasses of the class for which an operatorTemplate is specified, and these superclasses inherit from the abstract operatored class, and you don't want to provide concrete syntax for those superclasses, you must not define abstract templates for these "in-between" classes. The grammar would otherwise end up containing empty production rules.

In order to distinguish different syntaxes by the operator being used, it it is possible to provide multiple operatorTemplates for the same class but with distinct sets of operators. This makes it possible to have different syntaxes for one class depending on the operator. For example:

operatorTemplate SomeParenthesisExp (operators = left_bracket, source = left)
  : rightHandSite right_bracket
  ;

operatorTemplate SomeParenthesisExp (operators = left_paren, source = left)
  : rightHandSite right_paren
  ;

operators {
  priority 0 {
    left_bracket = "[", 2;
    left_paren = "(", 2;
  }
}

EnumerationTemplate

Enumeration templates are required for Enumeration Types. Since in general all the information required is stored in the metamodel the default easiest definition would be:

enumerationTemplate TestEnumeration auto;

where the auto keyword will make sure the grammar considers all literals included in the metamodel. In some cases, it may be required or desired to use different literals in the Syntax than in the metamodel, typically to have a different spelling in the syntax. E.g.

enumerationTemplate Planet
  :  #mer    = "Mercury",
     #ven    = "Venus",
     #mar    = "Mars"
  ;

Symbols and Keywords

If you use any fixed String within a Template, it will be interpreted as a keyword. For some such fixed Strings, you may wish for them to be interpreted as Symbols instead, especially for Syntax Highlighting. Also, you may wish to specify a Symbol or Keyword just once, such that you may change it in just one spot for the whole language. In that case, instead of using the literal in the template directly, as in 'template Person: "Person" name;', you would use the keyword reference: 'template Person: personKeyword name;'

I.e. in

template Author
  : "author "(" name "age" age ")" ";"
  ;
  

You may wish for (, ), and ; to be displayed in normal colours, while the keywords "author" and "age" should be bold.


NOTE: By default every usage of a literal "..." in a template is considered a keyword, so you do not need to explicitly list keywords to use them.


To define what is a symbol and what a keyword, you can list all keywords all symbols of your syntax:

keywords {
  personKeyword = "Person";
}

symbols {
  lsquare	= "[";
  rsquare	= "]";
  dlsquare	= "[[";
  drsquare	= "]]";
  excl		= "!";
  coma		= ",";
  lparen	= "(";
  rparen	= ")";
}
  

Tokens (including Comments)

Tokens labeled as 'omitted' are ignored by the lexer.

Examples:

omitted token COMMENT	
  :
	endOfLine(start = "#") 
  ;
  

matches all lines starting with '#'

omitted token COMMENT	
  :
	endOfLine(start = "//") 
        |  multiLine(start = "/*", end = "*/")
  ;
  

matches either lines starting with // or several lines in between /* and */

token HEADERID	
  :	
    word(
       start = "#",
       part = [alnum] | "_" | "!" | "%" | "*" | "-" | "+" | "'" | "`" | "~",
       end = ":"
    )
  ;
  

matches words starting with a "#", having any of the "part" chars in the middle, and ending with a ":"

 start? (part)* end?

For the word() rule, one of start and end must exist. Instead of [alnum], you may use [alpha] for all letters only

Lexer

The Lexer part of the syntax definition defines whitespaces and primitive EBNF rules used in PrimitiveTemplates. If you provide a custom lexer part, be sure to include the rules for NL and WS as below.

Example:

	lexer = "
%options testLiterals = false;

NL
	:	(	'\\r' '\\n'
		|	'\\n' '\\r'	//Improbable
		|	'\\r'
		|	'\\n'
		)
	{newline();$channel=HIDDEN;}
	;

WS
	:	(	' '
		|	'\\t'
		){$channel=HIDDEN;}
	;

%protected
DIGIT
	:	'0'..'9'
	;

%protected
ALPHA
	:	'a'..'z'
	|	'A'..'Z'
	|	'_'
	//For Unicode compatibility (from 0000 to 00ff)
	|	'\\u00C0' .. '\\u00D6'
	|	'\\u00D8' .. '\\u00F6'
	|	'\\u00F8' .. '\\u00FF'
	;
	



%protected
SNAME
	:	(ALPHA) (ALPHA | DIGIT)* 
;


NAME
	:	(   
		SNAME
		|	'\\''!
			(	ESC
			|	'\\n' {newline();}
			|	~('\\\\'|'\\\''|'\\n')
			)*
			'\\''!
		{setText(unescapeString(getText(), 1));}
		)
	;
	

INT
	:	(DIGIT)+
	;

	FLOAT	:	DIGIT+ '.' DIGIT*	;

%protected
ESC
	:	'\\\\'!
		(	'n' 
		|	'r' 
		|	't' 
		|	'b' 
		|	'f' 
		|	'\"' 
		|	'\\'' 
		|	'\\\\' 
		|	(
				('0'..'3')
				(
				:	('0'..'7')
					(
					:	'0'..'7'
					)?
				)?
			|	('4'..'7')
				(
				:	('0'..'7')
				)?
			)
				{
				}
		)
	;

STRING
	:	'\"'!
		(	ESC
		|	'\\n' {newline();}
		|	~('\\\\'|'\"'|'\\n')
		)*
		'\"'!
		{setText(unescapeString(getText(), 1));}

	;

	";
  

Lexer states

In some cases it is necessary to use lexer states to implement lexer behavior. This means adding java code to the lexerString such that it will be included in the lexer as a class member. Thus, FURCAS allows language designers to include lexermembers using

lexer = "
@lexer::members [[
 private boolean noFloatMode = false;
]]

LBRACKET
	:	'[' { noFloatMode = true; } 
	;
...
"
  

This function does not allow using the sequences "[[" and "]]" in the java code, for technical reasons.

Advanced Language Features

Syntactic Disambiguate

As the grammar that is generated from the mapping definition is a ANTLR grammar and therefore is a LL(*) recursive descend parser it is sometimes necessary to disambiguate rules from each other. If you have a certain k=n specified there and you have still rules that are non-LL(n) additional syntactic predicates have to be added in alternatives to resolve those conflicts. Therefore operatorTemplates have the option to specify a disambiguation rule:

template ambiguousTemplate (disambiguate = "\""ambiguousStatement"\" NAME")
	:	(isOptipnalFeatureTrue ? "ambiguousStatement")
		name
	;

This means that an additional backtracking is done for this rule trying to match as far as the disambiguate statement reaches. Note, that if you do not want to bother with disambiguating the rules it is also possible to specify no k=n at for the mapping. Then an ANTLR grammatic will be generated where all ambiguous rules will automatically get the appropriate predicates including backtracking generated into the parser.


If alternatives need a syntactical disambiguation from each other this is done using the following syntax:

[[ disambiguate("synpred") altA | altB  ]]

Semantic Disambiguate

A set of templates which describe identical syntactic values can be disambiguated with the keyword "semDisambiguate" in the template declaration. The expected expression is an OCL expression which semantically disambiguates the set of templates. You can use a feature which is declared in the template by the construct ${feature}. It will be replaced by the lexical parsed value of the feature at runtime. By the moment there is only one reference to a feature possible and it must be a basic type, like a String or Number. You can also mix semantic and syntactic disambiguates. If you have three templates like this, it is an example use of mixing semantic with syntactic predicates:

template A (disambiguateV3="abc")
-- do something
;

template B (disambiguateV3="def", semDisambiguate="${aReference}=someValueA")
aReference "..."
;

template C (disambiguateV3="def", semDisambiguate="${aReference}=someValueB")
aReference "..."
;

You see the syntactical value of B and C is identical (it must be identical, otherwise you will get unexpected values, yet there is no warning) where the syntactic value of A is different. If you like to reference the current template in the OCL query of semDisambiguate you can use #source. The OCL evaluation will replace this by the current template so it is likely the self construct of OCL. The semantically disambiguation will be resolved as delayed Reference at runtime. So it will be solved after the parser walked through the code once.

Semantic disambiguates are also available at operator templates the usage is the same as with class templates.

Here is another example which shows the use of semDisambiguate: We have two templates one should parse an author the other a publisher. The syntactic expression is exactly the same you cannot see a difference between Goethe: and Addison Wesley: But our model knows two functions which can evaluate if we have an author or a publisher, e.g. there is somewhere else in our model a list of authors and publishers and our example templates just reference them again in another way. In this example we must be sure that there the sets of authors and publishers are distinct otherwise a semantically disambiguation is not possible.

Template Author (semDisambiguate="#source.checkIsAuthor('${authorName}')")
authorName ":"
;

Template Publisher(semDisambiguatre="#source.checkIsPublisher('${publisherName}')")
publisherName ":"
; 


Serialisation

With FURCAS, you may define both the Syntax as well as the intended Serialisation (line breaks, white spaces, indentation). However it is easiest to first define the Syntax, then optimize Serialization properties afterwards.

Note that by default blanks are inserted between elements whenerver required, so you only need to specify additional wishes for text structure.

The following elements are ignored during parsing, meaning they do not specify what is correct or not in the syntax. No errors would be shown in an editor if the sample of the concrete DSL missed a tab or a newline, if they were specified like below. For semantic whitespaces, as in Python, different concepts are required.


customSeparator

One of "no_space", "space", "newline", "tab".

no_space will force adjacent tokens together during pretty-printing.

space will instert " ", newline a "\n", and tab a "\t"


Example:

template Book 
  :
    title "{"<newline>
    <tab>author<newline>
    <tab>year<newline>
    "}"
  ;
  

Symbol Space Settings

Each symbol can optionally have it's own space setting parameters. They are specified after the symbol name and a ":", separated by ",".

Possible values are "leftSpace", "leftNone", "rightSpace", "rightNone".

Only one left- and one right- value can be chosen.

  • A -Space parameter will force a " " between the symbol and the next adjacent token on the corresponding side during pretty-printing.
  • A -None parameter will force the next adjacent token on the corresponding side to be pretty-printed without any space between them.
  • No parameter for a given side means the default is used and a space is only inserted, if necessary for the lexer to separate the tokens.

Example:

symbols {
  lsquare = "[" : leftNone, rightSpace;
  rsquare = "]" : leftSpace, rightNone;
  comma   = "," : rightSpace;
}
  


Newlines

Block

the following show examples of usage of the Block "[" "]". In general blocks behave like this: The contents of the block are placed in a newline, and if the element is a multiElement (like a multivalued property), thie creates a new line for each.

After the Block, one may specify additional parameter (BlockArgs) in curly brackets.

  • indentIncr = int
  • startNL = boolean
  • endNL = boolean
  • nbNL = int
  • startNbNL = int



Examples:


template IfExp
		:	"if" condition "then" [
				thenExpression
			] "else" [
				elseExpression
			] "endif"
		;

template LetExp context nonPrimary
		:	"let" variable "in"
			[ in_ ] {indentIncr = 0, endNL = false}
		;

  

Escaping

  • If {as=stringSymbol} is specified, the pretty-printer puts the output in ""-Quotes (TODO: this is more of a workaround, assuming that a the primitiveTemplate stringSymbol is used for values that need to be escaped).
  • If {as=someOtherTemplate} is specified, the "orKeyword" property of the primitiveTemplate with the name someOtherTemplate is evaluated.

It is also evaluated, wheater or not the identifier matches [_a-zA-Z][_a-zA-Z0-9]* or not. ""-Quotes are then used either if the identifier contains special chars, or if a keyword with the same name exists and orKeyword is not specified.

  • If no primitiveTemplate is referenced using {as=}, currently orKeyword is assumed to be false. TODO: evaluated orKeyword of primitiveTemplate with "default" property?

Example:

  primitiveTemplate identifier for PrimitiveTypes::String default using NAME :
    value = "unescapeString(%token%)";

  primitiveTemplate identifierOrKeyword for PrimitiveTypes::String using NAME orKeyword:
    value = "unescapeString(%token%)";


Assuming that "jack" is used somewhere as a keyword, a Person with name "jack" will be pretty-printed as follows:

Using

  template Person
    :  "person" name{as=stringSymbol}
  ;

will print

person "jack"

Using

  template Person
    :  "person" name{as=identifierOrKeyword}
  ;

will print

person jack

Using

  template Person
    :  "person" name
  ;

will print

person "jack"

A Person with name "O'Bryan" will always be printed as

person "O'Bryan"


The serializer property of primitiveTemplates can be used to specify a custom serialization for values. The "%value%" part of the serializer string will then be replaced by the actual value. See the following example where additional "/**" and "*/" will be used to surround the value.

  primitiveTemplate comment for PrimitiveTypes::String using COMMENT
    value = "unescapeString(%token%)",
    serializer = "/** %value% */";

Primitive Serializer

For PrimitiveTemplates relating to String, a serializer may be defined (However this seems to be out of use in FURCAS)


Deprecated Language Features

Context (deprecated by referenceBy and the explicit lookupScope)

ClassTemplates may define a context. Elements that occur lexically within the text matched by the ClassTemplate can be added to the context using the
addToContext
directive after the respective template. Contexts can be nested, according to the lexical structure, forming a context stack. As an example, for a syntax for a java class, the class could be a context object, and each method could be a subcontext. This forms a tree, but in the context of a parse process, the parser will be in one node of the tree at any given point in time, and the ancestors then would be the context stack.

This stack will be used to resolve references, with the lowest context first, such that for variable declarations, declarations within the lowest context (method) would take precedence over variable declarations of the higher context (class). Each context by default only contains its subcontexts, meaning in order to do something more useful with contexts, you have to declare Classtemplates using "addToContext" which will be elements that will be added to the context stack.

Elements can be looked up using {refersTo = ...} after the property specification in a template (see section on #Reference: refersTo). In this case , by default, the reference target( the element to which to refer to) will be looked for in the current context and, if not found, in the containing contexts transitively. To override that default behavior a navigation in the model is possible by providing references with a lookIn=... properTyArgument. Navigation starts at the currently parsed ModelElement as default, but may also start at its context Element or a tagged context higher up in the context Stack. Further navigation steps are the names of features of modelElements. The context structure may as well be used to define a starting point for the createIn property Argument.

Only non-abstract ClassTemplates can be defined as context. E.g. in a Java class, the context for looking up a variable is first the variable declarations in the method, then the declarations in the class.

Meaning if you'd define template like this:

template JavaClass context :
    ...
    ;
template JavaMethod context :
    ...
    ;
  

then within a method, used variables will refer to method-local declarations first, as in Java.

Assume a Java Class like this:

class Test {
  int foo = 0;
  public void doBar() {
    int foo = 1;
    System.out.println(foo);
  }
}
  

will resolve foo in the System.out with 1, where as if the Syntax defined a method not to be context

template JavaMethod :
    ...
    ;
  

then the class above would not parse, causing a duplicate reference error.


coreMonet introduces the concept of tagged contexts to FURCAS. Optionally, ClassTemplates defining context elements can give these elements a number of tags, to be referenced by these tags from deeper down the context hierarchy. As said before, the contexts define a tree structure on a document, where contexts are being created for all elements being declared with the context keyword. By default, during the parsing process there is only one current context, and that one is sufficient for most usages of contexts. However in some cases contexts higher up in the context hierarchy (=earlier in the context Stack) may be required for reference lookups when setting properties, meaning in lookIn or the createIn PropertyArguments. As an example, consider Java classes again and this time the class, any method, and any method body could be defined as contexts.

The context tree at the end of parsing could then look like this

  • context(Class:Foo) : field myField1, field myField2
    • context (Method:bar1) : parameter value1, parameterValue2
      • context (methodBody) : variable i, variable index
    • context (Method:bar2) : parameter value3
      • context (methodBody) : variable x

Every node in this tree is a context, and has a context element (in brackets), as well as additional contents which are not contexts themselves. The context Stack for any declaration is the context it was parsed in and all the ancestor contexts. So within method body of Foo.bar2(Type value3) {...here...} the context stack is the [Class, Method, MethodBody], where the currentContext would be MethodBody. Now if for elements within the Method body we need to syntactically refer to elements to which we can best navigate starting from the Method context (not the current context), we need to use tagged contexts. This mean we need not only to make Method a context element adding "context" to the template, we need to give it a tag to refer to this level of context, such as delcaring it with

template Method context(methodLevel):...;


The syntax in FURCAS is:

template Something context(tag1, tag2) :
    ...
    ;
template OtherThing :
  myProperty{refersTo=name, lookIn='#context(tag1)'}
;
  


Reference: refersTo (deprected by referenceBy)

If one ModelElement references another, you may either make them contain each other in the syntax, or refer to it. In either case you would add the feature name of the reference in the template sequence for the referring ModelElement, but add different PropertyArgs in curly brackets.

The key for the reference is a property that will represent the reference target in the text. This must currently be a primitve feature, but an extention is planned to allor for any type as well (so far there is no example where this would be required). An alternative way to achieve a reference using complex mechanisms is to use the referenceOnly keyword in a ClassTemplate, allowing ClassTemplates to resolve references from text in complex ways.

In some cases references imply creating the referenced modelElement before referring to it, which practically works only with simple ModelElements having just one or no Attributes. As an example several ModelElements may be declared to one specific modelElement which is not represented in the document, then when the first reference is resolved, the reference target modelElement will be created, and it will be available as reference for the other referring modelElements. This is the default behavior, and it can be changed using the autoCreate propertyArgument.

This is demonstrated in the following.

template Article
  : "article" "{" author{refersTo=name} "}"
  ;
template Author
  : "author" "=" name "."
  ;
  

In the case above, the author would have to be defined somewhere else in a sample, else the reference could not be resolved. An example would be:

article { "John"}
author = "John".
  

If you defined without references:

template Article
  : "article" "{" author "}"
  ;
template Author
  : "author" "=" name "."
  ;
  

a sample would be

article { author = "John".}
  
Reference lookup scope

When a reference to a different element is used, a default scope is will be applied to look in, unless special lookIn property arguments are used. By default if no lookIn propertyArgument is provided, the current context is being used, and all parent contexts transitively. Meaning if no context is defined, then the reference will not be resolved. With lookIn, it is possible to also define a global scope, or to point to a specific modelElement relative to the current modelElement in the model.

importContext

In some cases, by referring to another ModelElement you may wish to use that other ModelElement as context for further references. As an example, import statements in java are references to other classes, which also allow using public methods of other classes as if they existed in the context of the current class.

This can be done using the importContext flag in the PropertyArgs:

template Class context
  : imports{refersTo=name, importContext, separator = ";"}
    "class" "{" ...
  ;
  

This is only a crude approximation of the import behavior of Java.

Formally, this requires the referenced element to be one which is a context Element itself, and also part of the parsed text (at the time of this writing), and the referencing object also to be a context objet itself. The implementation will then also search in the elements of the imported contexts whenever the importing context is accessed.

autoCreate and createAs

If a refence is made, but no suitable model element exists, the Injector may either raise a resolution error, or in some cases create the ModelElement. The default is to create an element in such a case, which is equivalent to declare "autoCreate = ifMissing" If the modelInjector has to create the element in any case, to save time trying to resolve the reference (or make sure it is not referenced twice) use "autoCreate = always". If the model should never create such a reference, but instead give an error when it cannot be resolved, use "autoCreate = never"

This behavior to create modelElements for references may be used with createIn to specify a ModelElement property which will contain the newly created Element. However, lookIn serves as createIn if the latter is not specified. This means if lookIn is specified but not createIn, then lookIn will be used to create the modelElement within another ModelElement, except if "lookin=#all".

In some cases a reference may be of an abstract type Foo, and we need to specify that the created referenced element needs to be of subtype bar. This can be done using the createAs='BarPackage::Bar' property argument.

lookIn and createIn

By default a reference will be looked for in the current context and all parent contexts, which is set by adding the context keyword to a template.

template JavaClass context
  : methods
  ;
...
template MethodCall
  : calledMethod
  ;
  

References may have lookIn and createIn parameters, which work with a keyword or a path notation to a model Element. The path is a dot-separated list of property names or keywords. Technically, the path is merely a string, and it may be necessary to put it within single quotes to parse, e.g. lookIn='#context'. CreateIn is used when a reference does not exist at the end of parsing, and the parameter autoCreate is one of "always" or "ifMissing". CreateIn does not need to be specified if it is the same as lookIn.

lookIn and createIn use a path notation where path steps are separated by dots. path steps represent a navigation in the model structure along ModelElement features. The starting point is the currently parsed modelElement by default. As an alternative starting point, a context may be used as first step of the path using the #context keyword. Instead of giving a path, a global scope can be given by using #all. LookIn must point at a single ModelElement if referring to a context, or may point at a modelElement or a multivalued feature of a modelElement else. It is up to the ModelAdapter implementation to define the scope in the latter case (FURCAS is ambiguous on what should be done). The last step of createIn must specify a featureName which will be used to set the modelElement to some owner modelElement (as declared by the path).

A common usage for lookIn is "#all", to look for a reference not just within the current context. This means that the document itself and the context structure will be ignored, and that instead any modelElement known to the ModelAdapter with the given type and attributes will be used. It is the implementation of the ModelAdapter which then may restrict the scope, e.g. to MOIN scopes, and not the responsibility of the syntax description. If there is more than one ModelElement fitting the description, the reference will not be set. This keyword does not work for CreateIn, of course.

template Article
  : "article" "{" reference{refersTo = name, lookIn =#all } "}"
  ;
  

If a reference should neither be resolved directly in the context or in the whole model, a path notation can be used.

By default the path is assumed to start from the current modelElement, and you may navigate throught the properties. I.e.

template Article
  : "article" "{" author{refersTo = name, lookIn =properties.publishingproperties } "}"
  ;
  

Would look for an Author within the property "publishingproperties" of the property "properties" of the current Article

Finally one may specify to look for a reference somewhere in the model tree statring at the current context, using the "#context" keyword at the root of the path.

I.e.

template Proceedings context
  : name "{" articles  "," specialarticles "}"
  ;

template Article
  : "article" "{" reference{refersTo = name, lookIn = '#context.specialarticles'} "}"
  ;
  

would look for referenced Articles within the proceedings "specialarticles" attribute.

The path notation was intended originally to work only within the parsed document, however in the monet context, this will be extended to work on a wider scope as well, allowing to navigate along attributes and references of metamodel Elements.


Property Argument Syntax

The following table show the existing property arguments, and in what combinations they may be used.

Property Argument Allowed Values Examples
refersTo (deprecated) name of feature of referenced class refersTo = id / refersTo = name
createAs (deprecated) (qualified) name of type to use createAs=FictionAuthor / createAs = 'BibText::Fiction::Author'
createIn (deprecated) path notation to modelElement feature to set createIn='myParent.container.attribute' / createIn = '#context.attribute'. Works also with paths which lead outside DSL document
lookIn (deprecated) path notation to context element or modelElement outside document, including #all lookIn='#all' / lookIn='#context.somewhereElse' / lookIn='myReference.otherReference'
importContext (deprecated) true or false importContext = true
autoCreate (deprecated) always, ifMissing or Never autoCreate=always / autoCreate=ifMissing / autoCreate=never

.

Personal tools