Skip to content

Commit

Permalink
Inline functions are now working.
Browse files Browse the repository at this point in the history
  • Loading branch information
david-waltermire committed Nov 27, 2024
1 parent 9e8491c commit 945e9d4
Show file tree
Hide file tree
Showing 28 changed files with 725 additions and 329 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import gov.nist.secauto.metaschema.core.configuration.DefaultConfiguration;
import gov.nist.secauto.metaschema.core.configuration.IConfiguration;
import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
import gov.nist.secauto.metaschema.core.metapath.function.DefaultFunction.CallingContext;
import gov.nist.secauto.metaschema.core.metapath.function.CallingContext;
import gov.nist.secauto.metaschema.core.metapath.function.IFunction.FunctionProperty;
import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem;
import gov.nist.secauto.metaschema.core.model.IUriResolver;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,40 @@ public R visitArgument(Metapath10.ArgumentContext ctx) {
throw new IllegalStateException(ERR_NO_DELEGATION);
}

// ============================================================
// https://www.w3.org/TR/xpath-31/#doc-xpath31-NamedFunctionRef
// ============================================================

@Override
public R visitNamedfunctionref(Metapath10.NamedfunctionrefContext ctx) {
throw new UnsupportedOperationException("expression not supported");
}

// ==============================================
// https://www.w3.org/TR/xpath-31/#id-inline-func
// ==============================================

@Override
public R visitFunctionitemexpr(Metapath10.FunctionitemexprContext ctx) {
assert ctx != null;
return delegateToChild(ctx);
}

/**
* Handle the provided expression.
*
* @param ctx
* the provided expression context
* @return the result
*/
protected abstract R handleInlinefunctionexpr(@NonNull Metapath10.InlinefunctionexprContext ctx);

@Override
public R visitInlinefunctionexpr(Metapath10.InlinefunctionexprContext ctx) {
assert ctx != null;
return handle(ctx, this::handleInlinefunctionexpr);
}

// =======================================================================
// Enclosed Expressions - https://www.w3.org/TR/xpath-31/#id-enclosed-expr
// =======================================================================
Expand Down Expand Up @@ -1018,16 +1052,6 @@ public R visitArrowfunctionspecifier(Metapath10.ArrowfunctionspecifierContext ct
throw new IllegalStateException(ERR_NO_DELEGATION);
}

@Override
public R visitNamedfunctionref(Metapath10.NamedfunctionrefContext ctx) {
throw new UnsupportedOperationException("expression not supported");
}

@Override
public R visitInlinefunctionexpr(Metapath10.InlinefunctionexprContext ctx) {
throw new UnsupportedOperationException("expression not supported");
}

/*
* ==========================================================
* The following are handled inline by other expression types
Expand Down Expand Up @@ -1225,12 +1249,6 @@ public R visitFunctionbody(Metapath10.FunctionbodyContext ctx) {
throw new IllegalStateException(ERR_NO_DELEGATION);
}

@Override
public R visitFunctionitemexpr(Metapath10.FunctionitemexprContext ctx) {
// should never be called, since this is handled by the parent expression
throw new IllegalStateException(ERR_NO_DELEGATION);
}

@Override
public R visitTypedeclaration(Metapath10.TypedeclarationContext ctx) {
// should never be called, since this is handled by the parent expression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,48 @@ public IExpression visit(ParseTree tree) {
* @return the outer expression or {@code null} if no children exist to parse
*/
@Nullable
protected <CONTEXT extends ParserRuleContext, T extends IExpression, R extends IExpression>
protected <CONTEXT extends ParserRuleContext, T, R, S extends List<R>>
List<R> nairyToList(
@NonNull CONTEXT context,
int startIndex,
int step,
@NonNull BiFunction<CONTEXT, Integer, R> parser) {
int numChildren = context.getChildCount();

List<R> retval = null;
if (startIndex < numChildren) {
retval = new ArrayList<>((numChildren - startIndex) / step);
for (int idx = startIndex; idx < numChildren; idx += step) {
R result = parser.apply(context, idx);
retval.add(result);
}
}
return retval;
}

