From 5016cc3305a1f91a2b70b827937521d0bbbb0123 Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 1 Sep 2012 23:06:05 +0400 Subject: [PATCH] use only jshint in javascript worker --- lib/ace/mode/javascript.js | 20 +- lib/ace/{worker => mode/javascript}/jshint.js | 0 lib/ace/mode/javascript_worker.js | 155 +- lib/ace/narcissus/definitions.js | 683 -- lib/ace/narcissus/lexer.js | 584 -- lib/ace/narcissus/options.js | 48 - lib/ace/narcissus/parser.js | 2057 ------ lib/ace/worker/jslint.js | 6396 ----------------- 8 files changed, 126 insertions(+), 9817 deletions(-) rename lib/ace/{worker => mode/javascript}/jshint.js (100%) delete mode 100644 lib/ace/narcissus/definitions.js delete mode 100644 lib/ace/narcissus/lexer.js delete mode 100644 lib/ace/narcissus/options.js delete mode 100644 lib/ace/narcissus/parser.js delete mode 100644 lib/ace/worker/jslint.js diff --git a/lib/ace/mode/javascript.js b/lib/ace/mode/javascript.js index c40200e0..3b1460a8 100644 --- a/lib/ace/mode/javascript.js +++ b/lib/ace/mode/javascript.js @@ -123,25 +123,9 @@ oop.inherits(Mode, TextMode); this.createWorker = function(session) { var worker = new WorkerClient(["ace"], "ace/mode/javascript_worker", "JavaScriptWorker"); worker.attachToDocument(session.getDocument()); - + worker.on("jslint", function(results) { - var errors = []; - for (var i=0; i=", ">", - "<<", ">>", ">>>", - "+", "-", - "*", "/", "%", - "!", "~", "UNARY_PLUS", "UNARY_MINUS", - "++", "--", - ".", - "[", "]", - "{", "}", - "(", ")", - - // Nonterminal tree node type codes. - "SCRIPT", "BLOCK", "LABEL", "FOR_IN", "CALL", "NEW_WITH_ARGS", "INDEX", - "ARRAY_INIT", "OBJECT_INIT", "PROPERTY_INIT", "GETTER", "SETTER", - "GROUP", "LIST", "LET_BLOCK", "ARRAY_COMP", "GENERATOR", "COMP_TAIL", - - // Contextual keywords. - "IMPLEMENTS", "INTERFACE", "LET", "MODULE", "PACKAGE", "PRIVATE", - "PROTECTED", "PUBLIC", "STATIC", "USE", "YIELD", - - // Terminals. - "IDENTIFIER", "NUMBER", "STRING", "REGEXP", - - // Keywords. - "break", - "case", "catch", "const", "continue", - "debugger", "default", "delete", "do", - "else", "export", - "false", "finally", "for", "function", - "if", "import", "in", "instanceof", - "new", "null", - "return", - "switch", - "this", "throw", "true", "try", "typeof", - "var", "void", - "while", "with", -]; - -var strictKeywords = { - __proto__: null, - "implements": true, - "interface": true, - "let": true, - //"module": true, - "package": true, - "private": true, - "protected": true, - "public": true, - "static": true, - "use": true, - "yield": true -}; - -var statementStartTokens = [ - "break", - "const", "continue", - "debugger", "do", - "for", - "if", - "let", - "return", - "switch", - "throw", "try", - "var", - "yield", - "while", "with", -]; - -// Whitespace characters (see ECMA-262 7.2) -var whitespaceChars = [ - // normal whitespace: - "\u0009", "\u000B", "\u000C", "\u0020", "\u00A0", "\uFEFF", - - // high-Unicode whitespace: - "\u1680", "\u180E", - "\u2000", "\u2001", "\u2002", "\u2003", "\u2004", "\u2005", "\u2006", - "\u2007", "\u2008", "\u2009", "\u200A", - "\u202F", "\u205F", "\u3000" -]; - -var whitespace = {}; -for (var i = 0; i < whitespaceChars.length; i++) { - whitespace[whitespaceChars[i]] = true; -} - -// Operator and punctuator mapping from token to tree node type name. -// NB: because the lexer doesn't backtrack, all token prefixes must themselves -// be valid tokens (e.g. !== is acceptable because its prefixes are the valid -// tokens != and !). -var opTypeNames = { - '\n': "NEWLINE", - ';': "SEMICOLON", - ',': "COMMA", - '?': "HOOK", - ':': "COLON", - '||': "OR", - '&&': "AND", - '|': "BITWISE_OR", - '^': "BITWISE_XOR", - '&': "BITWISE_AND", - '===': "STRICT_EQ", - '==': "EQ", - '=': "ASSIGN", - '!==': "STRICT_NE", - '!=': "NE", - '<<': "LSH", - '<=': "LE", - '<': "LT", - '>>>': "URSH", - '>>': "RSH", - '>=': "GE", - '>': "GT", - '++': "INCREMENT", - '--': "DECREMENT", - '+': "PLUS", - '-': "MINUS", - '*': "MUL", - '/': "DIV", - '%': "MOD", - '!': "NOT", - '~': "BITWISE_NOT", - '.': "DOT", - '[': "LEFT_BRACKET", - ']': "RIGHT_BRACKET", - '{': "LEFT_CURLY", - '}': "RIGHT_CURLY", - '(': "LEFT_PAREN", - ')': "RIGHT_PAREN" -}; - -// Hash of keyword identifier to tokens index. NB: we must null __proto__ to -// avoid toString, etc. namespace pollution. -var keywords = {__proto__: null}; -var mozillaKeywords = {__proto__: null}; - -// Define const END, etc., based on the token names. Also map name to index. -var tokenIds = {}; - -var hostSupportsEvalConst = (function() { - try { - return eval("(function(s) { eval(s); return x })('const x = true;')"); - } catch (e) { - return false; - } -})(); - -// Building up a string to be eval'd in different contexts. -var consts = hostSupportsEvalConst ? "const " : "var "; -for (var i = 0, j = tokens.length; i < j; i++) { - if (i > 0) - consts += ", "; - var t = tokens[i]; - var name; - if (/^[a-z]/.test(t)) { - name = t.toUpperCase(); - if (name === "LET" || name === "YIELD") - mozillaKeywords[name] = i; - if (strictKeywords[name]) - strictKeywords[name] = i; - keywords[t] = i; - } else { - name = (/^\W/.test(t) ? opTypeNames[t] : t); - } - consts += name + " = " + i; - tokenIds[name] = i; - tokens[t] = i; -} -consts += ";"; - -var isStatementStartCode = {__proto__: null}; -for (i = 0, j = statementStartTokens.length; i < j; i++) - isStatementStartCode[keywords[statementStartTokens[i]]] = true; - -// Map assignment operators to their indexes in the tokens array. -var assignOps = ['|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%']; - -for (i = 0, j = assignOps.length; i < j; i++) { - t = assignOps[i]; - assignOps[t] = tokens[t]; -} - -function defineGetter(obj, prop, fn, dontDelete, dontEnum) { - Object.defineProperty(obj, prop, - { get: fn, configurable: !dontDelete, enumerable: !dontEnum }); -} - -function defineGetterSetter(obj, prop, getter, setter, dontDelete, dontEnum) { - Object.defineProperty(obj, prop, { - get: getter, - set: setter, - configurable: !dontDelete, - enumerable: !dontEnum - }); -} - -function defineMemoGetter(obj, prop, fn, dontDelete, dontEnum) { - Object.defineProperty(obj, prop, { - get: function() { - var val = fn(); - defineProperty(obj, prop, val, dontDelete, true, dontEnum); - return val; - }, - configurable: true, - enumerable: !dontEnum - }); -} - -function defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) { - Object.defineProperty(obj, prop, - { value: val, writable: !readOnly, configurable: !dontDelete, - enumerable: !dontEnum }); -} - -// Returns true if fn is a native function. (Note: SpiderMonkey specific.) -function isNativeCode(fn) { - // Relies on the toString method to identify native code. - return ((typeof fn) === "function") && fn.toString().match(/\[native code\]/); -} - -var Fpapply = Function.prototype.apply; - -function apply(f, o, a) { - return Fpapply.call(f, [o].concat(a)); -} - -var applyNew; - -// ES5's bind is a simpler way to implement applyNew -if (Function.prototype.bind) { - applyNew = function applyNew(f, a) { - return new (f.bind.apply(f, [,].concat(Array.prototype.slice.call(a))))(); - }; -} else { - applyNew = function applyNew(f, a) { - switch (a.length) { - case 0: - return new f(); - case 1: - return new f(a[0]); - case 2: - return new f(a[0], a[1]); - case 3: - return new f(a[0], a[1], a[2]); - default: - var argStr = "a[0]"; - for (var i = 1, n = a.length; i < n; i++) - argStr += ",a[" + i + "]"; - return eval("new f(" + argStr + ")"); - } - }; -} - -function getPropertyDescriptor(obj, name) { - while (obj) { - if (({}).hasOwnProperty.call(obj, name)) - return Object.getOwnPropertyDescriptor(obj, name); - obj = Object.getPrototypeOf(obj); - } -} - -function getPropertyNames(obj) { - var table = Object.create(null, {}); - while (obj) { - var names = Object.getOwnPropertyNames(obj); - for (var i = 0, n = names.length; i < n; i++) - table[names[i]] = true; - obj = Object.getPrototypeOf(obj); - } - return Object.keys(table); -} - -function getOwnProperties(obj) { - var map = {}; - for (var name in Object.getOwnPropertyNames(obj)) - map[name] = Object.getOwnPropertyDescriptor(obj, name); - return map; -} - -function blacklistHandler(target, blacklist) { - var mask = Object.create(null, {}); - var redirect = Dict.create(blacklist).mapObject(function(name) { return mask; }); - return mixinHandler(redirect, target); -} - -function whitelistHandler(target, whitelist) { - var catchall = Object.create(null, {}); - var redirect = Dict.create(whitelist).mapObject(function(name) { return target; }); - return mixinHandler(redirect, catchall); -} - -/* - * Mixin proxies break the single-inheritance model of prototypes, so - * the handler treats all properties as own-properties: - * - * X - * | - * +------------+------------+ - * | O | - * | | | - * | O O O | - * | | | | | - * | O O O O | - * | | | | | | - * | O O O O O | - * | | | | | | | - * +-(*)--(w)--(x)--(y)--(z)-+ - */ - -function mixinHandler(redirect, catchall) { - function targetFor(name) { - return hasOwn(redirect, name) ? redirect[name] : catchall; - } - - function getMuxPropertyDescriptor(name) { - var desc = getPropertyDescriptor(targetFor(name), name); - if (desc) - desc.configurable = true; - return desc; - } - - function getMuxPropertyNames() { - var names1 = Object.getOwnPropertyNames(redirect).filter(function(name) { - return name in redirect[name]; - }); - var names2 = getPropertyNames(catchall).filter(function(name) { - return !hasOwn(redirect, name); - }); - return names1.concat(names2); - } - - function enumerateMux() { - var result = Object.getOwnPropertyNames(redirect).filter(function(name) { - return name in redirect[name]; - }); - for (name in catchall) { - if (!hasOwn(redirect, name)) - result.push(name); - }; - return result; - } - - function hasMux(name) { - return name in targetFor(name); - } - - return { - getOwnPropertyDescriptor: getMuxPropertyDescriptor, - getPropertyDescriptor: getMuxPropertyDescriptor, - getOwnPropertyNames: getMuxPropertyNames, - defineProperty: function(name, desc) { - Object.defineProperty(targetFor(name), name, desc); - }, - "delete": function(name) { - var target = targetFor(name); - return delete target[name]; - }, - // FIXME: ha ha ha - fix: function() { }, - has: hasMux, - hasOwn: hasMux, - get: function(receiver, name) { - var target = targetFor(name); - return target[name]; - }, - set: function(receiver, name, val) { - var target = targetFor(name); - target[name] = val; - return true; - }, - enumerate: enumerateMux, - keys: enumerateMux - }; -} - -function makePassthruHandler(obj) { - // Handler copied from - // http://wiki.ecmascript.org/doku.php?id=harmony:proxies&s=proxy%20object#examplea_no-op_forwarding_proxy - return { - getOwnPropertyDescriptor: function(name) { - var desc = Object.getOwnPropertyDescriptor(obj, name); - - // a trapping proxy's properties must always be configurable - desc.configurable = true; - return desc; - }, - getPropertyDescriptor: function(name) { - var desc = getPropertyDescriptor(obj, name); - - // a trapping proxy's properties must always be configurable - desc.configurable = true; - return desc; - }, - getOwnPropertyNames: function() { - return Object.getOwnPropertyNames(obj); - }, - defineProperty: function(name, desc) { - Object.defineProperty(obj, name, desc); - }, - "delete": function(name) { return delete obj[name]; }, - fix: function() { - if (Object.isFrozen(obj)) { - return getOwnProperties(obj); - } - - // As long as obj is not frozen, the proxy won't allow itself to be fixed. - return undefined; // will cause a TypeError to be thrown - }, - - has: function(name) { return name in obj; }, - hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); }, - get: function(receiver, name) { return obj[name]; }, - - // bad behavior when set fails in non-strict mode - set: function(receiver, name, val) { obj[name] = val; return true; }, - enumerate: function() { - var result = []; - for (name in obj) { result.push(name); }; - return result; - }, - keys: function() { return Object.keys(obj); } - }; -} - -var hasOwnProperty = ({}).hasOwnProperty; - -function hasOwn(obj, name) { - return hasOwnProperty.call(obj, name); -} - -function Dict(table, size) { - this.table = table || Object.create(null, {}); - this.size = size || 0; -} - -Dict.create = function(table) { - var init = Object.create(null, {}); - var size = 0; - var names = Object.getOwnPropertyNames(table); - for (var i = 0, n = names.length; i < n; i++) { - var name = names[i]; - init[name] = table[name]; - size++; - } - return new Dict(init, size); -}; - -Dict.prototype = { - has: function(x) { return hasOwnProperty.call(this.table, x); }, - set: function(x, v) { - if (!hasOwnProperty.call(this.table, x)) - this.size++; - this.table[x] = v; - }, - get: function(x) { return this.table[x]; }, - getDef: function(x, thunk) { - if (!hasOwnProperty.call(this.table, x)) { - this.size++; - this.table[x] = thunk(); - } - return this.table[x]; - }, - forEach: function(f) { - var table = this.table; - for (var key in table) - f.call(this, key, table[key]); - }, - map: function(f) { - var table1 = this.table; - var table2 = Object.create(null, {}); - this.forEach(function(key, val) { - table2[key] = f.call(this, val, key); - }); - return new Dict(table2, this.size); - }, - mapObject: function(f) { - var table1 = this.table; - var table2 = Object.create(null, {}); - this.forEach(function(key, val) { - table2[key] = f.call(this, val, key); - }); - return table2; - }, - toObject: function() { - return this.mapObject(function(val) { return val; }); - }, - choose: function() { - return Object.getOwnPropertyNames(this.table)[0]; - }, - remove: function(x) { - if (hasOwnProperty.call(this.table, x)) { - this.size--; - delete this.table[x]; - } - }, - copy: function() { - var table = Object.create(null, {}); - for (var key in this.table) - table[key] = this.table[key]; - return new Dict(table, this.size); - }, - keys: function() { - return Object.keys(this.table); - }, - toString: function() { return "[object Dict]" } -}; - -var _WeakMap = typeof WeakMap === "function" ? WeakMap : (function() { - // shim for ES6 WeakMap with poor asymptotics - function WeakMap(array) { - this.array = array || []; - } - - function searchMap(map, key, found, notFound) { - var a = map.array; - for (var i = 0, n = a.length; i < n; i++) { - var pair = a[i]; - if (pair.key === key) - return found(pair, i); - } - return notFound(); - } - - WeakMap.prototype = { - has: function(x) { - return searchMap(this, x, function() { return true }, function() { return false }); - }, - set: function(x, v) { - var a = this.array; - searchMap(this, x, - function(pair) { pair.value = v }, - function() { a.push({ key: x, value: v }) }); - }, - get: function(x) { - return searchMap(this, x, - function(pair) { return pair.value }, - function() { return null }); - }, - "delete": function(x) { - var a = this.array; - searchMap(this, x, - function(pair, i) { a.splice(i, 1) }, - function() { }); - }, - toString: function() { return "[object WeakMap]" } - }; - - return WeakMap; -})(); - -// non-destructive stack -function Stack(elts) { - this.elts = elts || null; -} - -Stack.prototype = { - push: function(x) { - return new Stack({ top: x, rest: this.elts }); - }, - top: function() { - if (!this.elts) - throw new Error("empty stack"); - return this.elts.top; - }, - isEmpty: function() { - return this.top === null; - }, - find: function(test) { - for (var elts = this.elts; elts; elts = elts.rest) { - if (test(elts.top)) - return elts.top; - } - return null; - }, - has: function(x) { - return Boolean(this.find(function(elt) { return elt === x })); - }, - forEach: function(f) { - for (var elts = this.elts; elts; elts = elts.rest) { - f(elts.top); - } - } -}; - -if (!Array.prototype.copy) { - defineProperty(Array.prototype, "copy", - function() { - var result = []; - for (var i = 0, n = this.length; i < n; i++) - result[i] = this[i]; - return result; - }, false, false, true); -} - -if (!Array.prototype.top) { - defineProperty(Array.prototype, "top", - function() { - return this.length && this[this.length-1]; - }, false, false, true); -} - -exports.tokens = tokens; -exports.whitespace = whitespace; -exports.opTypeNames = opTypeNames; -exports.keywords = keywords; -exports.mozillaKeywords = mozillaKeywords; -exports.strictKeywords = strictKeywords; -exports.isStatementStartCode = isStatementStartCode; -exports.tokenIds = tokenIds; -exports.consts = consts; -exports.assignOps = assignOps; -exports.defineGetter = defineGetter; -exports.defineGetterSetter = defineGetterSetter; -exports.defineMemoGetter = defineMemoGetter; -exports.defineProperty = defineProperty; -exports.isNativeCode = isNativeCode; -exports.apply = apply; -exports.applyNew = applyNew; -exports.mixinHandler = mixinHandler; -exports.whitelistHandler = whitelistHandler; -exports.blacklistHandler = blacklistHandler; -exports.makePassthruHandler = makePassthruHandler; -exports.Dict = Dict; -exports.WeakMap = _WeakMap; -exports.Stack = Stack; - -}); diff --git a/lib/ace/narcissus/lexer.js b/lib/ace/narcissus/lexer.js deleted file mode 100644 index c830bce3..00000000 --- a/lib/ace/narcissus/lexer.js +++ /dev/null @@ -1,584 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Distributed under the BSD license: - * - * Copyright (c) 2010, Ajax.org B.V. - * All rights reserved. - * - * 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. - * * Neither the name of Ajax.org B.V. nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * 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 AJAX.ORG B.V. 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. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Narcissus - JS implemented in JS. - * - * Lexical scanner. - */ - - define(function(require, exports, module) { - -var definitions = require('./definitions'); - -// Set constants in the local scope. -eval(definitions.consts); - -// Build up a trie of operator tokens. -var opTokens = {}; -for (var op in definitions.opTypeNames) { - if (op === '\n' || op === '.') - continue; - - var node = opTokens; - for (var i = 0; i < op.length; i++) { - var ch = op[i]; - if (!(ch in node)) - node[ch] = {}; - node = node[ch]; - node.op = op; - } -} - -/* - * Since JavaScript provides no convenient way to determine if a - * character is in a particular Unicode category, we use - * metacircularity to accomplish this (oh yeaaaah!) - */ -function isValidIdentifierChar(ch, first) { - // check directly for ASCII - if (ch <= "\u007F") { - if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_' || - (!first && (ch >= '0' && ch <= '9'))) { - return true; - } - return false; - } - - // create an object to test this in - var x = {}; - x["x"+ch] = true; - x[ch] = true; - - // then use eval to determine if it's a valid character - var valid = false; - try { - valid = (Function("x", "return (x." + (first?"":"x") + ch + ");")(x) === true); - } catch (ex) {} - - return valid; -} - -function isIdentifier(str) { - if (typeof str !== "string") - return false; - - if (str.length === 0) - return false; - - if (!isValidIdentifierChar(str[0], true)) - return false; - - for (var i = 1; i < str.length; i++) { - if (!isValidIdentifierChar(str[i], false)) - return false; - } - - return true; -} - -/* - * Tokenizer :: (source, filename, line number, boolean) -> Tokenizer - */ -function Tokenizer(s, f, l, allowHTMLComments) { - this.cursor = 0; - this.source = String(s); - this.tokens = []; - this.tokenIndex = 0; - this.lookahead = 0; - this.scanNewlines = false; - this.filename = f || ""; - this.lineno = l || 1; - this.allowHTMLComments = allowHTMLComments; - this.blockComments = null; -} - -Tokenizer.prototype = { - get done() { - // We need to set scanOperand to true here because the first thing - // might be a regexp. - return this.peek(true) === END; - }, - - get token() { - return this.tokens[this.tokenIndex]; - }, - - match: function (tt, scanOperand, keywordIsName) { - return this.get(scanOperand, keywordIsName) === tt || this.unget(); - }, - - mustMatch: function (tt, keywordIsName) { - if (!this.match(tt, false, keywordIsName)) { - throw this.newSyntaxError("Missing " + - definitions.tokens[tt].toLowerCase()); - } - return this.token; - }, - - peek: function (scanOperand) { - var tt, next; - if (this.lookahead) { - next = this.tokens[(this.tokenIndex + this.lookahead) & 3]; - tt = (this.scanNewlines && next.lineno !== this.lineno) - ? NEWLINE - : next.type; - } else { - tt = this.get(scanOperand); - this.unget(); - } - return tt; - }, - - peekOnSameLine: function (scanOperand) { - this.scanNewlines = true; - var tt = this.peek(scanOperand); - this.scanNewlines = false; - return tt; - }, - - lastBlockComment: function() { - var length = this.blockComments.length; - return length ? this.blockComments[length - 1] : null; - }, - - // Eat comments and whitespace. - skip: function () { - var input = this.source; - this.blockComments = []; - for (;;) { - var ch = input[this.cursor++]; - var next = input[this.cursor]; - // handle \r, \r\n and (always preferable) \n - if (ch === '\r') { - // if the next character is \n, we don't care about this at all - if (next === '\n') continue; - - // otherwise, we want to consider this as a newline - ch = '\n'; - } - - if (ch === '\n' && !this.scanNewlines) { - this.lineno++; - } else if (ch === '/' && next === '*') { - var commentStart = ++this.cursor; - for (;;) { - ch = input[this.cursor++]; - if (ch === undefined) - throw this.newSyntaxError("Unterminated comment"); - - if (ch === '*') { - next = input[this.cursor]; - if (next === '/') { - var commentEnd = this.cursor - 1; - this.cursor++; - break; - } - } else if (ch === '\n') { - this.lineno++; - } - } - this.blockComments.push(input.substring(commentStart, commentEnd)); - } else if ((ch === '/' && next === '/') || - (this.allowHTMLComments && ch === '<' && next === '!' && - input[this.cursor + 1] === '-' && input[this.cursor + 2] === '-' && - (this.cursor += 2))) { - this.cursor++; - for (;;) { - ch = input[this.cursor++]; - next = input[this.cursor]; - if (ch === undefined) - return; - - if (ch === '\r') { - // check for \r\n - if (next !== '\n') ch = '\n'; - } - - if (ch === '\n') { - if (this.scanNewlines) { - this.cursor--; - } else { - this.lineno++; - } - break; - } - } - } else if (!(ch in definitions.whitespace)) { - this.cursor--; - return; - } - } - }, - - // Lex the exponential part of a number, if present. Return true iff an - // exponential part was found. - lexExponent: function() { - var input = this.source; - var next = input[this.cursor]; - if (next === 'e' || next === 'E') { - this.cursor++; - ch = input[this.cursor++]; - if (ch === '+' || ch === '-') - ch = input[this.cursor++]; - - if (ch < '0' || ch > '9') - throw this.newSyntaxError("Missing exponent"); - - do { - ch = input[this.cursor++]; - } while (ch >= '0' && ch <= '9'); - this.cursor--; - - return true; - } - - return false; - }, - - lexZeroNumber: function (ch) { - var token = this.token, input = this.source; - token.type = NUMBER; - - ch = input[this.cursor++]; - if (ch === '.') { - do { - ch = input[this.cursor++]; - } while (ch >= '0' && ch <= '9'); - this.cursor--; - - this.lexExponent(); - token.value = parseFloat( - input.substring(token.start, this.cursor)); - } else if (ch === 'x' || ch === 'X') { - do { - ch = input[this.cursor++]; - } while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || - (ch >= 'A' && ch <= 'F')); - this.cursor--; - - token.value = parseInt(input.substring(token.start, this.cursor)); - } else if (ch >= '0' && ch <= '7') { - do { - ch = input[this.cursor++]; - } while (ch >= '0' && ch <= '7'); - this.cursor--; - - token.value = parseInt(input.substring(token.start, this.cursor)); - } else { - this.cursor--; - this.lexExponent(); // 0E1, &c. - token.value = 0; - } - }, - - lexNumber: function (ch) { - var token = this.token, input = this.source; - token.type = NUMBER; - - var floating = false; - do { - ch = input[this.cursor++]; - if (ch === '.' && !floating) { - floating = true; - ch = input[this.cursor++]; - } - } while (ch >= '0' && ch <= '9'); - - this.cursor--; - - var exponent = this.lexExponent(); - floating = floating || exponent; - - var str = input.substring(token.start, this.cursor); - token.value = floating ? parseFloat(str) : parseInt(str); - }, - - lexDot: function (ch) { - var token = this.token, input = this.source; - var next = input[this.cursor]; - if (next >= '0' && next <= '9') { - do { - ch = input[this.cursor++]; - } while (ch >= '0' && ch <= '9'); - this.cursor--; - - this.lexExponent(); - - token.type = NUMBER; - token.value = parseFloat( - input.substring(token.start, this.cursor)); - } else { - token.type = DOT; - token.assignOp = null; - token.value = '.'; - } - }, - - lexString: function (ch) { - var token = this.token, input = this.source; - token.type = STRING; - - var hasEscapes = false; - var delim = ch; - if (input.length <= this.cursor) - throw this.newSyntaxError("Unterminated string literal"); - while ((ch = input[this.cursor++]) !== delim) { - if (ch == '\n' || ch == '\r') - throw this.newSyntaxError("Unterminated string literal"); - if (this.cursor == input.length) - throw this.newSyntaxError("Unterminated string literal"); - if (ch === '\\') { - hasEscapes = true; - if (++this.cursor == input.length) - throw this.newSyntaxError("Unterminated string literal"); - } - } - - token.value = hasEscapes - ? eval(input.substring(token.start, this.cursor)) - : input.substring(token.start + 1, this.cursor - 1); - }, - - lexRegExp: function (ch) { - var token = this.token, input = this.source; - token.type = REGEXP; - - do { - ch = input[this.cursor++]; - if (ch === '\\') { - this.cursor++; - } else if (ch === '[') { - do { - if (ch === undefined) - throw this.newSyntaxError("Unterminated character class"); - - if (ch === '\\') - this.cursor++; - - ch = input[this.cursor++]; - } while (ch !== ']'); - } else if (ch === undefined) { - throw this.newSyntaxError("Unterminated regex"); - } - } while (ch !== '/'); - - do { - ch = input[this.cursor++]; - } while (ch >= 'a' && ch <= 'z'); - - this.cursor--; - - token.value = eval(input.substring(token.start, this.cursor)); - }, - - lexOp: function (ch) { - var token = this.token, input = this.source; - - // A bit ugly, but it seems wasteful to write a trie lookup routine - // for only 3 characters... - var node = opTokens[ch]; - var next = input[this.cursor]; - if (next in node) { - node = node[next]; - this.cursor++; - next = input[this.cursor]; - if (next in node) { - node = node[next]; - this.cursor++; - next = input[this.cursor]; - } - } - - var op = node.op; - if (definitions.assignOps[op] && input[this.cursor] === '=') { - this.cursor++; - token.type = ASSIGN; - token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]]; - op += '='; - } else { - token.type = definitions.tokenIds[definitions.opTypeNames[op]]; - token.assignOp = null; - } - - token.value = op; - }, - - // FIXME: Unicode escape sequences - lexIdent: function (ch, keywordIsName) { - var token = this.token; - var id = ch; - - while ((ch = this.getValidIdentifierChar(false)) !== null) { - id += ch; - } - - token.type = IDENTIFIER; - token.value = id; - - if (keywordIsName) - return; - - var kw; - - if (this.parser.mozillaMode) { - kw = definitions.mozillaKeywords[id]; - if (kw) { - token.type = kw; - return; - } - } - - if (this.parser.x.strictMode) { - kw = definitions.strictKeywords[id]; - if (kw) { - token.type = kw; - return; - } - } - - kw = definitions.keywords[id]; - if (kw) - token.type = kw; - }, - - /* - * Tokenizer.get :: ([boolean[, boolean]]) -> token type - * - * Consume input *only* if there is no lookahead. - * Dispatch to the appropriate lexing function depending on the input. - */ - get: function (scanOperand, keywordIsName) { - var token; - while (this.lookahead) { - --this.lookahead; - this.tokenIndex = (this.tokenIndex + 1) & 3; - token = this.tokens[this.tokenIndex]; - if (token.type !== NEWLINE || this.scanNewlines) - return token.type; - } - - this.skip(); - - this.tokenIndex = (this.tokenIndex + 1) & 3; - token = this.tokens[this.tokenIndex]; - if (!token) - this.tokens[this.tokenIndex] = token = {}; - - var input = this.source; - if (this.cursor >= input.length) - return token.type = END; - - token.start = this.cursor; - token.lineno = this.lineno; - - var ich = this.getValidIdentifierChar(true); - var ch = (ich === null) ? input[this.cursor++] : null; - if (ich !== null) { - this.lexIdent(ich, keywordIsName); - } else if (scanOperand && ch === '/') { - this.lexRegExp(ch); - } else if (ch in opTokens) { - this.lexOp(ch); - } else if (ch === '.') { - this.lexDot(ch); - } else if (ch >= '1' && ch <= '9') { - this.lexNumber(ch); - } else if (ch === '0') { - this.lexZeroNumber(ch); - } else if (ch === '"' || ch === "'") { - this.lexString(ch); - } else if (this.scanNewlines && (ch === '\n' || ch === '\r')) { - // if this was a \r, look for \r\n - if (ch === '\r' && input[this.cursor] === '\n') this.cursor++; - token.type = NEWLINE; - token.value = '\n'; - this.lineno++; - } else { - throw this.newSyntaxError("Illegal token"); - } - - token.end = this.cursor; - return token.type; - }, - - /* - * Tokenizer.unget :: void -> undefined - * - * Match depends on unget returning undefined. - */ - unget: function () { - if (++this.lookahead === 4) throw "PANIC: too much lookahead!"; - this.tokenIndex = (this.tokenIndex - 1) & 3; - }, - - newSyntaxError: function (m) { - m = (this.filename ? this.filename + ":" : "") + this.lineno + ": " + m; - var e = new SyntaxError(m, this.filename, this.lineno); - e.source = this.source; - e.cursor = this.lookahead - ? this.tokens[(this.tokenIndex + this.lookahead) & 3].start - : this.cursor; - return e; - }, - - - /* Gets a single valid identifier char from the input stream, or null - * if there is none. - */ - getValidIdentifierChar: function(first) { - var input = this.source; - if (this.cursor >= input.length) return null; - var ch = input[this.cursor]; - - // first check for \u escapes - if (ch === '\\' && input[this.cursor+1] === 'u') { - // get the character value - try { - ch = String.fromCharCode(parseInt( - input.substring(this.cursor + 2, this.cursor + 6), - 16)); - } catch (ex) { - return null; - } - this.cursor += 5; - } - - var valid = isValidIdentifierChar(ch, first); - if (valid) this.cursor++; - return (valid ? ch : null); - }, -}; - - -exports.isIdentifier = isIdentifier; -exports.Tokenizer = Tokenizer; - -}); diff --git a/lib/ace/narcissus/options.js b/lib/ace/narcissus/options.js deleted file mode 100644 index d399de38..00000000 --- a/lib/ace/narcissus/options.js +++ /dev/null @@ -1,48 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Distributed under the BSD license: - * - * Copyright (c) 2010, Ajax.org B.V. - * All rights reserved. - * - * 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. - * * Neither the name of Ajax.org B.V. nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * 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 AJAX.ORG B.V. 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. - * - * ***** END LICENSE BLOCK ***** */ - -define(function(require, exports, module) { - -// Global variables to hide from the interpreter -exports.hiddenHostGlobals = { Narcissus: true }; - -// Desugar SpiderMonkey language extensions? -exports.desugarExtensions = false; - -// Allow HTML comments? -exports.allowHTMLComments = false; - -// Allow non-standard Mozilla extensions? -exports.mozillaMode = true; - -// Allow experimental paren-free mode? -exports.parenFreeMode = false; - -}); diff --git a/lib/ace/narcissus/parser.js b/lib/ace/narcissus/parser.js deleted file mode 100644 index dbb5947f..00000000 --- a/lib/ace/narcissus/parser.js +++ /dev/null @@ -1,2057 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Distributed under the BSD license: - * - * Copyright (c) 2010, Ajax.org B.V. - * All rights reserved. - * - * 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. - * * Neither the name of Ajax.org B.V. nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * 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 AJAX.ORG B.V. 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. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Narcissus - JS implemented in JS. - * - * Parser. - */ - -define(function(require, exports, module) { - -var lexer = require('./lexer'); -var definitions = require('./definitions'); -var options = require('./options'); -var Tokenizer = lexer.Tokenizer; - -var Dict = definitions.Dict; -var Stack = definitions.Stack; - -// Set constants in the local scope. -eval(definitions.consts); - -/* - * pushDestructuringVarDecls :: (node, hoisting node) -> void - * - * Recursively add all destructured declarations to varDecls. - */ -function pushDestructuringVarDecls(n, s) { - for (var i in n) { - var sub = n[i]; - if (sub.type === IDENTIFIER) { - s.varDecls.push(sub); - } else { - pushDestructuringVarDecls(sub, s); - } - } -} - -function Parser(tokenizer) { - tokenizer.parser = this; - this.t = tokenizer; - this.x = null; - this.unexpectedEOF = false; - options.mozillaMode && (this.mozillaMode = true); - options.parenFreeMode && (this.parenFreeMode = true); -} - -function StaticContext(parentScript, parentBlock, inModule, inFunction, strictMode) { - this.parentScript = parentScript; - this.parentBlock = parentBlock || parentScript; - this.inModule = inModule || false; - this.inFunction = inFunction || false; - this.inForLoopInit = false; - this.topLevel = true; - this.allLabels = new Stack(); - this.currentLabels = new Stack(); - this.labeledTargets = new Stack(); - this.defaultLoopTarget = null; - this.defaultTarget = null; - this.strictMode = strictMode; -} - -StaticContext.prototype = { - // non-destructive update via prototype extension - update: function(ext) { - var desc = {}; - for (var key in ext) { - desc[key] = { - value: ext[key], - writable: true, - enumerable: true, - configurable: true - } - } - return Object.create(this, desc); - }, - pushLabel: function(label) { - return this.update({ currentLabels: this.currentLabels.push(label), - allLabels: this.allLabels.push(label) }); - }, - pushTarget: function(target) { - var isDefaultLoopTarget = target.isLoop; - var isDefaultTarget = isDefaultLoopTarget || target.type === SWITCH; - - if (this.currentLabels.isEmpty()) { - if (isDefaultLoopTarget) this.update({ defaultLoopTarget: target }); - if (isDefaultTarget) this.update({ defaultTarget: target }); - return this; - } - - target.labels = new Dict(); - this.currentLabels.forEach(function(label) { - target.labels.set(label, true); - }); - return this.update({ currentLabels: new Stack(), - labeledTargets: this.labeledTargets.push(target), - defaultLoopTarget: isDefaultLoopTarget - ? target - : this.defaultLoopTarget, - defaultTarget: isDefaultTarget - ? target - : this.defaultTarget }); - }, - nest: function() { - return this.topLevel ? this.update({ topLevel: false }) : this; - }, - canImport: function() { - return this.topLevel && !this.inFunction; - }, - canExport: function() { - return this.inModule && this.topLevel && !this.inFunction; - }, - banWith: function() { - return this.strictMode || this.inModule; - }, - modulesAllowed: function() { - return this.topLevel && !this.inFunction; - } -}; - -var Pp = Parser.prototype; - -Pp.mozillaMode = false; - -Pp.parenFreeMode = false; - -Pp.withContext = function(x, f) { - var x0 = this.x; - this.x = x; - var result = f.call(this); - // NB: we don't bother with finally, since exceptions trash the parser - this.x = x0; - return result; -}; - -Pp.newNode = function newNode(opts) { - return new Node(this.t, opts); -}; - -Pp.fail = function fail(msg) { - throw this.t.newSyntaxError(msg); -}; - -Pp.match = function match(tt, scanOperand, keywordIsName) { - return this.t.match(tt, scanOperand, keywordIsName); -}; - -Pp.mustMatch = function mustMatch(tt, keywordIsName) { - return this.t.mustMatch(tt, keywordIsName); -}; - -Pp.peek = function peek(scanOperand) { - return this.t.peek(scanOperand); -}; - -Pp.peekOnSameLine = function peekOnSameLine(scanOperand) { - return this.t.peekOnSameLine(scanOperand); -}; - -Pp.done = function done() { - return this.t.done; -}; - -/* - * Script :: (boolean, boolean, boolean) -> node - * - * Parses the toplevel and module/function bodies. - */ -Pp.Script = function Script(inModule, inFunction, expectEnd) { - var node = this.newNode(scriptInit()); - var x2 = new StaticContext(node, node, inModule, inFunction); - this.withContext(x2, function() { - this.Statements(node, true); - }); - if (expectEnd && !this.done()) - this.fail("expected end of input"); - return node; -}; - -/* - * Pragma :: (expression statement node) -> boolean - * - * Checks whether a node is a pragma and annotates it. - */ -function Pragma(n) { - if (n.type === SEMICOLON) { - var e = n.expression; - if (e.type === STRING && e.value === "use strict") { - n.pragma = "strict"; - return true; - } - } - return false; -} - -/* - * Node :: (tokenizer, optional init object) -> node - */ -function Node(t, init) { - var token = t.token; - if (token) { - // If init.type exists it will override token.type. - this.type = token.type; - this.value = token.value; - this.lineno = token.lineno; - - // Start and end are file positions for error handling. - this.start = token.start; - this.end = token.end; - } else { - this.lineno = t.lineno; - } - - this.filename = t.filename; - this.children = []; - - for (var prop in init) - this[prop] = init[prop]; -} - -/* - * SyntheticNode :: (optional init object) -> node - */ -function SyntheticNode(init) { - this.children = []; - for (var prop in init) - this[prop] = init[prop]; - this.synthetic = true; -} - -var Np = Node.prototype = SyntheticNode.prototype = {}; -Np.constructor = Node; - -var TO_SOURCE_SKIP = { - type: true, - value: true, - lineno: true, - start: true, - end: true, - tokenizer: true, - assignOp: true -}; -function unevalableConst(code) { - var token = definitions.tokens[code]; - var constName = definitions.opTypeNames.hasOwnProperty(token) - ? definitions.opTypeNames[token] - : token in definitions.keywords - ? token.toUpperCase() - : token; - return { toSource: function() { return constName } }; -} -Np.toSource = function toSource() { - var mock = {}; - var self = this; - mock.type = unevalableConst(this.type); - // avoid infinite recursion in case of back-links - if (this.generatingSource) - return mock.toSource(); - this.generatingSource = true; - if ("value" in this) - mock.value = this.value; - if ("lineno" in this) - mock.lineno = this.lineno; - if ("start" in this) - mock.start = this.start; - if ("end" in this) - mock.end = this.end; - if (this.assignOp) - mock.assignOp = unevalableConst(this.assignOp); - for (var key in this) { - if (this.hasOwnProperty(key) && !(key in TO_SOURCE_SKIP)) - mock[key] = this[key]; - } - try { - return mock.toSource(); - } finally { - delete this.generatingSource; - } -}; - -// Always use push to add operands to an expression, to update start and end. -Np.push = function (kid) { - // kid can be null e.g. [1, , 2]. - if (kid !== null) { - if (kid.start < this.start) - this.start = kid.start; - if (this.end < kid.end) - this.end = kid.end; - } - return this.children.push(kid); -} - -Node.indentLevel = 0; - -function tokenString(tt) { - var t = definitions.tokens[tt]; - return /^\W/.test(t) ? definitions.opTypeNames[t] : t.toUpperCase(); -} - -Np.toString = function () { - var a = []; - for (var i in this) { - if (this.hasOwnProperty(i) && i !== 'type' && i !== 'target') - a.push({id: i, value: this[i]}); - } - a.sort(function (a,b) { return (a.id < b.id) ? -1 : 1; }); - var INDENTATION = " "; - var n = ++Node.indentLevel; - var s = "{\n" + INDENTATION.repeat(n) + "type: " + tokenString(this.type); - for (i = 0; i < a.length; i++) - s += ",\n" + INDENTATION.repeat(n) + a[i].id + ": " + a[i].value; - n = --Node.indentLevel; - s += "\n" + INDENTATION.repeat(n) + "}"; - return s; -} - -Np.synth = function(init) { - var node = new SyntheticNode(init); - node.filename = this.filename; - node.lineno = this.lineno; - node.start = this.start; - node.end = this.end; - return node; -}; - -/* - * Helper init objects for common nodes. - */ - -var LOOP_INIT = { isLoop: true }; - -function blockInit() { - return { type: BLOCK, varDecls: [] }; -} - -function scriptInit() { - return { type: SCRIPT, - funDecls: [], - varDecls: [], - modDefns: new Dict(), - modAssns: new Dict(), - modDecls: new Dict(), - modLoads: new Dict(), - impDecls: [], - expDecls: [], - exports: new Dict(), - hasEmptyReturn: false, - hasReturnWithValue: false, - hasYield: false }; -} - -definitions.defineGetter(Np, "length", - function() { - throw new Error("Node.prototype.length is gone; " + - "use n.children.length instead"); - }); - -definitions.defineProperty(String.prototype, "repeat", - function(n) { - var s = "", t = this + s; - while (--n >= 0) - s += t; - return s; - }, false, false, true); - -Pp.MaybeLeftParen = function MaybeLeftParen() { - if (this.parenFreeMode) - return this.match(LEFT_PAREN) ? LEFT_PAREN : END; - return this.mustMatch(LEFT_PAREN).type; -}; - -Pp.MaybeRightParen = function MaybeRightParen(p) { - if (p === LEFT_PAREN) - this.mustMatch(RIGHT_PAREN); -} - -/* - * Statements :: (node[, boolean]) -> void - * - * Parses a sequence of Statements. - */ -Pp.Statements = function Statements(n, topLevel) { - var prologue = !!topLevel; - try { - while (!this.done() && this.peek(true) !== RIGHT_CURLY) { - var n2 = this.Statement(); - n.push(n2); - if (prologue && Pragma(n2)) { - this.x.strictMode = true; - n.strict = true; - } else { - prologue = false; - } - } - } catch (e) { - try { - if (this.done()) - this.unexpectedEOF = true; - } catch(e) {} - throw e; - } -} - -Pp.Block = function Block() { - this.mustMatch(LEFT_CURLY); - var n = this.newNode(blockInit()); - var x2 = this.x.update({ parentBlock: n }).pushTarget(n); - this.withContext(x2, function() { - this.Statements(n); - }); - this.mustMatch(RIGHT_CURLY); - return n; -} - -var DECLARED_FORM = 0, EXPRESSED_FORM = 1, STATEMENT_FORM = 2; - -/* - * Export :: (binding node, boolean) -> Export - * - * Static semantic representation of a module export. - */ -function Export(node, isDefinition) { - this.node = node; // the AST node declaring this individual export - this.isDefinition = isDefinition; // is the node an 'export'-annotated definition? - this.resolved = null; // resolved pointer to the target of this export -} - -/* - * registerExport :: (Dict, EXPORT node) -> void - */ -function registerExport(exports, decl) { - function register(name, exp) { - if (exports.has(name)) - throw new SyntaxError("multiple exports of " + name); - exports.set(name, exp); - } - - switch (decl.type) { - case MODULE: - case FUNCTION: - register(decl.name, new Export(decl, true)); - break; - - case VAR: - for (var i = 0; i < decl.children.length; i++) - register(decl.children[i].name, new Export(decl.children[i], true)); - break; - - case LET: - case CONST: - throw new Error("NYI: " + definitions.tokens[decl.type]); - - case EXPORT: - for (var i = 0; i < decl.pathList.length; i++) { - var path = decl.pathList[i]; - switch (path.type) { - case OBJECT_INIT: - for (var j = 0; j < path.children.length; j++) { - // init :: IDENTIFIER | PROPERTY_INIT - var init = path.children[j]; - if (init.type === IDENTIFIER) - register(init.value, new Export(init, false)); - else - register(init.children[0].value, new Export(init.children[1], false)); - } - break; - - case DOT: - register(path.children[1].value, new Export(path, false)); - break; - - case IDENTIFIER: - register(path.value, new Export(path, false)); - break; - - default: - throw new Error("unexpected export path: " + definitions.tokens[path.type]); - } - } - break; - - default: - throw new Error("unexpected export decl: " + definitions.tokens[exp.type]); - } -} - -/* - * Module :: (node) -> Module - * - * Static semantic representation of a module. - */ -function Module(node) { - var exports = node.body.exports; - var modDefns = node.body.modDefns; - - var exportedModules = new Dict(); - - exports.forEach(function(name, exp) { - var node = exp.node; - if (node.type === MODULE) { - exportedModules.set(name, node); - } else if (!exp.isDefinition && node.type === IDENTIFIER && modDefns.has(node.value)) { - var mod = modDefns.get(node.value); - exportedModules.set(name, mod); - } - }); - - this.node = node; - this.exports = exports; - this.exportedModules = exportedModules; -} - -/* - * Statement :: () -> node - * - * Parses a Statement. - */ -Pp.Statement = function Statement() { - var i, label, n, n2, p, c, ss, tt = this.t.get(true), tt2, x0, x2, x3; - - var comments = this.t.blockComments; - - // Cases for statements ending in a right curly return early, avoiding the - // common semicolon insertion magic after this switch. - switch (tt) { - case IMPORT: - if (!this.x.canImport()) - this.fail("illegal context for import statement"); - n = this.newNode(); - n.pathList = this.ImportPathList(); - this.x.parentScript.impDecls.push(n); - break; - - case EXPORT: - if (!this.x.canExport()) - this.fail("export statement not in module top level"); - switch (this.peek()) { - case MODULE: - case FUNCTION: - case LET: - case VAR: - case CONST: - n = this.Statement(); - n.blockComments = comments; - n.exported = true; - this.x.parentScript.expDecls.push(n); - registerExport(this.x.parentScript.exports, n); - return n; - } - n = this.newNode(); - n.pathList = this.ExportPathList(); - this.x.parentScript.expDecls.push(n); - registerExport(this.x.parentScript.exports, n); - break; - - case FUNCTION: - // DECLARED_FORM extends funDecls of x, STATEMENT_FORM doesn't. - return this.FunctionDefinition(true, this.x.topLevel ? DECLARED_FORM : STATEMENT_FORM, comments); - - case LEFT_CURLY: - n = this.newNode(blockInit()); - x2 = this.x.update({ parentBlock: n }).pushTarget(n).nest(); - this.withContext(x2, function() { - this.Statements(n); - }); - this.mustMatch(RIGHT_CURLY); - return n; - - case IF: - n = this.newNode(); - n.condition = this.HeadExpression(); - x2 = this.x.pushTarget(n).nest(); - this.withContext(x2, function() { - n.thenPart = this.Statement(); - n.elsePart = this.match(ELSE, true) ? this.Statement() : null; - }); - return n; - - case SWITCH: - // This allows CASEs after a DEFAULT, which is in the standard. - n = this.newNode({ cases: [], defaultIndex: -1 }); - n.discriminant = this.HeadExpression(); - x2 = this.x.pushTarget(n).nest(); - this.withContext(x2, function() { - this.mustMatch(LEFT_CURLY); - while ((tt = this.t.get()) !== RIGHT_CURLY) { - switch (tt) { - case DEFAULT: - if (n.defaultIndex >= 0) - this.fail("More than one switch default"); - // FALL THROUGH - case CASE: - n2 = this.newNode(); - if (tt === DEFAULT) - n.defaultIndex = n.cases.length; - else - n2.caseLabel = this.Expression(COLON); - break; - - default: - this.fail("Invalid switch case"); - } - this.mustMatch(COLON); - n2.statements = this.newNode(blockInit()); - while ((tt=this.peek(true)) !== CASE && tt !== DEFAULT && - tt !== RIGHT_CURLY) - n2.statements.push(this.Statement()); - n.cases.push(n2); - } - }); - return n; - - case FOR: - n = this.newNode(LOOP_INIT); - n.blockComments = comments; - if (this.match(IDENTIFIER)) { - if (this.t.token.value === "each") - n.isEach = true; - else - this.t.unget(); - } - if (!this.parenFreeMode) - this.mustMatch(LEFT_PAREN); - x2 = this.x.pushTarget(n).nest(); - x3 = this.x.update({ inForLoopInit: true }); - n2 = null; - if ((tt = this.peek(true)) !== SEMICOLON) { - this.withContext(x3, function() { - if (tt === VAR || tt === CONST) { - this.t.get(); - n2 = this.Variables(); - } else if (tt === LET) { - this.t.get(); - if (this.peek() === LEFT_PAREN) { - n2 = this.LetBlock(false); - } else { - // Let in for head, we need to add an implicit block - // around the rest of the for. - this.x.parentBlock = n; - n.varDecls = []; - n2 = this.Variables(); - } - } else { - n2 = this.Expression(); - } - }); - } - if (n2 && this.match(IN)) { - n.type = FOR_IN; - this.withContext(x3, function() { - n.object = this.Expression(); - if (n2.type === VAR || n2.type === LET) { - c = n2.children; - - // Destructuring turns one decl into multiples, so either - // there must be only one destructuring or only one - // decl. - if (c.length !== 1 && n2.destructurings.length !== 1) { - // FIXME: this.fail ? - throw new SyntaxError("Invalid for..in left-hand side", - this.filename, n2.lineno); - } - if (n2.destructurings.length > 0) { - n.iterator = n2.destructurings[0]; - } else { - n.iterator = c[0]; - } - n.varDecl = n2; - } else { - if (n2.type === ARRAY_INIT || n2.type === OBJECT_INIT) { - n2.destructuredNames = this.checkDestructuring(n2); - } - n.iterator = n2; - } - }); - } else { - x3.inForLoopInit = false; - n.setup = n2; - this.mustMatch(SEMICOLON); - if (n.isEach) - this.fail("Invalid for each..in loop"); - this.withContext(x3, function() { - n.condition = (this.peek(true) === SEMICOLON) - ? null - : this.Expression(); - this.mustMatch(SEMICOLON); - tt2 = this.peek(true); - n.update = (this.parenFreeMode - ? tt2 === LEFT_CURLY || definitions.isStatementStartCode[tt2] - : tt2 === RIGHT_PAREN) - ? null - : this.Expression(); - }); - } - if (!this.parenFreeMode) - this.mustMatch(RIGHT_PAREN); - this.withContext(x2, function() { - n.body = this.Statement(); - }); - return n; - - case WHILE: - n = this.newNode({ isLoop: true }); - n.blockComments = comments; - n.condition = this.HeadExpression(); - x2 = this.x.pushTarget(n).nest(); - this.withContext(x2, function() { - n.body = this.Statement(); - }); - return n; - - case DO: - n = this.newNode({ isLoop: true }); - n.blockComments = comments; - x2 = this.x.pushTarget(n).next(); - this.withContext(x2, function() { - n.body = this.Statement(); - }); - this.mustMatch(WHILE); - n.condition = this.HeadExpression(); - //