blob: 43f392b53c866a323f26a61450c600337bc6a820 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002, 2013 Object Factory Inc.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Object Factory Inc. - Initial implementation
* IBM Corporation - bug fixes
*******************************************************************************/
package org.eclipse.ant.internal.ui.dtd.schema;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.ant.internal.core.IAntCoreConstants;
import org.eclipse.ant.internal.ui.dtd.IAtom;
import org.eclipse.ant.internal.ui.dtd.IModel;
/**
* IModel implementation.
*
* @author Bob Foster
*/
public class Model implements IModel {
protected int fKind;
protected int fMin = 1;
protected int fMax = 1;
protected int fNum = 0;
protected IModel[] fContents;
protected List<IModel> fContentsList;
protected IAtom fLeaf;
protected boolean fMixed;
private static final IModel[] fEmptyContents = new IModel[0];
public Model(int kind) {
fKind = kind;
}
public Model() {
fKind = UNKNOWN;
}
public void setKind(int kind) {
fKind = kind;
}
public void setMinOccurs(int min) {
fMin = min;
}
public void setMaxOccurs(int max) {
fMax = max;
}
public void setContents(IModel[] contents) {
fContents = contents;
}
public void addModel(IModel model) {
if (fContents != null)
throw new IllegalStateException(AntDTDSchemaMessages.Model_model_may_not_be_changed);
if (fContentsList == null)
fContentsList = new LinkedList<>();
fContentsList.add(model);
}
public void setLeaf(IAtom leaf) {
fLeaf = leaf;
}
private static final String[] fOps = { "?", ",", "|", "&", "!!!" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
private Nfm qualifyNfm(Nfm nfm) {
if (nfm == null)
return null;
if (fMin == 1 && fMax == 1)
return nfm;
if (fMin == 0 && fMax == 1) {
return Nfm.getQuestion(nfm);
}
if (fMin == 0 && fMax == UNBOUNDED) {
return Nfm.getStar(nfm);
}
if (fMin == 1 && fMax == UNBOUNDED) {
return Nfm.getPlus(nfm);
}
// the following cases cannot be reached by DTD models
if (fMax == 0)
return Nfm.getNfm(null);
if (fMax == UNBOUNDED) {
return Nfm.getUnbounded(nfm, fMin);
}
return Nfm.getMinMax(nfm, fMin, fMax);
}
public Model shallowCopy() {
Model copy = new Model(getKind());
copy.fMixed = fMixed;
copy.fLeaf = fLeaf;
if (fContents != null) {
copy.fContentsList = new LinkedList<>();
for (IModel content : fContents) {
copy.fContentsList.add(content);
}
} else if (fContentsList != null) {
copy.fContentsList = new LinkedList<>();
Iterator<IModel> it = fContentsList.iterator();
while (it.hasNext()) {
copy.fContentsList.add(it.next());
}
}
return copy;
}
@Override
public int getKind() {
return 0;
}
@Override
public int getMinOccurs() {
return fMin;
}
@Override
public int getMaxOccurs() {
return fMax;
}
@Override
public IModel[] getContents() {
// A model contents may be referred to many times
// it would be inefficient to convert to array each time
if (fContents == null) {
if (fContentsList != null) {
fContents = fContentsList.toArray(new IModel[fContentsList.size()]);
fContentsList = null;
} else
fContents = fEmptyContents;
}
return fContents;
}
@Override
public IAtom getLeaf() {
return fLeaf;
}
@Override
public String getOperator() {
return fOps[fKind];
}
@Override
public String stringRep() {
StringBuffer buf = new StringBuffer();
stringRep(buf);
return buf.toString();
}
private void stringRep(StringBuffer buf) {
switch (getKind()) {
case IModel.CHOICE:
case IModel.SEQUENCE:
buf.append('(');
Iterator<IModel> it = fContentsList.iterator();
while (it.hasNext()) {
Model model = (Model) it.next();
model.stringRep(buf);
if (it.hasNext())
buf.append(getOperator());
}
buf.append(')');
buf.append(getQualifier());
break;
case IModel.LEAF:
IAtom atom = getLeaf();
buf.append(atom.getName());
break;
default:
buf.append(AntDTDSchemaMessages.Model____UNKNOWN____2);
break;
}
}
@Override
public String getQualifier() {
return fMin == 1 ? (fMax == UNBOUNDED ? "+" : IAntCoreConstants.EMPTY_STRING) : (fMax == UNBOUNDED ? "*" : "?"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@Override
public Nfm toNfm() {
Nfm nfm = null;
switch (fKind) {
case CHOICE:
case SEQUENCE: {
IModel[] contents = getContents();
if (contents == null || contents.length == 0) {
return null;
}
nfm = contents[0].toNfm();
for (int i = 1; i < contents.length; i++) {
Nfm tmp = contents[i].toNfm();
if (fKind == SEQUENCE) {
nfm = Nfm.getComma(nfm, tmp);
} else {
nfm = Nfm.getOr(nfm, tmp);
}
}
break;
}
case LEAF: {
nfm = Nfm.getNfm(fLeaf);
break;
}
default:
break;
}
return qualifyNfm(nfm);
}
}