Initial funcs support

commit_hash:78f512cfc76f18e5db8b956eaa1703e4b23e07ca
This commit is contained in:
4eb0da
2025-11-27 01:43:39 +03:00
parent 115aee6186
commit fec3dfc0bf
7 changed files with 56 additions and 9 deletions
+17 -4
View File
@@ -32,9 +32,9 @@ import type { CustomFunctions } from './funcs/customFuncs';
export type VariablesMap = Map<string, VariableInstance>;
export type EvalTypes = 'string' | 'number' | 'integer' | 'boolean' | 'color' | 'url' | 'datetime' | 'dict' | 'array';
export type EvalTypes = 'string' | 'number' | 'integer' | 'boolean' | 'color' | 'url' | 'datetime' | 'dict' | 'array' | 'function';
export type EvalTypesWithoutDatetime = 'string' | 'number' | 'integer' | 'boolean' | 'color' | 'url' | 'dict' | 'array';
export type EvalTypesWithoutDatetime = 'string' | 'number' | 'integer' | 'boolean' | 'color' | 'url' | 'dict' | 'array' | 'function';
export interface EvalValueBase {
type: string;
@@ -86,8 +86,13 @@ export interface ArrayValue extends EvalValueBase {
value: unknown[];
}
export interface FuncValue extends EvalValueBase {
type: 'function';
value: Func[];
}
export type EvalValue = StringValue | UrlValue | ColorValue | NumberValue | IntegerValue |
BooleanValue | DatetimeValue | DictValue | ArrayValue;
BooleanValue | DatetimeValue | DictValue | ArrayValue | FuncValue;
export interface EvalError {
type: 'error';
@@ -463,7 +468,7 @@ function evalCallExpression(ctx: EvalContext, expr: CallExpression): EvalValue {
const builtInFindRes = findBestMatchedFunc(funcs, funcName, args);
// Assign errors only there is no match error in user defined funcs
if ('func' in builtInFindRes || !findRes) {
if ('func' in builtInFindRes || !findRes || findRes.type === 'missing') {
findRes = builtInFindRes;
}
}
@@ -566,6 +571,14 @@ function evalMethodExpression(ctx: EvalContext, expr: MethodExpression): EvalVal
function evalVariable(ctx: EvalContext, expr: Variable): EvalValue {
const varName = expr.id.name;
const customFuncs = ctx.customFunctions?.get(varName);
if (customFuncs) {
return {
type: 'function',
value: customFuncs
};
}
const variable = ctx.variables.get(varName);
if (variable) {
@@ -59,6 +59,7 @@ export function customFunctionWrap(fn: DivFunction): Func {
let ast: Node | undefined;
return {
name: fn.name,
args: fn.arguments.map(it => {
return {
type: it.type
@@ -74,6 +75,9 @@ export function customFunctionWrap(fn: DivFunction): Func {
const vars: VariablesMap = new Map();
args.forEach((arg, index) => {
if (arg.type === 'function') {
throw new Error('Incorrect argument type: function');
}
const instance = createConstVariable(fn.arguments[index].name, arg.type, arg.value);
// DatetimeVariable doesnt exist right know, but works fine
vars.set(instance.getName(), instance as Variable);
@@ -9,6 +9,7 @@ export type FuncArg = EvalTypes | {
}
export interface Func {
name?: string;
args: FuncArg[];
cb(ctx: EvalContext, ...args: EvalValue[]): EvalValue;
}
@@ -105,6 +105,12 @@ class ExpressionBinding {
usedVars: res.usedVars
};
}
if (result.type === 'function') {
return {
result: `<${result.value[0]?.name || 'Function'}>` as T,
usedVars: res.usedVars
};
}
if (!keepComplex && (result.type === 'array' || result.type === 'dict')) {
try {
return {
@@ -60,6 +60,8 @@ export function valToString(val: EvalValue, stringifyComplex: boolean): string {
return '<dict>';
} else if (val.type === 'array') {
return '<array>';
} else if (val.type === 'function') {
return val.value[0].name || 'Function';
}
// For purpose when new eval value types will be added
@@ -186,6 +188,10 @@ export function convertJsValueToDivKit(
val: unknown,
evalType: EvalTypesWithoutDatetime
): EvalValue {
if (evalType === 'function') {
throw new Error('Cannot convert function');
}
const jsType = EVAL_TYPE_TO_JS_TYPE[evalType];
let type: string = typeof val;
@@ -9,6 +9,8 @@ import { evalExpression, type EvalResult } from '../../src/expressions/eval';
import { transformColorValue, valToString } from '../../src/expressions/utils';
import { parse } from '../../src/expressions/expressions';
import { createVariable } from '../../src/expressions/variable';
import { customFunctionWrap, type CustomFunctions } from '../../src/expressions/funcs/customFuncs';
import type { DivFunction } from '../../typings/common';
const path = require('path');
const fs = require('fs');
@@ -46,6 +48,7 @@ function convertVals(val: EvalResult) {
function runCase(item: any) {
const vars = new Map();
const customFunctions: CustomFunctions = new Map();
if (item.variables) {
for (const variable of item.variables) {
let value;
@@ -89,6 +92,14 @@ function runCase(item: any) {
vars.set(variable.name, createVariable(variable.name, variable.type, value));
}
}
if (item.functions) {
for (const func of item.functions) {
const fn = func as DivFunction;
const list = customFunctions.get(fn.name) || [];
list.push(customFunctionWrap(fn));
customFunctions.set(fn.name, list);
}
}
let ast;
try {
ast = parse(item.expression, {
@@ -105,7 +116,7 @@ function runCase(item: any) {
}
return;
}
const res = evalExpression(vars, undefined, undefined, ast, {
const res = evalExpression(vars, customFunctions, undefined, ast, {
weekStartDay: item.platform_specific?.web?.weekStartDay || 0
});
if (item.expected.value !== '' || res.result.type !== 'error') {
@@ -24,7 +24,8 @@
}
],
"platforms": [
"ios"
"ios",
"web"
]
},
{
@@ -51,7 +52,8 @@
}
],
"platforms": [
"ios"
"ios",
"web"
]
},
{
@@ -74,7 +76,9 @@
]
}
],
"platforms": []
"platforms": [
"web"
]
},
{
"expression": "@{toString(myFunction)}",
@@ -96,7 +100,9 @@
]
}
],
"platforms": []
"platforms": [
"web"
]
}
]
}