blob: 50b5c90d3cf64f36def7d242bad80a724dc551f0 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}