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:
igor%mir2.org 2003-02-16 11:34:54 +00:00
Родитель 56c3f65ac9
Коммит bed15cd944
8 изменённых файлов: 66 добавлений и 94 удалений

Просмотреть файл

@ -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);
}
}