// TileScript idea function Tile() { } Tile.prototype.tileName = "Tile" Tile.prototype.keys = [] Tile.prototype.eval = function(ctxt) { this.subclassResponsibility() } Tile.prototype.asTile = function() { var r = "new " + this.tileName + "(" for (var idx = 0; idx < this.keys.length; idx++) { if (idx > 0) r += ", " r += this[this.keys[idx]].asTile() } return r + ")" } Tile.prototype.toString = function() { return this.asTile() } function Prim(p) { this.p = p } Prim.prototype = new Tile() Prim.prototype.eval = function(ctxt) { return this } Prim.prototype.asTile = function() { return "(" + this.p.toString() + ").asPrim()" } Object.prototype.asPrim = function() { return new Prim(this) } function Plus(x, y) { this.x = x; this.y = y } Plus.prototype = new Tile() Plus.prototype.tileName = "Plus" Plus.prototype.keys = ["x", "y"] Plus.prototype.eval = function(ctxt) { var y = this.y.eval(ctxt) return (this.x.eval(ctxt).p + this.y.eval(ctxt).p).asPrim() } function Arr(elements) { this.elements = elements } Arr.prototype = new Tile() Arr.prototype.tileName = "Arr" Arr.prototype.keys = ["elements"] Arr.prototype.eval = function(ctxt) { var newElements = new Array(this.elements.length) for (var idx=0; idx < this.elements.length; idx++) newElements[idx] = this.elements[idx].eval(ctxt) return newElements.asArr() } Arr.prototype.asTile = function() { return "new Arr([" + this.elements.toString() + "])" } Array.prototype.asArr = function() { return new Arr(this) } function Get(prop) { this.prop = prop } Get.prototype = new Tile() Get.prototype.tileName = "Get" Get.prototype.keys = ["prop"] Get.prototype.eval = function(ctxt) { return ctxt.get(this.prop.eval(ctxt).p) } function Set(prop, val) { this.prop = prop this.val = val } Set.prototype = new Tile() Set.prototype.tileName = "Set" Set.prototype.keys = ["prop", "val"] Set.prototype.eval = function(ctxt) { return ctxt.set(this.prop.eval(ctxt).p, this.val.eval(ctxt)) } function Seq(before, after) { this.before = before this.after = after } Seq.prototype = new Tile() Seq.prototype.tileName = "Seq" Seq.prototype.keys = ["before", "after"] Seq.prototype.eval = function(ctxt) { this.before.eval(ctxt) return this.after.eval(ctxt) } function Func(formals, body, env) { this.formals = formals this.body = body this.env = env } Func.prototype = new Tile() Func.prototype.tileName = "Func" Func.prototype.keys = ["formals", "body", "env"] Func.prototype.eval= function(ctxt) { return this } function App(func, args) { this.func = func this.args = args } App.prototype = new Tile() App.prototype.tileName = "App" App.prototype.keys = ["func", "args"] App.prototype.eval = function(ctxt) { var func = this.func.eval(ctxt) var args = this.args.eval(ctxt) var activation = new Context(func.env) for (var idx = 0; idx < func.formals.elements.length; idx++) activation[func.formals.elements[idx].p] = args.elements[idx] activation.arguments = args activation.thisContext = activation return func.body.eval(activation) } function Context(parent) { this.__parentContext__ = parent; } Context.prototype = new Tile() Context.prototype.tileName = "Context" Context.prototype.keys = ["__parentContext__"] Context.prototype.eval = function(ctxt) { return this } Context.prototype.get = function(name) { if (this[name] == undefined) return this.__parentContext__.get(name) return this[name] } Context.prototype.set = function(name, value) { if (this[name] == undefined) return this.__parentContext__.set(name, value); return this[name] = value } Global = new Context(null) Global.asTile = function() { return "Global" } Global.get = function(name) { return this[name] } Global.set = function(name, value) { return this[name] = value } Tile.prototype.ev = function() { return this.eval(Global) } // Unit Test test= function() { show("-- basic test --") show((1).asPrim().ev().p == 1); show((2).asPrim().asTile() == "(2).asPrim()"); threePlusFour = new Plus((3).asPrim(), (4).asPrim()); show(threePlusFour.ev().p == 7); show("-- Set Turtle s X to 100 --"); setX= new Set(("turtleX").asPrim(), (100).asPrim()); show(setX); show(setX.toString() == "new Set((turtleX).asPrim(), (100).asPrim())"); show(setX.ev().p == 100); show("-- Get Turtle s X --"); getX= new Get(("turtleX").asPrim()); show(getX); show(getX.ev().toString()); show(getX.toString() == "new Get((turtleX).asPrim())"); show(getX.ev().p == 100); show("-- Forward By 10 --"); forwardBy10= new Set(("turtleX").asPrim(), new Plus(new Get(("turtleX").asPrim()), (10).asPrim())); show(forwardBy10); show(forwardBy10.ev().toString()); show(getX.ev().p == 110); show("-- Compound --"); show(new Seq(forwardBy10, forwardBy10)); show(new Seq(forwardBy10, forwardBy10).ev().toString()); show(getX.ev().p == 130); show("-- Function (Forward By X) --"); forwardByStatement= forwardBy10; // should be a deep copy??? forwardByStatement.val.y= new Get(("x").asPrim()); forwardBy= new Func([("x").asPrim()].asArr(), forwardByStatement, Global); show(new App(forwardBy, [(10).asPrim()].asArr()).ev().toString()); show(getX.ev().p == 140); show("-- Named Function --"); setForwardBy= new Set(("forwardBy").asPrim(), forwardBy); setForwardBy.ev() getForwardBy= new Get(("forwardBy").asPrim()); call = new App(getForwardBy, [(1234).asPrim()].asArr()); show(call) show(call.ev().p == 1374) done(); } lines= ""; show= function (line) {lines+= line + "\n"} done= function () { alert(lines); lines= "" } test()