1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
from .. import TypeEnum, Environment, Arg, Builtin, evaluate
from ..structs import *
import random
LISTS = Environment()
def interpretListLength(symbol, args, env, ns):
return Int(len(args[0].args))
LISTS.register("list-length", Builtin(interpretListLength, [Arg("arg", TypeEnum.LIST)]))
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(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(interpretRest, [Arg("arg", TypeEnum.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(interpretListReverse, [Arg("list", TypeEnum.LIST)]))
def interpretEmpty(symbol, args, env, ns):
return Bool(len(args[0].args) == 0)
LISTS.register("empty?", Builtin(interpretEmpty, [Arg("list", TypeEnum.LIST)]))
def interpretShuf(symbol, args, env, ns):
items = args[0].args[:]
random.shuffle(items)
return List(items)
LISTS.register("shuf", Builtin(interpretShuf, [Arg("list", TypeEnum.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(interpretIn, [in_target_arg, in_list_arg]))
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(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(interpretSlice, [slice_list_arg, slice_idx_arg, slice_length_arg]))
def interpretAppend(symbol, args, env, ns):
lst = args[0]
val = args[1]
items = lst.args[:]
return List(items + [val])
LISTS.register("append", Builtin(interpretAppend, [Arg("list", TypeEnum.LIST), Arg("item", TypeEnum.ANY)]))
# 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(interpretRemove, [Arg("list", TypeEnum.LIST), Arg("key", TypeEnum.ANY)]))
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(interpretZip, [zip_arg, zip_arg]))
def interpretList(symbol, args, env, ns):
return List(args)
LISTS.register("list", Builtin(interpretList, [], Arg("item", TypeEnum.ANY)))
|