Package org.aspectj.org.eclipse.jdt.internal.eval

Source Code of org.aspectj.org.eclipse.jdt.internal.eval.CodeSnippetParser

/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.eval;

import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.core.compiler.IProblem;
import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemReporter;

/**
* A parser for code snippets.
*/
public class CodeSnippetParser extends Parser implements EvaluationConstants {
  int codeSnippetStart, codeSnippetEnd;
  EvaluationContext evaluationContext;
  boolean hasRecoveredOnExpression;
  int lastStatement = -1; // end of last top level statement
  int lineSeparatorLength;

  int problemCountBeforeRecovery = 0;
/**
* Creates a new code snippet parser.
*/
public CodeSnippetParser(ProblemReporter problemReporter, EvaluationContext evaluationContext, boolean optimizeStringLiterals, int codeSnippetStart, int codeSnippetEnd) {
  super(problemReporter, optimizeStringLiterals);
  this.codeSnippetStart = codeSnippetStart;
  this.codeSnippetEnd = codeSnippetEnd;
  this.evaluationContext = evaluationContext;
  this.reportOnlyOneSyntaxError = true;
  this.javadocParser.checkDocComment = false;
}
protected void classInstanceCreation(boolean alwaysQualified) {
  // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt

  // ClassBodyopt produces a null item on the astStak if it produces NO class body
  // An empty class body produces a 0 on the length stack.....

  AllocationExpression alloc;
  int length;
  if (((length = this.astLengthStack[this.astLengthPtr--]) == 1)
    && (this.astStack[this.astPtr] == null)) {
    //NO ClassBody
    this.astPtr--;
    if (alwaysQualified) {
      alloc = new QualifiedAllocationExpression();
    } else {
      alloc = new CodeSnippetAllocationExpression(this.evaluationContext);
    }
    alloc.sourceEnd = this.endPosition; //the position has been stored explicitly

    if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
      this.expressionPtr -= length;
      System.arraycopy(
        this.expressionStack,
        this.expressionPtr + 1,
        alloc.arguments = new Expression[length],
        0,
        length);
    }
    alloc.type = getTypeReference(0);
    //the default constructor with the correct number of argument
    //will be created and added by the TC (see createsInternalConstructorWithBinding)
    alloc.sourceStart = this.intStack[this.intPtr--];
    pushOnExpressionStack(alloc);
  } else {
    dispatchDeclarationInto(length);
    TypeDeclaration anonymousTypeDeclaration = (TypeDeclaration) this.astStack[this.astPtr];
    anonymousTypeDeclaration.declarationSourceEnd = this.endStatementPosition;
    if (anonymousTypeDeclaration.allocation != null) {
      anonymousTypeDeclaration.allocation.sourceEnd = this.endStatementPosition;
    }   
    this.astPtr--;
    this.astLengthPtr--;

    // mark initializers with local type mark if needed
    markInitializersWithLocalType(anonymousTypeDeclaration);
  }
}
protected void consumeClassDeclaration() {
  super.consumeClassDeclaration();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeClassHeaderName1() {
  // ClassHeaderName ::= Modifiersopt 'class' 'Identifier'
  TypeDeclaration typeDecl;
  if (this.nestedMethod[this.nestedType] == 0) {
    if (this.nestedType != 0) {
      typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
      typeDecl.bits |= ASTNode.IsMemberType;
    } else {
      typeDecl = new CodeSnippetTypeDeclaration(this.compilationUnit.compilationResult);
    }
  } else {
    // Record that the block has a declaration for local types
    typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
    typeDecl.bits |= ASTNode.IsLocalType;
    markEnclosingMemberWithLocalType();
    blockReal();
  }

  //highlight the name of the type
  long pos = this.identifierPositionStack[this.identifierPtr];
  typeDecl.sourceEnd = (int) pos;
  typeDecl.sourceStart = (int) (pos >>> 32);
  typeDecl.name = this.identifierStack[this.identifierPtr--];
  this.identifierLengthPtr--;

  //compute the declaration source too
  typeDecl.declarationSourceStart = this.intStack[this.intPtr--];
  this.intPtr--;
  // 'class' and 'interface' push an int position
  typeDecl.modifiersSourceStart = this.intStack[this.intPtr--];
  typeDecl.modifiers = this.intStack[this.intPtr--];
  if (typeDecl.modifiersSourceStart >= 0) {
    typeDecl.declarationSourceStart = typeDecl.modifiersSourceStart;
  }
  typeDecl.bodyStart = typeDecl.sourceEnd + 1;
  pushOnAstStack(typeDecl);

  this.listLength = 0; // will be updated when reading super-interfaces
  // recovery
  if (this.currentElement != null){
    this.lastCheckPoint = typeDecl.bodyStart;
    this.currentElement = this.currentElement.add(typeDecl, 0);
    this.lastIgnoredToken = -1;
  }
  // javadoc
  typeDecl.javadoc = this.javadoc;
  this.javadoc = null;
}
protected void consumeEmptyStatement() {
  super.consumeEmptyStatement();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeEnhancedForStatement() {
  super.consumeEnhancedForStatement();
  /* recovery */
  recordLastStatementIfNeeded()
}
protected void consumeExpressionStatement() {
  super.consumeExpressionStatement();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeFieldAccess(boolean isSuperAccess) {
  // FieldAccess ::= Primary '.' 'Identifier'
  // FieldAccess ::= 'super' '.' 'Identifier'

  FieldReference fr =
    new CodeSnippetFieldReference(
      this.identifierStack[this.identifierPtr],
      this.identifierPositionStack[this.identifierPtr--],
      this.evaluationContext);
  this.identifierLengthPtr--;
  if (isSuperAccess) {
    //considerates the fieldReference beginning at the 'super' .... 
    fr.sourceStart = this.intStack[this.intPtr--];
    problemReporter().codeSnippetMissingClass(null,0, 0);
    fr.receiver = new CodeSnippetSuperReference(fr.sourceStart, this.endPosition);
    pushOnExpressionStack(fr);
  } else {
    //optimize push/pop
    if ((fr.receiver = this.expressionStack[this.expressionPtr]).isThis()) {
      //fieldreference begins at the this
      fr.sourceStart = fr.receiver.sourceStart;
    }
    this.expressionStack[this.expressionPtr] = fr;
  }
}
protected void consumeInterfaceHeaderName1() {
  // InterfaceHeaderName ::= Modifiersopt 'interface' 'Identifier'
  TypeDeclaration typeDecl;
  if (this.nestedMethod[this.nestedType] == 0) {
    if (this.nestedType != 0) {
      typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
      typeDecl.bits |= ASTNode.IsMemberType;
    } else {
      typeDecl = new CodeSnippetTypeDeclaration(this.compilationUnit.compilationResult);
    }
  } else {
    // Record that the block has a declaration for local types
    typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
    typeDecl.bits |= ASTNode.IsLocalType;
    markEnclosingMemberWithLocalType();
    blockReal();
  }

  //highlight the name of the type
  long pos = this.identifierPositionStack[this.identifierPtr];
  typeDecl.sourceEnd = (int) pos;
  typeDecl.sourceStart = (int) (pos >>> 32);
  typeDecl.name = this.identifierStack[this.identifierPtr--];
  this.identifierLengthPtr--;

  //compute the declaration source too
  typeDecl.declarationSourceStart = this.intStack[this.intPtr--];
  this.intPtr--;
  // 'class' and 'interface' push an int position
  typeDecl.modifiersSourceStart = this.intStack[this.intPtr--];
  typeDecl.modifiers = this.intStack[this.intPtr--];
  if (typeDecl.modifiersSourceStart >= 0) {
    typeDecl.declarationSourceStart = typeDecl.modifiersSourceStart;
  }
  typeDecl.bodyStart = typeDecl.sourceEnd + 1;
  pushOnAstStack(typeDecl);
  this.listLength = 0; // will be updated when reading super-interfaces
  // recovery
  if (this.currentElement != null){ // is recovering
    this.lastCheckPoint = typeDecl.bodyStart;
    this.currentElement = this.currentElement.add(typeDecl, 0);
    this.lastIgnoredToken = -1;   
  }
  // javadoc
  typeDecl.javadoc = this.javadoc;
  this.javadoc = null;
}
protected void consumeInternalCompilationUnit() {
  // InternalCompilationUnit ::= PackageDeclaration
  // InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports
  // InternalCompilationUnit ::= ImportDeclarations ReduceImports
}
protected void consumeInternalCompilationUnitWithTypes() {
  // InternalCompilationUnit ::= PackageDeclaration ImportDeclarations ReduceImports TypeDeclarations
  // InternalCompilationUnit ::= PackageDeclaration TypeDeclarations
  // InternalCompilationUnit ::= TypeDeclarations
  // InternalCompilationUnit ::= ImportDeclarations ReduceImports TypeDeclarations
  // consume type declarations
  int length;
  if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) {
    this.compilationUnit.types = new TypeDeclaration[length];
    this.astPtr -= length;
    System.arraycopy(this.astStack, this.astPtr + 1, this.compilationUnit.types, 0, length);
  }
}
protected void consumeLocalVariableDeclarationStatement() {
  super.consumeLocalVariableDeclarationStatement();
  /* recovery */
  recordLastStatementIfNeeded();
}

/**
* In case emulating local variables, wrap the (recovered) statements inside a
* try statement so as to achieve local state commiting (copy local vars back to fields).
* The CSToCuMapper could not be used, since it could have interfered with
* the syntax recovery specific to code snippets.
*/
protected void consumeMethodDeclaration(boolean isNotAbstract) {
  // MethodDeclaration ::= MethodHeader MethodBody
  // AbstractMethodDeclaration ::= MethodHeader ';'

  super.consumeMethodDeclaration(isNotAbstract);
 
  // now we know that we have a method declaration at the top of the ast stack
  MethodDeclaration methodDecl = (MethodDeclaration) this.astStack[this.astPtr];

  // automatically wrap the last statement inside a return statement, if it is an expression
  // support have to be defined at toplevel only
  if (this.isTopLevelType()) {
    int last = methodDecl.statements == null ? -1 : methodDecl.statements.length - 1;
    if (last >= 0 && methodDecl.statements[last] instanceof Expression){
      Expression lastExpression = (Expression) methodDecl.statements[last];
      methodDecl.statements[last] = new CodeSnippetReturnStatement(
                      lastExpression,
                      lastExpression.sourceStart,
                      lastExpression.sourceEnd);
    }
  }
 
  int start = methodDecl.bodyStart-1, end = start;
  long position = ((long)start << 32) + end;
  long[] positions = new long[]{position};
  if (this.evaluationContext.localVariableNames != null) {

    int varCount = this.evaluationContext.localVariableNames.length; // n local decls+ try statement

    // generate n local variable declarations: [type] [name] = val$[name];
    Statement[] newStatements = new Statement[varCount+1];
    for (int i = 0; i < varCount; i++){
      char[] trimmedTypeName = this.evaluationContext.localVariableTypeNames[i];
      int nameEnd = CharOperation.indexOf('[', trimmedTypeName);
      if (nameEnd >= 0) {
        trimmedTypeName = CharOperation.subarray(trimmedTypeName, 0, nameEnd);
      }
      nameEnd = CharOperation.indexOf(' ', trimmedTypeName);
      if (nameEnd >= 0) {
        trimmedTypeName = CharOperation.subarray(trimmedTypeName, 0, nameEnd);
      }
      TypeReference typeReference = new QualifiedTypeReference(
        CharOperation.splitOn('.', trimmedTypeName),
        positions);
      int dimCount = CharOperation.occurencesOf('[', this.evaluationContext.localVariableTypeNames[i]);
      if (dimCount > 0) {
        typeReference = this.copyDims(typeReference, dimCount);
      }
      NameReference init = new SingleNameReference(
                  CharOperation.concat(LOCAL_VAR_PREFIX, this.evaluationContext.localVariableNames[i]), position);
      LocalDeclaration declaration = new LocalDeclaration(this.evaluationContext.localVariableNames[i], start, end);
      declaration.initialization = init;
      declaration.type = typeReference;
      declaration.modifiers = this.evaluationContext.localVariableModifiers[i];
      newStatements[i] = declaration;
    }

    // generate try { [snippet] } finally { [save locals to fields] }
    // try block
    TryStatement tryStatement = new TryStatement();
    Block tryBlock = new Block(methodDecl.explicitDeclarations);
    tryBlock.sourceStart = start;
    tryBlock.sourceEnd = end;
    tryBlock.statements = methodDecl.statements; // snippet statements
    tryStatement.tryBlock = tryBlock;
    // finally block
    Block finallyBlock = new Block(0);
    finallyBlock.sourceStart = start;
    finallyBlock.sourceEnd = end;
    finallyBlock.statements = new Statement[varCount];
    for (int i = 0; i < varCount; i++){
      finallyBlock.statements[i] = new Assignment(
        new SingleNameReference(CharOperation.concat(LOCAL_VAR_PREFIX, this.evaluationContext.localVariableNames[i]), position),
        new SingleNameReference(this.evaluationContext.localVariableNames[i], position),
        (int) position);
    }
    tryStatement.finallyBlock = finallyBlock;

    newStatements[varCount] = tryStatement;
    methodDecl.statements = newStatements;
  }
}

protected void consumeMethodInvocationName() {
  // MethodInvocation ::= Name '(' ArgumentListopt ')'

  if (this.scanner.startPosition >= this.codeSnippetStart
    && this.scanner.startPosition <= this.codeSnippetEnd + 1 + this.lineSeparatorLength // 14838
    && isTopLevelType()) {
     
    // when the name is only an identifier...we have a message send to "this" (implicit)

    MessageSend m = newMessageSend();
    m.sourceEnd = this.rParenPos;
    m.sourceStart =
      (int) ((m.nameSourcePosition = this.identifierPositionStack[this.identifierPtr]) >>> 32);
    m.selector = this.identifierStack[this.identifierPtr--];
    if (this.identifierLengthStack[this.identifierLengthPtr] == 1) {
      m.receiver = new CodeSnippetThisReference(0,0,this.evaluationContext, true);
      this.identifierLengthPtr--;
    } else {
      this.identifierLengthStack[this.identifierLengthPtr]--;
      m.receiver = getUnspecifiedReference();
      m.sourceStart = m.receiver.sourceStart;   
    }
    pushOnExpressionStack(m);
  } else {
    super.consumeMethodInvocationName();
  }
}

protected void consumeMethodInvocationSuper() {
  // MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')'

  MessageSend m = newMessageSend();
  m.sourceStart = this.intStack[this.intPtr--];
  m.sourceEnd = this.rParenPos;
  m.nameSourcePosition = this.identifierPositionStack[this.identifierPtr];
  m.selector = this.identifierStack[this.identifierPtr--];
  this.identifierLengthPtr--;
  m.receiver = new CodeSnippetSuperReference(m.sourceStart, this.endPosition);
  pushOnExpressionStack(m);
}
protected void consumePrimaryNoNewArrayThis() {
  // PrimaryNoNewArray ::= 'this'

  if (this.scanner.startPosition >= this.codeSnippetStart
    && this.scanner.startPosition <= this.codeSnippetEnd + 1 + this.lineSeparatorLength // 14838
    && isTopLevelType()) {
    pushOnExpressionStack(
      new CodeSnippetThisReference(this.intStack[this.intPtr--], this.endPosition, this.evaluationContext, false));
  } else {
    super.consumePrimaryNoNewArrayThis();
  }
}
protected void consumeStatementBreak() {
  super.consumeStatementBreak();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementBreakWithLabel() {
  super.consumeStatementBreakWithLabel();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementCatch() {
  super.consumeStatementCatch();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementContinue() {
  super.consumeStatementContinue();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementContinueWithLabel() {
  super.consumeStatementContinueWithLabel();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementDo() {
  super.consumeStatementDo();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementFor() {
  super.consumeStatementFor();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementIfNoElse() {
  super.consumeStatementIfNoElse();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementIfWithElse() {
  super.consumeStatementIfWithElse();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementLabel() {
  super.consumeStatementLabel();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementReturn() {
  // ReturnStatement ::= 'return' Expressionopt ';'

  // returned value intercepted by code snippet
  // support have to be defined at toplevel only
  if ((this.hasRecoveredOnExpression
      || (this.scanner.startPosition >= this.codeSnippetStart && this.scanner.startPosition <= this.codeSnippetEnd+1+this.lineSeparatorLength /* 14838*/))
    && this.expressionLengthStack[this.expressionLengthPtr] != 0
    && isTopLevelType()) {
    this.expressionLengthPtr--;
    Expression expression = this.expressionStack[this.expressionPtr--];
    pushOnAstStack(
      new CodeSnippetReturnStatement(
        expression,
        expression.sourceStart,
        expression.sourceEnd));
  } else {
    super.consumeStatementReturn();
  }
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementSwitch() {
  super.consumeStatementSwitch();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementSynchronized() {
  super.consumeStatementSynchronized();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementThrow() {
  super.consumeStatementThrow();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementTry(boolean arg_0) {
  super.consumeStatementTry(arg_0);
  /* recovery */
  recordLastStatementIfNeeded();
}
protected void consumeStatementWhile() {
  super.consumeStatementWhile();
  /* recovery */
  recordLastStatementIfNeeded();
}
protected CompilationUnitDeclaration endParse(int act) {
  if (this.hasRecoveredOnExpression) {
    CompilationResult unitResult = this.compilationUnit.compilationResult;
    if (act != ERROR_ACTION) { // expression recovery worked
      // flush previously recorded problems
      for (int i = 0; i < unitResult.problemCount; i++) {
        unitResult.problems[i] = null; // discard problem
      }
      unitResult.problemCount = 0;
      if (this.referenceContext instanceof AbstractMethodDeclaration) {
        ((AbstractMethodDeclaration)this.referenceContext).ignoreFurtherInvestigation = false;
      }
      if (this.referenceContext instanceof CompilationUnitDeclaration) {
        ((CompilationUnitDeclaration)this.referenceContext).ignoreFurtherInvestigation = false;
      }

      // consume expresion as a return statement
      consumeStatementReturn();
      int fieldsCount =
        (this.evaluationContext.localVariableNames == null ? 0 : this.evaluationContext.localVariableNames.length)
        + (this.evaluationContext.declaringTypeName == null ? 0 : 1);
      if (this.astPtr > (this.diet ? 0 : 2 + fieldsCount)) {
          // in diet mode, the ast stack was empty when we went for method body
          // otherwise it contained the type, the generated fields for local variables,
          // the generated field for 'this' and the method
        consumeBlockStatements();
      }
      consumeMethodBody();
      if (!this.diet) {
        consumeMethodDeclaration(true);
        if (fieldsCount > 0) {
          consumeClassBodyDeclarations();
        }
        consumeClassBodyDeclarationsopt();
        consumeClassDeclaration();
        consumeInternalCompilationUnitWithTypes();
        consumeCompilationUnit();
      }
      this.lastAct = ACCEPT_ACTION;
    } else {
      // might have more than one error recorded:
      // 1. during regular parse
      // 2. during expression recovery
      // -> must filter out one of them, the earliest one is less accurate
      int maxRegularPos = 0, problemCount = unitResult.problemCount;
      for (int i = 0; i < this.problemCountBeforeRecovery; i++) {
        // skip unmatched bracket problems
        if (unitResult.problems[i].getID() == IProblem.UnmatchedBracket) continue;
       
        int start = unitResult.problems[i].getSourceStart();
        if (start > maxRegularPos && start <= this.codeSnippetEnd) {
          maxRegularPos = start;
        }
      }
      int maxRecoveryPos = 0;
      for (int i = this.problemCountBeforeRecovery; i < problemCount; i++) {
        // skip unmatched bracket problems
        if (unitResult.problems[i].getID() == IProblem.UnmatchedBracket) continue;
       
        int start = unitResult.problems[i].getSourceStart();
        if (start > maxRecoveryPos && start <= this.codeSnippetEnd) {
          maxRecoveryPos = start;
        }
      }
      if (maxRecoveryPos > maxRegularPos) {
        System.arraycopy(unitResult.problems, this.problemCountBeforeRecovery, unitResult.problems, 0, problemCount - this.problemCountBeforeRecovery);
        unitResult.problemCount -= this.problemCountBeforeRecovery;       
      } else {
        unitResult.problemCount -= (problemCount - this.problemCountBeforeRecovery);
      }
      for (int i = unitResult.problemCount; i < problemCount; i++) {
        unitResult.problems[i] = null; // discard problem
      }

    }
  }
  return super.endParse(act);
}
protected NameReference getUnspecifiedReference() {
  /* build a (unspecified) NameReference which may be qualified*/

  if (this.scanner.startPosition >= this.codeSnippetStart
    && this.scanner.startPosition <= this.codeSnippetEnd+1+this.lineSeparatorLength /*14838*/){
    int length;
    NameReference ref;
    if ((length = this.identifierLengthStack[this.identifierLengthPtr--]) == 1) {
      // single variable reference
      ref =
        new CodeSnippetSingleNameReference(
          this.identifierStack[this.identifierPtr],
          this.identifierPositionStack[this.identifierPtr--],
          this.evaluationContext);
    } else {
      //Qualified variable reference
      char[][] tokens = new char[length][];
      this.identifierPtr -= length;
      System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length);
      long[] positions = new long[length];
      System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length);
      ref =
        new CodeSnippetQualifiedNameReference(tokens,
          positions,
          (int) (this.identifierPositionStack[this.identifierPtr + 1] >> 32), // sourceStart
          (int) this.identifierPositionStack[this.identifierPtr + length],
          this.evaluationContext); // sourceEnd
    }
    return ref;
  } else {
    return super.getUnspecifiedReference();
  }
}
protected NameReference getUnspecifiedReferenceOptimized() {
  /* build a (unspecified) NameReference which may be qualified
  The optimization occurs for qualified reference while we are
  certain in this case the last item of the qualified name is
  a field access. This optimization is IMPORTANT while it results
  that when a NameReference is build, the type checker should always
  look for that it is not a type reference */

  if (this.scanner.startPosition >= this.codeSnippetStart
    && this.scanner.startPosition <= this.codeSnippetEnd+1+this.lineSeparatorLength /*14838*/){
    int length;
    NameReference ref;
    if ((length = this.identifierLengthStack[this.identifierLengthPtr--]) == 1) {
      // single variable reference
      ref =
        new CodeSnippetSingleNameReference(
          this.identifierStack[this.identifierPtr],
          this.identifierPositionStack[this.identifierPtr--],
          this.evaluationContext);
      ref.bits &= ~ASTNode.RestrictiveFlagMASK;
      ref.bits |= Binding.LOCAL | Binding.FIELD;
      return ref;
    }

    //Qualified-variable-reference
    //In fact it is variable-reference DOT field-ref , but it would result in a type
    //conflict tha can be only reduce by making a superclass (or inetrface ) between
    //nameReference and FiledReference or putting FieldReference under NameReference
    //or else..........This optimisation is not really relevant so just leave as it is

    char[][] tokens = new char[length][];
    this.identifierPtr -= length;
    System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length);
    long[] positions = new long[length];
    System.arraycopy(this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length);
    ref = new CodeSnippetQualifiedNameReference(
        tokens,
        positions,
        (int) (this.identifierPositionStack[this.identifierPtr + 1] >> 32), // sourceStart
        (int) this.identifierPositionStack[this.identifierPtr + length],
        this.evaluationContext); // sourceEnd
    ref.bits &= ~ASTNode.RestrictiveFlagMASK;
    ref.bits |= Binding.LOCAL | Binding.FIELD;
    return ref;
  } else {
    return super.getUnspecifiedReferenceOptimized();
  }
}
protected void ignoreExpressionAssignment() {
  super.ignoreExpressionAssignment();
  /* recovery */
  recordLastStatementIfNeeded();
}
/**
* Returns whether we are parsing a top level type or not.
*/
private boolean isTopLevelType() {
  return this.nestedType == (this.diet ? 0 : 1);
}
protected MessageSend newMessageSend() {
  // '(' ArgumentListopt ')'
  // the arguments are on the expression stack

  CodeSnippetMessageSend m = new CodeSnippetMessageSend(this.evaluationContext);
  int length;
  if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
    this.expressionPtr -= length;
    System.arraycopy(
      this.expressionStack,
      this.expressionPtr + 1,
      m.arguments = new Expression[length],
      0,
      length);
  }
  return m;
}
/**
* Records the scanner position if we're parsing a top level type.
*/
private void recordLastStatementIfNeeded() {
  if ((isTopLevelType()) && (this.scanner.startPosition <= this.codeSnippetEnd+this.lineSeparatorLength /*14838*/)) {
    this.lastStatement = this.scanner.startPosition;
  }
}

protected void reportSyntaxErrors(boolean isDietParse, int oldFirstToken) {
  if (!isDietParse) {
    this.scanner.initialPosition = this.lastStatement;
    this.scanner.eofPosition = this.codeSnippetEnd + 1; // stop after expression
    oldFirstToken = TokenNameTWIDDLE;//TokenNameREMAINDER; // first token of th expression parse
  }
  super.reportSyntaxErrors(isDietParse, oldFirstToken);
}
/*
* A syntax error was detected. If a method is being parsed, records the number of errors and
* attempts to restart from the last statement by going for an expression.
*/
protected boolean resumeOnSyntaxError() {
  if (this.diet || this.hasRecoveredOnExpression) { // no reentering inside expression recovery
    return false;
  }
 
  // record previous error, in case more accurate than potential one in expression recovery
  // e.g. "return foo(a a); 1+3"
  this.problemCountBeforeRecovery = this.compilationUnit.compilationResult.problemCount;

  // reposition for expression parsing
  if (this.lastStatement < 0) {
    this.lastStatement = this.codeSnippetStart; // no statement reduced prior to error point
  }
  this.scanner.initialPosition = this.lastStatement;
  this.scanner.startPosition = this.lastStatement;
  this.scanner.currentPosition = this.lastStatement;
  this.scanner.eofPosition = this.codeSnippetEnd < Integer.MAX_VALUE ? this.codeSnippetEnd + 1 : this.codeSnippetEnd; // stop after expression
  this.scanner.commentPtr = -1;

  // reset stacks in consistent state
  this.expressionPtr = -1;
  this.identifierPtr = -1;
  this.identifierLengthPtr = -1;

  // go for the expression
  goForExpression();
  this.hasRecoveredOnExpression = true;
  this.hasReportedError = false;
  this.hasError = false;
  return true;
}
}
TOP

Related Classes of org.aspectj.org.eclipse.jdt.internal.eval.CodeSnippetParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.