import React from "react";
import { objectClone } from "eez-studio-shared/util";
import * as os from "os";
import { FLOW_ITERATOR_INDEXES_VARIABLE } from "project-editor/features/variable/defs";
import type { ValueType } from "project-editor/features/variable/value-type";
import type { IExpressionContext } from "project-editor/flow/expression";
import type { ProjectStore } from "project-editor/store";
import { findBitmap } from "project-editor/project/assets";
import sha256 from "sha256";
function roundN(value: number, decimals: number) {
return Number(Math.round(Number(value + "e" + decimals)) + "e-" + decimals);
}
export const binaryOperators: {
[operator: string]: {
operationIndex: number;
name: string;
eval: (
expressionContext: IExpressionContext | undefined,
a: any,
b: any
) => any;
getValueType: (a: ValueType, b: ValueType) => ValueType;
};
} = {
"+": {
operationIndex: 0,
name: "add",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a + b,
getValueType: (a: ValueType, b: ValueType) => {
if (
a != "integer" &&
a != "float" &&
a != "double" &&
a != "string"
) {
return "undefined";
}
if (
b != "integer" &&
b != "float" &&
b != "double" &&
b != "string"
) {
return "undefined";
}
if (a == "string" || b == "string") {
return "string";
}
if (a == "double" || b == "double") {
return "double";
}
if (a == "float" || b == "float") {
return "float";
}
return "integer";
}
},
"-": {
operationIndex: 1,
name: "sub",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a - b,
getValueType: (a: ValueType, b: ValueType) => {
if (a != "integer" && a != "float" && a != "double") {
return "undefined";
}
if (b != "integer" && b != "float" && b != "double") {
return "undefined";
}
if (a == "double" || b == "double") {
return "double";
}
if (a == "float" || b == "float") {
return "float";
}
return "integer";
}
},
"*": {
operationIndex: 2,
name: "mul",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a * b,
getValueType: (a: ValueType, b: ValueType) => {
if (a != "integer" && a != "float" && a != "double") {
return "undefined";
}
if (b != "integer" && b != "float" && b != "double") {
return "undefined";
}
if (a == "double" || b == "double") {
return "double";
}
if (a == "float" || b == "float") {
return "float";
}
return "integer";
}
},
"/": {
operationIndex: 3,
name: "div",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a / b,
getValueType: (a: ValueType, b: ValueType) => {
if (a != "integer" && a != "float" && a != "double") {
return "undefined";
}
if (b != "integer" && b != "float" && b != "double") {
return "undefined";
}
if (a == "double" || b == "double") {
return "double";
}
if (a == "float" || b == "float") {
return "float";
}
return "integer";
}
},
"%": {
operationIndex: 4,
name: "mod",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a % b,
getValueType: (a: ValueType, b: ValueType) => {
if (a != "integer") {
return "undefined";
}
if (b != "integer") {
return "undefined";
}
return "integer";
}
},
"<<": {
operationIndex: 5,
name: "left_shift",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a << b,
getValueType: (a: ValueType, b: ValueType) => {
if (a != "integer") {
return "undefined";
}
if (b != "integer") {
return "undefined";
}
return "integer";
}
},
">>": {
operationIndex: 6,
name: "right_shift",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a >> b,
getValueType: (a: ValueType, b: ValueType) => {
if (a != "integer") {
return "undefined";
}
if (b != "integer") {
return "undefined";
}
return "integer";
}
},
"&": {
operationIndex: 7,
name: "binary_and",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a & b,
getValueType: (a: ValueType, b: ValueType) => {
if (a != "integer") {
return "undefined";
}
if (b != "integer") {
return "undefined";
}
return "integer";
}
},
"|": {
operationIndex: 8,
name: "binary_or",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a | b,
getValueType: (a: ValueType, b: ValueType) => {
if (a != "integer") {
return "undefined";
}
if (b != "integer") {
return "undefined";
}
return "integer";
}
},
"^": {
operationIndex: 9,
name: "binary_xor",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a ^ b,
getValueType: (a: ValueType, b: ValueType) => {
if (a != "integer") {
return "undefined";
}
if (b != "integer") {
return "undefined";
}
return "integer";
}
}
};
export const logicalOperators: {
[operator: string]: {
operationIndex: number;
name: string;
eval: (
expressionContext: IExpressionContext | undefined,
a: any,
b: any
) => any;
getValueType: (a: ValueType, b: ValueType) => ValueType;
};
} = {
"==": {
operationIndex: 10,
name: "equal",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a == b,
getValueType: (a: ValueType, b: ValueType) => {
return "boolean";
}
},
"!=": {
operationIndex: 11,
name: "not_equal",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a != b,
getValueType: (a: ValueType, b: ValueType) => {
return "boolean";
}
},
"<": {
operationIndex: 12,
name: "less",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a < b,
getValueType: (a: ValueType, b: ValueType) => {
return "boolean";
}
},
">": {
operationIndex: 13,
name: "greater",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a > b,
getValueType: (a: ValueType, b: ValueType) => {
return "boolean";
}
},
"<=": {
operationIndex: 14,
name: "less_or_equal",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a <= b,
getValueType: (a: ValueType, b: ValueType) => {
return "boolean";
}
},
">=": {
operationIndex: 15,
name: "greater_or_equal",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a >= b,
getValueType: (a: ValueType, b: ValueType) => {
return "boolean";
}
},
"&&": {
operationIndex: 16,
name: "logical_and",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a && b,
getValueType: (a: ValueType, b: ValueType) => {
return "boolean";
}
},
"||": {
operationIndex: 17,
name: "logical_or",
eval: (expressionContext: IExpressionContext | undefined, a, b) =>
a || b,
getValueType: (a: ValueType, b: ValueType) => {
return "boolean";
}
}
};
export const unaryOperators: {
[operator: string]: {
operationIndex: number;
name: string;
eval: (
expressionContext: IExpressionContext | undefined,
a: any
) => any;
getValueType: (a: ValueType) => ValueType;
};
} = {
"+": {
operationIndex: 18,
name: "unary_plus",
eval: (expressionContext: IExpressionContext | undefined, a) => +a,
getValueType: (a: ValueType) => {
if (a != "integer" && a != "float" && a != "double") {
return "undefined";
}
return a;
}
},
"-": {
operationIndex: 19,
name: "unary_minus",
eval: (expressionContext: IExpressionContext | undefined, a) => -a,
getValueType: (a: ValueType) => {
if (a != "integer" && a != "float" && a != "double") {
return "undefined";
}
return a;
}
},
"~": {
operationIndex: 20,
name: "binary_one_complement",
eval: (expressionContext: IExpressionContext | undefined, a) => ~a,
getValueType: (a: ValueType) => {
if (a != "integer") {
return "undefined";
}
return a;
}
},
"!": {
operationIndex: 21,
name: "not",
eval: (expressionContext: IExpressionContext | undefined, a) => !a,
getValueType: (a: ValueType) => {
if (a != "integer" && a != "float" && a != "double") {
return "undefined";
}
return "boolean";
}
}
};
export const CONDITIONAL_OPERATOR = "conditional"; // {test} ? {consequent} : {alternate}
export const builtInFunctions: {
[name: string]: {
operationIndex: number;
arity: number | { min: number; max?: number };
args: string[];
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => any;
getValueType: (...args: ValueType[]) => ValueType;
enabled?: (projectStore: ProjectStore) => boolean;
};
} = {
"System.getTick": {
operationIndex: 23,
arity: 0,
args: [],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
return Date.now();
},
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Flow.index": {
operationIndex: 24,
arity: 1,
args: ["index"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
if (!expressionContext) {
return 0;
}
const iterators = expressionContext.dataContext.get(
FLOW_ITERATOR_INDEXES_VARIABLE
);
if (!iterators) {
throw "no iterators";
}
const i = args[0];
if (typeof i != "number") {
return `iterator index '${i}' is not an number`;
} else if (i < 0 && i >= iterators.length) {
return `iterator index ${i} is not in the range [0...${iterators.length}]`;
} else {
return iterators[i];
}
},
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Flow.isPageActive": {
operationIndex: 25,
arity: 0,
args: [],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
if (!expressionContext) {
return false;
}
return (
expressionContext.flowState &&
expressionContext.flowState.flow ==
expressionContext.flowState.runtime.selectedPage
);
},
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Flow.pageTimelinePosition": {
operationIndex: 26,
arity: 0,
args: [],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
return expressionContext && expressionContext.flowState
? expressionContext.flowState.timelinePosition
: 0;
},
getValueType: (...args: ValueType[]) => {
return "float";
}
},
"Flow.makeValue": {
operationIndex: 27,
arity: 2,
args: ["struct", "value"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
return args[1];
},
getValueType: (...args: ValueType[]) => {
return args[0];
}
},
"Flow.makeArrayValue": {
operationIndex: 28,
arity: 2,
args: ["type", "size"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
return new Array(args[1]);
},
getValueType: (...args: ValueType[]) => {
return args[0];
}
},
"Flow.languages": {
operationIndex: 29,
arity: 0,
args: [],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
const texts = expressionContext?.projectStore.project.texts;
if (texts) {
return texts.languages.map(language => language.languageID);
}
return [];
},
getValueType: (...args: ValueType[]) => {
return "array:string";
}
},
"Flow.translate": {
operationIndex: 30,
arity: 1,
args: ["textResourceID"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
const texts = expressionContext?.projectStore.project.texts;
if (texts) {
const textResource = texts.resources[args[0]];
if (textResource) {
const translation = textResource.translations.find(
translation =>
translation.languageID ==
texts.languages[0].languageID
);
if (translation) {
return translation.text;
}
}
}
return "";
},
getValueType: (...args: ValueType[]) => {
return "string";
}
},
"Flow.themes": {
operationIndex: 89,
arity: 0,
args: [],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
const themes = expressionContext?.projectStore.project.themes;
if (themes) {
return themes.map(theme => theme.name);
}
return [];
},
getValueType: (...args: ValueType[]) => {
return "array:string";
}
},
"Flow.parseInteger": {
operationIndex: 31,
arity: 1,
args: ["str"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
return parseInt(args[0]);
},
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Flow.parseFloat": {
operationIndex: 32,
arity: 1,
args: ["str"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
return parseFloat(args[0]);
},
getValueType: (...args: ValueType[]) => {
return "float";
}
},
"Flow.parseDouble": {
operationIndex: 33,
arity: 1,
args: ["str"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
return parseFloat(args[0]);
},
getValueType: (...args: ValueType[]) => {
return "double";
}
},
"Flow.toInteger": {
operationIndex: 71,
arity: 1,
args: ["value"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
return args[0];
},
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Flow.getBitmapIndex": {
operationIndex: 70,
arity: 1,
args: ["bitmapName"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) =>
expressionContext
? findBitmap(expressionContext?.projectStore.project, args[0])
: undefined,
getValueType: (...args: ValueType[]) => {
return "blob";
},
enabled: projectStore => !projectStore.projectTypeTraits.isLVGL
},
"Flow.getBitmapAsDataURL": {
operationIndex: 78,
arity: 1,
args: ["bitmapName"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) =>
expressionContext
? findBitmap(expressionContext?.projectStore.project, args[0])
: undefined,
getValueType: (...args: ValueType[]) => {
return "string";
},
enabled: projectStore => projectStore.projectTypeTraits.isDashboard
},
"Crypto.sha256": {
operationIndex: 74,
arity: 1,
args: ["string_or_blob"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => sha256(args[0]),
getValueType: (...args: ValueType[]) => {
return "blob";
}
},
"Date.now": {
operationIndex: 34,
arity: 0,
args: [],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Date(),
getValueType: (...args: ValueType[]) => {
return "date";
}
},
"Date.toString": {
operationIndex: 35,
arity: 1,
args: ["date"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Date(args[0]).toISOString(),
getValueType: (...args: ValueType[]) => {
return "string";
}
},
"Date.toLocaleString": {
operationIndex: 59,
arity: 1,
args: ["date"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Date(args[0]).toLocaleString(),
getValueType: (...args: ValueType[]) => {
return "string";
}
},
"Date.fromString": {
operationIndex: 36,
arity: 1,
args: ["dateStr"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Date(args[0]).getTime(),
getValueType: (...args: ValueType[]) => {
return "date";
}
},
"Date.getYear": {
operationIndex: 60,
arity: 1,
args: ["date"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Date(args[0]).getFullYear(),
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Date.getMonth": {
operationIndex: 61,
arity: 1,
args: ["date"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Date(args[0]).getMonth(),
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Date.getDay": {
operationIndex: 62,
arity: 1,
args: ["date"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Date(args[0]).getDay(),
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Date.getHours": {
operationIndex: 63,
arity: 1,
args: ["date"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Date(args[0]).getHours(),
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Date.getMinutes": {
operationIndex: 64,
arity: 1,
args: ["date"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Date(args[0]).getMinutes(),
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Date.getSeconds": {
operationIndex: 65,
arity: 1,
args: ["date"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Date(args[0]).getSeconds(),
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Date.getMilliseconds": {
operationIndex: 66,
arity: 1,
args: ["date"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Date(args[0]).getMilliseconds(),
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Date.make": {
operationIndex: 67,
arity: 7,
args: [
"year",
"month",
"day",
"hours",
"minutes",
"seconds",
"milliseconds"
],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) =>
new Date(
args[0],
args[1] - 1,
args[2],
args[3],
args[4],
args[5],
args[6]
),
getValueType: (...args: ValueType[]) => {
return "date";
}
},
"Math.sin": {
operationIndex: 37,
arity: 1,
args: ["value"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => Math.sin(args[0]),
getValueType: (...args: ValueType[]) => {
if (
args[0] != "integer" &&
args[0] != "float" &&
args[0] != "double"
) {
return "undefined";
}
if (args[0] == "float") {
return "float";
}
return "double";
}
},
"Math.cos": {
operationIndex: 38,
arity: 1,
args: ["value"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => Math.cos(args[0]),
getValueType: (...args: ValueType[]) => {
if (
args[0] != "integer" &&
args[0] != "float" &&
args[0] != "double"
) {
return "undefined";
}
if (args[0] == "float") {
return "float";
}
return "double";
}
},
"Math.pow": {
operationIndex: 68,
arity: 2,
args: ["base", "exponent"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => Math.pow(args[0], args[1]),
getValueType: (...args: ValueType[]) => {
if (
(args[0] != "integer" &&
args[0] != "float" &&
args[0] != "double") ||
(args[1] != "integer" &&
args[1] != "float" &&
args[1] != "double")
) {
return "undefined";
}
if (args[0] == "float" && args[1] == "float") {
return "float";
}
return "double";
}
},
"Math.log": {
operationIndex: 39,
arity: 1,
args: ["value"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => Math.log(args[0]),
getValueType: (...args: ValueType[]) => {
if (
args[0] != "integer" &&
args[0] != "float" &&
args[0] != "double"
) {
return "undefined";
}
if (args[0] == "float") {
return "float";
}
return "double";
}
},
"Math.log10": {
operationIndex: 40,
arity: 1,
args: ["value"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => Math.log10(args[0]),
getValueType: (...args: ValueType[]) => {
if (
args[0] != "integer" &&
args[0] != "float" &&
args[0] != "double"
) {
return "undefined";
}
if (args[0] == "float") {
return "float";
}
return "double";
}
},
"Math.abs": {
operationIndex: 41,
arity: 1,
args: ["value"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => Math.abs(args[0]),
getValueType: (...args: ValueType[]) => {
if (
args[0] != "integer" &&
args[0] != "float" &&
args[0] != "double"
) {
return "undefined";
}
if (args[0] == "integer") {
return "integer";
}
if (args[0] == "float") {
return "float";
}
return "double";
}
},
"Math.floor": {
operationIndex: 42,
arity: 1,
args: ["value"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => Math.floor(args[0]),
getValueType: (...args: ValueType[]) => {
if (
args[0] != "integer" &&
args[0] != "float" &&
args[0] != "double"
) {
return "undefined";
}
if (args[0] == "float") {
return "float";
}
return "double";
}
},
"Math.ceil": {
operationIndex: 43,
arity: 1,
args: ["value"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => Math.ceil(args[0]),
getValueType: (...args: ValueType[]) => {
if (
args[0] != "integer" &&
args[0] != "float" &&
args[0] != "double"
) {
return "undefined";
}
if (args[0] == "float") {
return "float";
}
return "double";
}
},
"Math.round": {
operationIndex: 44,
arity: { min: 1, max: 2 },
args: ["value", "numOfDigits"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => (args.length == 1 ? roundN(args[0], 0) : roundN(args[0], args[1])),
getValueType: (...args: ValueType[]) => {
if (
args[0] != "integer" &&
args[0] != "float" &&
args[0] != "double"
) {
return "undefined";
}
if (args[0] == "float") {
return "float";
}
return "double";
}
},
"Math.min": {
operationIndex: 45,
arity: { min: 2 },
args: ["value", "..."],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => Math.min(...args),
getValueType: (...args: ValueType[]) => {
if (
args[0] != "integer" &&
args[0] != "float" &&
args[0] != "double"
) {
return "undefined";
}
if (args[0] == "float") {
return "float";
}
return "double";
}
},
"Math.max": {
operationIndex: 46,
arity: { min: 2 },
args: ["value", "..."],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => Math.max(...args),
getValueType: (...args: ValueType[]) => {
if (
args[0] != "integer" &&
args[0] != "float" &&
args[0] != "double"
) {
return "undefined";
}
if (args[0] == "float") {
return "float";
}
return "double";
}
},
"String.length": {
operationIndex: 47,
arity: 1,
args: ["string"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => args[0].length,
getValueType: (...args: ValueType[]) => {
return "string";
}
},
"String.substring": {
operationIndex: 48,
arity: { min: 2 },
args: ["string", "start", "end"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => args[0].substring(args[1], args[2]),
getValueType: (...args: ValueType[]) => {
return "string";
}
},
"String.find": {
operationIndex: 49,
arity: 2,
args: ["string", "substring"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => args[0].indexOf(args[1]),
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"String.format": {
operationIndex: 79,
arity: 2,
args: ["specifier", "number"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => {
if (
!expressionContext?.projectStore.projectTypeTraits.isDashboard
) {
if (args[0].startsWith("%")) {
return (window as any).d3.format(args[0].slice(1))(args[1]);
} else {
return (window as any).d3.format(args[0])(args[1]);
}
} else {
(window as any).d3.format(args[0])(args[1]);
}
},
getValueType: (...args: ValueType[]) => {
return "string";
}
},
"String.formatPrefix": {
operationIndex: 80,
arity: 3,
args: ["specifier", "value", "number"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => (window as any).d3.formatPrefix(args[0], args[1])(args[2]),
getValueType: (...args: ValueType[]) => {
return "string";
},
enabled: projectStore => projectStore.projectTypeTraits.isDashboard
},
"String.padStart": {
operationIndex: 50,
arity: 3,
args: ["string", "targetLength", "padString"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => args[0].toString().padStart(args[1], args[2]),
getValueType: (...args: ValueType[]) => {
return "string";
}
},
"String.split": {
operationIndex: 51,
arity: 2,
args: ["string", "separator"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => args[0].split(args[1]),
getValueType: (...args: ValueType[]) => {
return "array:string";
}
},
"String.fromCodePoint": {
operationIndex: 72,
arity: 1,
args: ["charCode"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => String.fromCodePoint(args[0]),
getValueType: (...args: ValueType[]) => {
return "string";
}
},
"String.codePointAt": {
operationIndex: 73,
arity: 2,
args: ["string", "index"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => args[0].codePointAt(args[1]),
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Array.length": {
operationIndex: 52,
arity: 1,
args: ["array"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => args[0].length,
getValueType: (...args: ValueType[]) => {
return "integer";
}
},
"Array.slice": {
operationIndex: 53,
arity: { min: 1, max: 3 },
args: ["array", "start", "[end]"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => args[0].slice(args[1], args[2]),
getValueType: (...args: ValueType[]) => {
return args[0];
}
},
"Array.allocate": {
operationIndex: 54,
arity: 1,
args: ["size"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => new Array(args[0]),
getValueType: (...args: ValueType[]) => {
return "array:any";
}
},
"Array.append": {
operationIndex: 55,
arity: 2,
args: ["array", "value"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => [...args[0], args[1]],
getValueType: (...args: ValueType[]) => {
return args[0];
}
},
"Array.insert": {
operationIndex: 56,
arity: 3,
args: ["array", "position", "value"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => [...args[0].slice(0, args[2]), args[2], ...args[0].slice(args[2])],
getValueType: (...args: ValueType[]) => {
return args[0];
}
},
"Array.remove": {
operationIndex: 57,
arity: 2,
args: ["array", "position"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => [...args[0].slice(0, args[2]), ...args[0].slice(args[2] + 1)],
getValueType: (...args: ValueType[]) => {
return args[0];
}
},
"Array.clone": {
operationIndex: 58,
arity: 1,
args: ["array"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => objectClone(args[0]),
getValueType: (...args: ValueType[]) => {
return args[0];
}
},
"Blob.allocate": {
operationIndex: 75,
arity: 1,
args: ["size"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => Buffer.alloc(args[0]),
getValueType: (...args: ValueType[]) => {
return "blob";
}
},
"Blob.toString": {
operationIndex: 88,
arity: 1,
args: ["blob"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => args[1].toString("utf8"),
getValueType: (...args: ValueType[]) => {
return "string";
},
enabled: projectStore => projectStore.projectTypeTraits.isDashboard
},
"JSON.get": {
operationIndex: 76,
arity: 2,
args: ["json", "property"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => args[0][args[1]],
getValueType: (...args: ValueType[]) => {
return "json";
},
enabled: projectStore => projectStore.projectTypeTraits.isDashboard
},
"JSON.clone": {
operationIndex: 77,
arity: 1,
args: ["json"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => JSON.parse(JSON.stringify(args[0])),
getValueType: (...args: ValueType[]) => {
return "json";
},
enabled: projectStore => projectStore.projectTypeTraits.isDashboard
},
"Event.getCode": {
operationIndex: 81,
arity: 1,
args: ["event"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => undefined,
getValueType: (...args: ValueType[]) => {
return "integer";
},
enabled: projectStore => projectStore.projectTypeTraits.isLVGL
},
"Event.getCurrentTarget": {
operationIndex: 82,
arity: 1,
args: ["event"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => undefined,
getValueType: (...args: ValueType[]) => {
return "widget";
},
enabled: projectStore => projectStore.projectTypeTraits.isLVGL
},
"Event.getTarget": {
operationIndex: 83,
arity: 1,
args: ["event"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => undefined,
getValueType: (...args: ValueType[]) => {
return "widget";
},
enabled: projectStore => projectStore.projectTypeTraits.isLVGL
},
"Event.getUserData": {
operationIndex: 84,
arity: 1,
args: ["event"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => undefined,
getValueType: (...args: ValueType[]) => {
return "any";
},
enabled: projectStore => projectStore.projectTypeTraits.isLVGL
},
"Event.getKey": {
operationIndex: 85,
arity: 1,
args: ["event"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => undefined,
getValueType: (...args: ValueType[]) => {
return "integer";
},
enabled: projectStore => projectStore.projectTypeTraits.isLVGL
},
"Event.getGestureDir": {
operationIndex: 86,
arity: 1,
args: ["event"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => undefined,
getValueType: (...args: ValueType[]) => {
return "integer";
},
enabled: projectStore => projectStore.projectTypeTraits.isLVGL
},
"Event.getRotaryDiff": {
operationIndex: 87,
arity: 1,
args: ["event"],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => undefined,
getValueType: (...args: ValueType[]) => {
return "integer";
},
enabled: projectStore => projectStore.projectTypeTraits.isLVGL
},
"LVGL.MeterTickIndex": {
operationIndex: 69,
arity: 0,
args: [],
eval: (
expressionContext: IExpressionContext | undefined,
...args: any[]
) => 0,
getValueType: (...args: ValueType[]) => {
return "integer";
},
enabled: projectStore => projectStore.projectTypeTraits.isLVGL
}
};
type BuiltInConstantsType = {
[name: string]: {
value: (projectStore: ProjectStore) => any;
valueType: ValueType;
label?: (name: string) => React.ReactNode;
};
};
const commonConstants: BuiltInConstantsType = {
"System.Platform": {
value: (projectStore: ProjectStore) => {
const platform = os.platform();
if (platform == "darwin") return "macos";
return platform;
},
valueType: "string"
},
"System.Architecture": {
value: (projectStore: ProjectStore) => os.arch(),
valueType: "string"
},
"System.ProjectFolder": {
value: (projectStore: ProjectStore) =>
projectStore.getAbsoluteProjectFolderPath(),
valueType: "string"
},
"System.ProjectFile": {
value: (projectStore: ProjectStore) => projectStore.filePath,
valueType: "string"
},
"Math.PI": {
value: () => Math.PI,
valueType: "double"
},
"Math.Infinity": {
value: () => Infinity,
valueType: "double"
}
};
function LVGL_SYMBOL(value: string): {
value: (projectStore: ProjectStore) => string;
valueType: ValueType;
label: (name: string) => React.ReactNode;
} {
return {
value: (projectStore: ProjectStore) => value,
valueType: "string",
label: name => (
<>
{value}
{name}
>
)
};
}
const lvglConstants: BuiltInConstantsType = {
...commonConstants,
"LVGL.LV_SYMBOL_AUDIO": LVGL_SYMBOL("\uF001"),
"LVGL.LV_SYMBOL_VIDEO": LVGL_SYMBOL("\uF008"),
"LVGL.LV_SYMBOL_LIST": LVGL_SYMBOL("\uF00B"),
"LVGL.LV_SYMBOL_OK": LVGL_SYMBOL("\uF00C"),
"LVGL.LV_SYMBOL_CLOSE": LVGL_SYMBOL("\uF00D"),
"LVGL.LV_SYMBOL_POWER": LVGL_SYMBOL("\uF011"),
"LVGL.LV_SYMBOL_SETTINGS": LVGL_SYMBOL("\uF013"),
"LVGL.LV_SYMBOL_HOME": LVGL_SYMBOL("\uF015"),
"LVGL.LV_SYMBOL_DOWNLOAD": LVGL_SYMBOL("\uF019"),
"LVGL.LV_SYMBOL_DRIVE": LVGL_SYMBOL("\uF01C"),
"LVGL.LV_SYMBOL_REFRESH": LVGL_SYMBOL("\uF021"),
"LVGL.LV_SYMBOL_MUTE": LVGL_SYMBOL("\uF026"),
"LVGL.LV_SYMBOL_VOLUME_MID": LVGL_SYMBOL("\uF027"),
"LVGL.LV_SYMBOL_VOLUME_MAX": LVGL_SYMBOL("\uF028"),
"LVGL.LV_SYMBOL_IMAGE": LVGL_SYMBOL("\uF03E"),
"LVGL.LV_SYMBOL_TINT": LVGL_SYMBOL("\uF043"),
"LVGL.LV_SYMBOL_PREV": LVGL_SYMBOL("\uF048"),
"LVGL.LV_SYMBOL_PLAY": LVGL_SYMBOL("\uF04B"),
"LVGL.LV_SYMBOL_PAUSE": LVGL_SYMBOL("\uF04C"),
"LVGL.LV_SYMBOL_STOP": LVGL_SYMBOL("\uF04D"),
"LVGL.LV_SYMBOL_NEXT": LVGL_SYMBOL("\uF051"),
"LVGL.LV_SYMBOL_EJECT": LVGL_SYMBOL("\uF052"),
"LVGL.LV_SYMBOL_LEFT": LVGL_SYMBOL("\uF053"),
"LVGL.LV_SYMBOL_RIGHT": LVGL_SYMBOL("\uF054"),
"LVGL.LV_SYMBOL_PLUS": LVGL_SYMBOL("\uF067"),
"LVGL.LV_SYMBOL_MINUS": LVGL_SYMBOL("\uF068"),
"LVGL.LV_SYMBOL_EYE_OPEN": LVGL_SYMBOL("\uF06E"),
"LVGL.LV_SYMBOL_EYE_CLOSE": LVGL_SYMBOL("\uF070"),
"LVGL.LV_SYMBOL_WARNING": LVGL_SYMBOL("\uF071"),
"LVGL.LV_SYMBOL_SHUFFLE": LVGL_SYMBOL("\uF074"),
"LVGL.LV_SYMBOL_UP": LVGL_SYMBOL("\uF077"),
"LVGL.LV_SYMBOL_DOWN": LVGL_SYMBOL("\uF078"),
"LVGL.LV_SYMBOL_LOOP": LVGL_SYMBOL("\uF079"),
"LVGL.LV_SYMBOL_DIRECTORY": LVGL_SYMBOL("\uF07B"),
"LVGL.LV_SYMBOL_UPLOAD": LVGL_SYMBOL("\uF093"),
"LVGL.LV_SYMBOL_CALL": LVGL_SYMBOL("\uF095"),
"LVGL.LV_SYMBOL_CUT": LVGL_SYMBOL("\uF0C4"),
"LVGL.LV_SYMBOL_COPY": LVGL_SYMBOL("\uF0C5"),
"LVGL.LV_SYMBOL_SAVE": LVGL_SYMBOL("\uF0C7"),
"LVGL.LV_SYMBOL_BARS": LVGL_SYMBOL("\uF0C9"),
"LVGL.LV_SYMBOL_ENVELOPE": LVGL_SYMBOL("\uF0E0"),
"LVGL.LV_SYMBOL_CHARGE": LVGL_SYMBOL("\uF0E7"),
"LVGL.LV_SYMBOL_PASTE": LVGL_SYMBOL("\uF0EA"),
"LVGL.LV_SYMBOL_BELL": LVGL_SYMBOL("\uF0F3"),
"LVGL.LV_SYMBOL_KEYBOARD": LVGL_SYMBOL("\uF11C"),
"LVGL.LV_SYMBOL_GPS": LVGL_SYMBOL("\uF124"),
"LVGL.LV_SYMBOL_FILE": LVGL_SYMBOL("\uF15B"),
"LVGL.LV_SYMBOL_WIFI": LVGL_SYMBOL("\uF1EB"),
"LVGL.LV_SYMBOL_BATTERY_FULL": LVGL_SYMBOL("\uF240"),
"LVGL.LV_SYMBOL_BATTERY_3": LVGL_SYMBOL("\uF241"),
"LVGL.LV_SYMBOL_BATTERY_2": LVGL_SYMBOL("\uF242"),
"LVGL.LV_SYMBOL_BATTERY_1": LVGL_SYMBOL("\uF243"),
"LVGL.LV_SYMBOL_BATTERY_EMPTY": LVGL_SYMBOL("\uF244"),
"LVGL.LV_SYMBOL_USB": LVGL_SYMBOL("\uF287"),
"LVGL.LV_SYMBOL_BLUETOOTH": LVGL_SYMBOL("\uF293"),
"LVGL.LV_SYMBOL_TRASH": LVGL_SYMBOL("\uF2ED"),
"LVGL.LV_SYMBOL_EDIT": LVGL_SYMBOL("\uF304"),
"LVGL.LV_SYMBOL_BACKSPACE": LVGL_SYMBOL("\uF55A"),
"LVGL.LV_SYMBOL_SD_CARD": LVGL_SYMBOL("\uF7C2"),
"LVGL.LV_SYMBOL_NEW_LINE": LVGL_SYMBOL("\uF8A2")
};
export const builtInConstants: (
projectStore: ProjectStore
) => BuiltInConstantsType = (projectStore: ProjectStore) =>
projectStore.projectTypeTraits.isLVGL ? lvglConstants : commonConstants;
export const operationIndexes: { [key: string]: number } = {};
function buildOperationIndexes() {
for (const name in binaryOperators) {
if (binaryOperators.hasOwnProperty(name)) {
operationIndexes[binaryOperators[name].name] =
binaryOperators[name].operationIndex;
}
}
for (const name in logicalOperators) {
if (logicalOperators.hasOwnProperty(name)) {
operationIndexes[logicalOperators[name].name] =
logicalOperators[name].operationIndex;
}
}
for (const name in unaryOperators) {
if (unaryOperators.hasOwnProperty(name)) {
operationIndexes[unaryOperators[name].name] =
unaryOperators[name].operationIndex;
}
}
operationIndexes[CONDITIONAL_OPERATOR] = 22;
for (const name in builtInFunctions) {
if (builtInFunctions.hasOwnProperty(name)) {
operationIndexes[name] = builtInFunctions[name].operationIndex;
}
}
}
buildOperationIndexes();