remove acorn compiled source

This commit is contained in:
Sebastian McKenzie 2015-03-22 04:09:18 +11:00
parent 37072737b9
commit 2cbbd86552
8 changed files with 0 additions and 894 deletions

View File

@ -1,668 +0,0 @@
// A recursive descent parser operates by defining functions for all
// syntactic elements, and recursively calling those, each function
// advancing the input stream and returning an AST node. Precedence
// of constructs (for example, the fact that `!x[1]` means `!(x[1])`
// instead of `(!x)[1]` is handled by the fact that the parser
// function that parses unary prefix operators is called first, and
// in turn calls the function that parses `[]` subscripts — that
// way, it'll receive the node for `x[1]` already parsed, and wraps
// *that* in the unary operator node.
//
// Acorn uses an [operator precedence parser][opp] to handle binary
// operator precedence, because it is much more compact than using
// the technique outlined above, which uses different, nesting
// functions to specify precedence, for all of the ten binary
// precedence levels that JavaScript defines.
//
// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser
import {types as tt} from "./tokentype"
import {Parser} from "./state"
import {reservedWords} from "./identifier"
import {has} from "./util"
const pp = Parser.prototype
// Check if property name clashes with already added.
// Object/class getters and setters are not allowed to clash —
// either with each other or with an init property — and in
// strict mode, init properties are also not allowed to be repeated.
pp.checkPropClash = function(prop, propHash) {
if (this.options.ecmaVersion >= 6) return
let key = prop.key, name
switch (key.type) {
case "Identifier": name = key.name; break
case "Literal": name = String(key.value); break
default: return
}
let kind = prop.kind || "init", other
if (has(propHash, name)) {
other = propHash[name]
let isGetSet = kind !== "init"
if ((this.strict || isGetSet) && other[kind] || !(isGetSet ^ other.init))
this.raise(key.start, "Redefinition of property")
} else {
other = propHash[name] = {
init: false,
get: false,
set: false
}
}
other[kind] = true
}
// ### Expression parsing
// These nest, from the most general expression type at the top to
// 'atomic', nondivisible expression types at the bottom. Most of
// the functions will simply let the function(s) below them parse,
// and, *if* the syntactic construct they handle is present, wrap
// the AST node that the inner parser gave them in another node.
// Parse a full expression. The optional arguments are used to
// forbid the `in` operator (in for loops initalization expressions)
// and provide reference for storing '=' operator inside shorthand
// property assignment in contexts where both object expression
// and object pattern might appear (so it's possible to raise
// delayed syntax error at correct position).
pp.parseExpression = function(noIn, refShorthandDefaultPos) {
let start = this.markPosition()
let expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos)
if (this.type === tt.comma) {
let node = this.startNodeAt(start)
node.expressions = [expr]
while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn, refShorthandDefaultPos))
return this.finishNode(node, "SequenceExpression")
}
return expr
}
// Parse an assignment expression. This includes applications of
// operators like `+=`.
pp.parseMaybeAssign = function(noIn, refShorthandDefaultPos) {
if (this.type == tt._yield && this.inGenerator) return this.parseYield()
let failOnShorthandAssign
if (!refShorthandDefaultPos) {
refShorthandDefaultPos = {start: 0}
failOnShorthandAssign = true
} else {
failOnShorthandAssign = false
}
let start = this.markPosition()
let left = this.parseMaybeConditional(noIn, refShorthandDefaultPos)
if (this.type.isAssign) {
let node = this.startNodeAt(start)
node.operator = this.value
node.left = this.type === tt.eq ? this.toAssignable(left) : left
refShorthandDefaultPos.start = 0; // reset because shorthand default was used correctly
this.checkLVal(left)
this.next()
node.right = this.parseMaybeAssign(noIn)
return this.finishNode(node, "AssignmentExpression")
} else if (failOnShorthandAssign && refShorthandDefaultPos.start) {
this.unexpected(refShorthandDefaultPos.start)
}
return left
}
// Parse a ternary conditional (`?:`) operator.
pp.parseMaybeConditional = function(noIn, refShorthandDefaultPos) {
let start = this.markPosition()
let expr = this.parseExprOps(noIn, refShorthandDefaultPos)
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr
if (this.eat(tt.question)) {
let node = this.startNodeAt(start)
node.test = expr
node.consequent = this.parseMaybeAssign()
this.expect(tt.colon)
node.alternate = this.parseMaybeAssign(noIn)
return this.finishNode(node, "ConditionalExpression")
}
return expr
}
// Start the precedence parser.
pp.parseExprOps = function(noIn, refShorthandDefaultPos) {
let start = this.markPosition()
let expr = this.parseMaybeUnary(refShorthandDefaultPos)
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr
return this.parseExprOp(expr, start, -1, noIn)
}
// Parse binary operators with the operator precedence parsing
// algorithm. `left` is the left-hand side of the operator.
// `minPrec` provides context that allows the function to stop and
// defer further parser to one of its callers when it encounters an
// operator that has a lower precedence than the set it is parsing.
pp.parseExprOp = function(left, leftStart, minPrec, noIn) {
let prec = this.type.binop
if (prec != null && (!noIn || this.type !== tt._in)) {
if (prec > minPrec) {
let node = this.startNodeAt(leftStart)
node.left = left
node.operator = this.value
let op = this.type
this.next()
let start = this.markPosition()
node.right = this.parseExprOp(this.parseMaybeUnary(), start, op.rightAssociative ? (prec - 1) : prec, noIn)
this.finishNode(node, (op === tt.logicalOR || op === tt.logicalAND) ? "LogicalExpression" : "BinaryExpression")
return this.parseExprOp(node, leftStart, minPrec, noIn)
}
}
return left
}
// Parse unary operators, both prefix and postfix.
pp.parseMaybeUnary = function(refShorthandDefaultPos) {
if (this.type.prefix) {
let node = this.startNode(), update = this.type === tt.incDec
node.operator = this.value
node.prefix = true
this.next()
node.argument = this.parseMaybeUnary()
if (refShorthandDefaultPos && refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start)
if (update) this.checkLVal(node.argument)
else if (this.strict && node.operator === "delete" &&
node.argument.type === "Identifier")
this.raise(node.start, "Deleting local variable in strict mode")
return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression")
}
let start = this.markPosition()
let expr = this.parseExprSubscripts(refShorthandDefaultPos)
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr
while (this.type.postfix && !this.canInsertSemicolon()) {
let node = this.startNodeAt(start)
node.operator = this.value
node.prefix = false
node.argument = expr
this.checkLVal(expr)
this.next()
expr = this.finishNode(node, "UpdateExpression")
}
return expr
}
// Parse call, dot, and `[]`-subscript expressions.
pp.parseExprSubscripts = function(refShorthandDefaultPos) {
let start = this.markPosition()
let expr = this.parseExprAtom(refShorthandDefaultPos)
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr
return this.parseSubscripts(expr, start)
}
pp.parseSubscripts = function(base, start, noCalls) {
if (this.eat(tt.dot)) {
let node = this.startNodeAt(start)
node.object = base
node.property = this.parseIdent(true)
node.computed = false
return this.parseSubscripts(this.finishNode(node, "MemberExpression"), start, noCalls)
} else if (this.eat(tt.bracketL)) {
let node = this.startNodeAt(start)
node.object = base
node.property = this.parseExpression()
node.computed = true
this.expect(tt.bracketR)
return this.parseSubscripts(this.finishNode(node, "MemberExpression"), start, noCalls)
} else if (!noCalls && this.eat(tt.parenL)) {
let node = this.startNodeAt(start)
node.callee = base
node.arguments = this.parseExprList(tt.parenR, false)
return this.parseSubscripts(this.finishNode(node, "CallExpression"), start, noCalls)
} else if (this.type === tt.backQuote) {
let node = this.startNodeAt(start)
node.tag = base
node.quasi = this.parseTemplate()
return this.parseSubscripts(this.finishNode(node, "TaggedTemplateExpression"), start, noCalls)
} return base
}
// Parse an atomic expression — either a single token that is an
// expression, an expression started by a keyword like `function` or
// `new`, or an expression wrapped in punctuation like `()`, `[]`,
// or `{}`.
pp.parseExprAtom = function(refShorthandDefaultPos) {
let node
switch (this.type) {
case tt._this:
case tt._super:
let type = this.type === tt._this ? "ThisExpression" : "Super"
node = this.startNode()
this.next()
return this.finishNode(node, type)
case tt._yield:
if (this.inGenerator) unexpected()
case tt.name:
let start = this.markPosition()
let id = this.parseIdent(this.type !== tt.name)
if (!this.canInsertSemicolon() && this.eat(tt.arrow)) {
return this.parseArrowExpression(this.startNodeAt(start), [id])
}
return id
case tt.regexp:
let value = this.value
node = this.parseLiteral(value.value)
node.regex = {pattern: value.pattern, flags: value.flags}
return node
case tt.num: case tt.string:
return this.parseLiteral(this.value)
case tt._null: case tt._true: case tt._false:
node = this.startNode()
node.value = this.type === tt._null ? null : this.type === tt._true
node.raw = this.type.keyword
this.next()
return this.finishNode(node, "Literal")
case tt.parenL:
return this.parseParenAndDistinguishExpression()
case tt.bracketL:
node = this.startNode()
this.next()
// check whether this is array comprehension or regular array
if ((this.options.ecmaVersion >= 7 || this.option.features["es7.comprehensions"]) && this.type === tt._for) {
return this.parseComprehension(node, false)
}
node.elements = this.parseExprList(tt.bracketR, true, true, refShorthandDefaultPos)
return this.finishNode(node, "ArrayExpression")
case tt.braceL:
return this.parseObj(false, refShorthandDefaultPos)
case tt._function:
node = this.startNode()
this.next()
return this.parseFunction(node, false)
case tt._class:
return this.parseClass(this.startNode(), false)
case tt._new:
return this.parseNew()
case tt.backQuote:
return this.parseTemplate()
default:
this.unexpected()
}
}
pp.parseLiteral = function(value) {
let node = this.startNode()
node.value = value
node.raw = this.input.slice(this.start, this.end)
this.next()
return this.finishNode(node, "Literal")
}
pp.parseParenExpression = function() {
this.expect(tt.parenL)
let val = this.parseExpression()
this.expect(tt.parenR)
return val
}
pp.parseParenAndDistinguishExpression = function(start, isAsync) {
start = start || this.markPosition()
var val
if (this.options.ecmaVersion >= 6) {
this.next()
if ((this.options.features["es7.comprehensions"] || this.options.ecmaVersion >= 7) && this.type === tt._for) {
return this.parseComprehension(this.startNodeAt(start), true)
}
var innerStart = this.markPosition(), exprList = [], first = true
var refShorthandDefaultPos = {start: 0}, spreadStart, innerParenStart
while (this.type !== tt.parenR) {
first ? first = false : this.expect(tt.comma)
if (this.type === tt.ellipsis) {
var spreadNodeStart = this.markPosition()
spreadStart = this.start
exprList.push(this.parseParenItem(this.parseRest(), spreadNodeStart))
break
} else {
if (this.type === tt.parenL && !innerParenStart) {
innerParenStart = this.start
}
exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem))
}
}
var innerEnd = this.markPosition()
this.expect(tt.parenR)
if (!this.canInsertSemicolon() && this.eat(tt.arrow)) {
if (innerParenStart) this.unexpected(innerParenStart)
return this.parseParenArrowList(start, exprList, isAsync)
}
if (!exprList.length) this.unexpected(this.lastTokStart)
if (spreadStart) this.unexpected(spreadStart)
if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start)
if (exprList.length > 1) {
val = this.startNodeAt(innerStart)
val.expressions = exprList
this.finishNodeAt(val, "SequenceExpression", innerEnd)
} else {
val = exprList[0]
}
} else {
val = this.parseParenExpression()
}
if (this.options.preserveParens) {
var par = this.startNodeAt(start)
par.expression = val
return this.finishNode(par, "ParenthesizedExpression")
} else {
return val
}
}
pp.parseParenArrowList = function (start, exprList, isAsync) {
return this.parseArrowExpression(this.startNodeAt(start), exprList, isAsync)
}
pp.parseParenItem = function (node, start) {
return node
}
// New's precedence is slightly tricky. It must allow its argument
// to be a `[]` or dot subscript expression, but not a call — at
// least, not without wrapping it in parentheses. Thus, it uses the
const empty = []
pp.parseNew = function() {
let node = this.startNode()
let meta = this.parseIdent(true)
if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) {
node.meta = meta
node.property = this.parseIdent(true)
if (node.property.name !== "target")
this.raise(node.property.start, "The only valid meta property for new is new.target")
return this.finishNode(node, "MetaProperty")
}
let start = this.markPosition()
node.callee = this.parseSubscripts(this.parseExprAtom(), start, true)
if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, false)
else node.arguments = empty
return this.finishNode(node, "NewExpression")
}
// Parse template expression.
pp.parseTemplateElement = function() {
let elem = this.startNode()
elem.value = {
raw: this.input.slice(this.start, this.end),
cooked: this.value
}
this.next()
elem.tail = this.type === tt.backQuote
return this.finishNode(elem, "TemplateElement")
}
pp.parseTemplate = function() {
let node = this.startNode()
this.next()
node.expressions = []
let curElt = this.parseTemplateElement()
node.quasis = [curElt]
while (!curElt.tail) {
this.expect(tt.dollarBraceL)
node.expressions.push(this.parseExpression())
this.expect(tt.braceR)
node.quasis.push(curElt = this.parseTemplateElement())
}
this.next()
return this.finishNode(node, "TemplateLiteral")
}
// Parse an object literal or binding pattern.
pp.parseObj = function(isPattern, refShorthandDefaultPos) {
let node = this.startNode(), first = true, propHash = {}
node.properties = []
this.next()
while (!this.eat(tt.braceR)) {
if (!first) {
this.expect(tt.comma)
if (this.afterTrailingComma(tt.braceR)) break
} else first = false
let prop = this.startNode(), isGenerator, start
if (this.options.ecmaVersion >= 6) {
prop.method = false
prop.shorthand = false
if (isPattern || refShorthandDefaultPos)
start = this.markPosition()
if (!isPattern)
isGenerator = this.eat(tt.star)
}
this.parsePropertyName(prop)
if (this.eat(tt.colon)) {
prop.value = isPattern ? this.parseMaybeDefault() : this.parseMaybeAssign(false, refShorthandDefaultPos)
prop.kind = "init"
} else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) {
if (isPattern) this.unexpected()
prop.kind = "init"
prop.method = true
prop.value = this.parseMethod(isGenerator)
} else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" &&
(prop.key.name === "get" || prop.key.name === "set") &&
(this.type != tt.comma && this.type != tt.braceR)) {
if (isGenerator || isPattern) this.unexpected()
prop.kind = prop.key.name
this.parsePropertyName(prop)
prop.value = this.parseMethod(false)
} else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") {
prop.kind = "init"
if (isPattern) {
if (this.isKeyword(prop.key.name) ||
(this.strict && (reservedWords.strictBind(prop.key.name) || reservedWords.strict(prop.key.name))) ||
(!this.options.allowReserved && this.isReservedWord(prop.key.name)))
this.raise(prop.key.start, "Binding " + prop.key.name)
prop.value = this.parseMaybeDefault(start, prop.key)
} else if (this.type === tt.eq && refShorthandDefaultPos) {
if (!refShorthandDefaultPos.start)
refShorthandDefaultPos.start = this.start
prop.value = this.parseMaybeDefault(start, prop.key)
} else {
prop.value = prop.key
}
prop.shorthand = true
} else this.unexpected()
this.checkPropClash(prop, propHash)
node.properties.push(this.finishNode(prop, "Property"))
}
return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression")
}
pp.parsePropertyName = function(prop) {
if (this.options.ecmaVersion >= 6) {
if (this.eat(tt.bracketL)) {
prop.computed = true
prop.key = this.parseMaybeAssign()
this.expect(tt.bracketR)
return
} else {
prop.computed = false
}
}
prop.key = (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true)
}
// Initialize empty function node.
pp.initFunction = function(node) {
node.id = null
if (this.options.ecmaVersion >= 6) {
node.generator = false
node.expression = false
}
}
// Parse object or class method.
pp.parseMethod = function(isGenerator) {
let node = this.startNode()
this.initFunction(node)
this.expect(tt.parenL)
node.params = this.parseBindingList(tt.parenR, false, false)
let allowExpressionBody
if (this.options.ecmaVersion >= 6) {
node.generator = isGenerator
allowExpressionBody = true
} else {
allowExpressionBody = false
}
this.parseFunctionBody(node, allowExpressionBody)
return this.finishNode(node, "FunctionExpression")
}
// Parse arrow function expression with given parameters.
pp.parseArrowExpression = function(node, params) {
this.initFunction(node)
node.params = this.toAssignableList(params, true)
this.parseFunctionBody(node, true)
return this.finishNode(node, "ArrowFunctionExpression")
}
// Parse function body and check parameters.
pp.parseFunctionBody = function(node, allowExpression) {
let isExpression = allowExpression && this.type !== tt.braceL
if (isExpression) {
node.body = this.parseMaybeAssign()
node.expression = true
} else {
// Start a new scope with regard to labels and the `inFunction`
// flag (restore them to their old value afterwards).
let oldInFunc = this.inFunction, oldInGen = this.inGenerator, oldLabels = this.labels
this.inFunction = true; this.inGenerator = node.generator; this.labels = []
node.body = this.parseBlock(true)
node.expression = false
this.inFunction = oldInFunc; this.inGenerator = oldInGen; this.labels = oldLabels
}
// If this is a strict mode function, verify that argument names
// are not repeated, and it does not try to bind the words `eval`
// or `arguments`.
if (this.strict || !isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) {
let nameHash = {}, oldStrict = this.strict
this.strict = true
if (node.id)
this.checkLVal(node.id, true)
for (let i = 0; i < node.params.length; i++)
this.checkLVal(node.params[i], true, nameHash)
this.strict = oldStrict
}
}
// Parses a comma-separated list of expressions, and returns them as
// an array. `close` is the token type that ends the list, and
// `allowEmpty` can be turned on to allow subsequent commas with
// nothing in between them to be parsed as `null` (which is needed
// for array literals).
pp.parseExprList = function(close, allowTrailingComma, allowEmpty, refShorthandDefaultPos) {
let elts = [], first = true
while (!this.eat(close)) {
if (!first) {
this.expect(tt.comma)
if (allowTrailingComma && this.afterTrailingComma(close)) break
} else first = false
if (allowEmpty && this.type === tt.comma) {
elts.push(null)
} else {
if (this.type === tt.ellipsis)
elts.push(this.parseSpread(refShorthandDefaultPos))
else
elts.push(this.parseMaybeAssign(false, refShorthandDefaultPos))
}
}
return elts
}
// Parse the next token as an identifier. If `liberal` is true (used
// when parsing properties), it will also convert keywords into
// identifiers.
pp.parseIdent = function(liberal) {
let node = this.startNode()
if (liberal && this.options.allowReserved == "never") liberal = false
if (this.type === tt.name) {
if (!liberal &&
((!this.options.allowReserved && this.isReservedWord(this.value)) ||
(this.strict && reservedWords.strict(this.value)) &&
(this.options.ecmaVersion >= 6 ||
this.input.slice(this.start, this.end).indexOf("\\") == -1)))
this.raise(this.start, "The keyword '" + this.value + "' is reserved")
node.name = this.value
} else if (liberal && this.type.keyword) {
node.name = this.type.keyword
} else {
this.unexpected()
}
this.next()
return this.finishNode(node, "Identifier")
}
// Parses yield expression inside generator.
pp.parseYield = function() {
let node = this.startNode()
this.next()
if (this.type == tt.semi || this.canInsertSemicolon() || (this.type != tt.star && !this.type.startsExpr)) {
node.delegate = false
node.argument = null
} else {
node.delegate = this.eat(tt.star)
node.argument = this.parseMaybeAssign()
}
return this.finishNode(node, "YieldExpression")
}
// Parses array and generator comprehensions.
pp.parseComprehension = function(node, isGenerator) {
node.blocks = []
while (this.type === tt._for) {
let block = this.startNode()
this.next()
this.expect(tt.parenL)
block.left = this.parseBindingAtom()
this.checkLVal(block.left, true)
this.expectContextual("of")
block.right = this.parseExpression()
this.expect(tt.parenR)
node.blocks.push(this.finishNode(block, "ComprehensionBlock"))
}
node.filter = this.eat(tt._if) ? this.parseParenExpression() : null
node.body = this.parseExpression()
this.expect(isGenerator ? tt.parenR : tt.bracketR)
node.generator = isGenerator
return this.finishNode(node, "ComprehensionExpression")
}

