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

org.yamcs.mdb.ConditionParser Maven / Gradle / Ivy

There is a newer version: 5.10.9
Show newest version
package org.yamcs.mdb;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.yamcs.xtce.ANDedConditions;
import org.yamcs.xtce.BooleanDataType;
import org.yamcs.xtce.BooleanExpression;
import org.yamcs.xtce.Comparison;
import org.yamcs.xtce.ComparisonList;
import org.yamcs.xtce.Condition;
import org.yamcs.xtce.ExpressionList;
import org.yamcs.xtce.MatchCriteria;
import org.yamcs.xtce.ORedConditions;
import org.yamcs.xtce.OperatorType;
import org.yamcs.xtce.Parameter;
import org.yamcs.xtce.ParameterInstanceRef;
import org.yamcs.xtce.util.NameReference;

/**
 * used by the SpreadsheetLoader to parse conditions
 * 
 * 
 * @author nm
 *
 */
public class ConditionParser {
    ParameterReferenceFactory prefFactory;

    public ConditionParser(ParameterReferenceFactory prefFactory) {
        this.prefFactory = prefFactory;
    }

    public MatchCriteria parseMatchCriteria(String criteriaString) throws ParseException {
        criteriaString = criteriaString.trim();
        if ((criteriaString.startsWith("&(") || criteriaString.startsWith("|("))
                && (criteriaString.endsWith(")"))) {
            return parseBooleanExpression(criteriaString);
        } else if (criteriaString.contains(";")) {
            ComparisonList cl = new ComparisonList();
            String splitted[] = criteriaString.split(";");
            for (String part : splitted) {
                cl.addComparison(toComparison(part));
            }
            return cl;
        } else {
            return toComparison(criteriaString);
        }
    }

    /**
     * Boolean expression has the following pattern: op(epx1;exp2;...;expn)
     *
     * op is & (AND) or | (OR) expi are boolean expression or condition
     *
     * A condition is defined as: parametername op value
     *
     * value can be - plain value - quoted with " or ”. The two quote characters can be used interchangeably . Backslash
     * can be use to escape those double quote. - $other_parametername
     *
     * parametername can be suffixed with .raw
     *
     * Top level expression can be in the form epx1;exp2;...;expn which will be transformed into &(epx1;exp2;...;expn)
     * for compatibility with the previously implemented Comparison
     * 
     * @param rawExpression
     * 
     * @return
     * @throws ParseException
     */
    public BooleanExpression parseBooleanExpression(String rawExpression) throws ParseException {
        String regex = "([\"”])([^\"”\\\\]*(?:\\\\.[^\"”\\\\]*)*)([\"”])";

        rawExpression = rawExpression.trim();

        // Correct top-level expression
        if (!rawExpression.startsWith("&") && !rawExpression.startsWith("|")) {
            rawExpression = "&(" + rawExpression + ")";
        }

        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(rawExpression);
        ArrayList quotes = new ArrayList<>();
        while (m.find()) {
            quotes.add(rawExpression.substring(m.start(2), m.end(2)));
        }

        String spec = p.matcher(rawExpression).replaceAll("\\$\\$");

        return toBooleanExpression(spec, quotes);
    }

    void parseConditionList(ExpressionList conditions, String spec, ArrayList quotes) throws ParseException {
        // Split top-level expressions
        ArrayList expressions = new ArrayList<>();
        int balance = 0;
        StringBuilder exp = new StringBuilder();
        for (int i = 0; i < spec.length(); i++) {
            if (spec.charAt(i) == '(') {
                balance++;
            } else if (spec.charAt(i) == ')') {
                balance--;
            } else if ((spec.charAt(i) == ';') && (balance == 0)) {
                if (exp.length() > 0) {
                    expressions.add(exp.toString());
                }
                exp = new StringBuilder();
                continue;
            }

            exp.append(spec.charAt(i));
        }

        if (exp.length() > 0) {
            expressions.add(exp.toString());
        }

        // Parse each expression
        for (String expression : expressions) {
            conditions.addConditionExpression(toBooleanExpression(expression, quotes));
        }
    }

    private BooleanExpression toBooleanExpression(String spec, ArrayList quotes) throws ParseException {
        spec = spec.trim();
        BooleanExpression condition = null;

        if (spec.startsWith("&(") && (spec.endsWith(")"))) {
            condition = new ANDedConditions();
            parseConditionList((ExpressionList) condition, spec.substring(2, spec.length() - 1), quotes);
        } else if (spec.startsWith("|(") && (spec.endsWith(")"))) {
            condition = new ORedConditions();
            parseConditionList((ExpressionList) condition, spec.substring(2, spec.length() - 1), quotes);
        } else {
            condition = toCondition(spec, quotes);
        }

        return condition;
    }

