All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.expr.parser.RoleLocator Maven / Gradle / Ivy

There is a newer version: 10.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2013 Saxonica Limited.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.expr.parser;

import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.type.ItemType;

import java.io.Serializable;

/**
 * A RoleLocator identifies the role in which an expression is used, for example as
 * the third argument of the concat() function. This information is stored in an
 * ItemChecker or CardinalityChecker so that good diagnostics can be
 * achieved when run-time type errors are detected.
 */
public class RoleLocator implements Serializable {

    private int kind;
    private Object operation; // always either a String or a StructuredQName
    private int operand;
    private String errorCode = "XPTY0004";  // default error code for type errors

    public static final int FUNCTION = 0;
    public static final int BINARY_EXPR = 1;
    public static final int TYPE_OP = 2;
    public static final int VARIABLE = 3;
    public static final int INSTRUCTION = 4;
    public static final int FUNCTION_RESULT = 5;
    public static final int ORDER_BY = 6;
    public static final int TEMPLATE_RESULT = 7;
    public static final int PARAM = 8;
    public static final int UNARY_EXPR = 9;
    public static final int UPDATING_EXPR = 10;
    public static final int GROUPING_KEY = 11;
    public static final int EVALUATE_RESULT = 12;
    public static final int CONTEXT_ITEM = 13;
    public static final int AXIS_STEP = 14;

    /**
     * Create information about the role of a subexpression within its parent expression
     * @param kind the kind of parent expression, e.g. a function call or a variable reference
     * @param operation the name of the object in the parent expression, e.g. a function name or
     * instruction name. May be expressed either as a String or as a {@link net.sf.saxon.om.StructuredQName}.
     * For a string, the special format element/attribute is recognized, for example xsl:for-each/select,
     * to identify the role of an XPath expression in a stylesheet.
     * @param operand Ordinal position of this subexpression, e.g. the position of an argument in
     * a function call
     */

    public RoleLocator(int kind, Object operation, int operand) {
        if (!(operation instanceof String || operation instanceof StructuredQName)) {
            throw new IllegalArgumentException("operation");
        }
        this.kind = kind;
        this.operation = operation;
        this.operand = operand;
    }

    /**
     * Set the error code to be produced if a type error is detected
     * @param code The error code
     */

    public void setErrorCode(/*@Nullable*/ String code) {
        if (code != null) {
            this.errorCode = code;
        }
    }

    /**
     * Get the error code to be produced if a type error is detected
     * @return code The error code
     */

    public String getErrorCode() {
        return errorCode;
    }

    /**
     * Ask whether the error code represents a type error
     * @return true if the error is treated as a type error
     */

    public boolean isTypeError() {
        return !errorCode.startsWith("FORG") && !errorCode.equals("XPDY0050");
    }

    /**
     * Construct and return the error message indicating a type error
     * @return the constructed error message
     */
    public String getMessage() {
        String name;
        if (operation instanceof String) {
            name = (String)operation;
        } else {
            name = ((StructuredQName)operation).getDisplayName();
        }

        switch (kind) {
            case FUNCTION:
                if (name.equals("saxon:call")) {
                    if (operand==0) {
                        return "target of dynamic function call";
                    } else {
                        return ordinal(operand) + " argument of dynamic function call";
                    }
                } else {
                    return ordinal(operand+1) + " argument of " +
                        (name.length()==0 ? "anonymous function" : name + "()");
                }
            case BINARY_EXPR:
                return ordinal(operand+1) + " operand of '" + name + '\'';
            case UNARY_EXPR:
                return "operand of '-'";
            case TYPE_OP:
                return "value in '" + name + "' expression";
            case VARIABLE:
                if (name.equals("saxon:context-item")) {
                    return "context item";
                } else {
                    return "value of variable $" + name;
                }
            case INSTRUCTION:
                int slash = name.indexOf('/');
                String attributeName = "";
                if (slash >= 0) {
                    attributeName = name.substring(slash+1);
                    name = name.substring(0, slash);
                }
                return '@' + attributeName + " attribute of " + name;
            case FUNCTION_RESULT:
                if (name.length() == 0) {
                    return "result of anonymous function";
                } else {
                    return "result of function " + name + "()";
                }
            case TEMPLATE_RESULT:
                return "result of template " + name;
            case ORDER_BY:
                return ordinal(operand+1) + " sort key";
            case PARAM:
                return "value of parameter $" + name;
            case UPDATING_EXPR:
                return "value of " + ordinal(operand+1) + " operand of " + name + " expression";
            case GROUPING_KEY:
                return "value of the grouping key";
            case EVALUATE_RESULT:
                return "result of the expression {" + name + "} evaluated by xsl:evaluate";
            case CONTEXT_ITEM:
                return "the context item";
            case AXIS_STEP:
                return "the context item for the " + operation + " axis";
            default:
                return "";
        }
    }

    /**
     * Construct the part of the message giving the required item type
     *
     * @param requiredItemType the item type required by the context of a particular expression
     * @return a message of the form "Required item type of X is Y"
     */

    public String composeRequiredMessage(ItemType requiredItemType) {
        return "Required item type of " + getMessage() +
                     " is " + requiredItemType.toString();
    }

    /**
     * Construct a full error message
     *
     * @param requiredItemType the item type required by the context of a particular expression
     * @param suppliedItemType the item type inferred by static analysis of an expression
     * @return a message of the form "Required item type of A is R; supplied value has item type S"
     */

    public String composeErrorMessage(ItemType requiredItemType, ItemType suppliedItemType) {
        return "Required item type of " + getMessage() +
                     " is " + requiredItemType.toString() +
                     "; supplied value has item type " +
                     suppliedItemType.toString();
    }

    /**
     * Get the ordinal representation of a number (used to identify which argument of a function
     * is in error)
     * @param n the cardinal number
     * @return the ordinal representation
     */
    public static String ordinal(int n) {
        switch(n) {
            case 1:
                return "first";
            case 2:
                return "second";
            case 3:
                return "third";
            default:
                // we can live with 21th, 22th... How many functions have >20 arguments?
                return n + "th";
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy