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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
import tables, strutils
type
MalTypeKind* = enum Nil, True, False, Number, Symbol, String,
List, Vector, HashMap, Fun, MalFun, Atom
FunType = proc(a: varargs[MalType]): MalType
MalFunType* = ref object
fn*: FunType
ast*: MalType
params*: MalType
env*: Env
is_macro*: bool
MalType* = object
case kind*: MalTypeKind
of Nil, True, False: nil
of Number: number*: int
of String, Symbol: str*: string
of List, Vector: list*: seq[MalType]
of HashMap: hash_map*: TableRef[string, MalType]
of Fun:
fun*: FunType
is_macro*: bool
of MalFun: malfun*: MalFunType
of Atom: val*: ref MalType
meta*: ref MalType
Env* = ref object
data*: Table[string, MalType]
outer*: Env
const nilObj* = MalType(kind: Nil)
const trueObj* = MalType(kind: True)
const falseObj* = MalType(kind: False)
proc number*(x: int): MalType = MalType(kind: Number, number: x)
proc symbol*(x: string): MalType = MalType(kind: Symbol, str: x)
proc str*(x: string): MalType {.procvar.} = MalType(kind: String, str: x)
proc keyword*(x: string): MalType = MalType(kind: String, str: "\xff" & x)
proc atom*(x: MalType): MalType =
result = MalType(kind: Atom)
new result.val
result.val[] = x
proc list*(xs: varargs[MalType]): MalType {.procvar.} =
result = MalType(kind: List, list: @[])
for x in xs: result.list.add x
proc vector*(xs: varargs[MalType]): MalType {.procvar.} =
result = MalType(kind: Vector, list: @[])
for x in xs: result.list.add x
proc hash_map*(xs: varargs[MalType]): MalType {.procvar.} =
result = MalType(kind: HashMap, hash_map: newTable[string, MalType]())
for i in countup(0, xs.high, 2):
let s = case xs[i].kind
of String: xs[i].str
else: xs[i].str
result.hash_map[s] = xs[i+1]
proc macro_q*(x: MalType): bool =
if x.kind == Fun: x.is_macro
else: x.malfun.is_macro
proc getFun*(x: MalType): FunType =
if x.kind == Fun: result = x.fun
elif x.kind == MalFun: result = x.malfun.fn
else: echo x.kind
proc fun*(x: proc(xs: varargs[MalType]): MalType, is_macro = false): MalType =
MalType(kind: Fun, fun: x, is_macro: is_macro)
proc malfun*(fn: auto, ast, params: MalType,
env: Env, is_macro = false): MalType =
MalType(kind: MalFun, malfun: MalFunType(fn: fn, ast: ast, params: params,
env: env, is_macro: is_macro))
proc boolObj*(b: bool): MalType =
if b: trueObj else: falseObj
proc list_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == List
proc vector_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == Vector
proc seq_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind in {List, Vector}
proc hash_map_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == HashMap
proc empty_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].list.len == 0
proc nil_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == Nil
proc true_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == True
proc false_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == False
proc symbol*(xs: varargs[MalType]): MalType {.procvar.} =
symbol(xs[0].str)
proc symbol_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == Symbol
proc keyword*(xs: varargs[MalType]): MalType {.procvar.} =
keyword(xs[0].str)
proc keyword_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj(xs[0].kind == String and xs[0].str[0] == '\xff')
proc atom*(xs: varargs[MalType]): MalType {.procvar.} =
atom(xs[0])
proc atom_q*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0].kind == Atom
proc count*(xs: varargs[MalType]): MalType {.procvar.} =
number if xs[0].kind == Nil: 0 else: xs[0].list.len
proc `==`*(x, y: MalType): bool =
if not (x.kind in {List, Vector} and y.kind in {List, Vector}):
if x.kind != y.kind: return false
result = case x.kind
of Nil, True, False: true
of Number: x.number == y.number
of Symbol, String: x.str == y.str
of List, Vector: x.list == y.list
of HashMap: x.hash_map == y.hash_map
of Fun: x.fun == y.fun and
x.is_macro == y.is_macro
of MalFun: x.malfun == y.malfun
of Atom: x.val == y.val
proc equal*(xs: varargs[MalType]): MalType {.procvar.} =
boolObj xs[0] == xs[1]
|