From 08333b714e73034ca9098692950051d5d9d78220 Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 21 Jan 2014 13:51:57 -0500 Subject: split off shader localstorage version --- shader-picker.html | 1 + 1 file changed, 1 insertion(+) (limited to 'shader-picker.html') diff --git a/shader-picker.html b/shader-picker.html index d482a6b..cc4bd18 100644 --- a/shader-picker.html +++ b/shader-picker.html @@ -115,6 +115,7 @@ a { color: #00f; } + -- cgit v1.2.3-70-g09d2 From b1aab59987e2f6aecf904d32ba092b509e72e9d3 Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 21 Jan 2014 15:31:31 -0500 Subject: call it local_shaders --- js/api/localstorage.js | 94 ++++++++++++++++++++++++------------------------ shader-localstorage.html | 4 +-- shader-picker.html | 4 +-- 3 files changed, 51 insertions(+), 51 deletions(-) (limited to 'shader-picker.html') diff --git a/js/api/localstorage.js b/js/api/localstorage.js index 0ec7cad..eeae658 100644 --- a/js/api/localstorage.js +++ b/js/api/localstorage.js @@ -1,106 +1,106 @@ -user.shaders = new function(){} -user.shaders.init = function(){ - user.shaders.bind() +local_shaders = new function(){} +local_shaders.init = function(){ + local_shaders.bind() } -user.shaders.bind = function(){ - user.shaders.buttons = {} +local_shaders.bind = function(){ + local_shaders.buttons = {} if ('SHADERS' in window) { - user.shaders.bindButtons( window.SHADERS ) + local_shaders.bindButtons( window.SHADERS ) } - user.shaders.bindButtons( user.shaders.getShaders() ) - document.getElementById("add-shader").addEventListener("click", user.shaders.save, false) - document.getElementById("remove-shader").addEventListener("click", user.shaders.remove, false) + local_shaders.bindButtons( local_shaders.getShaders() ) + document.getElementById("add-shader").addEventListener("click", local_shaders.save, false) + document.getElementById("remove-shader").addEventListener("click", local_shaders.remove, false) } -user.shaders.bindButtons = function(shaders){ +local_shaders.bindButtons = function(shaders){ for (var i = 0; i < shaders.length; i++){ - user.shaders.bindButton(shaders[i]) + local_shaders.bindButton(shaders[i]) } } -user.shaders.bindButton = function(data){ +local_shaders.bindButton = function(data){ // console.log("button >> " + data.name) var button = document.createElement("button") button.innerHTML = data.name - button.addEventListener("click", user.shaders.load.bind(this, data), false) + button.addEventListener("click", local_shaders.load.bind(this, data), false) document.getElementById("shaders").appendChild(button) - user.shaders.buttons[data.name] = button + local_shaders.buttons[data.name] = button } -user.shaders.load = function(data){ +local_shaders.load = function(data){ var shader = data.shader if (shader && shader.length > 0) { - user.shaders.name = data.name + local_shaders.name = data.name $("#shader").val(shader) // pause here? shader_build() $(".active").removeClass("active") - $(user.shaders.buttons[data.name]).addClass("active") - user.shaders.setLastAccessed(data.name) + $(local_shaders.buttons[data.name]).addClass("active") + local_shaders.setLastAccessed(data.name) } } -user.shaders.loadLastAccessed = function(){ +local_shaders.loadLastAccessed = function(){ var name = localStorage.getItem("im.lastShader") || "colorcycle" - if (name in user.shaders.buttons) { - $(user.shaders.buttons[name]).trigger("click") + if (name in local_shaders.buttons) { + $(local_shaders.buttons[name]).trigger("click") } } -user.shaders.setLastAccessed = function(name){ +local_shaders.setLastAccessed = function(name){ localStorage.setItem("im.lastShader", name) } -user.shaders.getShaderByName = function(name){ - return { name: name, shader: user.shaders.getShaderBody(name) } +local_shaders.getShaderByName = function(name){ + return { name: name, shader: local_shaders.getShaderBody(name) } } -user.shaders.getShaderIndex = function(){ +local_shaders.getShaderIndex = function(){ return JSON.parse( localStorage.getItem("im.shaders") ) || [] } -user.shaders.getShaderBody = function(name){ +local_shaders.getShaderBody = function(name){ return localStorage.getItem("im.shaders."+name) || null } -user.shaders.getShaders = function(){ - var shaders = user.shaders.getShaderIndex() - return shaders.map(function(name){ return { name: name, shader: user.shaders.getShaderBody(name) } }) +local_shaders.getShaders = function(){ + var shaders = local_shaders.getShaderIndex() + return shaders.map(function(name){ return { name: name, shader: local_shaders.getShaderBody(name) } }) } -user.shaders.setShaderIndex = function(shaders){ +local_shaders.setShaderIndex = function(shaders){ localStorage.setItem("im.shaders", JSON.stringify(shaders)) } -user.shaders.setShader = function(name, shader){ +local_shaders.setShader = function(name, shader){ if (! name.length || ! shader.length || !name.length || !shader.length) return localStorage.setItem("im.shaders." + name, shader) } -user.shaders.removeShader = function(name){ +local_shaders.removeShader = function(name){ localStorage.removeItem("im.shaders." + name) } -user.shaders.save = function(){ +local_shaders.save = function(){ var name = prompt("enter shader name") var shader = $("#shader").val() if (! name) return; if (shade !== shade_no_error_handling) return; - user.shaders.setShader(name, shader) + local_shaders.setShader(name, shader) - var shaders = user.shaders.getShaderIndex() + var shaders = local_shaders.getShaderIndex() shaders.push(name) - user.shaders.setShaderIndex(shaders) + local_shaders.setShaderIndex(shaders) - user.shaders.name = name - user.shaders.bindButton({ name: name, shader: shader }) + local_shaders.name = name + local_shaders.bindButton({ name: name, shader: shader }) $(".active").removeClass("active") - $(user.shaders.buttons[name]).addClass("active") - user.shaders.setLastAccessed(name) + $(local_shaders.buttons[name]).addClass("active") + local_shaders.setLastAccessed(name) } -user.shaders.remove = function(){ - var name = user.shaders.name +local_shaders.remove = function(){ + var name = local_shaders.name if (! name || ! name.length) return - var shaders = user.shaders.getShaderIndex() + var shaders = local_shaders.getShaderIndex() if (shaders.splice( shaders.indexOf(name), 1 )) { - user.shaders.setShaderIndex(shaders) - user.shaders.removeShader(name) - $(user.shaders.buttons[name]).remove() - user.shaders.name = "" + local_shaders.setShaderIndex(shaders) + local_shaders.removeShader(name) + $(local_shaders.buttons[name]).remove() + local_shaders.name = "" } } diff --git a/shader-localstorage.html b/shader-localstorage.html index cc4bd18..923f1b6 100644 --- a/shader-localstorage.html +++ b/shader-localstorage.html @@ -191,8 +191,8 @@ function init(){ console.log("signed in as", user.username) } - user.shaders.init() - user.shaders.loadLastAccessed() + local_shaders.init() + local_shaders.loadLastAccessed() document.getElementById('shader').addEventListener('input', shader_build); shader_build() diff --git a/shader-picker.html b/shader-picker.html index cc4bd18..923f1b6 100644 --- a/shader-picker.html +++ b/shader-picker.html @@ -191,8 +191,8 @@ function init(){ console.log("signed in as", user.username) } - user.shaders.init() - user.shaders.loadLastAccessed() + local_shaders.init() + local_shaders.loadLastAccessed() document.getElementById('shader').addEventListener('input', shader_build); shader_build() -- cgit v1.2.3-70-g09d2 From 3a51572e8a6628f90e73e2ab0bca52a98d9540e7 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Thu, 23 Jan 2014 10:10:19 -0500 Subject: more shuffling --- js/frames.js | 32 ++++++++++++++++++++++++++++++++ shader-api.html | 44 ++++++++++++++++++++++---------------------- shader-picker.html | 26 +++----------------------- 3 files changed, 57 insertions(+), 45 deletions(-) (limited to 'shader-picker.html') diff --git a/js/frames.js b/js/frames.js index 0ae256c..c9c844d 100644 --- a/js/frames.js +++ b/js/frames.js @@ -1,4 +1,36 @@ +var frame_editor = {} + +frame_editor.init = function(){ + frame_editor.bind() +} + +frame_editor.bind = function(){ + $("#add-frame").click(add_frame) + $("#frames").sortable({ + start: drag_start, + stop: drag_stop + }); + $(document).on("click","#frames .remove",remove_frame) + $("#framecount").change(function(){ + var val = $(this).int() + if (val < 1 || isNaN(val)) $(this).val(val = 1) + if (val == 1) $("#add-frame").html("+add frame") + else $("#add-frame").html("+add frames") + }) + + $("#frames").disableSelection(); + $("#remove-all-frames").click(remove_all_frames) + $("#weave-frames").click(weave_frames) + $("#shuffle-frames").click(shuffle_frames) + $("#reverse-frames").click(reverse_frames) + $("#sort-frames").click(sort_frames) + + $("#render").click(render) + $("#save").click(save) + $("#upload").click(upload) +} + function add_frame(){ var frame_count = $("#framecount").int() if (frame_count < 2) { diff --git a/shader-api.html b/shader-api.html index dc22d10..ba8530e 100644 --- a/shader-api.html +++ b/shader-api.html @@ -22,15 +22,15 @@ a { color: #00f; } @@ -57,15 +57,15 @@ a { color: #00f; } -
-
+
+
- -
- - - -
+ +
+ + + +
@@ -102,16 +102,16 @@ var shader_gallery_template = $("#shader-gallery-template").html() $(init) function init(){ - $("#url").change(load) - $("#reset").click(reset) - $("#pause").click(pause) + $("#url").change(load) + $("#reset").click(reset) + $("#pause").click(pause) user.init() shader_gallery.init() - document.getElementById('shader').addEventListener('input', shader_build); + document.getElementById('shader').addEventListener('input', shader_build); - requestAnimationFrame(animate) + requestAnimationFrame(animate) } diff --git a/shader-picker.html b/shader-picker.html index 923f1b6..0f27d6a 100644 --- a/shader-picker.html +++ b/shader-picker.html @@ -147,32 +147,13 @@ function init(){ mousey = e.pageY }) - $("#add-frame").click(add_frame) - $("#frames").sortable({ - start: drag_start, - stop: drag_stop - }); - $(document).on("click","#frames .remove",remove_frame) - $("#framecount").change(function(){ - var val = $(this).int() - if (val < 1 || isNaN(val)) $(this).val(val = 1) - if (val == 1) $("#add-frame").html("+add frame") - else $("#add-frame").html("+add frames") - }) $("#background").change(function(){ document.body.style.backgroundColor = $("#background").string() }) - $("#frames").disableSelection(); - $("#remove-all-frames").click(remove_all_frames) - $("#weave-frames").click(weave_frames) - $("#shuffle-frames").click(shuffle_frames) - $("#reverse-frames").click(reverse_frames) - $("#sort-frames").click(sort_frames) - - $("#render").click(render) - $("#save").click(save) - $("#upload").click(upload) + frame_editor.init() + + $(window).on("scroll DOMMouseScroll mousewheel", function(){ scrolling = true }) $("#help,#instructions .close").click(function(){ $("#instructions").toggle() }) $("#instructions").draggable({ start: drag_start, @@ -181,7 +162,6 @@ function init(){ $("#instructions").disableSelection(); load() - $(window).on("scroll DOMMouseScroll mousewheel", function(){ scrolling = true }) gallery.choose = choose gallery.init() -- cgit v1.2.3-70-g09d2 From 9bfb718de890bfaecae43b0d720038b0a9756bea Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Thu, 23 Jan 2014 10:11:23 -0500 Subject: switching from two-space indents to tabs --- shader-picker.html | 174 ++++++++++++++++++++++++++--------------------------- 1 file changed, 87 insertions(+), 87 deletions(-) (limited to 'shader-picker.html') diff --git a/shader-picker.html b/shader-picker.html index 0f27d6a..7d014f1 100644 --- a/shader-picker.html +++ b/shader-picker.html @@ -37,70 +37,70 @@ a { color: #00f; }
- -
-
- - -
-
- - frames - interval - - - -
- reorder: - - - - - -
-
-
- - gif delay - background - your name here → -
-
- -   - - -   - -
-
- Photoblaster Gallery + +
+
+ + +
+
+ + frames + interval + + + +
+ reorder: + + + + + +
+
+
+ + gif delay + background + your name here → +
+
+ +   + + +   + +
+
+ Photoblaster Gallery
- - - - - - -
- + + + + + + +
+
@@ -138,46 +138,46 @@ $(init) var mousex, mousey function init(){ - $("#url").change(load) - $("#reset").click(reset) - $("#pause").click(pause) - $("#step-forward").click(step_forward) - $(document).on("mousemove", function(e) { - mousex = e.pageX - mousey = e.pageY - }) - - $("#background").change(function(){ - document.body.style.backgroundColor = $("#background").string() - }) - + $("#url").change(load) + $("#reset").click(reset) + $("#pause").click(pause) + $("#step-forward").click(step_forward) + $(document).on("mousemove", function(e) { + mousex = e.pageX + mousey = e.pageY + }) + + $("#background").change(function(){ + document.body.style.backgroundColor = $("#background").string() + }) + frame_editor.init() - $(window).on("scroll DOMMouseScroll mousewheel", function(){ scrolling = true }) - $("#help,#instructions .close").click(function(){ $("#instructions").toggle() }) - $("#instructions").draggable({ - start: drag_start, - stop: drag_stop - }) - $("#instructions").disableSelection(); + $(window).on("scroll DOMMouseScroll mousewheel", function(){ scrolling = true }) + $("#help,#instructions .close").click(function(){ $("#instructions").toggle() }) + $("#instructions").draggable({ + start: drag_start, + stop: drag_stop + }) + $("#instructions").disableSelection(); - load() + load() - gallery.choose = choose - gallery.init() + gallery.choose = choose + gallery.init() - user.init() - if (user.username.length) { - console.log("signed in as", user.username) - } + user.init() + if (user.username.length) { + console.log("signed in as", user.username) + } - local_shaders.init() - local_shaders.loadLastAccessed() + local_shaders.init() + local_shaders.loadLastAccessed() - document.getElementById('shader').addEventListener('input', shader_build); - shader_build() + document.getElementById('shader').addEventListener('input', shader_build); + shader_build() - requestAnimationFrame(animate) + requestAnimationFrame(animate) } function drag_start(){ dragging = true; $(this).addClass("dragging") } function drag_stop(){ dragging = false; $(".dragging").removeClass("dragging") } -- cgit v1.2.3-70-g09d2 From 89bf91e68f1fac2d88eb97c7fe324753a5ef76cf Mon Sep 17 00:00:00 2001 From: timb Date: Fri, 24 Jan 2014 07:58:46 -0800 Subject: a try at error highlighting --- js/error.highlight.js | 160 +++++ js/shader.js | 28 + js/vendor/acorn.js | 1768 +++++++++++++++++++++++++++++++++++++++++++++++++ shader-api.html | 2 + shader-picker.html | 2 + 5 files changed, 1960 insertions(+) create mode 100644 js/error.highlight.js create mode 100644 js/vendor/acorn.js (limited to 'shader-picker.html') diff --git a/js/error.highlight.js b/js/error.highlight.js new file mode 100644 index 0000000..b7c583e --- /dev/null +++ b/js/error.highlight.js @@ -0,0 +1,160 @@ +(function(){ + +var html +var textarea +var dom = {} +var style = {} +var pos = {} +// i use this because a plain
collapses vertically sometimes... +var zero_width_space = '' + +var off = function(){ + dom.highlight.style.display = 'none' +} + +var height_until_error = 0; +var height_with_error = 0; + +var on = function(line_num){ + pos = textarea.getBoundingClientRect() + var text = textarea.value; + + var lines = text.split('\n') + var lines_until_error = lines.slice(0, line_num) + var line_with_error = lines[line_num] + + if (lines_until_error.length === 1) + dom.textmeasure.innerHTML = lines_until_error + zero_width_space + else + dom.textmeasure.innerHTML = lines_until_error.join('
' + zero_width_space) + + height_until_error = dom.textmeasure.offsetHeight + + dom.textmeasure.innerHTML = line_with_error + zero_width_space + + height_with_error = dom.textmeasure.offsetHeight + + reposition_highlight() + +}; + +var reposition_highlight = function(){ + dom.highlight.style.display = 'block' + + var bounds_bottom = pos.top + pos.height + + if (textarea.scrollHeight > textarea.clientHeight) // scrollbar exists + dom.highlight.style.width = pos.width - scrollbar_width + "px" + else + dom.highlight.style.width = pos.width + "px" + + dom.highlight.style.left = pos.left + "px" + + var y_pos = pos.top + height_until_error - textarea.scrollTop + + dom.highlight.style.top = y_pos + html.scrollTop + "px" + + var height_of_highlight = height_with_error; + + // nice clip on bottom + if (y_pos + height_of_highlight > bounds_bottom) + height_of_highlight = Math.max(0, bounds_bottom - y_pos) + // crap clip on top + if (y_pos < pos.top) + height_of_highlight = 0 + + dom.highlight.style.height = height_of_highlight + "px" +} + +var calc_textarea_style = function(){ + var $textarea = $("#shader") + textarea = $textarea[0] + // GG = textarea + + var props = ['lineHeight', 'fontFamily', 'fontSize', 'padding', 'margin', 'borderWidth', 'width'] + + for (var i=0, p; p=props[i]; i++){ + style[p] = $textarea.css(p) + } + console.log(style) + +} + + +var calc_scrollbar_width = function() { + var outer = document.createElement("div"); + outer.style.visibility = "hidden"; + outer.style.width = "100px"; + document.body.appendChild(outer); + + var width_no_scroll = outer.offsetWidth; + // force scrollbars + outer.style.overflow = "scroll"; + + // add innerdiv + var inner = document.createElement("div"); + inner.style.width = "100%"; + outer.appendChild(inner); + + var width_with_scroll = inner.offsetWidth; + // remove divs + outer.parentNode.removeChild(outer); + + return width_no_scroll - width_with_scroll; +} + +var create_el_textmeasure = function(){ + var el = dom.textmeasure = document.createElement('div') + el.id = 'textmeasure' + var s = el.style + for (var key in style) + s[key] = style[key] + + s.wordWrap = 'break-word' + s.wordBreak = 'break-all' + s.border = '1px solid red' + s.padding = '0' + s.display = 'block' + s.position = 'absolute' + s.left = "-5000px" + document.body.appendChild(el) +} + +var create_el_highlight = function(){ + var el = dom.highlight = document.createElement('div') + var s = el.style + for (var key in style) + s[key] = style[key] + + s.pointerEvents = 'none' + s.opacity = '0.2' + s.backgroundColor = '#f00' + s.position = 'absolute' + s.lineHeight = '0' + s.fontSize = '0' + s.padding = '0' + s.borderWidth = '0' + s.display = 'block' + document.body.appendChild(el) +} + +var scrollbar_width = 0; +var init = function(){ + calc_textarea_style() + create_el_highlight() + create_el_textmeasure() + scrollbar_width = calc_scrollbar_width() + textarea.addEventListener('scroll', reposition_highlight) + html = document.querySelector('html') +} + +error_highlight = { + init: init, + on: on, + off: off +} + + +})(); + +error_highlight.init() diff --git a/js/shader.js b/js/shader.js index 19c049b..003f543 100644 --- a/js/shader.js +++ b/js/shader.js @@ -4,8 +4,16 @@ var shader_build = function(){ try { var fn = new Function('x','y','t','d', fn_str) shader = fn + error_highlight.off() shade = shade_error_handling } catch (e) { + try { + acorn.parse(fn_str) + } catch(e){ + /* loc: {column: 0, line: 1} */ + /* line is 1-based for some goddamn reason*/ + error_highlight.on(e.loc.line-1) + } throw Error ("Shader compilation error") } } @@ -36,6 +44,9 @@ function shade_no_error_handling(frame, t){ cc.putImageData(imgData,0,0) } +var chrome_stack_regexp = /:([0-9]+)/; +var firefox_stack_regexp = /:([0-9]+)$/; + function shade_error_handling(frame, t){ if (! t || isNaN(t)) throw Error ("No time specified") if (! frame) throw Error ("No frame specified") @@ -61,6 +72,20 @@ function shade_error_handling(frame, t){ } } catch(e){ + var lines = (e.stack + "").split('\n') + if (lines[0].substr(0,10) === "anonymous@") { //firefox + var matches = lines[0].match(firefox_stack_regexp) + if (matches.length > 1) { + var line = parseInt(matches[1]) - 5 + error_highlight.on(line) + } + } else if (lines.length > 1) { // attempt chrome match + var matches = lines[1].match(chrome_stack_regexp) + if (matches.length > 1) { + var line = parseInt(matches[1]) - 3 + error_highlight.on(line) + } + } // console.log(e.stack) throw Error ("Shader execution error") } @@ -69,3 +94,6 @@ function shade_error_handling(frame, t){ } shade = shade_error_handling + +// :4:11) +// "anonymous@http://dither.local/js/shader.js:6" \ No newline at end of file diff --git a/js/vendor/acorn.js b/js/vendor/acorn.js new file mode 100644 index 0000000..c335f65 --- /dev/null +++ b/js/vendor/acorn.js @@ -0,0 +1,1768 @@ +// Acorn is a tiny, fast JavaScript parser written in JavaScript. +// +// Acorn was written by Marijn Haverbeke and released under an MIT +// license. The Unicode regexps (for identifiers and whitespace) were +// taken from [Esprima](http://esprima.org) by Ariya Hidayat. +// +// Git repositories for Acorn are available at +// +// http://marijnhaverbeke.nl/git/acorn +// https://github.com/marijnh/acorn.git +// +// Please use the [github bug tracker][ghbt] to report issues. +// +// [ghbt]: https://github.com/marijnh/acorn/issues +// +// This file defines the main parser interface. The library also comes +// with a [error-tolerant parser][dammit] and an +// [abstract syntax tree walker][walk], defined in other files. +// +// [dammit]: acorn_loose.js +// [walk]: util/walk.js + +(function(root, mod) { + if (typeof exports == "object" && typeof module == "object") return mod(exports); // CommonJS + if (typeof define == "function" && define.amd) return define(["exports"], mod); // AMD + mod(root.acorn || (root.acorn = {})); // Plain browser env +})(this, function(exports) { + "use strict"; + + exports.version = "0.4.1"; + + // The main exported interface (under `self.acorn` when in the + // browser) is a `parse` function that takes a code string and + // returns an abstract syntax tree as specified by [Mozilla parser + // API][api], with the caveat that the SpiderMonkey-specific syntax + // (`let`, `yield`, inline XML, etc) is not recognized. + // + // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API + + var options, input, inputLen, sourceFile; + + exports.parse = function(inpt, opts) { + input = String(inpt); inputLen = input.length; + setOptions(opts); + initTokenState(); + return parseTopLevel(options.program); + }; + + // A second optional argument can be given to further configure + // the parser process. These options are recognized: + + var defaultOptions = exports.defaultOptions = { + // `ecmaVersion` indicates the ECMAScript version to parse. Must + // be either 3 or 5. This + // influences support for strict mode, the set of reserved words, and + // support for getters and setter. + ecmaVersion: 5, + // Turn on `strictSemicolons` to prevent the parser from doing + // automatic semicolon insertion. + strictSemicolons: false, + // When `allowTrailingCommas` is false, the parser will not allow + // trailing commas in array and object literals. + allowTrailingCommas: true, + // By default, reserved words are not enforced. Enable + // `forbidReserved` to enforce them. + forbidReserved: false, + // When `locations` is on, `loc` properties holding objects with + // `start` and `end` properties in `{line, column}` form (with + // line being 1-based and column 0-based) will be attached to the + // nodes. + locations: false, + // A function can be passed as `onComment` option, which will + // cause Acorn to call that function with `(block, text, start, + // end)` parameters whenever a comment is skipped. `block` is a + // boolean indicating whether this is a block (`/* */`) comment, + // `text` is the content of the comment, and `start` and `end` are + // character offsets that denote the start and end of the comment. + // When the `locations` option is on, two more parameters are + // passed, the full `{line, column}` locations of the start and + // end of the comments. Note that you are not allowed to call the + // parser from the callback—that will corrupt its internal state. + onComment: null, + // Nodes have their start and end characters offsets recorded in + // `start` and `end` properties (directly on the node, rather than + // the `loc` object, which holds line/column data. To also add a + // [semi-standardized][range] `range` property holding a `[start, + // end]` array with the same numbers, set the `ranges` option to + // `true`. + // + // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 + ranges: false, + // It is possible to parse multiple files into a single AST by + // passing the tree produced by parsing the first file as + // `program` option in subsequent parses. This will add the + // toplevel forms of the parsed file to the `Program` (top) node + // of an existing parse tree. + program: null, + // When `locations` is on, you can pass this to record the source + // file in every node's `loc` object. + sourceFile: null, + // This value, if given, is stored in every node, whether + // `locations` is on or off. + directSourceFile: null + }; + + function setOptions(opts) { + options = opts || {}; + for (var opt in defaultOptions) if (!Object.prototype.hasOwnProperty.call(options, opt)) + options[opt] = defaultOptions[opt]; + sourceFile = options.sourceFile || null; + } + + // The `getLineInfo` function is mostly useful when the + // `locations` option is off (for performance reasons) and you + // want to find the line/column position for a given character + // offset. `input` should be the code string that the offset refers + // into. + + var getLineInfo = exports.getLineInfo = function(input, offset) { + for (var line = 1, cur = 0;;) { + lineBreak.lastIndex = cur; + var match = lineBreak.exec(input); + if (match && match.index < offset) { + ++line; + cur = match.index + match[0].length; + } else break; + } + return {line: line, column: offset - cur}; + }; + + // Acorn is organized as a tokenizer and a recursive-descent parser. + // The `tokenize` export provides an interface to the tokenizer. + // Because the tokenizer is optimized for being efficiently used by + // the Acorn parser itself, this interface is somewhat crude and not + // very modular. Performing another parse or call to `tokenize` will + // reset the internal state, and invalidate existing tokenizers. + + exports.tokenize = function(inpt, opts) { + input = String(inpt); inputLen = input.length; + setOptions(opts); + initTokenState(); + + var t = {}; + function getToken(forceRegexp) { + lastEnd = tokEnd; + readToken(forceRegexp); + t.start = tokStart; t.end = tokEnd; + t.startLoc = tokStartLoc; t.endLoc = tokEndLoc; + t.type = tokType; t.value = tokVal; + return t; + } + getToken.jumpTo = function(pos, reAllowed) { + tokPos = pos; + if (options.locations) { + tokCurLine = 1; + tokLineStart = lineBreak.lastIndex = 0; + var match; + while ((match = lineBreak.exec(input)) && match.index < pos) { + ++tokCurLine; + tokLineStart = match.index + match[0].length; + } + } + tokRegexpAllowed = reAllowed; + skipSpace(); + }; + return getToken; + }; + + // State is kept in (closure-)global variables. We already saw the + // `options`, `input`, and `inputLen` variables above. + + // The current position of the tokenizer in the input. + + var tokPos; + + // The start and end offsets of the current token. + + var tokStart, tokEnd; + + // When `options.locations` is true, these hold objects + // containing the tokens start and end line/column pairs. + + var tokStartLoc, tokEndLoc; + + // The type and value of the current token. Token types are objects, + // named by variables against which they can be compared, and + // holding properties that describe them (indicating, for example, + // the precedence of an infix operator, and the original name of a + // keyword token). The kind of value that's held in `tokVal` depends + // on the type of the token. For literals, it is the literal value, + // for operators, the operator name, and so on. + + var tokType, tokVal; + + // Interal state for the tokenizer. To distinguish between division + // operators and regular expressions, it remembers whether the last + // token was one that is allowed to be followed by an expression. + // (If it is, a slash is probably a regexp, if it isn't it's a + // division operator. See the `parseStatement` function for a + // caveat.) + + var tokRegexpAllowed; + + // When `options.locations` is true, these are used to keep + // track of the current line, and know when a new line has been + // entered. + + var tokCurLine, tokLineStart; + + // These store the position of the previous token, which is useful + // when finishing a node and assigning its `end` position. + + var lastStart, lastEnd, lastEndLoc; + + // This is the parser's state. `inFunction` is used to reject + // `return` statements outside of functions, `labels` to verify that + // `break` and `continue` have somewhere to jump to, and `strict` + // indicates whether strict mode is on. + + var inFunction, labels, strict; + + // This function is used to raise exceptions on parse errors. It + // takes an offset integer (into the current `input`) to indicate + // the location of the error, attaches the position to the end + // of the error message, and then raises a `SyntaxError` with that + // message. + + function raise(pos, message) { + var loc = getLineInfo(input, pos); + message += " (" + loc.line + ":" + loc.column + ")"; + var err = new SyntaxError(message); + err.pos = pos; err.loc = loc; err.raisedAt = tokPos; + throw err; + } + + // Reused empty array added for node fields that are always empty. + + var empty = []; + + // ## Token types + + // The assignment of fine-grained, information-carrying type objects + // allows the tokenizer to store the information it has about a + // token in a way that is very cheap for the parser to look up. + + // All token type variables start with an underscore, to make them + // easy to recognize. + + // These are the general types. The `type` property is only used to + // make them recognizeable when debugging. + + var _num = {type: "num"}, _regexp = {type: "regexp"}, _string = {type: "string"}; + var _name = {type: "name"}, _eof = {type: "eof"}; + + // Keyword tokens. The `keyword` property (also used in keyword-like + // operators) indicates that the token originated from an + // identifier-like word, which is used when parsing property names. + // + // The `beforeExpr` property is used to disambiguate between regular + // expressions and divisions. It is set on all token types that can + // be followed by an expression (thus, a slash after them would be a + // regular expression). + // + // `isLoop` marks a keyword as starting a loop, which is important + // to know when parsing a label, in order to allow or disallow + // continue jumps to that label. + + var _break = {keyword: "break"}, _case = {keyword: "case", beforeExpr: true}, _catch = {keyword: "catch"}; + var _continue = {keyword: "continue"}, _debugger = {keyword: "debugger"}, _default = {keyword: "default"}; + var _do = {keyword: "do", isLoop: true}, _else = {keyword: "else", beforeExpr: true}; + var _finally = {keyword: "finally"}, _for = {keyword: "for", isLoop: true}, _function = {keyword: "function"}; + var _if = {keyword: "if"}, _return = {keyword: "return", beforeExpr: true}, _switch = {keyword: "switch"}; + var _throw = {keyword: "throw", beforeExpr: true}, _try = {keyword: "try"}, _var = {keyword: "var"}; + var _while = {keyword: "while", isLoop: true}, _with = {keyword: "with"}, _new = {keyword: "new", beforeExpr: true}; + var _this = {keyword: "this"}; + + // The keywords that denote values. + + var _null = {keyword: "null", atomValue: null}, _true = {keyword: "true", atomValue: true}; + var _false = {keyword: "false", atomValue: false}; + + // Some keywords are treated as regular operators. `in` sometimes + // (when parsing `for`) needs to be tested against specifically, so + // we assign a variable name to it for quick comparing. + + var _in = {keyword: "in", binop: 7, beforeExpr: true}; + + // Map keyword names to token types. + + var keywordTypes = {"break": _break, "case": _case, "catch": _catch, + "continue": _continue, "debugger": _debugger, "default": _default, + "do": _do, "else": _else, "finally": _finally, "for": _for, + "function": _function, "if": _if, "return": _return, "switch": _switch, + "throw": _throw, "try": _try, "var": _var, "while": _while, "with": _with, + "null": _null, "true": _true, "false": _false, "new": _new, "in": _in, + "instanceof": {keyword: "instanceof", binop: 7, beforeExpr: true}, "this": _this, + "typeof": {keyword: "typeof", prefix: true, beforeExpr: true}, + "void": {keyword: "void", prefix: true, beforeExpr: true}, + "delete": {keyword: "delete", prefix: true, beforeExpr: true}}; + + // Punctuation token types. Again, the `type` property is purely for debugging. + + var _bracketL = {type: "[", beforeExpr: true}, _bracketR = {type: "]"}, _braceL = {type: "{", beforeExpr: true}; + var _braceR = {type: "}"}, _parenL = {type: "(", beforeExpr: true}, _parenR = {type: ")"}; + var _comma = {type: ",", beforeExpr: true}, _semi = {type: ";", beforeExpr: true}; + var _colon = {type: ":", beforeExpr: true}, _dot = {type: "."}, _question = {type: "?", beforeExpr: true}; + + // Operators. These carry several kinds of properties to help the + // parser use them properly (the presence of these properties is + // what categorizes them as operators). + // + // `binop`, when present, specifies that this operator is a binary + // operator, and will refer to its precedence. + // + // `prefix` and `postfix` mark the operator as a prefix or postfix + // unary operator. `isUpdate` specifies that the node produced by + // the operator should be of type UpdateExpression rather than + // simply UnaryExpression (`++` and `--`). + // + // `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as + // binary operators with a very low precedence, that should result + // in AssignmentExpression nodes. + + var _slash = {binop: 10, beforeExpr: true}, _eq = {isAssign: true, beforeExpr: true}; + var _assign = {isAssign: true, beforeExpr: true}; + var _incDec = {postfix: true, prefix: true, isUpdate: true}, _prefix = {prefix: true, beforeExpr: true}; + var _logicalOR = {binop: 1, beforeExpr: true}; + var _logicalAND = {binop: 2, beforeExpr: true}; + var _bitwiseOR = {binop: 3, beforeExpr: true}; + var _bitwiseXOR = {binop: 4, beforeExpr: true}; + var _bitwiseAND = {binop: 5, beforeExpr: true}; + var _equality = {binop: 6, beforeExpr: true}; + var _relational = {binop: 7, beforeExpr: true}; + var _bitShift = {binop: 8, beforeExpr: true}; + var _plusMin = {binop: 9, prefix: true, beforeExpr: true}; + var _multiplyModulo = {binop: 10, beforeExpr: true}; + + // Provide access to the token types for external users of the + // tokenizer. + + exports.tokTypes = {bracketL: _bracketL, bracketR: _bracketR, braceL: _braceL, braceR: _braceR, + parenL: _parenL, parenR: _parenR, comma: _comma, semi: _semi, colon: _colon, + dot: _dot, question: _question, slash: _slash, eq: _eq, name: _name, eof: _eof, + num: _num, regexp: _regexp, string: _string}; + for (var kw in keywordTypes) exports.tokTypes["_" + kw] = keywordTypes[kw]; + + // This is a trick taken from Esprima. It turns out that, on + // non-Chrome browsers, to check whether a string is in a set, a + // predicate containing a big ugly `switch` statement is faster than + // a regular expression, and on Chrome the two are about on par. + // This function uses `eval` (non-lexical) to produce such a + // predicate from a space-separated string of words. + // + // It starts by sorting the words by length. + + function makePredicate(words) { + words = words.split(" "); + var f = "", cats = []; + out: for (var i = 0; i < words.length; ++i) { + for (var j = 0; j < cats.length; ++j) + if (cats[j][0].length == words[i].length) { + cats[j].push(words[i]); + continue out; + } + cats.push([words[i]]); + } + function compareTo(arr) { + if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";"; + f += "switch(str){"; + for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":"; + f += "return true}return false;"; + } + + // When there are more than three length categories, an outer + // switch first dispatches on the lengths, to save on comparisons. + + if (cats.length > 3) { + cats.sort(function(a, b) {return b.length - a.length;}); + f += "switch(str.length){"; + for (var i = 0; i < cats.length; ++i) { + var cat = cats[i]; + f += "case " + cat[0].length + ":"; + compareTo(cat); + } + f += "}"; + + // Otherwise, simply generate a flat `switch` statement. + + } else { + compareTo(words); + } + return new Function("str", f); + } + + // The ECMAScript 3 reserved word list. + + var isReservedWord3 = makePredicate("abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile"); + + // ECMAScript 5 reserved words. + + var isReservedWord5 = makePredicate("class enum extends super const export import"); + + // The additional reserved words in strict mode. + + var isStrictReservedWord = makePredicate("implements interface let package private protected public static yield"); + + // The forbidden variable names in strict mode. + + var isStrictBadIdWord = makePredicate("eval arguments"); + + // And the keywords. + + var isKeyword = makePredicate("break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"); + + // ## Character categories + + // Big ugly regular expressions that match characters in the + // whitespace, identifier, and identifier-start categories. These + // are only applied when a character is found to actually have a + // code point above 128. + + var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/; + var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"; + var nonASCIIidentifierChars = "\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f"; + var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); + var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); + + // Whether a single character denotes a newline. + + var newline = /[\n\r\u2028\u2029]/; + + // Matches a whole line break (where CRLF is considered a single + // line break). Used to count lines. + + var lineBreak = /\r\n|[\n\r\u2028\u2029]/g; + + // Test whether a given character code starts an identifier. + + var isIdentifierStart = exports.isIdentifierStart = function(code) { + if (code < 65) return code === 36; + if (code < 91) return true; + if (code < 97) return code === 95; + if (code < 123)return true; + return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)); + }; + + // Test whether a given character is part of an identifier. + + var isIdentifierChar = exports.isIdentifierChar = function(code) { + if (code < 48) return code === 36; + if (code < 58) return true; + if (code < 65) return false; + if (code < 91) return true; + if (code < 97) return code === 95; + if (code < 123)return true; + return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)); + }; + + // ## Tokenizer + + // These are used when `options.locations` is on, for the + // `tokStartLoc` and `tokEndLoc` properties. + + function line_loc_t() { + this.line = tokCurLine; + this.column = tokPos - tokLineStart; + } + + // Reset the token state. Used at the start of a parse. + + function initTokenState() { + tokCurLine = 1; + tokPos = tokLineStart = 0; + tokRegexpAllowed = true; + skipSpace(); + } + + // Called at the end of every token. Sets `tokEnd`, `tokVal`, and + // `tokRegexpAllowed`, and skips the space after the token, so that + // the next one's `tokStart` will point at the right position. + + function finishToken(type, val) { + tokEnd = tokPos; + if (options.locations) tokEndLoc = new line_loc_t; + tokType = type; + skipSpace(); + tokVal = val; + tokRegexpAllowed = type.beforeExpr; + } + + function skipBlockComment() { + var startLoc = options.onComment && options.locations && new line_loc_t; + var start = tokPos, end = input.indexOf("*/", tokPos += 2); + if (end === -1) raise(tokPos - 2, "Unterminated comment"); + tokPos = end + 2; + if (options.locations) { + lineBreak.lastIndex = start; + var match; + while ((match = lineBreak.exec(input)) && match.index < tokPos) { + ++tokCurLine; + tokLineStart = match.index + match[0].length; + } + } + if (options.onComment) + options.onComment(true, input.slice(start + 2, end), start, tokPos, + startLoc, options.locations && new line_loc_t); + } + + function skipLineComment() { + var start = tokPos; + var startLoc = options.onComment && options.locations && new line_loc_t; + var ch = input.charCodeAt(tokPos+=2); + while (tokPos < inputLen && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { + ++tokPos; + ch = input.charCodeAt(tokPos); + } + if (options.onComment) + options.onComment(false, input.slice(start + 2, tokPos), start, tokPos, + startLoc, options.locations && new line_loc_t); + } + + // Called at the start of the parse and after every token. Skips + // whitespace and comments, and. + + function skipSpace() { + while (tokPos < inputLen) { + var ch = input.charCodeAt(tokPos); + if (ch === 32) { // ' ' + ++tokPos; + } else if (ch === 13) { + ++tokPos; + var next = input.charCodeAt(tokPos); + if (next === 10) { + ++tokPos; + } + if (options.locations) { + ++tokCurLine; + tokLineStart = tokPos; + } + } else if (ch === 10 || ch === 8232 || ch === 8233) { + ++tokPos; + if (options.locations) { + ++tokCurLine; + tokLineStart = tokPos; + } + } else if (ch > 8 && ch < 14) { + ++tokPos; + } else if (ch === 47) { // '/' + var next = input.charCodeAt(tokPos + 1); + if (next === 42) { // '*' + skipBlockComment(); + } else if (next === 47) { // '/' + skipLineComment(); + } else break; + } else if (ch === 160) { // '\xa0' + ++tokPos; + } else if (ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) { + ++tokPos; + } else { + break; + } + } + } + + // ### Token reading + + // This is the function that is called to fetch the next token. It + // is somewhat obscure, because it works in character codes rather + // than characters, and because operator parsing has been inlined + // into it. + // + // All in the name of speed. + // + // The `forceRegexp` parameter is used in the one case where the + // `tokRegexpAllowed` trick does not work. See `parseStatement`. + + function readToken_dot() { + var next = input.charCodeAt(tokPos + 1); + if (next >= 48 && next <= 57) return readNumber(true); + ++tokPos; + return finishToken(_dot); + } + + function readToken_slash() { // '/' + var next = input.charCodeAt(tokPos + 1); + if (tokRegexpAllowed) {++tokPos; return readRegexp();} + if (next === 61) return finishOp(_assign, 2); + return finishOp(_slash, 1); + } + + function readToken_mult_modulo() { // '%*' + var next = input.charCodeAt(tokPos + 1); + if (next === 61) return finishOp(_assign, 2); + return finishOp(_multiplyModulo, 1); + } + + function readToken_pipe_amp(code) { // '|&' + var next = input.charCodeAt(tokPos + 1); + if (next === code) return finishOp(code === 124 ? _logicalOR : _logicalAND, 2); + if (next === 61) return finishOp(_assign, 2); + return finishOp(code === 124 ? _bitwiseOR : _bitwiseAND, 1); + } + + function readToken_caret() { // '^' + var next = input.charCodeAt(tokPos + 1); + if (next === 61) return finishOp(_assign, 2); + return finishOp(_bitwiseXOR, 1); + } + + function readToken_plus_min(code) { // '+-' + var next = input.charCodeAt(tokPos + 1); + if (next === code) { + if (next == 45 && input.charCodeAt(tokPos + 2) == 62 && + newline.test(input.slice(lastEnd, tokPos))) { + // A `-->` line comment + tokPos += 3; + skipLineComment(); + skipSpace(); + return readToken(); + } + return finishOp(_incDec, 2); + } + if (next === 61) return finishOp(_assign, 2); + return finishOp(_plusMin, 1); + } + + function readToken_lt_gt(code) { // '<>' + var next = input.charCodeAt(tokPos + 1); + var size = 1; + if (next === code) { + size = code === 62 && input.charCodeAt(tokPos + 2) === 62 ? 3 : 2; + if (input.charCodeAt(tokPos + size) === 61) return finishOp(_assign, size + 1); + return finishOp(_bitShift, size); + } + if (next == 33 && code == 60 && input.charCodeAt(tokPos + 2) == 45 && + input.charCodeAt(tokPos + 3) == 45) { + // `
+ @@ -74,6 +82,7 @@ a { color: #00f; } + @@ -122,4 +131,3 @@ function init(){ -- \ No newline at end of file diff --git a/shader-picker.html b/shader-picker.html index 0896609..7efe39f 100644 --- a/shader-picker.html +++ b/shader-picker.html @@ -130,6 +130,12 @@ a { color: #00f; } + + + - -- cgit v1.2.3-70-g09d2 From dd7d18e344da5aa5b326621857d17993d01d7151 Mon Sep 17 00:00:00 2001 From: jules Date: Sun, 2 Feb 2014 01:08:41 -0500 Subject: toggle iframes, write short copy --- commands.html | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ instructions.html | 69 ------------------------------------------------------ js/help.js | 10 ++++---- shader-combo.html | 6 ++--- shader-picker.html | 12 +++++----- tutorial.html | 2 +- 6 files changed, 85 insertions(+), 83 deletions(-) create mode 100644 commands.html delete mode 100644 instructions.html (limited to 'shader-picker.html') diff --git a/commands.html b/commands.html new file mode 100644 index 0000000..df9b072 --- /dev/null +++ b/commands.html @@ -0,0 +1,69 @@ + + + +instructions + + + +
function parameters
+w, h, x, y
+t = current time (ms)
+d[] = imageData array
+r, g, b, a = color values
+mousex, mousey
+
+Math aliases
+floor, ceil, round
+abs, sign, mod(n,m)
+pow, exp, sqrt
+cos, sin, tan
+acos, asin, atan, atan2
+random()
+E, PI, PHI
+
+convenience functions
+clamp(n,min,max)
+mix(n,a,b) (lerp)
+step(a,b)
+smoothstep(min,max,n)
+avg(m,n,a)
+cosp, sinp (mapped to [0,1])
+pixel(x,y) == 4*(y*w+h)
+dist(x,y,a,b)
+angle(x,y,a,b)
+rand(n), randint(n)
+randrange(a,b)
+choice(array)
+deg(radians), rad(degrees)
+
+set pixel color
+rgb(r,g,b)
+rgbref([rgb])
+black() white() red()
+gray(n)
+
+color spaces
+rgb2xyz(rgb)
+xyz2rgb(xyz)
+xyz2hunterlab(xyz)
+hunterlab2xyz(Lab)
+xyz2cielab(xyz)
+cielab2xyz(Lab)
+rgb2hsl(rgb)
+hsl2rgb(hsl)
+rgb2cmy(r,g,b)
+cmy2rgb(cmy)
+cmy2cmyk(cmy)
+cmyk2cmy(cmyk)
+(not all have been tested)
+
+ + + diff --git a/instructions.html b/instructions.html deleted file mode 100644 index df9b072..0000000 --- a/instructions.html +++ /dev/null @@ -1,69 +0,0 @@ - - - -instructions - - - -
function parameters
-w, h, x, y
-t = current time (ms)
-d[] = imageData array
-r, g, b, a = color values
-mousex, mousey
-
-Math aliases
-floor, ceil, round
-abs, sign, mod(n,m)
-pow, exp, sqrt
-cos, sin, tan
-acos, asin, atan, atan2
-random()
-E, PI, PHI
-
-convenience functions
-clamp(n,min,max)
-mix(n,a,b) (lerp)
-step(a,b)
-smoothstep(min,max,n)
-avg(m,n,a)
-cosp, sinp (mapped to [0,1])
-pixel(x,y) == 4*(y*w+h)
-dist(x,y,a,b)
-angle(x,y,a,b)
-rand(n), randint(n)
-randrange(a,b)
-choice(array)
-deg(radians), rad(degrees)
-
-set pixel color
-rgb(r,g,b)
-rgbref([rgb])
-black() white() red()
-gray(n)
-
-color spaces
-rgb2xyz(rgb)
-xyz2rgb(xyz)
-xyz2hunterlab(xyz)
-hunterlab2xyz(Lab)
-xyz2cielab(xyz)
-cielab2xyz(Lab)
-rgb2hsl(rgb)
-hsl2rgb(hsl)
-rgb2cmy(r,g,b)
-cmy2rgb(cmy)
-cmy2cmyk(cmy)
-cmyk2cmy(cmyk)
-(not all have been tested)
-
- - - diff --git a/js/help.js b/js/help.js index 6f39aa7..7bc3a6b 100644 --- a/js/help.js +++ b/js/help.js @@ -7,13 +7,15 @@ help.init = function(){ help.bind = function(){ $(window).on("scroll DOMMouseScroll mousewheel", function(){ scrolling = true }) - $("#help").click(function(){ $("#instructions").toggle() ;console.log("zZ") }) - $("#instructions .close").click(function(){ $("#instructions").toggle() ;console.log("zZ") }) - $("#instructions").draggable({ + $("#show-commands").click(function(){ $("#tutorial").hide(); $("#commands").toggle() }) + $("#show-tutorial").click(function(){ $("#commands").hide(); $("#tutorial").toggle() }) + $("#commands .close").click(function(){ $("#commands").toggle() }) + $("#tutorial .close").click(function(){ $("#tutorial").toggle() }) + $("#commands,#tutorial").draggable({ start: drag_start, stop: drag_stop }) - $("#instructions").disableSelection(); + $("#commands,#tutorial").disableSelection(); } function drag_start(){ dragging = true; $(this).addClass("dragging") } diff --git a/shader-combo.html b/shader-combo.html index 99c5a6c..5d9c869 100644 --- a/shader-combo.html +++ b/shader-combo.html @@ -29,7 +29,7 @@ a { color: #00f; } .dragging { cursor: -webkit-grabbing !important; } .ui-sortable-helper { cursor: -webkit-grabbing !important; } -#instructions { top:20px;right:20px; width:190px;height:465px; } +#commands { top:40px;right:20px; width:190px;height:calc(95% - 230px); } #tutorial { top:40px;right:30px; width:290px;height:325px; display: block;} .iframe { position: absolute; box-shadow:5px 5px 10px rgba(0,0,0,0.3); background:rgba(255,255,255,0.8); display: none; cursor: -webkit-grab; } .iframe iframe {width: 100%;height:100%;margin:0;padding:0;border:0;} @@ -64,7 +64,7 @@ a { color: #00f; }

shaderblaster

- +

- +   @@ -103,7 +103,7 @@ a { color: #00f; }
-
+
diff --git a/tutorial.html b/tutorial.html index 84d4ca0..be42f74 100644 --- a/tutorial.html +++ b/tutorial.html @@ -18,7 +18,7 @@ Your basic variables are position (x, y), time (t), and color (r, g, b, a). Many math functions such as cos and sqrt are available, along with functions from GLSL like step and mix. Click commands to see a complete list. -Use the bar below to search Dumpfm and Photoblaster for images. +Use the bar below to search Dumpfm and Photoblaster for images, or use your own. If you make a cool effect, you can render it out to a gif, or save the shader for others to use. -- cgit v1.2.3-70-g09d2