nodejs / llparse

Generating parsers in LLVM IR
http://llparse.org
Other
584 stars 30 forks source link

[PoC] Parse integer data #32

Open arthurschreiber opened 4 years ago

arthurschreiber commented 4 years ago

This adds a very rough, unfinished implementation for parsing little- and big-endian integers, based on my question here: https://github.com/nodejs/llparse/issues/31

See also these 2 PRs:

This only includes the code to generate JS output (for now), and has no tests at all. 🤷‍♂ I'll try to flesh this out if I can find some more time.

Example input

const { LLParse } = require('./lib/api.js');

const p = new LLParse('colmetadata');

p.property('i16', 'userType');
p.property('i8', 'flags');
p.property('i8', 'type');
p.property('i32', 'dataLength');
p.property('i8', 'scale');
p.property('i8', 'precision');
p.property('i8', 'schemaPresent');
p.property('i8', 'dbNameLength');
p.property('i8', 'owningSchemaLength');
p.property('i16', 'xmlSchemaCollectionLength');
p.property('i8', 'collationLength');
p.property('i8', 'typeNameLength');
p.property('i16', 'assemblyNameLength');

const onCollation = p.span(p.code.span('on_collation'));
const onDbName = p.span(p.code.span('on_db_name'));
const onOwningSchema = p.span(p.code.span('on_owning_schema'));
const onXmlSchemaCollection = p.span(p.code.span('on_xml_schema_collection'));
const onTypeName = p.span(p.code.span('on_type_name'));
const onAssemblyName = p.span(p.code.span('on_assembly_name'));

const done = p.pause(1, "done");

function readUInt8(field, next) {
  return p.uIntLE(field, 1).skipTo(next);
}

function readUInt16LE(field, next) {
  return p.uIntLE(field, 2).skipTo(next);
}

function readUInt32LE(field, next) {
  return p.uIntLE(field, 4).skipTo(next);
}

const dataLengthByte = readUInt8('dataLength', done);
const dataLengthShort = readUInt16LE('dataLength', done);
const dataLengthLong = readUInt32LE('dataLength', done);

const dataLengthByteWithScaleAndPrecision = readUInt8('dataLength', readUInt8('scale', readUInt8('precision', done)));

const collation = p.invoke(p.code.update('collationLength', 5)).
  otherwise(
    onCollation.start(
      p.consume('collationLength').otherwise(onCollation.end(done)
    )
  )
);

const dataLengthShortWithCollation = readUInt16LE('dataLength', collation);
const dataLengthLongWithCollation = readUInt32LE('dataLength', collation);

function readBVarChar(name, span, next) {
  return readUInt8(name + 'Length', span.start(p.consume(name + 'Length').otherwise(span.end(next))));
}

function readUsVarChar(name, span, next) {
  return readUInt16LE(name + 'Length', span.start(p.consume(name + 'Length').otherwise(span.end(next))));
}

const schema = readUInt8('schemaPresent', p.invoke(p.code.load('schemaPresent'), {
  0x01: readBVarChar('dbName', onDbName,
    readBVarChar('owningSchema', onOwningSchema,
      readUsVarChar('xmlSchemaCollection', onXmlSchemaCollection, done)
    )
  )
}).skipTo(done));

const udtInfo = readBVarChar('dbName', onDbName,
  readBVarChar('owningSchema', onOwningSchema,
    readBVarChar('typeName', onTypeName,
      readUsVarChar('assemblyName', onAssemblyName, done)
    )
  )
);

const dataLengthShortWithUDTInfo = readUInt16LE('dataLength', udtInfo);

const TYPES = {
  NULL: 0x1F,
  TINYINT: 0x30,
  BIT: 0x32,
  SMALLINT: 0x34,
  INT: 0x38,
  SMALLDATETIME: 0x3A,
  REAL: 0x3B,
  MONEY: 0x3C,
  DATETIME: 0x3D,
  FLOAT: 0x3E,
  SMALLMONEY: 0x7A,
  BIGINT: 0x7F,

  GUID: 0x24,
  INTN: 0x26,
  DECIMAL: 0x37,
  NUMERIC: 0x3F,
  BITN: 0x68,
  DECIMALN: 0x6A,
  NUMERICN: 0x6C,
  FLOATN: 0x6D,
  MONEYN: 0x6E,
  DATETIMEN: 0x6F,
  DATEN: 0x28,
  TIMEN: 0x29,
  DATETIME2N: 0x2A,
  DATETIMEOFFSETN: 0x2B,
  CHAR: 0x2F,
  VARCHAR: 0x27,
  BINARY: 0x2D,
  VARBINARY: 0x25,

  BIGVARBINARY: 0xA5,
  BIGVARCHAR: 0xA7,
  BIGBINARY: 0xAD,
  BIGCHAR: 0XAF,
  NVARCHAR: 0xE7,
  NCHAR: 0xEF,
  XML: 0xF1,
  UDT: 0xF0,

  TEXT: 0x23,
  IMAGE: 0x22,
  NTEXT: 0x63,
  VARIANT: 0x62
}

