diff --git a/src/builder.ts b/src/builder.ts index 6b308f2..d59525f 100644 --- a/src/builder.ts +++ b/src/builder.ts @@ -5,6 +5,7 @@ import { Span } from './span'; import * as transform from './transform'; export { code, node, transform, Property, PropertyType, Span }; +export { Endianess } from "./code"; export { Edge } from './edge'; export { LoopChecker } from './loop-checker'; export { ISpanAllocatorResult, SpanAllocator } from './span-allocator'; @@ -72,6 +73,8 @@ export class Builder { otherwise?: node.Node): node.Invoke { let res: node.Invoke; + // TODO: (Vizonex) Should we add a check for non-existant unpack properties here? + // `.invoke(name)` if (map === undefined) { res = new node.Invoke(fn, {}); diff --git a/src/code/creator.ts b/src/code/creator.ts index 98f9296..21bbe9a 100644 --- a/src/code/creator.ts +++ b/src/code/creator.ts @@ -181,4 +181,20 @@ export class Creator { public test(field: string, value: number): code.Test { return new code.Test(field, value); } + + /** + * Intrinsic operation. + * + * state[field] <<= 8 or >>= 8 (depending on endianess) + * state[field] |= value + * return (state[field] < (property size limit)) ? 0 : -1; + * + * @param field Property Name + * @param endianness Endianness Enum to determine if big + * or little endianness should be accounted for. + * defaults to `Endianess.Little` + */ + public unpack(field: string, endianness?: code.Endianess) : code.Unpack { + return new code.Unpack(field, endianness); + } } diff --git a/src/code/index.ts b/src/code/index.ts index 7a651e3..1e06b34 100644 --- a/src/code/index.ts +++ b/src/code/index.ts @@ -13,3 +13,4 @@ export { Store } from './store'; export { Test } from './test'; export { Update } from './update'; export { Value } from './value'; +export { Unpack, Endianess } from './unpack'; diff --git a/src/code/unpack.ts b/src/code/unpack.ts new file mode 100644 index 0000000..1ddc455 --- /dev/null +++ b/src/code/unpack.ts @@ -0,0 +1,32 @@ +import { Field } from "./field"; + +/** Options for `code.unpack()` */ +export enum Endianess { + Little = 0, + Big = 1 +}; + +/** Helps with making unpacking protocols. + * It unpacks variables via left & right shifting + * based on a given endianness argument + */ +export class Unpack extends Field { + public readonly bigEndian:boolean; + /** + * @param field Name of the property that should be unpacked to + * @param endianness determines how to unpack the value provided + * Default Value: `Endianess.Little`. + */ + + constructor (field: string, endianness?:Endianess){ + if (endianness === undefined){ + endianness = Endianess.Little; + } + super( + 'match', + endianness == Endianess.Little ? 'unpack_le' : 'unpack_be', + field + ); + this.bigEndian = endianness == Endianess.Big; + } +} diff --git a/test/builder.test.ts b/test/builder.test.ts index ceffbed..22a7dc4 100644 --- a/test/builder.test.ts +++ b/test/builder.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, it, type TestContext } from 'node:test'; -import { Builder } from '../src/builder'; +import { Builder, Endianess } from '../src/builder'; describe('LLParse/Builder', () => { let b: Builder; @@ -88,4 +88,18 @@ describe('LLParse/Builder', () => { 10, ]); }); + + it('should create an unpack for Invoke'), (t: TestContext) => { + const start = b.node('start'); + b.property('i16', 'unpack_value'); + const unpack_error = b.error(0, 'failed to unpack value'); + const invoke = b.invoke( + b.code.unpack('unpack_value', Endianess.Little), + start, unpack_error + ); + const otherwise = invoke.getOtherwiseEdge(); + t.assert.deepStrictEqual( + otherwise?.node, unpack_error + ); + } });