    private Condition toCondition(String comparisonString, ArrayList quotes) throws ParseException {
        Matcher m = Pattern.compile("(.*?)(==|=|!=|<=|>=|<|>)(.*)").matcher(comparisonString);
        if (!m.matches()) {
            throw new ParseException("Cannot parse condition '" + comparisonString + "'", 0);
        }

        String lParamName = m.group(1).trim();
        boolean lParamCalibrated = true;

        if (lParamName.endsWith(".raw")) {
            lParamName = lParamName.substring(0, lParamName.length() - 4);
            lParamCalibrated = false;
        }
        final ParameterInstanceRef lParamRef = new ParameterInstanceRef(lParamCalibrated);

        String op = m.group(2);
        if ("=".equals(op)) {
            op = "==";
        }

        String rValue = m.group(3).trim();
        String rParamName = null;
        final ParameterInstanceRef rParamRef;
        final Condition cond;

        if (rValue.startsWith("$$")) { // Quoted values
            rValue = quotes.remove(0);
        }

        if (rValue.startsWith("$")) {
            boolean rParamCalibrated = true;
            rParamName = rValue.substring(1);
            if (rParamName.endsWith(".raw")) {
                rParamName = rParamName.substring(0, rParamName.length() - 4);
                rParamCalibrated = false;
            }

            rParamRef = new ParameterInstanceRef(rParamCalibrated);
            cond = new Condition(OperatorType.fromSymbol(op), lParamRef, rParamRef);
        } else {
            rParamRef = null;
            if ((rValue.startsWith("\"") || rValue.startsWith("”")) &&
                    (rValue.endsWith("\"") || rValue.endsWith("”"))) {
                rValue = rValue.substring(1, rValue.length() - 1);
            } else if ("true".equalsIgnoreCase(rValue)) {
                rValue = BooleanDataType.DEFAULT_ONE_STRING_VALUE;
            } else if ("false".equalsIgnoreCase(rValue)) {
                rValue = BooleanDataType.DEFAULT_ZERO_STRING_VALUE;
            }
            cond = new Condition(OperatorType.fromSymbol(op), lParamRef, rValue);
        }

        if (rParamRef != null) {
            NameReference pref = prefFactory.getReference(rParamName);
            pref.addResolvedAction(nd -> {
                rParamRef.setParameter((Parameter) nd);
            });
        }

        NameReference pref = prefFactory.getReference(lParamName);
        pref.addResolvedAction(nd -> {
            lParamRef.setParameter((Parameter) nd);
            cond.validateValueType();
        });

        return cond;
    }

    public Comparison toComparison(String comparisonString) throws ParseException {
        comparisonString = comparisonString.trim();
        Matcher m = Pattern.compile("(.*?)(==|=|!=|<=|>=|<|>)(.*)").matcher(comparisonString);
        if (!m.matches()) {
            throw new ParseException("Cannot parse condition '" + comparisonString + "'", 0);
        }
        String pname = m.group(1).trim();
        boolean useCalibrated = true;
        int idx = pname.indexOf('.');
        if (idx != -1) {
            String t = pname.substring(idx + 1);
            if ("raw".equals(t)) {
                pname = pname.substring(0, idx);
                useCalibrated = false;
            } else {
                throw new ParseException("Cannot parse parameter for comparison '" + pname
                        + "'. Use parameterName or parameterName.raw", 0);
            }
        }

        String op = m.group(2);
        String value = m.group(3).trim();

        if ((value.startsWith("\"") || value.startsWith("”")) &&
                (value.endsWith("\"") || value.endsWith("”"))) {
            value = value.substring(1, value.length() - 1);
        } else if ("true".equalsIgnoreCase(value)) {
            value = BooleanDataType.DEFAULT_ONE_STRING_VALUE;
        } else if ("false".equalsIgnoreCase(value)) {
            value = BooleanDataType.DEFAULT_ZERO_STRING_VALUE;
        }
        if ("=".equals(op)) {
            op = "==";
        }

        OperatorType opType;
        try {
            opType = OperatorType.fromSymbol(op);
        } catch (IllegalArgumentException e) {
            throw new ParseException("Unknown operator '" + op + "'", 0);
        }

        final ParameterInstanceRef pInstRef = new ParameterInstanceRef(useCalibrated);
        final Comparison ucomp = new Comparison(pInstRef, value, opType);

        NameReference pref = prefFactory.getReference(pname);
        pref.addResolvedAction(nd -> {
            pInstRef.setParameter((Parameter) nd);
            ucomp.validateValueType();
        });

        return ucomp;
    }

    public interface ParameterReferenceFactory {
        NameReference getReference(String pname);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy