/******************************************************************************* * Copyright (c) 2011 Wind River Systems, Inc. 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: * Markus Schorn - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.BinaryOperator; /** * Tracks variants of expressions due to the ambiguity between template-id and '<' operator. */ public class NameOrTemplateIDVariants { /** * A point where a '<' can be interpreted as less-than or as the angle-bracket of a template-id. */ static class BranchPoint { private BranchPoint fNext; private Variant fFirstVariant; private final boolean fAllowAssignment; private final int fConditionCount; private final BinaryOperator fLeftOperator; BranchPoint(BranchPoint next, Variant variant, BinaryOperator left, boolean allowAssignment, int conditionCount) { fNext= next; fFirstVariant= variant; fAllowAssignment= allowAssignment; fConditionCount= conditionCount; fLeftOperator= left; // Set owner while (variant != null) { variant.fOwner= this; variant= variant.getNext(); } } public boolean isAllowAssignment() { return fAllowAssignment; } public int getConditionCount() { return fConditionCount; } public BinaryOperator getLeftOperator() { return fLeftOperator; } public Variant getFirstVariant() { return fFirstVariant; } public BranchPoint getNext() { return fNext; } public void reverseVariants() { Variant prev= null; Variant curr= fFirstVariant; while (curr != null) { Variant next= curr.getNext(); curr.fNext= prev; prev= curr; curr= next; } fFirstVariant= prev; } } /** * A variant for a branch-point is a cast-expression that can be used within a binary expression. */ static class Variant { private BranchPoint fOwner; private Variant fNext; private final IASTExpression fExpression; private BinaryOperator fTargetOperator; private final int fRightOffset; private final IASTName[] fTemplateNames; public Variant(Variant next, IASTExpression expr, IASTName[] templateNames, int rightOffset) { fNext= next; fExpression= expr; fRightOffset= rightOffset; fTemplateNames= templateNames; } public BranchPoint getOwner() { return fOwner; } public int getRightOffset() { return fRightOffset; } public IASTName[] getTemplateNames() { return fTemplateNames; } public Variant getNext() { return fNext; } public IASTExpression getExpression() { return fExpression; } public BinaryOperator getTargetOperator() { return fTargetOperator; } public void setTargetOperator(BinaryOperator lastOperator) { fTargetOperator= lastOperator; } } private BranchPoint fFirst; public boolean isEmpty() { return fFirst == null; } public void addBranchPoint(Variant variants, BinaryOperator left, boolean allowAssignment, int conditionCount) { fFirst= new BranchPoint(fFirst, variants, left, allowAssignment, conditionCount); } public void closeVariants(int offset, BinaryOperator lastOperator) { for (BranchPoint p = fFirst; p != null; p= p.getNext()) { for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) { if (v.getTargetOperator() == null) { if (offset == v.getRightOffset()) { v.setTargetOperator(lastOperator); } else if (offset > v.getRightOffset()) { // Should not happen assert false; remove(v); } } } } } public void discardOpenVariants(int operatorOffset) { for (BranchPoint p = fFirst; p != null; p= p.getNext()) { for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) { if (v.getTargetOperator() == null && v.getRightOffset() != operatorOffset) { remove(v); } } } } public Variant findFallback(int operatorOffset) { // Search for an open variant, with a small right offset and a large left offset Variant best= null; for (BranchPoint p = fFirst; p != null; p= p.getNext()) { for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) { if (v.fRightOffset > operatorOffset) { if (best == null || v.fRightOffset < best.fRightOffset) { best= v; } } } } return best; } public void useFallback(Variant fallback) { // Discard variants that end within the fallback int begin= ((ASTNode) fallback.getExpression()).getOffset(); int end= fallback.getRightOffset(); for (BranchPoint p = fFirst; p != null; p= p.getNext()) { for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) { if (v == fallback) { remove(v); } else { int vend= v.getRightOffset(); if (vend > begin && vend < end) remove(v); } } } } private void remove(Variant remove) { final BranchPoint owner = remove.fOwner; final Variant next = remove.getNext(); Variant prev= owner.getFirstVariant(); if (remove == prev) { owner.fFirstVariant= next; if (next == null) { remove(owner); } } else { while (prev != null) { Variant n = prev.getNext(); if (n == remove) { prev.fNext= next; break; } prev= n; } } } private void remove(BranchPoint remove) { final BranchPoint next = remove.getNext(); if (remove == fFirst) { fFirst= next; } else { BranchPoint prev= fFirst; while (prev != null) { BranchPoint n = prev.getNext(); if (n == remove) { prev.fNext= next; break; } prev= n; } } } public BranchPoint getOrderedBranchPoints() { BranchPoint prev= null; BranchPoint curr= fFirst; while (curr != null) { curr.reverseVariants(); BranchPoint next= curr.getNext(); curr.fNext= prev; prev= curr; curr= next; } fFirst= null; return prev; } }