// The prelude creates all the builtin Shrimp functions. import { type Value, toValue, extractParamInfo, isWrapped, getOriginalFunction, } from 'reefvm' import { dict } from './dict' import { load } from './load' import { list } from './list' import { math } from './math' import { str } from './str' export const globals = { dict, load, list, math, str, // hello echo: (...args: any[]) => { console.log(...args.map(a => { const v = toValue(a) return ['array', 'dict'].includes(v.type) ? formatValue(v, true) : v.value })) return toValue(null) }, // info type: (v: any) => toValue(v).type, inspect: (v: any) => formatValue(toValue(v)), describe: (v: any) => { const val = toValue(v) return `#<${val.type}: ${formatValue(val)}>` }, length: (v: any) => { const value = toValue(v) switch (value.type) { case 'string': case 'array': return value.value.length case 'dict': return value.value.size default: return 0 } }, // type predicates 'string?': (v: any) => toValue(v).type === 'string', 'number?': (v: any) => toValue(v).type === 'number', 'boolean?': (v: any) => toValue(v).type === 'boolean', 'array?': (v: any) => toValue(v).type === 'array', 'dict?': (v: any) => toValue(v).type === 'dict', 'function?': (v: any) => { const t = toValue(v).type return t === 'function' || t === 'native' }, 'null?': (v: any) => toValue(v).type === 'null', 'some?': (v: any) => toValue(v).type !== 'null', // boolean/logic not: (v: any) => !v, // utilities inc: (n: number) => n + 1, dec: (n: number) => n - 1, identity: (v: any) => v, // collections at: (collection: any, index: number | string) => collection[index], range: (start: number, end: number | null) => { if (end === null) { end = start start = 0 } const result: number[] = [] for (let i = start; i <= end; i++) { result.push(i) } return result }, 'empty?': (v: any) => { const value = toValue(v) switch (value.type) { case 'string': case 'array': return value.value.length === 0 case 'dict': return value.value.size === 0 default: return false } }, // enumerables each: async (list: any[], cb: Function) => { for (const value of list) await cb(value) return list }, } export const colors = { reset: '\x1b[0m', bright: '\x1b[1m', dim: '\x1b[2m', cyan: '\x1b[36m', yellow: '\x1b[33m', green: '\x1b[32m', red: '\x1b[31m', blue: '\x1b[34m', magenta: '\x1b[35m', pink: '\x1b[38;2;255;105;180m' } export function formatValue(value: Value, inner = false): string { switch (value.type) { case 'string': return `${colors.green}'${value.value.replaceAll("'", "\\'")}${colors.green}'${colors.reset}` case 'number': return `${colors.cyan}${value.value}${colors.reset}` case 'boolean': return `${colors.yellow}${value.value}${colors.reset}` case 'null': return `${colors.dim}null${colors.reset}` case 'array': { const items = value.value.map(x => formatValue(x, true)).join(' ') return `${colors.blue}[${colors.reset}${items}${colors.blue}]${colors.reset}` } case 'dict': { const entries = Array.from(value.value.entries()) .map(([k, v]) => `${k}${colors.blue}=${colors.reset}${formatValue(v, true)}`) .join(' ') if (entries.length === 0) return `${colors.blue}[=]${colors.reset}` return `${colors.blue}[${colors.reset}${entries}${colors.blue}]${colors.reset}` } case 'function': { const params = value.params.length ? '(' + value.params.join(' ') + ')' : '' return `${colors.dim}${colors.reset}` } case 'native': const fn = isWrapped(value.fn) ? getOriginalFunction(value.fn) : value.fn const info = extractParamInfo(fn) const params = info.params.length ? '(' + info.params.join(' ') + ')' : '' return `${colors.dim}${colors.reset}` case 'regex': return `${colors.magenta}${value.value}${colors.reset}` default: return String(value) } }