20-строчный DSL в typescript или js без библиотеки

Это безумно просто. Вот небольшой lisp-подобный пример:

const s = Symbol
const keywords = [s('add'), s('sub'), s('if'), s('less')] as const
type Keyword = (typeof keywords)[number]
const [add, sub, if_, less] = keywords

const funcs = {
    [add]: (a, b) => valuate(a) + valuate(b),
    [sub]: (a, b) => valuate(a) - valuate(b),
    [if_]: (cond, a, b) => valuate(cond) ? valuate(a) : valuate(b),
    [less]: (a, b) => valuate(a) < valuate(b),
} as const

type Expression = boolean | number | symbol | [Keyword, ...Expression[]]

function valuate(expr: Expression): any {
    if (Array.isArray(expr)) {
        const args = expr.slice(1).map(valuate)
        // @ts-expect-error
        return funcs[expr[0]](...args)
    }
    return expr
}

const expr1: Expression = [add, [sub, [if_, [less, 1, 2], 3, 4], 5], 6]
console.log(valuate(expr1))
// (3 - 5) + 6 == 4
Войти в полноэкранный режим Выход из полноэкранного режима

Если вам нужна полная проверка типов в вашем DSL, то нужно просто немного больше символов для определения рекурсивной структуры. (например, type Add = [add, NumberExpr, NumberExpr) К сожалению, вам, вероятно, придется использовать строки или классы синглтонов для ваших ключевых слов, поскольку typescript не поддерживает символьные литералы.

А если вам нужны типы массивов, инфиксная нотация и прочие приятные мелочи, вам, вероятно, лучше использовать библиотеку типа angu

Оцените статью
Procodings.ru
Добавить комментарий