allow functions to call other functions #53

This commit is contained in:
undergroundwires
2021-01-16 13:26:41 +01:00
parent f1abd7682f
commit 7661575573
38 changed files with 1507 additions and 645 deletions

View File

@@ -0,0 +1,28 @@
import { IExpressionsCompiler, ParameterValueDictionary } from '@/application/Parser/Script/Compiler/Expressions/IExpressionsCompiler';
interface Scenario { code: string; parameters: ParameterValueDictionary; result: string; }
export class ExpressionsCompilerStub implements IExpressionsCompiler {
private readonly scenarios = new Array<Scenario>();
public setup(code: string, parameters: ParameterValueDictionary, result: string) {
this.scenarios.push({ code, parameters, result });
return this;
}
public compileExpressions(code: string, parameters?: ParameterValueDictionary): string {
const scenario = this.scenarios.find((s) => s.code === code && deepEqual(s.parameters, parameters));
if (scenario) {
return scenario.result;
}
return `[ExpressionsCompilerStub] code: "${code}"` +
`| parameters: ${Object.keys(parameters || {}).map((p) => p + '=' + parameters[p]).join(',')}`;
}
}
function deepEqual(dict1: ParameterValueDictionary, dict2: ParameterValueDictionary) {
const dict1Keys = Object.keys(dict1 || {});
const dict2Keys = Object.keys(dict2 || {});
if (dict1Keys.length !== dict2Keys.length) {
return false;
}
return dict1Keys.every((key) => dict2.hasOwnProperty(key) && dict2[key] === dict1[key]);
}

View File

@@ -0,0 +1,26 @@
import { ISharedFunctionCollection } from '@/application/Parser/Script/Compiler/Function/ISharedFunctionCollection';
import { ICompiledCode } from '@/application/Parser/Script/Compiler/FunctionCall/ICompiledCode';
import { IFunctionCallCompiler } from '@/application/Parser/Script/Compiler/FunctionCall/IFunctionCallCompiler';
import { FunctionCallData, ScriptFunctionCallData } from 'js-yaml-loader!*';
interface Scenario { call: ScriptFunctionCallData; functions: ISharedFunctionCollection; result: ICompiledCode; }
export class FunctionCallCompilerStub implements IFunctionCallCompiler {
public scenarios = new Array<Scenario>();
public setup(call: ScriptFunctionCallData, functions: ISharedFunctionCollection, result: ICompiledCode) {
this.scenarios.push({ call, functions, result });
}
public compileCall(
call: ScriptFunctionCallData,
functions: ISharedFunctionCollection): ICompiledCode {
const predefined = this.scenarios.find((s) => s.call === call && s.functions === functions);
if (predefined) {
return predefined.result;
}
const callee = functions.getFunctionByName((call as FunctionCallData).function);
return {
code: callee.code,
revertCode: callee.revertCode,
};
}
}

View File

@@ -0,0 +1,41 @@
import { IFunctionCompiler } from '@/application/Parser/Script/Compiler/Function/IFunctionCompiler';
import { ISharedFunctionCollection } from '@/application/Parser/Script/Compiler/Function/ISharedFunctionCollection';
import { FunctionData } from 'js-yaml-loader!*';
import { SharedFunctionCollectionStub } from './SharedFunctionCollectionStub';
export class FunctionCompilerStub implements IFunctionCompiler {
private setupResults = new Array<{
functions: readonly FunctionData[],
result: ISharedFunctionCollection,
}>();
public setup(functions: readonly FunctionData[], result: ISharedFunctionCollection) {
this.setupResults.push( { functions, result });
}
public compileFunctions(functions: readonly FunctionData[]): ISharedFunctionCollection {
const result = this.findResult(functions);
return result || new SharedFunctionCollectionStub();
}
private findResult(functions: readonly FunctionData[]): ISharedFunctionCollection {
for (const result of this.setupResults) {
if (sequenceEqual(result.functions, functions)) {
return result.result;
}
}
return undefined;
}
}
function sequenceEqual<T>(array1: readonly T[], array2: readonly T[]) {
if (array1.length !== array2.length) {
return false;
}
const sortedArray1 = sort(array1);
const sortedArray2 = sort(array2);
return sortedArray1.every((val, index) => val === sortedArray2[index]);
function sort(array: readonly T[]) {
return array.slice().sort();
}
}

View File

@@ -1,10 +1,31 @@
import { FunctionData } from 'js-yaml-loader!*';
import { FunctionData, ScriptFunctionCallData } from 'js-yaml-loader!*';
export class FunctionDataStub implements FunctionData {
public static createWithCode() {
return new FunctionDataStub()
.withCode('stub-code')
.withRevertCode('stub-revert-code');
}
public static createWithCall(call?: ScriptFunctionCallData) {
let instance = new FunctionDataStub();
if (call) {
instance = instance.withCall(call);
} else {
instance = instance.withMockCall();
}
return instance;
}
public static createWithoutCallOrCodes() {
return new FunctionDataStub();
}
public name = 'function data stub';
public code = 'function data stub code';
public revertCode = 'function data stub revertCode';
public code: string;
public revertCode: string;
public parameters?: readonly string[];
public call?: ScriptFunctionCallData;
private constructor() { }
public withName(name: string) {
this.name = name;
@@ -22,4 +43,12 @@ export class FunctionDataStub implements FunctionData {
this.revertCode = revertCode;
return this;
}
public withCall(call: ScriptFunctionCallData) {
this.call = call;
return this;
}
public withMockCall() {
this.call = { function: 'func' };
return this;
}
}

View File

@@ -27,6 +27,8 @@ export class ScriptDataStub implements ScriptData {
public recommend = RecommendationLevel[RecommendationLevel.Standard].toLowerCase();
public docs = ['hello.com'];
private constructor() { }
public withName(name: string): ScriptDataStub {
this.name = name;
return this;

View File

@@ -0,0 +1,21 @@
import { ISharedFunction } from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
import { ISharedFunctionCollection } from '@/application/Parser/Script/Compiler/Function/ISharedFunctionCollection';
export class SharedFunctionCollectionStub implements ISharedFunctionCollection {
private readonly functions = new Map<string, ISharedFunction>();
public withFunction(func: ISharedFunction) {
this.functions.set(func.name, func);
return this;
}
public getFunctionByName(name: string): ISharedFunction {
if (this.functions.has(name)) {
return this.functions.get(name);
}
return {
name,
parameters: [],
code: 'code by SharedFunctionCollectionStub',
revertCode: 'revert-code by SharedFunctionCollectionStub',
};
}
}

View File

@@ -0,0 +1,27 @@
import { ISharedFunction } from '@/application/Parser/Script/Compiler/Function/ISharedFunction';
export class SharedFunctionStub implements ISharedFunction {
public name = 'shared-function-stub-name';
public parameters?: readonly string[] = [
'shared-function-stub-parameter',
];
public code = 'shared-function-stub-code';
public revertCode = 'shared-function-stub-revert-code';
public withName(name: string) {
this.name = name;
return this;
}
public withCode(code: string) {
this.code = code;
return this;
}
public withRevertCode(revertCode: string) {
this.revertCode = revertCode;
return this;
}
public withParameters(...params: string[]) {
this.parameters = params;
return this;
}
}