JS: grouped all scope/name operations in JsParser

This commit is contained in:
Alexey Tsvetkov
2015-01-30 21:19:46 +03:00
parent bb634c6365
commit 47064ce03c
2 changed files with 114 additions and 68 deletions
@@ -28,7 +28,6 @@ import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import static com.google.dart.compiler.util.AstUtil.toFunctionScope;
@@ -37,7 +36,8 @@ import static com.google.dart.compiler.util.AstUtil.toFunctionScope;
*/
public class JsParser {
private JsProgram program;
private final JsProgram program;
private final ScopeContext scopeContext;
public static List<JsStatement> parse(
SourceInfo rootSourceInfo,
@@ -45,22 +45,21 @@ public class JsParser {
ErrorReporter errorReporter,
boolean insideFunction
) throws IOException, JsParserException {
return new JsParser(scope.getProgram()).parseImpl(rootSourceInfo, scope, r, errorReporter, insideFunction);
return new JsParser(scope).parseImpl(rootSourceInfo, r, errorReporter, insideFunction);
}
private final Stack<JsScope> scopeStack = new Stack<JsScope>();
/**
* since source maps are not mapped to kotlin source maps
*/
private static final String SOURCE_NAME_STUB = "jsCode";
private JsParser(JsProgram program) {
this.program = program;
private JsParser(@NotNull JsScope scope) {
scopeContext = new ScopeContext(scope);
program = scope.getProgram();
}
List<JsStatement> parseImpl(
final SourceInfo rootSourceInfo, JsScope scope,
final SourceInfo rootSourceInfo,
Reader r,
ErrorReporter errorReporter,
boolean insideFunction
@@ -73,12 +72,7 @@ public class JsParser {
TokenStream ts = new TokenStream(r, SOURCE_NAME_STUB, rootSourceInfo.getLine());
Parser parser = new Parser(new IRFactory(ts), insideFunction);
Node topNode = (Node) parser.parse(ts);
// Map the Rhino AST to ours.
pushScope(scope);
List<JsStatement> stmts = mapStatements(topNode);
popScope();
return stmts;
return mapStatements(topNode);
}
finally {
Context.exit();
@@ -90,10 +84,6 @@ public class JsParser {
return new JsParserException("Parser encountered internal error: " + msg, position);
}
private JsScope getScope() {
return scopeStack.peek();
}
private JsNode map(Node node) throws JsParserException {
switch (node.getType()) {
case TokenStream.SCRIPT: {
@@ -222,7 +212,7 @@ public class JsParser {
case TokenStream.NAME:
case TokenStream.BINDNAME:
return mapName(node);
return scopeContext.globalNameFor(node.getString()).makeRef();
case TokenStream.RETURN:
return mapReturn(node);
@@ -291,8 +281,7 @@ public class JsParser {
//
if (unknown instanceof JsStringLiteral) {
JsStringLiteral lit = (JsStringLiteral) unknown;
String litName = lit.getValue();
return new JsNameRef(litName);
return scopeContext.referenceFor(lit.getValue());
}
else {
throw createParserException("Expecting a name reference", nameRefNode);
@@ -379,8 +368,7 @@ public class JsParser {
String identifier = label.getString();
assert identifier != null: "If label exists identifier should not be null";
JsFunctionScope scope = toFunctionScope(getScope());
JsName labelName = scope.findLabel(identifier);
JsName labelName = scopeContext.labelFor(identifier);
assert labelName != null: "Unknown label name: " + identifier;
return labelName.makeRef();
@@ -548,7 +536,7 @@ public class JsParser {
//
Node fromIterVarName = fromIter.getFirstChild();
String fromName = fromIterVarName.getString();
JsName toName = getScope().declareName(fromName);
JsName toName = scopeContext.localNameFor(fromName);
toForIn = new JsForIn(toName);
Node fromIterInit = fromIterVarName.getFirstChild();
if (fromIterInit != null) {
@@ -611,29 +599,19 @@ public class JsParser {
Node fromFnNameNode = fnNode.getFirstChild();
Node fromParamNode = fnNode.getFirstChild().getNext().getFirstChild();
Node fromBodyNode = fnNode.getFirstChild().getNext().getNext();
JsFunction toFn = scopeContext.enterFunction();
// Decide the function's name, if any.
//
String fromFnName = fromFnNameNode.getString();
JsName toFnName = null;
if (fromFnName != null && fromFnName.length() > 0) {
toFnName = getScope().declareName(fromFnName);
String fnNameIdent = fromFnNameNode.getString();
if (fnNameIdent != null && fnNameIdent.length() > 0) {
scopeContext.globalNameFor(fnNameIdent);
}
// Create it, and set the params.
//
JsFunction toFn = new JsFunction(getScope(), "jsCode");
// Creating a function also creates a new scope, which we push onto
// the scope stack.
//
pushScope(toFn.getScope());
while (fromParamNode != null) {
String fromParamName = fromParamNode.getString();
// should this be unique? I think not since you can have dup args.
JsName paramName = toFn.getScope().declareName(fromParamName);
toFn.getParameters().add(new JsParameter(paramName));
JsName name = scopeContext.localNameFor(fromParamName);
toFn.getParameters().add(new JsParameter(name));
fromParamNode = fromParamNode.getNext();
}
@@ -642,10 +620,7 @@ public class JsParser {
JsBlock toBody = mapBlock(fromBodyNode);
toFn.setBody(toBody);
// Pop the new function's scope off of the scope stack.
//
popScope();
scopeContext.exitFunction();
return toFn;
}
@@ -673,7 +648,7 @@ public class JsParser {
//
Object obj = getPropNode.getProp(Node.SPECIAL_PROP_PROP);
assert (obj instanceof String);
toNameRef = new JsNameRef((String) obj);
toNameRef = scopeContext.referenceFor((String) obj);
}
toNameRef.setQualifier(toQualifier);
@@ -725,22 +700,16 @@ public class JsParser {
private JsLabel mapLabel(Node labelNode) throws JsParserException {
String fromName = labelNode.getFirstChild().getString();
JsFunctionScope scope = toFunctionScope(getScope());
JsName toName = scope.enterLabel(fromName);
JsName toName = scopeContext.enterLabel(fromName);
Node fromStmt = labelNode.getFirstChild().getNext();
JsLabel toLabel = new JsLabel(toName);
toLabel.setStatement(mapStatement(fromStmt));
scope.exitLabel();
return toLabel;
}
/**
* Creates a reference to a name that may or may not be obfuscatable, based on
* whether it matches a known name in the scope.
*/
private JsNameRef mapName(Node node) {
String ident = node.getString();
return new JsNameRef(ident);
scopeContext.exitLabel();
return toLabel;
}
private JsNew mapNew(Node newNode) throws JsParserException {
@@ -1069,8 +1038,7 @@ public class JsParser {
// Map the catch variable.
//
Node fromCatchVarName = fromCatchNode.getFirstChild();
JsCatch catchBlock = new JsCatch(
getScope(), fromCatchVarName.getString());
JsCatch catchBlock = scopeContext.enterCatch(fromCatchVarName.getString());
// Pre-advance to the next catch block, if any.
// We do this here to decide whether or not this is the last one.
@@ -1102,6 +1070,7 @@ public class JsParser {
// Attach it.
//
toTry.getCatches().add(catchBlock);
scopeContext.exitCatch();
}
Node fromFinallyNode = fromCatchNodes.getNext();
@@ -1153,7 +1122,7 @@ public class JsParser {
// literals.
//
String fromName = fromVar.getString();
JsName toName = getScope().declareName(fromName);
JsName toName = scopeContext.localNameFor(fromName);
JsVars.JsVar toVar = new JsVars.JsVar(toName);
Node fromInit = fromVar.getFirstChild();
@@ -1180,14 +1149,6 @@ public class JsParser {
withNode);
}
private void popScope() {
scopeStack.pop();
}
private void pushScope(JsScope scope) {
scopeStack.push(scope);
}
private boolean isJsNumber(Node jsNode) {
int type = jsNode.getType();
return type == TokenStream.NUMBER || type == TokenStream.NUMBER;
@@ -0,0 +1,85 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gwt.dev.js
import com.google.dart.compiler.backend.js.ast.*
import java.util.Stack
class ScopeContext(private val rootScope: JsScope) {
private val scopes = Stack<JsScope>();
{
scopes.push(rootScope)
}
fun enterFunction(): JsFunction {
val fn = JsFunction(currentScope, "<js function>")
enterScope(fn.getScope())
return fn
}
fun exitFunction() {
assert(currentScope is JsFunctionScope)
exitScope()
}
fun enterCatch(ident: String): JsCatch {
val jsCatch = JsCatch(currentScope, ident)
enterScope(jsCatch.getScope())
return jsCatch
}
fun exitCatch() {
assert(currentScope is JsCatchScope)
exitScope()
}
fun enterLabel(ident: String): JsName =
(currentScope as JsFunctionScope).enterLabel(ident)
fun exitLabel() =
(currentScope as JsFunctionScope).exitLabel()
fun labelFor(ident: String): JsName? =
(currentScope as JsFunctionScope).findLabel(ident)
fun globalNameFor(ident: String): JsName =
currentScope.findName(ident) ?: rootScope.declareName(ident)
fun localNameFor(ident: String): JsName =
currentScope.findOwnNameOrDeclare(ident)
fun referenceFor(ident: String): JsNameRef =
JsNameRef(ident)
private fun enterScope(scope: JsScope) = scopes.push(scope)
private fun exitScope() = scopes.pop()
private val currentScope: JsScope
get() = scopes.peek()
}
/**
* Overrides JsFunctionScope declareName as it's mapped to declareFreshName
*/
private fun JsScope.findOwnNameOrDeclare(ident: String): JsName =
when (this) {
is JsFunctionScope -> declareNameUnsafe(ident)
else -> declareName(ident)
}