Merge branch 'master' into develop

This commit is contained in:
Richard Hansen 2021-11-28 23:10:45 -05:00
commit f00b1ae89b
14 changed files with 606 additions and 348 deletions

View file

@ -205,6 +205,35 @@ class AttributePool {
}
return this;
}
/**
* Asserts that the data in the pool is consistent. Throws if inconsistent.
*/
check() {
if (!Number.isInteger(this.nextNum)) throw new Error('nextNum property is not an integer');
if (this.nextNum < 0) throw new Error('nextNum property is negative');
for (const prop of ['numToAttrib', 'attribToNum']) {
const obj = this[prop];
if (obj == null) throw new Error(`${prop} property is null`);
if (typeof obj !== 'object') throw new TypeError(`${prop} property is not an object`);
const keys = Object.keys(obj);
if (keys.length !== this.nextNum) {
throw new Error(`${prop} size mismatch (want ${this.nextNum}, got ${keys.length})`);
}
}
for (let i = 0; i < this.nextNum; ++i) {
const attr = this.numToAttrib[`${i}`];
if (!Array.isArray(attr)) throw new TypeError(`attrib ${i} is not an array`);
if (attr.length !== 2) throw new Error(`attrib ${i} is not an array of length 2`);
const [k, v] = attr;
if (k == null) throw new TypeError(`attrib ${i} key is null`);
if (typeof k !== 'string') throw new TypeError(`attrib ${i} key is not a string`);
if (v == null) throw new TypeError(`attrib ${i} value is null`);
if (typeof v !== 'string') throw new TypeError(`attrib ${i} value is not a string`);
const attrStr = String(attr);
if (this.attribToNum[attrStr] !== i) throw new Error(`attribToNum for ${attrStr} !== ${i}`);
}
}
}
module.exports = AttributePool;

View file

@ -380,7 +380,6 @@ exports.checkRep = (cs) => {
const assem = exports.smartOpAssembler();
let oldPos = 0;
let calcNewLen = 0;
let numInserted = 0;
for (const o of exports.deserializeOps(ops)) {
switch (o.opcode) {
case '=':
@ -393,25 +392,29 @@ exports.checkRep = (cs) => {
break;
case '+':
{
assert(charBank.length >= o.chars, 'Invalid changeset: not enough chars in charBank');
const chars = charBank.slice(0, o.chars);
const nlines = (chars.match(/\n/g) || []).length;
assert(nlines === o.lines,
'Invalid changeset: number of newlines in insert op does not match the charBank');
assert(o.lines === 0 || chars.endsWith('\n'),
'Invalid changeset: multiline insert op does not end with a newline');
charBank = charBank.slice(o.chars);
calcNewLen += o.chars;
numInserted += o.chars;
assert(calcNewLen <= newLen, `${calcNewLen} > ${newLen} in ${cs}`);
break;
}
default:
assert(false, `Invalid changeset: Unknown opcode: ${JSON.stringify(o.opcode)}`);
}
assem.append(o);
}
calcNewLen += oldLen - oldPos;
charBank = charBank.substring(0, numInserted);
while (charBank.length < numInserted) {
charBank += '?';
}
assert(calcNewLen === newLen, 'Invalid changeset: claimed length does not match actual length');
assert(charBank === '', 'Invalid changeset: excess characters in the charBank');
assem.endDocument();
const normalized = exports.pack(oldLen, calcNewLen, assem.toString(), charBank);
assert(normalized === cs, 'Invalid changeset (checkRep failed)');
const normalized = exports.pack(oldLen, calcNewLen, assem.toString(), unpacked.charBank);
assert(normalized === cs, 'Invalid changeset: not in canonical form');
return cs;
};
@ -1059,9 +1062,7 @@ const applyZip = (in1, in2, func) => {
exports.unpack = (cs) => {
const headerRegex = /Z:([0-9a-z]+)([><])([0-9a-z]+)|/;
const headerMatch = headerRegex.exec(cs);
if ((!headerMatch) || (!headerMatch[0])) {
error(`Not a exports: ${cs}`);
}
if ((!headerMatch) || (!headerMatch[0])) error(`Not a changeset: ${cs}`);
const oldLen = exports.parseNum(headerMatch[1]);
const changeSign = (headerMatch[2] === '>') ? 1 : -1;
const changeMag = exports.parseNum(headerMatch[3]);