-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathassert.lua
155 lines (119 loc) · 2.88 KB
/
assert.lua
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
149
150
151
152
153
154
155
local assert = {}
local Stream = {}
function Stream.cl_init(...)
local t = {}
setmetatable(t, {__index = Stream})
t:init(...)
return t
end
function Stream:init(text)
self.text = text
self.cursorCol = 1
self.cursorLine = 1
self.cursorAbs = 1
end
function Stream:peek(n)
n = n or 1
return self.text:sub(self.cursorAbs, self.cursorAbs + n)
end
function Stream:eat(n)
n = n or 1
local str = self:peek(n)
for i = 1, n do
local c = str:sub(i, i)
if c == "\n" then
self.cursorLine = self.cursorLine + 1
self.cursorCol = 1
else
self.cursorCol = self.cursorCol + 1
end
end
self.cursorAbs = self.cursorAbs + n
return str
end
function Stream:has(n)
n = n or 1
return #self:peek(n) == n
end
setmetatable(Stream, {__call = Stream.cl_init})
local function expectChar(stream, char)
if stream:peek() ~= char then
error(("Expected '%s' at line %d; col %d, but got '%s'")
:format(char, stream.cursorLine, stream.cursorCol, stream:peek()))
end
return stream:eat()
end
local function skipWhitespace(stream)
while true do
if stream:peek():match("^%s$") then
stream:eat()
elseif stream:peek(2) == ";;" then
-- Line comment
while stream:eat() ~= "\n" do end
else
break
end
end
end
local function parseIdent(stream)
local ident, i = {}, 0
while stream:peek():match("^[%w.]$") do
i = i + 1
ident[i] = stream:eat()
end
return {type = "ident", value = table.concat(i)}
end
local parseSElem -- Forward decleration
local function parseSExpr(stream)
expectChar(stream, "(")
skipWhitespace(stream)
local name = parseIdent(stream)
local elems, i = {}, 0
while true do
skipWhitespace(stream)
-- Exit condition
local nextToken = stream:peek()
if nextToken == ")" then break end
i = i + 1
elems[i] = parseSElem(stream)
end
expectChar(stream, ")")
return {type = "sexpr", name = name, elems = elems}
end
-- Not local since we forward declared
function parseSElem(stream)
local token = stream:peek()
if token == "(" then
return parseSExpr(stream)
elseif token:match("^%w$") then
return parseIdent(stream)
else
error(("Unexpected character '%s' at line %d; col %d"):format(token, stream.cursorLine, stream.cursorCol))
end
end
local function parseWAT(stream)
local components, i = {}, 0
while stream:has() do
skipWhitespace(stream)
i = i + 1
components[i] = parseSExpr(stream)
end
return components
end
function assert.loadAssertions(wat)
local tree = parseWAT(Stream(wat))
return tree
end
function assert.runTest(wat, wasm)
end
assert.util = {}
function assert.util.readFile(filename)
local handle = fs.open(filename, "r")
local data = handle:read("*a")
handle:close()
return data
end
function assert.util.readTest(testname)
return assert.util.readFile(("tests/%s.wat"):format(testname))
end
return assert