import { makeCompareFn } from "../compare/dynamic.js"; import { compareTypes } from "../compare/type.js"; import { assignFn, UnifyError } from "../generics/generics.js"; import { getInst, getType, newDynamic } from "../primitives/dynamic.js"; import { Dynamic, Type } from "../primitives/primitive_types.js"; import { getSymbol } from "../primitives/type.js"; import { emptyDict, get, set } from "../structures/dict.js"; import { fold as foldList } from "../structures/list.js"; import { add, emptySet, fold as foldSet, has } from "../structures/set.js"; import { symbolFunction } from "../structures/type_constructors.js"; import { emptyTrie, insert } from "../util/trie.js"; const addEntry = typeDict => i => t => { const setOfInstances = _getInstances(typeDict)(t); return set(typeDict)(t)(add(setOfInstances)(i)); }; export const emptyEnv = { typeDict: emptyDict(compareTypes), name2dyn: emptyTrie, }; export const growEnv = ({typeDict, name2dyn}) => name => dynamic => { const t = getType(dynamic); const typeDictWithEntry = addEntry(typeDict )(getInst(dynamic))(t ); const typeDictWithType = addEntry(typeDictWithEntry)(t )(Type ); const typeDictWithDynamic = addEntry(typeDictWithType )(dynamic )(Dynamic); return { typeDict: typeDictWithDynamic, name2dyn: insert(name2dyn)(name)(dynamic), }; }; export const module2Env = module => { return foldList(env => ([name, dynamic]) => { try { return growEnv(env)(name)(dynamic); } catch (e) { console.log('skip:', e.message); return env; } })(emptyEnv)(module); }; const _getInstances = typeDict => type => { return get(typeDict)(type) || emptySet(makeCompareFn(type)); }; export const getInstances = env => type => _getInstances(env.typeDict)(type); export const getTypes = env => { return get(env.typeDict)(Type) || emptySet(compareTypes); }; export const contains = env => dynamic => { return has (getInstances(env)(getType(dynamic))) (getInst(dynamic)); } export const getFunctions = env => { const types = getTypes(env); return foldSet(types => type => { if (getSymbol(type) === symbolFunction) { return [ ...types, ...foldSet (functions => fn => [ ...functions, newDynamic(fn)(type), ]) ([]) (_getInstances(env.typeDict)(type)), ]; } return types; })([])(types); }; // return list of functions that can be called on 'dynamic' export const getEnabledFunctions = env => dynamic => { const allFunctions = getFunctions(env); const enabled = foldList(enabled => fun => { try { const outType = assignFn(getType(fun), getType(dynamic)); return [...enabled, {fun, outType}]; } catch (e) { if (!(e instanceof UnifyError)) { throw e; } return enabled; } })([])(allFunctions); return enabled; }; export const getCompatibleInputTypes = env => funType => { const allTypes = getTypes(env); const inTypes = foldSet(types => inType => { try { const outType = assignFn(funType, inType); // may throw return [...types, {inType, outType}]; } catch (e) { if (!(e instanceof UnifyError)) { throw e; } return types; } })([])(allTypes); return inTypes; };