зеркало из https://github.com/mozilla/pjs.git
Implement checks for generators returning values.
Patch from Roshan James, roshanj@google.com.
This commit is contained in:
Родитель
08e940f4ab
Коммит
a6099a8648
|
@ -643,6 +643,7 @@ public class Node
|
|||
static final int END_DROPS_OFF = 1;
|
||||
static final int END_RETURNS = 2;
|
||||
static final int END_RETURNS_VALUE = 4;
|
||||
static final int END_YIELDS = 8;
|
||||
|
||||
/**
|
||||
* Checks that every return usage in a function body is consistent with the
|
||||
|
@ -653,7 +654,7 @@ public class Node
|
|||
{
|
||||
int n = endCheck();
|
||||
return (n & END_RETURNS_VALUE) == 0 ||
|
||||
(n & (END_DROPS_OFF|END_RETURNS)) == 0;
|
||||
(n & (END_DROPS_OFF|END_RETURNS|END_YIELDS)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -868,6 +869,14 @@ public class Node
|
|||
case Token.BREAK:
|
||||
return endCheckBreak();
|
||||
|
||||
case Token.EXPR_VOID:
|
||||
if (this.first != null)
|
||||
return first.endCheck();
|
||||
return END_DROPS_OFF;
|
||||
|
||||
case Token.YIELD:
|
||||
return END_YIELDS;
|
||||
|
||||
case Token.CONTINUE:
|
||||
case Token.THROW:
|
||||
return END_UNREACHED;
|
||||
|
|
|
@ -95,7 +95,7 @@ public class Parser
|
|||
private ObjArray loopSet;
|
||||
private ObjArray loopAndSwitchSet;
|
||||
private boolean hasReturnValue;
|
||||
private int functionEndFlags;
|
||||
private int endFlags;
|
||||
// end of per function variables
|
||||
|
||||
// Exception to unwind
|
||||
|
@ -517,7 +517,7 @@ public class Parser
|
|||
ObjArray savedLoopAndSwitchSet = loopAndSwitchSet;
|
||||
loopAndSwitchSet = null;
|
||||
boolean savedHasReturnValue = hasReturnValue;
|
||||
int savedFunctionEndFlags = functionEndFlags;
|
||||
int savedFunctionEndFlags = endFlags;
|
||||
|
||||
Node body;
|
||||
try {
|
||||
|
@ -574,7 +574,7 @@ public class Parser
|
|||
}
|
||||
finally {
|
||||
hasReturnValue = savedHasReturnValue;
|
||||
functionEndFlags = savedFunctionEndFlags;
|
||||
endFlags = savedFunctionEndFlags;
|
||||
loopAndSwitchSet = savedLoopAndSwitchSet;
|
||||
loopSet = savedLoopSet;
|
||||
labelSet = savedLabelSet;
|
||||
|
@ -1206,6 +1206,19 @@ public class Parser
|
|||
|
||||
return pn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the bits in the mask have changed to all set.
|
||||
* @param before bits before change
|
||||
* @param after bits after change
|
||||
* @param mask mask for bits
|
||||
* @return true if all the bits in the mask are set in "after" but not
|
||||
* "before"
|
||||
*/
|
||||
private static final boolean nowAllSet(int before, int after, int mask)
|
||||
{
|
||||
return ((before & mask) != mask) && ((after & mask) == mask);
|
||||
}
|
||||
|
||||
private Node returnOrYield(int tt, boolean exprContext)
|
||||
throws IOException, ParserException
|
||||
|
@ -1235,28 +1248,44 @@ public class Parser
|
|||
e = expr(false);
|
||||
break;
|
||||
}
|
||||
|
||||
int before = endFlags;
|
||||
Node ret;
|
||||
|
||||
if (tt == Token.RETURN) {
|
||||
// see if we need a strict mode warning
|
||||
// TODO(js1.7gen): check for mixture of yield and value returns
|
||||
if (e == null) {
|
||||
if (functionEndFlags == Node.END_RETURNS_VALUE)
|
||||
addStrictWarning("msg.return.inconsistent", "");
|
||||
|
||||
functionEndFlags |= Node.END_RETURNS;
|
||||
} else {
|
||||
hasReturnValue = true;
|
||||
if (functionEndFlags == Node.END_RETURNS)
|
||||
addStrictWarning("msg.return.inconsistent", "");
|
||||
|
||||
functionEndFlags |= Node.END_RETURNS_VALUE;
|
||||
}
|
||||
return nf.createReturn(e, lineno);
|
||||
if (e == null ) {
|
||||
endFlags |= Node.END_RETURNS;
|
||||
} else {
|
||||
endFlags |= Node.END_RETURNS_VALUE;
|
||||
hasReturnValue = true;
|
||||
}
|
||||
ret = nf.createReturn(e, lineno);
|
||||
|
||||
// see if we need a strict mode warning
|
||||
if (nowAllSet(before, endFlags,
|
||||
Node.END_RETURNS|Node.END_RETURNS_VALUE))
|
||||
{
|
||||
addStrictWarning("msg.return.inconsistent", "");
|
||||
}
|
||||
} else {
|
||||
Node n = nf.createYield(e, lineno);
|
||||
if (exprContext)
|
||||
return n;
|
||||
return new Node(Token.EXPR_VOID, n, lineno);
|
||||
endFlags |= Node.END_YIELDS;
|
||||
ret = nf.createYield(e, lineno);
|
||||
if (!exprContext)
|
||||
ret = new Node(Token.EXPR_VOID, ret, lineno);
|
||||
}
|
||||
|
||||
// see if we are mixing yields and value returns.
|
||||
if (nowAllSet(before, endFlags,
|
||||
Node.END_YIELDS|Node.END_RETURNS_VALUE))
|
||||
{
|
||||
String name = ((FunctionNode)currentScriptOrFn).getFunctionName();
|
||||
if (name.length() == 0)
|
||||
addError("msg.anon.generator.returns", "");
|
||||
else
|
||||
addError("msg.generator.returns", name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -422,6 +422,12 @@ msg.anon.no.return.value =\
|
|||
msg.return.inconsistent =\
|
||||
return statement is inconsistent with previous usage
|
||||
|
||||
msg.generator.returns =\
|
||||
generator function {0} returns a value
|
||||
|
||||
msg.anon.generator.returns =\
|
||||
anonymous generator function returns a value
|
||||
|
||||
msg.syntax =\
|
||||
syntax error
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче