1 module pbd.parse; 2 3 import pegged.grammar; 4 5 mixin(grammar(` 6 Proto: 7 Root < Syntax? :';'? 8 Package? :';'? 9 ((Import / Option / Enum / Message) :';'?)* 10 11 Spacing <~ (space / endOfLine / Comment)* 12 Comment <~ "//" (!endOfLine .)* endOfLine 13 14 Syntax < :"syntax" :'=' String 15 16 Package < :"package" identifier 17 18 Import < :"import" String 19 20 Option < :"option" identifier :'=' Value 21 22 Enum < :"enum" identifier :'{' 23 (EnumField :';'?)* 24 :'}' 25 26 EnumField < identifier :'=' Integer 27 28 Message < :"message" identifier :'{' 29 ((SingleField / RepeatedField / Oneof / Map / Enum / Message) :';'?)* 30 :'}' 31 32 SingleField < identifier identifier :'=' Integer 33 34 RepeatedField < :"repeated" identifier identifier :'=' Integer 35 (:'[' "packed" :'=' Bool :']')? 36 37 Oneof < :"oneof" identifier :'{' 38 (SingleField :';'?)* 39 :'}' 40 41 Map < :"map<" identifier :"," identifier :">" identifier :'=' Integer 42 43 Value <- String 44 / Integer 45 / Bool 46 47 Bool <- "true" / "false" 48 49 String <~ :doublequote Char* :doublequote 50 Char <~ backslash doublequote 51 / backslash backslash 52 / backslash [bfnrt] 53 / (!doublequote .) 54 55 Integer <~ '0' 56 / [1-9] Digit*? 57 Digit <- [0-9] 58 `)); 59 60 61 /// 62 version (pbd_test) 63 unittest 64 { 65 enum exampleProto = ` 66 /// test test 67 syntax = "proto3"; 68 69 /// test 70 package tensorflow; 71 72 /// test 73 option cc_enable_arenas = true; 74 option java_outer_classname = "OpDefProtos"; 75 import "tensorflow/core/framework/attr_value.proto"; 76 import "tensorflow/core/framework/types.proto"; 77 78 // Defines an operation. A NodeDef in a GraphDef specifies an Op by 79 // using the "op" field which should match the name of a OpDef. 80 // LINT.IfChange 81 message OpDef { 82 // Op names starting with an underscore are reserved for internal use. 83 // Names should be CamelCase and match the regexp "[A-Z][a-zA-Z0-9>_]*". 84 string name = 1; 85 86 // For describing inputs and outputs. 87 message ArgDef { 88 // Name for the input/output. Should match the regexp "[a-z][a-z0-9_]*". 89 string name = 1; 90 91 // Human readable description. 92 string description = 2; 93 }; 94 95 repeated AttrDef attr = 4 [packed = true]; // test 96 97 oneof test_oneof { 98 string name = 4; 99 string sub_message = 9; //test 100 }; 101 102 map<string, int32> str2int = 5; 103 104 enum Visibility { 105 // Normally this is "VISIBLE" unless you are inheriting a 106 // different value from another ApiDef. 107 DEFAULT_VISIBILITY = 0; 108 // Publicly visible in the API. 109 VISIBLE = 1; 110 // Do not include this op in the generated API. If visibility is 111 // set to 'SKIP', other fields are ignored for this op. 112 SKIP = 2; 113 // Hide this op by putting it into an internal namespace (or whatever 114 // is appropriate in the target language). 115 HIDDEN = 3; 116 } 117 Visibility visibility = 2; 118 } 119 `; 120 121 auto tree = Proto(exampleProto); 122 assert(tree.successful, tree.failMsg); 123 124 assert(tree.name == "Proto"); 125 126 auto root = tree.children[0]; 127 assert(root.name == "Proto.Root"); 128 129 // syntax = "proto3"; 130 auto syntax = root.children[0]; 131 assert(syntax.name == "Proto.Syntax"); 132 assert(syntax.matches == ["proto3"]); 133 134 // package tensorflow; 135 auto package_ = root.children[1]; 136 assert(package_.name == "Proto.Package"); 137 assert(package_.matches == ["tensorflow"]); 138 139 // option cc_enable_arenas = true; 140 auto option0 = root.children[2]; 141 assert(option0.name == "Proto.Option"); 142 assert(option0.matches == ["cc_enable_arenas", "true"]); 143 assert(option0.children[0].name == "Proto.Value"); 144 assert(option0.children[0].children[0].name == "Proto.Bool"); 145 146 // option java_outer_classname = "OpDefProtos"; 147 auto option1 = root.children[3]; 148 assert(option1.name == "Proto.Option"); 149 assert(option1.matches == ["java_outer_classname", "OpDefProtos"]); 150 151 // import "tensorflow/core/framework/attr_value.proto"; 152 auto import0 = root.children[4]; 153 assert(import0.name == "Proto.Import"); 154 assert(import0.matches == ["tensorflow/core/framework/attr_value.proto"]); 155 156 // import "tensorflow/core/framework/types.proto"; 157 auto import1 = root.children[5]; 158 assert(import1.name == "Proto.Import"); 159 assert(import1.matches == ["tensorflow/core/framework/types.proto"]); 160 161 // message OpDef { 162 auto message = root.children[6]; 163 assert(message.name == "Proto.Message"); 164 assert(message.matches[0] == "OpDef"); 165 166 // string name = 1; 167 auto field0 = message.children[0]; 168 assert(field0.name == "Proto.SingleField"); 169 assert(field0.matches == ["string", "name", "1"]); 170 assert(field0.children[0].name == "Proto.Integer"); 171 assert(field0.children[0].matches == ["1"]); 172 173 // message ArgDef { 174 auto subMessage = message.children[1]; 175 assert(subMessage.name == "Proto.Message"); 176 assert(subMessage.matches[0] == "ArgDef"); 177 178 // string name = 1; 179 auto subField0 = subMessage.children[0]; 180 assert(subField0.name == "Proto.SingleField"); 181 assert(subField0.matches == ["string", "name", "1"]); 182 183 // repeated AttrDef attr = 4; // test 184 auto repeated = message.children[2]; 185 assert(repeated.name == "Proto.RepeatedField"); 186 assert(repeated.matches == ["AttrDef", "attr", "4", "packed", "true"]); 187 188 // oneof test_oneof { 189 auto oneof = message.children[3]; 190 assert(oneof.name == "Proto.Oneof"); 191 assert(oneof.matches[0] == "test_oneof"); 192 193 // string name = 4; 194 auto oneofField0 = oneof.children[0]; 195 assert(oneofField0.name == "Proto.SingleField"); 196 assert(oneofField0.matches == ["string", "name", "4"]); 197 198 // string sub_message = 9; //test 199 auto oneofField1 = oneof.children[1]; 200 assert(oneofField1.name == "Proto.SingleField"); 201 assert(oneofField1.matches == ["string", "sub_message", "9"]); 202 203 // map<string, int32> str2int = 5; 204 auto map = message.children[4]; 205 assert(map.name == "Proto.Map"); 206 assert(map.matches == ["string", "int32", "str2int", "5"]); 207 208 // enum Visibility 209 auto enumDecl = message.children[5]; 210 assert(enumDecl.name == "Proto.Enum"); 211 assert(enumDecl.matches == [ 212 "Visibility", 213 "DEFAULT_VISIBILITY", "0", 214 "VISIBLE", "1", 215 "SKIP", "2", 216 "HIDDEN", "3"]); 217 auto enumField0 = enumDecl.children[0]; 218 assert(enumField0.name == "Proto.EnumField"); 219 assert(enumField0.matches == ["DEFAULT_VISIBILITY", "0"]); 220 }