* root ast

* updated grammar

* preserve CoffeeScript.nodes() API

* root ast methods

* try ast

* updated grammar

* updated grammar

* updated grammar

* updated grammar

* finally location data

* remove unused

* updates from code review
This commit is contained in:
Julian Rosse 2019-01-18 14:57:04 -05:00 committed by Geoffrey Booth
parent 38c8b2f35f
commit a7b1fa51e7
8 changed files with 737 additions and 271 deletions

View File

@ -1292,40 +1292,38 @@
o('TRY Block Catch',
function() {
return new Try($2,
$3[0],
$3[1]);
$3);
}),
o('TRY Block FINALLY Block',
function() {
return new Try($2,
null,
null,
$4);
$4,
LOC(3)(new Literal($3)));
}),
o('TRY Block Catch FINALLY Block',
function() {
return new Try($2,
$3[0],
$3[1],
$5);
$3,
$5,
LOC(4)(new Literal($4)));
})
],
// A catch clause names its error and runs a block of code.
Catch: [
o('CATCH Identifier Block',
function() {
return [$2,
$3];
return new Catch($3,
$2);
}),
o('CATCH Object Block',
function() {
return [LOC(2)(new Value($2)),
$3];
return new Catch($3,
LOC(2)(new Value($2)));
}),
o('CATCH Block',
function() {
return [null,
$2];
return new Catch($2);
})
],
// Throw an exception object.

View File

