// add a new canvas element to this page canvas = document.createElement('canvas') canvas.setAttribute('width', '500') canvas.setAttribute('height', '275') $('playArea').appendChild(canvas) ctxt = canvas.getContext('2d') // scheduler tasks = [] schedule = function(task) { tasks.push(task) } setInterval(function() { if (tasks.length > 0) tasks.shift()() }, 20) // the turtle smiley = { x: 250, y: 60, angle: 0, color: 'blue', penDown: true, forwardBy: function(n) { schedule(function() { ctxt.beginPath() ctxt.moveTo(smiley.x, smiley.y) smiley.x += n * Math.cos(smiley.angle) smiley.y += n * Math.sin(smiley.angle) if (smiley.penDown) { ctxt.lineTo(smiley.x, smiley.y); ctxt.stroke() } }) }, turnBy: function(n) { schedule(function() { smiley.angle += n * Math.PI / 180 }) }, setPenDown: function(penDown) { schedule(function() { smiley.penDown = penDown }) }, rt: function(n) { smiley.turnBy(n) }, lt: function(n) { smiley.turnBy(-n) }, fd: function(n) { smiley.forwardBy(n) }, bk: function(n) { smiley.forwardBy(-n) }, pu: function() { smiley.setPenDown(false) }, pd: function() { smiley.setPenDown(true) }, "if": function(cond, block) { if (cond) block() } } ometa LogoTranslator <: Parser { name = spaces , cmdName = ~("to" | "end" | "output") name, number = spaces , arg = ":" name, cmds = cmd*:xs -> xs.join(';'), block = "[" cmds:xs "]" -> ('(function() {' + xs + '})'), primExpr = arg | number | block | "(" (expr | cmd):x ")" -> x, mulExpr = mulExpr:x "*" primExpr:y -> (x + '*' + y) | mulExpr:x "/" primExpr:y -> (x + '/' + y) | primExpr, addExpr = addExpr:x "+" mulExpr:y -> (x + '+' + y) | addExpr:x "-" mulExpr:y -> (x + '-' + y) | mulExpr, expr = addExpr:x "<" addExpr:y -> (x + '<' + y) | addExpr:x "<=" addExpr:y -> (x + '<=' + y) | addExpr:x ">" addExpr:y -> (x + '>' + y) | addExpr:x ">=" addExpr:y -> (x + '>=' + y) | addExpr, cmd = "output" expr:x -> ('return ' + x) | cmdName:n expr*:args -> ('smiley["' + n + '"](' + args.join(',') + ')'), decl = "to" cmdName:n arg*:args cmds:body "end" -> ('smiley["' + n + '"]=function(' + args.join(',') + '){' + body + '}'), prog = (decl | cmd)*:xs spaces end -> xs.join(';') } translateCode = function(code) { return LogoTranslator.matchAll(code, 'prog') } to spiral :size :angle if :size < 100 [ fd :size rt :angle spiral :size + 2 :angle ] end spiral 1 89 spiral 1 30