
Contents |
This is a reference of the basic composition language provided by FraCoLa. The language can be used in any invasive composition system to compose fragment components independent of the component language. The abstract and concrete syntax definitions of the language are described like all languages in the Reuseware Framework and can be found at the end of this article.
A composition program is a sequence of composition statements. The following composition statements are available in the basic composition language:
declares a fragment. A fragment has a type (i.e., the language construct it is an instance of) and a name. The value that is assigned can be:
the path to a file containing the fragment.
the name of another fragment that should be assigned to the new name.
the code of a new fragment to construct. The extension identifies the concrete syntax the fragment is written in. The fragment code is a concatenation of defined code pieces and code pieces that are extracted from other fragments. This enables the construction of new fragments from existing ones based on their content only. The types of the existing fragments are irrelevant here.
prints the fragment to the path (path definition is equal to path definition in fragment declarations).
evaluates the condition and executes either the composition statements contained in the if-body or in the else-body. The condition can be:
that types and code of two fragments are equal.
that a fragment is an instance of a certain type (i.e., construct).
that a slot is bound (i.e., does not exist anymore) on a fragment.
iterates over the fragment list and executes the body for every iteration. In every iteration, the current fragment in the list is made available under the given fragment name.
traverses over the tree of sub-fragments of the fragments in the fragment list and executes the body for each sub-fragment. In every step, the current sub-fragment is made available under the given fragment name. The traversing of a sub-tree can be prevented by using the prune statement.
Composer statements are special composition statements that execute composition operators. The composition language includes such statements for the primitive composition operators.
queries for the slot(s) in the fragment and binds them with the value. The value is a fragment and the ways of specifying it correspond to the ways of defining the value of a fragment declaration. If no slot name is specified, the fragment is replaced with the value.
queries for the hook(s) in the fragment and extends them with the value. If no hook name is specified, the value is added to the list containing the fragment.
queries for the hook(s) in the fragment and prepends the value (specialization of extend).
queries for the hook(s) in the fragment and appends the value (specialization of extend).
Composition programs are themselves composable. In particular, they may contain in-place bind operations that are especially applicable in composer definitions (see next section).
Binds the value in-place.
In-place binds are available for values, fragment names, fragment types, and variation point names.
The basic composition language contains a construct to define complex composers. For each composer defined, a construct to call the composer has to exist in a specialized composition language.
defines the composer for the construct utilized to call it. The arguments have to correspond to the references of the call construct. The statement list may contain any composition statement. The return fragment, if specified, is bound in-place after the composer's execution.
The arguments are accessible as fragments. Thus, they can be directly composed, meaning that the fragments passed to the composer are bound and extended with each other. However, often arguments configure the composer itself. In this case, they need to be bound in-place (e.g., one argument is the name of a slot the composer should address: bind ->slotNameArg on fragArg1 with fragArg2;).
Abstract syntax grammar
CompositionProgram = statementList:CompositionStatementList;
CompositionStatementList = statements:CompositionStatement*;
CompositionStatement = Composer | FragmentDeclaration | Print | Conditional | ForEachLoop |
Traverse| Prune;
FragmentDeclaration = type:componentmodel.AbstractFragmentType,
name:AbstractFragmentName,
value:Value+;
componentmodel.AbstractFragmentType = FragmentTypeBind;
FragmentTypeBind;
FragmentTypeBind ==> Bind;
AbstractFragmentName = FragmentName | FragmentNameBind;
FragmentNameBind;
FragmentNameBind ==> Bind;
FragmentName = name:S, subFragment:AbstractFragmentName?, index:S?;
Value = Location | AbstractFragmentName | FragmentDefinition | ValueBind;
ValueBind;
ValueBind ==> Bind;
Location = path:S;
FragmentDefinition = codePieces: CodePiece+, fileExtension:S;
CodePiece = ConcreteCodePiece | AbstractFragmentName | RandomPiece;
ConcreteCodePiece = code:S;
RandomPiece;
Print = fragment:AbstractFragmentName, location:Location;
ForEachLoop = fragmentName:AbstractFragmentName,
list:AbstractFragmentName,
body:CompositionStatementList;
Traverse = fragmentName:AbstractFragmentName,
list:AbstractFragmentName,
body:CompositionStatementList;
Prune;
Conditional = condition:ConcatenatedCondition,
ifBody:CompositionStatementList,
elseBody:CompositionStatementList;
Condition = InstanceofCondition | IsBoundCondition | EqualsCondition;
ConcatenatedCondition = conditions:Condition+;
InstanceofCondition = fragment:AbstractFragmentName,
type:componentmodel.AbstractFragmentType;
IsBoundCondition = fragment:AbstractFragmentName,
slot:componentmodel.AbstractVariationPointName;
EqualsCondition = fragment1:AbstractFragmentName, fragment2:AbstractFragmentName;
VariationPointNameBind;
VariationPointNameBind ==> Bind;
componentmodel.AbstractVariationPointName = Bind;
Composer = Bind | Extend | Prepend | Append;
Bind = slot:componentmodel.AbstractVariationPointName?,
fragment:AbstractFragmentName?, value:Value;
Extend = hook:componentmodel.AbstractVariationPointName?,
fragment:AbstractFragmentName?, value:Value+;
Prepend;
Prepend ==> Extend;
Append;
Append ==> Extend;
Concrete syntax grammar
CONCRETESYNTAX fcp FOR compositionlanguage
CompositionProgram ::= "composition" "program" statementList;
CompositionStatementList ::= statements*;
FragmentDeclaration ::= "fragment" type name "=" value ("," value)* ";";
Location ::= path[(’/’ (’A’..’Z’|’a’..’z’|’0’..’9’|’_’|’.’|’’)+)+];
FragmentDefinition ::= codePieces (’+’ codePieces)* "."fileExtension[(’A’..’Z’|’a’..’z’|’_’)
(’A’..’Z’|’a’..’z’|’_’|’0’..’9’)*];
ConcreteCodePiece ::= code[ ’\’’ (~(’\’’))* ’\’’];
RandomPiece ::= "?";
Bind ::= "bind" (slot "on")? fragment "with" value ";";
Extend ::= "extend" (hook "on")? fragment "with" value ("," value)* ";";
Prepend ::= "prepend" (hook "on")? fragment "with" value ";";
Append ::= "append" (hook "on")? fragment "with" value ";";
Print ::= "print" fragment "to" location ";";
ValueBind ::= "->" value;
FragmentNameBind ::= "->" value;
FragmentTypeBind ::= "->" value;
VariationPointNameBind ::= "->" value;
FragmentName ::= name[(’A’..’Z’|’a’..’z’|’_’)(’A’..’Z’|’a’..’z’|’_’|’0’..’9’)*]
("[" index[(’’)?(’0’..’9’)+] "]")? ("." subFragment)?;
componentmodel.VariationPointName ::= name[(’A’..’Z’|’a’..’z’|’_’)
(’A’..’Z’|’a’..’z’|’_’|’0’..’9’)*];
componentmodel.FragmentType ::= (language[(’A’..’Z’|’a’..’z’|’_’)
(’A’..’Z’|’a’..’z’|’_’|’0’..’9’)*] ".")?
construct[(’A’..’Z’|’a’..’z’|’_’)
(’A’..’Z’|’a’..’z’|’_’|’0’..’9’)*];
Conditional ::= "if" "(" condition ")" "{" ifBody "}" ("else" "{" elseBody "}")?;
ConcatenatedCondition ::= conditions ("&&" conditions)*;
InstanceofCondition ::= fragment "instanceof" type;
IsBoundCondition ::= "isbound" slot "on" fragment;
EqualsCondition ::= fragment1 "equals" fragment2;
ForEachLoop ::= "foreach" "(" fragmentName ":" list ")" "{" body "}";
Traverse ::= "traverse" "(" fragmentName ":" list ")" "{" body "}";
Prune ::= "prune" ";";