diff options
Diffstat (limited to 'type.lua')
-rw-r--r-- | type.lua | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/type.lua b/type.lua new file mode 100644 index 0000000..945f4d1 --- /dev/null +++ b/type.lua | |||
@@ -0,0 +1,137 @@ | |||
1 | --- lam.type | ||
2 | -- lisp types | ||
3 | |||
4 | local t = {} | ||
5 | local util = require "util" | ||
6 | local unpack = table.unpack or unpack | ||
7 | |||
8 | --- Determining types | ||
9 | |||
10 | t.luatype = type | ||
11 | |||
12 | function t.lamtype (x) | ||
13 | if t.luatype(x) == "number" then | ||
14 | return "Number" | ||
15 | elseif t.luatype(x) == "string" then | ||
16 | return "Symbol" | ||
17 | elseif getmetatable(x) and getmetatable(x).__type then | ||
18 | return getmetatable(x).__type | ||
19 | else | ||
20 | return t.luatype(x) | ||
21 | end | ||
22 | end | ||
23 | |||
24 | -- isa is really only useful on basic types (i.e., not Lists) | ||
25 | function t.isa (x, type) | ||
26 | return t.lamtype(x) == type | ||
27 | end | ||
28 | |||
29 | --- Creating types | ||
30 | |||
31 | -- Symbols and Numbers are strings and numbers, respectively. At some point | ||
32 | -- I'll want to implement a full numeric tower and symbol tables or namespaces | ||
33 | -- or whatever, but today is not that day | ||
34 | t.Symbol = tostring | ||
35 | t.Number = tonumber | ||
36 | |||
37 | -- Strings are (lightly) wrapped | ||
38 | function t.String (str) | ||
39 | local v = { | ||
40 | value = str, | ||
41 | escape = | ||
42 | function (self) | ||
43 | return self.gsub("[\\\"]", "\\%1") | ||
44 | end, | ||
45 | } | ||
46 | local mt = { | ||
47 | __type = "String", | ||
48 | __tostring = | ||
49 | function (self) | ||
50 | return string.format("\"%s\"", self:escape()) | ||
51 | end, | ||
52 | } | ||
53 | return setmetatable(v, mt) | ||
54 | end | ||
55 | |||
56 | function t.totable (cons) | ||
57 | local out = {} | ||
58 | local car, cdr = cons.car, cons.cdr | ||
59 | while cdr do | ||
60 | table.insert(out, tostring(car)) | ||
61 | if t.luatype(cdr) == "table" then | ||
62 | car = cdr.car | ||
63 | cdr = cdr.cdr | ||
64 | else | ||
65 | table.insert(out, cdr) | ||
66 | break | ||
67 | end | ||
68 | end | ||
69 | return out | ||
70 | end | ||
71 | |||
72 | -- Conses are Lisp's fundamental collection type | ||
73 | function t.Cons (a, b) | ||
74 | local v = { a, b, } | ||
75 | local mt = { | ||
76 | __type = "Cons", | ||
77 | __index = | ||
78 | function (self, key) | ||
79 | if key == "car" then | ||
80 | return self[1] | ||
81 | elseif key == "cdr" then | ||
82 | return self[2] | ||
83 | end | ||
84 | end, | ||
85 | __tostring = | ||
86 | function (self) | ||
87 | local out = {} | ||
88 | local car, cdr = self.car, self.cdr | ||
89 | while cdr do | ||
90 | table.insert(out, tostring(car)) | ||
91 | if t.luatype(cdr) == "table" then | ||
92 | car = cdr.car | ||
93 | cdr = cdr.cdr | ||
94 | else | ||
95 | table.insert(out, ".") | ||
96 | table.insert(out, cdr) | ||
97 | break | ||
98 | end | ||
99 | end | ||
100 | return "("..table.concat(out, " ")..")" | ||
101 | end, | ||
102 | } | ||
103 | return setmetatable(v, mt) | ||
104 | end | ||
105 | |||
106 | -- Null is the one value that is both an atom and a list | ||
107 | t.Null = setmetatable({}, { | ||
108 | __type = "Null", | ||
109 | __tostring = function (self) return "()" end, | ||
110 | }) | ||
111 | |||
112 | function t.isNull (x) | ||
113 | return x == t.Null | ||
114 | end | ||
115 | |||
116 | -- Lists are chained Conses ending in Null | ||
117 | function t.List (items) | ||
118 | local function tolist (base, items) | ||
119 | if #items == 0 then return base end | ||
120 | return tolist(t.Cons(table.remove(items), base), items) | ||
121 | end | ||
122 | return tolist(t.Null, items) | ||
123 | end | ||
124 | |||
125 | function t.isList (x) | ||
126 | -- TODO: this does not detect circular lists yet | ||
127 | if t.isNull(x) then | ||
128 | return true | ||
129 | elseif t.isa(x, "Cons") then | ||
130 | return t.isList(x.cdr) | ||
131 | else | ||
132 | return false | ||
133 | end | ||
134 | end | ||
135 | |||
136 | --- | ||
137 | return t | ||