View File

@ -1,112 +0,0 @@
(function() {
var driver, acorn;
if (typeof require !== "undefined") {
driver = require("./driver.js");
require("./tests.js");
require("./tests-harmony.js");
require("babel/register")
acorn = require("../src")
} else {
driver = window;
acorn = window.acorn;
}
var htmlLog = typeof document === "object" && document.getElementById('log');
var htmlGroup = htmlLog;
function group(name) {
if (htmlGroup) {
var parentGroup = htmlGroup;
htmlGroup = document.createElement("ul");
var item = document.createElement("li");
item.textContent = name;
item.appendChild(htmlGroup);
parentGroup.appendChild(item);
}
if (typeof console === "object" && console.group) {
console.group(name);
}
}
function groupEnd() {
if (htmlGroup) {
htmlGroup = htmlGroup.parentElement.parentElement;
}
if (typeof console === "object" && console.groupEnd) {
console.groupEnd(name);
}
}
function log(title, message) {
if (htmlGroup) {
var elem = document.createElement("li");
elem.innerHTML = "<b>" + title + "</b> " + message;
htmlGroup.appendChild(elem);
}
if (typeof console === "object") console.log(title, message);
}
var stats, modes = {
Normal: {
config: {
parse: acorn.parse
}
},
Loose: {
config: {
parse: acorn.parse_dammit,
loose: true,
filter: function (test) {
var opts = test.options || {};
if (opts.loose === false) return false;
return (opts.ecmaVersion || 5) <= 6;
}
}
}
};
function report(state, code, message) {
if (state != "ok") {++stats.failed; log(code, message);}
++stats.testsRun;
}
group("Errors");
for (var name in modes) {
group(name);
var mode = modes[name];
stats = mode.stats = {testsRun: 0, failed: 0};
var t0 = +new Date;
driver.runTests(mode.config, report);
mode.stats.duration = +new Date - t0;
groupEnd();
}
groupEnd();
function outputStats(name, stats) {
log(name + ":", stats.testsRun + " tests run in " + stats.duration + "ms; " +
(stats.failed ? stats.failed + " failures." : "all passed."));
}
var total = {testsRun: 0, failed: 0, duration: 0};
group("Stats");
for (var name in modes) {
var stats = modes[name].stats;
outputStats(name + " parser", stats);
for (var key in stats) total[key] += stats[key];
}
outputStats("Total", total);
groupEnd();
if (total.failed && typeof process === "object") {
process.stdout.write("", function() {
process.exit(1);
});
}
})();

