Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / node_modules / protobufjs / src / ProtoBuf / Builder.js
1 /**\r
2  * @alias ProtoBuf.Builder\r
3  * @expose\r
4  */\r
5 ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) {\r
6     "use strict";\r
7 \r
8     /**\r
9      * Constructs a new Builder.\r
10      * @exports ProtoBuf.Builder\r
11      * @class Provides the functionality to build protocol messages.\r
12      * @param {Object.<string,*>=} options Options\r
13      * @constructor\r
14      */\r
15     var Builder = function(options) {\r
16 \r
17         /**\r
18          * Namespace.\r
19          * @type {ProtoBuf.Reflect.Namespace}\r
20          * @expose\r
21          */\r
22         this.ns = new Reflect.Namespace(this, null, ""); // Global namespace\r
23 \r
24         /**\r
25          * Namespace pointer.\r
26          * @type {ProtoBuf.Reflect.T}\r
27          * @expose\r
28          */\r
29         this.ptr = this.ns;\r
30 \r
31         /**\r
32          * Resolved flag.\r
33          * @type {boolean}\r
34          * @expose\r
35          */\r
36         this.resolved = false;\r
37 \r
38         /**\r
39          * The current building result.\r
40          * @type {Object.<string,ProtoBuf.Builder.Message|Object>|null}\r
41          * @expose\r
42          */\r
43         this.result = null;\r
44 \r
45         /**\r
46          * Imported files.\r
47          * @type {Array.<string>}\r
48          * @expose\r
49          */\r
50         this.files = {};\r
51 \r
52         /**\r
53          * Import root override.\r
54          * @type {?string}\r
55          * @expose\r
56          */\r
57         this.importRoot = null;\r
58 \r
59         /**\r
60          * Options.\r
61          * @type {!Object.<string, *>}\r
62          * @expose\r
63          */\r
64         this.options = options || {};\r
65     };\r
66 \r
67     /**\r
68      * @alias ProtoBuf.Builder.prototype\r
69      * @inner\r
70      */\r
71     var BuilderPrototype = Builder.prototype;\r
72 \r
73     // ----- Definition tests -----\r
74 \r
75     /**\r
76      * Tests if a definition most likely describes a message.\r
77      * @param {!Object} def\r
78      * @returns {boolean}\r
79      * @expose\r
80      */\r
81     Builder.isMessage = function(def) {\r
82         // Messages require a string name\r
83         if (typeof def["name"] !== 'string')\r
84             return false;\r
85         // Messages do not contain values (enum) or rpc methods (service)\r
86         if (typeof def["values"] !== 'undefined' || typeof def["rpc"] !== 'undefined')\r
87             return false;\r
88         return true;\r
89     };\r
90 \r
91     /**\r
92      * Tests if a definition most likely describes a message field.\r
93      * @param {!Object} def\r
94      * @returns {boolean}\r
95      * @expose\r
96      */\r
97     Builder.isMessageField = function(def) {\r
98         // Message fields require a string rule, name and type and an id\r
99         if (typeof def["rule"] !== 'string' || typeof def["name"] !== 'string' || typeof def["type"] !== 'string' || typeof def["id"] === 'undefined')\r
100             return false;\r
101         return true;\r
102     };\r
103 \r
104     /**\r
105      * Tests if a definition most likely describes an enum.\r
106      * @param {!Object} def\r
107      * @returns {boolean}\r
108      * @expose\r
109      */\r
110     Builder.isEnum = function(def) {\r
111         // Enums require a string name\r
112         if (typeof def["name"] !== 'string')\r
113             return false;\r
114         // Enums require at least one value\r
115         if (typeof def["values"] === 'undefined' || !Array.isArray(def["values"]) || def["values"].length === 0)\r
116             return false;\r
117         return true;\r
118     };\r
119 \r
120     /**\r
121      * Tests if a definition most likely describes a service.\r
122      * @param {!Object} def\r
123      * @returns {boolean}\r
124      * @expose\r
125      */\r
126     Builder.isService = function(def) {\r
127         // Services require a string name and an rpc object\r
128         if (typeof def["name"] !== 'string' || typeof def["rpc"] !== 'object' || !def["rpc"])\r
129             return false;\r
130         return true;\r
131     };\r
132 \r
133     /**\r
134      * Tests if a definition most likely describes an extended message\r
135      * @param {!Object} def\r
136      * @returns {boolean}\r
137      * @expose\r
138      */\r
139     Builder.isExtend = function(def) {\r
140         // Extends rquire a string ref\r
141         if (typeof def["ref"] !== 'string')\r
142             return false;\r
143         return true;\r
144     };\r
145 \r
146     // ----- Building -----\r
147 \r
148     /**\r
149      * Resets the pointer to the root namespace.\r
150      * @returns {!ProtoBuf.Builder} this\r
151      * @expose\r
152      */\r
153     BuilderPrototype.reset = function() {\r
154         this.ptr = this.ns;\r
155         return this;\r
156     };\r
157 \r
158     /**\r
159      * Defines a namespace on top of the current pointer position and places the pointer on it.\r
160      * @param {string} namespace\r
161      * @return {!ProtoBuf.Builder} this\r
162      * @expose\r
163      */\r
164     BuilderPrototype.define = function(namespace) {\r
165         if (typeof namespace !== 'string' || !Lang.TYPEREF.test(namespace))\r
166             throw Error("illegal namespace: "+namespace);\r
167         namespace.split(".").forEach(function(part) {\r
168             var ns = this.ptr.getChild(part);\r
169             if (ns === null) // Keep existing\r
170                 this.ptr.addChild(ns = new Reflect.Namespace(this, this.ptr, part));\r
171             this.ptr = ns;\r
172         }, this);\r
173         return this;\r
174     };\r
175 \r
176     /**\r
177      * Creates the specified definitions at the current pointer position.\r
178      * @param {!Array.<!Object>} defs Messages, enums or services to create\r
179      * @returns {!ProtoBuf.Builder} this\r
180      * @throws {Error} If a message definition is invalid\r
181      * @expose\r
182      */\r
183     BuilderPrototype.create = function(defs) {\r
184         if (!defs)\r
185             return this; // Nothing to create\r
186         if (!Array.isArray(defs))\r
187             defs = [defs];\r
188         else {\r
189             if (defs.length === 0)\r
190                 return this;\r
191             defs = defs.slice();\r
192         }\r
193 \r
194         // It's quite hard to keep track of scopes and memory here, so let's do this iteratively.\r
195         var stack = [defs];\r
196         while (stack.length > 0) {\r
197             defs = stack.pop();\r
198 \r
199             if (!Array.isArray(defs)) // Stack always contains entire namespaces\r
200                 throw Error("not a valid namespace: "+JSON.stringify(defs));\r
201 \r
202             while (defs.length > 0) {\r
203                 var def = defs.shift(); // Namespaces always contain an array of messages, enums and services\r
204 \r
205                 if (Builder.isMessage(def)) {\r
206                     var obj = new Reflect.Message(this, this.ptr, def["name"], def["options"], def["isGroup"], def["syntax"]);\r
207 \r
208                     // Create OneOfs\r
209                     var oneofs = {};\r
210                     if (def["oneofs"])\r
211                         Object.keys(def["oneofs"]).forEach(function(name) {\r
212                             obj.addChild(oneofs[name] = new Reflect.Message.OneOf(this, obj, name));\r
213                         }, this);\r
214 \r
215                     // Create fields\r
216                     if (def["fields"])\r
217                         def["fields"].forEach(function(fld) {\r
218                             if (obj.getChild(fld["id"]|0) !== null)\r
219                                 throw Error("duplicate or invalid field id in "+obj.name+": "+fld['id']);\r
220                             if (fld["options"] && typeof fld["options"] !== 'object')\r
221                                 throw Error("illegal field options in "+obj.name+"#"+fld["name"]);\r
222                             var oneof = null;\r
223                             if (typeof fld["oneof"] === 'string' && !(oneof = oneofs[fld["oneof"]]))\r
224                                 throw Error("illegal oneof in "+obj.name+"#"+fld["name"]+": "+fld["oneof"]);\r
225                             fld = new Reflect.Message.Field(this, obj, fld["rule"], fld["keytype"], fld["type"], fld["name"], fld["id"], fld["options"], oneof, def["syntax"]);\r
226                             if (oneof)\r
227                                 oneof.fields.push(fld);\r
228                             obj.addChild(fld);\r
229                         }, this);\r
230 \r
231                     // Push children to stack\r
232                     var subObj = [];\r
233                     if (def["enums"])\r
234                         def["enums"].forEach(function(enm) {\r
235                             subObj.push(enm);\r
236                         });\r
237                     if (def["messages"])\r
238                         def["messages"].forEach(function(msg) {\r
239                             subObj.push(msg);\r
240                         });\r
241                     if (def["services"])\r
242                         def["services"].forEach(function(svc) {\r
243                             subObj.push(svc);\r
244                         });\r
245 \r
246                     // Set extension ranges\r
247                     if (def["extensions"]) {\r
248                         if (typeof def["extensions"][0] === 'number') // pre 5.0.1\r
249                             obj.extensions = [ def["extensions"] ];\r
250                         else\r
251                             obj.extensions = def["extensions"];\r
252                     }\r
253 \r
254                     // Create on top of current namespace\r
255                     this.ptr.addChild(obj);\r
256                     if (subObj.length > 0) {\r
257                         stack.push(defs); // Push the current level back\r
258                         defs = subObj; // Continue processing sub level\r
259                         subObj = null;\r
260                         this.ptr = obj; // And move the pointer to this namespace\r
261                         obj = null;\r
262                         continue;\r
263                     }\r
264                     subObj = null;\r
265 \r
266                 } else if (Builder.isEnum(def)) {\r
267 \r
268                     obj = new Reflect.Enum(this, this.ptr, def["name"], def["options"], def["syntax"]);\r
269                     def["values"].forEach(function(val) {\r
270                         obj.addChild(new Reflect.Enum.Value(this, obj, val["name"], val["id"]));\r
271                     }, this);\r
272                     this.ptr.addChild(obj);\r
273 \r
274                 } else if (Builder.isService(def)) {\r
275 \r
276                     obj = new Reflect.Service(this, this.ptr, def["name"], def["options"]);\r
277                     Object.keys(def["rpc"]).forEach(function(name) {\r
278                         var mtd = def["rpc"][name];\r
279                         obj.addChild(new Reflect.Service.RPCMethod(this, obj, name, mtd["request"], mtd["response"], !!mtd["request_stream"], !!mtd["response_stream"], mtd["options"]));\r
280                     }, this);\r
281                     this.ptr.addChild(obj);\r
282 \r
283                 } else if (Builder.isExtend(def)) {\r
284 \r
285                     obj = this.ptr.resolve(def["ref"], true);\r
286                     if (obj) {\r
287                         def["fields"].forEach(function(fld) {\r
288                             if (obj.getChild(fld['id']|0) !== null)\r
289                                 throw Error("duplicate extended field id in "+obj.name+": "+fld['id']);\r
290                             // Check if field id is allowed to be extended\r
291                             if (obj.extensions) {\r
292                                 var valid = false;\r
293                                 obj.extensions.forEach(function(range) {\r
294                                     if (fld["id"] >= range[0] && fld["id"] <= range[1])\r
295                                         valid = true;\r
296                                 });\r
297                                 if (!valid)\r
298                                     throw Error("illegal extended field id in "+obj.name+": "+fld['id']+" (not within valid ranges)");\r
299                             }\r
300                             // Convert extension field names to camel case notation if the override is set\r
301                             var name = fld["name"];\r
302                             if (this.options['convertFieldsToCamelCase'])\r
303                                 name = ProtoBuf.Util.toCamelCase(name);\r
304                             // see #161: Extensions use their fully qualified name as their runtime key and...\r
305                             var field = new Reflect.Message.ExtensionField(this, obj, fld["rule"], fld["type"], this.ptr.fqn()+'.'+name, fld["id"], fld["options"]);\r
306                             // ...are added on top of the current namespace as an extension which is used for\r
307                             // resolving their type later on (the extension always keeps the original name to\r
308                             // prevent naming collisions)\r
309                             var ext = new Reflect.Extension(this, this.ptr, fld["name"], field);\r
310                             field.extension = ext;\r
311                             this.ptr.addChild(ext);\r
312                             obj.addChild(field);\r
313                         }, this);\r
314 \r
315                     } else if (!/\.?google\.protobuf\./.test(def["ref"])) // Silently skip internal extensions\r
316                         throw Error("extended message "+def["ref"]+" is not defined");\r
317 \r
318                 } else\r
319                     throw Error("not a valid definition: "+JSON.stringify(def));\r
320 \r
321                 def = null;\r
322                 obj = null;\r
323             }\r
324             // Break goes here\r
325             defs = null;\r
326             this.ptr = this.ptr.parent; // Namespace done, continue at parent\r
327         }\r
328         this.resolved = false; // Require re-resolve\r
329         this.result = null; // Require re-build\r
330         return this;\r
331     };\r
332 \r
333     /**\r
334      * Propagates syntax to all children.\r
335      * @param {!Object} parent\r
336      * @inner\r
337      */\r
338     function propagateSyntax(parent) {\r
339         if (parent['messages']) {\r
340             parent['messages'].forEach(function(child) {\r
341                 child["syntax"] = parent["syntax"];\r
342                 propagateSyntax(child);\r
343             });\r
344         }\r
345         if (parent['enums']) {\r
346             parent['enums'].forEach(function(child) {\r
347                 child["syntax"] = parent["syntax"];\r
348             });\r
349         }\r
350     }\r
351 \r
352     /**\r
353      * Imports another definition into this builder.\r
354      * @param {Object.<string,*>} json Parsed import\r
355      * @param {(string|{root: string, file: string})=} filename Imported file name\r
356      * @returns {!ProtoBuf.Builder} this\r
357      * @throws {Error} If the definition or file cannot be imported\r
358      * @expose\r
359      */\r
360     BuilderPrototype["import"] = function(json, filename) {\r
361         var delim = '/';\r
362 \r
363         // Make sure to skip duplicate imports\r
364 \r
365         if (typeof filename === 'string') {\r
366 \r
367             if (ProtoBuf.Util.IS_NODE)\r
368                 filename = require("path")['resolve'](filename);\r
369             if (this.files[filename] === true)\r
370                 return this.reset();\r
371             this.files[filename] = true;\r
372 \r
373         } else if (typeof filename === 'object') { // Object with root, file.\r
374 \r
375             var root = filename.root;\r
376             if (ProtoBuf.Util.IS_NODE)\r
377                 root = require("path")['resolve'](root);\r
378             if (root.indexOf("\\") >= 0 || filename.file.indexOf("\\") >= 0)\r
379                 delim = '\\';\r
380             var fname;\r
381             if (ProtoBuf.Util.IS_NODE)\r
382                 fname = require("path")['join'](root, filename.file);\r
383             else\r
384                 fname = root + delim + filename.file;\r
385             if (this.files[fname] === true)\r
386                 return this.reset();\r
387             this.files[fname] = true;\r
388         }\r
389 \r
390         // Import imports\r
391 \r
392         if (json['imports'] && json['imports'].length > 0) {\r
393             var importRoot,\r
394                 resetRoot = false;\r
395 \r
396             if (typeof filename === 'object') { // If an import root is specified, override\r
397 \r
398                 this.importRoot = filename["root"]; resetRoot = true; // ... and reset afterwards\r
399                 importRoot = this.importRoot;\r
400                 filename = filename["file"];\r
401                 if (importRoot.indexOf("\\") >= 0 || filename.indexOf("\\") >= 0)\r
402                     delim = '\\';\r
403 \r
404             } else if (typeof filename === 'string') {\r
405 \r
406                 if (this.importRoot) // If import root is overridden, use it\r
407                     importRoot = this.importRoot;\r
408                 else { // Otherwise compute from filename\r
409                     if (filename.indexOf("/") >= 0) { // Unix\r
410                         importRoot = filename.replace(/\/[^\/]*$/, "");\r
411                         if (/* /file.proto */ importRoot === "")\r
412                             importRoot = "/";\r
413                     } else if (filename.indexOf("\\") >= 0) { // Windows\r
414                         importRoot = filename.replace(/\\[^\\]*$/, "");\r
415                         delim = '\\';\r
416                     } else\r
417                         importRoot = ".";\r
418                 }\r
419 \r
420             } else\r
421                 importRoot = null;\r
422 \r
423             for (var i=0; i<json['imports'].length; i++) {\r
424                 if (typeof json['imports'][i] === 'string') { // Import file\r
425                     if (!importRoot)\r
426                         throw Error("cannot determine import root");\r
427                     var importFilename = json['imports'][i];\r
428                     if (importFilename === "google/protobuf/descriptor.proto")\r
429                         continue; // Not needed and therefore not used\r
430                     if (ProtoBuf.Util.IS_NODE)\r
431                         importFilename = require("path")['join'](importRoot, importFilename);\r
432                     else\r
433                         importFilename = importRoot + delim + importFilename;\r
434                     if (this.files[importFilename] === true)\r
435                         continue; // Already imported\r
436                     if (/\.proto$/i.test(importFilename) && !ProtoBuf.DotProto)       // If this is a light build\r
437                         importFilename = importFilename.replace(/\.proto$/, ".json"); // always load the JSON file\r
438                     var contents = ProtoBuf.Util.fetch(importFilename);\r
439                     if (contents === null)\r
440                         throw Error("failed to import '"+importFilename+"' in '"+filename+"': file not found");\r
441                     if (/\.json$/i.test(importFilename)) // Always possible\r
442                         this["import"](JSON.parse(contents+""), importFilename); // May throw\r
443                     else\r
444                         this["import"](ProtoBuf.DotProto.Parser.parse(contents), importFilename); // May throw\r
445                 } else // Import structure\r
446                     if (!filename)\r
447                         this["import"](json['imports'][i]);\r
448                     else if (/\.(\w+)$/.test(filename)) // With extension: Append _importN to the name portion to make it unique\r
449                         this["import"](json['imports'][i], filename.replace(/^(.+)\.(\w+)$/, function($0, $1, $2) { return $1+"_import"+i+"."+$2; }));\r
450                     else // Without extension: Append _importN to make it unique\r
451                         this["import"](json['imports'][i], filename+"_import"+i);\r
452             }\r
453             if (resetRoot) // Reset import root override when all imports are done\r
454                 this.importRoot = null;\r
455         }\r
456 \r
457         // Import structures\r
458 \r
459         if (json['package'])\r
460             this.define(json['package']);\r
461         if (json['syntax'])\r
462             propagateSyntax(json);\r
463         var base = this.ptr;\r
464         if (json['options'])\r
465             Object.keys(json['options']).forEach(function(key) {\r
466                 base.options[key] = json['options'][key];\r
467             });\r
468         if (json['messages'])\r
469             this.create(json['messages']),\r
470             this.ptr = base;\r
471         if (json['enums'])\r
472             this.create(json['enums']),\r
473             this.ptr = base;\r
474         if (json['services'])\r
475             this.create(json['services']),\r
476             this.ptr = base;\r
477         if (json['extends'])\r
478             this.create(json['extends']);\r
479 \r
480         return this.reset();\r
481     };\r
482 \r
483     /**\r
484      * Resolves all namespace objects.\r
485      * @throws {Error} If a type cannot be resolved\r
486      * @returns {!ProtoBuf.Builder} this\r
487      * @expose\r
488      */\r
489     BuilderPrototype.resolveAll = function() {\r
490         // Resolve all reflected objects\r
491         var res;\r
492         if (this.ptr == null || typeof this.ptr.type === 'object')\r
493             return this; // Done (already resolved)\r
494 \r
495         if (this.ptr instanceof Reflect.Namespace) { // Resolve children\r
496 \r
497             this.ptr.children.forEach(function(child) {\r
498                 this.ptr = child;\r
499                 this.resolveAll();\r
500             }, this);\r
501 \r
502         } else if (this.ptr instanceof Reflect.Message.Field) { // Resolve type\r
503 \r
504             if (!Lang.TYPE.test(this.ptr.type)) {\r
505                 if (!Lang.TYPEREF.test(this.ptr.type))\r
506                     throw Error("illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type);\r
507                 res = (this.ptr instanceof Reflect.Message.ExtensionField ? this.ptr.extension.parent : this.ptr.parent).resolve(this.ptr.type, true);\r
508                 if (!res)\r
509                     throw Error("unresolvable type reference in "+this.ptr.toString(true)+": "+this.ptr.type);\r
510                 this.ptr.resolvedType = res;\r
511                 if (res instanceof Reflect.Enum) {\r
512                     this.ptr.type = ProtoBuf.TYPES["enum"];\r
513                     if (this.ptr.syntax === 'proto3' && res.syntax !== 'proto3')\r
514                         throw Error("proto3 message cannot reference proto2 enum");\r
515                 }\r
516                 else if (res instanceof Reflect.Message)\r
517                     this.ptr.type = res.isGroup ? ProtoBuf.TYPES["group"] : ProtoBuf.TYPES["message"];\r
518                 else\r
519                     throw Error("illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type);\r
520             } else\r
521                 this.ptr.type = ProtoBuf.TYPES[this.ptr.type];\r
522 \r
523             // If it's a map field, also resolve the key type. The key type can be only a numeric, string, or bool type\r
524             // (i.e., no enums or messages), so we don't need to resolve against the current namespace.\r
525             if (this.ptr.map) {\r
526                 if (!Lang.TYPE.test(this.ptr.keyType))\r
527                     throw Error("illegal key type for map field in "+this.ptr.toString(true)+": "+this.ptr.keyType);\r
528                 this.ptr.keyType = ProtoBuf.TYPES[this.ptr.keyType];\r
529             }\r
530 \r
531             // If it's a repeated and packable field then proto3 mandates it should be packed by\r
532             // default\r
533             if (\r
534               this.ptr.syntax === 'proto3' &&\r
535               this.ptr.repeated && this.ptr.options.packed === undefined &&\r
536               ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.ptr.type.wireType) !== -1\r
537             ) {\r
538               this.ptr.options.packed = true;\r
539             }\r
540 \r
541         } else if (this.ptr instanceof ProtoBuf.Reflect.Service.Method) {\r
542 \r
543             if (this.ptr instanceof ProtoBuf.Reflect.Service.RPCMethod) {\r
544                 res = this.ptr.parent.resolve(this.ptr.requestName, true);\r
545                 if (!res || !(res instanceof ProtoBuf.Reflect.Message))\r
546                     throw Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.requestName);\r
547                 this.ptr.resolvedRequestType = res;\r
548                 res = this.ptr.parent.resolve(this.ptr.responseName, true);\r
549                 if (!res || !(res instanceof ProtoBuf.Reflect.Message))\r
550                     throw Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.responseName);\r
551                 this.ptr.resolvedResponseType = res;\r
552             } else // Should not happen as nothing else is implemented\r
553                 throw Error("illegal service type in "+this.ptr.toString(true));\r
554 \r
555         } else if (\r
556             !(this.ptr instanceof ProtoBuf.Reflect.Message.OneOf) && // Not built\r
557             !(this.ptr instanceof ProtoBuf.Reflect.Extension) && // Not built\r
558             !(this.ptr instanceof ProtoBuf.Reflect.Enum.Value) // Built in enum\r
559         )\r
560             throw Error("illegal object in namespace: "+typeof(this.ptr)+": "+this.ptr);\r
561 \r
562         return this.reset();\r
563     };\r
564 \r
565     /**\r
566      * Builds the protocol. This will first try to resolve all definitions and, if this has been successful,\r
567      * return the built package.\r
568      * @param {(string|Array.<string>)=} path Specifies what to return. If omitted, the entire namespace will be returned.\r
569      * @returns {!ProtoBuf.Builder.Message|!Object.<string,*>}\r
570      * @throws {Error} If a type could not be resolved\r
571      * @expose\r
572      */\r
573     BuilderPrototype.build = function(path) {\r
574         this.reset();\r
575         if (!this.resolved)\r
576             this.resolveAll(),\r
577             this.resolved = true,\r
578             this.result = null; // Require re-build\r
579         if (this.result === null) // (Re-)Build\r
580             this.result = this.ns.build();\r
581         if (!path)\r
582             return this.result;\r
583         var part = typeof path === 'string' ? path.split(".") : path,\r
584             ptr = this.result; // Build namespace pointer (no hasChild etc.)\r
585         for (var i=0; i<part.length; i++)\r
586             if (ptr[part[i]])\r
587                 ptr = ptr[part[i]];\r
588             else {\r
589                 ptr = null;\r
590                 break;\r
591             }\r
592         return ptr;\r
593     };\r
594 \r
595     /**\r
596      * Similar to {@link ProtoBuf.Builder#build}, but looks up the internal reflection descriptor.\r
597      * @param {string=} path Specifies what to return. If omitted, the entire namespace wiil be returned.\r
598      * @param {boolean=} excludeNonNamespace Excludes non-namespace types like fields, defaults to `false`\r
599      * @returns {?ProtoBuf.Reflect.T} Reflection descriptor or `null` if not found\r
600      */\r
601     BuilderPrototype.lookup = function(path, excludeNonNamespace) {\r
602         return path ? this.ns.resolve(path, excludeNonNamespace) : this.ns;\r
603     };\r
604 \r
605     /**\r
606      * Returns a string representation of this object.\r
607      * @return {string} String representation as of "Builder"\r
608      * @expose\r
609      */\r
610     BuilderPrototype.toString = function() {\r
611         return "Builder";\r
612     };\r
613 \r
614     // ----- Base classes -----\r
615     // Exist for the sole purpose of being able to "... instanceof ProtoBuf.Builder.Message" etc.\r
616 \r
617     /**\r
618      * @alias ProtoBuf.Builder.Message\r
619      */\r
620     Builder.Message = function() {};\r
621 \r
622     /**\r
623      * @alias ProtoBuf.Builder.Enum\r
624      */\r
625     Builder.Enum = function() {};\r
626 \r
627     /**\r
628      * @alias ProtoBuf.Builder.Message\r
629      */\r
630     Builder.Service = function() {};\r
631 \r
632     return Builder;\r
633 \r
634 })(ProtoBuf, ProtoBuf.Lang, ProtoBuf.Reflect);\r