It works! And still under 500 lines of code.
Chris Pressey
1 year, 6 months ago
366 | 366 | local evaluate |
367 | 367 | evaluate = function(ast) |
368 | 368 | assert(ast ~= nil, "ast is nil") |
369 | debug("eval", ast.tag) | |
370 | AST.case(ast, { | |
369 | debug("eval", render(ast)) | |
370 | local result = AST.case(ast, { | |
371 | 371 | program = function(assignments) |
372 | local index = math.random(1, #assignments) | |
373 | debug("eval", "program: chose " .. tostring(index)) | |
374 | return evaluate(assignments[index]) | |
372 | local index, result | |
373 | local done = false | |
374 | while not done do | |
375 | index = math.random(1, #assignments) | |
376 | debug("eval", "program: chose " .. tostring(index)) | |
377 | result = evaluate(assignments[index]) | |
378 | -- TODO: how do we tell when we're done? | |
379 | end | |
375 | 380 | end, |
376 | 381 | assignment = function(varname, varindex, expr) |
377 | 382 | debug("eval", "assignment: " .. varname .. " = " .. render(expr)) |
393 | 398 | elseif op == "*" then |
394 | 399 | lval = evaluate(lhs) |
395 | 400 | -- short-circuiting multiplication |
396 | if not lval then | |
401 | if lval == 0 then | |
397 | 402 | return 0 |
398 | 403 | else |
399 | 404 | rval = evaluate(rhs) |
402 | 407 | elseif op == "/" then |
403 | 408 | lval = evaluate(lhs) |
404 | 409 | rval = evaluate(rhs) |
405 | if not rval then | |
410 | if rval == 0 then | |
406 | 411 | return 0 |
407 | 412 | else |
408 | 413 | return lval // rval |
415 | 420 | else |
416 | 421 | return 0 |
417 | 422 | end |
423 | elseif op == ">" then | |
424 | lval = evaluate(lhs) | |
425 | rval = evaluate(rhs) | |
426 | if lval > rval then | |
427 | return 1 | |
428 | else | |
429 | return 0 | |
430 | end | |
418 | 431 | else |
419 | 432 | error("Not implemented BinOp: " .. op) |
420 | 433 | end |
423 | 436 | debug("eval", "action: " .. action .. " " .. mode .. " " .. render(expr)) |
424 | 437 | local r |
425 | 438 | local val = evaluate(expr) |
426 | if mode == "char" then r = chr(val) else r = tostring(val) end | |
427 | io:write(r) | |
439 | if mode == "char" then r = string.char(val) else r = tostring(val) end | |
440 | io.stdout:write(r) | |
441 | io.stdout:flush() | |
442 | return val | |
428 | 443 | end, |
429 | 444 | literal = function(val) |
430 | 445 | return val |
431 | 446 | end, |
432 | 447 | varaccess = function(varname, varindex) |
433 | debug("eval", "varaccess: " .. varname) | |
448 | debug("eval", "varaccess: " .. varname .. " is " .. tostring(store[varname])) | |
434 | 449 | if not store[varname] then |
435 | 450 | store[varname] = 0 |
436 | 451 | end |
452 | debug("eval", "varaccess: " .. varname .. " is " .. tostring(store[varname])) | |
437 | 453 | return store[varname] |
438 | 454 | end, |
439 | 455 | }) |
456 | assert(result ~= nil, "result of evaluating " .. render(ast) .. " was nil") | |
457 | return result | |
440 | 458 | end |
441 | 459 | |
442 | 460 | -- |
455 | 473 | -- |
456 | 474 | |
457 | 475 | function main(arg) |
476 | math.randomseed(os.time()) | |
458 | 477 | local filename |
459 | 478 | while #arg > 0 do |
460 | 479 | if arg[1] == "--debug" then |