summaryrefslogtreecommitdiffstats
path: root/llparse-builder/src/code
diff options
context:
space:
mode:
Diffstat (limited to 'llparse-builder/src/code')
-rw-r--r--llparse-builder/src/code/and.ts7
-rw-r--r--llparse-builder/src/code/base.ts16
-rw-r--r--llparse-builder/src/code/creator.ts184
-rw-r--r--llparse-builder/src/code/field-value.ts9
-rw-r--r--llparse-builder/src/code/field.ts10
-rw-r--r--llparse-builder/src/code/index.ts15
-rw-r--r--llparse-builder/src/code/is-equal.ts7
-rw-r--r--llparse-builder/src/code/load.ts7
-rw-r--r--llparse-builder/src/code/match.ts7
-rw-r--r--llparse-builder/src/code/mul-add.ts28
-rw-r--r--llparse-builder/src/code/or.ts7
-rw-r--r--llparse-builder/src/code/span.ts5
-rw-r--r--llparse-builder/src/code/store.ts7
-rw-r--r--llparse-builder/src/code/test.ts7
-rw-r--r--llparse-builder/src/code/update.ts7
-rw-r--r--llparse-builder/src/code/value.ts7
16 files changed, 330 insertions, 0 deletions
diff --git a/llparse-builder/src/code/and.ts b/llparse-builder/src/code/and.ts
new file mode 100644
index 0000000..5f78675
--- /dev/null
+++ b/llparse-builder/src/code/and.ts
@@ -0,0 +1,7 @@
+import { FieldValue } from './field-value';
+
+export class And extends FieldValue {
+ constructor(field: string, value: number) {
+ super('match', 'and', field, value);
+ }
+}
diff --git a/llparse-builder/src/code/base.ts b/llparse-builder/src/code/base.ts
new file mode 100644
index 0000000..00b479f
--- /dev/null
+++ b/llparse-builder/src/code/base.ts
@@ -0,0 +1,16 @@
+export type Signature = 'match' | 'value';
+
+/**
+ * Base code class.
+ */
+export abstract class Code {
+ /**
+ * @param signature Code signature to be used. `match` means that code takes
+ * no input value (from `.select()`), otherwise it must be
+ * `value`
+ * @param name External function or intrinsic name.
+ */
+ constructor(public readonly signature: Signature,
+ public readonly name: string) {
+ }
+}
diff --git a/llparse-builder/src/code/creator.ts b/llparse-builder/src/code/creator.ts
new file mode 100644
index 0000000..98f9296
--- /dev/null
+++ b/llparse-builder/src/code/creator.ts
@@ -0,0 +1,184 @@
+import * as code from './';
+
+/**
+ * API for creating external callbacks and intrinsic operations.
+ */
+export class Creator {
+ // Callbacks to external C functions
+
+ /**
+ * Create an external callback that **has no** `value` argument.
+ *
+ * This callback can be used in all `Invoke` nodes except those that are
+ * targets of `.select()` method.
+ *
+ * C signature of callback must be:
+ *
+ * ```c
+ * int name(llparse_t* state, const char* p, const char* endp)
+ * ```
+ *
+ * Where `llparse_t` is parser state's type name.
+ *
+ * @param name External function name.
+ */
+ public match(name: string): code.Match {
+ return new code.Match(name);
+ }
+
+ /**
+ * Create an external callback that **has** `value` argument.
+ *
+ * This callback can be used only in `Invoke` nodes that are targets of
+ * `.select()` method.
+ *
+ * C signature of callback must be:
+ *
+ * ```c
+ * int name(llparse_t* state, const char* p, const char* endp, int value)
+ * ```
+ *
+ * Where `llparse_t` is parser state's type name.
+ *
+ * @param name External function name.
+ */
+ public value(name: string): code.Value {
+ return new code.Value(name);
+ }
+
+ /**
+ * Create an external span callback.
+ *
+ * This callback can be used only in `Span` constructor.
+ *
+ * C signature of callback must be:
+ *
+ * ```c
+ * int name(llparse_t* state, const char* p, const char* endp)
+ * ```
+ *
+ * NOTE: non-zero return value is treated as resumable error.
+ *
+ * @param name External function name.
+ */
+ public span(name: string): code.Span {
+ return new code.Span(name);
+ }
+
+ // Helpers
+
+ /**
+ * Intrinsic operation. Stores `value` from `.select()` node into the state's
+ * property with the name specified by `field`, returns zero.
+ *
+ * state[field] = value;
+ * return 0;
+ *
+ * @param field Property name
+ */
+ public store(field: string): code.Store {
+ return new code.Store(field);
+ }
+
+ /**
+ * Intrinsic operation. Loads and returns state's property with the name
+ * specified by `field`.
+ *
+ * The value of the property is either truncated or zero-extended to fit into
+ * 32-bit unsigned integer.
+ *
+ * return state[field];
+ *
+ * @param field Property name.
+ */
+ public load(field: string): code.Load {
+ return new code.Load(field);
+ }
+
+ /**
+ * Intrinsic operation. Takes `value` from `.select()`, state's property
+ * with the name `field` and does:
+ *
+ * field = state[field];
+ * field *= options.base;
+ * field += value;
+ * state[field] = field;
+ * return 0; // or 1 on overflow
+ *
+ * Return values are:
+ *
+ * - 0 - success
+ * - 1 - overflow
+ *
+ * @param field Property name
+ * @param options See `code.MulAdd` documentation.
+ */
+ public mulAdd(field: string, options: code.IMulAddOptions): code.MulAdd {
+ return new code.MulAdd(field, options);
+ }
+
+ /**
+ * Intrinsic operation. Puts `value` integer into the state's property with
+ * the name specified by `field`.
+ *
+ * state[field] = value;
+ * return 0;
+ *
+ * @param field Property name
+ * @param value Integer value to be stored into the property.
+ */
+ public update(field: string, value: number): code.Update {
+ return new code.Update(field, value);
+ }
+
+ /**
+ * Intrinsic operation. Returns 1 if the integer `value` is equal to the
+ * state's property with the name specified by `field`.
+ *
+ * return state[field] === value ? 1 : 0;
+ *
+ * @param field Property name
+ * @param value Integer value to be checked against.
+ */
+ public isEqual(field: string, value: number): code.IsEqual {
+ return new code.IsEqual(field, value);
+ }
+
+ /**
+ * Intrinsic operation.
+ *
+ * state[field] &= value
+ * return 0;
+ *
+ * @param field Property name
+ * @param value Integer value
+ */
+ public and(field: string, value: number): code.And {
+ return new code.And(field, value);
+ }
+
+ /**
+ * Intrinsic operation.
+ *
+ * state[field] |= value
+ * return 0;
+ *
+ * @param field Property name
+ * @param value Integer value
+ */
+ public or(field: string, value: number): code.Or {
+ return new code.Or(field, value);
+ }
+
+ /**
+ * Intrinsic operation.
+ *
+ * return (state[field] & value) == value ? 1 : 0;
+ *
+ * @param field Property name
+ * @param value Integer value
+ */
+ public test(field: string, value: number): code.Test {
+ return new code.Test(field, value);
+ }
+}
diff --git a/llparse-builder/src/code/field-value.ts b/llparse-builder/src/code/field-value.ts
new file mode 100644
index 0000000..2ceea69
--- /dev/null
+++ b/llparse-builder/src/code/field-value.ts
@@ -0,0 +1,9 @@
+import { Signature } from './base';
+import { Field } from './field';
+
+export abstract class FieldValue extends Field {
+ constructor(signature: Signature, name: string, field: string,
+ public readonly value: number) {
+ super(signature, name, field);
+ }
+}
diff --git a/llparse-builder/src/code/field.ts b/llparse-builder/src/code/field.ts
new file mode 100644
index 0000000..af58c84
--- /dev/null
+++ b/llparse-builder/src/code/field.ts
@@ -0,0 +1,10 @@
+import * as assert from 'assert';
+import { Code, Signature } from './base';
+
+export abstract class Field extends Code {
+ constructor(signature: Signature, name: string,
+ public readonly field: string) {
+ super(signature, name + '_' + field);
+ assert(!/^_/.test(field), 'Can\'t access internal field from user code');
+ }
+}
diff --git a/llparse-builder/src/code/index.ts b/llparse-builder/src/code/index.ts
new file mode 100644
index 0000000..7a651e3
--- /dev/null
+++ b/llparse-builder/src/code/index.ts
@@ -0,0 +1,15 @@
+export { Code } from './base';
+export { Creator } from './creator';
+export { Field } from './field';
+export { FieldValue } from './field-value';
+export { IsEqual } from './is-equal';
+export { Load } from './load';
+export { Match } from './match';
+export { IMulAddOptions, MulAdd } from './mul-add';
+export { Or } from './or';
+export { And } from './and';
+export { Span } from './span';
+export { Store } from './store';
+export { Test } from './test';
+export { Update } from './update';
+export { Value } from './value';
diff --git a/llparse-builder/src/code/is-equal.ts b/llparse-builder/src/code/is-equal.ts
new file mode 100644
index 0000000..91bb957
--- /dev/null
+++ b/llparse-builder/src/code/is-equal.ts
@@ -0,0 +1,7 @@
+import { FieldValue } from './field-value';
+
+export class IsEqual extends FieldValue {
+ constructor(field: string, value: number) {
+ super('match', 'is_equal', field, value);
+ }
+}
diff --git a/llparse-builder/src/code/load.ts b/llparse-builder/src/code/load.ts
new file mode 100644
index 0000000..9f3df2e
--- /dev/null
+++ b/llparse-builder/src/code/load.ts
@@ -0,0 +1,7 @@
+import { Field } from './field';
+
+export class Load extends Field {
+ constructor(field: string) {
+ super('match', 'load', field);
+ }
+}
diff --git a/llparse-builder/src/code/match.ts b/llparse-builder/src/code/match.ts
new file mode 100644
index 0000000..631376a
--- /dev/null
+++ b/llparse-builder/src/code/match.ts
@@ -0,0 +1,7 @@
+import { Code } from './base';
+
+export class Match extends Code {
+ constructor(name: string) {
+ super('match', name);
+ }
+}
diff --git a/llparse-builder/src/code/mul-add.ts b/llparse-builder/src/code/mul-add.ts
new file mode 100644
index 0000000..fd648ed
--- /dev/null
+++ b/llparse-builder/src/code/mul-add.ts
@@ -0,0 +1,28 @@
+import { Field } from './field';
+
+/**
+ * Options for `code.mulAdd()`.
+ */
+export interface IMulAddOptions {
+ /** Value to multiply the property with in the first step */
+ readonly base: number;
+
+ /**
+ * Maximum value of the property. If at any point of computation the
+ * intermediate result exceeds it - `mulAdd` returns 1 (overflow).
+ */
+ readonly max?: number;
+
+ /**
+ * If `true` - all arithmetics perfomed by `mulAdd` will be signed.
+ *
+ * Default value: `false`
+ */
+ readonly signed?: boolean;
+}
+
+export class MulAdd extends Field {
+ constructor(field: string, public readonly options: IMulAddOptions) {
+ super('value', 'mul_add', field);
+ }
+}
diff --git a/llparse-builder/src/code/or.ts b/llparse-builder/src/code/or.ts
new file mode 100644
index 0000000..33bd402
--- /dev/null
+++ b/llparse-builder/src/code/or.ts
@@ -0,0 +1,7 @@
+import { FieldValue } from './field-value';
+
+export class Or extends FieldValue {
+ constructor(field: string, value: number) {
+ super('match', 'or', field, value);
+ }
+}
diff --git a/llparse-builder/src/code/span.ts b/llparse-builder/src/code/span.ts
new file mode 100644
index 0000000..b97e09e
--- /dev/null
+++ b/llparse-builder/src/code/span.ts
@@ -0,0 +1,5 @@
+import { Match } from './match';
+
+export class Span extends Match {
+ // no-op
+}
diff --git a/llparse-builder/src/code/store.ts b/llparse-builder/src/code/store.ts
new file mode 100644
index 0000000..84abfef
--- /dev/null
+++ b/llparse-builder/src/code/store.ts
@@ -0,0 +1,7 @@
+import { Field } from './field';
+
+export class Store extends Field {
+ constructor(field: string) {
+ super('value', 'store', field);
+ }
+}
diff --git a/llparse-builder/src/code/test.ts b/llparse-builder/src/code/test.ts
new file mode 100644
index 0000000..a9d0a22
--- /dev/null
+++ b/llparse-builder/src/code/test.ts
@@ -0,0 +1,7 @@
+import { FieldValue } from './field-value';
+
+export class Test extends FieldValue {
+ constructor(field: string, value: number) {
+ super('match', 'test', field, value);
+ }
+}
diff --git a/llparse-builder/src/code/update.ts b/llparse-builder/src/code/update.ts
new file mode 100644
index 0000000..de62476
--- /dev/null
+++ b/llparse-builder/src/code/update.ts
@@ -0,0 +1,7 @@
+import { FieldValue } from './field-value';
+
+export class Update extends FieldValue {
+ constructor(field: string, value: number) {
+ super('match', 'update', field, value);
+ }
+}
diff --git a/llparse-builder/src/code/value.ts b/llparse-builder/src/code/value.ts
new file mode 100644
index 0000000..06c6fd7
--- /dev/null
+++ b/llparse-builder/src/code/value.ts
@@ -0,0 +1,7 @@
+import { Code } from './base';
+
+export class Value extends Code {
+ constructor(name: string) {
+ super('value', name);
+ }
+}