blob: eb022eae77533c618fb4839181f17a8a82918414 [file] [log] [blame]
/*
* Copyright (c) 2011 Google Inc.
*
* All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
* Public License v1.0 which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Author: alruiz@google.com (Alex Ruiz)
*/
grammar com.google.eclipse.protobuf.Protobuf hidden(WS, ML_COMMENT, SL_COMMENT)
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate protobuf "http://www.google.com/eclipse/protobuf/Protobuf"
Protobuf:
(syntax=Syntax)?
(elements+=ProtobufElement)*;
Syntax:
'syntax' '=' name=STRING (';')+;
ProtobufElement:
Package | Import | Option | ComplexType | TypeExtension | Service;
Package:
'package' name=PackageName (';')+;
PackageName:
IdOrReservedWord ('.' IdOrReservedWord)*;
Import:
NormalImport | PublicImport | WeakImport;
NormalImport:
'import' importURI=STRING (';')+;
PublicImport:
'import' 'public' importURI=STRING (';')+;
WeakImport:
'import' 'weak' importURI=STRING (';')+;
ComplexType:
Enum | ExtensibleType;
Message:
'message' name=Name '{'
elements+=MessageElement*
'}' (';')?;
MessageElement:
Option | Extensions | ComplexType | MessageField | TypeExtension | OneOf;
Range:
from=LONG ('to' to=RangeMax)?;
RangeMax:
LONG | 'max';
Group:
modifier=Modifier 'group' name=Name '=' index=(LONG | HEX)
('[' (fieldOptions+=FieldOption (',' fieldOptions+=FieldOption)*) ']')? '{'
elements+=GroupElement*
'}' (';')?;
UnmodifiedGroup returns Group:
=>'group' name=Name '=' index=(LONG | HEX)
('[' (fieldOptions+=FieldOption (',' fieldOptions+=FieldOption)*) ']')? '{'
elements+=GroupElement*
'}' (';')?;
GroupElement:
Option | IndexedElement | ComplexType | TypeExtension | Extensions;
OneOf:
(isRepeated?='repeated')? 'oneof' name=Name '{'
elements+=OneOfElement+
'}' (';')?;
OneOfElement returns MessageElement:
Extensions | UnmodifiedGroup | UnmodifiedMessageField;
Extensions:
'extensions' ranges+=Range (',' ranges+=Range)* (';')+;
MessageField:
=>modifier=Modifier type=TypeLink name=Name '=' index=(LONG | HEX)
('[' (fieldOptions+=FieldOption (',' fieldOptions+=FieldOption)*)? ']')? (';')+;
UnmodifiedMessageField returns MessageField:
type=TypeLink name=Name '=' index=(LONG | HEX)
('[' (fieldOptions+=FieldOption (',' fieldOptions+=FieldOption)*)? ']')? (';')+;
enum Modifier:
optional | required | repeated;
TypeLink:
ScalarTypeLink | ComplexTypeLink;
ScalarTypeLink:
target=ScalarType;
enum ScalarType:
double | float | int32 | int64 | uint32 | uint64 | sint32 | sint64 | fixed32 | fixed64 | sfixed32 | sfixed64 | bool |
string | bytes;
ComplexTypeLink:
target=[ComplexType|QualifiedName];
Enum:
=>'enum' name=Name '{'
elements+=EnumElement*
'}' ';'?;
EnumElement:
Option | Literal;
Literal:
name=Name '=' index=(LONG | HEX)
('[' fieldOptions+=FieldOption (',' fieldOptions+=FieldOption)* ']')? (';')+;
terminal HEX returns ecore::ELong:
('-')? '0' ('x' | 'X') (NUMBER | 'a'..'f' | 'A'..'F')+;
TypeExtension:
=>'extend' type=ExtensibleTypeLink '{'
elements+=MessageElement*
'}' (';')?;
ExtensibleTypeLink:
target=[ExtensibleType|QualifiedName];
ExtensibleType:
Message | Group;
Service:
'service' name=Name '{'
(elements+=ServiceElement)*
'}' (';')?;
ServiceElement:
Option | Rpc | Stream;
Rpc:
'rpc' name=Name '(' argType=MessageLink ')' 'returns' '(' returnType=MessageLink ')'
(('{' options+=Option* '}') (';')? | (';')+);
Stream:
'stream' name=Name '(' clientMessage=MessageLink ',' serverMessage=MessageLink ')'
(('{' options+=Option* '}') (';')? | (';')+);
Name:
IdOrReservedWord;
IdOrReservedWord:
ID | ReservedWord;
MessageLink:
target=[Message|QualifiedName];
AbstractOption:
Option | FieldOption;
AbstractCustomOption:
CustomOption | CustomFieldOption;
Option:
NativeOption | CustomOption;
NativeOption:
'option' source=OptionSource '=' value=Value (';')+;
CustomOption:
'option' '(' source=OptionSource ')'
('.' fields+=OptionField ('.' fields+=OptionField)*)? '=' value=Value (';')+;
FieldOption:
DefaultValueFieldOption | NativeFieldOption | CustomFieldOption;
DefaultValueFieldOption:
=>'default' '=' value=Value;
NativeFieldOption:
source=OptionSource '=' value=Value;
CustomFieldOption:
'(' source=OptionSource ')'
('.' fields+=OptionField ('.' fields+=OptionField)*)? '=' value=Value;
OptionSource:
target=[IndexedElement|QualifiedName];
OptionField:
MessageOptionField | '(' ExtensionOptionField ')';
MessageOptionField:
target=[IndexedElement|Name];
ExtensionOptionField:
target=[IndexedElement|QualifiedName];
IndexedElement:
=>MessageField | Group;
Value:
ComplexValue | SimpleValueLink;
ComplexValue:
ComplexValueCurlyBracket | ComplexValueAngleBracket;
// { foo: 1, bar: 2 }
ComplexValueCurlyBracket:
'{'
fields+=ValueField ((',')? fields+=ValueField)* (',')?
'}';
// < foo: 1, bar: 2 >
ComplexValueAngleBracket:
'<'
fields+=ValueField ((',')? fields+=ValueField)* (',')?
'>';
ValueField:
SimpleValueField | ComplexValueField;
SimpleValueField:
name=FieldName ':' value=SimpleValueLink;
ComplexValueField:
name=FieldName ':'? values=ComplexValue;
FieldName:
NormalFieldName | ExtensionFieldName;
NormalFieldName:
target=[IndexedElement|Name];
ExtensionFieldName:
'[' target=[IndexedElement|QualifiedName] ']';
QualifiedName:
'.'? SafeId ('.' (WS)* SafeId)*;
SafeId:
ID | SafeReservedWord;
ReservedWord:
SafeReservedWord | 'group' | 'oneof';
SafeReservedWord:
'package' | 'import' | 'public' | 'option' | 'extend' | 'message' | 'optional' | 'required' | 'repeated' |
'enum' | 'service' | 'rpc' | 'stream' | 'returns' | 'default' | 'extensions' | 'to' | 'max' | 'true' | 'false' |
'double' | 'float' | 'int32' | 'int64' | 'uint32' | 'uint64' | 'sint32' | 'sint64' | 'fixed32' | 'fixed64' |
'sfixed32' | 'sfixed64' | 'bool' | 'string' | 'bytes' | 'weak';
SimpleValueLink:
LiteralLink | BooleanLink | NumberLink | StringLink;
LiteralLink:
target=[Literal];
BooleanLink:
target=BOOL;
enum BOOL:
true | false;
NumberLink:
HexNumberLink | LongLink | DoubleLink;
HexNumberLink:
target=HEX;
LongLink:
target=LONG;
terminal LONG returns ecore::ELong:
('-')? (NUMBER)+;
DoubleLink:
target=DOUBLE;
terminal DOUBLE returns ecore::EDouble:
('-')? (NUMBER)* ('.' (NUMBER)+)? |
('-')? (NUMBER)+ ('.') |
('-')? (NUMBER)+ ('.' (NUMBER)*)? (('e'|'E')('-'|'+')? (NUMBER)+) |
'nan' | 'inf' | '-inf';
terminal NUMBER:
'0'..'9';
StringLink:
target=STRING;
terminal STRING:
SL_STRING (SL_STRING)*;
terminal SL_STRING:
'"' ('\\' ('"' | "'" | '\\' | !('\\' | '"')) | !('\\' | '"'))* '"' (WS)* |
"'" ('\\' ('"' | "'" | '\\' | !('\\' | "'")) | !('\\' | "'"))* "'" (WS)*;
terminal ID: '^'?('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*;
terminal ML_COMMENT: '/*' -> '*/';
terminal SL_COMMENT: '//' !('\n'|'\r')* ('\r'? '\n')?;
terminal WS: (' '|'\t'|'\r'|'\n')+;
terminal ANY_OTHER: .;