mirror of
https://github.com/dart-lang/sdk
synced 2024-10-05 14:25:02 +00:00
Support for interpolated declarations in the js parser.
Also use this support to avoid non-constant templates in async_rewrite. R=floitsch@google.com Review URL: https://codereview.chromium.org//932053002 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@43837 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
38512aca1b
commit
6ff10c59a9
|
@ -184,11 +184,6 @@ What is not implemented:
|
|||
array case, we would need some way to know if an ArrayInitializer argument
|
||||
should be splice or is intended as a single value.
|
||||
|
||||
- There are no placeholders in definition contexts:
|
||||
|
||||
function #(){}
|
||||
var # = 1;
|
||||
|
||||
*/
|
||||
const JsBuilder js = const JsBuilder();
|
||||
|
||||
|
@ -766,10 +761,9 @@ class MiniJsParser {
|
|||
|
||||
Expression parseFunctionExpression() {
|
||||
String last = lastToken;
|
||||
if (acceptCategory(ALPHA)) {
|
||||
String functionName = last;
|
||||
return new NamedFunction(new VariableDeclaration(functionName),
|
||||
parseFun());
|
||||
if (lastCategory == ALPHA || lastCategory == HASH) {
|
||||
Declaration name = parseVariableDeclaration();
|
||||
return new NamedFunction(name, parseFun());
|
||||
}
|
||||
return parseFun();
|
||||
}
|
||||
|
@ -1015,27 +1009,25 @@ class MiniJsParser {
|
|||
}
|
||||
|
||||
VariableDeclarationList parseVariableDeclarationList() {
|
||||
String firstVariable = lastToken;
|
||||
expectCategory(ALPHA);
|
||||
Declaration firstVariable = parseVariableDeclaration();
|
||||
return finishVariableDeclarationList(firstVariable);
|
||||
}
|
||||
|
||||
VariableDeclarationList finishVariableDeclarationList(String firstVariable) {
|
||||
VariableDeclarationList finishVariableDeclarationList(
|
||||
Declaration firstVariable) {
|
||||
var initialization = [];
|
||||
|
||||
void declare(String variable) {
|
||||
void declare(Declaration declaration) {
|
||||
Expression initializer = null;
|
||||
if (acceptString("=")) {
|
||||
initializer = parseAssignment();
|
||||
}
|
||||
var declaration = new VariableDeclaration(variable);
|
||||
initialization.add(new VariableInitialization(declaration, initializer));
|
||||
}
|
||||
|
||||
declare(firstVariable);
|
||||
while (acceptCategory(COMMA)) {
|
||||
String variable = lastToken;
|
||||
expectCategory(ALPHA);
|
||||
Declaration variable = parseVariableDeclaration();
|
||||
declare(variable);
|
||||
}
|
||||
return new VariableDeclarationList(initialization);
|
||||
|
@ -1224,20 +1216,18 @@ class MiniJsParser {
|
|||
}
|
||||
|
||||
if (acceptString('var')) {
|
||||
String identifier = lastToken;
|
||||
expectCategory(ALPHA);
|
||||
Declaration declaration = parseVariableDeclaration();
|
||||
if (acceptString('in')) {
|
||||
Expression objectExpression = parseExpression();
|
||||
expectCategory(RPAREN);
|
||||
Statement body = parseStatement();
|
||||
return new ForIn(
|
||||
new VariableDeclarationList([
|
||||
new VariableInitialization(
|
||||
new VariableDeclaration(identifier), null)]),
|
||||
new VariableInitialization(declaration, null)]),
|
||||
objectExpression,
|
||||
body);
|
||||
}
|
||||
Expression declarations = finishVariableDeclarationList(identifier);
|
||||
Expression declarations = finishVariableDeclarationList(declaration);
|
||||
expectCategory(SEMICOLON);
|
||||
return finishFor(declarations);
|
||||
}
|
||||
|
@ -1247,11 +1237,24 @@ class MiniJsParser {
|
|||
return finishFor(init);
|
||||
}
|
||||
|
||||
Declaration parseVariableDeclaration() {
|
||||
if (acceptCategory(HASH)) {
|
||||
var nameOrPosition = parseHash();
|
||||
InterpolatedDeclaration declaration =
|
||||
new InterpolatedDeclaration(nameOrPosition);
|
||||
interpolatedValues.add(declaration);
|
||||
return declaration;
|
||||
} else {
|
||||
String token = lastToken;
|
||||
expectCategory(ALPHA);
|
||||
return new VariableDeclaration(token);
|
||||
}
|
||||
}
|
||||
|
||||
Statement parseFunctionDeclaration() {
|
||||
String name = lastToken;
|
||||
expectCategory(ALPHA);
|
||||
Declaration name = parseVariableDeclaration();
|
||||
Expression fun = parseFun();
|
||||
return new FunctionDeclaration(new VariableDeclaration(name), fun);
|
||||
return new FunctionDeclaration(name, fun);
|
||||
}
|
||||
|
||||
Statement parseTry() {
|
||||
|
@ -1326,11 +1329,10 @@ class MiniJsParser {
|
|||
|
||||
Catch parseCatch() {
|
||||
expectCategory(LPAREN);
|
||||
String identifier = lastToken;
|
||||
expectCategory(ALPHA);
|
||||
Declaration errorName = parseVariableDeclaration();
|
||||
expectCategory(RPAREN);
|
||||
expectCategory(LBRACE);
|
||||
Block body = parseBlock();
|
||||
return new Catch(new VariableDeclaration(identifier), body);
|
||||
return new Catch(errorName, body);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ abstract class NodeVisitor<T> {
|
|||
T visitInterpolatedParameter(InterpolatedParameter node);
|
||||
T visitInterpolatedSelector(InterpolatedSelector node);
|
||||
T visitInterpolatedStatement(InterpolatedStatement node);
|
||||
T visitInterpolatedDeclaration(InterpolatedDeclaration node);
|
||||
}
|
||||
|
||||
class BaseVisitor<T> implements NodeVisitor<T> {
|
||||
|
@ -163,6 +164,9 @@ class BaseVisitor<T> implements NodeVisitor<T> {
|
|||
=> visitInterpolatedNode(node);
|
||||
T visitInterpolatedStatement(InterpolatedStatement node)
|
||||
=> visitInterpolatedNode(node);
|
||||
T visitInterpolatedDeclaration(InterpolatedDeclaration node) {
|
||||
return visitInterpolatedNode(node);
|
||||
}
|
||||
|
||||
// Ignore comments by default.
|
||||
T visitComment(Comment node) => null;
|
||||
|
@ -419,7 +423,7 @@ class Try extends Statement {
|
|||
}
|
||||
|
||||
class Catch extends Node {
|
||||
final VariableDeclaration declaration;
|
||||
final Declaration declaration;
|
||||
final Block body;
|
||||
|
||||
Catch(this.declaration, this.body);
|
||||
|
@ -484,7 +488,7 @@ class Default extends SwitchClause {
|
|||
}
|
||||
|
||||
class FunctionDeclaration extends Statement {
|
||||
final VariableDeclaration name;
|
||||
final Declaration name;
|
||||
final Fun function;
|
||||
|
||||
FunctionDeclaration(this.name, this.function);
|
||||
|
@ -549,6 +553,10 @@ abstract class Expression extends Node {
|
|||
Statement toStatement() => new ExpressionStatement(this);
|
||||
}
|
||||
|
||||
abstract class Declaration implements VariableReference {
|
||||
|
||||
}
|
||||
|
||||
class LiteralExpression extends Expression {
|
||||
final String template;
|
||||
final List<Expression> inputs;
|
||||
|
@ -620,10 +628,10 @@ class Assignment extends Expression {
|
|||
|
||||
class VariableInitialization extends Assignment {
|
||||
/** [value] may be null. */
|
||||
VariableInitialization(VariableDeclaration declaration, Expression value)
|
||||
VariableInitialization(Declaration declaration, Expression value)
|
||||
: super(declaration, value);
|
||||
|
||||
VariableDeclaration get declaration => leftHandSide;
|
||||
Declaration get declaration => leftHandSide;
|
||||
|
||||
accept(NodeVisitor visitor) => visitor.visitVariableInitialization(this);
|
||||
|
||||
|
@ -798,7 +806,7 @@ class VariableUse extends VariableReference {
|
|||
toString() => 'VariableUse($name)';
|
||||
}
|
||||
|
||||
class VariableDeclaration extends VariableReference {
|
||||
class VariableDeclaration extends VariableReference implements Declaration {
|
||||
final bool allowRename;
|
||||
VariableDeclaration(String name, {this.allowRename: true}) : super(name);
|
||||
|
||||
|
@ -821,7 +829,7 @@ class This extends Parameter {
|
|||
}
|
||||
|
||||
class NamedFunction extends Expression {
|
||||
final VariableDeclaration name;
|
||||
final Declaration name;
|
||||
final Fun function;
|
||||
|
||||
NamedFunction(this.name, this.function);
|
||||
|
@ -1093,6 +1101,26 @@ class InterpolatedStatement extends Statement with InterpolatedNode {
|
|||
InterpolatedStatement _clone() => new InterpolatedStatement(nameOrPosition);
|
||||
}
|
||||
|
||||
class InterpolatedDeclaration extends Expression
|
||||
with InterpolatedNode
|
||||
implements Declaration {
|
||||
final nameOrPosition;
|
||||
|
||||
InterpolatedDeclaration(this.nameOrPosition);
|
||||
|
||||
accept(NodeVisitor visitor) => visitor.visitInterpolatedDeclaration(this);
|
||||
void visitChildren(NodeVisitor visitor) {}
|
||||
InterpolatedDeclaration _clone() {
|
||||
return new InterpolatedDeclaration(nameOrPosition);
|
||||
}
|
||||
|
||||
@override
|
||||
String get name => throw "No name for the interpolated node";
|
||||
|
||||
@override
|
||||
int get precedenceLevel => PRIMARY;
|
||||
}
|
||||
|
||||
/**
|
||||
* [RegExpLiteral]s, despite being called "Literal", do not inherit from
|
||||
* [Literal]. Indeed, regular expressions in JavaScript have a side-effect and
|
||||
|
|
|
@ -969,6 +969,10 @@ class Printer implements NodeVisitor {
|
|||
outLn('#${node.nameOrPosition}');
|
||||
}
|
||||
|
||||
visitInterpolatedDeclaration(InterpolatedDeclaration node) {
|
||||
visitInterpolatedNode(node);
|
||||
}
|
||||
|
||||
void visitComment(Comment node) {
|
||||
if (shouldCompressOutput) return;
|
||||
String comment = node.comment.trim();
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
library rewrite_async;
|
||||
|
||||
// TODO(sigurdm): Avoid using variables in templates. It could blow up memory
|
||||
// use.
|
||||
// TODO(sigurdm): Move the try/catch expression to a js_helper function.
|
||||
// That would also simplify the sync* case, where the error can just be thrown.
|
||||
|
||||
|
@ -601,22 +599,25 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
}
|
||||
switch (async) {
|
||||
case const js.AsyncModifier.async():
|
||||
String returnValue =
|
||||
analysis.hasExplicitReturns ? returnValueName : "null";
|
||||
addStatement(js.js.statement(
|
||||
"return #thenHelper($returnValue, #successCode, "
|
||||
"$completerName, null)", {
|
||||
"thenHelper": asyncHelper,
|
||||
"successCode": js.number(error_codes.SUCCESS)}));
|
||||
"return #runtimeHelper(#returnValue, #successCode, "
|
||||
"#completer, null)", {
|
||||
"runtimeHelper": asyncHelper,
|
||||
"successCode": js.number(error_codes.SUCCESS),
|
||||
"returnValue": analysis.hasExplicitReturns
|
||||
? returnValueName
|
||||
: new js.LiteralNull(),
|
||||
"completer": completerName}));
|
||||
break;
|
||||
case const js.AsyncModifier.syncStar():
|
||||
addStatement(new js.Return(new js.Call(endOfIteration, [])));
|
||||
break;
|
||||
case const js.AsyncModifier.asyncStar():
|
||||
addStatement(js.js.statement(
|
||||
"return #streamHelper(null, #successCode, $controllerName)", {
|
||||
"return #streamHelper(null, #successCode, #controller)", {
|
||||
"streamHelper": streamHelper,
|
||||
"successCode": js.number(error_codes.SUCCESS)}));
|
||||
"successCode": js.number(error_codes.SUCCESS),
|
||||
"controller": controllerName}));
|
||||
break;
|
||||
default:
|
||||
diagnosticListener.internalError(
|
||||
|
@ -625,10 +626,11 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
if (isAsync || isAsyncStar) {
|
||||
beginLabel(rethrowLabel);
|
||||
addStatement(js.js.statement(
|
||||
"return #thenHelper($currentErrorName, #errorCode, "
|
||||
"${isAsync ? completerName : controllerName})", {
|
||||
"return #thenHelper(#currentError, #errorCode, #controller)", {
|
||||
"thenHelper": isAsync ? asyncHelper : streamHelper,
|
||||
"errorCode": js.number(error_codes.ERROR)}));
|
||||
"errorCode": js.number(error_codes.ERROR),
|
||||
"currentError": currentErrorName,
|
||||
"controller": isAsync ? completerName : controllerName}));
|
||||
} else {
|
||||
assert(isSyncStar);
|
||||
beginLabel(rethrowLabel);
|
||||
|
@ -647,13 +649,16 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
js.Statement generateInitializer() {
|
||||
if (isAsync) {
|
||||
return js.js.statement(
|
||||
"return #asyncHelper(null, $bodyName, $completerName, null);", {
|
||||
"asyncHelper": asyncHelper
|
||||
"return #asyncHelper(null, #body, #completer, null);", {
|
||||
"asyncHelper": asyncHelper,
|
||||
"body": bodyName,
|
||||
"completer": completerName,
|
||||
});
|
||||
} else if (isAsyncStar) {
|
||||
return js.js.statement(
|
||||
"return #streamOfController($controllerName);", {
|
||||
"streamOfController": streamOfController
|
||||
"return #streamOfController(#controller);", {
|
||||
"streamOfController": streamOfController,
|
||||
"controller": controllerName,
|
||||
});
|
||||
} else {
|
||||
throw diagnosticListener.internalError(
|
||||
|
@ -828,15 +833,21 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
js.Statement helperBody =
|
||||
new js.Switch(new js.VariableUse(gotoName), clauses);
|
||||
if (hasJumpThoughOuterLabel) {
|
||||
helperBody = js.js.statement("$outerLabelName: #", [helperBody]);
|
||||
helperBody = new js.LabeledStatement(outerLabelName, helperBody);
|
||||
}
|
||||
helperBody = js.js.statement("""
|
||||
try {
|
||||
#body
|
||||
} catch ($errorName){
|
||||
$currentErrorName = $errorName;
|
||||
$gotoName = $handlerName;
|
||||
}""", {"body": helperBody});
|
||||
} catch (#error){
|
||||
#currentError = #error;
|
||||
#goto = #handler;
|
||||
}""", {
|
||||
"body": helperBody,
|
||||
"goto": gotoName,
|
||||
"error": errorName,
|
||||
"currentError": currentErrorName,
|
||||
"handler": handlerName,
|
||||
});
|
||||
List<js.VariableInitialization> inits = <js.VariableInitialization>[];
|
||||
|
||||
js.VariableInitialization makeInit(String name, js.Expression initValue) {
|
||||
|
@ -878,10 +889,10 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
return js.js("""
|
||||
function (#params) {
|
||||
if (#needsThis)
|
||||
var $selfName = this;
|
||||
var #self = this;
|
||||
return new #newIterable(function () {
|
||||
#varDecl;
|
||||
return function $bodyName() {
|
||||
return function #body() {
|
||||
while (true)
|
||||
#helperBody;
|
||||
};
|
||||
|
@ -892,27 +903,29 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
"needsThis": analysis.hasThis,
|
||||
"helperBody": helperBody,
|
||||
"varDecl": varDecl,
|
||||
"newIterable": newIterable
|
||||
"newIterable": newIterable,
|
||||
"body": bodyName,
|
||||
"self": selfName,
|
||||
});
|
||||
}
|
||||
return js.js("""
|
||||
function (#params) {
|
||||
#varDecl;
|
||||
function $bodyName($errorCodeName, $resultName) {
|
||||
function #bodyName(#errorCode, #result) {
|
||||
if (#hasYield)
|
||||
switch ($errorCodeName) {
|
||||
case #streamWasCanceled:
|
||||
$nextName = $nextWhenCanceledName;
|
||||
$gotoName = $nextName.pop();
|
||||
switch (#errorCode) {
|
||||
case #STREAM_WAS_CANCELED:
|
||||
#next = #nextWhenCanceled;
|
||||
#goto = #next.pop();
|
||||
break;
|
||||
case #errorCode:
|
||||
$currentErrorName = $resultName;
|
||||
$gotoName = $handlerName;
|
||||
case #ERROR:
|
||||
#currentError = #result;
|
||||
#goto = #handler;
|
||||
}
|
||||
else
|
||||
if ($errorCodeName == #errorCode) {
|
||||
$currentErrorName = $resultName;
|
||||
$gotoName = $handlerName;
|
||||
if (#errorCode == #ERROR) {
|
||||
#currentError = #result;
|
||||
#goto = #handler;
|
||||
}
|
||||
while (true)
|
||||
#helperBody;
|
||||
|
@ -921,11 +934,19 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
}""", {
|
||||
"params": node.params,
|
||||
"varDecl": varDecl,
|
||||
"streamWasCanceled": js.number(error_codes.STREAM_WAS_CANCELED),
|
||||
"errorCode": js.number(error_codes.ERROR),
|
||||
"STREAM_WAS_CANCELED": js.number(error_codes.STREAM_WAS_CANCELED),
|
||||
"ERROR": js.number(error_codes.ERROR),
|
||||
"hasYield": analysis.hasYield,
|
||||
"helperBody": helperBody,
|
||||
"init": generateInitializer()
|
||||
"init": generateInitializer(),
|
||||
"bodyName": bodyName,
|
||||
"currentError": currentErrorName,
|
||||
"goto": gotoName,
|
||||
"handler": handlerName,
|
||||
"next": nextName,
|
||||
"nextWhenCanceled": nextWhenCanceledName,
|
||||
"errorCode": errorCodeName,
|
||||
"result": resultName,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -984,11 +1005,13 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
addStatement(setGotoVariable(afterAwait));
|
||||
addStatement(js.js.statement("""
|
||||
return #asyncHelper(#value,
|
||||
$bodyName,
|
||||
${isAsync ? completerName : controllerName});
|
||||
#body,
|
||||
#controller);
|
||||
""", {
|
||||
"asyncHelper": isAsync ? asyncHelper : streamHelper,
|
||||
"value": value,
|
||||
"body": bodyName,
|
||||
"controller": isAsync ? completerName : controllerName,
|
||||
}));
|
||||
}, store: false);
|
||||
beginLabel(afterAwait);
|
||||
|
@ -1165,7 +1188,7 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
hasJumpThroughFinally = true;
|
||||
js.Expression jsJumpStack = new js.ArrayInitializer(
|
||||
jumpStack.map((int label) => js.number(label)).toList());
|
||||
addStatement(js.js.statement("$nextName = #", [jsJumpStack]));
|
||||
addStatement(js.js.statement("# = #", [nextName, jsJumpStack]));
|
||||
}
|
||||
addGoto(firstTarget);
|
||||
}
|
||||
|
@ -1337,6 +1360,11 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
return unsupported(node);
|
||||
}
|
||||
|
||||
@override
|
||||
visitInterpolatedDeclaration(js.InterpolatedDeclaration node) {
|
||||
return unsupported(node);
|
||||
}
|
||||
|
||||
@override
|
||||
visitInterpolatedLiteral(js.InterpolatedLiteral node) => unsupported(node);
|
||||
|
||||
|
@ -1485,7 +1513,7 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
js.Node target = analysis.targets[node];
|
||||
if (node.value != null) {
|
||||
withExpression(node.value, (js.Expression value) {
|
||||
addStatement(js.js.statement("$returnValueName = #", [value]));
|
||||
addStatement(js.js.statement("# = #", [returnValueName, value]));
|
||||
}, store: false);
|
||||
}
|
||||
translateJump(target, exitLabel);
|
||||
|
@ -1666,7 +1694,8 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
} else {
|
||||
// The handler is reset as the first thing in the finally block.
|
||||
addStatement(
|
||||
js.js.statement("$nextName = [#];", [js.number(afterFinallyLabel)]));
|
||||
js.js.statement("# = [#];",
|
||||
[nextName, js.number(afterFinallyLabel)]));
|
||||
addGoto(finallyLabel);
|
||||
}
|
||||
|
||||
|
@ -1692,8 +1721,8 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
if (node.finallyPart != null) {
|
||||
// The error has been caught, so after the finally, continue after the
|
||||
// try.
|
||||
addStatement(js.js.statement("$nextName = [#];",
|
||||
[js.number(afterFinallyLabel)]));
|
||||
addStatement(js.js.statement("# = [#];",
|
||||
[nextName, js.number(afterFinallyLabel)]));
|
||||
addGoto(finallyLabel);
|
||||
} else {
|
||||
addGoto(afterFinallyLabel);
|
||||
|
@ -1713,8 +1742,8 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
// [enclosingFinallies] can be empty if there is no surrounding finally
|
||||
// blocks. Then [nextLabel] will be [rethrowLabel].
|
||||
addStatement(
|
||||
js.js.statement("$nextName = #;", new js.ArrayInitializer(
|
||||
enclosingFinallies.map(js.number).toList())));
|
||||
js.js.statement("# = #;", [nextName, new js.ArrayInitializer(
|
||||
enclosingFinallies.map(js.number).toList())]));
|
||||
}
|
||||
if (node.finallyPart == null) {
|
||||
// The finally-block belonging to [node] will be visited because of
|
||||
|
@ -1729,7 +1758,7 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
setErrorHandler();
|
||||
visitStatement(node.finallyPart);
|
||||
addStatement(new js.Comment("// goto the next finally handler"));
|
||||
addStatement(js.js.statement("$gotoName = $nextName.pop();"));
|
||||
addStatement(js.js.statement("# = #.pop();", [gotoName, nextName]));
|
||||
addBreak();
|
||||
}
|
||||
beginLabel(afterFinallyLabel);
|
||||
|
@ -1832,15 +1861,17 @@ class AsyncRewriter extends js.NodeVisitor {
|
|||
enclosingFinallyLabels.addAll(jumpTargets
|
||||
.where((js.Node node) => finallyLabels[node] != null)
|
||||
.map((js.Block node) => finallyLabels[node]));
|
||||
addStatement(js.js.statement("$nextWhenCanceledName = #",
|
||||
[new js.ArrayInitializer(enclosingFinallyLabels.map(js.number)
|
||||
.toList())]));
|
||||
addStatement(js.js.statement("# = #;",
|
||||
[nextWhenCanceledName, new js.ArrayInitializer(
|
||||
enclosingFinallyLabels.map(js.number).toList())]));
|
||||
addStatement(js.js.statement("""
|
||||
return #streamHelper(#yieldExpression(#expression),
|
||||
$bodyName, $controllerName);""", {
|
||||
return #streamHelper(#yieldExpression(#expression), #body,
|
||||
#controller);""", {
|
||||
"streamHelper": streamHelper,
|
||||
"yieldExpression": node.hasStar ? yieldStarExpression : yieldExpression,
|
||||
"expression": expression,
|
||||
"body": bodyName,
|
||||
"controller": controllerName,
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -2088,6 +2119,11 @@ class PreTranslationAnalysis extends js.NodeVisitor<bool> {
|
|||
return unsupported(node);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitInterpolatedDeclaration(js.InterpolatedDeclaration node) {
|
||||
return unsupported(node);
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitInterpolatedLiteral(js.InterpolatedLiteral node) {
|
||||
return unsupported(node);
|
||||
|
|
|
@ -185,6 +185,11 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
return new VariableUse(value);
|
||||
}
|
||||
|
||||
static Expression convertStringToVariableDeclaration(String value) {
|
||||
assert(identiferRE.hasMatch(value));
|
||||
return new VariableDeclaration(value);
|
||||
}
|
||||
|
||||
Instantiator visitInterpolatedExpression(InterpolatedExpression node) {
|
||||
var nameOrPosition = node.nameOrPosition;
|
||||
return (arguments) {
|
||||
|
@ -195,6 +200,16 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
|
|||
};
|
||||
}
|
||||
|
||||
Instantiator visitInterpolatedDeclaration(InterpolatedDeclaration node) {
|
||||
var nameOrPosition = node.nameOrPosition;
|
||||
return (arguments) {
|
||||
var value = arguments[nameOrPosition];
|
||||
if (value is Declaration) return value;
|
||||
if (value is String) return convertStringToVariableDeclaration(value);
|
||||
error('Interpolated value #$nameOrPosition is not a declaration: $value');
|
||||
};
|
||||
}
|
||||
|
||||
Instantiator visitSplayableExpression(Node node) {
|
||||
if (node is InterpolatedExpression) {
|
||||
var nameOrPosition = node.nameOrPosition;
|
||||
|
|
|
@ -325,5 +325,25 @@ switch (true) {
|
|||
testStatement('label: while (a) { label2: break label;}', [],
|
||||
'label:\n while (a) {\n label2:\n break label;\n }'),
|
||||
|
||||
|
||||
testStatement('var # = 3', ['x'], 'var x = 3;'),
|
||||
testStatement('var # = 3',
|
||||
[new jsAst.VariableDeclaration('x')],
|
||||
'var x = 3;'),
|
||||
testStatement('var # = 3, # = #',
|
||||
['x', 'y', js.number(2)],
|
||||
'var x = 3, y = 2;'),
|
||||
testStatement('var #a = 3, #b = #c',
|
||||
{"a": 'x', "b": 'y', "c": js.number(2)},
|
||||
'var x = 3, y = 2;'),
|
||||
testStatement('function #() {}', ['x'], 'function x() {\n}'),
|
||||
testStatement('function #() {}',
|
||||
[new jsAst.VariableDeclaration('x')],
|
||||
'function x() {\n}'),
|
||||
testStatement('try {} catch (#) {}', ['x'], 'try {\n} catch (x) {\n}'),
|
||||
testStatement('try {} catch (#a) {}', {"a": 'x'}, 'try {\n} catch (x) {\n}'),
|
||||
testStatement('try {} catch (#a) {}',
|
||||
{"a": new jsAst.VariableDeclaration('x')},
|
||||
'try {\n} catch (x) {\n}'),
|
||||
]));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue