Added support for namespaces and member expressions in tag names.
This commit is contained in:
parent
283d47c038
commit
b4c5d1f2e9
88
acorn.js
88
acorn.js
@ -1248,6 +1248,20 @@
|
||||
eat(type) || unexpected();
|
||||
}
|
||||
|
||||
// Expect a char. If found, consume it, otherwise,
|
||||
// raise an unexpected token error.
|
||||
|
||||
function expectChar(ch) {
|
||||
if (tokVal === ch) next();
|
||||
else unexpected();
|
||||
}
|
||||
|
||||
// Get following char.
|
||||
|
||||
function nextChar() {
|
||||
return input[tokPos];
|
||||
}
|
||||
|
||||
// Raise an unexpected token error.
|
||||
|
||||
function unexpected(pos) {
|
||||
@ -2547,35 +2561,67 @@
|
||||
}
|
||||
|
||||
function parseXJSIdentifier() {
|
||||
var node = parseIdent(true);
|
||||
node.type = "XJSIdentifier";
|
||||
return node;
|
||||
}
|
||||
|
||||
function parseXJSNamespacedName() {
|
||||
var node = startNode();
|
||||
if (tokType === _name) {
|
||||
node.name = tokVal;
|
||||
} else {
|
||||
unexpected();
|
||||
|
||||
node.namespace = parseXJSIdentifier();
|
||||
expect(_colon);
|
||||
node.name = parseXJSIdentifier();
|
||||
|
||||
return finishNode(node, "XJSNamespacedName");
|
||||
}
|
||||
|
||||
function parseXJSMemberExpression() {
|
||||
var node = parseXJSIdentifier();
|
||||
|
||||
while (eat(_dot)) {
|
||||
var newNode = startNodeFrom(node);
|
||||
newNode.object = node;
|
||||
newNode.property = parseXJSIdentifier();
|
||||
node = finishNode(newNode, "XJSMemberExpression");
|
||||
}
|
||||
tokRegexpAllowed = false;
|
||||
next();
|
||||
return finishNode(node, "XJSIdentifier");
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function parseXJSElementName() {
|
||||
switch (nextChar()) {
|
||||
case ':':
|
||||
return parseXJSNamespacedName();
|
||||
|
||||
case '.':
|
||||
return parseXJSMemberExpression();
|
||||
|
||||
default:
|
||||
return parseXJSIdentifier();
|
||||
}
|
||||
}
|
||||
|
||||
function parseXJSAttributeName() {
|
||||
if (nextChar() === ':') {
|
||||
return parseXJSNamespacedName();
|
||||
}
|
||||
|
||||
return parseXJSIdentifier();
|
||||
}
|
||||
|
||||
function parseXJSChild() {
|
||||
var token;
|
||||
/*
|
||||
var token, marker;
|
||||
if (tokVal === '{') {
|
||||
token = parseXJSExpressionContainer();
|
||||
} else if (lookahead.type === Token.XJSText) {
|
||||
marker = markerCreatePreserveWhitespace();
|
||||
token = markerApply(marker, delegate.createLiteral(lex()));
|
||||
} else {
|
||||
} else*/ {
|
||||
token = parseXJSElement();
|
||||
}
|
||||
return token;
|
||||
*/
|
||||
return parseXJSElement();
|
||||
}
|
||||
|
||||
function parseXJSClosingElement() {
|
||||
@ -2585,15 +2631,15 @@
|
||||
inXJSChild = false;
|
||||
inXJSTag = true;
|
||||
tokRegexpAllowed = false;
|
||||
tokVal === '<' ? next() : unexpected();
|
||||
tokVal === '/' ? next() : unexpected();
|
||||
expectChar('<');
|
||||
expectChar('/');
|
||||
node.name = parseXJSElementName();
|
||||
// Because advance() (called by lex() called by expect()) expects there
|
||||
// to be a valid token after >, it needs to know whether to look for a
|
||||
// standard JS token or an XJS text node
|
||||
inXJSChild = origInXJSChild;
|
||||
inXJSTag = origInXJSTag;
|
||||
tokVal === '>' ? next() : unexpected();
|
||||
expectChar('>');
|
||||
return finishNode(node, "XJSClosingElement");
|
||||
}
|
||||
|
||||
@ -2605,17 +2651,13 @@
|
||||
inXJSChild = false;
|
||||
inXJSTag = true;
|
||||
|
||||
tokVal === '<' ? next() : unexpected();
|
||||
expectChar('<');
|
||||
|
||||
node.name = parseXJSElementName();
|
||||
|
||||
/*
|
||||
while (index < length &&
|
||||
lookahead.value !== '/' &&
|
||||
lookahead.value !== '>') {
|
||||
attributes.push(parseXJSAttribute());
|
||||
while (tokType !== _eof && tokVal !== '/' && tokVal !== '>') {
|
||||
//attributes.push(parseXJSAttribute());
|
||||
}
|
||||
*/
|
||||
|
||||
inXJSTag = origInXJSTag;
|
||||
|
||||
@ -2627,7 +2669,7 @@
|
||||
inXJSChild = true;
|
||||
node.selfClosing = false;
|
||||
}
|
||||
tokVal === '>' ? next() : unexpected();
|
||||
expectChar('>');
|
||||
return finishNode(node, "XJSOpeningElement");
|
||||
}
|
||||
|
||||
@ -2642,7 +2684,7 @@
|
||||
if (!openingElement.selfClosing) {
|
||||
while (tokType !== _eof) {
|
||||
inXJSChild = false; // Call lookahead2() with inXJSChild = false because </ should not be considered in the child
|
||||
if (tokVal === '<' && input.charAt(tokPos) === '/') {
|
||||
if (tokVal === '<' && nextChar() === '/') {
|
||||
break;
|
||||
}
|
||||
inXJSChild = true;
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
<title>Acorn test suite</title>
|
||||
<script src="../acorn.js"></script>
|
||||
<script src="driver.js"></script>
|
||||
<script src="tests-jsx.js" charset="utf-8"></script>
|
||||
<script src="tests.js" charset="utf-8"></script>
|
||||
<script src="tests-harmony.js" charset="utf-8"></script>
|
||||
</head>
|
||||
|
||||
@ -6,10 +6,10 @@ if (typeof exports != "undefined") {
|
||||
var testAssert = require("./driver.js").testAssert;
|
||||
}
|
||||
|
||||
test('<a />', {
|
||||
type: 'Program',
|
||||
body: [
|
||||
{
|
||||
// Simply taken from esprima-fb/fbtest.js
|
||||
var fbTestFixture = {
|
||||
'XJS': {
|
||||
'<a />': {
|
||||
type: "ExpressionStatement",
|
||||
expression: {
|
||||
type: "XJSElement",
|
||||
@ -18,8 +18,7 @@ test('<a />', {
|
||||
name: {
|
||||
type: "XJSIdentifier",
|
||||
name: "a",
|
||||
start: 1,
|
||||
end: 2,
|
||||
range: [1, 2],
|
||||
loc: {
|
||||
start: { line: 1, column: 1 },
|
||||
end: { line: 1, column: 2 }
|
||||
@ -27,27 +26,234 @@ test('<a />', {
|
||||
},
|
||||
selfClosing: true,
|
||||
attributes: [],
|
||||
start: 0,
|
||||
end: 5,
|
||||
range: [0, 5],
|
||||
loc: {
|
||||
start: { line: 1, column: 0 },
|
||||
end: { line: 1, column: 5 }
|
||||
}
|
||||
},
|
||||
children: [],
|
||||
start: 0,
|
||||
end: 5,
|
||||
range: [0, 5],
|
||||
loc: {
|
||||
start: { line: 1, column: 0 },
|
||||
end: { line: 1, column: 5 }
|
||||
}
|
||||
},
|
||||
start: 0,
|
||||
end: 5,
|
||||
range: [0, 5],
|
||||
loc: {
|
||||
start: { line: 1, column: 0 },
|
||||
end: { line: 1, column: 5 }
|
||||
}
|
||||
},
|
||||
'<a\n/>': {
|
||||
type: "ExpressionStatement",
|
||||
expression: {
|
||||
type: "XJSElement",
|
||||
openingElement: {
|
||||
type: "XJSOpeningElement",
|
||||
name: {
|
||||
type: "XJSIdentifier",
|
||||
name: "a",
|
||||
range: [
|
||||
1,
|
||||
2
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 1
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 2
|
||||
}
|
||||
}
|
||||
},
|
||||
selfClosing: true,
|
||||
attributes: [],
|
||||
range: [
|
||||
0,
|
||||
5
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 2,
|
||||
column: 2
|
||||
}
|
||||
}
|
||||
},
|
||||
children: [],
|
||||
range: [
|
||||
0,
|
||||
5
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 2,
|
||||
column: 2
|
||||
}
|
||||
}
|
||||
},
|
||||
range: [
|
||||
0,
|
||||
5
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 2,
|
||||
column: 2
|
||||
}
|
||||
}
|
||||
},
|
||||
'<日本語></日本語>': {
|
||||
type: "ExpressionStatement",
|
||||
expression: {
|
||||
type: "XJSElement",
|
||||
openingElement: {
|
||||
type: "XJSOpeningElement",
|
||||
name: {
|
||||
type: "XJSIdentifier",
|
||||
name: "日本語",
|
||||
range: [
|
||||
1,
|
||||
4
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 1
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 4
|
||||
}
|
||||
}
|
||||
},
|
||||
selfClosing: false,
|
||||
attributes: [],
|
||||
range: [
|
||||
0,
|
||||
5
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 5
|
||||
}
|
||||
}
|
||||
},
|
||||
closingElement: {
|
||||
type: "XJSClosingElement",
|
||||
name: {
|
||||
type: "XJSIdentifier",
|
||||
name: "日本語",
|
||||
range: [
|
||||
7,
|
||||
10
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 7
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 10
|
||||
}
|
||||
}
|
||||
},
|
||||
range: [
|
||||
5,
|
||||
11
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 5
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 11
|
||||
}
|
||||
}
|
||||
},
|
||||
children: [],
|
||||
range: [
|
||||
0,
|
||||
11
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 11
|
||||
}
|
||||
}
|
||||
},
|
||||
range: [
|
||||
0,
|
||||
11
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 11
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}, {locations: true});
|
||||
}
|
||||
};
|
||||
|
||||
// patching test data to match acorn-specific format instead of esprima-specific one
|
||||
function esprima2acorn(ast, isTopLevel) {
|
||||
if ('range' in ast) {
|
||||
ast.start = ast.range[0];
|
||||
ast.end = ast.range[1];
|
||||
delete ast.range;
|
||||
}
|
||||
|
||||
for (var subPropName in ast) {
|
||||
var subProp = ast[subPropName];
|
||||
if (typeof subProp === 'object' && subProp !== null) {
|
||||
ast[subPropName] = esprima2acorn(subProp);
|
||||
}
|
||||
}
|
||||
|
||||
if (isTopLevel) {
|
||||
ast = {
|
||||
type: 'Program',
|
||||
body: [ast],
|
||||
start: ast.start,
|
||||
end: ast.end
|
||||
};
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
||||
for (var code in fbTestFixture.XJS) {
|
||||
test(code, esprima2acorn(fbTestFixture.XJS[code], true), {locations: true});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user