Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
4 changed files
with
347 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
var Variables = require('../variables') | ||
var explode = require('../explode') | ||
var qualify = require('../qualify') | ||
var $ = require('programmatic') | ||
var joinSources = require('../join-sources') | ||
|
||
Generator.prototype.integer = function (field, property) { | ||
var bites = [], bite = field.bite, stop = field.stop, shift | ||
while (bite != stop) { | ||
var value = bite ? 'value >>> ' + bite * 8 : 'value' | ||
bites.push('buffer[start++] = ' + value + ' & 0xff') | ||
bite += field.direction | ||
} | ||
bites = bites.join('\n') | ||
var direction = field.little ? '++' : '--' | ||
return $(' \n\ | ||
case ' + (this.step++) + ': \n\ | ||
// __blank__ \n\ | ||
this.step = ' + this.step + ' \n\ | ||
this.bite = ' + field.bite + ' \n\ | ||
// __blank__ \n\ | ||
case ' + (this.step++) + ': \n\ | ||
// __blank__ \n\ | ||
while (this.bite != ' + field.stop + ') { \n\ | ||
if (start == end) { \n\ | ||
engine.start = start \n\ | ||
return \n\ | ||
} \n\ | ||
buffer[start++] = ' + property + ' >>> this.bite * 8 & 0xff \n\ | ||
this.bite', direction, ' \n\ | ||
} \n\ | ||
// __blank__ \n\ | ||
this.step = ' + this.step + ' \n\ | ||
') | ||
} | ||
|
||
Generator.prototype.construct = function (definition) { | ||
var fields = [] | ||
for (var name in definition) { | ||
if (name[0] === '$') { | ||
continue | ||
} | ||
var field = definition[name] | ||
if (Array.isArray(field)) { | ||
fields.push(name + ': new Array') | ||
} else { | ||
fields.push(name + ': null') | ||
} | ||
} | ||
return fields.join(',\n') | ||
} | ||
|
||
Generator.prototype.nested = function (definition) { | ||
return $(' \n\ | ||
', this.serialize(definition), ' \n\ | ||
') | ||
} | ||
|
||
Generator.prototype.lengthEncoded = function (name, field, depth) { | ||
var source = '' | ||
var length = qualify('length', depth) | ||
var object = qualify('object', depth) | ||
var subObject = qualify('object', depth + 1) | ||
var i = qualify('i', depth) | ||
this.variables.hoist(i) | ||
this.variables.hoist(length) | ||
this.forever = true | ||
var step = this.step + 2 | ||
source = $(' \n\ | ||
// __reference__ \n\ | ||
', this.integer(explode(field.$length), 'frame.object.' + name + '.length'), '\n\ | ||
// __blank__ \n\ | ||
case ' + (this.step++) + ': \n\ | ||
// __blank__ \n\ | ||
this.stack.push(frame = {\n\ | ||
object: frame.object.' + name + '[frame.index], \n\ | ||
index: 0 \n\ | ||
}) \n\ | ||
this.step = ' + this.step + ' \n\ | ||
// __blank__ \n\ | ||
', this.nested(field), ' \n\ | ||
// __blank__ \n\ | ||
this.stack.pop() \n\ | ||
frame = this.stack[this.stack.length - 1] \n\ | ||
if (++frame.index != frame.object.' + name + '.length) { \n\ | ||
this.step = ' + step + ' \n\ | ||
continue \n\ | ||
} \n\ | ||
') | ||
return source | ||
} | ||
|
||
Generator.prototype.serialize = function (definition) { | ||
var sources = [] | ||
for (var name in definition) { | ||
if (name[0] === '$') { | ||
continue | ||
} | ||
var field = definition[name] | ||
if (Array.isArray(field)) { | ||
field = field[0] | ||
if (field.$length) { | ||
sources.push(this.lengthEncoded(name, field)) | ||
} | ||
} else { | ||
field = explode(field) | ||
if (field.type === 'integer') { | ||
sources.push(this.integer(field, 'frame.object.' + name)) | ||
} | ||
} | ||
} | ||
return joinSources(sources) | ||
} | ||
|
||
function parser (name, definition) { | ||
return new Generator(name, definition).generate() | ||
} | ||
|
||
function Generator (name, definition) { | ||
this.step = 0 | ||
this.name = name | ||
this.definition = definition | ||
this.variables = new Variables | ||
} | ||
|
||
Generator.prototype.generate = function () { | ||
var source = this.serialize(this.definition) | ||
var dispatch = $(' \n\ | ||
switch (this.step) { \n\ | ||
', source, ' \n\ | ||
} \n\ | ||
') | ||
if (this.forever) { | ||
dispatch = $(' \n\ | ||
for (;;) { \n\ | ||
', dispatch, ' \n\ | ||
engine.start = start \n\ | ||
return \n\ | ||
} \n\ | ||
') | ||
} | ||
return $(' \n\ | ||
serializers.' + this.name + ' = function (object) { \n\ | ||
this.step = 0 \n\ | ||
this.bite = 0 \n\ | ||
this.stop = 0 \n\ | ||
this.stack = [{ \n\ | ||
object: object, \n\ | ||
index: 0, \n\ | ||
length: 0 \n\ | ||
}] \n\ | ||
} \n\ | ||
// __blank__ \n\ | ||
serializers.' + this.name + '.prototype.serialize = function (engine) { \n\ | ||
var buffer = engine.buffer \n\ | ||
var start = engine.start \n\ | ||
var end = engine.end \n\ | ||
// __blank__ \n\ | ||
var frame = this.stack[this.stack.length - 1] \n\ | ||
// __blank__ \n\ | ||
', String(this.variables), ' \n\ | ||
// __blank__ \n\ | ||
', dispatch, ' \n\ | ||
// __blank__ \n\ | ||
engine.start = start \n\ | ||
// __blank__ \n\ | ||
return frame.object \n\ | ||
} \n\ | ||
') | ||
} | ||
|
||
module.exports = function (compiler, definition) { | ||
var source = $(' \n\ | ||
var serializers = {} \n\ | ||
') | ||
Object.keys(definition).forEach(function (packet) { | ||
source = $(' \n\ | ||
', source, ' \n\ | ||
// __blank__ \n\ | ||
', parser(packet, definition[packet]), ' \n\ | ||
') | ||
}) | ||
source = $(' \n\ | ||
', source, ' \n\ | ||
// __blank__ \n\ | ||
return serializers \n\ | ||
') | ||
return compiler(source) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
module.exports = (function () { | ||
var serializers = {} | ||
|
||
serializers.object = function (object) { | ||
this.step = 0 | ||
this.bite = 0 | ||
this.stop = 0 | ||
this.stack = [{ | ||
object: object, | ||
index: 0, | ||
length: 0 | ||
}] | ||
} | ||
|
||
serializers.object.prototype.serialize = function (engine) { | ||
var buffer = engine.buffer | ||
var start = engine.start | ||
var end = engine.end | ||
|
||
var frame = this.stack[this.stack.length - 1] | ||
|
||
var i | ||
var length | ||
|
||
for (;;) { | ||
switch (this.step) { | ||
case 0: | ||
|
||
this.step = 1 | ||
this.bite = 1 | ||
|
||
case 1: | ||
|
||
while (this.bite != -1) { | ||
if (start == end) { | ||
engine.start = start | ||
return | ||
} | ||
buffer[start++] = frame.object.values.length >>> this.bite * 8 & 0xff | ||
this.bite-- | ||
} | ||
|
||
this.step = 2 | ||
|
||
case 2: | ||
|
||
this.stack.push(frame = { | ||
object: frame.object.values[frame.index], | ||
index: 0 | ||
}) | ||
this.step = 3 | ||
|
||
case 3: | ||
|
||
this.step = 4 | ||
this.bite = 1 | ||
|
||
case 4: | ||
|
||
while (this.bite != -1) { | ||
if (start == end) { | ||
engine.start = start | ||
return | ||
} | ||
buffer[start++] = frame.object.key >>> this.bite * 8 & 0xff | ||
this.bite-- | ||
} | ||
|
||
this.step = 5 | ||
|
||
case 5: | ||
|
||
this.step = 6 | ||
this.bite = 1 | ||
|
||
case 6: | ||
|
||
while (this.bite != -1) { | ||
if (start == end) { | ||
engine.start = start | ||
return | ||
} | ||
buffer[start++] = frame.object.value >>> this.bite * 8 & 0xff | ||
this.bite-- | ||
} | ||
|
||
this.step = 7 | ||
|
||
this.stack.pop() | ||
frame = this.stack[this.stack.length - 1] | ||
if (++frame.index != frame.object.values.length) { | ||
this.step = 2 | ||
continue | ||
} | ||
} | ||
engine.start = start | ||
return | ||
} | ||
|
||
engine.start = start | ||
|
||
return frame.object | ||
} | ||
|
||
return serializers | ||
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
require('proof')(20, prove) | ||
|
||
function prove (assert) { | ||
var path = require('path') | ||
var compiler = require('../../../compiler/require') | ||
var composer = require('../../../compose/serializer/inc.js') | ||
var filename = path.resolve(__filename, '../../../generated/array-of-objects.serialize.inc.js') | ||
|
||
var serializers = composer(compiler(filename), { | ||
object: { | ||
values: [{ | ||
$length: { | ||
endianess: 'b', | ||
bits: 16 | ||
}, | ||
key: { | ||
endianess: 'b', | ||
bits: 16 | ||
}, | ||
value: { | ||
endianess: 'b', | ||
bits: 16 | ||
} | ||
}] | ||
} | ||
}) | ||
var bufferLength = 10 | ||
for (var i = 0; i < bufferLength; i++) { | ||
var buffer = new Buffer(bufferLength) | ||
var object = { | ||
values: [ { key: 2570, value: 1 }, { key: 2, value: 3 } ] | ||
} | ||
var engine = { | ||
buffer: buffer, | ||
start: 0, | ||
end: bufferLength - i | ||
} | ||
var serializer = new serializers.object(object) | ||
serializer.serialize(engine) | ||
var engine = { | ||
buffer: buffer, | ||
start: bufferLength - i, | ||
end: bufferLength | ||
} | ||
serializer.serialize(engine) | ||
assert(engine.buffer.toJSON(), [ | ||
0x0, 0x2, 0xa, 0xa, 0x0, 0x1, 0x0, 0x2, 0x0, 0x3 | ||
], 'compiled') | ||
assert(engine.start, buffer.length, 'start moved') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters