Skip to content

Commit

Permalink
Tidy incremental parser.
Browse files Browse the repository at this point in the history
  • Loading branch information
flatheadmill committed Jul 30, 2015
1 parent 52c3b9d commit c10cae9
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 144 deletions.
264 changes: 128 additions & 136 deletions composers/parsers/inc.js
Expand Up @@ -2,153 +2,145 @@ var $ = require('programmatic')
var signage = require('./signage')
var unpackAll = require('./unpack')

function parseInit (field) {
var little = field.endianness == 'l'
var bytes = field.bytes
var bite = little ? 0 : bytes - 1
return 'bite = ' + bite
}

function parseLoop (field, assign) {
var little = field.endianness == 'l'
var bytes = field.bytes
var bite = little ? 0 : bytes - 1
var direction = little ? 'bite++' : 'bite--'
var stop = little ? bytes : -1
return $(' \n\
while (bite != ' + stop + ') { \n\
if (start == end) { \n\
return start \n\
} \n\
' + assign + ' \n\
' + direction + ' \n\
} \n\
')
}

var formatters = {
skip: function (hoist, source, vars) {
var field = vars.field
hoist('skip')
hoist('remaining')
return $(' \n\
', source, ' \n\
case ' + vars.step + ': \n\
skip = ' + (field.bytes * field.repeat) + ' \n\
step = ' + (vars.step + 1) + ' \n\
case ' + (vars.step + 1) + ': \n\
remaining = end - start \n\
if (remaining < skip) { \n\
skip -= remaining \n\
return end \n\
} \n\
start += skip \n\
')
},
float: function (hoist, source, vars) {
var field = vars.field
hoist('value')
hoist('bite')
return $(' \n\
', source, ' \n\
case ' + vars.step + ': \n\
value = new ArrayBuffer(' + field.bytes + ') \n\
', parseInit(field), ' \n\
step = ' + (vars.step + 1) + ' \n\
case ' + (vars.step + 1) + ': \n\
', parseLoop(field, 'value[bite] = buffer[start++]'), ' \n\
' + vars.assign + ' = new DataView(value).getFloat' + field.bits + '(0, true) \n\
')
},
integer: function (hoist, source, vars) {
var step = vars.step
var field = vars.field
var little = field.endianness == 'l'
var bytes = field.bytes
var bite = little ? 0 : bytes - 1
var direction = little ? 'bite++' : 'bite--'
var stop = little ? bytes : -1

var variable = 'value'
var parseStep = step + 1
var fixup = '', assign

var initialization = variable + ' = 0'
hoist(variable)
fixup = signage(field)
assign = ' += Math.pow(256, bite) * buffer[start++]'

hoist('bite')
hoist('next')

var parse = $(' \n\
while (bite != ' + stop + ') { \n\
if (start == end) { \n\
return start \n\
} \n\
value' + assign + ' \n\
' + direction + ' \n\
} \n\
')

source = $(' \n\
', source, ' \n\
case ' + step + ': \n\
', initialization, ' \n\
bite = ' + bite + ' \n\
step = ' + parseStep + ' \n\
case ' + parseStep + ': \n\
', parse, ' \n\
')

// sign fixup
source = $(' \n\
// __reference__ \n\
', source, ' \n\
', fixup)
if (field.packing) {
// TODO: Not sure why indent is necessary.
return $(' \n\
// __reference__ \n\
', source, ' \n\
', unpackAll(field, source) + ' \n\
')
} else {
return $(' \n\
// __reference__ \n\
', source, ' \n\
object.' + field.name + ' = ' + variable + ' \n\
')
}
}
}

