if (isDeclaration && !isSynthetic(name)
&& newScope.isFunction(name.getName())
&& !newScope.isDeclaredFunction(name.getName())) {
headDecls.add((Declaration) QuasiBuilder.substV(
"var @innerName = @outerName;",
"outerName", new Reference(rewrittenName),
"innerName", new Identifier(
name.getFilePosition(),
newContext.lookup(name.getName()).newName)));
// TODO(mikesamuel): skip if the self name is never used.
}
FunctionConstructor out = (FunctionConstructor) substV(
"name", rewrittenName,
"headDecls", optionalDeclarations(headDecls),
"params", new ParseTreeNodeContainer(newFormals),
"body", expandAll(bindings.get("body"), newScope));
return isDeclaration ? new FunctionDeclaration(out) : out;
}
return NONE;
}
},
new Rule() {
@Override
@RuleDescription(
name="block",
synopsis="block scoping",
reason="",
matches="{ @body* }",
substitutes="{ @body* }")
public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
if (node instanceof Block) {
Block bl = (Block) node;
List<Statement> stmts = Lists.newArrayList();
Scope newScope = Scope.fromPlainBlock(scope);
NameContext<String, ?> newContext = contexts.get(scope)
.makeChildContext();
contexts.put(newScope, newContext);
for (String local : newScope.getLocals()) {
try {
newContext.declare(
local, newScope.getLocationOfDeclaration(local));
} catch (NameContext.RedeclarationException ex) {
throw new SomethingWidgyHappenedError(
"Local variable unexpectedly not set", ex);
}
}
for (Statement s : bl.children()) {
stmts.add((Statement) expand(s, newScope));
}
stmts.addAll(0, newScope.getStartStatements());
return new Block(bl.getFilePosition(), stmts);
}
return NONE;
}
},
new Rule() {
@Override
@RuleDescription(
name="catch",
synopsis="catch block scoping",
reason="",
matches="catch (@e) { @body* }",
substitutes="catch (@e) { @body* }")
public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
if (node instanceof CatchStmt) {
CatchStmt cs = (CatchStmt) node;
Scope newScope = Scope.fromCatchStmt(scope, cs);
NameContext<String, ?> context = contexts.get(scope);
NameContext<String, ?> newContext = context.makeChildContext();
contexts.put(newScope, newContext);
try {
newContext.declare(cs.getException().getIdentifierName(),
cs.getException().getFilePosition());
} catch (NameContext.RedeclarationException ex) {
ex.toMessageQueue(mq);
}
return expandAll(cs, newScope);
}
return NONE;
}
},
//////////////
// Renaming //
//////////////
new Rule() {
@Override
@RuleDescription(
name="memberAccess",
synopsis="",
reason="so that we do not mistakenly rename property names",
matches="@o.@r",
substitutes="@o.@r")
public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
Map<String, ParseTreeNode> bindings = match(node);
if (bindings != null) {
return substV("o", expand(bindings.get("o"), scope),
"r", bindings.get("r"));
}
return NONE;
}
},
new Rule() {
@Override
@RuleDescription(
name="thisReference",
synopsis="Disallow this in the global scope.",
reason="The declaration cannot be rewritten.",
matches="this",
substitutes="this")
public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
if (match(node) != null) {
if (scope.isOuter()) {
mq.addMessage(
RewriterMessageType.THIS_IN_GLOBAL_CONTEXT,
node.getFilePosition());
return new NullLiteral(node.getFilePosition());
}
}
return NONE;
}
},
new Rule() {
@Override
@RuleDescription(
name="argumentsReference",
synopsis="Disallow arguments in the global scope.",
reason="The declaration cannot be rewritten.",
matches="arguments",
substitutes="arguments")
public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
if (match(node) != null) {
if (scope.isOuter()) {
mq.addMessage(
RewriterMessageType.ARGUMENTS_IN_GLOBAL_CONTEXT,
node.getFilePosition());
return new NullLiteral(node.getFilePosition());
}
}
return NONE;
}
},
new Rule() {
@Override
@RuleDescription(
name="rename",
synopsis="",
reason="",
matches="/* Reference */ @r",
substitutes="@r")
public ParseTreeNode fire(ParseTreeNode node, Scope scope) {
if (node instanceof Reference) {
Reference r = (Reference) node;
if (!isSynthetic(r)) {
FilePosition pos = r.getFilePosition();
String rname = r.getIdentifierName();
NameContext<String, ?> context = contexts.get(scope);
NameContext.VarInfo<String, ?> vi = context.lookup(rname);
if (vi != null) {
return new Reference(new Identifier(pos, vi.newName));
} else {
mq.addMessage(
RewriterMessageType.FREE_VARIABLE, pos,
MessagePart.Factory.valueOf(rname));
return new NullLiteral(pos);