This commit is contained in:
@@ -1,31 +1,49 @@
|
||||
import { IExpressionsCompiler, ParameterValueDictionary } from './IExpressionsCompiler';
|
||||
import { generateIlCode, IILCode } from './ILCode';
|
||||
import { IExpression } from './Expression/IExpression';
|
||||
import { IExpressionParser } from './Parser/IExpressionParser';
|
||||
import { CompositeExpressionParser } from './Parser/CompositeExpressionParser';
|
||||
|
||||
export class ExpressionsCompiler implements IExpressionsCompiler {
|
||||
public static readonly instance: IExpressionsCompiler = new ExpressionsCompiler();
|
||||
protected constructor() { }
|
||||
public constructor(private readonly extractor: IExpressionParser = new CompositeExpressionParser()) { }
|
||||
public compileExpressions(code: string, parameters?: ParameterValueDictionary): string {
|
||||
let intermediateCode = generateIlCode(code);
|
||||
intermediateCode = substituteParameters(intermediateCode, parameters);
|
||||
return intermediateCode.compile();
|
||||
const expressions = this.extractor.findExpressions(code);
|
||||
const requiredParameterNames = expressions.map((e) => e.parameters).filter((p) => p).flat();
|
||||
const uniqueParameterNames = Array.from(new Set(requiredParameterNames));
|
||||
ensureRequiredArgsProvided(uniqueParameterNames, parameters);
|
||||
return compileExpressions(expressions, code, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
function substituteParameters(intermediateCode: IILCode, parameters: ParameterValueDictionary): IILCode {
|
||||
const parameterNames = intermediateCode.getUniqueParameterNames();
|
||||
ensureValuesProvided(parameterNames, parameters);
|
||||
for (const parameterName of parameterNames) {
|
||||
const parameterValue = parameters[parameterName];
|
||||
intermediateCode = intermediateCode.substituteParameter(parameterName, parameterValue);
|
||||
function compileExpressions(expressions: IExpression[], code: string, parameters?: ParameterValueDictionary) {
|
||||
let compiledCode = '';
|
||||
expressions = expressions
|
||||
.slice() // copy the array to not mutate the parameter
|
||||
.sort((a, b) => b.position.start - a.position.start);
|
||||
let index = 0;
|
||||
while (index !== code.length) {
|
||||
const nextExpression = expressions.pop();
|
||||
if (nextExpression) {
|
||||
compiledCode += code.substring(index, nextExpression.position.start);
|
||||
const expressionCode = nextExpression.evaluate(parameters);
|
||||
compiledCode += expressionCode;
|
||||
index = nextExpression.position.end;
|
||||
} else {
|
||||
compiledCode += code.substring(index, code.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return intermediateCode;
|
||||
return compiledCode;
|
||||
}
|
||||
|
||||
function ensureValuesProvided(names: string[], nameValues: ParameterValueDictionary) {
|
||||
nameValues = nameValues || {};
|
||||
const notProvidedNames = names.filter((name) => !Boolean(nameValues[name]));
|
||||
if (notProvidedNames.length) {
|
||||
throw new Error(`parameter value(s) not provided for: ${printList(notProvidedNames)}`);
|
||||
function ensureRequiredArgsProvided(parameters: readonly string[], args: ParameterValueDictionary) {
|
||||
parameters = parameters || [];
|
||||
args = args || {};
|
||||
if (!parameters.length) {
|
||||
return;
|
||||
}
|
||||
const notProvidedParameters = parameters.filter((parameter) => !Boolean(args[parameter]));
|
||||
if (notProvidedParameters.length) {
|
||||
throw new Error(`parameter value(s) not provided for: ${printList(notProvidedParameters)}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user