| /******************************************************************************* |
| * Copyright (c) 2011, 2012 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.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); |
| } |
| } |
| } |
| } |
| } |
| |
| public Variant selectFallback() { |
| // Search for an open variant, with a small right offset and a large left offset |
| for (BranchPoint p = fFirst; p != null; p= p.getNext()) { |
| Variant best= null; |
| for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) { |
| if (v.getTargetOperator() == null) { |
| if (best == null || v.fRightOffset < best.fRightOffset) { |
| best= v; |
| } |
| } |
| } |
| if (best != null) { |
| remove(best); |
| return best; |
| } |
| } |
| return null; |
| } |
| |
| 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; |
| } |
| |
| public boolean hasRightBound(int opOffset) { |
| // Search for an open variant, with a small right offset and a large left offset |
| for (BranchPoint p = fFirst; p != null; p= p.getNext()) { |
| for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) { |
| if (v.fRightOffset > opOffset) |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public void removeInvalid(BinaryOperator lastOperator) { |
| for (BranchPoint p = fFirst; p != null; p= p.getNext()) { |
| if (!isReachable(p, lastOperator)) { |
| remove(p); |
| } else { |
| for (Variant v= p.getFirstVariant(); v != null; v= v.getNext()) { |
| if (v.getTargetOperator() == null) { |
| remove(v); |
| } |
| } |
| } |
| } |
| } |
| |
| private boolean isReachable(BranchPoint bp, BinaryOperator endOperator) { |
| BinaryOperator op = bp.getLeftOperator(); |
| if (op == null) |
| return true; |
| |
| for (; endOperator != null; endOperator= endOperator.getNext()) { |
| if (endOperator == op) |
| return true; |
| } |
| return false; |
| } |
| } |