Skip to content

Commit

Permalink
Sketch of BFF nested parser.
Browse files Browse the repository at this point in the history
  • Loading branch information
flatheadmill committed Oct 16, 2016
1 parent 38980e2 commit 9a8ec08
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 13 deletions.
52 changes: 39 additions & 13 deletions compose/parser/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var joinSources = require('../join-sources')
var $ = require('programmatic')

function Generator () {
this.step = 0
}

Generator.prototype.integer = function (field, assignee) {
Expand All @@ -20,6 +21,7 @@ Generator.prototype.integer = function (field, assignee) {
if (field.bytes == 1) {
return assignee + ' = ' + read
}
this.step += 2
return $(' \n\
' + assignee + ' = \n\
', read, '')
Expand Down Expand Up @@ -98,14 +100,15 @@ Generator.prototype.alternation = function (variables, packet, depth) {
}

Generator.prototype.lengthEncoded = function (variables, packet, depth) {
this.step += 2
var source = ''
var length = qualify('length', depth)
var object = qualify('object', depth)
var subObject = qualify('object', depth + 1)
var i = qualify('i', depth)
variables.hoist(i)
variables.hoist(length)
var looped = this.field(variables, packet.element, depth + 1)
var looped = this.field(variables, packet.element, depth + 1, true)
return $(' \n\
', this.integer(packet.length, length), ' \n\
// __blank__ \n\
Expand All @@ -117,15 +120,24 @@ Generator.prototype.lengthEncoded = function (variables, packet, depth) {
')
}

Generator.prototype.checkpoint = function (variables, packet, depth) {
var stack = ''
Generator.prototype.checkpoint = function (variables, packet, depth, arrayed) {
var arrayed = arrayed ? $(' \n\
length: length, \n\
index: i, \n\
') : ''
var separator = '',
object = 'object',
stack = 'parser.stack = [{'
for (var i = -1; i < depth; i++) {
for (var i = -1; i < 0; i++) {
stack = $(' \n\
// __reference__ \n\
', stack, ' \n\
object: object \n\
', separator, ' \n\
// __reference__ \n\
', arrayed, ' \n\
object: ' + object + ' \n\
')
separator = '}, {'
object = 'object' + (i + 2)
}
stack = $(' \n\
// __reference__ \n\
Expand All @@ -135,24 +147,24 @@ Generator.prototype.checkpoint = function (variables, packet, depth) {
return $(' \n\
if (end - start < ' + packet.length + ') { \n\
var parser = new parsers.inc.' + current.name + ' \n\
parser.step = 0 \n\
parser.step = ' + this.step + ' \n\
', stack , ' \n\
parser.object = object \n\
return { start: start, parser: parser, object: null } \n\
} \n\
')
}

Generator.prototype.field = function (variables, packet, depth) {
Generator.prototype.field = function (variables, packet, depth, arrayed) {
switch (packet.type) {
case 'checkpoint':
return this.checkpoint(variables, packet, depth)
return this.checkpoint(variables, packet, depth, arrayed)
case 'structure':
return $(' \n\
', this._constructor(variables, packet, depth), ' \n\
__blank__ \n\
', joinSources(packet.fields.map(function (packet) {
return this.field(variables, packet, depth)
return this.field(variables, packet, depth, arrayed)
}.bind(this))), ' \n\
')
case 'alternation':
Expand Down Expand Up @@ -180,7 +192,7 @@ Generator.prototype.parser = function (packet, bff) {

var variables = new Variables

var source = this.field(variables, packet, 0)
var source = this.field(variables, packet, 0, false)

// No need to track the end if we are a whole packet parser.
var signature = [ 'buffer', 'start', 'end' ]
Expand Down Expand Up @@ -218,8 +230,22 @@ Generator.prototype.parser = function (packet, bff) {
function bff (packet) {
var checkpoint, fields = [ checkpoint = { type: 'checkpoint', length: 0 } ]
for (var i = 0, I = packet.fields.length; i < I; i++) {
var field = packet.fields[i]
checkpoint.length += field.bytes
var field = JSON.parse(JSON.stringify(packet.fields[i]))
switch (field.type) {
case 'lengthEncoded':
checkpoint.length += field.length.bytes
switch (field.element.type) {
case 'structure':
field.element.fields = bff(field.element)
break
default:
throw new Error
}
break
default:
checkpoint.length += field.bytes
break
}
fields.push(field)
}
return fields
Expand Down
66 changes: 66 additions & 0 deletions t/generated/nested.parse.bff.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
module.exports = function (parsers) {
parsers.bff.object = function () {
}

parsers.bff._inc = function (buffer, start, end, stack) {
var parser = new parsers.inc.object
return 1
}

parsers.bff.object.prototype.parse = function (buffer, start, end) {

var i
var length
var object
var object1

object = {
values: new Array
}

if (end - start < 2) {
var parser = new parsers.inc.object
parser.step = 0
parser.stack = [{
object: object
}]
parser.object = object
return { start: start, parser: parser, object: null }
}

length =
buffer[start++] * 0x100 +
buffer[start++]

for (i = 0; i < length; i++) {
object1 = {
key: null,
value: null
}

if (end - start < 4) {
var parser = new parsers.inc.object
parser.step = 2
parser.stack = [{
length: length,
index: i,
object: object
}]
parser.object = object
return { start: start, parser: parser, object: null }
}

object1.key =
buffer[start++] * 0x100 +
buffer[start++]

object1.value =
buffer[start++] * 0x100 +
buffer[start++]

object.values.push(object1)
}

return { start: start, object: object, parser: null }
}
}
58 changes: 58 additions & 0 deletions t/parse/bff/nested.t.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
require('proof')(10, prove)

function prove (assert) {
var path = require('path')
var compiler = require('../../../compiler/require')
var all = require('../../../compose/parser/all.js')
var inc = require('../../../compose/parser/inc.js')
var filename = {
bff: path.resolve(__filename, '../../../generated/nested.parse.bff.js'),
inc: path.resolve(__filename, '../../../generated/nested.parse.inc.js')
}

var parsers = { bff: {}, inc: {} }

var definition = [{
type: 'structure',
name: 'object',
fields: [{
type: 'lengthEncoded',
name: 'values',
length: {
type: 'integer',
endianness: 'b',
bits: 16
},
element: {
type: 'structure',
fields: [{
type: 'integer',
name: 'key',
endianness: 'b',
bits: 16
}, {
type: 'integer',
name: 'value',
endianness: 'b',
bits: 16
}]
}
}]
}]
inc(compiler('parsers', filename.inc), definition)(parsers)
all(compiler('parsers', filename.bff), definition, { bff: true })(parsers)

var buffer = new Buffer([ 0x0, 0x2, 0xa, 0xa, 0x0, 0x1, 0x0, 0x2, 0x0, 0x3 ])
for (var i = 0; i < buffer.length; i++) {
var parser = new parsers.bff.object
var outcome = parser.parse(buffer, 0, buffer.length - i)
if (outcome.parser != null) {
outcome = outcome.parser.parse(buffer, outcome.start, buffer.length)
}
assert(outcome, {
start: buffer.length,
object: { values: [ { key: 2570, value: 1 }, { key: 2, value: 3 } ] },
parser: null
}, 'complete ' + i)
}
}

0 comments on commit 9a8ec08

Please sign in to comment.