translation_unit ::=
#ignore(C++) #continue
[
package_declaration(this)
|
service_declaration(this)
|
component_declaration
]*
#empty;
package_declaration(myParentPackage : node) ::=
#readIdentifier:"package"
=> local myPackage;
#continue
package_path:listOfPaths
'{'
=> {
ref myPackage = myParentPackage;
foreach i in listOfPaths {
insert myPackage.listOfPackages[i].name = i;
if myPackage.sequence insert myPackage.listOfPackages[i].sequence = myPackage.sequence + "." + i;
else insert myPackage.listOfPackages[i].sequence = i;
ref myPackage = myPackage.listOfPackages[i];
}
}
[
package_declaration(myPackage)
|
class_declaration(myPackage)
|
service_declaration(myPackage)
]*
'}';
package_path : list ::=
#readIdentifier:package_path
[['.' | "::"] #continue #readIdentifier:package_path]*;
class_declaration(myPackage : node) : value ::=
[class_modifier]?:myModifiers
#readIdentifier:"class" #continue
#readIdentifier:class_declaration
=> merge myPackage.listOfClasses[class_declaration] = myModifiers;
=> localref myClass = myPackage.listOfClasses[class_declaration];
=> insert myClass.name = class_declaration;
[parent_declaration(myClass)]?
class_declaration_body(myClass)
=> {
pushItem this.allClasses[class_declaration].packages;
ref this.allClasses[class_declaration].packages#back = myPackage;
insert myPackage.listOfClasses[class_declaration].sequence = myPackage.sequence;
}
[';']?;
class_modifier : node ::=
#readIdentifier:"abstract"
=> insert class_modifier.isAbstract = true;
;
parent_declaration(myClass : node) ::=
[
#readIdentifier:"extends" #continue
#readIdentifier:myClass.extendedClass
]?
[
#readIdentifier:"implements" #continue
=> pushItem myClass.listOfInterfaces;
#readIdentifier:myClass.listOfInterfaces#back
[
',' #continue
=> pushItem myClass.listOfInterfaces;
#readIdentifier:myClass.listOfInterfaces#back
]*
]?
;
class_declaration_body(myClass : node) ::=
'{' #continue
[
attribute_declaration(myClass)
|
method_declaration(myClass)
]* '}';
service_declaration(myPackage : node) : value ::=
#readIdentifier:"service" #continue
#readIdentifier:service_declaration
=> insert myPackage.listOfServices[service_declaration].name = service_declaration;
service_declaration_body(myPackage.listOfServices[service_declaration])
=> {
pushItem this.allServices[service_declaration].packages;
ref this.allServices[service_declaration].packages#back = myPackage;
insert myPackage.listOfServices[service_declaration].sequence = myPackage.sequence;
}
[';']?
;
service_declaration_body(myService : node) ::=
'{' #continue [method_declaration(myService)]* '}';
component_declaration ::=
#readIdentifier:"component"
#continue
#readIdentifier:sName
=> if findElement(sName, this.listOfComponents) error("component '" + sName + "' has already been declared");
=> insert this.listOfComponents[sName].name = sName;
=> localref theComponent = this.listOfComponents[sName];
'{'
[
#readIdentifier:{"client", "server"}:sSide
#continue
':'
#readIdentifier:sService
=> if !this.allServices.findElement(sService) error("unrecognized service '" + sService + "'");
=> if sSide == "client" insert theComponent.client[sService] = sService;
else insert theComponent.server[sService] = sService;
[
',' #continue
#readIdentifier:sService
=> if !this.allServices.findElement(sService) error("unrecognized service '" + sService + "'");
=> if sSide == "client" insert theComponent.client[sService] = sService;
else insert theComponent.server[sService] = sService;
]*
';'
]*
'}'
[';']?
;
type_specifier(myType : node) ::=
[
base_type_specifier(myType)
|
container_type_specifier(myType)
|
class_type(myType)
]
[array_specifier(myType)]*;
base_type_specifier(myType : node) ::=
numeric_type(myType)
|
#readIdentifier:{"char", "string", "date", "bool", "boolean"}:myType.name
=> if myType.name == "bool" set myType.name = "boolean";
;
numeric_type(myType : node) ::=
[numeric_type_modifier(myType)]?
#readIdentifier:{"byte", "short", "long", "int", "float", "double"}:myType.name;
numeric_type_modifier(myType : node) ::=
#readIdentifier:{"positive", "negative"}:sModifier
=> {
if sModifier == "positive" insert myType.isPositive = true;
else insert myType.isNegative = true;
}
;
class_type(myType : node) ::=
#readIdentifier:thePath[0]
[
['.' | "::"] #continue
=> pushItem thePath;
#readIdentifier:thePath#back
]*
=> {
if thePath.size() == 1 {
insert myType.name = thePath#back;
insert myType.isObject = true;
} else {
error("'class_type' with scope (" + thePath.size() + " elements) not implemented yet");
}
if !findElement(myType.name, this.allClasses) error("invalid class type '" + myType.name + "'");
};
container_type_specifier(myType : node) ::=
#readIdentifier:{"list", "map", "vector"}:myType.name
'<' #continue
[
#check(myType.name == "map")
#continue
base_type_specifier(myType.keyType) ','
]?
type_specifier(myType.elementType)
'>';
array_specifier(myType : node) ::=
'[' ']'
=> {
slideNodeContent(myType, elementType);
if myType.elementType.isObject insert myType.isObject = true;
insert myType.isArray = true;
};
method_declaration(myClass : node) ::=
[method_pre_modifier(myModifiers)]*
type_specifier(myType)
#readIdentifier:sName
'(' #continue
[
#pushItem(listOfParameters)
parameter_declaration:listOfParameters#back
[
',' #continue
=> pushItem listOfParameters;
parameter_declaration:listOfParameters#back
]*
]?
')'
[method_post_modifier(myModifiers)]?
=>{
local sKey = sName;
setall myClass.listOfMethods[sKey] = myModifiers;
insert myClass.listOfMethods[sKey].name = sName;
setall myClass.listOfMethods[sKey].listOfParameters = listOfParameters;
setall myClass.listOfMethods[sKey].type = myType;
}
';';
method_pre_modifier(myModifiers : node) ::=
#readIdentifier:{"synchronized", "abstract", "final"}:sModifier
=> {
if sModifier == "synchronized" insert myModifiers.isSynchronized = true;
else if sModifier == "abstract" insert myModifiers.isAbstract = true;
else if sModifier == "final" insert myModifiers.isFinal = true;
};
method_post_modifier(myModifiers : node) ::=
#readIdentifier:"const"
=> insert myModifiers.isConst = true;
;
parameter_declaration : node ::=
parameter_type_specifier(parameter_declaration.type) #continue
#readIdentifier:parameter_declaration.name;
parameter_type_specifier(myType : node) ::=
[parameter_type_modifier(myType)]*
type_specifier(myType);
parameter_type_modifier(myType : node) : node ::=
#readIdentifier:{"const", "synchronized"}:sModifier
=> {
if sModifier == "const" insert myType.isConst = true;
else if sModifier == "synchronized" insert myType.isSynchronized = true;
};
attribute_declaration(myClass : node) ::=
attribute_type_specifier(myType) #readIdentifier:sName
#continue
['=' #continue literal:myClass.listOfAttributes[sName].default]?
';'
=> {
insert myClass.listOfAttributes[sName].name = sName;
setall myClass.listOfAttributes[sName].type = myType;
};
attribute_type_specifier(myType : node) ::=
[attribute_type_modifier(myModifiers)]*
type_specifier(myType)
=> merge myType = myModifiers;
;
attribute_type_modifier(myModifier : node) ::=
#readIdentifier:{"aggregate", "const", "readonly", "transient", "pertinent", "synchronized", "pkey", "optional"}:sModifier
=> switch(sModifier) {
case "aggregate": insert myModifier.isAggregate = true;break;
case "const": insert myModifier.isConst = true;break;
case "readonly": insert myModifier.isReadOnly = true;break;
case "transient": insert myModifier.isTransient = true;break;
case "pertinent": insert myModifier.isPertinent = true;break;
case "synchronized": insert myModifier.isSynchronized = true;break;
case "pkey": insert myModifier.isPrimaryKey = true;break;
case "optional": insert myModifier.isOptional = true;break;
};
literal ::= integer_literal | string_literal | character_literal | numeric_literal | boolean_literal;
boolean_literal ::= #readIdentifier:{"true", "false"};
integer_literal ::= INT | OCTAL | HEX;
string_literal ::= [STRING_LITERAL]+;
character_literal ::= CHAR_LITERAL;
numeric_literal ::= FLOAT;
OR ::= '|';
XOR ::= '^';
AND ::= '&';
NOT ::= '!';
LT ::= '<';
LSHIFT ::= "<<";
GT ::= '>';
RSHIFT ::= ">>";
DIV ::= '/';
PLUS ::= '+';
MINUS ::= '-';
TILDE ::= '~';
STAR ::= '*';
MOD ::= '%';
CHAR_LITERAL ::= #!ignore '\'' [ESC | ~'\''] '\'';
ESC ::= #!ignore '\\' ['n' | 't' | 'v' | 'b' | 'r' | 'f' | 'a' | '\\' | '?' | '\'' | '"' | HEX | OCTAL];
DIGIT ::= '0'..'9';
OCTDIGIT ::= '0'..'7';
HEXDIGIT ::= '0'..'9' | 'a'..'f' | 'A'..'F';
OCTAL ::= #!ignore ['0'..'3'] [OCTDIGIT]*;
HEX ::= #!ignore ["0x" | "0X"] [HEXDIGIT]+;
INT ::= #!ignore [DIGIT]+;
FLOAT ::=
#!ignore
[
'.' [DIGIT]+
|
[DIGIT]+ '.' [DIGIT]*
]
[['e' | 'E'] ['+' | '-']? [DIGIT]+]?;