@ -4,7 +4,7 @@
// nodes are created as the result of actions in the [grammar](grammar.html),
// but some are created by other nodes as a method of code generation. To convert
// the syntax tree into a string of JavaScript code, call `compile()` on the root.
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXAttribute, CSXAttributes, CSXElement, CSXExpressionContainer, CSXIdentifier, CSXTag, Call, Class, Code, CodeFragment, ComputedPropertyName, DefaultLiteral, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncGlyph, HEREGEX_OMIT, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, Interpolation, JS_FORBIDDEN, LEADING_BLANK_LINE, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, ObjectProperty, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, Root, SIMPLENUM, SIMPLE_STRING_OMIT, STRING_OMIT, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, TAB, THIS, TRAILING_BLANK_LINE, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, greater, hasLineComments, indentInitial, isFunction, isLiteralArguments, isLiteralThis, isNumber, isPlainObject, isUnassignable, jisonLocationDataToAstLocationData, lesser, locationDataToString, makeDelimitedLiteral, merge, mergeAstLocationData, mergeLocationData, moveComments, multident, replaceUnicodeCodePointEscapes, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
var Access, Arr, Assign, AwaitReturn, Base, Block, BooleanLiteral, CSXAttribute, CSXAttributes, CSXElement, CSXExpressionContainer, CSXIdentifier, CSXTag, Call, Catch, Class, Code, CodeFragment, ComputedPropertyName, DefaultLiteral, Elision, ExecutableClassBody, Existence, Expansion, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, ExportSpecifier, ExportSpecifierList, Extends, For, FuncGlyph, HEREGEX_OMIT, HereComment, HoistTarget, IdentifierLiteral, If, ImportClause, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ImportSpecifierList, In, Index, InfinityLiteral, Interpolation, JS_FORBIDDEN, LEADING_BLANK_LINE, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, LineComment, Literal, ModuleDeclaration, ModuleSpecifier, ModuleSpecifierList, NEGATE, NO, NaNLiteral, NullLiteral, NumberLiteral, Obj, ObjectProperty, Op, Param, Parens, PassthroughLiteral, PropertyName, Range, RegexLiteral, RegexWithInterpolations, Return, Root, SIMPLENUM, SIMPLE_STRING_OMIT, STRING_OMIT, Scope, Slice, Splat, StatementLiteral, StringLiteral, StringWithInterpolations, Super, SuperCall, Switch, TAB, THIS, TRAILING_BLANK_LINE, TaggedTemplateCall, ThisLiteral, Throw, Try, UTILITIES, UndefinedLiteral, Value, While, YES, YieldReturn, addDataToNode, attachCommentsToNode, compact, del, ends, extend, flatten, fragmentsToText, greater, hasLineComments, indentInitial, isFunction, isLiteralArguments, isLiteralThis, isNumber, isPlainObject, isUnassignable, jisonLocationDataToAstLocationData, lesser, locationDataToString, makeDelimitedLiteral, merge, mergeAstLocationData, mergeLocationData, moveComments, multident, replaceUnicodeCodePointEscapes, shouldCacheOrIsAssignable, some, starts, throwSyntaxError, unfoldSoak, unshiftAfterComments, utility,
indexOf = [].indexOf,
splice = [].splice,
slice1 = [].slice;
@ -363,7 +363,7 @@
// as JSON. This is what the `ast` option in the Node API returns.
// We try to follow the [Babel AST spec](https://github.com/babel/babel/blob/master/packages/babel-parser/ast/spec.md)
// as closely as possible, for improved interoperability with other tools.
ast() {
ast(o) {
// Every abstract syntax tree node object has four categories of properties:
// - type, stored in the `type` field and a string like `NumberLiteral`.
// - location data, stored in the `loc`, `start`, `end` and `range` fields.
@ -372,9 +372,9 @@
// These fields are all intermixed in the Babel spec; `type` and `start` and
// `parsedValue` are all top level fields in the AST node object. We have
// separate methods for returning each category, that we merge together here.
return Object.assign({}, this.astProperties(), {
return Object.assign({}, {
type: this.astType()
}, this.astLocationData());
}, this.astProperties(o), this.astLocationData());
}
// By default, a node class has no specific properties.
@ -689,9 +689,10 @@
return 'File';
}
astProperties() {
astProperties(o) {
this.body.isRootBlock = true;
return {
program: Object.assign(this.body.ast(), this.astLocationData()),
program: Object.assign(this.body.ast(o), this.astLocationData()),
comments: []
};
}
@ -1085,7 +1086,11 @@
}
astType() {
return 'Program';
if (this.isRootBlock) {
return 'Program';
} else {
return 'BlockStatement';
}
}
astProperties(o) {
@ -1096,12 +1101,12 @@
expression = ref1[j];
// If an expression is a statement, it can be added to the body as is.
if (expression.isStatement(o)) {
body.push(expression.ast());
body.push(expression.ast(o));
} else {
// Otherwise, we need to wrap it in an `ExpressionStatement` AST node.
body.push(Object.assign({
type: 'ExpressionStatement',
expression: expression.ast()
expression: expression.ast(o)
}, expression.astLocationData()));
}
}
@ -1434,8 +1439,8 @@
return [this.makeCode('['), ...this.value.compileToFragments(o, LEVEL_LIST), this.makeCode(']')];
}
ast() {
return this.value.ast();
ast(o) {
return this.value.ast(o);
}
};
@ -1924,15 +1929,15 @@
return object;
}
ast() {
ast(o) {
if (!this.hasProperties()) {
// If the `Value` has no properties, the AST node is just whatever this
// nodes `base` is.
return this.base.ast();
return this.base.ast(o);
}
// Otherwise, call `Base::ast` which in turn calls the `astType` and
// `astProperties` methods below.
return super.ast();
return super.ast(o);
}
astType() {
@ -1946,15 +1951,15 @@
// If this `Value` has properties, the *last* property (e.g. `c` in `a.b.c`)
// becomes the `property`, and the preceding properties (e.g. `a.b`) become
// a child `Value` node assigned to the `object` property.
astProperties() {
astProperties(o) {
var property, ref1, ref2;
ref1 = this.properties, [property] = slice1.call(ref1, -1);
if (this.isCSXTag()) {
property.name.csx = true;
}
return {
object: this.object().ast(),
property: property.ast(),
object: this.object().ast(o),
property: property.ast(o),
computed: property instanceof Index || !(((ref2 = property.name) != null ? ref2.unwrap() : void 0) instanceof PropertyName),
optional: !!property.soak,
shorthand: !!property.shorthand
@ -2249,7 +2254,7 @@
return !this.tagName.base.value.length;
}
ast() {
ast(o) {
var tagName;
// The location data spanning the opening element < ... > is captured by
// the generated Arr which contains the element's attributes
@ -2259,7 +2264,7 @@
if (this.content != null) {
this.closingElementLocationData = mergeAstLocationData(jisonLocationDataToAstLocationData(tagName.closingTagOpeningBracketLocationData), jisonLocationDataToAstLocationData(tagName.closingTagClosingBracketLocationData));
}
return super.ast();
return super.ast(o);
}
astType() {
@ -2270,19 +2275,19 @@
}
}
elementAstProperties() {
elementAstProperties(o) {
var closingElement, currentExpr, openingElement, rangeDiff, shiftAstLocationData;
openingElement = Object.assign({
type: 'JSXOpeningElement',
name: this.tagName.unwrap().ast(),
name: this.tagName.unwrap().ast(o),
selfClosing: this.closingElementLocationData == null,
attributes: this.attributes.ast()
attributes: this.attributes.ast(o)
}, this.openingElementLocationData);
closingElement = null;
if (this.closingElementLocationData != null) {
closingElement = Object.assign({
type: 'JSXClosingElement',
name: Object.assign(this.tagName.unwrap().ast(), jisonLocationDataToAstLocationData(this.tagName.base.closingTagNameLocationData))
name: Object.assign(this.tagName.unwrap().ast(o), jisonLocationDataToAstLocationData(this.tagName.base.closingTagNameLocationData))
}, this.closingElementLocationData);
if (closingElement.name.type === 'JSXMemberExpression') {
rangeDiff = closingElement.range[0] - openingElement.range[0] + '/'.length;
@ -2313,7 +2318,7 @@
return {openingElement, closingElement};
}
fragmentAstProperties() {
fragmentAstProperties(o) {
var closingFragment, openingFragment;
openingFragment = Object.assign({
type: 'JSXOpeningFragment'
@ -2324,8 +2329,8 @@
return {openingFragment, closingFragment};
}
astProperties() {
return Object.assign(this.isFragment() ? this.fragmentAstProperties() : this.elementAstProperties(), {
astProperties(o) {
return Object.assign(this.isFragment() ? this.fragmentAstProperties(o) : this.elementAstProperties(o), {
children: []
});
}
@ -2532,17 +2537,17 @@
}
}
astProperties() {
astProperties(o) {
var arg;
return {
callee: this.variable.ast(),
callee: this.variable.ast(o),
arguments: (function() {
var j, len1, ref1, results;
ref1 = this.args;
results = [];
for (j = 0, len1 = ref1.length; j < len1; j++) {
arg = ref1[j];
results.push(arg.ast());
results.push(arg.ast(o));
}
return results;
}).call(this),
@ -2729,11 +2734,11 @@
}
}
ast() {
ast(o) {
// Babel doesnt have an AST node for `Access`, but rather just includes
// this Access nodes child `name` Identifier node as the `property` of
// the `MemberExpression` node.
return this.name.ast();
return this.name.ast(o);
}
};
@ -2764,13 +2769,13 @@
return this.index.shouldCache();
}
ast() {
ast(o) {
// Babel doesnt have an AST node for `Index`, but rather just includes
// this Index nodes child `index` Identifier node as the `property` of
// the `MemberExpression` node. The fact that the `MemberExpression`s
// `property` is an Index means that `computed` is `true` for the
// `MemberExpression`.
return this.index.ast();
return this.index.ast(o);
}
};
@ -2900,11 +2905,11 @@
return [this.makeCode(`(function() {${pre}\n${idt}for (${body})${post}}).apply(this${args != null ? args : ''})`)];
}
astProperties() {
astProperties(o) {
var ref1, ref2, ref3, ref4;
return {
from: (ref1 = (ref2 = this.from) != null ? ref2.ast() : void 0) != null ? ref1 : null,
to: (ref3 = (ref4 = this.to) != null ? ref4.ast() : void 0) != null ? ref3 : null,
from: (ref1 = (ref2 = this.from) != null ? ref2.ast(o) : void 0) != null ? ref1 : null,
to: (ref3 = (ref4 = this.to) != null ? ref4.ast(o) : void 0) != null ? ref3 : null,
exclusive: this.exclusive
};
}
@ -2953,8 +2958,8 @@
return [this.makeCode(`.slice(${fragmentsToText(fromCompiled)}${toStr || ''})`)];
}
ast() {
return this.range.ast();
ast(o) {
return this.range.ast(o);
}
};
@ -3234,7 +3239,7 @@
}
}
astProperties() {
astProperties(o) {
var property;
return {
implicit: !!this.generated,
@ -3244,7 +3249,7 @@
results = [];
for (j = 0, len1 = ref1.length; j < len1; j++) {
property = ref1[j];
results.push(property.ast());
results.push(property.ast(o));
}
return results;
}).call(this)
@ -3286,13 +3291,13 @@
}
}
astProperties() {
astProperties(o) {
var isComputedPropertyName, keyAst, ref1, ref2;
isComputedPropertyName = this.key instanceof Value && this.key.base instanceof ComputedPropertyName;
keyAst = this.key.ast();
keyAst = this.key.ast(o);
return {
key: keyAst,
value: (ref1 = (ref2 = this.value) != null ? ref2.ast() : void 0) != null ? ref1 : keyAst,
value: (ref1 = (ref2 = this.value) != null ? ref2.ast(o) : void 0) != null ? ref1 : keyAst,
shorthand: !!this.shorthand,
computed: !!isComputedPropertyName,
method: false
@ -3493,7 +3498,7 @@
}
}
astProperties() {
astProperties(o) {
var object;
return {
elements: (function() {
@ -3502,7 +3507,7 @@
results = [];
for (j = 0, len1 = ref1.length; j < len1; j++) {
object = ref1[j];
results.push(object.ast());
results.push(object.ast(o));
}
return results;
}).call(this)
@ -4003,11 +4008,11 @@
return code;
}
astProperties() {
astProperties(o) {
var ref1, ref2, ret;
ret = {
specifiers: (ref1 = (ref2 = this.clause) != null ? ref2.ast() : void 0) != null ? ref1 : [],
source: this.source.ast()
specifiers: (ref1 = (ref2 = this.clause) != null ? ref2.ast(o) : void 0) != null ? ref1 : [],
source: this.source.ast(o)
};
if (this.clause) {
ret.importKind = 'value';
@ -4040,11 +4045,11 @@
return code;
}
ast() {
ast(o) {
var ref1, ref2;
// The AST for `ImportClause` is the non-nested list of import specifiers
// that will be the `specifiers` property of an `ImportDeclaration` AST
return compact(flatten([(ref1 = this.defaultBinding) != null ? ref1.ast() : void 0, (ref2 = this.namedImports) != null ? ref2.ast() : void 0]));
return compact(flatten([(ref1 = this.defaultBinding) != null ? ref1.ast(o) : void 0, (ref2 = this.namedImports) != null ? ref2.ast(o) : void 0]));
}
};
@ -4087,13 +4092,13 @@
};
exports.ExportNamedDeclaration = ExportNamedDeclaration = class ExportNamedDeclaration extends ExportDeclaration {
astProperties() {
astProperties(o) {
var clauseAst, ref1, ref2, ret;
ret = {
source: (ref1 = (ref2 = this.source) != null ? ref2.ast() : void 0) != null ? ref1 : null,
source: (ref1 = (ref2 = this.source) != null ? ref2.ast(o) : void 0) != null ? ref1 : null,
exportKind: 'value'
};
clauseAst = this.clause.ast();
clauseAst = this.clause.ast(o);
if (this.clause instanceof ExportSpecifierList) {
ret.specifiers = clauseAst;
ret.declaration = null;
@ -4107,18 +4112,18 @@
};
exports.ExportDefaultDeclaration = ExportDefaultDeclaration = class ExportDefaultDeclaration extends ExportDeclaration {
astProperties() {
astProperties(o) {
return {
declaration: this.clause.ast()
declaration: this.clause.ast(o)
};
}
};
exports.ExportAllDeclaration = ExportAllDeclaration = class ExportAllDeclaration extends ExportDeclaration {
astProperties() {
astProperties(o) {
return {
source: this.source.ast(),
source: this.source.ast(o),
exportKind: 'value'
};
}
@ -4162,13 +4167,13 @@
return code;
}
ast() {
ast(o) {
var j, len1, ref1, results, specifier;
ref1 = this.specifiers;
results = [];
for (j = 0, len1 = ref1.length; j < len1; j++) {
specifier = ref1[j];
results.push(specifier.ast());
results.push(specifier.ast(o));
}
return results;
}
@ -4242,12 +4247,12 @@
return super.compileNode(o);
}
astProperties() {
astProperties(o) {
var originalAst, ref1, ref2;
originalAst = this.original.ast();
originalAst = this.original.ast(o);
return {
imported: originalAst,
local: (ref1 = (ref2 = this.alias) != null ? ref2.ast() : void 0) != null ? ref1 : originalAst,
local: (ref1 = (ref2 = this.alias) != null ? ref2.ast(o) : void 0) != null ? ref1 : originalAst,
importKind: null
};
}
@ -4255,18 +4260,18 @@
};
exports.ImportDefaultSpecifier = ImportDefaultSpecifier = class ImportDefaultSpecifier extends ImportSpecifier {
astProperties() {
astProperties(o) {
return {
local: this.original.ast()
local: this.original.ast(o)
};
}
};
exports.ImportNamespaceSpecifier = ImportNamespaceSpecifier = class ImportNamespaceSpecifier extends ImportSpecifier {
astProperties() {
astProperties(o) {
return {
local: this.alias.ast()
local: this.alias.ast(o)
};
}
@ -4277,12 +4282,12 @@
super(local, exported, 'export');
}
astProperties() {
astProperties(o) {
var originalAst, ref1, ref2;
originalAst = this.original.ast();
originalAst = this.original.ast(o);
return {
local: originalAst,
exported: (ref1 = (ref2 = this.alias) != null ? ref2.ast() : void 0) != null ? ref1 : originalAst
exported: (ref1 = (ref2 = this.alias) != null ? ref2.ast(o) : void 0) != null ? ref1 : originalAst
};
}
@ -4794,11 +4799,11 @@
}
}
astProperties() {
astProperties(o) {
var ref1, ret;
ret = {
right: this.value.ast(),
left: this.variable.ast()
right: this.value.ast(o),
left: this.variable.ast(o)
};
if (!this.isDefaultAssignment()) {
ret.operator = (ref1 = this.originalContext) != null ? ref1 : '=';
@ -5470,9 +5475,9 @@
}
}
astProperties() {
astProperties(o) {
return {
argument: this.name.ast(),
argument: this.name.ast(o),
postfix: this.postfix
};
}
@ -5946,10 +5951,10 @@
}
}
astProperties() {
astProperties(o) {
var firstAst, ref1, secondAst;
firstAst = this.first.ast();
secondAst = (ref1 = this.second) != null ? ref1.ast() : void 0;
firstAst = this.first.ast(o);
secondAst = (ref1 = this.second) != null ? ref1.ast(o) : void 0;
switch (false) {
case !this.isUnary():
return {
@ -6071,25 +6076,25 @@
// A classic *try/catch/finally* block.
exports.Try = Try = (function() {
class Try extends Base {
constructor(attempt, errorVariable, recovery, ensure) {
constructor(attempt, _catch, ensure, finallyTag) {
super();
this.attempt = attempt;
this.errorVariable = errorVariable;
this.recovery = recovery;
this.catch = _catch;
this.ensure = ensure;
this.finallyTag = finallyTag;
}
jumps(o) {
var ref1;
return this.attempt.jumps(o) || ((ref1 = this.recovery) != null ? ref1.jumps(o) : void 0);
return this.attempt.jumps(o) || ((ref1 = this.catch) != null ? ref1.jumps(o) : void 0);
}
makeReturn(res) {
if (this.attempt) {
this.attempt = this.attempt.makeReturn(res);
}
if (this.recovery) {
this.recovery = this.recovery.makeReturn(res);
if (this.catch) {
this.catch = this.catch.makeReturn(res);
}
return this;
}
@ -6097,21 +6102,36 @@
// Compilation is more or less as you would expect -- the *finally* clause
// is optional, the *catch* is not.
compileNode(o) {
var catchPart, ensurePart, generatedErrorVariableName, message, placeholder, tryPart;
var catchPart, ensurePart, generatedErrorVariableName, originalIndent, tryPart;
originalIndent = o.indent;
o.indent += TAB;
tryPart = this.attempt.compileToFragments(o, LEVEL_TOP);
catchPart = this.recovery ? (generatedErrorVariableName = o.scope.freeVariable('error', {
reserve: false
}), placeholder = new IdentifierLiteral(generatedErrorVariableName), this.errorVariable ? (message = isUnassignable(this.errorVariable.unwrapAll().value), message ? this.errorVariable.error(message) : void 0, this.recovery.unshift(new Assign(this.errorVariable, placeholder))) : void 0, [].concat(this.makeCode(" catch ("), placeholder.compileToFragments(o), this.makeCode(") {\n"), this.recovery.compileToFragments(o, LEVEL_TOP), this.makeCode(`\n${this.tab}}`))) : !(this.ensure || this.recovery) ? (generatedErrorVariableName = o.scope.freeVariable('error', {
catchPart = this.catch ? this.catch.compileToFragments(merge(o, {
indent: originalIndent
}), LEVEL_TOP) : !(this.ensure || this.catch) ? (generatedErrorVariableName = o.scope.freeVariable('error', {
reserve: false
}), [this.makeCode(` catch (${generatedErrorVariableName}) {}`)]) : [];
ensurePart = this.ensure ? [].concat(this.makeCode(" finally {\n"), this.ensure.compileToFragments(o, LEVEL_TOP), this.makeCode(`\n${this.tab}}`)) : [];
return [].concat(this.makeCode(`${this.tab}try {\n`), tryPart, this.makeCode(`\n${this.tab}}`), catchPart, ensurePart);
}
astType() {
return 'TryStatement';
}
astProperties(o) {
var ref1, ref2;
return {
block: this.attempt.ast(o),
handler: (ref1 = (ref2 = this.catch) != null ? ref2.ast(o) : void 0) != null ? ref1 : null,
// Include `finally` keyword in location data.
finalizer: this.ensure != null ? Object.assign(this.ensure.ast(o), mergeAstLocationData(jisonLocationDataToAstLocationData(this.finallyTag.locationData), this.ensure.astLocationData())) : null
};
}
};
Try.prototype.children = ['attempt', 'recovery', 'ensure'];
Try.prototype.children = ['attempt', 'catch', 'ensure'];
Try.prototype.isStatement = YES;
@ -6119,6 +6139,68 @@
}).call(this);
exports.Catch = Catch = (function() {
class Catch extends Base {
constructor(recovery, errorVariable) {
var base1, ref1;
super();
this.recovery = recovery;
this.errorVariable = errorVariable;
if ((ref1 = this.errorVariable) != null) {
if (typeof (base1 = ref1.unwrap()).propagateLhs === "function") {
base1.propagateLhs(true);
}
}
}
jumps(o) {
return this.recovery.jumps(o);
}
makeReturn(res) {
this.recovery = this.recovery.makeReturn(res);
return this;
}
compileNode(o) {
var generatedErrorVariableName, message, placeholder;
o.indent += TAB;
generatedErrorVariableName = o.scope.freeVariable('error', {
reserve: false
});
placeholder = new IdentifierLiteral(generatedErrorVariableName);
if (this.errorVariable) {
message = isUnassignable(this.errorVariable.unwrapAll().value);
if (message) {
this.errorVariable.error(message);
}
this.recovery.unshift(new Assign(this.errorVariable, placeholder));
}
return [].concat(this.makeCode(" catch ("), placeholder.compileToFragments(o), this.makeCode(") {\n"), this.recovery.compileToFragments(o, LEVEL_TOP), this.makeCode(`\n${this.tab}}`));
}
astType() {
return 'CatchClause';
}
astProperties(o) {
var ref1, ref2;
return {
param: (ref1 = (ref2 = this.errorVariable) != null ? ref2.ast(o) : void 0) != null ? ref1 : null,
body: this.recovery.ast(o)
};
}
};
Catch.prototype.children = ['recovery', 'errorVariable'];
Catch.prototype.isStatement = YES;
return Catch;
}).call(this);
//### Throw
// Simple node to throw an exception.
@ -6142,9 +6224,9 @@
return 'ThrowStatement';
}
astProperties() {
astProperties(o) {
return {
argument: this.expression.ast()
argument: this.expression.ast(o)
};
}
@ -6217,9 +6299,9 @@
return 'UnaryExpression';
}
astProperties() {
astProperties(o) {
return {
argument: this.expression.ast(),
argument: this.expression.ast(o),
operator: '?',
prefix: false
};
@ -6284,8 +6366,8 @@
}
}
ast() {
return this.body.unwrap().ast();
ast(o) {
return this.body.unwrap().ast(o);
}
};

File diff suppressed because one or more lines are too long

View File

@ -629,16 +629,16 @@ grammar =
# The variants of *try/catch/finally* exception handling blocks.
Try: [
o 'TRY Block', -> new Try $2
o 'TRY Block Catch', -> new Try $2, $3[0], $3[1]
o 'TRY Block FINALLY Block', -> new Try $2, null, null, $4
o 'TRY Block Catch FINALLY Block', -> new Try $2, $3[0], $3[1], $5
o 'TRY Block Catch', -> new Try $2, $3
o 'TRY Block FINALLY Block', -> new Try $2, null, $4, LOC(3)(new Literal $3)
o 'TRY Block Catch FINALLY Block', -> new Try $2, $3, $5, LOC(4)(new Literal $4)
]
# A catch clause names its error and runs a block of code.
Catch: [
o 'CATCH Identifier Block', -> [$2, $3]
o 'CATCH Object Block', -> [LOC(2)(new Value($2)), $3]
o 'CATCH Block', -> [null, $2]
o 'CATCH Identifier Block', -> new Catch $3, $2
o 'CATCH Object Block', -> new Catch $3, LOC(2)(new Value($2))
o 'CATCH Block', -> new Catch $2
]
# Throw an exception object.

View File

@ -270,7 +270,7 @@ exports.Base = class Base
# as JSON. This is what the `ast` option in the Node API returns.
# We try to follow the [Babel AST spec](https://github.com/babel/babel/blob/master/packages/babel-parser/ast/spec.md)
# as closely as possible, for improved interoperability with other tools.
ast: ->
ast: (o) ->
# Every abstract syntax tree node object has four categories of properties:
# - type, stored in the `type` field and a string like `NumberLiteral`.
# - location data, stored in the `loc`, `start`, `end` and `range` fields.
@ -279,7 +279,7 @@ exports.Base = class Base
# These fields are all intermixed in the Babel spec; `type` and `start` and
# `parsedValue` are all top level fields in the AST node object. We have
# separate methods for returning each category, that we merge together here.
Object.assign {}, @astProperties(), {type: @astType()}, @astLocationData()
Object.assign {}, {type: @astType()}, @astProperties(o), @astLocationData()
# By default, a node class has no specific properties.
astProperties: -> {}
@ -491,9 +491,10 @@ exports.Root = class Root extends Base
astType: -> 'File'
astProperties: ->
astProperties: (o) ->
@body.isRootBlock = yes
return
program: Object.assign @body.ast(), @astLocationData()
program: Object.assign @body.ast(o), @astLocationData()
comments: []
#### Block
@ -773,19 +774,23 @@ exports.Block = class Block extends Base
return nodes[0] if nodes.length is 1 and nodes[0] instanceof Block
new Block nodes
astType: -> 'Program'
astType: ->
if @isRootBlock
'Program'
else
'BlockStatement'
astProperties: (o) ->
body = []
for expression in @expressions
# If an expression is a statement, it can be added to the body as is.
if expression.isStatement o
body.push expression.ast()
body.push expression.ast o
# Otherwise, we need to wrap it in an `ExpressionStatement` AST node.
else
body.push Object.assign
type: 'ExpressionStatement'
expression: expression.ast()
expression: expression.ast o
,
expression.astLocationData()
@ -994,8 +999,8 @@ exports.ComputedPropertyName = class ComputedPropertyName extends PropertyName
compileNode: (o) ->
[@makeCode('['), @value.compileToFragments(o, LEVEL_LIST)..., @makeCode(']')]
ast: ->
@value.ast()
ast: (o) ->
@value.ast o
exports.StatementLiteral = class StatementLiteral extends Literal
isStatement: YES
@ -1295,13 +1300,13 @@ exports.Value = class Value extends Base
mergeLocationData @base.locationData, initialProperties[initialProperties.length - 1].locationData
object
ast: ->
ast: (o) ->
# If the `Value` has no properties, the AST node is just whatever this
# nodes `base` is.
return @base.ast() unless @hasProperties()
return @base.ast o unless @hasProperties()
# Otherwise, call `Base::ast` which in turn calls the `astType` and
# `astProperties` methods below.
super()
super o
astType: ->
if @isCSXTag()
@ -1312,12 +1317,12 @@ exports.Value = class Value extends Base
# If this `Value` has properties, the *last* property (e.g. `c` in `a.b.c`)
# becomes the `property`, and the preceding properties (e.g. `a.b`) become
# a child `Value` node assigned to the `object` property.
astProperties: ->
astProperties: (o) ->
[..., property] = @properties
property.name.csx = yes if @isCSXTag()
return
object: @object().ast()
property: property.ast()
object: @object().ast o
property: property.ast o
computed: property instanceof Index or property.name?.unwrap() not instanceof PropertyName
optional: !!property.soak
shorthand: !!property.shorthand
@ -1501,7 +1506,7 @@ exports.CSXElement = class CSXElement extends Base
isFragment: ->
!@tagName.base.value.length
ast: ->
ast: (o) ->
# The location data spanning the opening element < ... > is captured by
# the generated Arr which contains the element's attributes
@openingElementLocationData = jisonLocationDataToAstLocationData @attributes.locationData
@ -1514,7 +1519,7 @@ exports.CSXElement = class CSXElement extends Base
jisonLocationDataToAstLocationData tagName.closingTagClosingBracketLocationData
)
super()
super o
astType: ->
if @isFragment()
@ -1522,12 +1527,12 @@ exports.CSXElement = class CSXElement extends Base
else
'JSXElement'
elementAstProperties: ->
elementAstProperties: (o) ->
openingElement = Object.assign {
type: 'JSXOpeningElement'
name: @tagName.unwrap().ast()
name: @tagName.unwrap().ast o
selfClosing: not @closingElementLocationData?
attributes: @attributes.ast()
attributes: @attributes.ast o
}, @openingElementLocationData
closingElement = null
@ -1535,7 +1540,7 @@ exports.CSXElement = class CSXElement extends Base
closingElement = Object.assign {
type: 'JSXClosingElement'
name: Object.assign(
@tagName.unwrap().ast(),
@tagName.unwrap().ast(o),
jisonLocationDataToAstLocationData @tagName.base.closingTagNameLocationData
)
}, @closingElementLocationData
@ -1563,7 +1568,7 @@ exports.CSXElement = class CSXElement extends Base
{openingElement, closingElement}
fragmentAstProperties: ->
fragmentAstProperties: (o) ->
openingFragment = Object.assign {
type: 'JSXOpeningFragment'
}, @openingElementLocationData
@ -1574,12 +1579,12 @@ exports.CSXElement = class CSXElement extends Base
{openingFragment, closingFragment}
astProperties: ->
astProperties: (o) ->
Object.assign(
if @isFragment()
@fragmentAstProperties()
@fragmentAstProperties o
else
@elementAstProperties()
@elementAstProperties o
,
children: []
)
@ -1723,10 +1728,10 @@ exports.Call = class Call extends Base
else
'CallExpression'
astProperties: ->
astProperties: (o) ->
return
callee: @variable.ast()
arguments: arg.ast() for arg in @args
callee: @variable.ast o
arguments: arg.ast(o) for arg in @args
optional: !!@soak
implicit: !!@implicit
@ -1846,11 +1851,11 @@ exports.Access = class Access extends Base
shouldCache: NO
ast: ->
ast: (o) ->
# Babel doesnt have an AST node for `Access`, but rather just includes
# this Access nodes child `name` Identifier node as the `property` of
# the `MemberExpression` node.
@name.ast()
@name.ast o
#### Index
@ -1867,13 +1872,13 @@ exports.Index = class Index extends Base
shouldCache: ->
@index.shouldCache()
ast: ->
ast: (o) ->
# Babel doesnt have an AST node for `Index`, but rather just includes
# this Index nodes child `index` Identifier node as the `property` of
# the `MemberExpression` node. The fact that the `MemberExpression`s
# `property` is an Index means that `computed` is `true` for the
# `MemberExpression`.
@index.ast()
@index.ast o
#### Range
@ -1987,10 +1992,10 @@ exports.Range = class Range extends Base
args = ', arguments' if hasArgs(@from) or hasArgs(@to)
[@makeCode "(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this#{args ? ''})"]
astProperties: ->
astProperties: (o) ->
return {
from: @from?.ast() ? null
to: @to?.ast() ? null
from: @from?.ast(o) ? null
to: @to?.ast(o) ? null
@exclusive
}
@ -2030,8 +2035,8 @@ exports.Slice = class Slice extends Base
"+#{fragmentsToText compiled} + 1 || 9e9"
[@makeCode ".slice(#{ fragmentsToText fromCompiled }#{ toStr or '' })"]
ast: ->
@range.ast()
ast: (o) ->
@range.ast(o)
#### Obj
@ -2198,11 +2203,11 @@ exports.Obj = class Obj extends Base
else
'ObjectExpression'
astProperties: ->
astProperties: (o) ->
return
implicit: !!@generated
properties:
property.ast() for property in @expandProperties()
property.ast(o) for property in @expandProperties()
exports.ObjectProperty = class ObjectProperty extends Base
constructor: ({key, fromAssign}) ->
@ -2223,13 +2228,13 @@ exports.ObjectProperty = class ObjectProperty extends Base
@shorthand = yes
@locationData = key.locationData
astProperties: ->
astProperties: (o) ->
isComputedPropertyName = @key instanceof Value and @key.base instanceof ComputedPropertyName
keyAst = @key.ast()
keyAst = @key.ast o
return
key: keyAst
value: @value?.ast() ? keyAst
value: @value?.ast(o) ? keyAst
shorthand: !!@shorthand
computed: !!isComputedPropertyName
method: no
@ -2341,10 +2346,10 @@ exports.Arr = class Arr extends Base
else
'ArrayExpression'
astProperties: ->
astProperties: (o) ->
return
elements:
object.ast() for object in @objects
object.ast(o) for object in @objects
#### Class
@ -2693,10 +2698,10 @@ exports.ImportDeclaration = class ImportDeclaration extends ModuleDeclaration
code.push @makeCode ';'
code
astProperties: ->
astProperties: (o) ->
ret =
specifiers: @clause?.ast() ? []
source: @source.ast()
specifiers: @clause?.ast(o) ? []
source: @source.ast o
ret.importKind = 'value' if @clause
ret
@ -2718,12 +2723,12 @@ exports.ImportClause = class ImportClause extends Base
code
ast: ->
ast: (o) ->
# The AST for `ImportClause` is the non-nested list of import specifiers
# that will be the `specifiers` property of an `ImportDeclaration` AST
compact flatten [
@defaultBinding?.ast()
@namedImports?.ast()
@defaultBinding?.ast o
@namedImports?.ast o
]
exports.ExportDeclaration = class ExportDeclaration extends ModuleDeclaration
@ -2753,11 +2758,11 @@ exports.ExportDeclaration = class ExportDeclaration extends ModuleDeclaration
code
exports.ExportNamedDeclaration = class ExportNamedDeclaration extends ExportDeclaration
astProperties: ->
astProperties: (o) ->
ret =
source: @source?.ast() ? null
source: @source?.ast(o) ? null
exportKind: 'value'
clauseAst = @clause.ast()
clauseAst = @clause.ast o
if @clause instanceof ExportSpecifierList
ret.specifiers = clauseAst
ret.declaration = null
@ -2767,14 +2772,14 @@ exports.ExportNamedDeclaration = class ExportNamedDeclaration extends ExportDecl
ret
exports.ExportDefaultDeclaration = class ExportDefaultDeclaration extends ExportDeclaration
astProperties: ->
astProperties: (o) ->
return
declaration: @clause.ast()
declaration: @clause.ast o
exports.ExportAllDeclaration = class ExportAllDeclaration extends ExportDeclaration
astProperties: ->
astProperties: (o) ->
return
source: @source.ast()
source: @source.ast o
exportKind: 'value'
exports.ModuleSpecifierList = class ModuleSpecifierList extends Base
@ -2798,8 +2803,8 @@ exports.ModuleSpecifierList = class ModuleSpecifierList extends Base
code.push @makeCode '{}'
code
ast: ->
specifier.ast() for specifier in @specifiers
ast: (o) ->
specifier.ast(o) for specifier in @specifiers
exports.ImportSpecifierList = class ImportSpecifierList extends ModuleSpecifierList
@ -2839,32 +2844,32 @@ exports.ImportSpecifier = class ImportSpecifier extends ModuleSpecifier
o.importedSymbols.push @identifier
super o
astProperties: ->
originalAst = @original.ast()
astProperties: (o) ->
originalAst = @original.ast o
return
imported: originalAst
local: @alias?.ast() ? originalAst
local: @alias?.ast(o) ? originalAst
importKind: null
exports.ImportDefaultSpecifier = class ImportDefaultSpecifier extends ImportSpecifier
astProperties: ->
astProperties: (o) ->
return
local: @original.ast()
local: @original.ast o
exports.ImportNamespaceSpecifier = class ImportNamespaceSpecifier extends ImportSpecifier
astProperties: ->
astProperties: (o) ->
return
local: @alias.ast()
local: @alias.ast o
exports.ExportSpecifier = class ExportSpecifier extends ModuleSpecifier
constructor: (local, exported) ->
super local, exported, 'export'
astProperties: ->
originalAst = @original.ast()
astProperties: (o) ->
originalAst = @original.ast o
return
local: originalAst
exported: @alias?.ast() ? originalAst
exported: @alias?.ast(o) ? originalAst
#### Assign
@ -3217,10 +3222,10 @@ exports.Assign = class Assign extends Base
else
'AssignmentExpression'
astProperties: ->
astProperties: (o) ->
ret =
right: @value.ast()
left: @variable.ast()
right: @value.ast o
left: @variable.ast o
unless @isDefaultAssignment()
ret.operator = @originalContext ? '='
@ -3686,8 +3691,8 @@ exports.Splat = class Splat extends Base
else
'SpreadElement'
astProperties: -> {
argument: @name.ast()
astProperties: (o) -> {
argument: @name.ast o
@postfix
}
@ -4017,9 +4022,9 @@ exports.Op = class Op extends Base
if @isUnary() then 'UnaryExpression'
else 'BinaryExpression'
astProperties: ->
firstAst = @first.ast()
secondAst = @second?.ast()
astProperties: (o) ->
firstAst = @first.ast o
secondAst = @second?.ast o
switch
when @isUnary()
return
@ -4074,36 +4079,30 @@ exports.In = class In extends Base
# A classic *try/catch/finally* block.
exports.Try = class Try extends Base
constructor: (@attempt, @errorVariable, @recovery, @ensure) ->
constructor: (@attempt, @catch, @ensure, @finallyTag) ->
super()
children: ['attempt', 'recovery', 'ensure']
children: ['attempt', 'catch', 'ensure']
isStatement: YES
jumps: (o) -> @attempt.jumps(o) or @recovery?.jumps(o)
jumps: (o) -> @attempt.jumps(o) or @catch?.jumps(o)
makeReturn: (res) ->
@attempt = @attempt .makeReturn res if @attempt
@recovery = @recovery.makeReturn res if @recovery
@attempt = @attempt.makeReturn res if @attempt
@catch = @catch .makeReturn res if @catch
this
# Compilation is more or less as you would expect -- the *finally* clause
# is optional, the *catch* is not.
compileNode: (o) ->
originalIndent = o.indent
o.indent += TAB
tryPart = @attempt.compileToFragments o, LEVEL_TOP
catchPart = if @recovery
generatedErrorVariableName = o.scope.freeVariable 'error', reserve: no
placeholder = new IdentifierLiteral generatedErrorVariableName
if @errorVariable
message = isUnassignable @errorVariable.unwrapAll().value
@errorVariable.error message if message
@recovery.unshift new Assign @errorVariable, placeholder
[].concat @makeCode(" catch ("), placeholder.compileToFragments(o), @makeCode(") {\n"),
@recovery.compileToFragments(o, LEVEL_TOP), @makeCode("\n#{@tab}}")
else unless @ensure or @recovery
catchPart = if @catch
@catch.compileToFragments merge(o, indent: originalIndent), LEVEL_TOP
else unless @ensure or @catch
generatedErrorVariableName = o.scope.freeVariable 'error', reserve: no
[@makeCode(" catch (#{generatedErrorVariableName}) {}")]
else
@ -4116,6 +4115,56 @@ exports.Try = class Try extends Base
tryPart,
@makeCode("\n#{@tab}}"), catchPart, ensurePart
astType: -> 'TryStatement'
astProperties: (o) ->
return
block: @attempt.ast o
handler: @catch?.ast(o) ? null
finalizer:
if @ensure?
Object.assign @ensure.ast(o),
# Include `finally` keyword in location data.
mergeAstLocationData(
jisonLocationDataToAstLocationData(@finallyTag.locationData),
@ensure.astLocationData()
)
else
null
exports.Catch = class Catch extends Base
constructor: (@recovery, @errorVariable) ->
super()
@errorVariable?.unwrap().propagateLhs? yes
children: ['recovery', 'errorVariable']
isStatement: YES
jumps: (o) -> @recovery.jumps(o)
makeReturn: (res) ->
@recovery = @recovery.makeReturn res
this
compileNode: (o) ->
o.indent += TAB
generatedErrorVariableName = o.scope.freeVariable 'error', reserve: no
placeholder = new IdentifierLiteral generatedErrorVariableName
if @errorVariable
message = isUnassignable @errorVariable.unwrapAll().value
@errorVariable.error message if message
@recovery.unshift new Assign @errorVariable, placeholder
[].concat @makeCode(" catch ("), placeholder.compileToFragments(o), @makeCode(") {\n"),
@recovery.compileToFragments(o, LEVEL_TOP), @makeCode("\n#{@tab}}")
astType: -> 'CatchClause'
astProperties: (o) ->
return
param: @errorVariable?.ast(o) ? null
body: @recovery.ast o
#### Throw
# Simple node to throw an exception.
@ -4140,9 +4189,9 @@ exports.Throw = class Throw extends Base
astType: -> 'ThrowStatement'
astProperties: ->
astProperties: (o) ->
return
argument: @expression.ast()
argument: @expression.ast o
#### Existence
@ -4188,9 +4237,9 @@ exports.Existence = class Existence extends Base
astType: -> 'UnaryExpression'
astProperties: ->
astProperties: (o) ->
return
argument: @expression.ast()
argument: @expression.ast o
operator: '?'
prefix: no
@ -4231,7 +4280,7 @@ exports.Parens = class Parens extends Base
return @wrapInBraces fragments if @csxAttribute
if bare then fragments else @wrapInParentheses fragments
ast: -> @body.unwrap().ast()
ast: (o) -> @body.unwrap().ast o
#### StringWithInterpolations

View File

@ -28,8 +28,7 @@ looseArray = (arr) ->
enumerable: no
arr
testExpression = (code, expected) ->
ast = getAstExpression code
testAgainstExpected = (ast, expected) ->
if expected?
deepStrictIncludeExpectedProperties ast, expected
else
@ -37,6 +36,13 @@ testExpression = (code, expected) ->
# parameter to see what the current AST generation is for your input code.
console.log inspect ast
testExpression = (code, expected) ->
ast = getAstExpression code
testAgainstExpected ast, expected
testStatement = (code, expected) ->
ast = getAstStatement code
testAgainstExpected ast, expected
test 'Confirm functionality of `deepStrictIncludeExpectedProperties`', ->
actual =
@ -346,13 +352,13 @@ test "AST as expected for ComputedPropertyName node", ->
implicit: yes
test "AST as expected for StatementLiteral node", ->
testExpression 'break',
testStatement 'break',
type: 'BreakStatement'
testExpression 'continue',
testStatement 'continue',
type: 'ContinueStatement'
testExpression 'debugger',
testStatement 'debugger',
type: 'DebuggerStatement'
test "AST as expected for ThisLiteral node", ->
@ -1030,7 +1036,7 @@ test "AST as expected for Arr node", ->
# ]
test "AST as expected for ModuleDeclaration node", ->
testExpression 'export {X}',
testStatement 'export {X}',
type: 'ExportNamedDeclaration'
declaration: null
specifiers: [
@ -1045,7 +1051,7 @@ test "AST as expected for ModuleDeclaration node", ->
source: null
exportKind: 'value'
testExpression 'import X from "."',
testStatement 'import X from "."',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportDefaultSpecifier'
@ -1059,7 +1065,7 @@ test "AST as expected for ModuleDeclaration node", ->
value: '.'
test "AST as expected for ImportDeclaration node", ->
testExpression 'import React, {Component} from "react"',
testStatement 'import React, {Component} from "react"',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportDefaultSpecifier'
@ -1084,14 +1090,14 @@ test "AST as expected for ImportDeclaration node", ->
raw: '"react"'
test "AST as expected for ExportNamedDeclaration node", ->
testExpression 'export {}',
testStatement 'export {}',
type: 'ExportNamedDeclaration'
declaration: null
specifiers: []
source: null
exportKind: 'value'
# testExpression 'export fn = ->',
# testStatement 'export fn = ->',
# type: 'ExportNamedDeclaration'
# clause:
# type: 'Assign'
@ -1100,9 +1106,9 @@ test "AST as expected for ExportNamedDeclaration node", ->
# value:
# type: 'Code'
# testExpression 'export class A',
# testStatement 'export class A',
testExpression 'export {x as y, z as default}',
testStatement 'export {x as y, z as default}',
type: 'ExportNamedDeclaration'
declaration: null
specifiers: [
@ -1125,7 +1131,7 @@ test "AST as expected for ExportNamedDeclaration node", ->
source: null
exportKind: 'value'
testExpression 'export {default, default as b} from "./abc"',
testStatement 'export {default, default as b} from "./abc"',
type: 'ExportNamedDeclaration'
declaration: null
specifiers: [
@ -1153,12 +1159,12 @@ test "AST as expected for ExportNamedDeclaration node", ->
exportKind: 'value'
test "AST as expected for ExportDefaultDeclaration node", ->
# testExpression 'export default class',
# testStatement 'export default class',
# type: 'ExportDefaultDeclaration'
# clause:
# type: 'Class'
testExpression 'export default "abc"',
testStatement 'export default "abc"',
type: 'ExportDefaultDeclaration'
declaration:
type: 'StringLiteral'
@ -1167,7 +1173,7 @@ test "AST as expected for ExportDefaultDeclaration node", ->
raw: '"abc"'
test "AST as expected for ExportAllDeclaration node", ->
testExpression 'export * from "module-name"',
testStatement 'export * from "module-name"',
type: 'ExportAllDeclaration'
source:
type: 'StringLiteral'
@ -1177,7 +1183,7 @@ test "AST as expected for ExportAllDeclaration node", ->
exportKind: 'value'
test "AST as expected for ExportSpecifierList node", ->
testExpression 'export {a, b, c}',
testStatement 'export {a, b, c}',
type: 'ExportNamedDeclaration'
declaration: null
specifiers: [
@ -1207,7 +1213,7 @@ test "AST as expected for ExportSpecifierList node", ->
]
test "AST as expected for ImportDefaultSpecifier node", ->
testExpression 'import React from "react"',
testStatement 'import React from "react"',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportDefaultSpecifier'
@ -1221,7 +1227,7 @@ test "AST as expected for ImportDefaultSpecifier node", ->
value: 'react'
test "AST as expected for ImportNamespaceSpecifier node", ->
testExpression 'import * as React from "react"',
testStatement 'import * as React from "react"',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportNamespaceSpecifier'
@ -1234,7 +1240,7 @@ test "AST as expected for ImportNamespaceSpecifier node", ->
type: 'StringLiteral'
value: 'react'
testExpression 'import React, * as ReactStar from "react"',
testStatement 'import React, * as ReactStar from "react"',
type: 'ImportDeclaration'
specifiers: [
type: 'ImportDefaultSpecifier'
@ -1685,24 +1691,102 @@ test "AST as expected for Op node", ->
# type: 'NumberLiteral'
# value: '2'
# test "AST as expected for Try node", ->
# testExpression 'try cappuccino',
# type: 'Try'
# attempt:
# type: 'Value'
# recovery: undefined
test "AST as expected for Try node", ->
testStatement 'try cappuccino',
type: 'TryStatement'
block:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'Identifier'
name: 'cappuccino'
]
handler: null
finalizer: null
# testExpression 'try to catch it then log it',
# type: 'Try'
# attempt:
# type: 'Value'
# recovery:
# type: 'Value'
# base:
# type: 'Call'
testStatement '''
try
x = 1
y()
catch e
d()
finally
f + g
''',
type: 'TryStatement'
block:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'AssignmentExpression'
,
type: 'ExpressionStatement'
expression:
type: 'CallExpression'
]
handler:
type: 'CatchClause'
param:
type: 'Identifier'
name: 'e'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'CallExpression'
]
finalizer:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
expression:
type: 'BinaryExpression'
]
testStatement '''
try
catch
finally
''',
type: 'TryStatement'
block:
type: 'BlockStatement'
body: []
handler:
type: 'CatchClause'
param: null
body:
type: 'BlockStatement'
body: []
finalizer:
type: 'BlockStatement'
body: []
testStatement '''
try
catch {e}
f
''',
type: 'TryStatement'
block:
type: 'BlockStatement'
body: []
handler:
type: 'CatchClause'
param:
type: 'ObjectPattern'
body:
type: 'BlockStatement'
body: [
type: 'ExpressionStatement'
]
finalizer: null
test "AST as expected for Throw node", ->
testExpression 'throw new BallError "catch"',
testStatement 'throw new BallError "catch"',
type: 'ThrowStatement'
argument:
type: 'NewExpression'

View File

@ -2,7 +2,7 @@
# ---------------------------------
testAstLocationData = (code, expected) ->
testAstNodeLocationData getAstExpression(code), expected
testAstNodeLocationData getAstExpressionOrStatement(code), expected
testAstRootLocationData = (code, expected) ->
testAstNodeLocationData getAstRoot(code), expected
@ -2667,6 +2667,253 @@ test "AST location data as expected for CSXTag node", ->
column: 11
]
test "AST as expected for Try node", ->
testAstLocationData 'try cappuccino',
type: 'TryStatement'
block:
type: 'BlockStatement'
body: [
expression:
start: 4
end: 14
range: [4, 14]
loc:
start:
line: 1
column: 4
end:
line: 1
column: 14
start: 4
end: 14
range: [4, 14]
loc:
start:
line: 1
column: 4
end:
line: 1
column: 14
]
# TODO: the location data for the block is wrong (wrong location data on generated INDENT)
# start: 4
# end: 14
# range: [4, 14]
# loc:
# start:
# line: 1
# column: 4
# end:
# line: 1
# column: 14
start: 0
end: 14
range: [0, 14]
loc:
start:
line: 1
column: 0
end:
line: 1
column: 14
testAstLocationData '''
try
x = 1
y()
catch e
d()
finally
f + g
''',
type: 'TryStatement'
block:
type: 'BlockStatement'
body: [
expression:
start: 6
end: 11
range: [6, 11]
loc:
start:
line: 2
column: 2
end:
line: 2
column: 7
start: 6
end: 11
range: [6, 11]
loc:
start:
line: 2
column: 2
end:
line: 2
column: 7
,
expression:
start: 14
end: 17
range: [14, 17]
loc:
start:
line: 3
column: 2
end:
line: 3
column: 5
start: 14
end: 17
range: [14, 17]
loc:
start:
line: 3
column: 2
end:
line: 3
column: 5
]
start: 4
end: 17
range: [4, 17]
loc:
start:
line: 2
column: 0
end:
line: 3
column: 5
handler:
param:
start: 24
end: 25
range: [24, 25]
loc:
start:
line: 4
column: 6
end:
line: 4
column: 7
body:
body: [
start: 28
end: 31
range: [28, 31]
loc:
start:
line: 5
column: 2
end:
line: 5
column: 5
]
start: 26
end: 31
range: [26, 31]
loc:
start:
line: 5
column: 0
end:
line: 5
column: 5
start: 18
end: 31
range: [18, 31]
loc:
start:
line: 4
column: 0
end:
line: 5
column: 5
finalizer:
body: [
expression:
start: 42
end: 47
range: [42, 47]
loc:
start:
line: 7
column: 2
end:
line: 7
column: 7
start: 42
end: 47
range: [42, 47]
loc:
start:
line: 7
column: 2
end:
line: 7
column: 7
]
start: 32
end: 47
range: [32, 47]
loc:
start:
line: 6
column: 0
end:
line: 7
column: 7
start: 0
end: 47
range: [0, 47]
loc:
start:
line: 1
column: 0
end:
line: 7
column: 7
testAstLocationData '''
try
catch {e}
f
''',
type: 'TryStatement'
handler:
param:
start: 10
end: 13
range: [10, 13]
loc:
start:
line: 2
column: 6
end:
line: 2
column: 9
body:
start: 14
end: 17
range: [14, 17]
loc:
start:
line: 3
column: 0
end:
line: 3
column: 3
start: 4
end: 17
range: [4, 17]
loc:
start:
line: 2
column: 0
end:
line: 3
column: 3
test "AST location data as expected for Root node", ->
testAstRootLocationData '1\n2',
type: 'File'

View File

@ -59,8 +59,16 @@ getAstExpressions = (code) ->
# Many tests want just the root node.
exports.getAstExpression = (code) ->
expressionStatementAst = getAstExpressions(code)[0]
ok expressionStatementAst.type is 'ExpressionStatement', 'Expected ExpressionStatement AST wrapper'
expressionStatementAst.expression
exports.getAstStatement = (code) ->
statement = getAstExpressions(code)[0]
ok statement.type isnt 'ExpressionStatement', "Didn't expect ExpressionStatement AST wrapper"
statement
exports.getAstExpressionOrStatement = (code) ->
expressionAst = getAstExpressions(code)[0]
if expressionAst.type is 'ExpressionStatement'
expressionAst.expression
else
expressionAst
return expressionAst unless expressionAst.type is 'ExpressionStatement'
expressionAst.expression