import { Context } from './context'; import { Node } from './node'; import { MatcherProps } from './matchers'; /** * Expression evaluation using an extended version of Dijkstra's "shunting * yard" algorithm with JavaScript semantics. This algorithm was chosen as * it is simple, sufficient, and can be implemented compactly, minimizing * the size of the code and making it easier to verify correct. * * Features: * * - Number, Boolean, Null, and String types * - String parsing of backslash char, hex, and unicode escapes * - unicode escapes can contain up to 6 hex characters with a * value of <= 0x10FFFF * - "\n", "\x20", "\u2018", "\u01f600" are all valid strings * - Decimal and hex numbers * - Assignment statements * - Variable references * - Operator precedence * - Common math, binary and logical operators * - Both strict and non-strict equality * - Nesting of sub-expressions with parenthesis * - Single pass evaluation of multiple semicolon-delimited expressions * - String equality and concatenation * - Function calls with a variable number of arguments * - example: max(1, 2, 3, ..., N) is accepted * - Type conversion functions * - Common constants (pi, e, etc) * - Configurable parse and reduce limits * - maximum tokens an expression can contain * - maximum length of a concatenated string * * The algorithm assumes the expression is well-formed and performs minimal * validation. A malformed expression should either terminate evaluation * early or produce no value. */ /** * Matches patterns as part of the expression tokenizer. This reuses the same matcher * mixin as the main syntax parser. */ declare class ExprMatcher implements MatcherProps { str: string; matchEnd: number; start: number; end: number; private variableReference; constructor(str: string); init(str: string): void; /** * Set the range to match over. */ set(start: number, end: number): void; /** * Match a single variable reference. */ matchVariable(): (string | number)[] | null; /** * Overridden in mixin. */ compile(s: string): RegExp; /** * Overridden in mixin. */ match(pattern: RegExp, i: number): string | null; /** * Overridden in mixin. */ test(pattern: RegExp, i: number): boolean; } declare const StickyExprMatcher_base: { new (...args: any[]): { compile(s: string): RegExp; match(pattern: RegExp, i: number): string | null; test(pattern: RegExp, i: number): boolean; str: string; matchEnd: number; start: number; end: number; }; } & typeof ExprMatcher; export declare class StickyExprMatcher extends StickyExprMatcher_base { } declare const GlobalExprMatcher_base: { new (...args: any[]): { compile(s: string): RegExp; match(pattern: RegExp, i: number): string | null; test(pattern: RegExp, start: number): boolean; str: string; matchEnd: number; start: number; end: number; }; } & typeof ExprMatcher; export declare class GlobalExprMatcher extends GlobalExprMatcher_base { } export declare const ExprMatcherImpl: typeof StickyExprMatcher; export declare const enum Assoc { LEFT = 0, RIGHT = 1 } export interface Operator { type: OperatorType; prec: number; assoc: Assoc; desc: string; } export declare const enum ExprTokenType { OPERATOR = 0, NULL = 1, NUMBER = 2, BOOLEAN = 3, STRING = 4, CALL = 5, ARGS = 6, VARIABLE = 7 } export interface ArgsToken { type: ExprTokenType.ARGS; } export interface NullToken { type: ExprTokenType.NULL; value: null; } export interface NumberToken { type: ExprTokenType.NUMBER; value: number; } export interface BooleanToken { type: ExprTokenType.BOOLEAN; value: boolean; } export interface StringToken { type: ExprTokenType.STRING; value: string; } export interface CallToken { type: ExprTokenType.CALL; value: string; } export interface VarToken { type: ExprTokenType.VARIABLE; value: (string | number)[]; } export interface OperatorToken { type: ExprTokenType.OPERATOR; value: Operator; } export type LiteralToken = NullToken | NumberToken | BooleanToken | StringToken; export type Token = NullToken | NumberToken | BooleanToken | StringToken | CallToken | VarToken | OperatorToken | ArgsToken; declare const enum OperatorType { PLUS = 0, MINUS = 1, LNOT = 2, BNOT = 3, POW = 4, MUL = 5, DIV = 6, MOD = 7, ADD = 8, SUB = 9, SHL = 10, SHR = 11, LT = 12, GT = 13, EQ = 14, NEQ = 15, SEQ = 16, SNEQ = 17, LTEQ = 18, GTEQ = 19, BAND = 20, BXOR = 21, BOR = 22, LAND = 23, LOR = 24, ASN = 25, SEMI = 26, COMMA = 27, LPRN = 28, RPRN = 29 } export declare const PLUS: OperatorToken; export declare const MINUS: OperatorToken; export declare const LNOT: OperatorToken; export declare const BNOT: OperatorToken; export declare const POW: OperatorToken; export declare const MUL: OperatorToken; export declare const DIV: OperatorToken; export declare const MOD: OperatorToken; export declare const ADD: OperatorToken; export declare const SUB: OperatorToken; export declare const SHL: OperatorToken; export declare const SHR: OperatorToken; export declare const LT: OperatorToken; export declare const GT: OperatorToken; export declare const LTEQ: OperatorToken; export declare const GTEQ: OperatorToken; export declare const EQ: OperatorToken; export declare const NEQ: OperatorToken; export declare const SEQ: OperatorToken; export declare const SNEQ: OperatorToken; export declare const BAND: OperatorToken; export declare const BXOR: OperatorToken; export declare const BOR: OperatorToken; export declare const LAND: OperatorToken; export declare const LOR: OperatorToken; export declare const ASN: OperatorToken; export declare const SEMI: OperatorToken; export declare const COMMA: OperatorToken; export declare const LPRN: OperatorToken; export declare const RPRN: OperatorToken; /** * Stack. */ declare class Stack { private _elems; get length(): number; get top(): T | undefined; set top(t: T | undefined); get elems(): (T | undefined)[]; push(t: T): void; pop(): T | undefined; } /** * Build a number token. */ export declare const num: (value: number) => NumberToken; /** * Build a boolean token. */ export declare const bool: (value: boolean) => BooleanToken; /** * Build a string token. */ export declare const str: (value: string) => StringToken; export declare const tokenDebug: (t: Token | undefined) => string; /** * Options to configure the expression engine. */ export interface ExprOptions { /** * Maximum number of tokens an expression can contain. If an expression exceeds * this limit it raises an error. */ maxTokens?: number; /** * Maximum length of a string that can be constructed through concatenation. * If string result of A + B exceeds the length it raises an error. */ maxStringLen?: number; } /** * Parse and evaluate an expression. */ export declare class Expr { private raw; expr: Token[][]; errors: string[]; tokens: Stack; maxTokens: number; maxStringLen: number; constructor(raw: string, opts?: ExprOptions); /** * Reduce each of the expressions to its simplest form, then return the * final value of the last expression as output. */ reduce(ctx: Context): Node | undefined; /** * Reduce an expression to its simplest form. */ reduceExpr(ctx: Context, expr: Token[]): Node | undefined; /** * Iterate over tokens and build expressions using the shunting yard algorithm. */ build(): void; /** * Push a token. */ private push; /** * Push an expression. */ private pushExpr; /** * Tokenize the string input. */ private tokenize; /** * Scan a decimal number and push a token, or an error message. * We use parseFloat() to convert the chars into the final decimal number. */ decimal(str: string, i: number, len: number): number; /** * Parse a hexadecimal integer number. */ hex(str: string, i: number, len: number): number; /** * Parse a string literal. */ string(str: string, i: number, len: number, end: string): number; } export {};