public function compileMessage(proto\DescriptorProto $msg, $namespace)
 {
     $s[] = "/**";
     $s[] = " * @constructor";
     $s[] = " * @augments {ProtoJson.Message}";
     $s[] = " * @extends ProtoJson.Message";
     $s[] = " * @memberOf {$namespace}";
     $s[] = " * @param {object} data - Optional, provide initial data to parse";
     $s[] = " */";
     $s[] = "{$namespace}.{$msg->name} = ProtoJson.create({";
     $s[] = "  fields: {";
     $lines = array();
     foreach ($msg->getFieldList() as $field) {
         $lines[] = "    {$field->number}: " . $this->generateField($field);
     }
     $s[] = implode(",\n", $lines);
     $s[] = "  },";
     $s[] = "  ranges: [";
     // @todo dump extension ranges
     $s[] = "  ]";
     $s[] = "});";
     $s[] = "";
     // Compute a new namespace with the message name as suffix
     $namespace .= "." . $msg->getName();
     // Generate getters/setters
     foreach ($msg->getFieldList() as $field) {
         $s[] = $this->generateAccessors($field, $namespace);
     }
     // Generate Enums
     foreach ($msg->getEnumTypeList() as $enum) {
         $s[] = $this->compileEnum($enum, $namespace);
     }
     // Generate nested messages
     foreach ($msg->getNestedTypeList() as $msg) {
         $s[] = $this->compileMessage($msg, $namespace);
     }
     // Collect extensions
     foreach ($msg->getExtensionList() as $field) {
         $this->extensions[$field->getExtendee()][] = array($namespace, $field);
     }
     return implode("\n", $s);
 }