Skip to content

Commit

Permalink
add proto compiler implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mourner committed Feb 5, 2015
1 parent ea0a20d commit 99dc619
Showing 1 changed file with 147 additions and 0 deletions.
147 changes: 147 additions & 0 deletions bin/pbf
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#!/usr/bin/env node

'use strict';

var resolve = require('resolve-protobuf-schema');

if (process.argv.length > 2) {
console.log('\'use strict\';');
compileMessages(resolve.sync(process.argv[2]), 'exports', {},
process.argv.indexOf('--no-read') === -1,
process.argv.indexOf('--no-write') === -1);
}

function compileMessage(message, parentName, enums, read, write) {
var name = message.name,
nameLow = name.toLowerCase();

console.log('\n// %s ========================================\n', name);

var methods = [];
if (read) methods.push('read: read' + name);
if (write) methods.push('write: write' + name);

console.log((message.messages.length ? 'var ' + name + ' = ' : '') +
'%s.%s = {%s};\n', parentName, name, methods.join(', '));

if (message.enums.length) {
for (var i = 0; i < message.enums.length; i++) {
var en = message.enums[i];
enums[en.name] = true;
console.log('%s.%s = ' + JSON.stringify(en.values, null, 4) + ';\n', name, en.name);
}
}

if (read) {
console.log('function read%s(pbf, end) {', name);
console.log(' var %s = pbf.readFields(read%sField, %s, end);', nameLow, name, repeatedDest(message.fields));
for (var i = 0; i < message.fields.length; i++) {
var field = message.fields[i];
if (enums[field.type] && field.options['default'] !== undefined) {
console.log(' if (%s.%s === undefined) %s.%s = ' + JSON.stringify(field.options['default']) + ';',
nameLow, field.name, nameLow, field.name);
}
}
console.log(' return %s;', nameLow);
console.log('}');

console.log('function read%sField(tag, %s, pbf) {', name, nameLow);

for (var i = 0; i < message.fields.length; i++) {
var field = message.fields[i];
console.log(' ' + (i ? 'else if' : 'if') + ' (tag === %d) %s.%s = %s;',
field.tag, nameLow, field.name, readMethod(field, enums));
}
console.log('}');
}

if (read && write) console.log('');

if (write) {
console.log('function write%s(%s, pbf) {', name, nameLow);
var iDeclared;
for (var i = 0; i < message.fields.length; i++) {
var field = message.fields[i];
if (!iDeclared && field.repeated) {
console.log(' var i;');
iDeclared = true;
}
console.log(' if (%s.%s !== undefined) %s;', nameLow, field.name,
writeMethod(field.tag, field.type, nameLow + '.' + field.name,
field.repeated, field.options.packed, enums));
}
console.log('}');
}

compileMessages(message, name, enums, read, write);
}

function compileMessages(parent, parentName, enums, read, write) {
for (var i = 0; i < parent.messages.length; i++) {
compileMessage(parent.messages[i], parentName, enums, read, write);
}
}

function repeatedDest(fields) {
var repeated = [];
for (var i = 0; i < fields.length; i++) {
if (fields[i].repeated) repeated.push('"' + fields[i].name + '": []');
}
return '{' + repeated.join(', ') + '}';
}

function readMethod(field, enums) {
switch (field.type) {
case 'string': return 'pbf.readString()';
case 'float': return 'pbf.readFloat()';
case 'double': return 'pbf.readDouble()';
case 'bool': return 'pbf.readBoolean()';
case 'enum':
case 'uint32':
case 'uint64':
case 'int32':
case 'int64': return 'pbf.readVarint()';
case 'sint32':
case 'sint64': return 'pbf.readSVarint()';
case 'fixed32': return 'pbf.readFixed32()';
case 'fixed64': return 'pbf.readFixed64()';
case 'sfixed32': return 'pbf.readSFixed32()';
case 'sfixed64': return 'pbf.readSFixed64()';
case 'bytes': return 'pbf.readBytes()';
default: return enums[field.type] ? 'pbf.readVarint()' :
'read' + field.type + '(pbf, pbf.readVarint() + pbf.pos)';
}
}

function writeMethod(tag, type, name, repeated, packed) {
if (repeated) return repeatedWriteMethod(tag, type, name);

var prefix = 'pbf.write';
if (packed) prefix += 'Packed';

var postfix = '(' + tag + ', ' + name + ')';

switch (type) {
case 'string': return prefix + 'String' + postfix;
case 'float': return prefix + 'Float' + postfix;
case 'double': return prefix + 'Double' + postfix;
case 'bool': return prefix + 'Boolean' + postfix;
case 'enum':
case 'uint32':
case 'uint64':
case 'int32':
case 'int64': return prefix + 'Varint' + postfix;
case 'sint32':
case 'sint64': return prefix + 'SVarint' + postfix;
case 'fixed32': return prefix + 'Fixed32' + postfix;
case 'fixed64': return prefix + 'Fixed64' + postfix;
case 'sfixed32': return prefix + 'SFixed32' + postfix;
case 'sfixed64': return prefix + 'SFixed64' + postfix;
case 'bytes': return prefix + 'Bytes' + postfix;
default: return prefix + 'Message(' + tag + ', write' + type + ', ' + name + ')';
}
}

function repeatedWriteMethod(tag, type, name) {
return 'for (i = 0; i < ' + name + '.length; i++) ' + writeMethod(tag, type, name + '[i]');
}

0 comments on commit 99dc619

Please sign in to comment.