Skip to content

Commit

Permalink
Fix anon containers (#159)
Browse files Browse the repository at this point in the history
* Update compiler-structures.js: Remove special container inlining code

* Update compiler-conditional.js: fix switch cases not inheriting scope

* Update compiler-structures.js

* update handling for switch getField

* lint
  • Loading branch information
extremeheat authored Oct 12, 2024
1 parent 73479a0 commit 68bb223
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 68 deletions.
8 changes: 6 additions & 2 deletions src/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ class Compiler {
return code.split('\n').map((line) => indent + line).join('\n')
}

getField (name) {
getField (name, noAssign) {
const path = name.split('/')
let i = this.scopeStack.length - 1
const reserved = ['value', 'enum', 'default', 'size', 'offset']
Expand All @@ -217,7 +217,11 @@ class Compiler {
for (let j = 0; j < i; j++) {
if (this.scopeStack[j][field]) count++
}
scope[field] = field + (count || '') // If the name is already used, add a number
if (noAssign) { // referencing a variable, inherit from parent scope
scope[field] = field
} else { // creating a new variable in this scope
scope[field] = field + (count || '') // If the name is already used, add a number
}
return scope[field]
}
throw new Error('Unknown field ' + path)
Expand Down
6 changes: 3 additions & 3 deletions src/datatypes/compiler-conditional.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module.exports = {
const args = []
if (compare.startsWith('$')) args.push(compare)
else if (struct.compareTo) {
compare = compiler.getField(compare)
compare = compiler.getField(compare, true)
}
let code = `switch (${compare}) {\n`
for (const key in struct.fields) {
Expand Down Expand Up @@ -35,7 +35,7 @@ module.exports = {
const args = []
if (compare.startsWith('$')) args.push(compare)
else if (struct.compareTo) {
compare = compiler.getField(compare)
compare = compiler.getField(compare, true)
}
let code = `switch (${compare}) {\n`
for (const key in struct.fields) {
Expand Down Expand Up @@ -66,7 +66,7 @@ module.exports = {
const args = []
if (compare.startsWith('$')) args.push(compare)
else if (struct.compareTo) {
compare = compiler.getField(compare)
compare = compiler.getField(compare, true)
}
let code = `switch (${compare}) {\n`
for (const key in struct.fields) {
Expand Down
81 changes: 18 additions & 63 deletions src/datatypes/compiler-structures.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ module.exports = {
let offsetExpr = 'offset'
const names = []
for (const i in values) {
const { type, name, anon } = values[i]
const { type, name, anon, _shouldBeInlined } = values[i]
let trueName
let sizeName
if (type instanceof Array && type[0] === 'bitfield' && anon) {
Expand All @@ -52,7 +52,8 @@ module.exports = {
} else {
trueName = compiler.getField(name)
sizeName = `${trueName}Size`
if (name === trueName) names.push(name)
if (_shouldBeInlined) names.push('...' + name)
else if (name === trueName) names.push(name)
else names.push(`${name}: ${trueName}`)
}
code += `let { value: ${trueName}, size: ${sizeName} } = ` + compiler.callType(type, offsetExpr) + '\n'
Expand Down Expand Up @@ -88,7 +89,7 @@ module.exports = {
values = containerInlining(values)
let code = ''
for (const i in values) {
const { type, name, anon } = values[i]
const { type, name, anon, _shouldBeInlined } = values[i]
let trueName
if (type instanceof Array && type[0] === 'bitfield' && anon) {
const names = []
Expand All @@ -101,7 +102,8 @@ module.exports = {
trueName = '{' + names.join(', ') + '}'
} else {
trueName = compiler.getField(name)
code += `let ${trueName} = value.${name}\n`
if (_shouldBeInlined) code += `let ${name} = value\n`
else code += `let ${trueName} = value.${name}\n`
}
code += 'offset = ' + compiler.callType(trueName, type) + '\n'
}
Expand Down Expand Up @@ -138,7 +140,7 @@ module.exports = {
values = containerInlining(values)
let code = 'let size = 0\n'
for (const i in values) {
const { type, name, anon } = values[i]
const { type, name, anon, _shouldBeInlined } = values[i]
let trueName
if (type instanceof Array && type[0] === 'bitfield' && anon) {
const names = []
Expand All @@ -151,7 +153,8 @@ module.exports = {
trueName = '{' + names.join(', ') + '}'
} else {
trueName = compiler.getField(name)
code += `let ${trueName} = value.${name}\n`
if (_shouldBeInlined) code += `let ${name} = value\n`
else code += `let ${trueName} = value.${name}\n`
}
code += 'size += ' + compiler.callType(trueName, type) + '\n'
}
Expand All @@ -161,6 +164,10 @@ module.exports = {
}
}

function uniqueId () {
return '_' + Math.random().toString(36).substr(2, 9)
}

function containerInlining (values) {
// Inlining (support only 1 level)
const newValues = []
Expand All @@ -170,63 +177,11 @@ function containerInlining (values) {
if (type instanceof Array && type[0] === 'container') {
for (const j in type[1]) newValues.push(type[1][j])
} else if (type instanceof Array && type[0] === 'switch') {
const theSwitch = type[1]
const valueSet = new Set()
// search for containers and build a set of possible values
for (const field in theSwitch.fields) {
if (theSwitch.fields[field] instanceof Array && theSwitch.fields[field][0] === 'container') {
for (const j in theSwitch.fields[field][1]) {
const item = theSwitch.fields[field][1][j]
valueSet.add(item.name)
}
}
}
if (theSwitch.default instanceof Array && theSwitch.default[0] === 'container') {
for (const j in theSwitch.default[1]) {
const item = theSwitch.default[1][j]
valueSet.add(item.name)
}
}
// For each value create a switch
for (const name of valueSet.keys()) {
const fields = {}
let theDefault = theSwitch.default

if (theDefault instanceof Array && theDefault[0] === 'container') {
for (const j in theDefault[1]) {
const item = theDefault[1][j]
if (item.name === name) {
theDefault = item.type
break
}
}
}
for (const field in theSwitch.fields) {
if (theSwitch.fields[field] instanceof Array && theSwitch.fields[field][0] === 'container') {
for (const j in theSwitch.fields[field][1]) {
const item = theSwitch.fields[field][1][j]
if (item.name === name) {
fields[field] = theSwitch.fields[field][1][j].type
break
}
}
} else {
fields[field] = theSwitch.fields[field]
}
}
if (!theDefault) {
theDefault = 'void'
}
newValues.push({
name,
type: ['switch', {
compareTo: theSwitch.compareTo,
compareToValue: theSwitch.compareToValue,
default: theDefault,
fields
}]
})
}
newValues.push({
name: uniqueId(),
_shouldBeInlined: true,
type
})
} else {
throw new Error('Cannot inline anonymous type: ' + type)
}
Expand Down

0 comments on commit 68bb223

Please sign in to comment.