View File

@ -1,96 +0,0 @@
<!doctype html>
<head>
<meta charset="utf-8">
<title>Acorn benchmark</title>
<script src="../acorn.js"></script>
<script src="compare/esprima.js"></script>
<script src="compare/traceur.js"></script>
<script src="jquery-string.js"></script>
<script src="codemirror-string.js"></script>
<style>
td { text-align: right; padding-right: 20px; }
th { text-align: left; padding-right: 40px; }
body { max-width: 50em; padding: 1em 2em; }
h1 { font-size: 150%; }
</style>
</head>
<h1>Acorn/Esprima/Traceur speed comparison</h1>
<p>This will run each of the three ES6 parsers on the source code of
jQuery 1.11.1 and CodeMirror 3.0b1 for five seconds, and show a table
indicating the number of lines parsed per second. Note that Traceur
always stores location data, and is thus not fairly compared by the
benchmark <em>without</em> location data.<p>
<p>Also note that having the developer tools open in Chrome, or
Firebug in Firefox <em>heavily</em> influences the numbers you get. In
Chrome, the effect even lingers (in the tab) after you close the
developer tools. Load in a fresh tab to get (halfway) stable
numbers.</p>
<button onclick="run(false)">Compare <strong>without</strong> location data</button>
<button onclick="run(true)">Compare <strong>with</strong> location data</button>
<button onclick="run(false, true)">Run only Acorn</button>
<span id="running"></span>
<script>
var sourceFileName = 'source.js';
function runAcorn(code, locations) {
acorn.parse(code, {ecmaVersion: 6, locations: locations, sourceFile: sourceFileName});
}
function runEsprima(code, locations) {
esprima.parse(code, {loc: locations, source: sourceFileName});
}
function runTraceur(code) {
var file = new traceur.syntax.SourceFile(sourceFileName, code);
var parser = new traceur.syntax.Parser(file);
parser.parseScript();
}
var totalLines = codemirror30.split("\n").length + jquery111.split("\n").length;
var nowHost = (typeof performance === 'object' && 'now' in performance) ? performance : Date;
function benchmark(runner, locations) {
// Give it a chance to warm up (first runs are usually outliers)
runner(jquery111, locations);
runner(codemirror30, locations);
var t0 = nowHost.now(), t1, lines = 0;
for (;;) {
runner(jquery111, locations);
runner(codemirror30, locations);
lines += totalLines;
t1 = nowHost.now();
if (t1 - t0 > 5000) break;
}
return lines / ((t1 - t0) / 1000);
}
function showOutput(values) {
var html = "<hr><table>";
for (var i = 0; i < values.length; ++i)
html += "<tr><th>" + values[i].name + "</td><td>" + Math.round(values[i].score) + " lines per second</td><td>" +
Math.round(values[i].score * 100 / values[0].score) + "%</td></tr>";
document.body.appendChild(document.createElement("div")).innerHTML = html;
}
function run(locations, acornOnly) {
var running = document.getElementById("running");
running.innerHTML = "Running benchmark...";
var data = [{name: "Acorn", runner: runAcorn},
{name: "Esprima", runner: runEsprima},
{name: "Traceur", runner: runTraceur}];
if (acornOnly) data.length = 1;
var pos = 0;
function next() {
data[pos].score = benchmark(data[pos].runner, locations);
if (++pos == data.length) {
running.innerHTML = "";
showOutput(data);
} else setTimeout(next, 100);
}
setTimeout(next, 50);
}
</script>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,14 +0,0 @@
<!doctype html>
<head>
<meta charset="utf-8">
<title>Acorn test suite</title>
<script src="../dist/acorn.js"></script>
<script src="../dist/acorn_loose.js"></script>
<script src="driver.js"></script>
<script src="tests.js" charset="utf-8"></script>
<script src="tests-harmony.js" charset="utf-8"></script>
</head>
<body>
<ul id="log"></ul>
<script src="run.js"></script>
</body>

File diff suppressed because one or more lines are too long