summaryrefslogtreecommitdiffstats
path: root/llparse-frontend/src/container
diff options
context:
space:
mode:
Diffstat (limited to 'llparse-frontend/src/container')
-rw-r--r--llparse-frontend/src/container/index.ts84
-rw-r--r--llparse-frontend/src/container/wrap.ts15
2 files changed, 99 insertions, 0 deletions
diff --git a/llparse-frontend/src/container/index.ts b/llparse-frontend/src/container/index.ts
new file mode 100644
index 0000000..a62aac8
--- /dev/null
+++ b/llparse-frontend/src/container/index.ts
@@ -0,0 +1,84 @@
+import * as assert from 'assert';
+
+import { ICodeImplementation } from '../implementation/code';
+import { IImplementation } from '../implementation/full';
+import { INodeImplementation } from '../implementation/node';
+import { ITransformImplementation } from '../implementation/transform';
+import { IWrap } from '../wrap';
+import { ContainerWrap } from './wrap';
+
+export { ContainerWrap };
+
+export class Container {
+ private readonly map: Map<string, IImplementation> = new Map();
+
+ public add(key: string, impl: IImplementation): void {
+ assert(!this.map.has(key), `Duplicate implementation key: "${key}"`);
+ this.map.set(key, impl);
+ }
+
+ public build(): IImplementation {
+ return {
+ code: this.buildCode(),
+ node: this.buildNode(),
+ transform: this.buildTransform(),
+ };
+ }
+
+ public buildCode(): ICodeImplementation {
+ return {
+ And: this.combine((impl) => impl.code.And),
+ IsEqual: this.combine((impl) => impl.code.IsEqual),
+ Load: this.combine((impl) => impl.code.Load),
+ Match: this.combine((impl) => impl.code.Match),
+ MulAdd: this.combine((impl) => impl.code.MulAdd),
+ Or: this.combine((impl) => impl.code.Or),
+ Span: this.combine((impl) => impl.code.Span),
+ Store: this.combine((impl) => impl.code.Store),
+ Test: this.combine((impl) => impl.code.Test),
+ Update: this.combine((impl) => impl.code.Update),
+ Value: this.combine((impl) => impl.code.Value),
+ };
+ }
+
+ public buildNode(): INodeImplementation {
+ return {
+ Consume: this.combine((impl) => impl.node.Consume),
+ Empty: this.combine((impl) => impl.node.Empty),
+ Error: this.combine((impl) => impl.node.Error),
+ Invoke: this.combine((impl) => impl.node.Invoke),
+ Pause: this.combine((impl) => impl.node.Pause),
+ Sequence: this.combine((impl) => impl.node.Sequence),
+ Single: this.combine((impl) => impl.node.Single),
+ SpanEnd: this.combine((impl) => impl.node.SpanEnd),
+ SpanStart: this.combine((impl) => impl.node.SpanStart),
+ TableLookup: this.combine((impl) => impl.node.TableLookup),
+ };
+ }
+
+ public buildTransform(): ITransformImplementation {
+ return {
+ ID: this.combine((impl) => impl.transform.ID),
+ ToLower: this.combine((impl) => impl.transform.ToLower),
+ ToLowerUnsafe: this.combine((impl) => impl.transform.ToLowerUnsafe),
+ };
+ }
+
+ private combine<T>(gather: (impl: IImplementation) => new(n: T) => IWrap<T>)
+ : new(n: T) => ContainerWrap<T> {
+ const wraps: Map<string, new(n: T) => IWrap<T>> = new Map();
+ for (const [ key, impl ] of this.map) {
+ wraps.set(key, gather(impl));
+ }
+
+ return class ContainerWrapSingle extends ContainerWrap<T> {
+ constructor(ref: T) {
+ super(ref);
+
+ for (const [ key, impl ] of wraps) {
+ this.map.set(key, new impl(ref));
+ }
+ }
+ };
+ }
+}
diff --git a/llparse-frontend/src/container/wrap.ts b/llparse-frontend/src/container/wrap.ts
new file mode 100644
index 0000000..f3b886c
--- /dev/null
+++ b/llparse-frontend/src/container/wrap.ts
@@ -0,0 +1,15 @@
+import * as assert from 'assert';
+
+import { IWrap } from '../wrap';
+
+export class ContainerWrap<T> {
+ protected readonly map: Map<string, IWrap<T>> = new Map();
+
+ constructor(public readonly ref: T) {
+ }
+
+ public get<R extends IWrap<T>>(key: string): R {
+ assert(this.map.has(key), `Unknown implementation key "${key}"`);
+ return this.map.get(key)! as R;
+ }
+}