зеркало из https://github.com/mozilla/gecko-dev.git
Creating and filling VariableTable directly during parsing phase and then accessing it in NodeTransformer. It still does not remove the need to have a separated walk through the tree for variables but now it only checks for function name / variable name clashes.
And http://bugzilla.mozilla.org/show_bug.cgi?id=193555 is now fixed as well.
This commit is contained in:
Родитель
56c3f65ac9
Коммит
bed15cd944
|
@ -53,12 +53,7 @@ public class FunctionNode extends Node {
|
|||
return itsVariableTable;
|
||||
}
|
||||
|
||||
public void setVariableTable(VariableTable variableTable) {
|
||||
// Can do it only once
|
||||
if (variableTable == null) Context.codeBug();
|
||||
if (itsVariableTable != null) Context.codeBug();
|
||||
itsVariableTable = variableTable;
|
||||
}
|
||||
protected void markVariableTableReady() { }
|
||||
|
||||
public boolean requiresActivation() {
|
||||
return itsNeedsActivation;
|
||||
|
@ -104,7 +99,7 @@ public class FunctionNode extends Node {
|
|||
}
|
||||
|
||||
public int getParameterCount() {
|
||||
return argNames.size();
|
||||
return itsVariableTable.getParameterCount();
|
||||
}
|
||||
|
||||
protected VariableTable itsVariableTable;
|
||||
|
@ -112,5 +107,4 @@ public class FunctionNode extends Node {
|
|||
protected boolean itsCheckThis;
|
||||
protected int itsFunctionType;
|
||||
private String functionName;
|
||||
ObjArray argNames;
|
||||
}
|
||||
|
|
|
@ -52,13 +52,14 @@ public class IRFactory {
|
|||
/**
|
||||
* Script (for associating file/url names with toplevel scripts.)
|
||||
*/
|
||||
public Object createScript(Object body, String sourceName,
|
||||
int baseLineno, int endLineno, Object source)
|
||||
public Object
|
||||
createScript(Object body, VariableTable vars, String sourceName,
|
||||
int baseLineno, int endLineno, String source)
|
||||
{
|
||||
Node result = Node.newString(TokenStream.SCRIPT, sourceName);
|
||||
Node children = ((Node) body).getFirstChild();
|
||||
if (children != null)
|
||||
result.addChildrenToBack(children);
|
||||
if (children != null) { result.addChildrenToBack(children); }
|
||||
result.putProp(Node.VARS_PROP, vars);
|
||||
result.putProp(Node.SOURCENAME_PROP, sourceName);
|
||||
result.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
|
||||
result.putIntProp(Node.END_LINENO_PROP, endLineno);
|
||||
|
@ -206,7 +207,7 @@ public class IRFactory {
|
|||
return new FunctionNode(name, (Node) statements);
|
||||
}
|
||||
|
||||
public Object createFunction(String name, ObjArray argNames,
|
||||
public Object createFunction(String name, VariableTable vars,
|
||||
Object statements,
|
||||
String sourceName, int baseLineno,
|
||||
int endLineno, Object source,
|
||||
|
@ -216,7 +217,7 @@ public class IRFactory {
|
|||
name = "";
|
||||
}
|
||||
FunctionNode f = (FunctionNode) createFunctionNode(name, statements);
|
||||
f.argNames = argNames;
|
||||
f.itsVariableTable = vars;
|
||||
f.setFunctionType(functionType);
|
||||
f.putProp(Node.SOURCENAME_PROP, sourceName);
|
||||
f.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
|
||||
|
|
|
@ -505,40 +505,33 @@ public class NativeGlobal implements IdFunctionMaster {
|
|||
String sourceName = ScriptRuntime.
|
||||
makeUrlForGeneratedScript(true, filename, lineNumber);
|
||||
|
||||
// Compile the reader with opt level of -1 to force interpreter
|
||||
// mode.
|
||||
int oldOptLevel = cx.getOptimizationLevel();
|
||||
cx.setOptimizationLevel(-1);
|
||||
Script script;
|
||||
try {
|
||||
StringReader in = new StringReader((String) x);
|
||||
|
||||
// Compile the reader with opt level of -1 to force interpreter
|
||||
// mode.
|
||||
int oldOptLevel = cx.getOptimizationLevel();
|
||||
cx.setOptimizationLevel(-1);
|
||||
Script script;
|
||||
try {
|
||||
script = cx.compileReader(scope, in, sourceName, 1, null);
|
||||
} finally {
|
||||
cx.setOptimizationLevel(oldOptLevel);
|
||||
}
|
||||
|
||||
// if the compile fails, an error has been reported by the
|
||||
// compiler, but we need to stop execution to avoid
|
||||
// infinite looping on while(true) { eval('foo bar') } -
|
||||
// so we throw an EvaluatorException.
|
||||
if (script == null) {
|
||||
String message = Context.getMessage0("msg.syntax");
|
||||
throw new EvaluatorException(message);
|
||||
}
|
||||
|
||||
InterpretedScript is = (InterpretedScript) script;
|
||||
is.itsData.itsFromEvalCode = true;
|
||||
Object result = is.call(cx, scope, (Scriptable) thisArg,
|
||||
ScriptRuntime.emptyArgs);
|
||||
|
||||
return result;
|
||||
script = cx.compileString(scope, (String)x, sourceName, 1,
|
||||
null);
|
||||
} finally {
|
||||
cx.setOptimizationLevel(oldOptLevel);
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
// should never happen since we just made the Reader from a String
|
||||
throw new RuntimeException("unexpected io exception");
|
||||
|
||||
// if the compile fails, an error has been reported by the
|
||||
// compiler, but we need to stop execution to avoid
|
||||
// infinite looping on while(true) { eval('foo bar') } -
|
||||
// so we throw an EvaluatorException.
|
||||
if (script == null) {
|
||||
String message = Context.getMessage0("msg.syntax");
|
||||
throw new EvaluatorException(message);
|
||||
}
|
||||
|
||||
InterpretedScript is = (InterpretedScript) script;
|
||||
is.itsData.itsFromEvalCode = true;
|
||||
Object result = is.call(cx, scope, (Scriptable) thisArg,
|
||||
ScriptRuntime.emptyArgs);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -64,15 +64,15 @@ public class NodeTransformer {
|
|||
loops = new ObjArray();
|
||||
loopEnds = new ObjArray();
|
||||
inFunction = tree.getType() == TokenStream.FUNCTION;
|
||||
VariableTable vars = new VariableTable();
|
||||
VariableTable vars;
|
||||
if (!inFunction) {
|
||||
addVariables(tree, vars);
|
||||
tree.putProp(Node.VARS_PROP, vars);
|
||||
vars = (VariableTable)tree.getProp(Node.VARS_PROP);
|
||||
checkVariables(tree, vars);
|
||||
} else {
|
||||
FunctionNode fnNode = (FunctionNode)tree;
|
||||
addParameters(fnNode, vars);
|
||||
addVariables(tree, vars);
|
||||
fnNode.setVariableTable(vars);
|
||||
vars = fnNode.getVariableTable();
|
||||
checkVariables(tree, vars);
|
||||
fnNode.markVariableTableReady();
|
||||
}
|
||||
irFactory = createIRFactory(ts, scope);
|
||||
|
||||
|
@ -488,11 +488,10 @@ public class NodeTransformer {
|
|||
return tree;
|
||||
}
|
||||
|
||||
protected void addVariables(Node tree, VariableTable vars) {
|
||||
// OPT: a whole pass to collect variables seems expensive.
|
||||
private void checkVariables(Node tree, VariableTable vars) {
|
||||
// OPT: a whole pass to check variables seems expensive.
|
||||
// Could special case to go into statements only.
|
||||
boolean inFunction = (tree.getType() == TokenStream.FUNCTION);
|
||||
ObjToIntMap fNames = null;
|
||||
PreorderNodeIterator iter = new PreorderNodeIterator();
|
||||
for (iter.start(tree); !iter.done(); iter.next()) {
|
||||
Node node = iter.getCurrent();
|
||||
|
@ -508,25 +507,13 @@ public class NodeTransformer {
|
|||
if (name == null)
|
||||
continue;
|
||||
vars.removeLocal(name);
|
||||
if (fNames == null)
|
||||
fNames = new ObjToIntMap();
|
||||
fNames.put(name, 0);
|
||||
}
|
||||
if (nodeType != TokenStream.VAR)
|
||||
continue;
|
||||
for (Node cursor = node.getFirstChild(); cursor != null;
|
||||
cursor = cursor.getNext())
|
||||
{
|
||||
String name = cursor.getString();
|
||||
if (fNames == null || !fNames.has(name))
|
||||
vars.addLocal(name);
|
||||
}
|
||||
}
|
||||
if (inFunction) {
|
||||
FunctionNode fn = (FunctionNode)tree;
|
||||
String name = fn.getFunctionName();
|
||||
if (fn.getFunctionType() == FunctionNode.FUNCTION_EXPRESSION
|
||||
&& name != null && name.length() > 0 && vars.hasVariable(name))
|
||||
&& name != null && name.length() > 0 && !vars.hasVariable(name))
|
||||
{
|
||||
// A function expression needs to have its name as a variable
|
||||
// (if it isn't already allocated as a variable). See
|
||||
|
@ -545,17 +532,6 @@ public class NodeTransformer {
|
|||
}
|
||||
}
|
||||
|
||||
protected void addParameters(FunctionNode fnNode, VariableTable vars) {
|
||||
if (vars.getParameterCount() == 0) {
|
||||
ObjArray argNames = fnNode.argNames;
|
||||
// Add parameters
|
||||
for (int i = 0, N = argNames.size(); i != N; ++i) {
|
||||
String arg = (String)argNames.get(i);
|
||||
vars.addParameter(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void visitNew(Node node, Node tree) {
|
||||
}
|
||||
|
||||
|
|
|
@ -104,6 +104,7 @@ class Parser {
|
|||
this.ok = true;
|
||||
fn_sourceTop = 0;
|
||||
fn_functionNumber = 0;
|
||||
fn_vars = new VariableTable();
|
||||
|
||||
int tt; // last token from getToken();
|
||||
int baseLineno = ts.getLineno(); // line number where source starts
|
||||
|
@ -146,7 +147,7 @@ class Parser {
|
|||
|
||||
String source = sourceToString(0);
|
||||
sourceBuffer = null; // To help GC
|
||||
pn = nf.createScript(pn, ts.getSourceName(),
|
||||
pn = nf.createScript(pn, fn_vars, ts.getSourceName(),
|
||||
baseLineno, ts.getLineno(), source);
|
||||
return pn;
|
||||
}
|
||||
|
@ -240,11 +241,14 @@ class Parser {
|
|||
// function to parent source
|
||||
int saved_sourceTop = fn_sourceTop;
|
||||
int saved_functionNumber = fn_functionNumber;
|
||||
ObjArray args = new ObjArray();
|
||||
VariableTable saved_vars = fn_vars;
|
||||
VariableTable new_vars = new VariableTable();
|
||||
|
||||
Object body;
|
||||
String source;
|
||||
try {
|
||||
fn_functionNumber = 0;
|
||||
fn_vars = new_vars;
|
||||
|
||||
// FUNCTION as the first token in a Source means it's a function
|
||||
// definition, and not a reference.
|
||||
|
@ -260,7 +264,11 @@ class Parser {
|
|||
first = false;
|
||||
mustMatchToken(ts, ts.NAME, "msg.no.parm");
|
||||
String s = ts.getString();
|
||||
args.add(s);
|
||||
if (new_vars.hasVariable(s)) {
|
||||
Object[] msgArgs = { s };
|
||||
ts.reportSyntaxWarning("msg.dup.parms", msgArgs);
|
||||
}
|
||||
new_vars.addParameter(s);
|
||||
sourceAddString(ts.NAME, s);
|
||||
} while (ts.matchToken(ts.COMMA));
|
||||
|
||||
|
@ -282,11 +290,12 @@ class Parser {
|
|||
finally {
|
||||
fn_sourceTop = saved_sourceTop;
|
||||
fn_functionNumber = saved_functionNumber;
|
||||
fn_vars = saved_vars;
|
||||
}
|
||||
|
||||
Object pn;
|
||||
if (memberExprNode == null) {
|
||||
pn = nf.createFunction(name, args, body,
|
||||
pn = nf.createFunction(name, new_vars, body,
|
||||
ts.getSourceName(),
|
||||
baseLineno, ts.getLineno(),
|
||||
source,
|
||||
|
@ -304,7 +313,7 @@ class Parser {
|
|||
checkWellTerminatedFunction(ts);
|
||||
}
|
||||
} else {
|
||||
pn = nf.createFunction(name, args, body,
|
||||
pn = nf.createFunction(name, new_vars, body,
|
||||
ts.getSourceName(),
|
||||
baseLineno, ts.getLineno(),
|
||||
source,
|
||||
|
@ -877,6 +886,7 @@ class Parser {
|
|||
first = false;
|
||||
|
||||
sourceAddString(ts.NAME, s);
|
||||
fn_vars.addLocal(s);
|
||||
name = nf.createName(s);
|
||||
|
||||
// omitted check for argument hiding
|
||||
|
@ -2276,6 +2286,8 @@ class Parser {
|
|||
// Nested function number
|
||||
private int fn_functionNumber;
|
||||
|
||||
private VariableTable fn_vars;
|
||||
|
||||
private static final int TOP_LEVEL_SCRIPT_OR_FUNCTION = 0;
|
||||
private static final int CONSTRUCTED_FUNCTION = 1;
|
||||
private static final int NESTED_FUNCTION = 2;
|
||||
|
|
|
@ -1352,7 +1352,7 @@ public class TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
private void reportSyntaxWarning(String messageProperty, Object[] args) {
|
||||
void reportSyntaxWarning(String messageProperty, Object[] args) {
|
||||
String message = Context.getMessage(messageProperty, args);
|
||||
Context.reportWarning(message, getSourceName(),
|
||||
getLineno(), getLine(), getOffset());
|
||||
|
|
|
@ -69,11 +69,7 @@ public class VariableTable {
|
|||
public void addParameter(String pName) {
|
||||
// Check addParameter is not called after addLocal
|
||||
if (varStart != itsVariables.size()) Context.codeBug();
|
||||
int pIndex = itsVariableNames.get(pName, -1);
|
||||
if (itsVariableNames.has(pName)) {
|
||||
String message = Context.getMessage1("msg.dup.parms", pName);
|
||||
Context.reportWarning(message, null, 0, null, 0);
|
||||
}
|
||||
// Allow non-unique parameter names: use the last occurrence
|
||||
int index = varStart++;
|
||||
itsVariables.add(pName);
|
||||
itsVariableNames.put(pName, index);
|
||||
|
|
|
@ -47,13 +47,13 @@ class OptFunctionNode extends FunctionNode {
|
|||
itsClassName = className;
|
||||
}
|
||||
|
||||
public void setVariableTable(VariableTable variableTable) {
|
||||
super.setVariableTable(variableTable);
|
||||
int N = variableTable.size();
|
||||
int parameterCount = variableTable.getParameterCount();
|
||||
protected void markVariableTableReady() {
|
||||
super.markVariableTableReady();
|
||||
int N = itsVariableTable.size();
|
||||
int parameterCount = itsVariableTable.getParameterCount();
|
||||
optVars = new OptLocalVariable[N];
|
||||
for (int i = 0; i != N; ++i) {
|
||||
String name = variableTable.getVariable(i);
|
||||
String name = itsVariableTable.getVariable(i);
|
||||
optVars[i] = new OptLocalVariable(name, i < parameterCount);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче