from .. import TypeEnum, Environment, Arg, Builtin, evaluate, InterpretPanic from ..structs import * import random LISTS = Environment() def interpretListLength(symbol, args, env, ns): return Int(len(args[0].args)) LISTS.register("list-length", Builtin("list-length", interpretListLength, [Arg("arg", TypeEnum.LIST)], return_type=Type(":int"))) def interpretFirst(symbol, args, env, ns): if len(args[0].args) == 0: raise InterpretPanic(symbol, "list is empty") return evaluate(args[0].args[0], env, ns) LISTS.register("first", Builtin("first", interpretFirst, [Arg("arg", TypeEnum.LIST, )])) def interpretRest(symbol, args, env, ns): # TODO do we know it's not evaluated? return List(args[0].args[1:]) # we don't evaluate the remainder of the list LISTS.register("rest", Builtin("rest", interpretRest, [Arg("arg", TypeEnum.LIST)], return_type=Type(":list"))) def interpretListReverse(symbol, args, env, ns): new_args = args[0].args[:] # make a copy of the args new_args.reverse() return List(new_args) LISTS.register("list-reverse", Builtin("list-reverse", interpretListReverse, [Arg("list", TypeEnum.LIST)], return_type=Type(":list"))) def interpretEmpty(symbol, args, env, ns): return Bool(len(args[0].args) == 0) LISTS.register("empty?", Builtin("empty?", interpretEmpty, [Arg("list", TypeEnum.LIST)], return_type=Type(":bool"))) def interpretShuf(symbol, args, env, ns): items = args[0].args[:] random.shuffle(items) return List(items) LISTS.register("shuf", Builtin("shuf", interpretShuf, [Arg("list", TypeEnum.LIST)], return_type=Type(":list"))) def interpretIn(symbol, args, env, ns): target = args[0] lst = args[1] for arg in lst.args: if type(arg) == type(target) and arg.value == target.value: return Bool(True) return Bool(False) in_target_arg = Arg("target", TypeEnum.LITERAL) in_list_arg = Arg("list", TypeEnum.LIST) LISTS.register("in?", Builtin("in?", interpretIn, [in_target_arg, in_list_arg], return_type=Type(":bool"))) def interpretLast(symbol, args, env, ns): if len(args[0].args) == 0: raise InterpretPanic("List is empty") return evaluate(args[0].args[-1], env, ns) LISTS.register("last", Builtin("last", interpretLast, [Arg("list", TypeEnum.LIST)])) def interpretSlice(symbol, args, env, ns): lst = args[0] idx = args[1] if len(args) == 2: return List(lst.args[idx.value - 1:]) length = args[2] diff = idx.value - 1 + length.value return List(lst.args[idx.value - 1:diff]) slice_list_arg = Arg("list", TypeEnum.LIST) slice_idx_arg = Arg("idx", TypeEnum.INT) slice_length_arg = Arg("length", TypeEnum.INT, optional=True) LISTS.register("slice", Builtin("slice", interpretSlice, [slice_list_arg, slice_idx_arg, slice_length_arg], return_type=Type(":list"))) def interpretAppend(symbol, args, env, ns): lst = args[0] val = args[1] items = lst.args[:] return List(items + [val]) LISTS.register("append", Builtin("append", interpretAppend, [Arg("list", TypeEnum.LIST), Arg("item", TypeEnum.ANY)], return_type=Type(":list"))) # TODO: this is actually for records/structs/whatever they're called def interpretRemove(symbol, args, env, ns): lst = args[0] key = args[1] out = [] for arg in lst.args: if arg.args[0].value != key.value: out.append(arg) return List(out) LISTS.register("remove", Builtin("remove", interpretRemove, [Arg("list", TypeEnum.LIST), Arg("key", TypeEnum.ANY)], return_type=Type(":list"))) def interpretZip(symbol, args, env, ns): z1 = args[0] z2 = args[1] if len(z1.args) != len(z2.args): raise InterpretPanic(symbol, "requires two :lists of the same size") out = [] for idx in range(len(z1.args)): f = z1.args[idx] s = z2.args[idx] out.append(List([f, s])) return List(out) zip_arg = Arg("list", TypeEnum.LIST) LISTS.register("zip", Builtin("zip", interpretZip, [zip_arg, zip_arg], return_type=Type(":list"))) def interpretList(symbol, args, env, ns): return List(args) LISTS.register("list", Builtin("list", interpretList, [], Arg("item", TypeEnum.ANY), Type(":list"))) def interpretSortNumbers(symbol, args, env, ns): items = [] for arg in args[0].args: if not isinstance(arg, Int) and not isinstance(arg, Float): raise InterpretPanic(symbol, "requires all :numbers", arg) items.append(arg.value) items.sort() out = [] for item in items: if isinstance(item, int): out.append(Int(item)) else: out.append(Float(item)) return List(out) LISTS.register("sort-numbers", Builtin("sort-numbers", interpretSortNumbers, [Arg("list", TypeEnum.LIST)], return_type=Type(":list")))