296
297 final List<Statement> stmts = body.getStatements();
298 final List<Statement> newStatements = new ArrayList<>(stmts.size() + syntheticInitializers.size());
299 newStatements.addAll(syntheticInitializers);
300 newStatements.addAll(stmts);
301 return functionNode.setBody(lc, body.setStatements(lc, newStatements));
302 }
303
304 /**
305 * Defines a new symbol in the given block.
306 *
307 * @param block the block in which to define the symbol
308 * @param name name of symbol.
309 * @param origin origin node
310 * @param symbolFlags Symbol flags.
311 *
312 * @return Symbol for given name or null for redefinition.
313 */
314 private Symbol defineSymbol(final Block block, final String name, final Node origin, final int symbolFlags) {
315 int flags = symbolFlags;
316 final boolean isBlockScope = (flags & IS_LET) != 0 || (flags & IS_CONST) != 0;
317 final boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
318
319 Symbol symbol;
320 final FunctionNode function;
321 if (isBlockScope) {
322 // block scoped variables always live in current block, no need to look for existing symbols in parent blocks.
323 symbol = block.getExistingSymbol(name);
324 function = lc.getCurrentFunction();
325 } else {
326 symbol = findSymbol(block, name);
327 function = lc.getFunction(block);
328 }
329
330 // Global variables are implicitly always scope variables too.
331 if (isGlobal) {
332 flags |= IS_SCOPE;
333 }
334
335 if (lc.getCurrentFunction().isProgram()) {
336 flags |= IS_PROGRAM_LEVEL;
337 }
338
339 final boolean isParam = (flags & KINDMASK) == IS_PARAM;
340 final boolean isVar = (flags & KINDMASK) == IS_VAR;
341
342 if (symbol != null) {
343 // Symbol was already defined. Check if it needs to be redefined.
344 if (isParam) {
345 if (!isLocal(function, symbol)) {
346 // Not defined in this function. Create a new definition.
347 symbol = null;
348 } else if (symbol.isParam()) {
349 // Duplicate parameter. Null return will force an error.
350 throw new AssertionError("duplicate parameter");
351 }
352 } else if (isVar) {
353 if (isBlockScope) {
354 // Check redeclaration in same block
355 if (symbol.hasBeenDeclared()) {
356 throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin);
357 } else {
358 symbol.setHasBeenDeclared();
359 }
360 } else if ((flags & IS_INTERNAL) != 0) {
361 // Always create a new definition.
362 symbol = null;
363 } else {
364 // Found LET or CONST in parent scope of same function - s SyntaxError
365 if (symbol.isBlockScoped() && isLocal(lc.getCurrentFunction(), symbol)) {
366 throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin);
367 }
368 // Not defined in this function. Create a new definition.
369 if (!isLocal(function, symbol) || symbol.less(IS_VAR)) {
370 symbol = null;
371 }
372 }
373 }
374 }
375
376 if (symbol == null) {
377 // If not found, then create a new one.
378 final Block symbolBlock;
379
380 // Determine where to create it.
381 if (isVar && ((flags & IS_INTERNAL) != 0 || isBlockScope)) {
382 symbolBlock = block; //internal vars are always defined in the block closest to them
383 } else if (isGlobal) {
384 symbolBlock = lc.getOutermostFunction().getBody();
385 } else {
386 symbolBlock = lc.getFunctionBody(function);
387 }
388
389 // Create and add to appropriate block.
390 symbol = createSymbol(name, flags);
391 symbolBlock.putSymbol(lc, symbol);
392
393 if ((flags & IS_SCOPE) == 0) {
394 // Initial assumption; symbol can lose its slot later
395 symbol.setNeedsSlot(true);
396 }
397 } else if (symbol.less(flags)) {
398 symbol.setFlags(flags);
399 }
400
401 return symbol;
523 // body of the declared function for self-reference.
524 if (varNode.isFunctionDeclaration()) {
525 defineVarIdent(varNode);
526 }
527 return true;
528 }
529
530 @Override
531 public Node leaveVarNode(final VarNode varNode) {
532 if (!varNode.isFunctionDeclaration()) {
533 defineVarIdent(varNode);
534 }
535 return super.leaveVarNode(varNode);
536 }
537
538 private void defineVarIdent(final VarNode varNode) {
539 final IdentNode ident = varNode.getName();
540 final int flags;
541 if (varNode.isAnonymousFunctionDeclaration()) {
542 flags = IS_INTERNAL;
543 } else if (lc.getCurrentFunction().isProgram()) {
544 flags = IS_SCOPE;
545 } else {
546 flags = 0;
547 }
548 defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | flags);
549 }
550
551 private Symbol exceptionSymbol() {
552 return newObjectInternal(EXCEPTION_PREFIX);
553 }
554
555 /**
556 * This has to run before fix assignment types, store any type specializations for
557 * parameters, then turn them into objects for the generic version of this method.
558 *
559 * @param functionNode functionNode
560 */
561 private FunctionNode finalizeParameters(final FunctionNode functionNode) {
562 final List<IdentNode> newParams = new ArrayList<>();
563 final boolean isVarArg = functionNode.isVarArg();
|
296
297 final List<Statement> stmts = body.getStatements();
298 final List<Statement> newStatements = new ArrayList<>(stmts.size() + syntheticInitializers.size());
299 newStatements.addAll(syntheticInitializers);
300 newStatements.addAll(stmts);
301 return functionNode.setBody(lc, body.setStatements(lc, newStatements));
302 }
303
304 /**
305 * Defines a new symbol in the given block.
306 *
307 * @param block the block in which to define the symbol
308 * @param name name of symbol.
309 * @param origin origin node
310 * @param symbolFlags Symbol flags.
311 *
312 * @return Symbol for given name or null for redefinition.
313 */
314 private Symbol defineSymbol(final Block block, final String name, final Node origin, final int symbolFlags) {
315 int flags = symbolFlags;
316 final boolean isLexicalScope = (flags & IS_LET) != 0 || (flags & IS_CONST) != 0;
317 final boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
318
319 Symbol symbol;
320 final FunctionNode function;
321 if (isLexicalScope) {
322 // lexically scoped variables always live in current block, no need to look for existing symbols in parent blocks.
323 symbol = block.getExistingSymbol(name);
324 function = lc.getCurrentFunction();
325 } else {
326 symbol = findSymbol(block, name);
327 function = lc.getFunction(block);
328 }
329
330 // Global variables are implicitly always scope variables too.
331 if (isGlobal) {
332 flags |= IS_SCOPE;
333 }
334
335 if (lc.getCurrentFunction().isProgram()) {
336 flags |= IS_PROGRAM_LEVEL;
337 }
338
339 final boolean isParam = (flags & KINDMASK) == IS_PARAM;
340 final boolean isVar = (flags & KINDMASK) == IS_VAR;
341
342 if (symbol != null) {
343 // Symbol was already defined. Check if it needs to be redefined.
344 if (isParam) {
345 if (!isLocal(function, symbol)) {
346 // Not defined in this function. Create a new definition.
347 symbol = null;
348 } else if (symbol.isParam()) {
349 // Duplicate parameter. Null return will force an error.
350 throw new AssertionError("duplicate parameter");
351 }
352 } else if (isVar) {
353 if (isLexicalScope) {
354 // Check redeclaration in same block
355 if (symbol.hasBeenDeclared()) {
356 throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin);
357 } else {
358 symbol.setHasBeenDeclared();
359 // Set scope flag on top-level lexical symbols
360 if (function.isProgram() && function.getBody() == block) {
361 symbol.setIsScope();
362 }
363 }
364 } else if ((flags & IS_INTERNAL) != 0) {
365 // Always create a new definition.
366 symbol = null;
367 } else {
368 // Found LET or CONST in parent scope of same function - s SyntaxError
369 if (symbol.isBlockScoped() && isLocal(lc.getCurrentFunction(), symbol)) {
370 throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin);
371 }
372 // Not defined in this function. Create a new definition.
373 if (!isLocal(function, symbol) || symbol.less(IS_VAR)) {
374 symbol = null;
375 }
376 }
377 }
378 }
379
380 if (symbol == null) {
381 // If not found, then create a new one.
382 final Block symbolBlock;
383
384 // Determine where to create it.
385 if (isVar && ((flags & IS_INTERNAL) != 0 || isLexicalScope)) {
386 symbolBlock = block; //internal vars are always defined in the block closest to them
387 } else if (isGlobal) {
388 symbolBlock = lc.getOutermostFunction().getBody();
389 } else {
390 symbolBlock = lc.getFunctionBody(function);
391 }
392
393 // Create and add to appropriate block.
394 symbol = createSymbol(name, flags);
395 symbolBlock.putSymbol(lc, symbol);
396
397 if ((flags & IS_SCOPE) == 0) {
398 // Initial assumption; symbol can lose its slot later
399 symbol.setNeedsSlot(true);
400 }
401 } else if (symbol.less(flags)) {
402 symbol.setFlags(flags);
403 }
404
405 return symbol;
527 // body of the declared function for self-reference.
528 if (varNode.isFunctionDeclaration()) {
529 defineVarIdent(varNode);
530 }
531 return true;
532 }
533
534 @Override
535 public Node leaveVarNode(final VarNode varNode) {
536 if (!varNode.isFunctionDeclaration()) {
537 defineVarIdent(varNode);
538 }
539 return super.leaveVarNode(varNode);
540 }
541
542 private void defineVarIdent(final VarNode varNode) {
543 final IdentNode ident = varNode.getName();
544 final int flags;
545 if (varNode.isAnonymousFunctionDeclaration()) {
546 flags = IS_INTERNAL;
547 } else if (!varNode.isBlockScoped() && lc.getCurrentFunction().isProgram()) {
548 flags = IS_SCOPE;
549 } else {
550 flags = 0;
551 }
552 defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | flags);
553 }
554
555 private Symbol exceptionSymbol() {
556 return newObjectInternal(EXCEPTION_PREFIX);
557 }
558
559 /**
560 * This has to run before fix assignment types, store any type specializations for
561 * parameters, then turn them into objects for the generic version of this method.
562 *
563 * @param functionNode functionNode
564 */
565 private FunctionNode finalizeParameters(final FunctionNode functionNode) {
566 final List<IdentNode> newParams = new ArrayList<>();
567 final boolean isVarArg = functionNode.isVarArg();
|