Add JSX support to loose parser.
This commit is contained in:
parent
95479ab6aa
commit
e0bcfca03f
10
acorn.js
10
acorn.js
@ -463,7 +463,8 @@
|
||||
dot: _dot, ellipsis: _ellipsis, question: _question, slash: _slash, eq: _eq,
|
||||
name: _name, eof: _eof, num: _num, regexp: _regexp, string: _string,
|
||||
arrow: _arrow, template: _template, star: _star, assign: _assign,
|
||||
backQuote: _backQuote, dollarBraceL: _dollarBraceL};
|
||||
backQuote: _backQuote, dollarBraceL: _dollarBraceL, jsxName: _jsxName,
|
||||
jsxText: _jsxText, jsxTagStart: _jsxTagStart, jsxTagEnd: _jsxTagEnd};
|
||||
for (var kw in keywordTypes) exports.tokTypes["_" + kw] = keywordTypes[kw];
|
||||
|
||||
// This is a trick taken from Esprima. It turns out that, on
|
||||
@ -3321,9 +3322,6 @@
|
||||
return node;
|
||||
|
||||
case _jsxTagStart:
|
||||
return parseJSXElement();
|
||||
|
||||
case _jsxText:
|
||||
case _string:
|
||||
return parseExprAtom();
|
||||
|
||||
@ -3337,10 +3335,6 @@
|
||||
// at the beginning of the next one (right brace).
|
||||
|
||||
function parseJSXEmptyExpression() {
|
||||
if (tokType !== _braceR) {
|
||||
unexpected();
|
||||
}
|
||||
|
||||
var tmp;
|
||||
|
||||
tmp = tokStart;
|
||||
|
||||
179
acorn_loose.js
179
acorn_loose.js
@ -256,11 +256,27 @@
|
||||
return node;
|
||||
}
|
||||
|
||||
function dummyIdent() {
|
||||
var dummy = startNode();
|
||||
dummy.name = "✖";
|
||||
return finishNode(dummy, "Identifier");
|
||||
function finishNodeAt(node, type, pos) {
|
||||
if (options.locations) { node.loc.end = pos[1]; pos = pos[0]; }
|
||||
node.type = type;
|
||||
node.end = pos;
|
||||
if (options.ranges)
|
||||
node.range[1] = pos;
|
||||
return node;
|
||||
}
|
||||
|
||||
function emptyNode(type) {
|
||||
var dummy = startNodeAt(options.locations ? [lastEnd, lastEndLoc] : lastEnd);
|
||||
dummy.name = "✖";
|
||||
return finishNodeAt(dummy, type, storeCurrentPos());
|
||||
}
|
||||
|
||||
function dummyIdent() {
|
||||
var dummy = emptyNode("Identifier");
|
||||
dummy.name = "✖";
|
||||
return dummy;
|
||||
}
|
||||
|
||||
function isDummy(node) { return node.name == "✖"; }
|
||||
|
||||
function eat(type) {
|
||||
@ -724,7 +740,7 @@
|
||||
next();
|
||||
return finishNode(node, "Literal");
|
||||
|
||||
case tt.num: case tt.string:
|
||||
case tt.num: case tt.string: case tt.jsxText:
|
||||
var node = startNode();
|
||||
node.value = token.value;
|
||||
node.raw = input.slice(token.start, token.end);
|
||||
@ -788,6 +804,9 @@
|
||||
case tt.backQuote:
|
||||
return parseTemplate();
|
||||
|
||||
case tt.jsxTagStart:
|
||||
return parseJSXElement();
|
||||
|
||||
default:
|
||||
return dummyIdent();
|
||||
}
|
||||
@ -1161,4 +1180,154 @@
|
||||
}
|
||||
return elts;
|
||||
}
|
||||
|
||||
// Parse next token as JSX identifier
|
||||
|
||||
function parseJSXIdentifier() {
|
||||
var node = startNode();
|
||||
node.name = token.type === tt.jsxName ? token.value : token.type.keyword;
|
||||
next();
|
||||
return finishNode(node, "JSXIdentifier");
|
||||
}
|
||||
|
||||
// Parse namespaced identifier.
|
||||
|
||||
function parseJSXNamespacedName() {
|
||||
var start = storeCurrentPos();
|
||||
var name = parseJSXIdentifier();
|
||||
if (!eat(tt.colon)) return name;
|
||||
var node = startNodeAt(start);
|
||||
node.namespace = name;
|
||||
node.name = parseJSXIdentifier();
|
||||
return finishNode(node, "JSXNamespacedName");
|
||||
}
|
||||
|
||||
// Parses element name in any form - namespaced, member
|
||||
// or single identifier.
|
||||
|
||||
function parseJSXElementName() {
|
||||
var start = storeCurrentPos();
|
||||
var node = parseJSXNamespacedName();
|
||||
while (eat(tt.dot)) {
|
||||
var newNode = startNodeAt(start);
|
||||
newNode.object = node;
|
||||
newNode.property = parseJSXIdentifier();
|
||||
node = finishNode(newNode, "JSXMemberExpression");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
// Parses any type of JSX attribute value.
|
||||
|
||||
function parseJSXAttributeValue() {
|
||||
return token.type === tt.braceL ? parseJSXExpressionContainer() : parseExprAtom();
|
||||
}
|
||||
|
||||
// Parses JSX expression enclosed into curly brackets.
|
||||
|
||||
function parseJSXExpressionContainer(allowEmpty) {
|
||||
var node = startNode();
|
||||
pushCx();
|
||||
next();
|
||||
node.expression = allowEmpty && token.type === tt.braceR ? emptyNode("JSXEmptyExpression") : parseExpression();
|
||||
popCx();
|
||||
expect(tt.braceR);
|
||||
return finishNode(node, "JSXExpressionContainer");
|
||||
}
|
||||
|
||||
// Parses following JSX attribute name-value pair.
|
||||
|
||||
function parseJSXAttribute() {
|
||||
var node = startNode();
|
||||
if (token.type === tt.braceL) {
|
||||
if (lookAhead(1).type === tt.ellipsis) {
|
||||
next();
|
||||
next();
|
||||
node.argument = parseMaybeAssign();
|
||||
expect(tt.braceR);
|
||||
return finishNode(node, "JSXSpreadAttribute");
|
||||
} else {
|
||||
node.name = dummyIdent();
|
||||
node.value = parseJSXAttributeValue();
|
||||
}
|
||||
} else {
|
||||
node.name = parseJSXNamespacedName();
|
||||
node.value = eat(tt.eq) ? parseJSXAttributeValue() : null;
|
||||
}
|
||||
return finishNode(node, "JSXAttribute");
|
||||
}
|
||||
|
||||
// Parses JSX opening tag starting after '<'.
|
||||
|
||||
function parseJSXOpeningElementAt(start) {
|
||||
var node = startNodeAt(start);
|
||||
node.attributes = [];
|
||||
node.name = parseJSXElementName();
|
||||
while (token.type !== tt.slash && token.type !== tt.jsxTagEnd && token.type !== tt.eof) {
|
||||
node.attributes.push(parseJSXAttribute());
|
||||
}
|
||||
node.selfClosing = eat(tt.slash);
|
||||
expect(tt.jsxTagEnd);
|
||||
if (token.type === tt.eof) node.selfClosing = true;
|
||||
return finishNode(node, "JSXOpeningElement");
|
||||
}
|
||||
|
||||
// Parses JSX closing tag starting after '</'.
|
||||
|
||||
function parseJSXClosingElementAt(start) {
|
||||
var node = startNodeAt(start);
|
||||
node.name = parseJSXElementName();
|
||||
expect(tt.jsxTagEnd);
|
||||
return finishNode(node, "JSXClosingElement");
|
||||
}
|
||||
|
||||
// Parses entire JSX element, including it's opening tag
|
||||
// (starting after '<'), attributes, contents and closing tag.
|
||||
|
||||
function parseJSXElementAt(start) {
|
||||
var node = startNodeAt(start);
|
||||
var children = [];
|
||||
var openingElement = parseJSXOpeningElementAt(start);
|
||||
var closingElement = null;
|
||||
|
||||
if (!openingElement.selfClosing) {
|
||||
contents:for (;;) {
|
||||
switch (token.type) {
|
||||
case tt.jsxTagStart:
|
||||
start = storeCurrentPos();
|
||||
next();
|
||||
if (eat(tt.slash)) {
|
||||
closingElement = parseJSXClosingElementAt(start);
|
||||
break contents;
|
||||
}
|
||||
children.push(parseJSXElementAt(start));
|
||||
break;
|
||||
|
||||
case tt.braceL:
|
||||
children.push(parseJSXExpressionContainer(true));
|
||||
break;
|
||||
|
||||
case tt.eof:
|
||||
break contents;
|
||||
|
||||
default:
|
||||
children.push(parseExprAtom());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node.openingElement = openingElement;
|
||||
node.closingElement = closingElement;
|
||||
node.children = children;
|
||||
return finishNode(node, "JSXElement");
|
||||
}
|
||||
|
||||
// Parses entire JSX element from current position.
|
||||
|
||||
function parseJSXElement() {
|
||||
var start = storeCurrentPos();
|
||||
next();
|
||||
return parseJSXElementAt(start);
|
||||
}
|
||||
});
|
||||
|
||||
@ -3604,8 +3604,7 @@ for (var ns in fbTestFixture) {
|
||||
}, {
|
||||
ecmaVersion: 6,
|
||||
locations: true,
|
||||
ranges: true,
|
||||
loose: false
|
||||
ranges: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user