import { Environment, Pattern, NamedPattern, lookup } from "./meta"; import * as M from './meta'; import { Value, Float, Bytes, is, isPointer, Record, Dictionary, Set } from "@preserves/core"; export function validator(env: Environment, p: Pattern): (v: Value) => boolean { function walk(p: Pattern, v: Value, recordOkAsTuple = false): boolean { switch (p.label) { case M.___atom: switch (p[0]) { case M.___Boolean: return typeof v === 'boolean'; case M.___Float: return Float.isSingle(v); case M.___Double: return Float.isDouble(v); case M.___SignedInteger: return typeof v === 'number'; case M.___String: return typeof v === 'string'; case M.___ByteString: return Bytes.isBytes(v); case M.___Symbol: return typeof v === 'symbol'; } case M.___lit: return is(v, p[0]); case M.___ref: return walk(lookup(env, p[0]), v); case M.___or: for (const pp of p[0]) { if (walk(pp, v)) return true; } return false; case M.___and: for (const pp of p[0]) { if (!walk(pp, v)) return false; } return true; case M.___pointer: return isPointer(v); case M.___rec: if (!Record.isRecord(v)) return false; if (!walk(p[0], v.label)) return false; return walk(p[1], v, true); case M.___tuple: if (!Array.isArray(v)) return false; if (!recordOkAsTuple && Record.isRecord(v)) return false; if (p[0].length !== v.length) return false; for (let i = 0; i < v.length; i++) { if (!walknamed(p[0][i], v[i])) return false; } return true; case M.___tuple_STAR_: if (!Array.isArray(v)) return false; if (!recordOkAsTuple && Record.isRecord(v)) return false; if (p[0].length > v.length) return false; for (let i = 0; i < p[0].length; i++) { if (!walknamed(p[0][i], v[i])) return false; } for (let i = p[0].length; i < v.length; i++) { if (!walknamed(p[1], v[i])) return false; } return true; case M.___setof: if (!Set.isSet(v)) return false; for (const vv of v) { if (!walk(p[0], vv)) return false; } return true; case M.___dictof: if (!Dictionary.isDictionary>(v)) return false; for (const e of v) { if (!walk(p[0], e[0])) return false; if (!walk(p[1], e[1])) return false; } return true; case M.___dict: if (!Dictionary.isDictionary>(v)) return false; for (const e of p[0]) { const vv = v.get(e[0]); if (vv === void 0) return false; if (!walk(e[1], vv)) return false; } return true; default: ((_p: never) => {})(p); return false; } } function walknamed(p: NamedPattern, v: Value): boolean { return (p.label === M.___named) ? walk(p[1], v) : walk(p, v); } return v => walk(p, v); }