const colmetadata =
  readUInt32LE.call(null, 'userType',
    readUInt16LE('flags',
      readUInt8('type',
        p.invoke(p.code.load('type'), {
          [TYPES.NULL]: done,
          [TYPES.TINYINT]: done,
          [TYPES.SMALLINT]: done,
          [TYPES.INT]: done,
          [TYPES.BIGINT]: done,
          [TYPES.REAL]: done,
          [TYPES.FLOAT]: done,
          [TYPES.SMALLMONEY]: done,
          [TYPES.MONEY]: done,
          [TYPES.BIT]: done,
          [TYPES.SMALLDATETIME]: done,
          [TYPES.DATETIME]: done,

          [TYPES.INTN]: dataLengthByte,
          [TYPES.FLOATN]: dataLengthByte,
          [TYPES.MONEYN]: dataLengthByte,
          [TYPES.BITN]: dataLengthByte,
          [TYPES.GUID]: dataLengthByte,
          [TYPES.DATETIMEN]: dataLengthByte,
          [TYPES.TIMEN]: dataLengthByte,
          [TYPES.DATETIME2N]: dataLengthByte,
          [TYPES.DATETIMEOFFSETN]: dataLengthByte,

          [TYPES.VARIANT]: dataLengthLong,
          [TYPES.IMAGE]: dataLengthLong,

          [TYPES.VARCHAR]: dataLengthByte,
          [TYPES.CHAR]: dataLengthByte,
          [TYPES.VARBINARY]: dataLengthByte,
          [TYPES.BINARY]: dataLengthByte,

          [TYPES.BIGVARCHAR]: dataLengthShortWithCollation,
          [TYPES.BIGCHAR]: dataLengthShortWithCollation,
          [TYPES.BIGVARBINARY]: dataLengthShort,
          [TYPES.BIGBINARY]: dataLengthShort,

          [TYPES.NVARCHAR]: dataLengthShortWithCollation,
          [TYPES.NCHAR]: dataLengthShortWithCollation,

          [TYPES.TEXT]: dataLengthLongWithCollation,
          [TYPES.NTEXT]: dataLengthLongWithCollation,

          [TYPES.XML]: schema,

          [TYPES.NUMERICN]: dataLengthByteWithScaleAndPrecision,
          [TYPES.DECIMALN]: dataLengthByteWithScaleAndPrecision,
          [TYPES.NUMERIC]: dataLengthByteWithScaleAndPrecision,
          [TYPES.DECIMAL]: dataLengthByteWithScaleAndPrecision,

          [TYPES.UDT]: dataLengthShortWithUDTInfo
        }).otherwise(p.error(1, "Unknown type"))
      )
    )
  );

done.otherwise(colmetadata);

p.property('i8', 'field');

const artifacts = p.build(colmetadata, { js: { module: 'commonjs' } });
console.log(artifacts.js);  // buffer

Example output

'use strict';

