mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-26 18:20:28 +00:00
8057980: let & const: remaining issues with lexical scoping
Reviewed-by: lagergren, attila
This commit is contained in:
parent
a0485e336d
commit
7b35db48f7
@ -189,7 +189,7 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
|
||||
* @param body the body of the FunctionNode we are entering
|
||||
*/
|
||||
private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
|
||||
// This visitor will assign symbol to all declared variables, except "var" declarations in for loop initializers.
|
||||
// This visitor will assign symbol to all declared variables.
|
||||
body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
|
||||
@Override
|
||||
protected boolean enterDefault(final Node node) {
|
||||
@ -200,16 +200,17 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
|
||||
|
||||
@Override
|
||||
public Node leaveVarNode(final VarNode varNode) {
|
||||
if (varNode.isStatement()) {
|
||||
final IdentNode ident = varNode.getName();
|
||||
final Block block = varNode.isBlockScoped() ? getLexicalContext().getCurrentBlock() : body;
|
||||
final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags());
|
||||
if (varNode.isFunctionDeclaration()) {
|
||||
symbol.setIsFunctionDeclaration();
|
||||
}
|
||||
return varNode.setName(ident.setSymbol(symbol));
|
||||
final IdentNode ident = varNode.getName();
|
||||
final boolean blockScoped = varNode.isBlockScoped();
|
||||
if (blockScoped && lc.inUnprotectedSwitchContext()) {
|
||||
throwUnprotectedSwitchError(varNode);
|
||||
}
|
||||
return varNode;
|
||||
final Block block = blockScoped ? lc.getCurrentBlock() : body;
|
||||
final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags());
|
||||
if (varNode.isFunctionDeclaration()) {
|
||||
symbol.setIsFunctionDeclaration();
|
||||
}
|
||||
return varNode.setName(ident.setSymbol(symbol));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1048,6 +1049,15 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
|
||||
return !(units == null || units.isEmpty());
|
||||
}
|
||||
|
||||
private void throwUnprotectedSwitchError(final VarNode varNode) {
|
||||
// Block scoped declarations in switch statements without explicit blocks should be declared
|
||||
// in a common block that contains all the case clauses. We cannot support this without a
|
||||
// fundamental rewrite of how switch statements are handled (case nodes contain blocks and are
|
||||
// directly contained by switch node). As a temporary solution we throw a reference error here.
|
||||
final String msg = ECMAErrors.getMessage("syntax.error.unprotected.switch.declaration", varNode.isLet() ? "let" : "const");
|
||||
throwParserException(msg, varNode);
|
||||
}
|
||||
|
||||
private void throwParserException(final String message, final Node origin) {
|
||||
if (origin == null) {
|
||||
throw new ParserException(message);
|
||||
|
||||
@ -3264,6 +3264,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
emitContinueLabel(continueLabel, liveLocalsOnContinue);
|
||||
}
|
||||
|
||||
if (loopNode.hasPerIterationScope() && lc.getParentBlock().needsScope()) {
|
||||
// ES6 for loops with LET init need a new scope for each iteration. We just create a shallow copy here.
|
||||
method.loadCompilerConstant(SCOPE);
|
||||
method.invoke(virtualCallNoLookup(ScriptObject.class, "copy", ScriptObject.class));
|
||||
method.storeCompilerConstant(SCOPE);
|
||||
}
|
||||
|
||||
if(method.isReachable()) {
|
||||
if(modify != null) {
|
||||
lineNumber(loopNode);
|
||||
|
||||
@ -525,7 +525,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> implements Lo
|
||||
|
||||
if (isAlwaysTrue(test)) {
|
||||
//turn it into a for node without a test.
|
||||
final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, ForNode.IS_FOR).accept(this);
|
||||
final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, 0).accept(this);
|
||||
lc.replace(whileNode, forNode);
|
||||
return forNode;
|
||||
}
|
||||
|
||||
@ -45,14 +45,14 @@ public final class ForNode extends LoopNode {
|
||||
/** Iterator symbol. */
|
||||
private Symbol iterator;
|
||||
|
||||
/** Is this a normal for loop? */
|
||||
public static final int IS_FOR = 1 << 0;
|
||||
|
||||
/** Is this a normal for in loop? */
|
||||
public static final int IS_FOR_IN = 1 << 1;
|
||||
public static final int IS_FOR_IN = 1 << 0;
|
||||
|
||||
/** Is this a normal for each in loop? */
|
||||
public static final int IS_FOR_EACH = 1 << 2;
|
||||
public static final int IS_FOR_EACH = 1 << 1;
|
||||
|
||||
/** Does this loop need a per-iteration scope because its init contain a LET declaration? */
|
||||
public static final int PER_ITERATION_SCOPE = 1 << 2;
|
||||
|
||||
private final int flags;
|
||||
|
||||
@ -264,4 +264,9 @@ public final class ForNode extends LoopNode {
|
||||
JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
|
||||
return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPerIterationScope() {
|
||||
return (flags & PER_ITERATION_SCOPE) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -597,6 +597,20 @@ public class LexicalContext {
|
||||
throw new AssertionError(target + " was expected in lexical context " + LexicalContext.this + " but wasn't");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current context is inside a switch statement without explicit blocks (curly braces).
|
||||
* @return true if in unprotected switch statement
|
||||
*/
|
||||
public boolean inUnprotectedSwitchContext() {
|
||||
for (int i = sp; i > 0; i--) {
|
||||
final LexicalContextNode next = stack[i];
|
||||
if (next instanceof Block) {
|
||||
return stack[i - 1] instanceof SwitchNode;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
|
||||
@ -177,4 +177,10 @@ public abstract class LoopNode extends BreakableStatement {
|
||||
* @return new loop node if changed otherwise the same
|
||||
*/
|
||||
public abstract LoopNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes);
|
||||
|
||||
/**
|
||||
* Does this loop have a LET declaration and hence require a per-iteration scope?
|
||||
* @return true if a per-iteration scope is required.
|
||||
*/
|
||||
public abstract boolean hasPerIterationScope();
|
||||
}
|
||||
|
||||
@ -45,19 +45,16 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
|
||||
/** Is this a var statement (as opposed to a "var" in a for loop statement) */
|
||||
private final int flags;
|
||||
|
||||
/** Flag that determines if this function node is a statement */
|
||||
public static final int IS_STATEMENT = 1 << 0;
|
||||
|
||||
/** Flag for ES6 LET declaration */
|
||||
public static final int IS_LET = 1 << 1;
|
||||
public static final int IS_LET = 1 << 0;
|
||||
|
||||
/** Flag for ES6 CONST declaration */
|
||||
public static final int IS_CONST = 1 << 2;
|
||||
public static final int IS_CONST = 1 << 1;
|
||||
|
||||
/** Flag that determines if this is the last function declaration in a function
|
||||
* This is used to micro optimize the placement of return value assignments for
|
||||
* a program node */
|
||||
public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 3;
|
||||
public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 2;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -69,7 +66,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
|
||||
* @param init init node or null if just a declaration
|
||||
*/
|
||||
public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Expression init) {
|
||||
this(lineNumber, token, finish, name, init, IS_STATEMENT);
|
||||
this(lineNumber, token, finish, name, init, 0);
|
||||
}
|
||||
|
||||
private VarNode(final VarNode varNode, final IdentNode name, final Expression init, final int flags) {
|
||||
@ -259,14 +256,6 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
|
||||
return setFlags(flags | flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a var statement (as opposed to a var initializer in a for loop).
|
||||
* @return true if this is a var statement (as opposed to a var initializer in a for loop).
|
||||
*/
|
||||
public boolean isStatement() {
|
||||
return (flags & IS_STATEMENT) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a function declaration.
|
||||
* @return true if this is a function declaration.
|
||||
|
||||
@ -150,4 +150,9 @@ public final class WhileNode extends LoopNode {
|
||||
}
|
||||
return test == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPerIterationScope() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -554,7 +554,7 @@ loop:
|
||||
// Set up new block. Captures first token.
|
||||
final ParserContextBlockNode newBlock = newBlock();
|
||||
try {
|
||||
statement();
|
||||
statement(false, false, true);
|
||||
} finally {
|
||||
restoreBlock(newBlock);
|
||||
}
|
||||
@ -770,7 +770,7 @@ loop:
|
||||
|
||||
try {
|
||||
// Get the next element.
|
||||
statement(true, allowPropertyFunction);
|
||||
statement(true, allowPropertyFunction, false);
|
||||
allowPropertyFunction = false;
|
||||
|
||||
// check for directive prologues
|
||||
@ -860,13 +860,15 @@ loop:
|
||||
* Parse any of the basic statement types.
|
||||
*/
|
||||
private void statement() {
|
||||
statement(false, false);
|
||||
statement(false, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param topLevel does this statement occur at the "top level" of a script or a function?
|
||||
* @param allowPropertyFunction allow property "get" and "set" functions?
|
||||
* @param singleStatement are we in a single statement context?
|
||||
*/
|
||||
private void statement(final boolean topLevel, final boolean allowPropertyFunction) {
|
||||
private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) {
|
||||
if (type == FUNCTION) {
|
||||
// As per spec (ECMA section 12), function declarations as arbitrary statement
|
||||
// is not "portable". Implementation can issue a warning or disallow the same.
|
||||
@ -930,6 +932,9 @@ loop:
|
||||
break;
|
||||
default:
|
||||
if (useBlockScope() && (type == LET || type == CONST)) {
|
||||
if (singleStatement) {
|
||||
throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token);
|
||||
}
|
||||
variableStatement(type, true);
|
||||
break;
|
||||
}
|
||||
@ -1055,7 +1060,7 @@ loop:
|
||||
next();
|
||||
|
||||
final List<VarNode> vars = new ArrayList<>();
|
||||
int varFlags = VarNode.IS_STATEMENT;
|
||||
int varFlags = 0;
|
||||
if (varType == LET) {
|
||||
varFlags |= VarNode.IS_LET;
|
||||
} else if (varType == CONST) {
|
||||
@ -1200,7 +1205,6 @@ loop:
|
||||
final int startLine = start;
|
||||
final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
|
||||
|
||||
|
||||
// Create FOR node, capturing FOR token.
|
||||
final ParserContextLoopNode forNode = new ParserContextLoopNode();
|
||||
lc.push(forNode);
|
||||
@ -1228,19 +1232,22 @@ loop:
|
||||
|
||||
switch (type) {
|
||||
case VAR:
|
||||
// Var statements captured in for outer block.
|
||||
// Var declaration captured in for outer block.
|
||||
vars = variableStatement(type, false);
|
||||
break;
|
||||
case SEMICOLON:
|
||||
break;
|
||||
default:
|
||||
if (useBlockScope() && (type == LET || type == CONST)) {
|
||||
// LET/CONST captured in container block created above.
|
||||
if (type == LET) {
|
||||
flags |= ForNode.PER_ITERATION_SCOPE;
|
||||
}
|
||||
// LET/CONST declaration captured in container block created above.
|
||||
vars = variableStatement(type, false);
|
||||
break;
|
||||
}
|
||||
if (env._const_as_var && type == CONST) {
|
||||
// Var statements captured in for outer block.
|
||||
// Var declaration captured in for outer block.
|
||||
vars = variableStatement(TokenType.VAR, false);
|
||||
break;
|
||||
}
|
||||
@ -1316,22 +1323,23 @@ loop:
|
||||
body = getStatement();
|
||||
} finally {
|
||||
lc.pop(forNode);
|
||||
if (vars != null) {
|
||||
for (final VarNode var : vars) {
|
||||
appendStatement(var);
|
||||
}
|
||||
}
|
||||
if (body != null) {
|
||||
appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
|
||||
}
|
||||
if (outer != null) {
|
||||
restoreBlock(outer);
|
||||
appendStatement(new BlockStatement(startLine, new Block(
|
||||
outer.getToken(),
|
||||
body.getFinish(),
|
||||
outer.getStatements())));
|
||||
}
|
||||
|
||||
if (vars != null) {
|
||||
for (final VarNode var : vars) {
|
||||
appendStatement(var);
|
||||
}
|
||||
}
|
||||
if (body != null) {
|
||||
appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
|
||||
}
|
||||
if (outer != null) {
|
||||
restoreBlock(outer);
|
||||
appendStatement(new BlockStatement(startLine, new Block(
|
||||
outer.getToken(),
|
||||
body.getFinish(),
|
||||
outer.getStatements())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1364,9 +1372,10 @@ loop:
|
||||
body = getStatement();
|
||||
} finally {
|
||||
lc.pop(whileNode);
|
||||
if (body != null){
|
||||
appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body));
|
||||
}
|
||||
}
|
||||
|
||||
if (body != null) {
|
||||
appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1408,8 +1417,9 @@ loop:
|
||||
}
|
||||
} finally {
|
||||
lc.pop(doWhileNode);
|
||||
appendStatement(new WhileNode(doLine, doToken, finish, true, test, body));
|
||||
}
|
||||
|
||||
appendStatement(new WhileNode(doLine, doToken, finish, true, test, body));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1607,17 +1617,12 @@ loop:
|
||||
throw error(AbstractParser.message("strict.no.with"), withToken);
|
||||
}
|
||||
|
||||
Expression expression = null;
|
||||
Block body = null;
|
||||
try {
|
||||
expect(LPAREN);
|
||||
expression = expression();
|
||||
expect(RPAREN);
|
||||
body = getStatement();
|
||||
} finally {
|
||||
appendStatement(new WithNode(withLine, withToken, finish, expression, body));
|
||||
}
|
||||
expect(LPAREN);
|
||||
final Expression expression = expression();
|
||||
expect(RPAREN);
|
||||
final Block body = getStatement();
|
||||
|
||||
appendStatement(new WithNode(withLine, withToken, finish, expression, body));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1706,8 +1711,9 @@ loop:
|
||||
next();
|
||||
} finally {
|
||||
lc.pop(switchNode);
|
||||
appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase));
|
||||
}
|
||||
|
||||
appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1738,10 +1744,9 @@ loop:
|
||||
} finally {
|
||||
assert lc.peek() instanceof ParserContextLabelNode;
|
||||
lc.pop(labelNode);
|
||||
if (ident != null){
|
||||
appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body));
|
||||
}
|
||||
}
|
||||
|
||||
appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2725,12 +2730,9 @@ loop:
|
||||
functionBody);
|
||||
|
||||
if (isStatement) {
|
||||
int varFlags = VarNode.IS_STATEMENT;
|
||||
if (!topLevel && useBlockScope()) {
|
||||
// mark ES6 block functions as lexically scoped
|
||||
varFlags |= VarNode.IS_LET;
|
||||
}
|
||||
final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags);
|
||||
// mark ES6 block functions as lexically scoped
|
||||
final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET;
|
||||
final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags);
|
||||
if (topLevel) {
|
||||
functionDeclarations.add(varNode);
|
||||
} else if (useBlockScope()) {
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
package jdk.nashorn.internal.parser;
|
||||
|
||||
/**
|
||||
* A ParserContextNode that represents a SwithcNode that is currently being parsed
|
||||
* A ParserContextNode that represents a SwitchNode that is currently being parsed
|
||||
*/
|
||||
class ParserContextSwitchNode extends ParserContextBaseNode implements ParserContextBreakableNode {
|
||||
|
||||
|
||||
@ -46,6 +46,8 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
|
||||
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
|
||||
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isScopeFlag;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isStrictFlag;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
@ -98,7 +100,7 @@ import jdk.nashorn.internal.runtime.linker.NashornGuards;
|
||||
* </ul>
|
||||
*/
|
||||
|
||||
public abstract class ScriptObject implements PropertyAccess {
|
||||
public abstract class ScriptObject implements PropertyAccess, Cloneable {
|
||||
/** __proto__ special property name inside object literals. ES6 draft. */
|
||||
public static final String PROTO_PROPERTY_NAME = "__proto__";
|
||||
|
||||
@ -2202,6 +2204,9 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
|
||||
if (find != null) {
|
||||
if (!find.getProperty().isWritable() && !NashornCallSiteDescriptor.isDeclaration(desc)) {
|
||||
if (NashornCallSiteDescriptor.isScope(desc) && find.getProperty().isLexicalBinding()) {
|
||||
throw typeError("assign.constant", name); // Overwriting ES6 const should throw also in non-strict mode.
|
||||
}
|
||||
// Existing, non-writable property
|
||||
return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
|
||||
}
|
||||
@ -3103,7 +3108,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
private boolean doesNotHaveEnsureLength(final long longIndex, final long oldLength, final int callSiteFlags) {
|
||||
if (longIndex >= oldLength) {
|
||||
if (!isExtensible()) {
|
||||
if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
|
||||
if (isStrictFlag(callSiteFlags)) {
|
||||
throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this));
|
||||
}
|
||||
return true;
|
||||
@ -3127,7 +3132,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
final long oldLength = getArray().length();
|
||||
final long longIndex = ArrayIndex.toLongIndex(index);
|
||||
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
|
||||
final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
|
||||
final boolean strict = isStrictFlag(callSiteFlags);
|
||||
setArray(getArray().set(index, value, strict));
|
||||
doesNotHaveEnsureDelete(longIndex, oldLength, strict);
|
||||
}
|
||||
@ -3137,7 +3142,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
final long oldLength = getArray().length();
|
||||
final long longIndex = ArrayIndex.toLongIndex(index);
|
||||
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
|
||||
final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
|
||||
final boolean strict = isStrictFlag(callSiteFlags);
|
||||
setArray(getArray().set(index, value, strict));
|
||||
doesNotHaveEnsureDelete(longIndex, oldLength, strict);
|
||||
}
|
||||
@ -3147,7 +3152,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
final long oldLength = getArray().length();
|
||||
final long longIndex = ArrayIndex.toLongIndex(index);
|
||||
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
|
||||
final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
|
||||
final boolean strict = isStrictFlag(callSiteFlags);
|
||||
setArray(getArray().set(index, value, strict));
|
||||
doesNotHaveEnsureDelete(longIndex, oldLength, strict);
|
||||
}
|
||||
@ -3157,7 +3162,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
final long oldLength = getArray().length();
|
||||
final long longIndex = ArrayIndex.toLongIndex(index);
|
||||
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
|
||||
final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
|
||||
final boolean strict = isStrictFlag(callSiteFlags);
|
||||
setArray(getArray().set(index, value, strict));
|
||||
doesNotHaveEnsureDelete(longIndex, oldLength, strict);
|
||||
}
|
||||
@ -3178,7 +3183,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
invalidateGlobalConstant(key);
|
||||
|
||||
if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) {
|
||||
final boolean isScope = NashornCallSiteDescriptor.isScopeFlag(callSiteFlags);
|
||||
final boolean isScope = isScopeFlag(callSiteFlags);
|
||||
// If the start object of the find is not this object it means the property was found inside a
|
||||
// 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set'
|
||||
// to the 'with' object.
|
||||
@ -3199,16 +3204,19 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
|
||||
if (f != null) {
|
||||
if (!f.getProperty().isWritable()) {
|
||||
if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
|
||||
if (isScopeFlag(callSiteFlags) && f.getProperty().isLexicalBinding()) {
|
||||
throw typeError("assign.constant", key); // Overwriting ES6 const should throw also in non-strict mode.
|
||||
}
|
||||
if (isStrictFlag(callSiteFlags)) {
|
||||
throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
f.setValue(value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags));
|
||||
f.setValue(value, isStrictFlag(callSiteFlags));
|
||||
|
||||
} else if (!isExtensible()) {
|
||||
if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
|
||||
if (isStrictFlag(callSiteFlags)) {
|
||||
throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
|
||||
}
|
||||
} else {
|
||||
@ -3235,7 +3243,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3255,7 +3263,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3275,7 +3283,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3295,7 +3303,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3314,7 +3322,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3333,7 +3341,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3352,7 +3360,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3371,7 +3379,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3390,7 +3398,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3409,7 +3417,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3428,7 +3436,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3447,7 +3455,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3465,7 +3473,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
if (getArray().has(index)) {
|
||||
final ArrayData data = getArray();
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3483,7 +3491,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3502,7 +3510,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3521,7 +3529,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (isValidArrayIndex(index)) {
|
||||
final ArrayData data = getArray();
|
||||
if (data.has(index)) {
|
||||
setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
|
||||
setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
|
||||
} else {
|
||||
doesNotHave(index, value, callSiteFlags);
|
||||
}
|
||||
@ -3685,6 +3693,29 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a shallow copy of this ScriptObject.
|
||||
* @return a shallow copy.
|
||||
*/
|
||||
public final ScriptObject copy() {
|
||||
try {
|
||||
return clone();
|
||||
} catch (final CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptObject clone() throws CloneNotSupportedException {
|
||||
final ScriptObject clone = (ScriptObject) super.clone();
|
||||
if (objectSpill != null) {
|
||||
clone.objectSpill = objectSpill.clone();
|
||||
clone.primitiveSpill = primitiveSpill.clone();
|
||||
}
|
||||
clone.arrayData = arrayData.copy();
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new UserAccessorProperty property. getter and setter functions are stored in
|
||||
* this ScriptObject and slot values are used in property object.
|
||||
|
||||
@ -61,9 +61,9 @@ public abstract class ArrayData {
|
||||
/**
|
||||
* Length of the array data. Not necessarily length of the wrapped array.
|
||||
* This is private to ensure that no one in a subclass is able to touch the length
|
||||
* without going through {@link setLength}. This is used to implement
|
||||
* without going through {@link #setLength}. This is used to implement
|
||||
* {@link LengthNotWritableFilter}s, ensuring that there are no ways past
|
||||
* a {@link setLength} function replaced by a nop
|
||||
* a {@link #setLength} function replaced by a nop
|
||||
*/
|
||||
private long length;
|
||||
|
||||
@ -79,11 +79,7 @@ public abstract class ArrayData {
|
||||
*/
|
||||
private static class UntouchedArrayData extends ContinuousArrayData {
|
||||
private UntouchedArrayData() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
private UntouchedArrayData(final int length) {
|
||||
super(length);
|
||||
super(0);
|
||||
}
|
||||
|
||||
private ArrayData toRealArrayData() {
|
||||
@ -100,7 +96,8 @@ public abstract class ArrayData {
|
||||
|
||||
@Override
|
||||
public ContinuousArrayData copy() {
|
||||
return new UntouchedArrayData((int)length());
|
||||
assert length() == 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -246,7 +243,7 @@ public abstract class ArrayData {
|
||||
public Class<?> getBoxedElementType() {
|
||||
return Integer.class;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
||||
@ -116,6 +116,7 @@ type.error.instanceof.on.non.object=instanceof must be called with a javascript
|
||||
type.error.cannot.convert.to.interface=object {0} cannot be converted to {1} due to "{2}"
|
||||
type.error.array.reduce.invalid.init=invalid initialValue for Array.prototype.reduce
|
||||
type.error.array.reduceright.invalid.init=invalid initialValue for Array.prototype.reduceRight
|
||||
type.error.assign.constant=Assignment to constant "{0}"
|
||||
type.error.cannot.get.default.string=Cannot get default string value
|
||||
type.error.cannot.get.default.number=Cannot get default number value
|
||||
type.error.cant.apply.with.to.null=Cannot apply "with" to null
|
||||
@ -166,6 +167,7 @@ syntax.error.invalid.json=Invalid JSON: {0}
|
||||
syntax.error.strict.cant.delete=cannot delete "{0}" in strict mode
|
||||
syntax.error.redeclare.variable=Variable "{0}" has already been declared
|
||||
syntax.error.assign.constant=Assignment to constant "{0}"
|
||||
syntax.error.unprotected.switch.declaration=Unsupported {0} declaration in unprotected switch statement
|
||||
|
||||
io.error.cant.write=cannot write "{0}"
|
||||
config.error.no.dest=no destination directory supplied
|
||||
|
||||
@ -39,3 +39,40 @@ try {
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
let a = [];
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
a.push(function() { print(i); });
|
||||
}
|
||||
|
||||
a.forEach(function(f) { f(); });
|
||||
|
||||
a = [];
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (i == 5) {
|
||||
i = "foo";
|
||||
}
|
||||
a.push(function() { print(i); });
|
||||
}
|
||||
|
||||
a.forEach(function(f) { f(); });
|
||||
|
||||
try {
|
||||
print(i);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
a = [];
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
if (i % 2 == 1) {
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
a.push(function() { print(i); });
|
||||
}
|
||||
|
||||
a.forEach(function(f) { f(); });
|
||||
|
||||
@ -9,3 +9,25 @@
|
||||
8
|
||||
9
|
||||
ReferenceError: "i" is not defined
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
foo
|
||||
ReferenceError: "i" is not defined
|
||||
0
|
||||
4
|
||||
8
|
||||
12
|
||||
16
|
||||
|
||||
49
nashorn/test/script/basic/es6/let-const-statement-context.js
Normal file
49
nashorn/test/script/basic/es6/let-const-statement-context.js
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8057980: let & const: remaining issues with lexical scoping
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6
|
||||
*/
|
||||
|
||||
function tryEval(s) {
|
||||
try {
|
||||
eval(s);
|
||||
} catch (e) {
|
||||
print(String(e).replace(/\\/g, "/"));
|
||||
}
|
||||
}
|
||||
|
||||
tryEval('if (true) let x = 1;');
|
||||
tryEval('if (true) const x = 1;');
|
||||
tryEval('while (true) let x = 1;');
|
||||
tryEval('while (true) const x = 1;');
|
||||
tryEval('for (;;) let x = 1;');
|
||||
tryEval('for (;;) const x = 1;');
|
||||
tryEval('do let x = 1; while (true);');
|
||||
tryEval('do const x = 1; while (true);');
|
||||
tryEval('with (y) const x = 1;');
|
||||
tryEval('with (y) let x = 1;');
|
||||
@ -0,0 +1,30 @@
|
||||
SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:10 Expected statement but found let declaration
|
||||
if (true) let x = 1;
|
||||
^
|
||||
SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:10 Expected statement but found const declaration
|
||||
if (true) const x = 1;
|
||||
^
|
||||
SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:13 Expected statement but found let declaration
|
||||
while (true) let x = 1;
|
||||
^
|
||||
SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:13 Expected statement but found const declaration
|
||||
while (true) const x = 1;
|
||||
^
|
||||
SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found let declaration
|
||||
for (;;) let x = 1;
|
||||
^
|
||||
SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found const declaration
|
||||
for (;;) const x = 1;
|
||||
^
|
||||
SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:3 Expected statement but found let declaration
|
||||
do let x = 1; while (true);
|
||||
^
|
||||
SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:3 Expected statement but found const declaration
|
||||
do const x = 1; while (true);
|
||||
^
|
||||
SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found const declaration
|
||||
with (y) const x = 1;
|
||||
^
|
||||
SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found let declaration
|
||||
with (y) let x = 1;
|
||||
^
|
||||
45
nashorn/test/script/basic/es6/let-const-switch.js
Normal file
45
nashorn/test/script/basic/es6/let-const-switch.js
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8057980: let & const: remaining issues with lexical scoping
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6
|
||||
*/
|
||||
|
||||
function tryEval(s) {
|
||||
try {
|
||||
eval(s);
|
||||
} catch (e) {
|
||||
print(String(e).replace(/\\/g, "/"));
|
||||
}
|
||||
}
|
||||
|
||||
tryEval('var x = 0; switch (x) { case 0: { let x = 1; print(x); } case 1: { let x = 2; print(x); }} print(x);');
|
||||
tryEval('var x = 0; switch (x) { case 0: { const x = 1; print(x); } case 1: { const x = 2; print(x); }} print(x);');
|
||||
|
||||
// TODO: the following should not throw
|
||||
tryEval('switch (x) { case 0: let x = 1; }');
|
||||
tryEval('switch (x) { case 0: const x = 1; }');
|
||||
12
nashorn/test/script/basic/es6/let-const-switch.js.EXPECTED
Normal file
12
nashorn/test/script/basic/es6/let-const-switch.js.EXPECTED
Normal file
@ -0,0 +1,12 @@
|
||||
1
|
||||
2
|
||||
0
|
||||
1
|
||||
2
|
||||
0
|
||||
SyntaxError: test/script/basic/es6/let-const-switch.js#34:8<eval>:1:25 Unsupported let declaration in unprotected switch statement
|
||||
switch (x) { case 0: let x = 1; }
|
||||
^
|
||||
SyntaxError: test/script/basic/es6/let-const-switch.js#34:8<eval>:1:27 Unsupported const declaration in unprotected switch statement
|
||||
switch (x) { case 0: const x = 1; }
|
||||
^
|
||||
@ -40,17 +40,8 @@ load(__DIR__ + "let-load-lib.js");
|
||||
}
|
||||
|
||||
print("imported var: " + a);
|
||||
try {
|
||||
print("imported let: " + b);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
try {
|
||||
print("imported const: " + c);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
print("imported let: " + b);
|
||||
print("imported const: " + c);
|
||||
|
||||
top();
|
||||
|
||||
@ -60,4 +51,10 @@ try {
|
||||
print(e);
|
||||
}
|
||||
|
||||
try {
|
||||
c = "foo";
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -6,3 +6,4 @@ imported let: 2
|
||||
imported const: 3
|
||||
top level function
|
||||
ReferenceError: "block" is not defined
|
||||
TypeError: Assignment to constant "c"
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
test
|
||||
test
|
||||
test
|
||||
3
|
||||
3
|
||||
3
|
||||
0
|
||||
1
|
||||
2
|
||||
0
|
||||
1
|
||||
2
|
||||
|
||||
@ -13,6 +13,7 @@ false
|
||||
false
|
||||
true
|
||||
true
|
||||
TypeError: Assignment to constant "CONST"
|
||||
VAR
|
||||
LETLET
|
||||
CONST
|
||||
@ -28,3 +29,4 @@ false
|
||||
false
|
||||
true
|
||||
true
|
||||
TypeError: Assignment to constant "CONST"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user