Index: input.fnl ================================================================== --- input.fnl +++ input.fnl @@ -5,14 +5,34 @@ ;; This file reads lines from the default input file (stdin) and pushes the ;; read lines (and any errors) onto the love event queue. It stops reading ;; after the first nil line it reads (which may be the result of an error, or ;; simply EOF). +(local fennel (require :fennel)) +(fennel.install) +(set debug.traceback fennel.traceback) + +(fn make_love_searcher [env] + (fn [module-name] + (let [path (.. (module-name:gsub "%." "/") ".fnl")] + (if (love.filesystem.getInfo path) + (values (fn [...] + (let [code (love.filesystem.read path)] + (fennel.eval code {: env} ...))) + path))))) + +(table.insert package.loaders (make_love_searcher _G)) +(table.insert (. fennel "macro-searchers") (make_love_searcher "_COMPILER")) + ;; We will have been provided, by love.thread.newThread, a name to attach to ;; the events we push. -(local event-name ...) +(local (event-name run-id) ...) (assert event-name) +(assert run-id) + +(local transcript (require :transcript)) +(transcript.install run-id) (require "love.event") (var ok true) (fn handle [...] Index: main.fnl ================================================================== --- main.fnl +++ main.fnl @@ -1,7 +1,10 @@ ;; By the way, if you don't like goto statements, don't read this. +(local transcript (require :transcript)) +(local run-id (transcript.install)) + (local fennel (require :fennel)) (set debug.traceback fennel.traceback) ;; A table of update functions that will be exported by the game module. We'll ;; call each of these functions with the delta time in each call to @@ -29,14 +32,14 @@ ;; Start the stdin-reading thread, which pushes an event for each line of ;; input. This is run in a thread so that it is non-blocking. Instruct the ;; thread to tag its events with the event name :input, which we have ;; installed a handler for just above. (let [input-thread (love.thread.newThread "input.fnl")] - (input-thread:start :input))) + (input-thread:start :input run-id))) (lambda love.update [dt] ;; Run all the updater functions exported by the game module. (each [key update (pairs updaters)] (if (not (update dt)) ;; The update function returned false, indicating that it's no longer ;; needed. Remove it from the table. (tset updaters key nil)))) ADDED transcript.fnl Index: transcript.fnl ================================================================== --- /dev/null +++ transcript.fnl @@ -0,0 +1,47 @@ +;; Override print, io.write, and io.read calls to log timestamped interaction +;; to a file. + +(local fennel (require :fennel)) + +(local FILENAME "transcript.txt") + +(require "love.math") +(require "love.timer") + +(local start-time (love.timer.getTime)) + +(lambda record [run-id what s] + (let [now (love.timer.getTime) + dt (- now start-time) + rec (string.format "%s\t%.3f\t%s\t%s\n" + run-id dt what + (fennel.view s {:one-line? true :line-length math.huge :escape-newlines? true}))] + (assert (love.filesystem.append FILENAME rec)))) + +(lambda install [?run-id] + (let [run-id (or ?run-id (string.format "%07x" (love.math.random 0xfffffff)))] + (local print print) + (lambda transcript-print [...] + (each [_ s (ipairs (if (next [...]) [...] [""]))] + (record run-id "print" s)) + (print ...)) + (set _G.print transcript-print) + + (local io-write io.write) + (lambda transcript-io-write [...] + (each [_ s (ipairs [...])] + (record run-id "write" s)) + (io-write ...)) + (set _G.io.write transcript-io-write) + + (local io-read io.read) + (lambda transcript-io-read [...] + (let [res [(io-read ...)]] + (each [_ s (ipairs res)] + (record run-id "read" s)) + (unpack res))) + (set _G.io.read transcript-io-read) + + run-id)) + +{: install} ADDED untranscript.fnl Index: untranscript.fnl ================================================================== --- /dev/null +++ untranscript.fnl @@ -0,0 +1,16 @@ +;; ./fennel-1.6.0 untranscript.fnl < transcript.txt + +(local fennel (require :fennel)) + +(var prev-run-id nil) +(each [line (io.lines)] + (let [(run-id dt what s) (string.match line "^([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)$") + s (fennel.eval s)] + (assert run-id) + (if (not= run-id prev-run-id) + (print (string.format "\n=== %s ===\n" run-id))) + (set prev-run-id run-id) + (case what + "print" (print s) + "write" (io.write s) + "read" (print s))))