UNPKG

@onlabsorg/swan-js

Version:

A simple yet powerful expression language written in JavaScript

284 lines (245 loc) 10.1 kB
/** * Swan Builtins * ============================================================================ * * The swan builtins is a collection of functions and constants that are * always present in a swan context. */ const types = require("./types"); const builtins = module.exports = { /** * `require: Text id -> Namespace m` * ---------------------------------------------------------------------------- * This function loads the swan standard module identified by `id` and returns * it as a Namespace item. * * If `id` is a tuple, it returns the corresponding tuple of modules. */ async require (...module_ids) { const modules = require('./modules'); const id_tuple = new types.Tuple(...module_ids) const modules_tuple = await id_tuple.imapAsync(async module_id => { const payload = await modules[module_id](); const module = payload.default || payload; if (typeof module === "function") { return module(types); } else { return module } }); return modules_tuple.normalize(); }, /** * `type: Item x -> Text t` * ---------------------------------------------------------------------------- * Given any item, it returns the name of its type; i.e.: * * - it returns`"Bool"` if x is a Bool item * - it returns`"Numb"` if x is a Numb item * - it returns`"Text"` if x is a Text item * - it returns`"List"` if x is a List item * - it returns`"Namespace"` if x is a Namespace item * - it returns`"Func"` if x is a Func item * - it returns`"Undefined"` if x is an Undefined item * * If `x` is a tuple, it returns a tuple of type names. As a consequence of * this behavior, it returns `()` if `x` is an empty Tuple. */ type (...values) { return new types.Tuple(...values).imapSync(X => X.typeName).normalize(); }, /** * `this: Namespace` * ---------------------------------------------------------------------------- * This name always maps to the current context. */ get this () { return new types.Namespace(this); }, /** * `TRUE: Bool` * ---------------------------------------------------------------------------- * This constant represent the boolean true value in swan. */ TRUE: new types.Bool(true), /** * `FALSE: Bool` * ---------------------------------------------------------------------------- * This constant represent the boolean false value in swan. */ FALSE: new types.Bool(false), /** * `bool: Term x -> Bool b` * ---------------------------------------------------------------------------- * Given a swan term `x`, the `bool` function returns: * * - `FALSE` if x is `FALSE` * - `FALSE` if x is `0` * - `FALSE` if x is `""` * - `FALSE` if x is `[]` * - `FALSE` if x is `{}` * - `FALSE` if x is `()` * - `FALSE` if x is an `Undefined` item * - `FALSE` if x is a tuple containing only items that booleanize to `FALSE` * - `TRUE` in any other case */ bool (...values) { return new types.Bool(new types.Tuple(...values).toBoolean()); }, /** * `not: Term x -> Bool b` * ---------------------------------------------------------------------------- * Given a swan term `x`, the `not` function returns: * * - `FALSE` if `bool x` returns `TRUE` * - `TRUE` if `bool x` returns `FALSE` */ not (...values) { return new types.Bool(!(new types.Tuple(...values).toBoolean())); }, /** * enum: Term x -> Tuple t * ------------------------------------------------------------------------- * Converts the term `x`` to a tuple, according to the tollowing rules: * * - if x is a Numb item, it returns (0, 1, 2, ...) up to the first integer smaller than x * - if x is a Text item, it returns the tuple of all the characters of x * - if x is a List item, it returns the tuple of all the items of x * - if x is a Namespace item, it returns the tuple of all the names of x * * For any other type, it returns Undefined Enumeration. * * If x is a tuple `(x1, x2, ...)` it returns `(enum x1, enum x2, ...)`. */ enum (...items) { return new types.Tuple(...items).imapSync(item => { // If a number ... if (item instanceof types.Numb) { let n = types.unwrap(item); let tuple = new types.Tuple(); for (let i=0; i<n; i++) { tuple = new types.Tuple(tuple, i); } return tuple; } // If a namespace ... if (item instanceof types.Namespace) { return new types.Tuple(...item.domain); } // If a sequence ... if (item instanceof types.Sequence) { return new types.Tuple(...item.image); } // If undefined ... if (item instanceof types.Undefined) { return new types.Tuple(item.type, ...item.args); } return new types.Undefined("Enumeration", item); }).normalize(); }, /** * tsize: Term t -> Numb n * ------------------------------------------------------------------------- * Given a tuple `t` it returns the number of items it contains. Consistently, * it returns `1` if `t` is an item and `0` if `t` is the empty tuple. */ tsize (...X) { const size = Array.from(new types.Tuple(...X)).length; return new types.Numb(size); }, /** * msize: Mapping m -> Numb n * ------------------------------------------------------------------------- * Given a Mapping item `m` it returns the number of items it contains, or * undefined("Size") if m is not a Mapping item. * * If `m` is a tuple, it returns a tuple of mapping sizes. */ msize (...X) { return new types.Tuple(...X).imapSync(item => { if (item instanceof types.Mapping) { return item.size; } else { return new types.Undefined("Size", item); } }).normalize(); }, /** * `str: Term X -> Text s` * ------------------------------------------------------------------------ * The `str` function takes any term `X` as argument and converts it * to a Text item according to the following rules: * * - if `X` is a `Bool` item it either returns `"TRUE"` or `"FALSE"` * - if `X` is a `Numb` item it returns the number as a string * - if `X` is a `Text` item it teturns `X` * - if `X` is a `List` item it returns `"[[List of <n> items]]"` where . * `<n>` is the size of `X` * - if `X` is a `Namespace` item it returns `"[[Namespace of <n> items]]"` * where `<n>` is the size of `X`. * - if `X` is a `Namespace` item and `X.__str__` is a Text item, it * returns `X.__str__`. * - if `X` is a `Namespace` item and `X.__str__` is a Func item, it * returns `X.__str__(X)`. * - if `X` is a `Func` item, it returns `"[[Func]]"` * - if `X` is an `Undefined` item it returns `"[[Undefined <type>]]"`, * where `<type>` is the Undefined operaton type. * - if `X` is a `Tuple` term, it returns the concatenation of all its * items stringified with `Text`. As a particular case, if `X` is an * empty tuple, it returns `""` */ async str (...values) { const term = new types.Tuple(...values); const textTuple = await term.imapAsync(async (item) => { if (item instanceof types.Namespace) { const __str__ = item.apply("__str__"); if (__str__ instanceof types.Text) return __str__; if (__str__ instanceof types.Func) { return await __str__.apply(item); } } return item; }); return new types.Text(textTuple.toString()); }, /** * `parent: Namespace x -> Namespace p` * ------------------------------------------------------------------------ * Given a Namespace `x`, returns its parent namespace or `Undefined Namespace` * if the `x` has no parent or if `x` is not a Namespace item. If `x` * is a tuple, it applies to all its items. */ parent (...X) { return new types.Tuple(...X).imapSync(item => { if (item instanceof types.Namespace) { const parent = item.vmapSync(Object.getPrototypeOf); if (parent instanceof types.Namespace) return parent; } return new types.Undefined('Namespace'); }).normalize(); }, /** * `own: Namespace x -> Namespace o` * ------------------------------------------------------------------------ * Given a namespace `x`, returns a copy of its own names, enclosed in a * parent-less namespace. It returns Undefined Namespace if `x` is not * a namespace. If `x` is a tuple, it applies to all its items. */ own (...X) { return new types.Tuple(...X).imapSync(item => { if (item instanceof types.Namespace) { return item.vmapSync(ns => Object.assign(Object.create(null), ns)); } else { return new types.Undefined('Namespace'); } }).normalize(); }, /** * `undefined: (Text t, Tuple a) -> Undefined u` * ---------------------------------------------------------------------------- * This function returns an `Undefined` item with type `t` and arguments `a`. */ undefined (type, ...args) { return new types.Undefined(type, ...args); } }