from .. import TypeEnum, Environment, Arg, Builtin, Function, evaluate, InterpretPanic from ..structs import * FUNCTOOLS = Environment() def interpretFilter(symbol, args, env, ns): func = args[0] if not isinstance(func, Function): raise InterpretPanic(symbol, "requires a :func as its first argument", func) lst = args[1] out = [] for arg in lst.args: ev = func.call(Expr([func, arg]), env, ns) if not isinstance(ev, Bool): raise InterpretPanic(symbol, "function must return :bool", ev) if ev.value: out.append(arg) return List(out) FUNCTOOLS.register("filter", Builtin("filter", interpretFilter, [Arg("func", TypeEnum.ANY), Arg("list", TypeEnum.LIST)])) def interpretMap(symbol, args, env, ns): func = args[0] if not isinstance(func, Function): raise InterpretPanic(symbol, "requires a :func as its first argument", func) lst = args[1] if not isinstance(lst, List): raise InterpretPanic(symbol, "requires a :list as its second argument", lst) out = [] for arg in lst.args: ev = func.call(Expr([func, arg]), env, ns) out.append(ev) return List(out) FUNCTOOLS.register("map", Builtin("map", interpretMap, [Arg("func", TypeEnum.ANY), Arg("list", TypeEnum.LIST)])) def interpretApply(symbol, args, env, ns): # TODO: to support lambdas, we can't assume the func is defined func = args[0] if not isinstance(func, Symbol): raise InterpretPanic(symbol, "requires a symbol as its first argument", func) new_expr = Expr([func] + args[1].args) return evaluate(new_expr, env, ns) FUNCTOOLS.register("apply", Builtin("apply", interpretApply, [Arg("func", TypeEnum.ANY, lazy=True), Arg("list", TypeEnum.LIST)]))