-- We tricked the Fennel repl into running inside a browser using Fengari and -- init.lua+repl.fnl. Now we must trick our trick into running back inside -- a normal shell, because debugging in the browser is kinda miserable. -- Helper functions local p = print local noop = function() return {} end local createElement = function() return { style={}, appendChild=table.insert, getAttribute=noop, setAttribute=noop, dispatchEvent=noop, } end -- io.open gets replaced with XHR stuff, so create a fake XHR that knows how -- to secretly io.open: local open = io.open local open = function(x, _, filename) local f = assert(open(filename)) x.response = f:read("*all") f:close() end -- Prepopulate the js module with pretend versions of every function the web -- repl uses to interact with the DOM, but redirect them to the shell. package.loaded.js = { new = function(x) return x end, global = { XMLHttpRequest = {open=open, send=noop, status=200, statusText=""}, document = { createEvent=function() return {initEvent=noop} end, createElement=createElement, createTextNode=function(_, x) return x end, -- Most elements we just don't care about, but we treat fengari-console -- specially because that's where our print output gets sent! getElementById=function(_, id) if id == "fengari-console" then local console = createElement() -- print gets replaced with some DOM stuff, so make -- fake DOM stuff that actually prints instead of -- inserting child elements into a div: function console.appendChild(_, line) p(table.concat(line, " ")) end return console else return createElement() end end, }, } } -- This file thinks it's running in the browser! Nobody spill the beans. local coro = require("init") -- The web repl contains an interactive tutorial. In the future, this could -- allow us to test the interactive tutorial, but for now let's just feed it -- some values and see what it does with them. -- The init.lua file launches the normal Fennel repl inside a -- coroutine, and instead of using io.read to get input from stdin, it -- replaces that function with coroutine.yield. This means that by -- resuming the coroutine, it simulates someone pressing enter in the -- shell. In the browser, this coroutine is resumed when someone -- presses enter in the web repl's <input> field, passing the contents -- of that field in when it resumes. Since we don't have that here, we -- just resume it manually with the "input" strings we want. coroutine.resume(coro, "(print :abc)") coroutine.resume(coro, "(var x 1)") coroutine.resume(coro, "(set x 2)") coroutine.resume(coro, "(print x :better-equal 2)") -- Output: -- Welcome to Fennel 0.4.0, running on Fengari (Lua 5.2) -- You can run any Fennel code here; try this: (print "Hello world!") -- > (print :abc) -- abc -- -- Well, not exactly what I had in mind, but close enough. -- How about some math; do you like math? Try this: (+ 1 1) -- > (var x 1) -- -- > (set x 2) -- -- > (print x :better-equal 2) -- 2 better-equal 2
Generated by Phil Hagelberg using scpaste at Wed May 13 19:16:48 2020. PDT. (original)