module.exports = (binding) => {
  function unreachable() {
    throw new Error('Unreachable');
  }

  const S_ERROR = 0;
  const S_N_COLMETADATA__N_PAUSE = 1;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE4 = 2;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE3 = 3;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE2 = 4;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE = 5;
  const S_N_COLMETADATA__N_SPAN_END_ON_COLLATION = 6;
  const S_N_COLMETADATA__N_CONSUME_COLLATIONLENGTH = 7;
  const S_N_COLMETADATA__N_SPAN_START_ON_COLLATION = 8;
  const S_N_COLMETADATA__N_INVOKE_UPDATE_COLLATIONLENGTH = 9;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE4_1 = 10;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE3_1 = 11;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE2_1 = 12;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_1 = 13;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_8 = 14;
  const S_N_COLMETADATA__N_PRECISION_UINT_8 = 15;
  const S_N_COLMETADATA__N_SCALE_UINT_8 = 16;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_8_1 = 17;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2 = 18;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE = 19;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2_1 = 20;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_1 = 21;
  const S_N_COLMETADATA__N_SPAN_END_ON_ASSEMBLY_NAME = 22;
  const S_N_COLMETADATA__N_CONSUME_ASSEMBLYNAMELENGTH = 23;
  const S_N_COLMETADATA__N_SPAN_START_ON_ASSEMBLY_NAME = 24;
  const S_N_COLMETADATA__N_ASSEMBLYNAMELENGTH_UINT_16_LE_BYTE2 = 25;
  const S_N_COLMETADATA__N_ASSEMBLYNAMELENGTH_UINT_16_LE = 26;
  const S_N_COLMETADATA__N_SPAN_END_ON_TYPE_NAME = 27;
  const S_N_COLMETADATA__N_CONSUME_TYPENAMELENGTH = 28;
  const S_N_COLMETADATA__N_SPAN_START_ON_TYPE_NAME = 29;
  const S_N_COLMETADATA__N_TYPENAMELENGTH_UINT_8 = 30;
  const S_N_COLMETADATA__N_SPAN_END_ON_OWNING_SCHEMA = 31;
  const S_N_COLMETADATA__N_CONSUME_OWNINGSCHEMALENGTH = 32;
  const S_N_COLMETADATA__N_SPAN_START_ON_OWNING_SCHEMA = 33;
  const S_N_COLMETADATA__N_OWNINGSCHEMALENGTH_UINT_8 = 34;
  const S_N_COLMETADATA__N_SPAN_END_ON_DB_NAME = 35;
  const S_N_COLMETADATA__N_CONSUME_DBNAMELENGTH = 36;
  const S_N_COLMETADATA__N_SPAN_START_ON_DB_NAME = 37;
  const S_N_COLMETADATA__N_DBNAMELENGTH_UINT_8 = 38;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2_2 = 39;
  const S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_2 = 40;
  const S_N_COLMETADATA__N_SPAN_END_ON_XML_SCHEMA_COLLECTION = 41;
  const S_N_COLMETADATA__N_CONSUME_XMLSCHEMACOLLECTIONLENGTH = 42;
  const S_N_COLMETADATA__N_SPAN_START_ON_XML_SCHEMA_COLLECTION = 43;
  const S_N_COLMETADATA__N_XMLSCHEMACOLLECTIONLENGTH_UINT_16_LE_BYTE2 = 44;
  const S_N_COLMETADATA__N_XMLSCHEMACOLLECTIONLENGTH_UINT_16_LE = 45;
  const S_N_COLMETADATA__N_SPAN_END_ON_OWNING_SCHEMA_1 = 46;
  const S_N_COLMETADATA__N_CONSUME_OWNINGSCHEMALENGTH_1 = 47;
  const S_N_COLMETADATA__N_SPAN_START_ON_OWNING_SCHEMA_1 = 48;
  const S_N_COLMETADATA__N_OWNINGSCHEMALENGTH_UINT_8_1 = 49;
  const S_N_COLMETADATA__N_SPAN_END_ON_DB_NAME_1 = 50;
  const S_N_COLMETADATA__N_CONSUME_DBNAMELENGTH_1 = 51;
  const S_N_COLMETADATA__N_SPAN_START_ON_DB_NAME_1 = 52;
  const S_N_COLMETADATA__N_DBNAMELENGTH_UINT_8_1 = 53;
  const S_N_COLMETADATA__N_INVOKE_LOAD_SCHEMAPRESENT = 54;
  const S_N_COLMETADATA__N_SCHEMAPRESENT_UINT_8 = 55;
  const S_N_COLMETADATA__N_ERROR = 56;
  const S_N_COLMETADATA__N_INVOKE_LOAD_TYPE = 57;
  const S_N_COLMETADATA__N_TYPE_UINT_8 = 58;
  const S_N_COLMETADATA__N_FLAGS_UINT_16_LE_BYTE2 = 59;
  const S_N_COLMETADATA__N_FLAGS_UINT_16_LE = 60;
  const S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE4 = 61;
  const S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE3 = 62;
  const S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE2 = 63;
  const S_N_COLMETADATA__N_USERTYPE_UINT_32_LE = 64;

  const on_db_name = binding.on_db_name;

  const on_owning_schema = binding.on_owning_schema;

  const on_xml_schema_collection = binding.on_xml_schema_collection;

  const on_type_name = binding.on_type_name;

  const on_assembly_name = binding.on_assembly_name;

  const on_collation = binding.on_collation;

  class Parser {
    constructor() {
      this._index = 0;
      this._current = S_N_COLMETADATA__N_USERTYPE_UINT_32_LE;
      this._status = 0;
      this.error = 0;
      this.reason = null;
      this.errorOff = 0;
      this.userType = 0;
      this.flags = 0;
      this.type = 0;
      this.dataLength = 0;
      this.scale = 0;
      this.precision = 0;
      this.schemaPresent = 0;
      this.dbNameLength = 0;
      this.owningSchemaLength = 0;
      this.xmlSchemaCollectionLength = 0;
      this.collationLength = 0;
      this.typeNameLength = 0;
      this.assemblyNameLength = 0;
      this.field = 0;
      this._spanOff0 = -1;
      this._spanCb0 = null;
    }

    _on_db_name(buf, off, offEnd) {
      return on_db_name(this, buf, off, offEnd);
    }

    _on_owning_schema(buf, off, offEnd) {
      return on_owning_schema(this, buf, off, offEnd);
    }

    _on_xml_schema_collection(buf, off, offEnd) {
      return on_xml_schema_collection(this, buf, off, offEnd);
    }

    _on_type_name(buf, off, offEnd) {
      return on_type_name(this, buf, off, offEnd);
    }

    _on_assembly_name(buf, off, offEnd) {
      return on_assembly_name(this, buf, off, offEnd);
    }

    _on_collation(buf, off, offEnd) {
      return on_collation(this, buf, off, offEnd);
    }

    _colmetadata__c_load_type(buf, off) {
      return this.type;
    }

    _colmetadata__c_update_collationLength(buf, off) {
      this.collationLength = 5;
      return 0;
    }

    _colmetadata__c_load_schemaPresent(buf, off) {
      return this.schemaPresent;
    }

    _run(current, buf, off) {
      let match;
      for (;;) {
        switch (current | 0) {
          case S_N_COLMETADATA__N_PAUSE: {
            this.error = 0x1;
            this.reason = "done";
            this.errorOff = off;
            this._current = S_N_COLMETADATA__N_USERTYPE_UINT_32_LE
            return S_ERROR;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE4: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE4;
            }
            this.dataLength += buf[off] * 2 ** 24;
            off++;
            current = S_N_COLMETADATA__N_PAUSE;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE3: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE3;
            }
            this.dataLength += buf[off] * 2 ** 16;
            off++;
            current = S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE4;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE2: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE2;
            }
            this.dataLength += buf[off] * 2 ** 8;
            off++;
            current = S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE3;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE;
            }
            this.dataLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE2;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_END_ON_COLLATION: {
            const start = this._spanOff0;
            this._spanOff0 = -1;
            const err = this._on_collation(buf, start, off) | 0;
            if (err !== 0) {
              this.error = err;
              this.errorOff = off;
              this._current = S_N_COLMETADATA__N_PAUSE;
              return S_ERROR;
            }
            current = S_N_COLMETADATA__N_PAUSE;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_CONSUME_COLLATIONLENGTH: {
            let avail = buf.length - off;
            const need = this.collationLength;
            if (avail >= need) {
              off += need;
              this.collationLength = 0;
              current = S_N_COLMETADATA__N_SPAN_END_ON_COLLATION;
              continue;
            }

            this.collationLength -= avail;
            return S_N_COLMETADATA__N_CONSUME_COLLATIONLENGTH;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_START_ON_COLLATION: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_SPAN_START_ON_COLLATION;
            }
            this._spanOff0 = off;
            this._spanCb0 = this._on_collation;
            current = S_N_COLMETADATA__N_CONSUME_COLLATIONLENGTH;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_INVOKE_UPDATE_COLLATIONLENGTH: {
            switch (this._colmetadata__c_update_collationLength(buf, off) | 0) {
              default:
                current = S_N_COLMETADATA__N_SPAN_START_ON_COLLATION;
                continue;
            }
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE4_1: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE4_1;
            }
            this.dataLength += buf[off] * 2 ** 24;
            off++;
            current = S_N_COLMETADATA__N_INVOKE_UPDATE_COLLATIONLENGTH;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE3_1: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE3_1;
            }
            this.dataLength += buf[off] * 2 ** 16;
            off++;
            current = S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE4_1;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE2_1: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE2_1;
            }
            this.dataLength += buf[off] * 2 ** 8;
            off++;
            current = S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE3_1;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_1: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_1;
            }
            this.dataLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_BYTE2_1;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_8: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_8;
            }
            this.dataLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_PAUSE;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_PRECISION_UINT_8: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_PRECISION_UINT_8;
            }
            this.precision = buf[off];
            off++;
            current = S_N_COLMETADATA__N_PAUSE;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_SCALE_UINT_8: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_SCALE_UINT_8;
            }
            this.scale = buf[off];
            off++;
            current = S_N_COLMETADATA__N_PRECISION_UINT_8;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_8_1: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_8_1;
            }
            this.dataLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_SCALE_UINT_8;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2;
            }
            this.dataLength += buf[off] * 2 ** 8;
            off++;
            current = S_N_COLMETADATA__N_PAUSE;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE;
            }
            this.dataLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2_1: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2_1;
            }
            this.dataLength += buf[off] * 2 ** 8;
            off++;
            current = S_N_COLMETADATA__N_INVOKE_UPDATE_COLLATIONLENGTH;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_1: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_1;
            }
            this.dataLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2_1;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_END_ON_ASSEMBLY_NAME: {
            const start = this._spanOff0;
            this._spanOff0 = -1;
            const err = this._on_assembly_name(buf, start, off) | 0;
            if (err !== 0) {
              this.error = err;
              this.errorOff = off;
              this._current = S_N_COLMETADATA__N_PAUSE;
              return S_ERROR;
            }
            current = S_N_COLMETADATA__N_PAUSE;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_CONSUME_ASSEMBLYNAMELENGTH: {
            let avail = buf.length - off;
            const need = this.assemblyNameLength;
            if (avail >= need) {
              off += need;
              this.assemblyNameLength = 0;
              current = S_N_COLMETADATA__N_SPAN_END_ON_ASSEMBLY_NAME;
              continue;
            }

            this.assemblyNameLength -= avail;
            return S_N_COLMETADATA__N_CONSUME_ASSEMBLYNAMELENGTH;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_START_ON_ASSEMBLY_NAME: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_SPAN_START_ON_ASSEMBLY_NAME;
            }
            this._spanOff0 = off;
            this._spanCb0 = this._on_assembly_name;
            current = S_N_COLMETADATA__N_CONSUME_ASSEMBLYNAMELENGTH;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_ASSEMBLYNAMELENGTH_UINT_16_LE_BYTE2: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_ASSEMBLYNAMELENGTH_UINT_16_LE_BYTE2;
            }
            this.assemblyNameLength += buf[off] * 2 ** 8;
            off++;
            current = S_N_COLMETADATA__N_SPAN_START_ON_ASSEMBLY_NAME;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_ASSEMBLYNAMELENGTH_UINT_16_LE: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_ASSEMBLYNAMELENGTH_UINT_16_LE;
            }
            this.assemblyNameLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_ASSEMBLYNAMELENGTH_UINT_16_LE_BYTE2;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_END_ON_TYPE_NAME: {
            const start = this._spanOff0;
            this._spanOff0 = -1;
            const err = this._on_type_name(buf, start, off) | 0;
            if (err !== 0) {
              this.error = err;
              this.errorOff = off;
              this._current = S_N_COLMETADATA__N_ASSEMBLYNAMELENGTH_UINT_16_LE;
              return S_ERROR;
            }
            current = S_N_COLMETADATA__N_ASSEMBLYNAMELENGTH_UINT_16_LE;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_CONSUME_TYPENAMELENGTH: {
            let avail = buf.length - off;
            const need = this.typeNameLength;
            if (avail >= need) {
              off += need;
              this.typeNameLength = 0;
              current = S_N_COLMETADATA__N_SPAN_END_ON_TYPE_NAME;
              continue;
            }

            this.typeNameLength -= avail;
            return S_N_COLMETADATA__N_CONSUME_TYPENAMELENGTH;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_START_ON_TYPE_NAME: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_SPAN_START_ON_TYPE_NAME;
            }
            this._spanOff0 = off;
            this._spanCb0 = this._on_type_name;
            current = S_N_COLMETADATA__N_CONSUME_TYPENAMELENGTH;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_TYPENAMELENGTH_UINT_8: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_TYPENAMELENGTH_UINT_8;
            }
            this.typeNameLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_SPAN_START_ON_TYPE_NAME;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_END_ON_OWNING_SCHEMA: {
            const start = this._spanOff0;
            this._spanOff0 = -1;
            const err = this._on_owning_schema(buf, start, off) | 0;
            if (err !== 0) {
              this.error = err;
              this.errorOff = off;
              this._current = S_N_COLMETADATA__N_TYPENAMELENGTH_UINT_8;
              return S_ERROR;
            }
            current = S_N_COLMETADATA__N_TYPENAMELENGTH_UINT_8;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_CONSUME_OWNINGSCHEMALENGTH: {
            let avail = buf.length - off;
            const need = this.owningSchemaLength;
            if (avail >= need) {
              off += need;
              this.owningSchemaLength = 0;
              current = S_N_COLMETADATA__N_SPAN_END_ON_OWNING_SCHEMA;
              continue;
            }

            this.owningSchemaLength -= avail;
            return S_N_COLMETADATA__N_CONSUME_OWNINGSCHEMALENGTH;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_START_ON_OWNING_SCHEMA: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_SPAN_START_ON_OWNING_SCHEMA;
            }
            this._spanOff0 = off;
            this._spanCb0 = this._on_owning_schema;
            current = S_N_COLMETADATA__N_CONSUME_OWNINGSCHEMALENGTH;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_OWNINGSCHEMALENGTH_UINT_8: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_OWNINGSCHEMALENGTH_UINT_8;
            }
            this.owningSchemaLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_SPAN_START_ON_OWNING_SCHEMA;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_END_ON_DB_NAME: {
            const start = this._spanOff0;
            this._spanOff0 = -1;
            const err = this._on_db_name(buf, start, off) | 0;
            if (err !== 0) {
              this.error = err;
              this.errorOff = off;
              this._current = S_N_COLMETADATA__N_OWNINGSCHEMALENGTH_UINT_8;
              return S_ERROR;
            }
            current = S_N_COLMETADATA__N_OWNINGSCHEMALENGTH_UINT_8;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_CONSUME_DBNAMELENGTH: {
            let avail = buf.length - off;
            const need = this.dbNameLength;
            if (avail >= need) {
              off += need;
              this.dbNameLength = 0;
              current = S_N_COLMETADATA__N_SPAN_END_ON_DB_NAME;
              continue;
            }

            this.dbNameLength -= avail;
            return S_N_COLMETADATA__N_CONSUME_DBNAMELENGTH;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_START_ON_DB_NAME: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_SPAN_START_ON_DB_NAME;
            }
            this._spanOff0 = off;
            this._spanCb0 = this._on_db_name;
            current = S_N_COLMETADATA__N_CONSUME_DBNAMELENGTH;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DBNAMELENGTH_UINT_8: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DBNAMELENGTH_UINT_8;
            }
            this.dbNameLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_SPAN_START_ON_DB_NAME;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2_2: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2_2;
            }
            this.dataLength += buf[off] * 2 ** 8;
            off++;
            current = S_N_COLMETADATA__N_DBNAMELENGTH_UINT_8;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_2: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_2;
            }
            this.dataLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_BYTE2_2;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_END_ON_XML_SCHEMA_COLLECTION: {
            const start = this._spanOff0;
            this._spanOff0 = -1;
            const err = this._on_xml_schema_collection(buf, start, off) | 0;
            if (err !== 0) {
              this.error = err;
              this.errorOff = off;
              this._current = S_N_COLMETADATA__N_PAUSE;
              return S_ERROR;
            }
            current = S_N_COLMETADATA__N_PAUSE;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_CONSUME_XMLSCHEMACOLLECTIONLENGTH: {
            let avail = buf.length - off;
            const need = this.xmlSchemaCollectionLength;
            if (avail >= need) {
              off += need;
              this.xmlSchemaCollectionLength = 0;
              current = S_N_COLMETADATA__N_SPAN_END_ON_XML_SCHEMA_COLLECTION;
              continue;
            }

            this.xmlSchemaCollectionLength -= avail;
            return S_N_COLMETADATA__N_CONSUME_XMLSCHEMACOLLECTIONLENGTH;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_START_ON_XML_SCHEMA_COLLECTION: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_SPAN_START_ON_XML_SCHEMA_COLLECTION;
            }
            this._spanOff0 = off;
            this._spanCb0 = this._on_xml_schema_collection;
            current = S_N_COLMETADATA__N_CONSUME_XMLSCHEMACOLLECTIONLENGTH;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_XMLSCHEMACOLLECTIONLENGTH_UINT_16_LE_BYTE2: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_XMLSCHEMACOLLECTIONLENGTH_UINT_16_LE_BYTE2;
            }
            this.xmlSchemaCollectionLength += buf[off] * 2 ** 8;
            off++;
            current = S_N_COLMETADATA__N_SPAN_START_ON_XML_SCHEMA_COLLECTION;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_XMLSCHEMACOLLECTIONLENGTH_UINT_16_LE: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_XMLSCHEMACOLLECTIONLENGTH_UINT_16_LE;
            }
            this.xmlSchemaCollectionLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_XMLSCHEMACOLLECTIONLENGTH_UINT_16_LE_BYTE2;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_END_ON_OWNING_SCHEMA_1: {
            const start = this._spanOff0;
            this._spanOff0 = -1;
            const err = this._on_owning_schema(buf, start, off) | 0;
            if (err !== 0) {
              this.error = err;
              this.errorOff = off;
              this._current = S_N_COLMETADATA__N_XMLSCHEMACOLLECTIONLENGTH_UINT_16_LE;
              return S_ERROR;
            }
            current = S_N_COLMETADATA__N_XMLSCHEMACOLLECTIONLENGTH_UINT_16_LE;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_CONSUME_OWNINGSCHEMALENGTH_1: {
            let avail = buf.length - off;
            const need = this.owningSchemaLength;
            if (avail >= need) {
              off += need;
              this.owningSchemaLength = 0;
              current = S_N_COLMETADATA__N_SPAN_END_ON_OWNING_SCHEMA_1;
              continue;
            }

            this.owningSchemaLength -= avail;
            return S_N_COLMETADATA__N_CONSUME_OWNINGSCHEMALENGTH_1;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_START_ON_OWNING_SCHEMA_1: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_SPAN_START_ON_OWNING_SCHEMA_1;
            }
            this._spanOff0 = off;
            this._spanCb0 = this._on_owning_schema;
            current = S_N_COLMETADATA__N_CONSUME_OWNINGSCHEMALENGTH_1;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_OWNINGSCHEMALENGTH_UINT_8_1: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_OWNINGSCHEMALENGTH_UINT_8_1;
            }
            this.owningSchemaLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_SPAN_START_ON_OWNING_SCHEMA_1;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_END_ON_DB_NAME_1: {
            const start = this._spanOff0;
            this._spanOff0 = -1;
            const err = this._on_db_name(buf, start, off) | 0;
            if (err !== 0) {
              this.error = err;
              this.errorOff = off;
              this._current = S_N_COLMETADATA__N_OWNINGSCHEMALENGTH_UINT_8_1;
              return S_ERROR;
            }
            current = S_N_COLMETADATA__N_OWNINGSCHEMALENGTH_UINT_8_1;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_CONSUME_DBNAMELENGTH_1: {
            let avail = buf.length - off;
            const need = this.dbNameLength;
            if (avail >= need) {
              off += need;
              this.dbNameLength = 0;
              current = S_N_COLMETADATA__N_SPAN_END_ON_DB_NAME_1;
              continue;
            }

            this.dbNameLength -= avail;
            return S_N_COLMETADATA__N_CONSUME_DBNAMELENGTH_1;
            unreachable();
          }
          case S_N_COLMETADATA__N_SPAN_START_ON_DB_NAME_1: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_SPAN_START_ON_DB_NAME_1;
            }
            this._spanOff0 = off;
            this._spanCb0 = this._on_db_name;
            current = S_N_COLMETADATA__N_CONSUME_DBNAMELENGTH_1;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_DBNAMELENGTH_UINT_8_1: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_DBNAMELENGTH_UINT_8_1;
            }
            this.dbNameLength = buf[off];
            off++;
            current = S_N_COLMETADATA__N_SPAN_START_ON_DB_NAME_1;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_INVOKE_LOAD_SCHEMAPRESENT: {
            switch (this._colmetadata__c_load_schemaPresent(buf, off) | 0) {
              case 1:
                current = S_N_COLMETADATA__N_DBNAMELENGTH_UINT_8_1;
                continue;
              default:
                off++;
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
            }
            unreachable();
          }
          case S_N_COLMETADATA__N_SCHEMAPRESENT_UINT_8: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_SCHEMAPRESENT_UINT_8;
            }
            this.schemaPresent = buf[off];
            off++;
            current = S_N_COLMETADATA__N_INVOKE_LOAD_SCHEMAPRESENT;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_ERROR: {
            this.error = 0x1;
            this.reason = "Unknown type";
            this.errorOff = off;
            this._current = S_ERROR;
            return S_ERROR;
            unreachable();
          }
          case S_N_COLMETADATA__N_INVOKE_LOAD_TYPE: {
            switch (this._colmetadata__c_load_type(buf, off) | 0) {
              case 31:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 34:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE;
                continue;
              case 35:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_1;
                continue;
              case 36:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 37:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 38:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 39:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 41:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 42:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 43:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 45:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 47:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 48:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 50:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 52:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 55:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8_1;
                continue;
              case 56:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 58:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 59:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 60:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 61:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 62:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 63:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8_1;
                continue;
              case 98:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE;
                continue;
              case 99:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_32_LE_1;
                continue;
              case 104:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 106:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8_1;
                continue;
              case 108:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8_1;
                continue;
              case 109:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 110:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 111:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_8;
                continue;
              case 122:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 127:
                current = S_N_COLMETADATA__N_PAUSE;
                continue;
              case 165:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE;
                continue;
              case 167:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_1;
                continue;
              case 173:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE;
                continue;
              case 175:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_1;
                continue;
              case 231:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_1;
                continue;
              case 239:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_1;
                continue;
              case 240:
                current = S_N_COLMETADATA__N_DATALENGTH_UINT_16_LE_2;
                continue;
              case 241:
                current = S_N_COLMETADATA__N_SCHEMAPRESENT_UINT_8;
                continue;
              default:
                current = S_N_COLMETADATA__N_ERROR;
                continue;
            }
            unreachable();
          }
          case S_N_COLMETADATA__N_TYPE_UINT_8: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_TYPE_UINT_8;
            }
            this.type = buf[off];
            off++;
            current = S_N_COLMETADATA__N_INVOKE_LOAD_TYPE;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_FLAGS_UINT_16_LE_BYTE2: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_FLAGS_UINT_16_LE_BYTE2;
            }
            this.flags += buf[off] * 2 ** 8;
            off++;
            current = S_N_COLMETADATA__N_TYPE_UINT_8;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_FLAGS_UINT_16_LE: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_FLAGS_UINT_16_LE;
            }
            this.flags = buf[off];
            off++;
            current = S_N_COLMETADATA__N_FLAGS_UINT_16_LE_BYTE2;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE4: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE4;
            }
            this.userType += buf[off] * 2 ** 24;
            off++;
            current = S_N_COLMETADATA__N_FLAGS_UINT_16_LE;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE3: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE3;
            }
            this.userType += buf[off] * 2 ** 16;
            off++;
            current = S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE4;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE2: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE2;
            }
            this.userType += buf[off] * 2 ** 8;
            off++;
            current = S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE3;
            continue;
            unreachable();
          }
          case S_N_COLMETADATA__N_USERTYPE_UINT_32_LE: {
            if (off === buf.length) {
              return S_N_COLMETADATA__N_USERTYPE_UINT_32_LE;
            }
            this.userType = buf[off];
            off++;
            current = S_N_COLMETADATA__N_USERTYPE_UINT_32_LE_BYTE2;
            continue;
            unreachable();
          }
        }
      }
      unreachable();
    }

    execute(buf) {
      // check lingering errors
      if (this.error !== 0) {
        return this.error;
      }

      // restart spans
      if (this._spanOff0 !== -1) {
        this._spanOff0 = 0;
      }

      const next = this._run(this._current, buf, 0);
      if (next === S_ERROR) {
        return this.error;
      }
      this._current = next;

      // execute spans
      if (this._spanOff0 !== -1) {
        const error = this._spanCb0(buf, this._spanOff0, buf.length) | 0;
        if (error !== 0) {
          this.error = error;
          this.errorOff = buf.length;
          return error;
        }
      }

      return 0;
    }
  }

  return Parser;
};
arthurschreiber commented 4 years ago

@indutny I see that properties don't carry any sign information - is that a purposeful design decision in llparse? Does that mean that property access in C needs to be casted appropriately to not get the unsigned value? Am I missing something? 🤔

indutny commented 4 years ago

@arthurschreiber this is a design decision that was historically motivated by bitcode output. C has to cast fields if a signed access is required.