| 39 | } |
| 40 | |
| 41 | @Override |
| 42 | protected final Expr opt(final CompileContext cc) throws QueryException { |
| 43 | final boolean exists = this instanceof FnExists; |
| 44 | Expr input = arg(0); |
| 45 | final SeqType st = input.seqType(); |
| 46 | |
| 47 | // ignore nondeterministic expressions (e.g.: empty(error())) |
| 48 | if(!input.has(Flag.NDT)) { |
| 49 | if(st.zero()) return Bln.get(!exists); |
| 50 | if(st.oneOrMore()) return Bln.get(exists); |
| 51 | } |
| 52 | |
| 53 | // static integer will always be greater than 1 |
| 54 | if(REPLICATE.is(input) && input.arg(1) instanceof Itr) { |
| 55 | input = input.arg(0); |
| 56 | } |
| 57 | // rewrite list to union expression: exists((nodes1, nodes2)) → exists(nodes1 | nodes2) |
| 58 | if(input instanceof List && input.seqType().type instanceof NodeType) { |
| 59 | input = new Union(info, input.args()).optimize(cc); |
| 60 | } |
| 61 | if(input != arg(0)) return cc.function(exists ? EXISTS : EMPTY, info, input); |
| 62 | |
| 63 | // replace optimized expression by boolean function |
| 64 | if(input instanceof final Filter filter) { |
| 65 | // rewrite filter: exists($a[text() = string]) → $a/text() = string |
| 66 | input = filter.flattenEbv(filter.root, false, cc); |
| 67 | } else if(INDEX_OF.is(input)) { |
| 68 | // rewrite index-of: exists(index-of($texts, string)) → $texts = string |
| 69 | final Expr[] args = input.args(); |
| 70 | if(args.length == 2 && args[1].seqType().one()) { |
| 71 | input = new CmpG(info, args[0], args[1], CmpOp.EQ).optimize(cc); |
| 72 | } |
| 73 | } else if(STRING_TO_CODEPOINTS.is(input) || CHARACTERS.is(input)) { |
| 74 | // exists(string-to-codepoints(E)) → boolean(string(E)) |
| 75 | input = cc.function(STRING, info, input.args()); |
| 76 | } |
| 77 | if(input != arg(0)) return cc.function(exists ? BOOLEAN : NOT, info, input); |
| 78 | |
| 79 | // exists(map:keys(E)) → map:size(E) > 0 |
| 80 | // empty(util:array-members(E)) → array:size(E) = 0 |
| 81 | final boolean map = _MAP_KEYS.is(input), array = _ARRAY_MEMBERS.is(input); |
| 82 | if(map || array) { |
| 83 | input = cc.function(map ? _MAP_SIZE : _ARRAY_SIZE, info, input.args()); |
| 84 | return new CmpG(info, input, Itr.ZERO, exists ? CmpOp.NE : CmpOp.EQ).optimize(cc); |
| 85 | } |
| 86 | |
| 87 | return embed(cc, true); |
| 88 | } |
| 89 | |
| 90 | @Override |
| 91 | public final Expr mergeEbv(final Expr expr, final boolean or, final CompileContext cc) |