package org.exist.xquery.functions.map; import org.exist.xquery.*; import org.exist.xquery.util.ExpressionDumper; import org.exist.xquery.value.AtomicValue; import org.exist.xquery.value.Item; import org.exist.xquery.value.Sequence; import org.exist.xquery.value.Type; import java.util.ArrayList; import java.util.List; /** * Implements the literal syntax for creating maps. */ public class MapExpr extends AbstractExpression { protected List<Mapping> mappings = new ArrayList(13); public MapExpr(XQueryContext context) { super(context); } public void map(PathExpr key, PathExpr value) { final Mapping mapping = new Mapping(key.simplify(), value.simplify()); this.mappings.add(mapping); } public void analyze(AnalyzeContextInfo contextInfo) throws XPathException { if(getContext().getXQueryVersion() < 30){ throw new XPathException(this, ErrorCodes.EXXQDY0003, "Map is not available before XQuery 3.0"); } contextInfo.setParent(this); for (final Mapping mapping : this.mappings) { mapping.key.analyze(contextInfo); mapping.value.analyze(contextInfo); } } public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException { if (contextItem != null) {contextSequence = contextItem.toSequence();} final MapType map = new MapType(this.context); for (final Mapping mapping : this.mappings) { final Sequence key = mapping.key.eval(contextSequence); if (key.getItemCount() != 1) {throw new XPathException(MapErrorCode.EXMPDY001, "Expected single value for key, got " + key.getItemCount());} final AtomicValue atomic = key.itemAt(0).atomize(); final Sequence value = mapping.value.eval(contextSequence); map.add(atomic, value); } return map; } public int returnsType() { return Type.MAP; } @Override public void accept(ExpressionVisitor visitor) { super.accept(visitor); for (final Mapping mapping: this.mappings) { mapping.key.accept(visitor); mapping.value.accept(visitor); } } public void dump(ExpressionDumper dumper) { dumper.display("map {"); for (final Mapping mapping : this.mappings) { mapping.key.dump(dumper); dumper.display(" := "); mapping.value.dump(dumper); } dumper.display("}"); } @Override public void resetState(boolean postOptimization) { super.resetState(postOptimization); mappings.forEach(m -> m.resetState(postOptimization)); } private static class Mapping { final Expression key; final Expression value; public Mapping(Expression key, Expression value) { this.key = key; this.value = value; } private void resetState(boolean postOptimization) { key.resetState(postOptimization); value.resetState(postOptimization); } } }