| /* |
| * Copyright (c) 2011, 2015 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=StringLiteral (';')+; |
| |
| ProtobufElement: |
| Package | Import | Option | ComplexType | TypeExtension | Service; |
| |
| Package: |
| 'package' name=PackageName (';')+; |
| |
| PackageName: |
| IdOrReservedWord ('.' IdOrReservedWord)*; |
| |
| Import: |
| NormalImport | PublicImport | WeakImport; |
| |
| NormalImport: |
| 'import' path=StringLiteral (';')+; |
| |
| PublicImport: |
| 'import' 'public' path=StringLiteral (';')+; |
| |
| WeakImport: |
| 'import' 'weak' path=StringLiteral (';')+; |
| |
| ComplexType: |
| Enum | ExtensibleType; |
| |
| Message: |
| ->'message' name=Name '{' |
| elements+=MessageElement* |
| '}' (';')?; |
| |
| MessageElement: |
| =>Option | Extensions | ComplexType | MessageField | TypeExtension | OneOf | Reserved; |
| |
| IndexRange: |
| from=LONG ('to' to=IndexRangeMax)?; |
| |
| IndexRangeMax: |
| LONG | 'max'; |
| |
| // Hack to make the default modifier 'unspecified' |
| enum ModifierEnum: |
| unspecified | optional | required | repeated |
| ; |
| |
| enum Modifier returns ModifierEnum: |
| optional | required | repeated; |
| |
| Group: |
| (modifier=Modifier)? =>'group' name=Name '=' index=(LONG | HEX) |
| ('[' (fieldOptions+=FieldOption (',' fieldOptions+=FieldOption)*) ']')? '{' |
| elements+=GroupElement* |
| '}' (';')?; |
| |
| GroupElement: |
| =>Option | MessageField | ComplexType | TypeExtension | Extensions | Reserved; |
| |
| OneOf: |
| (isRepeated?='repeated')? =>'oneof' name=Name '{' |
| elements+=OneOfElement+ |
| '}' (';')?; |
| |
| OneOfElement returns MessageElement: |
| Extensions | Group | MessageField; |
| |
| Extensions: |
| ->'extensions' ranges+=IndexRange (',' ranges+=IndexRange)* (';')+; |
| |
| MessageField: |
| (modifier=Modifier)? =>type=TypeLink name=Name '=' index=(LONG | HEX) |
| ('[' (fieldOptions+=FieldOption (',' fieldOptions+=FieldOption)*)? ']')? (';')+; |
| |
| TypeLink: |
| =>ScalarTypeLink | ComplexTypeLink | MapTypeLink; |
| |
| ScalarTypeLink: |
| target=ScalarType; |
| |
| enum ScalarType: |
| double | float | int32 | int64 | uint32 | uint64 | sint32 | sint64 | fixed32 | fixed64 | sfixed32 | sfixed64 | bool | |
| string | bytes; |
| |
| ComplexTypeLink: |
| target=[ComplexType|QualifiedName]; |
| |
| MapTypeLink: |
| target=MapType; |
| |
| MapType: |
| ->'map' '<' keyType=TypeLink ',' valueType=TypeLink '>'; |
| |
| 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') (DIGIT | 'a'..'f' | 'A'..'F')+; |
| |
| TypeExtension: |
| ->'extend' type=ExtensibleTypeLink '{' |
| elements+=IndexedElement* |
| '}' (';')?; |
| |
| ExtensibleTypeLink: |
| target=[ExtensibleType|QualifiedName]; |
| |
| ExtensibleType: |
| Message | Group; |
| |
| Reserved: |
| 'reserved' reservations+=Reservation (',' reservations+=Reservation)* ';'+; |
| |
| Reservation: |
| IndexRange | StringLiteral; |
| |
| Service: |
| ->'service' name=Name '{' |
| (elements+=ServiceElement)* |
| '}' (';')?; |
| |
| ServiceElement: |
| Option | Rpc | Stream; |
| |
| Rpc: |
| ->'rpc' name=Name '(' (=>isArgStreaming?='stream')? argType=MessageLink ')' |
| 'returns' '(' (=>isReturnStreaming?='stream')? 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: |
| '{' {ComplexValueCurlyBracket} (fields+=ValueField (',')?)* '}'; |
| |
| // < foo: 1, bar: 2 > |
| ComplexValueAngleBracket: |
| '<' {ComplexValueAngleBracket} (fields+=ValueField (',')?)* '>'; |
| |
| ValueField: |
| ->SimpleValueField | ComplexValueField; |
| |
| SimpleValueField: |
| name=FieldName ':' |
| (values+=SimpleValueLink | '[' values+=SimpleValueLink (',' values+=SimpleValueLink)* ','? ']') |
| ';'?; |
| |
| ComplexValueField: |
| name=FieldName ':'? |
| (values+=ComplexValue | '[' values+=ComplexValue (',' values+=ComplexValue)* ','? ']') |
| ';'?; |
| |
| FieldName: |
| NormalFieldName | ExtensionFieldName; |
| |
| NormalFieldName: |
| target=[IndexedElement|Name]; |
| |
| ExtensionFieldName: |
| '[' target=[IndexedElement|QualifiedName] ']'; |
| |
| QualifiedName: |
| '.'? SafeId ('.' (WS)* SafeId)*; |
| |
| SafeId: |
| ID | SafeReservedWord; |
| |
| ReservedWord: |
| SafeReservedWord | 'group' | 'oneof'; |
| |
| // These tokens appear as keywords in other rules. Explicitly listing them here prevents the lexer |
| // from consuming them as keywords and gives the parser a chance to interpret them as identifiers. |
| SafeReservedWord: |
| 'bool' | |
| 'bytes' | |
| 'default' | |
| 'double' | |
| 'enum' | |
| 'extend' | |
| 'extensions' | |
| 'false' | |
| 'fixed32' | |
| 'fixed64' | |
| 'float' | |
| 'import' | |
| 'int32' | |
| 'int64' | |
| 'map' | |
| 'max' | |
| 'message' | |
| 'option' | |
| 'optional' | |
| 'package' | |
| 'public' | |
| 'repeated' | |
| 'required' | |
| 'reserved' | |
| 'returns' | |
| 'rpc' | |
| 'service' | |
| 'sfixed32' | |
| 'sfixed64' | |
| 'sint32' | |
| 'sint64' | |
| 'stream' | |
| 'string' | |
| 'syntax' | |
| 'to' | |
| 'true' | |
| 'uint32' | |
| 'uint64' | |
| '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: |
| ('-')? (DIGIT)+; |
| |
| DoubleLink: |
| target=DOUBLE; |
| |
| terminal DOUBLE returns ecore::EDouble: |
| ('-')? (DIGIT)* ('.' (DIGIT)+)? | |
| ('-')? (DIGIT)+ ('.') | |
| ('-')? (DIGIT)+ ('.' (DIGIT)*)? (('e'|'E')('-'|'+')? (DIGIT)+) | |
| 'nan' | 'inf' | '-inf'; |
| |
| terminal fragment DIGIT: |
| '0'..'9'; |
| |
| StringLink: |
| target=StringLiteral; |
| |
| StringLiteral: |
| chunks+=CHUNK+; |
| |
| terminal CHUNK: |
| '"' ('\\' . | !('\\' | '"'))* '"' | |
| "'" ('\\' . | !('\\' | "'"))* "'"; |
| |
| terminal ID: '^'?('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|DIGIT)*; |
| terminal ML_COMMENT: '/*' -> '*/'; |
| terminal SL_COMMENT: '//' !('\n'|'\r')* ('\r'? '\n')?; |
| terminal WS: (' '|'\t'|'\r'|'\n')+; |
| terminal ANY_OTHER: .; |