From d4d2b85e69ad0158cd09a54f69e4b376b077cc46 Mon Sep 17 00:00:00 2001 From: David Waltermire Date: Fri, 10 May 2024 11:58:33 -0400 Subject: [PATCH] Completed code to support Metapath array construction. --- .../metapath/antlr/AbstractAstVisitor.java | 197 ++++++++++---- .../metapath/cst/AbstractCSTVisitorBase.java | 23 ++ .../cst/AbstractExpressionVisitor.java | 10 + .../core/metapath/cst/ArrayMembers.java | 80 ++++++ .../core/metapath/cst/ArraySequence.java | 82 ++++++ .../core/metapath/cst/BuildCSTVisitor.java | 247 ++++++++---------- .../core/metapath/cst/CSTPrinter.java | 9 + .../core/metapath/cst/IExpressionVisitor.java | 22 ++ .../core/metapath/impl/AbstractArrayItem.java | 11 + .../metapath/item/function/IArrayItem.java | 56 ++++ .../item/function/IArrayItemTest.java | 8 +- 11 files changed, 543 insertions(+), 202 deletions(-) create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArrayMembers.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequence.java diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/AbstractAstVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/AbstractAstVisitor.java index b1e15f4e1..c336e26ff 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/AbstractAstVisitor.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/AbstractAstVisitor.java @@ -32,11 +32,14 @@ import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.AndexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ArgumentContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ArgumentlistContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ArrayconstructorContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ArrowexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ArrowfunctionspecifierContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.AxisstepContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ComparisonexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ContextitemexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.CurlyarrayconstructorContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.EnclosedexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.EqnameContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ExprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ExprsingleContext; @@ -71,6 +74,7 @@ import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimpleletbindingContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimpleletclauseContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimplemapexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SquarearrayconstructorContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.StepexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.StringconcatexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.UnaryexprContext; @@ -138,8 +142,9 @@ protected R delegateToChild(@NonNull T ctx) { throw new IllegalStateException("a single child expression was expected"); } - /* ============================================================ - * Expressions - https://www.w3.org/TR/xpath-31/#id-expressions + /* + * ============================================================ Expressions - + * https://www.w3.org/TR/xpath-31/#id-expressions * ============================================================ */ @@ -169,7 +174,8 @@ public R visitExprsingle(ExprsingleContext ctx) { assert ctx != null; return delegateToChild(ctx); } - /* ============================================================================ + /* + * ============================================================================ * Primary Expressions - https://www.w3.org/TR/xpath-31/#id-primary-expressions * ============================================================================ */ @@ -180,8 +186,9 @@ public R visitPrimaryexpr(PrimaryexprContext ctx) { return delegateToChild(ctx); } - /* ================================================================= - * Literal Expressions - https://www.w3.org/TR/xpath-31/#id-literals + /* + * ================================================================= Literal + * Expressions - https://www.w3.org/TR/xpath-31/#id-literals * ================================================================= */ @@ -215,8 +222,9 @@ public R visitNumericliteral(NumericliteralContext ctx) { return handle(ctx, (context) -> handleNumericLiteral(ctx)); } - /* ================================================================== - * Variable References - https://www.w3.org/TR/xpath-31/#id-variables + /* + * ================================================================== Variable + * References - https://www.w3.org/TR/xpath-31/#id-variables * ================================================================== */ @@ -241,9 +249,12 @@ public R visitVarname(VarnameContext ctx) { return delegateToChild(ctx); } - /* ================================================================================= - * Parenthesized Expressions - https://www.w3.org/TR/xpath-31/#id-paren-expressions - * ================================================================================= + /* + * ============================================================================= + * ==== Parenthesized Expressions - + * https://www.w3.org/TR/xpath-31/#id-paren-expressions + * ============================================================================= + * ==== */ /** @@ -262,9 +273,12 @@ public R visitParenthesizedexpr(ParenthesizedexprContext ctx) { return expr == null ? handleEmptyParenthesizedexpr(ctx) : visit(expr); } - /* ===================================================================================== - * Context Item Expression - https://www.w3.org/TR/xpath-31/#id-context-item-expression - * ===================================================================================== + /* + * ============================================================================= + * ======== Context Item Expression - + * https://www.w3.org/TR/xpath-31/#id-context-item-expression + * ============================================================================= + * ======== */ /** @@ -282,10 +296,9 @@ public R visitContextitemexpr(ContextitemexprContext ctx) { return handle(ctx, (context) -> handleContextitemexpr(ctx)); } - /* ========================================================================= - * Static Function Calls - https://www.w3.org/TR/xpath-31/#id-function-calls - * ========================================================================= - */ + // ========================================================================= + // Static Function Calls - https://www.w3.org/TR/xpath-31/#id-function-calls + // ========================================================================= /** * Handle the provided expression. @@ -314,7 +327,18 @@ public R visitArgument(ArgumentContext ctx) { throw new IllegalStateException(); } - /* ========================================================================= + // ======================================================================= + // Enclosed Expressions - https://www.w3.org/TR/xpath-31/#id-enclosed-expr + // ======================================================================= + + @Override + public R visitEnclosedexpr(EnclosedexprContext ctx) { + ExprContext expr = ctx.expr(); + return expr == null ? null : expr.accept(this); + } + + /* + * ========================================================================= * Filter Expressions - https://www.w3.org/TR/xpath-31/#id-filter-expression * ========================================================================= */ @@ -340,8 +364,9 @@ public R visitPredicate(PredicateContext ctx) { throw new IllegalStateException(); } - /* ====================================================================== - * Path Expressions - https://www.w3.org/TR/xpath-31/#id-path-expressions + /* + * ====================================================================== Path + * Expressions - https://www.w3.org/TR/xpath-31/#id-path-expressions * ====================================================================== */ @@ -360,9 +385,12 @@ public R visitPathexpr(PathexprContext ctx) { return handle(ctx, (context) -> handlePathexpr(ctx)); } - /* ======================================================================================= - * RelativePath Expressions - https://www.w3.org/TR/xpath-31/#id-relative-path-expressions - * ======================================================================================= + /* + * ============================================================================= + * ========== RelativePath Expressions - + * https://www.w3.org/TR/xpath-31/#id-relative-path-expressions + * ============================================================================= + * ========== */ /** @@ -380,8 +408,9 @@ public R visitRelativepathexpr(RelativepathexprContext ctx) { return handle(ctx, (context) -> handleRelativepathexpr(ctx)); } - /* ================================================ - * Steps - https://www.w3.org/TR/xpath-31/#id-steps + /* + * ================================================ Steps - + * https://www.w3.org/TR/xpath-31/#id-steps * ================================================ */ @@ -423,7 +452,8 @@ public R visitReversestep(ReversestepContext ctx) { return handle(ctx, (context) -> handleReversestep(ctx)); } - /* ====================================================================== + /* + * ====================================================================== * Predicates within Steps - https://www.w3.org/TR/xpath-31/#id-predicate * ====================================================================== */ @@ -449,8 +479,9 @@ public R visitPredicatelist(PredicatelistContext ctx) { throw new IllegalStateException(); } - /* =========================================== - * Axes - https://www.w3.org/TR/xpath-31/#axes + /* + * =========================================== Axes - + * https://www.w3.org/TR/xpath-31/#axes * =========================================== */ @@ -466,8 +497,9 @@ public R visitReverseaxis(ReverseaxisContext ctx) { throw new IllegalStateException(); } - /* ======================================================= - * Node Tests - https://www.w3.org/TR/xpath-31/#node-tests + /* + * ======================================================= Node Tests - + * https://www.w3.org/TR/xpath-31/#node-tests * ======================================================= */ @@ -504,8 +536,9 @@ public R visitWildcard(WildcardContext ctx) { return handleWildcard(ctx); } - /* =========================================================== - * Abbreviated Syntax - https://www.w3.org/TR/xpath-31/#abbrev + /* + * =========================================================== Abbreviated + * Syntax - https://www.w3.org/TR/xpath-31/#abbrev * =========================================================== */ @@ -539,7 +572,8 @@ public R visitAbbrevreversestep(AbbrevreversestepContext ctx) { return handleAbbrevreversestep(ctx); } - /* ====================================================================== + /* + * ====================================================================== * Constructing Sequences - https://www.w3.org/TR/xpath-31/#construct_seq * ====================================================================== */ @@ -559,7 +593,8 @@ public R visitRangeexpr(RangeexprContext ctx) { return handle(ctx, (context) -> handleRangeexpr(ctx)); } - /* ======================================================================== + /* + * ======================================================================== * Combining Node Sequences - https://www.w3.org/TR/xpath-31/#combining_seq * ======================================================================== */ @@ -594,7 +629,8 @@ public R visitIntersectexceptexpr(IntersectexceptexprContext ctx) { return handle(ctx, (context) -> handleIntersectexceptexpr(ctx)); } - /* ====================================================================== + /* + * ====================================================================== * Arithmetic Expressions - https://www.w3.org/TR/xpath-31/#id-arithmetic * ====================================================================== */ @@ -650,9 +686,12 @@ public R visitValueexpr(ValueexprContext ctx) { return delegateToChild(ctx); } - /* ======================================================================================== - * String Concatenation Expressions - https://www.w3.org/TR/xpath-31/#id-string-concat-expr - * ======================================================================================== + /* + * ============================================================================= + * =========== String Concatenation Expressions - + * https://www.w3.org/TR/xpath-31/#id-string-concat-expr + * ============================================================================= + * =========== */ /** @@ -670,7 +709,8 @@ public R visitStringconcatexpr(StringconcatexprContext ctx) { return handle(ctx, (context) -> handleStringconcatexpr(ctx)); } - /* ======================================================================= + /* + * ======================================================================= * Comparison Expressions - https://www.w3.org/TR/xpath-31/#id-comparisons * ======================================================================= */ @@ -702,7 +742,8 @@ public R visitGeneralcomp(GeneralcompContext ctx) { throw new IllegalStateException(); } - /* ============================================================================ + /* + * ============================================================================ * Logical Expressions - https://www.w3.org/TR/xpath-31/#id-logical-expressions * ============================================================================ */ @@ -737,10 +778,9 @@ public R visitAndexpr(AndexprContext ctx) { return handle(ctx, (context) -> handleAndexpr(ctx)); } - /* ==================================================================== - * For Expressions - https://www.w3.org/TR/xpath-31/#id-for-expressions - * ==================================================================== - */ + // ==================================================================== + // For Expressions - https://www.w3.org/TR/xpath-31/#id-for-expressions + // ==================================================================== /** * Handle the provided expression. @@ -769,10 +809,9 @@ public R visitSimpleforbinding(SimpleforbindingContext ctx) { throw new IllegalStateException(); } - /* ==================================================================== - * Let Expressions - https://www.w3.org/TR/xpath-31/#id-let-expressions - * ==================================================================== - */ + // ==================================================================== + // Let Expressions - https://www.w3.org/TR/xpath-31/#id-let-expressions + // ==================================================================== /** * Handle the provided expression. @@ -801,10 +840,49 @@ public R visitSimpleletbinding(SimpleletbindingContext ctx) { throw new IllegalStateException(); } - /* ========================================================================= - * Conditional Expressions - https://www.w3.org/TR/xpath-31/#id-conditionals - * ========================================================================= + // ============================================================== + // Array Constructors - https://www.w3.org/TR/xpath-31/#id-arrays + // ============================================================== + + @Override + public R visitArrayconstructor(ArrayconstructorContext ctx) { + assert ctx != null; + return delegateToChild(ctx); + } + + /** + * Handle the provided expression. + * + * @param ctx + * the provided expression context + * @return the result + */ + protected abstract R handleArrayConstructor(@NonNull SquarearrayconstructorContext ctx); + + @Override + public R visitSquarearrayconstructor(SquarearrayconstructorContext ctx) { + assert ctx != null; + return handleArrayConstructor(ctx); + } + + /** + * Handle the provided expression. + * + * @param ctx + * the provided expression context + * @return the result */ + protected abstract R handleArrayConstructor(@NonNull CurlyarrayconstructorContext ctx); + + @Override + public R visitCurlyarrayconstructor(CurlyarrayconstructorContext ctx) { + assert ctx != null; + return handleArrayConstructor(ctx); + } + + // ========================================================================= + // Conditional Expressions - https://www.w3.org/TR/xpath-31/#id-conditionals + // ========================================================================= /** * Handle the provided expression. @@ -821,9 +899,12 @@ public R visitIfexpr(IfexprContext ctx) { return handle(ctx, (context) -> handleIfexpr(ctx)); } - /* ================================================================================== - * Quantified Expressions - https://www.w3.org/TR/xpath-31/#id-quantified-expressions - * ================================================================================== + /* + * ============================================================================= + * ===== Quantified Expressions - + * https://www.w3.org/TR/xpath-31/#id-quantified-expressions + * ============================================================================= + * ===== */ /** @@ -841,7 +922,8 @@ public R visitQuantifiedexpr(QuantifiedexprContext ctx) { return handleQuantifiedexpr(ctx); } - /* ========================================================================= + /* + * ========================================================================= * Simple map operator (!) - https://www.w3.org/TR/xpath-31/#id-map-operator * ========================================================================= */ @@ -861,8 +943,9 @@ public R visitSimplemapexpr(SimplemapexprContext ctx) { return handle(ctx, (context) -> handleSimplemapexpr(ctx)); } - /* ======================================================================= - * Arrow operator (=>) - https://www.w3.org/TR/xpath-31/#id-arrow-operator + /* + * ======================================================================= Arrow + * operator (=>) - https://www.w3.org/TR/xpath-31/#id-arrow-operator * ======================================================================= */ diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractCSTVisitorBase.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractCSTVisitorBase.java index 637d24caf..2a7e6e1ef 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractCSTVisitorBase.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractCSTVisitorBase.java @@ -47,6 +47,7 @@ import javax.xml.namespace.QName; import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; public abstract class AbstractCSTVisitorBase extends AbstractAstVisitor { @@ -130,6 +131,28 @@ public IExpression visit(ParseTree tree) { return super.visit(tree); } + @Nullable + protected IExpression + nAiryToCollection( + @NonNull CONTEXT context, + int startIndex, + int step, + @NonNull BiFunction parser, + @NonNull Function, IExpression> supplier) { + int numChildren = context.getChildCount(); + + IExpression retval = null; + if (startIndex < numChildren) { + List children = new ArrayList<>((numChildren - startIndex) / step); + for (int idx = startIndex; idx < numChildren; idx += step) { + EXPRESSION result = parser.apply(context, idx); + children.add(result); + } + retval = supplier.apply(children); + } + return retval; + } + /** * Parse the provided context as an n-ary phrase, which will be one of the * following. diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpressionVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpressionVisitor.java index 92c0b5e2a..7a8c807ad 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpressionVisitor.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpressionVisitor.java @@ -352,4 +352,14 @@ public RESULT visitFor(For expr, CONTEXT context) { public RESULT visitSimpleMap(SimpleMap expr, CONTEXT context) { return visitChildren(expr, context); } + + @Override + public RESULT visitArray(ArraySequence expr, CONTEXT context) { + return visitChildren(expr, context); + } + + @Override + public RESULT visitArray(ArrayMembers expr, CONTEXT context) { + return visitChildren(expr, context); + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArrayMembers.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArrayMembers.java new file mode 100644 index 000000000..4b7ec9213 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArrayMembers.java @@ -0,0 +1,80 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.cst; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.function.library.FnData; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayMember; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class ArrayMembers implements IExpression { + @NonNull + private final List children; + + public ArrayMembers(@NonNull List children) { + this.children = children; + } + + @Override + public List getChildren() { + return children; + } + + @Override + public ISequence accept(DynamicContext dynamicContext, ISequence focus) { + return ISequence.of(getChildren().stream() + .map(expr -> { + ISequence result = FnData.fnData(expr.accept(dynamicContext, focus)); + + IArrayMember retval; + switch (result.size()) { + case 0: + retval = ISequence.of(); + break; + case 1: + retval = result.iterator().next(); + break; + default: + retval = result; + } + return retval; + }) + .collect(IArrayItem.toArrayItem())); + } + + @Override + public RESULT accept(IExpressionVisitor visitor, CONTEXT context) { + return visitor.visitArray(this, context); + } + +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequence.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequence.java new file mode 100644 index 000000000..5e302eb2b --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequence.java @@ -0,0 +1,82 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.cst; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.function.library.FnData; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayMember; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.Nullable; + +public class ArraySequence implements IExpression { + @Nullable + private final IExpression expr; + + public ArraySequence(@Nullable IExpression expr) { + this.expr = expr; + } + + @SuppressWarnings("rawtypes") + @Override + public Class getBaseResultType() { + return IArrayItem.class; + } + + @SuppressWarnings("rawtypes") + @Override + public Class getStaticResultType() { + return IArrayItem.class; + } + + @SuppressWarnings("null") + @Override + public List getChildren() { + return List.of(expr); + } + + @Override + public ISequence> accept(DynamicContext dynamicContext, ISequence focus) { + ISequence> retval; + if (expr != null) { + List result = FnData.fnData(expr.accept(dynamicContext, focus)); + IArrayItem array = IArrayItem.of(result); + retval = ISequence.of(array); + } else { + retval = ISequence.of(); + } + return retval; + } + + @Override + public RESULT accept(IExpressionVisitor visitor, CONTEXT context) { + return visitor.visitArray(this, context); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java index 471d2acd1..0db7d56c5 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java @@ -38,6 +38,7 @@ import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.AxisstepContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ComparisonexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ContextitemexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.CurlyarrayconstructorContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.EqnameContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ExprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ExprsingleContext; @@ -67,6 +68,7 @@ import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimpleletbindingContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimpleletclauseContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimplemapexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SquarearrayconstructorContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.StringconcatexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.UnaryexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.UnionexprContext; @@ -138,11 +140,10 @@ public BuildCSTVisitor(@NonNull StaticContext context) { this.context = context; } - /* - * ============================================================ Expressions - - * https://www.w3.org/TR/xpath-31/#id-expressions - * ============================================================ - */ + // ============================================================ + // Expressions - https://www.w3.org/TR/xpath-31/#id-expressions + // ============================================================ + @NonNull protected StaticContext getContext() { return context; @@ -156,11 +157,9 @@ protected IExpression handleExpr(ExprContext ctx) { }); } - /* - * ================================================================= Literal - * Expressions - https://www.w3.org/TR/xpath-31/#id-literals - * ================================================================= - */ + // ================================================================= + // Literal Expressions - https://www.w3.org/TR/xpath-31/#id-literals + // ================================================================= @Override protected IExpression handleStringLiteral(LiteralContext ctx) { @@ -187,11 +186,9 @@ protected IExpression handleNumericLiteral(NumericliteralContext ctx) { return retval; } - /* - * ================================================================== Variable - * References - https://www.w3.org/TR/xpath-31/#id-variables - * ================================================================== - */ + // ================================================================== + // Variable References - https://www.w3.org/TR/xpath-31/#id-variables + // ================================================================== @Override protected IExpression handleVarref(VarrefContext ctx) { @@ -201,11 +198,9 @@ protected IExpression handleVarref(VarrefContext ctx) { getContext().getVariablePrefixResolver())); } - /* - * ==================================================================== For - * Expressions - https://www.w3.org/TR/xpath-31/#id-for-expressions - * ==================================================================== - */ + // ==================================================================== + // For Expressions - https://www.w3.org/TR/xpath-31/#id-for-expressions + // ==================================================================== @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") @Override @@ -238,11 +233,9 @@ protected IExpression handleForexpr(ForexprContext ctx) { return retval; } - /* - * ==================================================================== Let - * Expressions - https://www.w3.org/TR/xpath-31/#id-let-expressions - * ==================================================================== - */ + // ==================================================================== + // Let Expressions - https://www.w3.org/TR/xpath-31/#id-let-expressions + // ==================================================================== @Override protected IExpression handleLet(LetexprContext context) { @@ -267,13 +260,33 @@ protected IExpression handleLet(LetexprContext context) { return retval; } - /* - * ============================================================================= - * ===== Quantified Expressions - - * https://www.w3.org/TR/xpath-31/#id-quantified-expressions - * ============================================================================= - * ===== - */ + // ============================================================== + // Array Constructors - https://www.w3.org/TR/xpath-31/#id-arrays + // ============================================================== + + @Override + protected IExpression handleArrayConstructor(SquarearrayconstructorContext context) { + return nAiryToCollection(context, 1, 2, + (ctx, idx) -> { + int pos = (idx - 1) / 2; + ParseTree tree = ctx.exprsingle(pos); + return visit(tree); + }, + children -> { + assert children != null; + return new ArrayMembers(children); + }); + } + + @Override + protected IExpression handleArrayConstructor(CurlyarrayconstructorContext ctx) { + return new ArraySequence(visit(ctx.enclosedexpr())); + } + + // ========================================================= + // Quantified Expressions - + // https://www.w3.org/TR/xpath-31/#id-quantified-expressions + // ========================================================= @Override protected IExpression handleQuantifiedexpr(QuantifiedexprContext ctx) { @@ -310,11 +323,9 @@ protected IExpression handleQuantifiedexpr(QuantifiedexprContext ctx) { return new Quantified(quantifier, vars, satisfies); } - /* - * ======================================================================= Arrow - * operator (=>) - https://www.w3.org/TR/xpath-31/#id-arrow-operator - * ======================================================================= - */ + // ======================================================================= + // Arrow operator (=>) - https://www.w3.org/TR/xpath-31/#id-arrow-operator + // ======================================================================= @Override protected IExpression handleArrowexpr(ArrowexprContext context) { @@ -342,37 +353,29 @@ protected IExpression handleArrowexpr(ArrowexprContext context) { }); } - /* - * ============================================================================= - * ==== Parenthesized Expressions - - * https://www.w3.org/TR/xpath-31/#id-paren-expressions - * ============================================================================= - * ==== - */ + // ==================================================== + // Parenthesized Expressions - + // https://www.w3.org/TR/xpath-31/#id-paren-expressions + // ==================================================== @Override protected IExpression handleEmptyParenthesizedexpr(ParenthesizedexprContext ctx) { return EmptySequence.instance(); } - /* - * ============================================================================= - * ======== Context Item Expression - - * https://www.w3.org/TR/xpath-31/#id-context-item-expression - * ============================================================================= - * ======== - */ + // ========================================================== + // Context Item Expression - + // https://www.w3.org/TR/xpath-31/#id-context-item-expression + // ========================================================== @Override protected IExpression handleContextitemexpr(ContextitemexprContext ctx) { return ContextItem.instance(); } - /* - * ========================================================================= - * Static Function Calls - https://www.w3.org/TR/xpath-31/#id-function-calls - * ========================================================================= - */ + // ========================================================================= + // Static Function Calls - https://www.w3.org/TR/xpath-31/#id-function-calls + // ========================================================================= /** * Parse a list of arguments. @@ -412,11 +415,9 @@ protected IExpression handleFunctioncall(FunctioncallContext ctx) { .collect(Collectors.toUnmodifiableList()))); } - /* - * ========================================================================= - * Filter Expressions - https://www.w3.org/TR/xpath-31/#id-filter-expression - * ========================================================================= - */ + // ========================================================================= + // Filter Expressions - https://www.w3.org/TR/xpath-31/#id-filter-expression + // ========================================================================= /** * Parse a predicate AST. @@ -478,11 +479,9 @@ protected IExpression handlePostfixexpr(PostfixexprContext ctx) { } return retval; } - /* - * ====================================================================== Path - * Expressions - https://www.w3.org/TR/xpath-31/#id-path-expressions - * ====================================================================== - */ + // ====================================================================== + // Path Expressions - https://www.w3.org/TR/xpath-31/#id-path-expressions + // ====================================================================== @Override protected IExpression handlePathexpr(PathexprContext ctx) { @@ -516,13 +515,10 @@ protected IExpression handlePathexpr(PathexprContext ctx) { return retval; } - /* - * ============================================================================= - * ========== RelativePath Expressions - - * https://www.w3.org/TR/xpath-31/#id-relative-path-expressions - * ============================================================================= - * ========== - */ + // ============================================================ + // RelativePath Expressions - + // https://www.w3.org/TR/xpath-31/#id-relative-path-expressions + // ============================================================ @Override protected IExpression handleRelativepathexpr(RelativepathexprContext context) { @@ -549,11 +545,9 @@ protected IExpression handleRelativepathexpr(RelativepathexprContext context) { }); } - /* - * ================================================ Steps - - * https://www.w3.org/TR/xpath-31/#id-steps - * ================================================ - */ + // ================================================ + // Steps - https://www.w3.org/TR/xpath-31/#id-steps + // ================================================ @Override protected IExpression handleForwardstep(ForwardstepContext ctx) { @@ -616,17 +610,9 @@ protected IExpression handleReversestep(ReversestepContext ctx) { return new Step(axis, parseNodeTest(ctx.nodetest(), false)); } - /* - * ======================================================= Node Tests - - * https://www.w3.org/TR/xpath-31/#node-tests - * ======================================================= - */ - - /* - * ======================================================= Node Tests - - * https://www.w3.org/TR/xpath-31/#node-tests - * ======================================================= - */ + // ======================================================= + // Node Tests - https://www.w3.org/TR/xpath-31/#node-tests + // ======================================================= protected INodeTestExpression parseNodeTest(NodetestContext ctx, boolean flag) { // TODO: implement kind test @@ -674,11 +660,9 @@ protected Wildcard handleWildcard(WildcardContext ctx) { return new Wildcard(matcher); } - /* - * ====================================================================== - * Predicates within Steps - https://www.w3.org/TR/xpath-31/#id-predicate - * ====================================================================== - */ + // ====================================================================== + // Predicates within Steps - https://www.w3.org/TR/xpath-31/#id-predicate + // ====================================================================== @Override protected IExpression handleAxisstep(AxisstepContext ctx) { @@ -691,11 +675,9 @@ protected IExpression handleAxisstep(AxisstepContext ctx) { return predicates.isEmpty() ? step : new PredicateExpression(step, predicates); } - /* - * =========================================================== Abbreviated - * Syntax - https://www.w3.org/TR/xpath-31/#abbrev - * =========================================================== - */ + // =========================================================== + // Abbreviated Syntax - https://www.w3.org/TR/xpath-31/#abbrev + // =========================================================== @Override protected IExpression handleAbbrevforwardstep(AbbrevforwardstepContext ctx) { @@ -716,11 +698,9 @@ protected IExpression handleAbbrevreversestep(AbbrevreversestepContext ctx) { return Axis.PARENT; } - /* - * ====================================================================== - * Constructing Sequences - https://www.w3.org/TR/xpath-31/#construct_seq - * ====================================================================== - */ + // ====================================================================== + // Constructing Sequences - https://www.w3.org/TR/xpath-31/#construct_seq + // ====================================================================== @Override protected IExpression handleRangeexpr(RangeexprContext ctx) { @@ -732,11 +712,9 @@ protected IExpression handleRangeexpr(RangeexprContext ctx) { return new Range(left, right); } - /* - * ======================================================================== - * Combining Node Sequences - https://www.w3.org/TR/xpath-31/#combining_seq - * ======================================================================== - */ + // ======================================================================== + // Combining Node Sequences - https://www.w3.org/TR/xpath-31/#combining_seq + // ======================================================================== @Override protected IExpression handleUnionexpr(UnionexprContext ctx) { @@ -771,11 +749,9 @@ protected IExpression handleIntersectexceptexpr(IntersectexceptexprContext conte }); } - /* - * ====================================================================== - * Arithmetic Expressions - https://www.w3.org/TR/xpath-31/#id-arithmetic - * ====================================================================== - */ + // ====================================================================== + // Arithmetic Expressions - https://www.w3.org/TR/xpath-31/#id-arithmetic + // ====================================================================== @Override protected IExpression handleAdditiveexpr(AdditiveexprContext context) { @@ -863,13 +839,10 @@ protected IExpression handleUnaryexpr(UnaryexprContext ctx) { return retval; } - /* - * ============================================================================= - * =========== String Concatenation Expressions - - * https://www.w3.org/TR/xpath-31/#id-string-concat-expr - * ============================================================================= - * =========== - */ + // ===================================================== + // String Concatenation Expressions - + // https://www.w3.org/TR/xpath-31/#id-string-concat-expr + // ===================================================== @Override protected IExpression handleStringconcatexpr(StringconcatexprContext ctx) { @@ -879,11 +852,9 @@ protected IExpression handleStringconcatexpr(StringconcatexprContext ctx) { }); } - /* - * ======================================================================= - * Comparison Expressions - https://www.w3.org/TR/xpath-31/#id-comparisons - * ======================================================================= - */ + // ======================================================================= + // Comparison Expressions - https://www.w3.org/TR/xpath-31/#id-comparisons + // ======================================================================= @Override protected IExpression handleComparisonexpr(ComparisonexprContext ctx) { // NOPMD - ok @@ -956,11 +927,9 @@ protected IExpression handleComparisonexpr(ComparisonexprContext ctx) { // NOPMD return retval; } - /* - * ============================================================================ - * Logical Expressions - https://www.w3.org/TR/xpath-31/#id-logical-expressions - * ============================================================================ - */ + // ============================================================================ + // Logical Expressions - https://www.w3.org/TR/xpath-31/#id-logical-expressions + // ============================================================================ @Override protected IExpression handleOrexpr(OrexprContext ctx) { @@ -978,11 +947,9 @@ protected IExpression handleAndexpr(AndexprContext ctx) { }); } - /* - * ========================================================================= - * Conditional Expressions - https://www.w3.org/TR/xpath-31/#id-conditionals - * ========================================================================= - */ + // ========================================================================= + // Conditional Expressions - https://www.w3.org/TR/xpath-31/#id-conditionals + // ========================================================================= @Override protected IExpression handleIfexpr(IfexprContext ctx) { @@ -993,11 +960,9 @@ protected IExpression handleIfexpr(IfexprContext ctx) { return new If(testExpr, thenExpr, elseExpr); } - /* - * ========================================================================= - * Simple map operator (!) - https://www.w3.org/TR/xpath-31/#id-map-operator - * ========================================================================= - */ + // ========================================================================= + // Simple map operator (!) - https://www.w3.org/TR/xpath-31/#id-map-operator + // ========================================================================= @Override protected IExpression handleSimplemapexpr(SimplemapexprContext context) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/CSTPrinter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/CSTPrinter.java index 635edacb7..738dbbd4b 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/CSTPrinter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/CSTPrinter.java @@ -336,6 +336,15 @@ public String visitSimpleMap(SimpleMap expr, State context) { return appendNode(expr, super.visitSimpleMap(expr, context), context); } + @Override + public String visitArray(ArraySequence expr, State context) { + return appendNode(expr, super.visitArray(expr, context), context); + } + + @Override + public String visitArray(ArrayMembers expr, State context) { + return appendNode(expr, super.visitArray(expr, context), context); + } } static class State { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/IExpressionVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/IExpressionVisitor.java index d0642f479..e52a5f336 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/IExpressionVisitor.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/IExpressionVisitor.java @@ -510,4 +510,26 @@ public interface IExpressionVisitor { * @return the visitation result or {@code null} if no result was produced */ RESULT visitSimpleMap(@NonNull SimpleMap expr, @NonNull CONTEXT context); + + /** + * Visit the CST node. + * + * @param expr + * the CST node to visit + * @param context + * the processing context + * @return the visitation result or {@code null} if no result was produced + */ + RESULT visitArray(@NonNull ArraySequence expr, @NonNull CONTEXT context); + + /** + * Visit the CST node. + * + * @param expr + * the CST node to visit + * @param context + * the processing context + * @return the visitation result or {@code null} if no result was produced + */ + RESULT visitArray(@NonNull ArrayMembers expr, @NonNull CONTEXT context); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractArrayItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractArrayItem.java index ea687c65b..f132dd327 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractArrayItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractArrayItem.java @@ -41,6 +41,7 @@ import java.util.EnumSet; import java.util.List; +import java.util.Objects; import java.util.Set; import javax.xml.namespace.QName; @@ -89,4 +90,14 @@ public ISequence execute(List> arguments, DynamicContext dynamic : ObjectUtils.notNull((ISequence) result); } + @Override + public int hashCode() { + return Objects.hash(getValue()); + } + + @Override + public boolean equals(Object other) { + return other == this + || other instanceof IArrayItem && getValue().equals(((IArrayItem) other).getValue()); + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItem.java index 1f25b9f6d..e478d423f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItem.java @@ -34,12 +34,19 @@ import gov.nist.secauto.metaschema.core.metapath.impl.AbstractArrayItem; import gov.nist.secauto.metaschema.core.metapath.impl.ArrayItemN; import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; import javax.xml.namespace.QName; @@ -185,6 +192,55 @@ default List subList(int fromIndex, int toIndex) { return getValue().subList(fromIndex, toIndex); } + /** + * A {@link Collector} implementation to generates a sequence from a stream of + * Metapath items. + * + * @param + * the Java type of the items + * @return a collector that will generate a sequence + */ + @NonNull + static Collector> toArrayItem() { + return new Collector, IArrayItem>() { + + @Override + public Supplier> supplier() { + return ArrayList::new; + } + + @Override + public BiConsumer, T> accumulator() { + return List::add; + } + + @Override + public BinaryOperator> combiner() { + return (list1, list2) -> { + list1.addAll(list2); + return list1; + }; + } + + @Override + public Function, IArrayItem> finisher() { + return list -> of(ObjectUtils.notNull(list)); + } + + @Override + public Set characteristics() { + return Collections.emptySet(); + } + }; + } + + @SuppressWarnings("unchecked") + @NonNull + static IArrayItem of( // NOPMD - intentional + @NonNull List items) { + return items.isEmpty() ? empty() : (IArrayItem) new ArrayItemN<>(items); + } + /** * Returns an unmodifiable array item containing zero elements. * diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItemTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItemTest.java index f9c5ba247..8bd7924d0 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItemTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItemTest.java @@ -32,6 +32,7 @@ import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -62,9 +63,8 @@ private static Stream provideValues() { // NOPMD - false positive @ParameterizedTest @MethodSource("provideValues") void testExpression(@NonNull IArrayItem expected, @NonNull String metapath) { - assertEquals( - expected, - MetapathExpression.compile(metapath) - .evaluateAs(null, MetapathExpression.ResultType.SEQUENCE, newDynamicContext())); + IItem result = MetapathExpression.compile(metapath) + .evaluateAs(null, MetapathExpression.ResultType.NODE, newDynamicContext()); + assertEquals(expected, result); } }