/******************************************************************************* * Copyright (c) 2000, 2010 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.eclipse.jdt.internal.eval; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Assignment; import org.eclipse.jdt.internal.compiler.ast.Block; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldReference; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.NameReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.parser.Parser; import 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--; } } protected void consumeClassInstanceCreationExpressionWithTypeArguments() { // ClassInstanceCreationExpression ::= 'new' TypeArguments ClassType '(' ArgumentListopt ')' ClassBodyopt AllocationExpression alloc; int length; if (((length= this.astLengthStack[this.astLengthPtr--]) == 1) && (this.astStack[this.astPtr] == null)) { //NO ClassBody this.astPtr--; 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); length= this.genericsLengthStack[this.genericsLengthPtr--]; this.genericsPtr-= length; System.arraycopy(this.genericsStack, this.genericsPtr + 1, alloc.typeArguments= new TypeReference[length], 0, length); this.intPtr--; //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; anonymousTypeDeclaration.bodyEnd= this.endStatementPosition; if (length == 0 && !containsComment(anonymousTypeDeclaration.bodyStart, anonymousTypeDeclaration.bodyEnd)) { anonymousTypeDeclaration.bits|= ASTNode.UndocumentedEmptyBlock; } this.astPtr--; this.astLengthPtr--; QualifiedAllocationExpression allocationExpression= anonymousTypeDeclaration.allocation; if (allocationExpression != null) { allocationExpression.sourceEnd= this.endStatementPosition; // handle type arguments length= this.genericsLengthStack[this.genericsLengthPtr--]; this.genericsPtr-= length; System.arraycopy(this.genericsStack, this.genericsPtr + 1, allocationExpression.typeArguments= new TypeReference[length], 0, length); allocationExpression.sourceStart= this.intStack[this.intPtr--]; } } } 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 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 (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; if (CharOperation.indexOf('.', trimmedTypeName) == -1) { typeReference= new SingleTypeReference(trimmedTypeName, position); } else { typeReference= new QualifiedTypeReference( CharOperation.splitOn('.', trimmedTypeName), positions); } int dimCount= CharOperation.occurencesOf('[', this.evaluationContext.localVariableTypeNames[i]); if (dimCount > 0) { typeReference= 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++) { SingleNameReference nameRef= new SingleNameReference(this.evaluationContext.localVariableNames[i], position); finallyBlock.statements[i]= new Assignment( new SingleNameReference(CharOperation.concat(LOCAL_VAR_PREFIX, this.evaluationContext.localVariableNames[i]), position), nameRef, nameRef.sourceEnd); } 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 consumeMethodInvocationNameWithTypeArguments() { // MethodInvocation ::= Name '.' TypeArguments 'Identifier' '(' ArgumentListopt ')' // when the name is only an identifier...we have a message send to "this" (implicit) if (this.scanner.startPosition >= this.codeSnippetStart && this.scanner.startPosition <= this.codeSnippetEnd + 1 + this.lineSeparatorLength // 14838 && isTopLevelType()) { MessageSend m= newMessageSendWithTypeArguments(); m.sourceEnd= this.rParenPos; m.sourceStart= (int)((m.nameSourcePosition= this.identifierPositionStack[this.identifierPtr]) >>> 32); m.selector= this.identifierStack[this.identifierPtr--]; this.identifierLengthPtr--; // handle type arguments int length= this.genericsLengthStack[this.genericsLengthPtr--]; this.genericsPtr-= length; System.arraycopy(this.genericsStack, this.genericsPtr + 1, m.typeArguments= new TypeReference[length], 0, length); this.intPtr--; m.receiver= getUnspecifiedReference(); m.sourceStart= m.receiver.sourceStart; pushOnExpressionStack(m); } else { super.consumeMethodInvocationNameWithTypeArguments(); } } 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 consumeMethodInvocationSuperWithTypeArguments() { // MethodInvocation ::= 'super' '.' TypeArguments 'Identifier' '(' ArgumentListopt ')' MessageSend m= newMessageSendWithTypeArguments(); this.intPtr--; // start position of the typeArguments m.sourceEnd= this.rParenPos; m.nameSourcePosition= this.identifierPositionStack[this.identifierPtr]; m.selector= this.identifierStack[this.identifierPtr--]; this.identifierLengthPtr--; // handle type arguments int length= this.genericsLengthStack[this.genericsLengthPtr--]; this.genericsPtr-= length; System.arraycopy(this.genericsStack, this.genericsPtr + 1, m.typeArguments= new TypeReference[length], 0, length); m.sourceStart= this.intStack[this.intPtr--]; // start position of the super keyword 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; } protected MessageSend newMessageSendWithTypeArguments() { // '(' 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; } }