Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ private static FuncItem funcItem(final Value rows, final XQMap columnIndex,
final QueryContext qc, final InputInfo ii) {
final VarScope vs = new VarScope();
final SeqType rowType = POSITIVE_INTEGER_O;
final SeqType colType = ChoiceItemType.get(STRING_O, POSITIVE_INTEGER_O).seqType();
final SeqType colType = ChoiceItemType.get(BasicType.STRING,
BasicType.POSITIVE_INTEGER).seqType();
final Var row = vs.addNew(new QNm("row"), rowType, qc, ii);
final Var col = vs.addNew(new QNm("column"), colType, qc, ii);
final Get get = new Get(ii, rows, columnIndex, new VarRef(ii, row), new VarRef(ii, col));
Expand Down
2 changes: 1 addition & 1 deletion basex-core/src/main/java/org/basex/query/QueryParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -3805,7 +3805,7 @@ private EnumType enumerationType() throws QueryException {
private SeqType choiceItemType() throws QueryException {
final ChoiceItemType.Builder builder = new ChoiceItemType.Builder();
do {
builder.add(itemType());
builder.add(itemType().type);
} while(wsConsume("|"));
check(')');
return builder.build().seqType();
Expand Down
6 changes: 3 additions & 3 deletions basex-core/src/main/java/org/basex/query/func/Function.java
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ public enum Function implements AFunction {
params(ELEMENT_ZO, MAP_ZO), ITEM_ZO.mapType(BasicType.STRING).seqType(Occ.ZERO_OR_ONE)),
/** XQuery function. */
ELEMENT_TO_MAP_PLAN(FnElementToMapPlan::new, "element-to-map-plan(input)",
params(ChoiceItemType.get(DOCUMENT_O, ELEMENT_O).seqType(Occ.ZERO_OR_MORE)),
params(ChoiceItemType.get(NodeType.DOCUMENT, NodeType.ELEMENT).seqType(Occ.ZERO_OR_MORE)),
RECORD_O.mapType(BasicType.STRING).seqType()),
/** XQuery function. */
ELEMENT_WITH_ID(FnElementWithId::new, "element-with-id(values[,node])",
Expand Down Expand Up @@ -385,7 +385,7 @@ public enum Function implements AFunction {
/** XQuery function. */
IN_SCOPE_NAMESPACES(FnInScopeNamespaces::new, "in-scope-namespaces(element)",
params(ELEMENT_O),
ANY_URI_O.mapType(ChoiceItemType.get(NCNAME_O, EnumType.get("").seqType())).seqType()),
ANY_URI_O.mapType(ChoiceItemType.get(BasicType.NCNAME, EnumType.get(""))).seqType()),
/** XQuery function. */
IN_SCOPE_PREFIXES(FnInScopePrefixes::new, "in-scope-prefixes(element)",
params(ELEMENT_O), STRING_ZM),
Expand Down Expand Up @@ -511,7 +511,7 @@ public enum Function implements AFunction {
params(NODE_ZO), QNAME_ZO),
/** XQuery function. */
NODE_TYPE_ANNOTATION(FnNodeTypeAnnotation::new, "node-type-annotation(node)",
params(ChoiceItemType.get(ELEMENT_O, ATTRIBUTE_O).seqType()),
params(ChoiceItemType.get(NodeType.ELEMENT, NodeType.ATTRIBUTE).seqType()),
Records.SCHEMA_TYPE.get().seqType()),
/** XQuery function. */
NORMALIZE_SPACE(FnNormalizeSpace::new, "normalize-space([value])",
Expand Down
2 changes: 1 addition & 1 deletion basex-core/src/main/java/org/basex/query/func/Records.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public enum Records {
field("column-index", MapType.get(BasicType.STRING, Types.INTEGER_O).seqType(Occ.ZERO_OR_ONE)),
field("rows", ArrayType.get(Types.STRING_O).seqType(Occ.ZERO_OR_MORE)),
field("get", FuncType.get(Types.STRING_O, Types.POSITIVE_INTEGER_O,
ChoiceItemType.get(Types.POSITIVE_INTEGER_O, Types.STRING_O).seqType()).seqType())),
ChoiceItemType.get(BasicType.POSITIVE_INTEGER, BasicType.STRING).seqType()).seqType())),
/** Record definition. */
RANDOM_NUMBER_GENERATOR(FN_URI, "random-number-generator"),
/** Record definition. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
*/
public final class FnInvisibleXml extends StandardFunc {
/** The function's argument type. */
public static final SeqType ARG_TYPE = ChoiceItemType.get(Types.STRING_O,
NodeType.get(NameTest.get(new QNm("ixml"))).seqType()).seqType(Occ.ZERO_OR_ONE);
public static final SeqType ARG_TYPE = ChoiceItemType.get(BasicType.STRING,
NodeType.get(NameTest.get(new QNm("ixml")))).seqType(Occ.ZERO_OR_ONE);
/** The invisible XML parser generator. */
private Generator generator;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
public final class FnNodeTypeAnnotation extends FnSchemaType {
/** The function's argument type. */
private static final SeqType ARG_TYPE =
ChoiceItemType.get(Types.ELEMENT_O, Types.ATTRIBUTE_O).seqType();
ChoiceItemType.get(NodeType.ELEMENT, NodeType.ATTRIBUTE).seqType();

@Override
public Value value(final QueryContext qc) throws QueryException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

import java.util.*;

import org.basex.io.in.DataInput;
import org.basex.io.in.*;
import org.basex.query.*;
import org.basex.query.expr.path.*;
import org.basex.query.value.*;
import org.basex.query.value.item.*;
import org.basex.util.*;
Expand All @@ -19,7 +18,7 @@
*/
public final class ChoiceItemType implements Type {
/** Alternative item types. */
public final List<SeqType> types;
public final List<Type> types;
/** Common ancestor type. */
private final Type union;

Expand All @@ -30,31 +29,31 @@ public final class ChoiceItemType implements Type {
* Constructor.
* @param types alternative item types
*/
private ChoiceItemType(final List<SeqType> types) {
private ChoiceItemType(final List<Type> types) {
this.types = types;
Type tp = null;
for(final SeqType st : this.types) {
tp = tp == null ? st.type : tp.union(st.type);
Type ut = null;
for(final Type tp : this.types) {
ut = ut == null ? tp : ut.union(tp);
}
union = tp;
union = ut;
}

/**
* Creates a choice item type.
* @param types alternative item types
* @return choice item type
*/
public static Type get(final SeqType... types) {
public static Type get(final Type... types) {
final Builder builder = new Builder();
for(final SeqType st : types) builder.add(st);
for(final Type tp : types) builder.add(tp);
return builder.build();
}

@Override
public Value cast(final Item item, final QueryContext qc, final InputInfo info)
throws QueryException {
for(final SeqType st : types) {
final Value val = st.cast(item, false, qc, info);
for(final Type tp : types) {
final Value val = tp.seqType().cast(item, false, qc, info);
if(val != null) return val;
}
throw FUNCCAST_X_X_X.get(info, item.type, this, item);
Expand All @@ -63,9 +62,9 @@ public Value cast(final Item item, final QueryContext qc, final InputInfo info)
@Override
public Value cast(final Object value, final QueryContext qc, final InputInfo info)
throws QueryException {
for(final SeqType st : types) {
for(final Type tp : types) {
try {
return st.type.cast(value, qc, info);
return tp.cast(value, qc, info);
} catch(final QueryException ex) {
Util.debug(ex);
}
Expand All @@ -90,25 +89,48 @@ public boolean eq(final Type type) {
return this == type || type instanceof final ChoiceItemType cit && types.equals(cit.types);
}

@Override
public boolean instanceOf(final Type type) {
final Type norm = expand(type);
if(norm instanceof final ChoiceItemType ct) {
for(final Type tp : types) {
if(!ct.hasInstance(tp)) return false;
}
} else {
for(final Type tp : types) {
if(!tp.instanceOf(norm)) return false;
}
}
return true;
}

/**
* Checks if this choice item type is an instance of the specified sequence type.
* @param seqType sequence type to check
* Checks if this choice type is a supertype of the given type.
* @param type type to be checked
* @return result of check
*/
public boolean instanceOf(final SeqType seqType) {
if(!seqType.one()) throw Util.notExpected();
for(final SeqType st : types) {
if(!st.instanceOf(seqType)) return false;
boolean hasInstance(final Type type) {
final Type norm = expand(type);
if(norm instanceof final ChoiceItemType ct) return ct.instanceOf(this);
for(final Type tp : types) {
if(norm.instanceOf(tp)) return true;
}
return true;
return false;
}

@Override
public boolean instanceOf(final Type type) {
for(final SeqType st : types) {
if(!st.type.instanceOf(type)) return false;
}
return true;
/**
* Expand the given type for comparison with choice item types, if necessary, as specified in the
* subtyping rules for choice item types.
* @param type type to expand
* @return expanded type
*/
private static Type expand(final Type type) {
if(type == BasicType.NUMERIC) return Types.NUMERIC_EXPANSION;
if(type == BasicType.ANY_ATOMIC_TYPE) return Types.ANY_ATOMIC_TYPE_EXPANSION;
if(type == BasicType.ITEM) return Types.ITEM_EXPANSION;
if(type == NodeType.NODE) return Types.NODE_EXPANSION;
if(type == NodeType.GNODE) return Types.GNODE_EXPANSION;
return type;
}

@Override
Expand All @@ -119,9 +141,9 @@ public Type union(final Type type) {
@Override
public Type intersect(final Type type) {
final Builder builder = new Builder();
for(final SeqType st : types) {
final Type tp = type.intersect(st.type);
if(tp != null) builder.add(tp.seqType());
for(final Type tp : types) {
final Type is = type.intersect(tp);
if(is != null) builder.add(is);
}
return builder.types.isEmpty() ? null : builder.build();
}
Expand All @@ -133,7 +155,7 @@ public boolean isNumber() {

@Override
public boolean isUntyped() {
return union.isNumberOrUntyped();
return union.isUntyped();
}

@Override
Expand Down Expand Up @@ -163,41 +185,8 @@ public ID id() {

@Override
public boolean nsSensitive() {
for(final SeqType st : types) {
if(st.type.nsSensitive()) return true;
}
return false;
}

/**
* Checks if the given type is an instance of this type.
* @param type type to be checked
* @return result of check
*/
boolean hasInstance(final Type type) {
for(final SeqType st : types) {
if(type.instanceOf(st.type)) return true;
}
return false;
}

/**
* Checks if the given sequence type is an instance of this type.
* @param seqType sequence type to be checked
* @return result of check
*/
boolean hasInstance(final SeqType seqType) {
if(!seqType.one()) throw Util.notExpected();
if(seqType.type instanceof final NodeType nt) {
if(nt.test instanceof final UnionTest ut) {
for(final Test t : ut.tests) {
if(!hasInstance(NodeType.get(t))) return false;
}
return true;
}
}
for(final SeqType st : types) {
if(seqType.instanceOf(st)) return true;
for(final Type tp : types) {
if(tp.nsSensitive()) return true;
}
return false;
}
Expand All @@ -219,7 +208,7 @@ public String name() {

@Override
public String toString() {
return toString("|", (Object[]) types.toArray(SeqType[]::new));
return toString("|", (Object[]) types.toArray(Type[]::new));
}

/**
Expand All @@ -229,66 +218,66 @@ public String toString() {
*/
public static final class Builder {
/** Alternative item types. */
private final ArrayList<SeqType> types = new ArrayList<>();
private final ArrayList<Type> types = new ArrayList<>();

/**
* Builds and returns the resulting choice item type.
* @return choice item type, or the single item type if the list contains only one type
*/
public Type build() {
if(types.size() != 1) types.remove(Types.ERROR_O);
if(types.size() != 1) types.remove(BasicType.ERROR);
return switch(types.size()) {
case 0 -> throw Util.notExpected();
case 1 -> types.get(0).type;
case 1 -> types.get(0);
default -> new ChoiceItemType(types);
};
}

/**
* Adds the specified sequence type to this builder, merging enum types only if consecutive, and
* merging document, element, attribute, and pi types anywhere in the list, ignoring duplicates,
* and flattening nested ChoiceItemTypes.
* @param st sequence type to be added
* Adds the specified type to this builder, merging enum types only if consecutive, and merging
* document, element, attribute, and pi types anywhere in the list, ignoring duplicates, and
* flattening nested ChoiceItemTypes.
* @param type type to be added
* @return this builder
*/
public Builder add(final SeqType st) {
public Builder add(final Type type) {
// flatten nested ChoiceItemTypes
if(st.type instanceof ChoiceItemType ct) {
for(final SeqType s : ct.types) add(s);
if(type instanceof final ChoiceItemType ct) {
for(final Type tp : ct.types) add(tp);
return this;
}
// ignore duplicates
if(types.contains(st)) return this;
if(types.contains(type)) return this;
// non-mergeable types or first entry
final Type.ID id = st.type.id();
final Type.ID id = type.id();
if(types.isEmpty()
|| !id.oneOf(Type.ID.ENM, Type.ID.DOC, Type.ID.ELM, Type.ID.ATT, Type.ID.PI)) {
types.add(st);
types.add(type);
return this;
}
// enums: merge consecutive entries only, to preserve position of alternatives
if(id == Type.ID.ENM) {
final int last = types.size() - 1;
final Type tp = types.get(last).type;
final Type tp = types.get(last);
if(tp.id() == Type.ID.ENM) {
// remove and re-add, for duplicate removal
types.remove(last);
return add(tp.union(st.type).seqType());
return add(tp.union(type));
}
// not consecutive: add as-is
types.add(st);
// not consecutive: add as-is
types.add(type);
return this;
}
// nodes (DOC/ELM/ATT/PI): merge with existing alternative of same kind anywhere, in-place
for(int i = 0; i < types.size(); i++) {
final SeqType existing = types.get(i);
if(existing.type.id() == id) {
types.set(i, existing.type.union(st.type).seqType());
final Type existing = types.get(i);
if(existing.id() == id) {
types.set(i, existing.union(type));
return this;
}
}
// no existing node kind found
types.add(st);
types.add(type);
return this;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ private boolean instanceOf(final Type type, final Set<Pair> pairs) {
return true;
}
if(type instanceof final ChoiceItemType cit) {
for(final SeqType st : cit.types) {
if(instanceOf(st.type, pairs)) return true;
for(final Type tp : cit.types) {
if(instanceOf(tp, pairs)) return true;
}
return false;
}
Expand Down
Loading
Loading