Skip to content

Commit

Permalink
Made the insertion points optional and fixed Json generator
Browse files Browse the repository at this point in the history
  • Loading branch information
drslump committed Oct 4, 2011
1 parent 5c9fa1c commit faa153e
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 117 deletions.
9 changes: 9 additions & 0 deletions library/DrSlump/Protobuf/Compiler/Cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ public static function runProtoc($pluginExecutable)
$args['options'][$parts[0]] = $parts[1];
}
}
if ($result->options['insertions']) {
$args['options']['insertions'] = 1;
}

$cmd[] = '--php_out=' .
escapeshellarg(
Expand Down Expand Up @@ -203,6 +206,12 @@ public static function parseArguments()
'description' => 'port .proto comments to generated code',
));

$main->addOption('insertions', array(
'long_name' => '--insertions',
'action' => 'StoreTrue',
'description' => 'generate @@protoc insertion points',
));

$main->addOption('define', array(
'short_name' => '-D',
'long_name' => '--define',
Expand Down
283 changes: 185 additions & 98 deletions library/DrSlump/Protobuf/Compiler/JsonGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,164 @@

class JsonGenerator extends AbstractGenerator
{
public function getNamespace(proto\FileDescriptorProto $proto)
/**
* Get an option from the compiler arguments or from the proto file.
*
* @param string $name
* @return string|null
*/
protected function getOption($name)
{
$namespace = $proto->getPackage();
$opts = $proto->getOptions();
if (isset($opts['json.package'])) {
$namespace = $opts['jsonpackage'];
$opt = $this->compiler->getOption($name);

if (NULL === $opt) {
$opts = $this->proto->getOptions();
if (!empty($opts) && isset($opts['json.' . $name])) {
$opt = $opts['json.' . $name];
}
}
if (isset($opts['json.namespace'])) {

return $opt;
}


public function getNamespace(proto\FileDescriptorProto $proto = NULL)
{
$proto = $proto ?: $this->proto;

$opts = $proto->getOptions();
if ($this->compiler->getOption('namespace')) {
$namespace = $this->compiler->getOption('namespace');
} else if (isset($opts['json.namespace'])) {
$namespace = $opts['json.namespace'];
} else if (isset($opts['json.package'])) {
$namespace = $opts['json.package'];
} else {
$namespace = parent::getNamespace($proto);
}

$namespace = trim($namespace, '.');
return $namespace;
}


public function generate(proto\FileDescriptorProto $proto)
{
parent::generate($proto);



}

protected function buildFile(proto\FileDescriptorProto $proto, $fname, $contents)
{
$suffix = $this->getOption('suffix') ?: '.js';
$fname .= $suffix;

$file = new \google\protobuf\compiler\CodeGeneratorResponse\File();
$file->setName($fname);

$s = array();
$s[]= "// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin " . Protobuf::VERSION;
$s[]= "// Source: " . $proto->getName();
$s[]= "// Date: " . gmdate('Y-m-d H:i:s');
$s[]= "";
$s[]= "// @@protoc_insertion_point(scope_file)";
$s[]= "";
$s[]= "(function(){";
$s[]= "";
$s[]= " /** @namespace */";
$s[]= " var $namespace = $namespace || {};";
$s[]= "";
$s[]= " // Make it CommonJS compatible";
$s[]= " if (typeof exports !== 'undefined') {";
$s[]= " var ProtoJson = this.ProtoJson;";
$s[]= " if (!ProtoJson && typeof require !== 'undefined') {";
$s[]= " ProtoJson = require('ProtoJson');";
$s[]= " }";
$s[]= " $namespace = exports;";
$s[]= " } else {";
$s[]= " this.$namespace = $namespace;";
$s[]= " }";
$s[]= "";
$s[]= $contents;
$s[]= "";
$s[]= "})();";
$s[]= "";

$contents = implode(PHP_EOL, $s) . PHP_EOL . $contents;
$file->setContent($contents);
return $file;
}

public function compileProtoFile(proto\FileDescriptorProto $proto)
{
$file = new \google\protobuf\compiler\CodeGeneratorResponse\File();

$opts = $proto->getOptions();
$name = pathinfo($proto->getName(), PATHINFO_FILENAME);
$name .= isset($opts['json.suffix'])
? $opts['json.suffix']
: '.js';
$file->setName($name);

$namespace = $this->getNamespace($proto);

$s[]= "// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin " . Protobuf::VERSION;
$s[]= "// Source: " . $proto->getName();
$s[]= "// Date: " . date('Y-m-d H:i:s');
$s[]= "";

$s[]= "(function(){";
$s[]= "/** @namespace */";
$s[]= "var $namespace = $namespace || {};";
$s[]= "";
$s[]= "// Make it CommonJS compatible";
$s[]= "if (typeof exports !== 'undefined') {";
$s[]= " var ProtoJson = this.ProtoJson;";
$s[]= " if (!ProtoJson && typeof require !== 'undefined')";
$s[]= " ProtoJson = require('ProtoJson');";
$s[]= " $namespace = exports;";
$s[]= "} else {";
$s[]= " this.$namespace = $namespace;";
$s[]= "}";
$s[]= "";


// Generate Enums
foreach ($proto->getEnumTypeList() as $enum) {
$s[]= $this->compileEnum($enum, $namespace);
}

// Generate Messages
foreach ($proto->getMessageTypeList() as $msg) {
$s[] = $this->compileMessage($msg, $namespace);
}

// Collect extensions
if ($proto->hasExtension()) {
foreach ($proto->getExtensionList() as $field) {
$this->extensions[$field->getExtendee()][] = array($namespace, $field);
}
}

// Dump all extensions found in this proto file
if (count($this->extensions)) {
foreach ($this->extensions as $extendee => $fields) {
foreach ($fields as $pair) {
list($ns, $field) = $pair;
$s[]= $this->compileExtension($field, $ns, '');
}
}
}

$s[]= "})();";

$src = implode("\n", $s);
$file->setContent($src);
return array($file);
}

public function compileEnum(proto\EnumDescriptorProto $enum, $namespace)
{
$s[]= "$namespace.$enum->name = {";
Expand Down Expand Up @@ -103,73 +246,6 @@ public function compileMessage(proto\DescriptorProto $msg, $namespace)
return implode("\n", $s);
}

public function compileProtoFile(proto\FileDescriptorProto $proto)
{
$file = new proto\compiler\CodeGeneratorResponse\File();

$opts = $proto->getOptions();
$name = pathinfo($proto->getName(), PATHINFO_FILENAME);
$name .= isset($opts['json.suffix'])
? $opts['json.suffix']
: '.js';
$file->setName($name);

$namespace = $this->getNamespace($proto);

$s[]= "// DO NOT EDIT! Generated by Protobuf for PHP protoc plugin " . Protobuf::VERSION;
$s[]= "// Source: " . $proto->getName();
$s[]= "// Date: " . date('Y-m-d H:i:s');
$s[]= "";

$s[]= "(function(){";
$s[]= "/** @namespace */";
$s[]= "var $namespace = $namespace || {};";
$s[]= "";
$s[]= "// Make it CommonJS compatible";
$s[]= "if (typeof exports !== 'undefined') {";
$s[]= " var ProtoJson = this.ProtoJson;";
$s[]= " if (!ProtoJson && typeof require !== 'undefined')";
$s[]= " ProtoJson = require('ProtoJson');";
$s[]= " $namespace = exports;";
$s[]= "} else {";
$s[]= " this.$namespace = $namespace;";
$s[]= "}";
$s[]= "";


// Generate Enums
foreach ($proto->getEnumTypeList() as $enum) {
$s[]= $this->compileEnum($enum, $namespace);
}

// Generate Messages
foreach ($proto->getMessageTypeList() as $msg) {
$s[] = $this->compileMessage($msg, $namespace);
}

// Collect extensions
if ($proto->hasExtension()) {
foreach ($proto->getExtensionList() as $field) {
$this->extensions[$field->getExtendee()][] = array($namespace, $field);
}
}

// Dump all extensions found in this proto file
if (count($this->extensions)) {
foreach ($this->extensions as $extendee => $fields) {
foreach ($fields as $pair) {
list($ns, $field) = $pair;
$s[]= $this->compileExtension($field, $ns, '');
}
}
}

$s[]= "})();";

$src = implode("\n", $s);
$file->setContent($src);
return array($file);
}

public function generateField(proto\FieldDescriptorProto $field)
{
Expand All @@ -179,7 +255,7 @@ public function generateField(proto\FieldDescriptorProto $field)
if (substr($reference, 0, 1) !== '.') {
throw new \RuntimeException('Only fully qualified names are supported: ' . $reference);
}
$reference = "'" . $this->normalizeReference($reference) . "'";
$reference = "'" . $this->normalizeNS($reference) . "'";
}

$default = 'null';
Expand All @@ -192,7 +268,7 @@ public function generateField(proto\FieldDescriptorProto $field)
$default = '"' . addcslashes($field->getDefaultValue(), '"\\') . '"';
break;
case Protobuf::TYPE_ENUM:
$default = $this->normalizeReference($field->getTypeName()) . '.' . $field->getDefaultValue();
$default = $this->normalizeNS($field->getTypeName()) . '.' . $field->getDefaultValue();
break;
default: // Numbers
$default = $field->getDefaultValue();
Expand All @@ -213,7 +289,7 @@ public function generateField(proto\FieldDescriptorProto $field)

public function generateAccessors($field, $namespace)
{
$camel = $this->comp->camelize(ucfirst($field->getName()));
$camel = $this->compiler->camelize(ucfirst($field->getName()));

$s[]= "/**";
$s[]= " * Check <$field->name> value";
Expand Down Expand Up @@ -316,38 +392,49 @@ public function getJsDoc(proto\FieldDescriptorProto $field)
case Protobuf::TYPE_STRING:
return 'String';
case Protobuf::TYPE_MESSAGE:
return $this->normalizeReference($field->getTypeName());
return $this->normalizeNS($field->getTypeName());
case Protobuf::TYPE_BYTES:
return 'String';
case Protobuf::TYPE_ENUM:
return 'Int (' . $this->normalizeReference($field->getTypeName()) . ')';
return 'Int (' . $this->normalizeNS($field->getTypeName()) . ')';

case Protobuf::TYPE_GROUP:
default:
return 'unknown';
}
}

public function normalizeReference($reference)

protected function normalizeNS($package)
{
// Remove leading dot
$reference = ltrim($reference, '.');

if (!$this->comp->hasPackage($reference)) {
$found = false;
foreach ($this->comp->getPackages() as $package=>$namespace) {
if (0 === strpos($reference, $package.'.')) {
$reference = $namespace . substr($reference, strlen($package));
$found = true;
}
}
if (!$found) {
$this->comp->warning('Non tracked package name found "' . $reference . '"');
}
} else {
$reference = $this->comp->getPackage($reference);
}

return $reference;
// Remove leading dot (used in references)
$package = ltrim($package, '.');

if ($this->compiler->hasPackage($package)) {
return $this->compiler->getPackage($package);
}

// Check the currently registered packages to find a root one
$found = null;
foreach ($this->compiler->getPackages() as $pkg=>$ns) {
// Keep only the longest match
if (0 === strpos($package, $pkg.'.') && strlen($found) < strlen($pkg)) {
$found = $pkg;
}
}

// If no matching package was found issue a warning and use the package name
if (!$found) {
$this->compiler->warning('Non tracked package name found "' . $package . '"');
$namespace = $package;
} else {
// Complete the namespace with the remaining package
$namespace = $this->compiler->getPackage($found);
$namespace .= substr($package, strlen($found));
// Set the newly found namespace in the registry
$this->compiler->setPackage($package, $namespace);
}

return $namespace;
}
}
Loading

0 comments on commit faa153e

Please sign in to comment.