/**
* Parse the provided context as an n-ary phrase.
*
* @param <CONTEXT>
* the Java type of the antlr context to parse
* @param <T>
* the Java type of the child expressions produced by this parser
* @param <R>
* the Java type of the outer expression produced by the parser
* @param context
* the antlr context to parse
* @param startIndex
* the child index to start parsing on
* @param step
* the increment to advance while parsing child expressions
* @param parser
* a binary function used to produce child expressions
* @param supplier
* a function used to produce the other expression
* @return the outer expression or {@code null} if no children exist to parse
*/
@Nullable
protected <CONTEXT extends ParserRuleContext, T, R>
R nairyToCollection(
@NonNull CONTEXT context,
int startIndex,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ public RESULT visitDynamicFunctionCall(DynamicFunctionCall expr, CONTEXT context
return visitChildren(expr, context);
}

@Override
public RESULT visitAnonymousFunctionCall(AnonymousFunctionCall expr, CONTEXT context) {
return visitChildren(expr, context);
}

@Override
public RESULT visitIntegerDivision(IntegerDivision expr, CONTEXT context) {
return visitChildren(expr, context);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* SPDX-FileCopyrightText: none
* SPDX-License-Identifier: CC0-1.0
*/

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.IArgument;
import gov.nist.secauto.metaschema.core.metapath.function.IFunction;
import gov.nist.secauto.metaschema.core.metapath.function.impl.AbstractFunction;
import gov.nist.secauto.metaschema.core.metapath.item.IItem;
import gov.nist.secauto.metaschema.core.metapath.type.ISequenceType;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;

import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;

/**
* Executes a function call based on a specifier expression that is used to
* dtermine the function and multiple argument expressions that are used to
* determine the function arguments.
*/
public class AnonymousFunctionCall
extends AbstractFunction
implements IExpression, IFunction {
@NonNull
private static final Set<FunctionProperty> PROPERTIES = ObjectUtils.notNull(EnumSet.of(
// FunctionProperty.CONTEXT_DEPENDENT,
// FunctionProperty.FOCUS_DEPENDENT,
FunctionProperty.DETERMINISTIC));
@NonNull
private final ISequenceType result;
@NonNull
private final IExpression body;

/**
* Construct a new function call expression.
*
* @param arguments
*/
public AnonymousFunctionCall(
@NonNull List<IArgument> arguments,
@NonNull ISequenceType result,
@NonNull IExpression body) {
super("(anonymous)-" + UUID.randomUUID().toString(), "", arguments);
this.result = result;
this.body = body;
}

@Override
public List<IExpression> getChildren() {
return ObjectUtils.notNull(List.of(body));
}

@Override
public Class<? extends IItem> getBaseResultType() {
return IFunction.class;
}

@Override
public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
return visitor.visitAnonymousFunctionCall(this, context);
}

@Override
public ISequence<?> accept(DynamicContext dynamicContext, ISequence<?> focus) {
return ISequence.of(this);
}

@SuppressWarnings("null")
@Override
public String toASTString() {
return String.format("%s[arguments=%s,return=%s]",
getClass().getName(), getName(),
getArguments(),
result.toSignature());
}

@Override
public Set<FunctionProperty> getProperties() {
return PROPERTIES;
}

@Override
public ISequenceType getResult() {
return result;
}

@Override
@NonNull
protected ISequence<?> executeInternal(
@NonNull List<ISequence<?>> arguments,
@NonNull DynamicContext dynamicContext,
@Nullable IItem focus) {

DynamicContext subContext = dynamicContext.subContext();
Iterator<? extends ISequence<?>> args = arguments.iterator();
Iterator<IArgument> params = getArguments().iterator();
while (args.hasNext() && params.hasNext()) {
ISequence<?> sequence = args.next();
IArgument param = params.next();

subContext.bindVariableValue(param.getName(), ObjectUtils.notNull(sequence));
}

return body.accept(subContext, ISequence.of(focus));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import gov.nist.secauto.metaschema.core.metapath.StaticContext;
import gov.nist.secauto.metaschema.core.metapath.StaticMetapathException;
import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10;
import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ParamContext;
import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10Lexer;
import gov.nist.secauto.metaschema.core.metapath.cst.items.ArraySequenceConstructor;
import gov.nist.secauto.metaschema.core.metapath.cst.items.ArraySquareConstructor;
Expand Down Expand Up @@ -61,12 +62,14 @@
import gov.nist.secauto.metaschema.core.metapath.cst.type.Treat;
import gov.nist.secauto.metaschema.core.metapath.cst.type.TypeTestSupport;
import gov.nist.secauto.metaschema.core.metapath.function.ComparisonFunctions;
import gov.nist.secauto.metaschema.core.metapath.function.IArgument;
import gov.nist.secauto.metaschema.core.metapath.impl.AbstractKeySpecifier;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem;
import gov.nist.secauto.metaschema.core.metapath.item.function.IKeySpecifier;
import gov.nist.secauto.metaschema.core.metapath.type.IAtomicOrUnionType;
import gov.nist.secauto.metaschema.core.metapath.type.IItemType;
import gov.nist.secauto.metaschema.core.metapath.type.ISequenceType;
import gov.nist.secauto.metaschema.core.metapath.type.Occurrence;
import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
import gov.nist.secauto.metaschema.core.util.CollectionUtil;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
Expand Down Expand Up @@ -100,6 +103,9 @@
// https://www.w3.org/TR/xpath-31/#id-node-comparisons
public class BuildCSTVisitor
extends AbstractCSTVisitorBase {
private static final ISequenceType DEFAULT_FUNCTION_SEQUENCE_TYPE
= ISequenceType.of(IItemType.item(), Occurrence.ZERO_OR_MORE);

@NonNull
private final StaticContext context;

Expand Down Expand Up @@ -381,6 +387,51 @@ protected IExpression handleFunctioncall(Metapath10.FunctioncallContext ctx) {
arguments);
}

// ============================================================
// https://www.w3.org/TR/xpath-31/#doc-xpath31-NamedFunctionRef
// ============================================================

@Override
public IExpression visitNamedfunctionref(Metapath10.NamedfunctionrefContext ctx) {
throw new UnsupportedOperationException("expression not supported");
}

// ==============================================
// https://www.w3.org/TR/xpath-31/#id-inline-func
// ==============================================

@Override
public IExpression handleInlinefunctionexpr(Metapath10.InlinefunctionexprContext context) {
// parse the param list
List<IArgument> parameters = ObjectUtils.notNull(context.paramlist() == null
? CollectionUtil.emptyList()
: nairyToList(
ObjectUtils.notNull(context.paramlist()),
0,
2,
(ctx, idx) -> {
int pos = (idx - 1) / 2;
ParamContext tree = ctx.param(pos);
return IArgument.of(
getContext().parseVariableName(ObjectUtils.notNull(tree.eqname().getText())),
tree.typedeclaration() == null
? DEFAULT_FUNCTION_SEQUENCE_TYPE
: TypeTestSupport.parseSequenceType(tree.typedeclaration().sequencetype(), getContext()));
}));

// parse the result type
ISequenceType resultSequenceType = context.sequencetype() == null
? DEFAULT_FUNCTION_SEQUENCE_TYPE
: TypeTestSupport.parseSequenceType(
ObjectUtils.notNull(context.sequencetype()),
getContext());

// parse the function body
IExpression body = visit(context.functionbody().enclosedexpr());

return new AnonymousFunctionCall(parameters, resultSequenceType, body);
}

// =========================================================================
// Filter Expressions - https://www.w3.org/TR/xpath-31/#id-filter-expression
// =========================================================================
Expand Down Expand Up @@ -448,7 +499,8 @@ protected IExpression handlePostfixexpr(Metapath10.PostfixexprContext context) {
// map or array access using function call syntax
result = new FunctionCallAccessor(
left,
ObjectUtils.notNull(parseArgumentList((Metapath10.ArgumentlistContext) tree).findFirst().get()));
ObjectUtils.notNull(parseArgumentList((Metapath10.ArgumentlistContext) tree)
.collect(Collectors.toUnmodifiableList())));
} else if (tree instanceof Metapath10.PredicateContext) {
result = new PredicateExpression(
left,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ public String visitDynamicFunctionCall(DynamicFunctionCall expr, State context)
return appendNode(expr, super.visitDynamicFunctionCall(expr, context), context);
}

@Override
public String visitAnonymousFunctionCall(AnonymousFunctionCall expr, State context) {
return appendNode(expr, super.visitAnonymousFunctionCall(expr, context), context);
}

@Override
public String visitIntegerDivision(IntegerDivision expr, State context) {
return appendNode(expr, super.visitIntegerDivision(expr, context), context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,17 @@ public interface IExpressionVisitor<RESULT, CONTEXT> {
*/
RESULT visitDynamicFunctionCall(@NonNull DynamicFunctionCall 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 visitAnonymousFunctionCall(@NonNull AnonymousFunctionCall expr, @NonNull CONTEXT context);

/**
* Visit the CST node.
*
Expand Down
Loading

0 comments on commit 945e9d4

Please sign in to comment.