From ffe42d4d98a999916433a0e4bb230472ac2e1641 Mon Sep 17 00:00:00 2001 From: Bill Burdick Date: Wed, 25 Apr 2012 13:45:16 -0500 Subject: [PATCH] made 'require' monad (for both cmdline and browser, but not tested in cmdline) --- browserRepl.cs | 1 + browserRepl.js | 6 ++- leisure.cs | 13 +++--- leisure.html | 106 +++++-------------------------------------------- leisure.js | 20 +++++----- maps.js | 2 +- notebook.cs | 46 ++++++++++++++++++++- notebook.js | 67 +++++++++++++++++++++++++++++-- prim.cs | 29 ++++++++++---- prim.js | 47 +++++++++++++++------- replCore.cs | 3 +- replCore.js | 5 ++- std.js | 2 +- svg.js | 2 +- ttt_v2.html | 26 +++++------- 15 files changed, 214 insertions(+), 161 deletions(-) diff --git a/browserRepl.cs b/browserRepl.cs index c2696d43..f94616e2 100644 --- a/browserRepl.cs +++ b/browserRepl.cs @@ -9,6 +9,7 @@ write = null envFrame = null writeOutput = (line)-> + if output? output.innerHTML += "#{line}" output.lastChild.scrollIntoView() diff --git a/browserRepl.js b/browserRepl.js index 980e63a8..572a4467 100644 --- a/browserRepl.js +++ b/browserRepl.js @@ -18,8 +18,10 @@ envFrame = null; writeOutput = function writeOutput(line) { - output.innerHTML += "" + line + ""; - return output.lastChild.scrollIntoView(); + if (typeof output !== "undefined" && output !== null) { + output.innerHTML += "" + line + ""; + return output.lastChild.scrollIntoView(); + } }; getHtml = function getHtml(x) { diff --git a/leisure.cs b/leisure.cs index 0b3f1b03..1d5dc0de 100644 --- a/leisure.cs +++ b/leisure.cs @@ -594,12 +594,13 @@ continueApply tag(apply(laz(func))(laz(arg)), func.leisureStart, arg.leisureEnd) req = (name, gl)-> processDefs(require(name), gl) processDefs = (res, gl)-> - gl = gl ? global - if res.defs? then for i,v of res.defs - gl[i] = v - processTokenDefs res.tokenDefs - res.leisureFuncNames = ctx.leisureFuncNames - res.ctx = ctx + if res + gl = gl ? global + if res.defs? then for i,v of res.defs + gl[i] = v + processTokenDefs res.tokenDefs + res.leisureFuncNames = ctx.leisureFuncNames + res.ctx = ctx res processTokenDefs = (defs)-> diff --git a/leisure.html b/leisure.html index 24209b74..a946a4d6 100644 --- a/leisure.html +++ b/leisure.html @@ -2,7 +2,11 @@ - + + + + + @@ -18,11 +22,6 @@ --> - - - + - - -
@@ -152,15 +80,15 @@
-
-
maluba a b=a
+	
+
+
maluba a b=a
   true true
   b
 
 fred a=a
 
-print hello
+print 'hello'
 do
   n <- prompt 'What is your name?'
   print (concat ['hello, ', n])
@@ -172,19 +100,7 @@
 circle
diff --git a/leisure.js b/leisure.js index 331d8ad3..d5cb3f1d 100644 --- a/leisure.js +++ b/leisure.js @@ -1083,17 +1083,19 @@ misrepresented as being the original software. processDefs = function processDefs(res, gl) { var i, v, _ref; - gl = gl != null ? gl : global; - if (res.defs != null) { - _ref = res.defs; - for (i in _ref) { - v = _ref[i]; - gl[i] = v; + if (res) { + gl = gl != null ? gl : global; + if (res.defs != null) { + _ref = res.defs; + for (i in _ref) { + v = _ref[i]; + gl[i] = v; + } } + processTokenDefs(res.tokenDefs); + res.leisureFuncNames = ctx.leisureFuncNames; + res.ctx = ctx; } - processTokenDefs(res.tokenDefs); - res.leisureFuncNames = ctx.leisureFuncNames; - res.ctx = ctx; return res; }; diff --git a/maps.js b/maps.js index b0330151..001011c0 100644 --- a/maps.js +++ b/maps.js @@ -1,4 +1,4 @@ -(function(){ +var maps = (function(){ var root; if ((typeof window !== 'undefined' && window !== null) && (!(typeof global !== 'undefined' && global !== null) || global === window)) { diff --git a/notebook.cs b/notebook.cs index 2fa120dc..62a427fb 100644 --- a/notebook.cs +++ b/notebook.cs @@ -7,6 +7,7 @@ Leisure = window.Leisure ReplCore = window.ReplCore window.Notebook = root = {} + Prim = window.Prim else root = exports ? this delay = (func)-> @@ -116,6 +117,7 @@ parent.removeChild node markupDefs = (defs)-> pgm = '' + auto = '' for i in defs [main, name, def, body] = i if name? @@ -128,13 +130,14 @@ bod.appendChild textNode('\n') bx.appendChild bod pgm += "#{name} #{def} #{body}\n" else + if main.leisureAuto then auto += "#{body}\n" s = codeSpan body, 'codeExpr' s.appendChild textNode('\n') s.setAttribute('generatedNL', '') bx = box main, 'codeMainExpr', true bx.appendChild s makeOutputBox(bx) - pgm + [pgm, auto] textNode = (text)-> document.createTextNode(text) @@ -145,7 +148,6 @@ cleanOutput exBox b.innerHTML = "X" exBox.appendChild b ReplCore.processLine(prepExpr(exBox.source.textContent), envFor(exBox)) - #alert("Eval: #{exBox.source.textContent}") cleanOutput = (exBox)-> while exBox.firstChild != exBox.lastChild @@ -155,6 +157,7 @@ exBox.removeChild exBox.lastChild envFor = (box)-> exBox = getBox box + require: req write: (msg)-> div = document.createElement('div') div.innerHTML = "#{msg}\n" @@ -239,6 +242,7 @@ node.appendChild textNode(text) ex = txt.substring(mainStart, mainEnd).match /^(.*[^ \n])[ \n]*$/ exEnd = if ex then mainStart + ex[1].length else mainEnd outerRange = makeRange el, mainStart, exEnd + if leading.match /@auto/ then outerRange.leisureAuto = true [outerRange, null, null, txt.substring(mainStart, exEnd), next] makeRange = (el, off1, off2)-> @@ -283,11 +287,49 @@ nodeEnd child addsLine = (node)-> node.nodeName == 'BR' or (node.nodeType == 1 and getComputedStyle(node, null).display == 'block' and node.childNodes.length > 0) +req = (file, cont)-> + if !(file.match /\.js$/) then file = "#{file}.js" + name = file.substring(0, file.length - 3) + s = document.createElement 'script' + s.setAttribute 'src', file + s.addEventListener 'load', -> + Leisure.processDefs global[name], global + cont(_false()) + document.head.appendChild s + +loadQueue = [] + +queueAfterLoad = (func)-> loadQueue.push(func) + +evalDoc = (el)-> + Repl.clearEnv() + [pgm, auto] = initNotebook(el) + try + if auto + Notebook.queueAfterLoad -> Leisure.processDefs(Leisure.eval(ReplCore.generateCode('_doc', pgm, false)), global) + auto += "\nfinishLoading 'fred'\n"; + Leisure.eval(ReplCore.generateCode('_auto', auto, false)) + else Leisure.processDefs(Leisure.eval(ReplCore.generateCode('_doc', pgm, false)), global) + catch err + alert(err.stack) + + +Leisure.define 'finishLoading', (bubba)-> + Prim.makeMonad 'end', (env, cont)-> + for i in loadQueue + i() + loadQueue = [] + cont(_false()) + +Prim.defaultEnv.require = req root.initNotebook = initNotebook root.bindNotebook = bindNotebook root.evalOutput = evalOutput root.cleanOutput = cleanOutput root.envFor = envFor +root.queueAfterLoad = queueAfterLoad +root.evalDoc = evalDoc + #root.selection = -> window.getSelection().getRangeAt(0) #root.test = -> flatten(root.selection().cloneContents().childNodes[0]) \ No newline at end of file diff --git a/notebook.js b/notebook.js index cac3c658..8e9364a6 100644 --- a/notebook.js +++ b/notebook.js @@ -4,7 +4,7 @@ */ (function() { - var Leisure, ReplCore, addsLine, bindNotebook, box, checkMutateFromModification, checkMutateToDef, cleanOutput, codeBox, codeSpan, continueRangePosition, delay, envFor, evalOutput, findDefs, getBox, getRangePosition, getRanges, grp, initNotebook, makeOutputBox, makeRange, markupDefs, nodeEnd, prepExpr, removeOldDefs, root, selInDef, textNode, toDefBox, toExprBox, + var Leisure, Prim, ReplCore, addsLine, bindNotebook, box, checkMutateFromModification, checkMutateToDef, cleanOutput, codeBox, codeSpan, continueRangePosition, delay, envFor, evalDoc, evalOutput, findDefs, getBox, getRangePosition, getRanges, grp, initNotebook, loadQueue, makeOutputBox, makeRange, markupDefs, nodeEnd, prepExpr, queueAfterLoad, removeOldDefs, req, root, selInDef, textNode, toDefBox, toExprBox, __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; if ((typeof window !== "undefined" && window !== null) && (!(typeof global !== "undefined" && global !== null) || global === window)) { @@ -12,6 +12,7 @@ Leisure = window.Leisure; ReplCore = window.ReplCore; window.Notebook = root = {}; + Prim = window.Prim; } else { root = typeof exports !== "undefined" && exports !== null ? exports : this; } @@ -182,8 +183,9 @@ }; markupDefs = function markupDefs(defs) { - var bod, body, bx, def, i, main, name, pgm, s, _i, _len; + var auto, bod, body, bx, def, i, main, name, pgm, s, _i, _len; pgm = ''; + auto = ''; for (_i = 0, _len = defs.length; _i < _len; _i++) { i = defs[_i]; main = i[0], name = i[1], def = i[2], body = i[3]; @@ -197,6 +199,7 @@ bx.appendChild(bod); pgm += "" + name + " " + def + " " + body + "\n"; } else { + if (main.leisureAuto) auto += "" + body + "\n"; s = codeSpan(body, 'codeExpr'); s.appendChild(textNode('\n')); s.setAttribute('generatedNL', ''); @@ -205,7 +208,7 @@ makeOutputBox(bx); } } - return pgm; + return [pgm, auto]; }; textNode = function textNode(text) { @@ -244,6 +247,7 @@ var exBox; exBox = getBox(box); return { + require: req, write: function write(msg) { var div; div = document.createElement('div'); @@ -361,6 +365,7 @@ ex = txt.substring(mainStart, mainEnd).match(/^(.*[^ \n])[ \n]*$/); exEnd = ex ? mainStart + ex[1].length : mainEnd; outerRange = makeRange(el, mainStart, exEnd); + if (leading.match(/@auto/)) outerRange.leisureAuto = true; return [outerRange, null, null, txt.substring(mainStart, exEnd), next]; } } @@ -445,6 +450,58 @@ return node.nodeName === 'BR' || (node.nodeType === 1 && getComputedStyle(node, null).display === 'block' && node.childNodes.length > 0); }; + req = function req(file, cont) { + var name, s; + if (!(file.match(/\.js$/))) file = "" + file + ".js"; + name = file.substring(0, file.length - 3); + s = document.createElement('script'); + s.setAttribute('src', file); + s.addEventListener('load', function() { + Leisure.processDefs(global[name], global); + return cont(_false()); + }); + return document.head.appendChild(s); + }; + + loadQueue = []; + + queueAfterLoad = function queueAfterLoad(func) { + return loadQueue.push(func); + }; + + evalDoc = function evalDoc(el) { + var auto, pgm, _ref; + Repl.clearEnv(); + _ref = initNotebook(el), pgm = _ref[0], auto = _ref[1]; + try { + if (auto) { + Notebook.queueAfterLoad(function() { + return Leisure.processDefs(Leisure.eval(ReplCore.generateCode('_doc', pgm, false)), global); + }); + auto += "\nfinishLoading 'fred'\n"; + return Leisure.eval(ReplCore.generateCode('_auto', auto, false)); + } else { + return Leisure.processDefs(Leisure.eval(ReplCore.generateCode('_doc', pgm, false)), global); + } + } catch (err) { + return alert(err.stack); + } + }; + + Leisure.define('finishLoading', function(bubba) { + return Prim.makeMonad('end', function(env, cont) { + var i, _i, _len; + for (_i = 0, _len = loadQueue.length; _i < _len; _i++) { + i = loadQueue[_i]; + i(); + } + loadQueue = []; + return cont(_false()); + }); + }); + + Prim.defaultEnv.require = req; + root.initNotebook = initNotebook; root.bindNotebook = bindNotebook; @@ -455,4 +512,8 @@ root.envFor = envFor; + root.queueAfterLoad = queueAfterLoad; + + root.evalDoc = evalDoc; + }).call(this); diff --git a/prim.cs b/prim.cs index 6dee56d5..7ff417e1 100644 --- a/prim.cs +++ b/prim.cs @@ -6,8 +6,9 @@ output = null defaultEnv.write = (msg)-> if !output? then output = document.getElementById('output') - output.innerHTML += "#{msg}" - output.lastChild.scrollIntoView() + if output? + output.innerHTML += "#{msg}" + output.lastChild.scrollIntoView() defaultEnv.prompt = (msg, cont)-> cont(window.prompt(msg)) window.Prim = root = {} Leisure = window.Leisure @@ -21,6 +22,12 @@ tty = null defaultEnv.write = (msg)-> process.stdout.write(msg) defaultEnv.prompt = (msg, cont)-> tty.question(msg, cont) + r = (file, cont)-> + console.log(U.inspect(file)) + if !(file.match /^\.\//) then file = "./#{file}" + require file + cont() + defaultEnv.require = r setTty = (rl)-> tty = rl @@ -54,7 +61,7 @@ makeMonad 'end', (env, cont)-> cont Math.floor(from() + Math.random() * (to() - from() + 1)) -define 'rand', ()-> +define 'rand', -> makeMonad 'end', (env, cont)-> cont (Math.random()) @@ -68,6 +75,11 @@ cont Math.floor(from() + Math.random() * (to() - from() + 1)) eventCmds = [] running = false +define 'log', (msg)->(value)-> + if (msg().type != 'cons') then defaultEnv.write("#{msg()}") else defaultEnv.write(concatList(msg())) + defaultEnv.write("\n") + value() + leisureEvent = (leisureFuncName, evt, env)-> currentEvent = evt monad = Leisure.eval("#{Leisure.nameSub(leisureFuncName)}()")(laz(evt)) @@ -102,6 +114,8 @@ cont Math.floor(from() + Math.random() * (to() - from() + 1)) if binding != "end" then m.binding = binding m +define 'eventContext', (evt)-> evt().leisureContext + define 'eventX', (evt)-> evt().x define 'eventY', (evt)-> evt().y @@ -111,15 +125,14 @@ cont Math.floor(from() + Math.random() * (to() - from() + 1)) define 'return', (v)-> makeMonad 'end', (env, cont)->cont(v()) -define 'log', (msg)->(value)-> - if (msg().type != 'cons') then defaultEnv.write("#{msg()}") else defaultEnv.write(concatList(msg())) - defaultEnv.write("\n") - value() +define 'require', (file)-> + makeMonad 'end', (env, cont)-> + env.require(file(), cont) define 'print', (msg)-> makeMonad 'end', (env, cont)-> if msg() != _nil() then env.write("#{msg()}\n") - cont(_false) + cont(_false()) define 'prompt', (msg)-> makeMonad 'end', (env, cont)-> diff --git a/prim.js b/prim.js index df997ac6..bcc37d2f 100644 --- a/prim.js +++ b/prim.js @@ -1,5 +1,5 @@ (function() { - var Leisure, Pretty, RL, U, concatList, defaultEnv, define, eventCmds, getType, head, laz, leisureEvent, makeMonad, output, root, runMonad, runMonads, running, setTty, tail, tty, values; + var Leisure, Pretty, RL, U, concatList, defaultEnv, define, eventCmds, getType, head, laz, leisureEvent, makeMonad, output, r, root, runMonad, runMonads, running, setTty, tail, tty, values; defaultEnv = {}; @@ -8,8 +8,10 @@ output = null; defaultEnv.write = function write(msg) { if (!(output != null)) output = document.getElementById('output'); - output.innerHTML += "" + msg + ""; - return output.lastChild.scrollIntoView(); + if (output != null) { + output.innerHTML += "" + msg + ""; + return output.lastChild.scrollIntoView(); + } }; defaultEnv.prompt = function prompt(msg, cont) { return cont(window.prompt(msg)); @@ -29,6 +31,13 @@ defaultEnv.prompt = function prompt(msg, cont) { return tty.question(msg, cont); }; + r = function r(file, cont) { + console.log(U.inspect(file)); + if (!(file.match(/^\.\//))) file = "./" + file; + require(file); + return cont(); + }; + defaultEnv.require = r; } setTty = function setTty(rl) { @@ -214,6 +223,18 @@ running = false; + define('log', function(msg) { + return function(value) { + if (msg().type !== 'cons') { + defaultEnv.write("" + (msg())); + } else { + defaultEnv.write(concatList(msg())); + } + defaultEnv.write("\n"); + return value(); + }; + }); + leisureEvent = function leisureEvent(leisureFuncName, evt, env) { var currentEvent, monad; currentEvent = evt; @@ -260,6 +281,10 @@ return m; }; + define('eventContext', function(evt) { + return evt().leisureContext; + }); + define('eventX', function(evt) { return evt().x; }); @@ -278,22 +303,16 @@ }); }); - define('log', function(msg) { - return function(value) { - if (msg().type !== 'cons') { - defaultEnv.write("" + (msg())); - } else { - defaultEnv.write(concatList(msg())); - } - defaultEnv.write("\n"); - return value(); - }; + define('require', function(file) { + return makeMonad('end', function(env, cont) { + return env.require(file(), cont); + }); }); define('print', function(msg) { return makeMonad('end', function(env, cont) { if (msg() !== _nil()) env.write("" + (msg()) + "\n"); - return cont(_false); + return cont(_false()); }); }); diff --git a/replCore.cs b/replCore.cs index 81212f24..ed83caf1 100644 --- a/replCore.cs +++ b/replCore.cs @@ -127,8 +127,9 @@ processResult result generateCode = (file, contents, loud, handle, nomacros)-> if loud then console.log("Compiling #{file}:\n") + objName = if file? and file.match /\.lsr$/ then file.substring(0, file.length - 4) else file ? '_anonymous' out = """ -(function(){ +var #{objName} = (function(){ var root; if ((typeof window !== 'undefined' && window !== null) && (!(typeof global !== 'undefined' && global !== null) || global === window)) { diff --git a/replCore.js b/replCore.js index b318f626..14f074b2 100644 --- a/replCore.js +++ b/replCore.js @@ -190,9 +190,10 @@ }; generateCode = function generateCode(file, contents, loud, handle, nomacros) { - var a, ast, c, code, defs, err, errs, globals, i, m, names, nm, oldRest, out, prev, r, rest, src, v, varOut, _len, _ref, _ref2, _ref3, _ref4, _ref5; + var a, ast, c, code, defs, err, errs, globals, i, m, names, nm, objName, oldRest, out, prev, r, rest, src, v, varOut, _len, _ref, _ref2, _ref3, _ref4, _ref5; if (loud) console.log("Compiling " + file + ":\n"); - out = "(function(){\nvar root;\n\nif ((typeof window !== 'undefined' && window !== null) && (!(typeof global !== 'undefined' && global !== null) || global === window)) {\n " + (file != null ? file.replace(/\.lsr/, '') + ' = ' : '') + "root = {};\n global = window;\n} else {\n root = typeof exports !== 'undefined' && exports !== null ? exports : this;\n Leisure = require('./leisure');\n Leisure.req('./std');\n require('./prim');\n ReplCore = require('./replCore');\n Repl = require('./repl');\n}\nroot.defs = {};\nroot.tokenDefs = [];\nroot.macros = {};\n\nvar setType = Leisure.setType;\nvar setDataType = Leisure.setDataType;\nvar define = Leisure.define;\nvar defineMacro = Leisure.defineMacro;\nvar defineToken = Leisure.defineToken;\nvar processResult = Repl.processResult;\n"; + objName = (file != null) && file.match(/\.lsr$/) ? file.substring(0, file.length - 4) : file != null ? file : '_anonymous'; + out = "var " + objName + " = (function(){\nvar root;\n\nif ((typeof window !== 'undefined' && window !== null) && (!(typeof global !== 'undefined' && global !== null) || global === window)) {\n " + (file != null ? file.replace(/\.lsr/, '') + ' = ' : '') + "root = {};\n global = window;\n} else {\n root = typeof exports !== 'undefined' && exports !== null ? exports : this;\n Leisure = require('./leisure');\n Leisure.req('./std');\n require('./prim');\n ReplCore = require('./replCore');\n Repl = require('./repl');\n}\nroot.defs = {};\nroot.tokenDefs = [];\nroot.macros = {};\n\nvar setType = Leisure.setType;\nvar setDataType = Leisure.setDataType;\nvar define = Leisure.define;\nvar defineMacro = Leisure.defineMacro;\nvar defineToken = Leisure.defineToken;\nvar processResult = Repl.processResult;\n"; _ref = findDefs(contents, nomacros, loud), globals = _ref[0], errs = _ref[1]; names = globals; prev = Leisure.Nil; diff --git a/std.js b/std.js index e58c5a97..4771bb79 100644 --- a/std.js +++ b/std.js @@ -1,4 +1,4 @@ -(function(){ +var std = (function(){ var root; if ((typeof window !== 'undefined' && window !== null) && (!(typeof global !== 'undefined' && global !== null) || global === window)) { diff --git a/svg.js b/svg.js index 5af0859c..5f2b86cb 100644 --- a/svg.js +++ b/svg.js @@ -1,4 +1,4 @@ -(function(){ +var svg = (function(){ var root; if ((typeof window !== 'undefined' && window !== null) && (!(typeof global !== 'undefined' && global !== null) || global === window)) { diff --git a/ttt_v2.html b/ttt_v2.html index d717aa85..ca961c6e 100644 --- a/ttt_v2.html +++ b/ttt_v2.html @@ -10,11 +10,6 @@ - - - @@ -204,6 +192,12 @@
 
 
+#@auto
+require 'maps'
+
+#@auto
+require 'svg'
+
 svg-map = hash-from-list [ 'id', 'scene', 'data', 'ttt.svg', 'onload', 'initSVG(this)', 'width', 500, 'height', 600 ]
 
 svg-file svg-map