protected ExpQuery( Type resultType, VarDeclList elemVarDecls, Expression rangeExp, Expression queryExp) throws ExpInvalidException { super(resultType, rangeExp, queryExp); fElemVarDecls = elemVarDecls; fRangeExp = rangeExp; fQueryExp = queryExp; // type of rangeExp must be a subtype of Collection, i.e. Set, // Sequence or Bag if (!fRangeExp.type().isCollection(false)) throw new ExpInvalidException( "Range expression must be of type " + "`Collection', found `" + fRangeExp.type() + "'."); // assert that declard element variables are equal or // supertypes of range element type Type rangeElemType = ((CollectionType) fRangeExp.type()).elemType(); for (int i = 0; i < fElemVarDecls.size(); i++) { VarDecl vd = fElemVarDecls.varDecl(i); if (!rangeElemType.isSubtypeOf(vd.type())) throw new ExpInvalidException( "Type `" + vd.type() + "' of range variable `" + vd.name() + "' does not match type `" + rangeElemType + "' of collection elements."); } }
/** Evaluate collect expressions. */ protected final Value evalCollectNested(EvalContext ctx) { // evaluate range Value v = fRangeExp.eval(ctx); if (v.isUndefined()) return UndefinedValue.instance; CollectionValue rangeVal = (CollectionValue) v; // prepare result value ArrayList<Value> resValues = new ArrayList<Value>(); // loop over range elements for (Value elemVal : rangeVal) { // bind element variable to range element, if variable was // declared if (!fElemVarDecls.isEmpty()) ctx.pushVarBinding(fElemVarDecls.varDecl(0).name(), elemVal); // evaluate collect expression Value val = fQueryExp.eval(ctx); // add element to result resValues.add(val); if (!fElemVarDecls.isEmpty()) ctx.popVarBinding(); } // result is collection with mapped values if (fRangeExp.type().isSequence() || fRangeExp.type().isOrderedSet()) return new SequenceValue(fQueryExp.type(), resValues); else return new BagValue(fQueryExp.type(), resValues); }
protected void assertBooleanQuery() throws ExpInvalidException { // queryExp must be a boolean expression if (!fQueryExp.type().isBoolean()) throw new ExpInvalidException( "Argument expression of `" + name() + "' must have boolean type, found `" + fQueryExp.type() + "'."); }
/** Evaluate sortedBy expressions. */ protected final Value evalSortedBy(EvalContext ctx) { // evaluate range Value v = fRangeExp.eval(ctx); if (v.isUndefined()) return UndefinedValue.instance; CollectionValue rangeVal = (CollectionValue) v; ArrayList<KeyValPair> keyValList = new ArrayList<KeyValPair>(); // loop over range elements for (Value elemVal : rangeVal) { // bind element variable to range element, if variable was // declared if (!fElemVarDecls.isEmpty()) ctx.pushVarBinding(fElemVarDecls.varDecl(0).name(), elemVal); // evaluate sortedBy expression and store the result as a // key together with elemVal Value key = fQueryExp.eval(ctx); keyValList.add(new KeyValPair(key, elemVal)); if (!fElemVarDecls.isEmpty()) ctx.popVarBinding(); } // sort elements by key Collections.sort( keyValList, new Comparator<KeyValPair>() { public int compare(KeyValPair o1, KeyValPair o2) { return o1.fKey.compareTo(o2.fKey); } }); // drop the keys from the list ListIterator<KeyValPair> listIter = keyValList.listIterator(); Collection<Value> result = new ArrayList<Value>(keyValList.size()); while (listIter.hasNext()) { KeyValPair kvp = listIter.next(); result.add(kvp.fElem); } Type rangeElemType = ((CollectionType) fRangeExp.type()).elemType(); return new SequenceValue(rangeElemType, result); }