Skip to content

Commit

Permalink
feat(core): new framework for plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
denizenging committed Oct 3, 2023
1 parent 96375b9 commit 5af445c
Show file tree
Hide file tree
Showing 9 changed files with 555 additions and 1,131 deletions.
9 changes: 9 additions & 0 deletions pkg/core/src/lexer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { allTokens } from '@slangroom/core/tokens';
import { Lexer as L } from '@slangroom/deps/chevrotain';

const Lexer = new L(allTokens);

/**
* Lexes the given line.
*/
export const lex = (line: string) => Lexer.tokenize(line);
75 changes: 75 additions & 0 deletions pkg/core/src/parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {
allTokens,
Read,
Connect,
Save,
Within,
And,
Into,
Buzzword,
Identifier,
} from '@slangroom/core/tokens';
import { CstParser, type IToken } from '@slangroom/deps/chevrotain';

const Parser = new (class extends CstParser {
constructor() {
super(allTokens);
this.performSelfAnalysis();
}

statement = this.RULE('statement', () => {
this.OR([
{ ALT: () => this.SUBRULE(this.#connect) },
{ ALT: () => this.SUBRULE(this.#read) },
]);
});

#connect = this.RULE('connect', () => {
this.CONSUME(Connect);
this.SUBRULE(this.#action);
});

#read = this.RULE('read', () => {
this.CONSUME(Read);
this.SUBRULE(this.#action, { LABEL: 'readAction' });
this.OPTION(() =>
this.OR([
{ ALT: () => this.SUBRULE(this.#andSave) },
{ ALT: () => this.SUBRULE(this.#into) },
])
);
});

#andSave = this.RULE('andSave', () => {
this.CONSUME(And);
this.CONSUME(Save);
this.SUBRULE(this.#action, { LABEL: 'saveAction' });
});

#into = this.RULE('into', () => {
this.CONSUME(Into);
this.CONSUME(Identifier, { LABEL: 'intoIdentifier' });
this.OPTION(() => this.SUBRULE(this.#within));
});

#within = this.RULE('within', () => {
this.CONSUME(Within);
this.CONSUME(Identifier, { LABEL: 'withinIdentifier' });
});

#action = this.RULE('action', () => {
this.AT_LEAST_ONE(() => this.SUBRULE(this.#phrase));
});

#phrase = this.RULE('phrase', () => {
this.CONSUME(Buzzword);
this.OPTION(() => this.CONSUME(Identifier));
});
})();

export const CstVisitor = Parser.getBaseCstVisitorConstructor();

export const parse = (tokens: IToken[]) => {
Parser.input = tokens;
return Parser.statement();
};
149 changes: 101 additions & 48 deletions pkg/core/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,105 @@
import type { ZenroomParams, JsonableObject } from '@slangroom/shared';

/**
* A plugin that must be executed **before** the actual Zenroom execution takes
* place.
*
* The plugin is defined using a single parameter which is a callback,
* named [execute], which takes in the necessary parameters from [BeforeParams]
* and optionally returns a [ZenroomParams].
*/
export class BeforePlugin {
constructor(
readonly execute: (params: BeforeParams
) => Promise<void> | void | Promise<JsonableObject> | JsonableObject
) { }
import type { Jsonable, JsonableObject, ZenroomParams } from '@slangroom/shared';
import { Action } from '@slangroom/core/visitor';

export class ExecContext {
#store = new Map<any, any>();

get(key: any): any {
return this.#store.get(key);
}

set(key: any, value: any) {
this.#store.set(key, value);
}
}

/**
* A plugin that must be executed **after** the actual Zenroom execution takes
* place.
*
* The plugin is defined using a single parameter which is a callback,
* named [execute], which takes in the necessary parameters from [AfterParams].
*/
export class AfterPlugin {
constructor(readonly execute: (params: AfterParams
) => Promise<void> | void | Promise<JsonableObject> | JsonableObject
) { }
export class ExecParams {
#data: JsonableObject;
#keys: JsonableObject;

contsructor(params: ZenroomParams) {
this.#data = params.data || {};
this.#keys = params.keys || {};
}

get(key: string): Jsonable | undefined {
return this.#data[key] ? this.#data[key] : this.#keys[key];
}

set(key: string, value: Jsonable) {
this.#data[key] = value;
}
}

/**
* The parameters passed down to [BeforePlugin]'s callback.
*
* [statement] is the ignored statement for each iteration.
* [params] is the original parameters passed to Zenroom, if any.
*/
export type BeforeParams = {
readonly statement: string;
readonly params: ZenroomParams | undefined;
};

/**
* The parameters passed down to [BeforePlugin]'s callback.
* [statement] is the ignored statement for each iteration.
* [params] is the original parameters passed to Zenroom, if any.
* [result] is the result of the actual Zenroom execution.
*/
export type AfterParams = {
readonly statement: string;
readonly params: ZenroomParams | undefined;
readonly result: JsonableObject;
};
export abstract class Plugin {
#phrase: string;

constructor(phrase: string) {
this.#phrase = phrase.toLowerCase();
}

match(actn: Action) {
return actn.phrase.toLowerCase() === this.#phrase;
}

abstract execute(params: ExecParams, ctx: ExecContext): void | Promise<void>;
}

export class ConnectPlugin extends Plugin {
#execute: (params: ExecParams, ctx: ExecContext) => void;
constructor(phrase: string, cb: (params: ExecParams, ctx: ExecContext) => void) {
super(phrase);
// TODO: using `phrase`, fetch all the variables and put them inside
// `ExecParams`.
this.#execute = cb;
}

execute(params: ExecParams, ctx: ExecContext) {
this.#execute(params, ctx);
}
}

export class ReadPlugin extends Plugin {
#execute: (params: ExecParams, ctx: ExecContext) => void;

constructor(phrase: string, cb: (params: ExecParams, ctx: ExecContext) => void) {
super(phrase);
// TODO: using `phrase`, fetch all the variables and put them inside
// `ExecParams`.
this.#execute = cb;
}

execute(params: ExecParams, ctx: ExecContext) {
this.#execute(params, ctx);
}
}

export class IntoPlugin extends Plugin {
#execute: (params: ExecParams) => void;

constructor(phrase: string, cb: (params: ExecParams) => void) {
super(phrase);
// TODO: using `phrase`, fetch all the variables and put them inside
// `ExecParams`.
this.#execute = cb;
}

execute(params: ExecParams) {
this.#execute(params);
}
}

export class SavePlugin extends Plugin {
#execute: (params: ExecParams) => void;

constructor(phrase: string, cb: (params: ExecParams) => void) {
super(phrase);
// TODO: using `phrase`, fetch all the variables and put them inside
// `ExecParams`.
this.#execute = cb;
}

execute(params: ExecParams) {
this.#execute(params);
}
}
Loading

0 comments on commit 5af445c

Please sign in to comment.