src/jdk/nashorn/internal/codegen/AssignSymbols.java

Print this page




 172 
 173     /**
 174      * Define symbols for all variable declarations at the top of the function scope. This way we can get around
 175      * problems like
 176      *
 177      * while (true) {
 178      *   break;
 179      *   if (true) {
 180      *     var s;
 181      *   }
 182      * }
 183      *
 184      * to an arbitrary nesting depth.
 185      *
 186      * see NASHORN-73
 187      *
 188      * @param functionNode the FunctionNode we are entering
 189      * @param body the body of the FunctionNode we are entering
 190      */
 191     private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
 192         // This visitor will assign symbol to all declared variables, except "var" declarations in for loop initializers.
 193         body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
 194             @Override
 195             protected boolean enterDefault(final Node node) {
 196                 // Don't bother visiting expressions; var is a statement, it can't be inside an expression.
 197                 // This will also prevent visiting nested functions (as FunctionNode is an expression).
 198                 return !(node instanceof Expression);
 199             }
 200 
 201             @Override
 202             public Node leaveVarNode(final VarNode varNode) {
 203                 if (varNode.isStatement()) {
 204                     final IdentNode ident  = varNode.getName();
 205                     final Block block = varNode.isBlockScoped() ? getLexicalContext().getCurrentBlock() : body;




 206                     final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags());
 207                     if (varNode.isFunctionDeclaration()) {
 208                         symbol.setIsFunctionDeclaration();
 209                     }
 210                     return varNode.setName(ident.setSymbol(symbol));
 211                 }
 212                 return varNode;
 213             }
 214         });
 215     }
 216 
 217     private IdentNode compilerConstantIdentifier(final CompilerConstants cc) {
 218         return createImplicitIdentifier(cc.symbolName()).setSymbol(lc.getCurrentFunction().compilerConstant(cc));
 219     }
 220 
 221     /**
 222      * Creates an ident node for an implicit identifier within the function (one not declared in the script source
 223      * code). These identifiers are defined with function's token and finish.
 224      * @param name the name of the identifier
 225      * @return an ident node representing the implicit identifier.
 226      */
 227     private IdentNode createImplicitIdentifier(final String name) {
 228         final FunctionNode fn = lc.getCurrentFunction();
 229         return new IdentNode(fn.getToken(), fn.getFinish(), name);
 230     }
 231 
 232     private Symbol createSymbol(final String name, final int flags) {
 233         if ((flags & Symbol.KINDMASK) == IS_GLOBAL) {


1029             } else if (node instanceof Block) {
1030                 if (((Block)node).getExistingSymbol(symbol.getName()) == symbol) {
1031                     // We reached the block that defines the symbol without reaching either the function boundary, or a
1032                     // WithNode. The symbol need not be scoped.
1033                     return false;
1034                 }
1035                 previousWasBlock = true;
1036             } else {
1037                 previousWasBlock = false;
1038             }
1039         }
1040         throw new AssertionError();
1041     }
1042 
1043     private static boolean isSplitArray(final LexicalContextNode expr) {
1044         if(!(expr instanceof ArrayLiteralNode)) {
1045             return false;
1046         }
1047         final List<ArrayUnit> units = ((ArrayLiteralNode)expr).getUnits();
1048         return !(units == null || units.isEmpty());









1049     }
1050 
1051     private void throwParserException(final String message, final Node origin) {
1052         if (origin == null) {
1053             throw new ParserException(message);
1054         }
1055         final Source source = compiler.getSource();
1056         final long token = origin.getToken();
1057         final int line = source.getLine(origin.getStart());
1058         final int column = source.getColumn(origin.getStart());
1059         final String formatted = ErrorManager.format(message, source, line, column, token);
1060         throw new ParserException(JSErrorType.SYNTAX_ERROR, formatted, source, line, column, token);
1061     }
1062 }


 172 
 173     /**
 174      * Define symbols for all variable declarations at the top of the function scope. This way we can get around
 175      * problems like
 176      *
 177      * while (true) {
 178      *   break;
 179      *   if (true) {
 180      *     var s;
 181      *   }
 182      * }
 183      *
 184      * to an arbitrary nesting depth.
 185      *
 186      * see NASHORN-73
 187      *
 188      * @param functionNode the FunctionNode we are entering
 189      * @param body the body of the FunctionNode we are entering
 190      */
 191     private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
 192         // This visitor will assign symbol to all declared variables.
 193         body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
 194             @Override
 195             protected boolean enterDefault(final Node node) {
 196                 // Don't bother visiting expressions; var is a statement, it can't be inside an expression.
 197                 // This will also prevent visiting nested functions (as FunctionNode is an expression).
 198                 return !(node instanceof Expression);
 199             }
 200 
 201             @Override
 202             public Node leaveVarNode(final VarNode varNode) {

 203                 final IdentNode ident  = varNode.getName();
 204                 final boolean blockScoped = varNode.isBlockScoped();
 205                 if (blockScoped && lc.inUnprotectedSwitchContext()) {
 206                     throwUnprotectedSwitchError(varNode);
 207                 }
 208                 final Block block = blockScoped ? lc.getCurrentBlock() : body;
 209                 final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags());
 210                 if (varNode.isFunctionDeclaration()) {
 211                     symbol.setIsFunctionDeclaration();
 212                 }
 213                 return varNode.setName(ident.setSymbol(symbol));
 214             }


 215         });
 216     }
 217 
 218     private IdentNode compilerConstantIdentifier(final CompilerConstants cc) {
 219         return createImplicitIdentifier(cc.symbolName()).setSymbol(lc.getCurrentFunction().compilerConstant(cc));
 220     }
 221 
 222     /**
 223      * Creates an ident node for an implicit identifier within the function (one not declared in the script source
 224      * code). These identifiers are defined with function's token and finish.
 225      * @param name the name of the identifier
 226      * @return an ident node representing the implicit identifier.
 227      */
 228     private IdentNode createImplicitIdentifier(final String name) {
 229         final FunctionNode fn = lc.getCurrentFunction();
 230         return new IdentNode(fn.getToken(), fn.getFinish(), name);
 231     }
 232 
 233     private Symbol createSymbol(final String name, final int flags) {
 234         if ((flags & Symbol.KINDMASK) == IS_GLOBAL) {


1030             } else if (node instanceof Block) {
1031                 if (((Block)node).getExistingSymbol(symbol.getName()) == symbol) {
1032                     // We reached the block that defines the symbol without reaching either the function boundary, or a
1033                     // WithNode. The symbol need not be scoped.
1034                     return false;
1035                 }
1036                 previousWasBlock = true;
1037             } else {
1038                 previousWasBlock = false;
1039             }
1040         }
1041         throw new AssertionError();
1042     }
1043 
1044     private static boolean isSplitArray(final LexicalContextNode expr) {
1045         if(!(expr instanceof ArrayLiteralNode)) {
1046             return false;
1047         }
1048         final List<ArrayUnit> units = ((ArrayLiteralNode)expr).getUnits();
1049         return !(units == null || units.isEmpty());
1050     }
1051 
1052     private void throwUnprotectedSwitchError(final VarNode varNode) {
1053         // Block scoped declarations in switch statements without explicit blocks should be declared
1054         // in a common block that contains all the case clauses. We cannot support this without a
1055         // fundamental rewrite of how switch statements are handled (case nodes contain blocks and are
1056         // directly contained by switch node). As a temporary solution we throw a reference error here.
1057         final String msg = ECMAErrors.getMessage("syntax.error.unprotected.switch.declaration", varNode.isLet() ? "let" : "const");
1058         throwParserException(msg, varNode);
1059     }
1060 
1061     private void throwParserException(final String message, final Node origin) {
1062         if (origin == null) {
1063             throw new ParserException(message);
1064         }
1065         final Source source = compiler.getSource();
1066         final long token = origin.getToken();
1067         final int line = source.getLine(origin.getStart());
1068         final int column = source.getColumn(origin.getStart());
1069         final String formatted = ErrorManager.format(message, source, line, column, token);
1070         throw new ParserException(JSErrorType.SYNTAX_ERROR, formatted, source, line, column, token);
1071     }
1072 }