| 37 | } |
| 38 | |
| 39 | @Override |
| 40 | public Expr optimize(final CompileContext cc) throws QueryException { |
| 41 | // flatten nested maps: { 1: 2, { 3: 4, 5: 6 }, () } → { 1: 2, 3: 4, 5: 6 } |
| 42 | int el = exprs.length; |
| 43 | if(((Checks<Expr>) expr -> expr == Empty.UNDEFINED).any(exprs)) { |
| 44 | final ExprList list = new ExprList(); |
| 45 | for(int e = 0; e < el; e += 2) { |
| 46 | final Expr expr = exprs[e]; |
| 47 | if(!(nested(e) && flatten(expr, list))) list.add(expr).add(exprs[e + 1]); |
| 48 | } |
| 49 | exprs = list.finish(); |
| 50 | el = exprs.length; |
| 51 | } |
| 52 | |
| 53 | // atomize keys: { <_>A</_>: 1 } → { 'A': 1 } |
| 54 | for(int e = 0; e < el; e += 2) { |
| 55 | if(!nested(e)) { |
| 56 | exprs[e] = exprs[e].simplifyFor(Simplify.DATA, cc); |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | // empty map? |
| 61 | if(el == 0) return XQMap.empty(); |
| 62 | if(el == 2) { |
| 63 | // { $a: $b } → map:entry($a, $b) |
| 64 | if(!nested(0)) return cc.function(_MAP_ENTRY, info, exprs); |
| 65 | // { { 'a': <a/> } } → { 'a': <a/> } |
| 66 | if(exprs[0].seqType().instanceOf(Types.MAP_O)) return exprs[0]; |
| 67 | } |
| 68 | |
| 69 | // not too large, only strings as keys? replace with record constructor |
| 70 | boolean record = el / 2 <= RecordType.MAX_GENERATED_SIZE; |
| 71 | for(int e = 0; e < el && record; e += 2) { |
| 72 | if(nested(e) || !(exprs[e] instanceof AStr && exprs[e].seqType().eq(Types.STRING_O))) { |
| 73 | record = false; |
| 74 | } |
| 75 | } |
| 76 | if(record) { |
| 77 | final TokenObjectMap<RecordField> fields = new TokenObjectMap<>(el / 2); |
| 78 | final ExprList args = new ExprList(el / 2); |
| 79 | for(int e = 0; e < el; e += 2) { |
| 80 | final Expr key = exprs[e], value = exprs[e + 1]; |
| 81 | if(fields.put(((AStr) key).string(info), new RecordField(value.seqType())) != null) { |
| 82 | throw MAPDUPLKEY_X.get(info, key); |
| 83 | } |
| 84 | args.add(value); |
| 85 | } |
| 86 | final RecordType rt = cc.qc.shared.record(new RecordType(fields)); |
| 87 | return RecordConstructor.get(info, rt, args.finish()).optimize(cc); |
| 88 | } |
| 89 | |
| 90 | // determine static types |
| 91 | Type kt = null; |
| 92 | SeqType vt = null; |
| 93 | for(int e = 0; e < el; e += 2) { |
| 94 | Type ekt = BasicType.ANY_ATOMIC_TYPE; |
| 95 | SeqType evt = Types.ITEM_ZM; |
| 96 | if(nested(e)) { |