Checkpoint converting AST to be composed of variant records.
Chris Pressey
1 year, 5 months ago
13 | 13 | fn() |
14 | 14 | end |
15 | 15 | end |
16 | ||
17 | 16 | |
18 | 17 | debug = function(what, s) |
19 | 18 | do_debug(what, function() print("--> (" .. s .. ")") end) |
33 | 32 | return tostring(v) |
34 | 33 | end |
35 | 34 | end |
35 | ||
36 | -- | |
37 | -- Variant Records (for AST) | |
38 | -- | |
39 | ||
40 | function make_vrecord(config) | |
41 | return { | |
42 | maker = function(tag) | |
43 | local fields = config[tag] | |
44 | if not fields then | |
45 | error("Undefined tag: " .. tag) | |
46 | end | |
47 | return function(...) | |
48 | local num_args = select("#", ...) | |
49 | if num_args ~= #fields then | |
50 | error( | |
51 | "Arity error: expected " .. tostring(#fields) .. | |
52 | " for " .. tag .. ", got " .. tostring(num_args) | |
53 | ) | |
54 | end | |
55 | return { | |
56 | tag = tag, | |
57 | field_values = {...} | |
58 | } | |
59 | end | |
60 | end, | |
61 | case = function(obj, cases) | |
62 | local tag = obj.tag | |
63 | local field_values = obj.field_values | |
64 | local fields = config[tag] | |
65 | if not fields then | |
66 | error("Undefined tag: " .. tostring(tag)) | |
67 | end | |
68 | if #fields ~= #field_values then | |
69 | error("Arity error") | |
70 | end | |
71 | ||
72 | local sel = cases[tag] or cases.otherwise | |
73 | if not sel then | |
74 | error("No case for tag: " .. tag) | |
75 | end | |
76 | ||
77 | return sel(table.unpack(obj.field_values)) | |
78 | end | |
79 | } | |
80 | end | |
81 | ||
82 | -- | |
83 | -- AST | |
84 | -- | |
85 | ||
86 | local AST = make_vrecord({ | |
87 | assignment = {"varname", "varindex", "expr"}, | |
88 | binop = {"op", "lhs", "rhs"}, | |
89 | action = {"action", "mode", "val"}, | |
90 | literal = {"val"}, | |
91 | varaccess = {"name", "varindex"}, | |
92 | }) | |
93 | ||
94 | local Assignment = AST.maker("assignment") | |
95 | local BinOp = AST.maker("binop") | |
96 | local Action = AST.maker("action") | |
97 | local Literal = AST.maker("literal") | |
98 | local VarAccess = AST.maker("varaccess") | |
36 | 99 | |
37 | 100 | -- |
38 | 101 | -- Scanner |
183 | 246 | end |
184 | 247 | self.scanner:expect("=") |
185 | 248 | local expr = self:expression0() |
186 | return { | |
187 | type = "assignment", | |
188 | varname = varname, | |
189 | varindex = varindex, | |
190 | expr = expr, | |
191 | } | |
249 | return Assignment(varname, varindex, expr) | |
192 | 250 | end |
193 | 251 | |
194 | 252 | function Parser:expression0() |
196 | 254 | while self.scanner.token == "=" or self.scanner.token == ">" do |
197 | 255 | local t = self:consume_token() |
198 | 256 | local rhs = self:expression1() |
199 | expr = { | |
200 | type = t, | |
201 | lhs = expr, | |
202 | rhs = rhs, | |
203 | } | |
257 | expr = BinOp(t, expr, rhs) | |
204 | 258 | end |
205 | 259 | return expr |
206 | 260 | end |
210 | 264 | while self.scanner.token == "+" or self.scanner.token == "-" do |
211 | 265 | local t = self:consume_token() |
212 | 266 | local rhs = self:expression2() |
213 | expr = { | |
214 | type = t, | |
215 | lhs = expr, | |
216 | rhs = rhs, | |
217 | } | |
267 | expr = BinOp(t, expr, rhs) | |
218 | 268 | end |
219 | 269 | return expr |
220 | 270 | end |
224 | 274 | while self.scanner.token == "*" or self.scanner.token == "/" do |
225 | 275 | local t = self:consume_token() |
226 | 276 | local rhs = self:primitive() |
227 | expr = { | |
228 | type = t, | |
229 | lhs = expr, | |
230 | rhs = rhs, | |
231 | } | |
277 | expr = BinOp(t, expr, rhs) | |
232 | 278 | end |
233 | 279 | return expr |
234 | 280 | end |
253 | 299 | |
254 | 300 | if self.scanner.toktype == "number" then |
255 | 301 | local val = tonumber(self.scanner.token) |
302 | local expr = Literal(val) | |
256 | 303 | self.scanner:scan() |
257 | 304 | if action == "PRINT" then |
258 | return { | |
259 | type = "print", | |
260 | mode = mode, | |
261 | val = val | |
262 | } | |
305 | return Action("print", mode, expr) | |
263 | 306 | else |
264 | 307 | -- FIXME what about "INPUT" ... ? |
265 | return { | |
266 | type = "literal", | |
267 | val = val | |
268 | } | |
308 | return expr | |
269 | 309 | end |
270 | 310 | elseif self.scanner.toktype == "char" then |
271 | 311 | local val = string.byte(self.scanner.token, 2) |
312 | local expr = Literal(val) | |
272 | 313 | -- FIXME just as above |
273 | 314 | self.scanner:scan() |
274 | 315 | if action == "PRINT" then |
275 | return { | |
276 | type = "print", | |
277 | mode = mode, | |
278 | val = val | |
279 | } | |
316 | return Action("print", mode, expr) | |
280 | 317 | else |
281 | 318 | -- FIXME what about "INPUT" ... ? |
282 | return { | |
283 | type = "literal", | |
284 | val = val | |
285 | } | |
319 | return expr | |
286 | 320 | end |
287 | 321 | elseif self.scanner.token == "(" then |
288 | 322 | self.scanner:scan() |
290 | 324 | self.scanner:expect(")") |
291 | 325 | -- FIXME just as above |
292 | 326 | if action == "PRINT" then |
293 | return { | |
294 | type = "print", | |
295 | mode = mode, | |
296 | val = val | |
297 | } | |
327 | return Action("print", mode, expr) | |
298 | 328 | else |
299 | 329 | -- FIXME what about "INPUT" ... ? |
300 | return { | |
301 | type = "literal", | |
302 | val = val | |
303 | } | |
330 | return expr | |
304 | 331 | end |
305 | 332 | else |
306 | 333 | local name = self:expect_toktype("ident") |
307 | local ast = { | |
308 | type = "varaccess", | |
309 | name = name, | |
310 | } | |
334 | local varindex = nil | |
311 | 335 | if self.scanner.token == "[" then |
312 | ast.varindex = self:varindex() | |
313 | end | |
314 | return ast | |
315 | -- ?? return ['print', 'int', $q] if $mode == 1; | |
316 | -- ?? return ['print', 'char', $q] if $mode == 3; | |
317 | -- ?? return $q; | |
336 | varindex = self:varindex() | |
337 | end | |
338 | local expr = VarAccess(name, varindex) | |
339 | if action == "PRINT" then | |
340 | return Action("print", mode, expr) | |
341 | else | |
342 | -- FIXME what about "INPUT" ... ? | |
343 | return expr | |
344 | end | |
318 | 345 | end |
319 | 346 | end |
320 | 347 | |
326 | 353 | |
327 | 354 | local evaluate |
328 | 355 | evaluate = function(ast) |
329 | local type = ast.type | |
330 | if type == nil then -- FIXME: more explicit type on program? | |
356 | local tag = ast.type | |
357 | if type == nil then -- FIXME: more explicit type on program! | |
331 | 358 | local r = math.random(1, #ast) |
332 | 359 | return evaluate(ast[r]) |
333 | 360 | elseif type == "assignment" then |
372 | 399 | local p = Parser.new(program_text) |
373 | 400 | local ast = p:program() |
374 | 401 | debug("ast", render(ast)) |
375 | local result = evaluate(ast) | |
376 | debug("result", result) | |
402 | --local result = evaluate(ast) | |
403 | --debug("result", result) | |
377 | 404 | end |
378 | 405 | |
379 | 406 | if arg ~= nil then |