bungee
Version:
Bungee is a declarative language engine to run inside a browser. The node module contains the offline compiler.
1,352 lines (1,172 loc) • 162 kB
JavaScript
;(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){
var Bungee = require('../../index.js');
var test = require('./test.jmp.js');
console.log('Bungee:', Bungee);
var engine = new Bungee.Engine(new Bungee.RendererDOM());
console.log('Engine:', engine);
var app = test(Bungee, engine);
console.log(app);
Bungee.jump(engine);
},{"../../index.js":2,"./test.jmp.js":3}],3:[function(require,module,exports){
if (!window.Bungee) {
window.Bungee = {};
}
window.Bungee.Modules.test = function () {
'use strict';
var e = {
children: [],
addChild: function(child) {
this[child.id] = child;
for (var i in this.children) {
if (this.children.hasOwnProperty(i)) {
this.children[i][child.id] = child;
child[this.children[i].id] = this.children[i];
}
}
e.children.push(child);
Bungee.Engine.addElement(child);
return child;
},
initializeBindings: function() {
for (var i = 0; i < e.children.length; ++i) { e.children[i].initializeBindings(); }
},
render: function() {
for (var i = 0; i < e.children.length; ++i) { e.children[i].render(); }
}
};
Bungee.List = function (id, parent) {
var e = new Bungee.Item(id, parent);
e.addProperty("width", function () {return this.childrenWidth;});
e.addProperty("height", function () {return this.childrenHeight;});
e.addProperty("spacing", function () {return 10;});
e.addProperty("layoutDirection", function () {return "vertical";});
e.addFunction("_layout", function () {
var kids = this.children();
var sibling = undefined;
for (var i in kids) {
if (kids.hasOwnProperty(i)) {
if (this.layoutDirection === "vertical") {
kids[i].top = sibling ? (this.spacing + sibling.top + sibling.height) : 0;
kids[i].left = 0;
} else {
kids[i].top = 0;
kids[i].left = sibling ? (this.spacing + sibling.left + sibling.width) : 0;
}
sibling = kids[i];
}
}
});
e.addFunction("_setupListeners", function () {
var kids = this.children();
var that = this;
this._layout();
for (var i in kids) {
if (kids.hasOwnProperty(i)) {
kids[i].addChanged('width', function () { that._layout() });
kids[i].addChanged('height', function () { that._layout() });
}
}
});
e.addEventHandler("onlayoutDirection", function () {
this._layout()
});
e.addEventHandler("onload", function () {
this._setupListeners()
});
return e;
};
Bungee.Button = function (id, parent) {
var e = new Bungee.InputItem(id, parent);
e.addProperty("label", function () {return "Demo";});
e.addProperty("src", function () {return "";});
e.addProperty("backgroundColor", function () {
if (this.mousePressed) {
return config.downBackgroundColor
} else if (this.containsMouse) {
return config.hightlightBackgroundColor
} else {
return config.normalBackgroundColor
}
});
e.addProperty("width", function () {return this.textLabel.textWidth + 100;});
e.addProperty("height", function () {return this.textLabel.textHeight + 10;});
e.addProperty("cursor", function () {return "default";});
e.addEventHandler("onmouseover", function () {
this.hoverAnimation.restart()
});
e.addEventHandler("onactivated", function () {
this.animation.restart();
window.document.getElementById("demoArea").src = this.src;
});
e.addChild((function() {
var e = new Bungee.Animation("animation");
e.addProperty("target", function () {return this.parent;});
e.addProperty("duration", function () {return 2000;});
e.addChild((function() {
var e = new Bungee.Step();
e.addProperty("percentage", function () {return 0;});
e.addProperty("width", function () {return this.parent.parent.width;});
return e;
})());
e.addChild((function() {
var e = new Bungee.Step();
e.addProperty("percentage", function () {return 50;});
e.addProperty("width", function () {return 0;});
return e;
})());
e.addChild((function() {
var e = new Bungee.Step();
e.addProperty("percentage", function () {return 70;});
e.addProperty("width", function () {return this.parent.parent.width * 1.5;});
return e;
})());
e.addChild((function() {
var e = new Bungee.Step();
e.addProperty("percentage", function () {return 100;});
e.addProperty("width", function () {return this.parent.parent.width;});
return e;
})());
return e;
})());
e.addChild((function() {
var e = new Bungee.Animation("hoverAnimation");
e.addProperty("target", function () {return this.parent;});
e.addProperty("duration", function () {return 1000;});
e.addChild((function() {
var e = new Bungee.Step();
e.addProperty("percentage", function () {return 0;});
e.addProperty("background-color", function () {return config.hightlightBackgroundColor;});
return e;
})());
e.addChild((function() {
var e = new Bungee.Step();
e.addProperty("percentage", function () {return 25;});
e.addProperty("background-color", function () {return "pink";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Step();
e.addProperty("percentage", function () {return 50;});
e.addProperty("background-color", function () {return "silver";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Step();
e.addProperty("percentage", function () {return 75;});
e.addProperty("background-color", function () {return "cyan";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Step();
e.addProperty("percentage", function () {return 100;});
e.addProperty("width", function () {return config.hightlightBackgroundColor;});
return e;
})());
return e;
})());
e.addChild((function() {
var e = new Bungee.Text("textLabel");
e.addProperty("fontSize", function () {return "24px";});
e.addProperty("text", function () {return this.parent.label;});
e.addProperty("left", function () {return this.parent.width / 2 - this.width / 2;});
e.addProperty("top", function () {return this.parent.height / 2 - this.height / 2;});
e.addProperty("color", function () {return config.normalTextColor;});
return e;
})());
return e;
};
e.addChild((function() {
var e = new Bungee.Window();
e.addProperty("top", function () {return 0;});
e.addProperty("left", function () {return 0;});
e.addProperty("width", function () {return 300;});
e.addChild((function() {
var e = new Bungee.List();
e.addChild((function() {
var e = new Bungee.Button();
e.addProperty("label", function () {return "Model Updates";});
e.addProperty("src", function () {return "model.html";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Button();
e.addProperty("label", function () {return "Pin Entry";});
e.addProperty("src", function () {return "pin.html";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Button();
e.addProperty("label", function () {return "Animation";});
e.addProperty("src", function () {return "animation.html";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Button();
e.addProperty("label", function () {return "Bounding Rect";});
e.addProperty("src", function () {return "boundingrect.html";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Button();
e.addProperty("label", function () {return "Delegates";});
e.addProperty("src", function () {return "delegate.html";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Button();
e.addProperty("label", function () {return "Widgets";});
e.addProperty("src", function () {return "widgets.html";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Button();
e.addProperty("label", function () {return "Tracking";});
e.addProperty("src", function () {return "tracking.html";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Button();
e.addProperty("label", function () {return "Path";});
e.addProperty("src", function () {return "path.html";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Button();
e.addProperty("label", function () {return "Scaling";});
e.addProperty("src", function () {return "scale.html";});
return e;
})());
e.addChild((function() {
var e = new Bungee.Button();
e.addProperty("label", function () {return "Dragging";});
e.addProperty("src", function () {return "drag.html";});
return e;
})());
return e;
})());
return e;
})());
e.initializeBindings();
e.render();
return e;
};
},{}],2:[function(require,module,exports){
/*
**************************************************
* Bungee.js
*
* (c) 2012-2013 Johannes Zellner
*
* Bungee may be freely distributed under the MIT license.
* For all details and documentation:
* http://bungeejs.org
**************************************************
*/
"use strict";
var fs = require('fs');
module.exports = (function () {
var ret = {};
ret.tokenizer = require('./src/tokenizer.js');
ret.compiler = require('./src/compiler.js');
ret.compileFile = function(file, options, callback) {
fs.readFile(file, 'utf8', function (error, data) {
if (error) {
callback(error);
} else {
ret.compile(data, options, callback);
}
});
};
ret.compile = function(source, options, callback) {
var tokens = ret.tokenizer.parse(source);
// console.log("$$$$", tokens);
ret.compiler.compileAndRender(tokens, options, function (error, result) {
callback(error, result);
});
};
return ret;
}());
},{"fs":4,"./src/tokenizer.js":5,"./src/compiler.js":6}],4:[function(require,module,exports){
// nothing to see here... no file methods for the browser
},{}],6:[function(require,module,exports){
(function(){/*
**************************************************
* Bungee.js
*
* (c) 2012-2013 Johannes Zellner
*
* Bungee may be freely distributed under the MIT license.
* For all details and documentation:
* http://bungeejs.org
**************************************************
*/
"use strict";
/*
**************************************************
* Compiler
**************************************************
*/
if (!Bungee) {
var Bungee = {};
}
var compiler = (function () {
// public compiler properties
var compiler = {};
// TODO sort out this kindof global variable mess
var ELEM_PREFIX = "e"; // just a define
var ELEM_NS = "Bungee."; // main namespace
var output; // output buffer used by all render functions
var index; // index used for tracking the indentation
var errorCodes = {
GENERIC: 0,
UNKNOWN_ELEMENT: 1,
NO_PROPERTY: 2,
NO_ELEMENTTYPE: 3,
NO_TYPENAME: 4,
NO_EXPRESSION: 5,
NO_COLON: 6,
INVALID_PROPERTY_NAME: 7,
UNEXPECTED_END: 8
};
// make error codes public
compiler.errorCodes = errorCodes;
var errorMessages = [];
errorMessages[errorCodes.GENERIC] = "generic error";
errorMessages[errorCodes.UNKNOWN_ELEMENT] = "Cannot create element.";
errorMessages[errorCodes.NO_PROPERTY] = "No property to assing expression.";
errorMessages[errorCodes.NO_ELEMENTTYPE] = "No type to create an element.";
errorMessages[errorCodes.NO_TYPENAME] = "No typename for the new type definition.";
errorMessages[errorCodes.NO_COLON] = "Property must be followed by a ':'.";
errorMessages[errorCodes.NO_EXPRESSION] = "No right-hand-side expression or element found.";
errorMessages[errorCodes.INVALID_PROPERTY_NAME] = "Invalid property name found.";
errorMessages[errorCodes.UNEXPECTED_END] = "Unexpected end of input.";
function error(code, token) {
var ret = {};
ret.code = code;
ret.context = token ? token.CONTEXT : undefined;
ret.message = errorMessages[code];
ret.line = token ? token.LINE : -1;
return ret;
}
function log(msg) {
if (Bungee.verbose) {
console.log(msg);
}
}
function isNumeric (c) {
return (c >= '0' && c <= '9');
}
/*
* adds current indentation to compiler output
*/
function addIndentation(additional) {
var indentLevel = index + (additional ? additional : 0);
var i;
for (i = indentLevel; i; --i) {
output += " ";
}
}
/*
* Renders the head of the javascript output
* Only called once
*/
function renderBegin(options) {
if (Bungee.debug) {
addIndentation(1);
output += "debugger;\n";
}
output += "if (!window.Bungee) {\n";
output += " window.Bungee = {};\n";
output += "}\n\n";
if (options.module) {
output += "window.Bungee.Modules." + options.module + " = function () {\n";
} else {
output += "(function() {\n";
}
addIndentation();
output += "'use strict';\n\n";
// add pseudo parent
addIndentation();
output += "var " + ELEM_PREFIX + " = { \n";
addIndentation(1);
output += "children: [],\n";
addIndentation(1);
output += "addChild: function(child) {\n";
addIndentation(2);
output += "this[child.id] = child;\n";
addIndentation(2);
output += "for (var i in this.children) {\n";
addIndentation(2);
output += " if (this.children.hasOwnProperty(i)) {\n";
addIndentation(2);
output += " this.children[i][child.id] = child;\n";
addIndentation(2);
output += " child[this.children[i].id] = this.children[i];\n";
addIndentation(2);
output += " }\n";
addIndentation(2);
output += "}\n";
addIndentation(2);
output += ELEM_PREFIX + ".children.push(child);\n";
addIndentation(2);
output += "Bungee.Engine.addElement(child);\n";
addIndentation(2);
output += "return child;\n";
addIndentation(1);
output += "},\n";
addIndentation(1);
output += "initializeBindings: function() {\n";
addIndentation(2);
output += "for (var i = 0; i < " + ELEM_PREFIX + ".children.length; ++i) { " + ELEM_PREFIX + ".children[i].initializeBindings(); }\n";
addIndentation(1);
output += "},\n";
addIndentation(1);
output += "render: function() {\n";
addIndentation(2);
output += "for (var i = 0; i < " + ELEM_PREFIX + ".children.length; ++i) { " + ELEM_PREFIX + ".children[i].render(); }\n";
addIndentation(1);
output += "}\n";
addIndentation();
output += "};\n\n";
}
/*
* Render the end of the javascript output
* Only called once
*/
function renderEnd(options) {
addIndentation();
output += ELEM_PREFIX + ".initializeBindings();\n";
addIndentation();
output += ELEM_PREFIX + ".render();\n";
if (options.module) {
addIndentation();
output += "return " + ELEM_PREFIX + ";\n";
output += "};\n";
} else {
output += "})();\n";
}
}
/*
* Renders the start of a new Element instance
* Called for each element instantiation in jump
*/
function renderBeginElement(type, id) {
addIndentation();
output += ELEM_PREFIX + ".addChild((function() {\n";
++index;
addIndentation();
output += "var " + ELEM_PREFIX + " = new " + ELEM_NS + type + "(";
output += id ? "\"" + id + "\"" : "";
output += ");\n";
}
/*
* Renders the end of a new Element instance
* Called for each element instantiation in jump
*/
function renderEndElement() {
addIndentation();
output += "return " + ELEM_PREFIX + ";\n";
--index;
addIndentation();
output += "})());\n";
}
/*
* Renders the start of a new Type definition
* Called for each type in jump
*/
function renderBeginType(type, inheritedType) {
addIndentation();
output += ELEM_NS + type + " = function (id, parent) {\n";
++index;
addIndentation();
output += "var " + ELEM_PREFIX + " = new " + ELEM_NS + inheritedType + "(id, parent);\n";
}
/*
* Renders the end of a new Type definition
* Called for each type in jump
*/
function renderEndType() {
addIndentation();
output += "return " + ELEM_PREFIX + ";\n";
--index;
addIndentation();
output += "};\n";
}
/*
* Renders an event handler for the current element/type in scope
* Event handlers will be generated whenever a property name
* begins with 'on' like 'onmousedown'
*/
function renderEventHandler(property, value) {
addIndentation();
output += ELEM_PREFIX + ".addEventHandler(\"" + property + "\", ";
output += "function () {\n";
addIndentation();
output += value + "\n";
addIndentation();
output += "});\n";
}
/*
* Renders a function for the current element/type in scope
* Functions will be generated whenever a property name
* contains a '(', a preceeding 'function ' is not necessary
* and will be stripped
*/
function renderFunction(property, value) {
var name = property.slice(property.indexOf(' ') + 1, property.indexOf('('));
var args = property.slice(property.indexOf('(') + 1, -1);
addIndentation();
output += ELEM_PREFIX + ".addFunction(\"" + name + "\", ";
output += "function (" + args + ") {\n";
addIndentation();
output += value + "\n";
addIndentation();
output += "});\n";
}
/*
* Renders a property for the current element/type in scope
*/
function renderProperty(property, value) {
// special case for ID
if (property === "id") {
return;
}
if (property.indexOf('on') === 0) {
renderEventHandler(property, value);
return;
}
if (property.indexOf('(') !== -1) {
renderFunction(property, value);
return;
}
addIndentation();
output += ELEM_PREFIX + ".addProperty(\"" + property + "\", ";
output += "function () {";
if (String(value).indexOf("return") !== -1) {
output += value + " ";
} else {
output += "return " + value + ";";
}
output += "});\n";
}
/*
* Renders a delegate for the current element/type in scope
*/
function renderDelegate(property, value) {
addIndentation();
output += ELEM_PREFIX + ".create" + property + " = function () {\n";
addIndentation(1);
output += "return new " + ELEM_NS + value + "();\n";
addIndentation();
output += "}\n";
}
/*
* Takes a TreeObject, containing either a Type or an Element
* and runs over the object's properties, types and children
* this is called recoursively
*/
function renderTreeObject(tree) {
var i;
if (tree.typeDefinition) {
renderBeginType(tree.typeDefinition, tree.type);
} else {
renderBeginElement(tree.type, tree.id);
}
for (i = 0; i < tree.properties.length; ++i) {
renderProperty(tree.properties[i].name, tree.properties[i].value);
}
for (i = 0; i < tree.delegates.length; ++i) {
renderDelegate(tree.delegates[i].name, tree.delegates[i].value);
}
for (i = 0; i < tree.types.length; ++i) {
renderTreeObject(tree.types[i]);
}
for (i = 0; i < tree.elements.length; ++i) {
renderTreeObject(tree.elements[i]);
}
if (tree.typeDefinition) {
renderEndType();
} else {
renderEndElement();
}
}
/*
* Starting point of the renderer
* Takes a TreeObject tree to render
* The first tree object is root and needs special treatment
*/
compiler.renderTree = function (tree, options, callback) {
var i;
index = 1;
output = "";
renderBegin(options);
for (i = 0; i < tree.types.length; ++i) {
renderTreeObject(tree.types[i]);
}
for (i = 0; i < tree.elements.length; ++i) {
renderTreeObject(tree.elements[i]);
}
renderEnd(options);
callback(null, output);
};
/*
* Dump out the current object tree to the console
*/
function dumpObjectTree(tree, indent) {
var i;
if (indent === undefined) {
indent = 0;
}
function niceLog(msg) {
var j;
var out = "";
for (j = 0; j < indent; ++j) {
out += " ";
}
console.log(out + msg);
}
niceLog("+ Element:");
niceLog("|- type: " + tree.type);
niceLog("|- type definition: " + tree.typeDefinition);
niceLog("|+ Properties:");
for (i = 0; i < tree.properties.length; ++i) {
niceLog("|--> " + tree.properties[i].name);
}
niceLog("|+ Delegates:");
for (i = 0; i < tree.delegates.length; ++i) {
niceLog("|--> " + tree.delegates[i].name + " : " + tree.delegates[i].value);
}
if (tree.types.length) {
niceLog("|+ Types:");
for (i = 0; i < tree.types.length; ++i) {
dumpObjectTree(tree.types[i], indent + 2);
}
}
if (tree.elements.length) {
niceLog("|+ Elements: ");
for (i = 0; i < tree.elements.length; ++i) {
dumpObjectTree(tree.elements[i], indent + 2);
}
}
}
/*
* Take all tokens and compile it to a object tree, which can be rendered
*/
compiler.createObjectTree = function (tok, options, callback) {
var property;
var tokens = tok;
var token_length = tokens.length;
var elementType;
var elementTypeDefinition;
var i, j;
// TreeObject is a helper to pass information to the renderer
var TreeObject = function (parent) {
this.id = undefined;
this.type = undefined;
this.typeDefinition = undefined;
this.parent = parent;
this.types = [];
this.elements = [];
this.properties = [];
this.delegates = [];
};
var objectTreeRoot = new TreeObject();
objectTreeRoot.type = "RootObject";
var objectTree = objectTreeRoot;
for (i = 0; i < token_length; i += 1) {
var token = tokens[i];
if (token.TOKEN === "IS_A") {
if (elementType) {
elementTypeDefinition = elementType;
elementType = undefined;
} else {
callback(error(errorCodes.NO_TYPENAME, token), null);
return;
}
}
if (token.TOKEN === "ELEMENT") {
elementType = token.DATA;
}
if (token.TOKEN === "SCOPE_START") {
log("start element description");
// only if elementType was found previously
if (elementType) {
// we found a element definition, so add one to create an element instance
var tmp = new TreeObject(objectTree);
tmp.type = elementType;
// check if we have a type definition or an element
if (elementTypeDefinition) {
tmp.typeDefinition = elementTypeDefinition;
objectTree.types.push(tmp);
} else {
objectTree.elements.push(tmp);
}
objectTree = tmp;
elementType = undefined;
elementTypeDefinition = undefined;
} else {
callback(error(errorCodes.NO_ELEMENTTYPE, token), null);
}
}
if (token.TOKEN === "SCOPE_END") {
log("end element description");
// scope end, so reset the objectTree pointer
objectTree = objectTree.parent;
}
if (token.TOKEN === "EXPRESSION") {
// next token must be COLON
var next_token = (i + 1 < token_length) ? tokens[i + 1] : undefined;
if (next_token && next_token.TOKEN === "COLON") {
property = token.DATA;
log("property found '" + property + "'");
// check for valid property names
if (isNumeric(property[0])) {
log("property name '" + property + "' is invalid.");
callback(error(errorCodes.INVALID_PROPERTY_NAME, token), null);
return;
}
i += 1;
next_token = undefined;
} else {
callback(error(errorCodes.NO_COLON, token), null);
return;
}
// next token must be EXPRESSION or ELEMENT
next_token = (i + 1 < token_length) ? tokens[i + 1] : undefined;
if (next_token && next_token.TOKEN === "EXPRESSION") {
log("right-hand-side expression found for property '" + property + "' '" + next_token.DATA + "'");
// special treatment for element IDs they are no real properties
if (property === "id") {
objectTree.id = next_token.DATA;
} else {
objectTree.properties.push({name: property, value: next_token.DATA});
}
i += 1;
property = undefined;
} else if (next_token && next_token.TOKEN === "ELEMENT") {
log("right-hand-side element found for property", property, next_token.DATA);
objectTree.delegates.push({name: property, value: next_token.DATA});
i += 1;
property = undefined;
} else {
callback(error(errorCodes.NO_EXPRESSION, next_token), null);
return;
}
}
}
if (objectTree !== objectTreeRoot) {
callback(error(errorCodes.UNEXPECTED_END, null), null);
return;
}
callback(null, objectTreeRoot);
};
/*
* Take all tokens, compile it to a object tree and render it
* options:
* - 'dump' dump object tree
*/
compiler.compileAndRender = function (tok, options, callback) {
compiler.createObjectTree(tok, options, function (error, result) {
if (error) {
callback(error, null);
return;
}
if (options.dump) {
dumpObjectTree(result);
}
compiler.renderTree(result, options, callback);
});
};
return compiler;
}());
// TODO is this the proper check?
if (typeof window === 'undefined') {
module.exports = compiler;
} else {
window.Bungee.Compiler = compiler;
}
})()
},{}],5:[function(require,module,exports){
/*
**************************************************
* Bungee.js
*
* (c) 2012-2013 Johannes Zellner
*
* Bungee may be freely distributed under the MIT license.
* For all details and documentation:
* http://bungeejs.org
**************************************************
*/
"use strict";
/*
**************************************************
* Tokenizer
**************************************************
*/
if (!Bungee) {
var Bungee = {};
}
var tokenizer = (function () {
var c, i, line, tokens, bindings, exp, colonOnLine, comment, lineContext;
var ret = {};
function log (msg) {
if (Bungee.verbose) {
console.log(msg);
}
}
// add a found token to the token table
function addToken (type, data) {
tokens.push( {"TOKEN" : type, "DATA" : data, "LINE" : line, "CONTEXT" : lineContext} );
}
// extract an element name
function parseElementName () {
var token = "";
while (c) {
if (c === '\n') {
i -= 1;
break;
}
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c === '_' || c === '-')
token += c;
else
break;
advance();
}
// strip trailing ';'
if (token[token.length-1] === ';') {
token = token.substring(0, token.length-1);
}
return token;
}
// extract an expression, can be a property definition, function or right side expression after :
function parseExpression () {
var expression = "";
while (c) {
if (c === '\n') {
i -= 1;
break;
}
// only break if this is the first colon in that line
if (!colonOnLine && c === ':') {
i -= 1;
break;
}
// ignore whitespace
// if ((c !== '\t' && c !== ' ') || expression === "function")
expression += c;
advance();
}
// strip trailing ';'
if (expression[expression.length-1] === ';') {
expression = expression.substring(0, expression.length-1);
}
return expression;
}
function parseInlineBlock () {
var block = '';
var script;
while (c) {
block += c;
if (c === '}') {
try {
script = Bungee.esprima.parse(block, { tolerant: true});
break;
} catch (e) {
// block statement parsing failed, force esprima to check for object notation
var tmp = "var a = " + block;
try {
script = Bungee.esprima.parse(tmp, { tolerant: true});
break;
} catch (e) {
}
}
}
if (c === '\n') {
++line;
}
advance();
}
// if we have a block statement, this means we need to trim the
// prepending and trailing curly brackets
if (script && script.body && script.body[0] && script.body[0].type === "BlockStatement") {
// TODO this looks a bit messy and error prone
block = block.trim();
if (block[0] === '{') {
block = block.slice(1);
}
if (block[block.length-1] === '}') {
block = block.slice(0, block.length-1);
}
}
return block;
}
// Convenience function to advance the current tokenizer character
function advance () {
c = exp[++i];
return (c);
}
/*
* Parse the input string and create tokens
*/
ret.parse = function (input) {
exp = input;
i = -1;
line = 1;
lineContext = "";
tokens = [];
c = undefined;//exp[i];
bindings = [];
colonOnLine = false;
comment = false;
while (advance()) {
if (comment && c !== '\n')
continue;
// check for one line comments
if (c === '/' && exp[i+1] === '/') {
comment = true;
continue;
}
if (c === '\n') {
comment = false;
colonOnLine = false;
++line;
lineContext = "";
// add next line so we have a error context to print
var j = i;
var tmpChar = exp[++j];
while(tmpChar) {
if (tmpChar === '\n') {
break;
}
lineContext += tmpChar;
tmpChar = exp[++j];
}
continue;
}
// check for element name
if (c >= 'A' && c <= 'Z') {
addToken("ELEMENT", parseElementName());
continue;
}
if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c === '"' || c === '\'' || c === '(' || c === '-' || c === '_' || c === '[') {
addToken("EXPRESSION", parseExpression());
continue;
}
if (c === '{' && tokens[tokens.length-1].TOKEN === "ELEMENT") {
addToken("SCOPE_START");
continue;
}
if (c === '{') {
addToken("EXPRESSION", parseInlineBlock());
continue;
}
if (c === '}') {
addToken("SCOPE_END");
continue;
}
if (c === ':') {
colonOnLine = true;
addToken("COLON");
continue;
}
if (c === '@') {
addToken("IS_A");
continue;
}
if (c === ';') {
colonOnLine = false;
addToken("SEMICOLON");
continue;
}
}
if (Bungee.verbose) {
ret.dumpTokens();
}
return tokens;
};
/*
* Print all found tokens on the console
*/
ret.dumpTokens = function () {
for (var i = 0; i < tokens.length; ++i)
console.log("TOKEN: " + tokens[i].TOKEN + " " + (tokens[i].DATA ? tokens[i].DATA : ""));
};
return ret;
}());
// TODO is this the proper check?
if (typeof window === 'undefined') {
Bungee.esprima = require("esprima");
module.exports = tokenizer;
} else {
window.Bungee.Tokenizer = tokenizer;
}
},{"esprima":7}],7:[function(require,module,exports){
(function(){/*
Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*jslint bitwise:true plusplus:true */
/*global esprima:true, define:true, exports:true, window: true,
throwError: true, createLiteral: true, generateStatement: true,
parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
parseFunctionDeclaration: true, parseFunctionExpression: true,
parseFunctionSourceElements: true, parseVariableIdentifier: true,
parseLeftHandSideExpression: true,
parseStatement: true, parseSourceElement: true */
(function (root, factory) {
'use strict';
// Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
// Rhino, and plain browser loading.
if (typeof define === 'function' && define.amd) {
define(['exports'], factory);
} else if (typeof exports !== 'undefined') {
factory(exports);
} else {
factory((root.esprima = {}));
}
}(this, function (exports) {
'use strict';
var Token,
TokenName,
Syntax,
PropertyKind,
Messages,
Regex,
source,
strict,
index,
lineNumber,
lineStart,
length,
buffer,
state,
extra;
Token = {
BooleanLiteral: 1,
EOF: 2,
Identifier: 3,
Keyword: 4,
NullLiteral: 5,
NumericLiteral: 6,
Punctuator: 7,
StringLiteral: 8
};
TokenName = {};
TokenName[Token.BooleanLiteral] = 'Boolean';
TokenName[Token.EOF] = '<end>';
TokenName[Token.Identifier] = 'Identifier';
TokenName[Token.Keyword] = 'Keyword';
TokenName[Token.NullLiteral] = 'Null';
TokenName[Token.NumericLiteral] = 'Numeric';
TokenName[Token.Punctuator] = 'Punctuator';
TokenName[Token.StringLiteral] = 'String';
Syntax = {
AssignmentExpression: 'AssignmentExpression',
ArrayExpression: 'ArrayExpression',
BlockStatement: 'BlockStatement',
BinaryExpression: 'BinaryExpression',
BreakStatement: 'BreakStatement',
CallExpression: 'CallExpression',
CatchClause: 'CatchClause',
ConditionalExpression: 'ConditionalExpression',
ContinueStatement: 'ContinueStatement',
DoWhileStatement: 'DoWhileStatement',
DebuggerStatement: 'DebuggerStatement',
EmptyStatement: 'EmptyStatement',
ExpressionStatement: 'ExpressionStatement',
ForStatement: 'ForStatement',
ForInStatement: 'ForInStatement',
FunctionDeclaration: 'FunctionDeclaration',
FunctionExpression: 'FunctionExpression',
Identifier: 'Identifier',
IfStatement: 'IfStatement',
Literal: 'Literal',
LabeledStatement: 'LabeledStatement',
LogicalExpression: 'LogicalExpression',
MemberExpression: 'MemberExpression',
NewExpression: 'NewExpression',
ObjectExpression: 'ObjectExpression',
Program: 'Program',
Property: 'Property',
ReturnStatement: 'ReturnStatement',
SequenceExpression: 'SequenceExpression',
SwitchStatement: 'SwitchStatement',
SwitchCase: 'SwitchCase',
ThisExpression: 'ThisExpression',
ThrowStatement: 'ThrowStatement',
TryStatement: 'TryStatement',
UnaryExpression: 'UnaryExpression',
UpdateExpression: 'UpdateExpression',
VariableDeclaration: 'VariableDeclaration',
VariableDeclarator: 'VariableDeclarator',
WhileStatement: 'WhileStatement',
WithStatement: 'WithStatement'
};
PropertyKind = {
Data: 1,
Get: 2,
Set: 4
};
// Error messages should be identical to V8.
Messages = {
UnexpectedToken: 'Unexpected token %0',
UnexpectedNumber: 'Unexpected number',
UnexpectedString: 'Unexpected string',
UnexpectedIdentifier: 'Unexpected identifier',
UnexpectedReserved: 'Unexpected reserved word',
UnexpectedEOS: 'Unexpected end of input',
NewlineAfterThrow: 'Illegal newline after throw',
InvalidRegExp: 'Invalid regular expression',
UnterminatedRegExp: 'Invalid regular expression: missing /',
InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
InvalidLHSInForIn: 'Invalid left-hand side in for-in',
MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
NoCatchOrFinally: 'Missing catch or finally after try',
UnknownLabel: 'Undefined label \'%0\'',
Redeclaration: '%0 \'%1\' has already been declared',
IllegalContinue: 'Illegal continue statement',
IllegalBreak: 'Illegal break statement',
IllegalReturn: 'Illegal return statement',
StrictModeWith: 'Strict mode code may not include a with statement',
StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
StrictVarName: 'Variable name may not be eval or arguments in strict mode',
StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
StrictDelete: 'Delete of an unqualified identifier in strict mode.',
StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
StrictReservedWord: 'Use of future reserved word in strict mode'
};
// See also tools/generate-unicode-regex.py.
Regex = {
NonAsciiIdentifierStart: new RegExp('[\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]'),
NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\