function composeIncrementalParser (ranges) {
var variables = [], source = '', previous = ''
var variables = [], source = ''

ranges.forEach(function (range, rangeIndex) {
range.pattern.forEach(function (field, fieldIndex) {
var step = field.index * 2

var little = field.endianness == 'l'
var bytes = field.bytes
var bite = little ? 0 : bytes - 1
var direction = little ? 'bite++' : 'bite--'
var stop = little ? bytes : -1

var variable = 'value'
var parseStep = step + 1
var fixup = '', assign

var fetch = ''
if (range.lengthEncoded) {
fetch = $(' \n\
array = object.' + field.name + ' \n\
')
} else if (field.arrayed) {
fetch = 'array = new Array(' + field.repeat + ')'
}

var initialization, fixup, assignee = variable
if (field.endianness == 'x') {
hoist('skip')
hoist('remaining')
source = $(' \n\
', source, ' \n\
case ' + step + ': \n\
skip = ' + (field.bytes * field.repeat) + ' \n\
step = ' + (step + 1) + ' \n\
case ' + (step + 1) + ': \n\
remaining = end - start \n\
if (remaining < skip) { \n\
skip -= remaining \n\
return end \n\
} \n\
start += skip \n\
')
source = formatters.skip(hoist, source, { step: step, field: field })
} else if (field.type == 'f') {
source = formatters.float(hoist, source, { step: step, field: field, assign: 'object.' + field.name })
} else {
if (field.type == 'f') {
hoist('value')
initialization = $(' \n\
' + variable + ' = new ArrayBuffer(' + field.bytes + ') \n\
')
fixup = $(' \n\
' + variable + ' = new DataView(' +
variable + ').getFloat' +
field.bits + '(0, true) \n\
')
assign = '[bite] = buffer[start++]'
} else if (field.arrayed) {
initialization = $('\n\
if (array.length !== 0) { \n\
array[0] = 0 \n\
} \n\
i = 0 \n\
')
assignee = 'array[i]'
assign = ' += Math.pow(256, bite) * buffer[start++]'
} else {
if (field.lengthEncoding) {
initialization = 'length = 0'
assignee = 'length'
} else {
initialization = variable + ' = 0'
}
hoist(variable)
fixup = signage(field)
assign = ' += Math.pow(256, bite) * buffer[start++]'
}

hoist('bite')
hoist('next')

if (field.arrayed) {
hoist('i')
}

var parse = $(' \n\
while (bite != ' + stop + ') { \n\
if (start == end) { \n\
return start \n\
} \n\
' + assignee + assign + ' \n\
' + direction + ' \n\
} \n\
')

if (field.arrayed) {
parse = $(' \n\
for (;;) { \n\
', parse, ' \n\
if (++i === array.length) { \n\
break \n\
} \n\
' + assignee + ' = 0 \n\
bite = ' + bite + ' \n\
} \n\
')
}

source = $(' \n\
', source, ' \n\
case ' + step + ': \n\
', fetch, ' \n\
', initialization, ' \n\
bite = ' + bite + ' \n\
step = ' + parseStep + ' \n\
case ' + parseStep + ': \n\
', parse, ' \n\
')

// sign fixup
source = $(' \n\
// __reference__ \n\
', previous , ' \n\
', source, ' \n\
', fixup)
if (field.packing) {
// TODO: Not sure why indent is necessary.
source = $(' \n\
// __reference__ \n\
', source, ' \n\
', unpackAll(field, source) + ' \n\
')
} else if (field.lengthEncoding) {
source = $(' \n\
// __reference__ \n\
', source, ' \n\
object.' + range.name + ' = new Array(length) \n\
')
} else if (!field.arrayed) {
source = $(' \n\
// __reference__ \n\
', source, ' \n\
object.' + field.name + ' = ' + variable + ' \n\
')
}
source = formatters.integer(hoist, source, { step: step, field: field, assign: 'object.' + field.name })
}
})
})

hoist('next')

source = $(' \n\
this.parse = function (buffer, start, end) { \n\
switch (step) { \n\
Expand Down
3 changes: 1 addition & 2 deletions t/generated/parse.bff.b32f_foo.js
Expand Up @@ -20,8 +20,7 @@ module.exports = function (object, callback) {
value[bite] = buffer[start++]
bite--
}
value = new DataView(value).getFloat32(0, true)
object.foo = value
object.foo = new DataView(value).getFloat32(0, true)
}

if (next = callback(object)) {
Expand Down
3 changes: 1 addition & 2 deletions t/generated/parse.bff.b64f_foo.js
Expand Up @@ -20,8 +20,7 @@ module.exports = function (object, callback) {
value[bite] = buffer[start++]
bite--
}
value = new DataView(value).getFloat64(0, true)
object.foo = value
object.foo = new DataView(value).getFloat64(0, true)
}

if (next = callback(object)) {
Expand Down
3 changes: 1 addition & 2 deletions t/generated/parse.bff.l32f_foo.js
Expand Up @@ -20,8 +20,7 @@ module.exports = function (object, callback) {
value[bite] = buffer[start++]
bite++
}
value = new DataView(value).getFloat32(0, true)
object.foo = value
object.foo = new DataView(value).getFloat32(0, true)
}

if (next = callback(object)) {
Expand Down
3 changes: 1 addition & 2 deletions t/generated/parse.bff.l64f_foo.js
Expand Up @@ -20,8 +20,7 @@ module.exports = function (object, callback) {
value[bite] = buffer[start++]
bite++
}
value = new DataView(value).getFloat64(0, true)
object.foo = value
object.foo = new DataView(value).getFloat64(0, true)
}

if (next = callback(object)) {
Expand Down

0 comments on commit c10cae9

Please sign in to comment.