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

org.kie.dmn.validation.dtanalysis.DMNDTAnalyserValueFromNodeVisitor Maven / Gradle / Ivy

The newest version!
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.kie.dmn.validation.dtanalysis;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;

import org.kie.dmn.feel.lang.FEELProfile;
import org.kie.dmn.feel.lang.ast.ASTNode;
import org.kie.dmn.feel.lang.ast.BaseNode;
import org.kie.dmn.feel.lang.ast.BooleanNode;
import org.kie.dmn.feel.lang.ast.FunctionInvocationNode;
import org.kie.dmn.feel.lang.ast.NameRefNode;
import org.kie.dmn.feel.lang.ast.NumberNode;
import org.kie.dmn.feel.lang.ast.QualifiedNameNode;
import org.kie.dmn.feel.lang.ast.SignedUnaryNode;
import org.kie.dmn.feel.lang.ast.SignedUnaryNode.Sign;
import org.kie.dmn.feel.lang.ast.StringNode;
import org.kie.dmn.feel.lang.ast.visitor.DefaultedVisitor;
import org.kie.dmn.feel.lang.impl.FEELBuilder;
import org.kie.dmn.feel.lang.impl.FEELImpl;
import org.kie.dmn.feel.util.StringEvalHelper;
import org.kie.dmn.validation.dtanalysis.model.DDTAOutputEntryExpression;

import static org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames.DATE;
import static org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames.DATE_AND_TIME;
import static org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames.DURATION;
import static org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames.NUMBER;
import static org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames.STRING;
import static org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames.TIME;
import static org.kie.dmn.feel.runtime.functions.FEELConversionFunctionNames.YEARS_AND_MONTHS_DURATION;

public class DMNDTAnalyserValueFromNodeVisitor extends DefaultedVisitor> {

    private final FEELImpl FEEL;

    public DMNDTAnalyserValueFromNodeVisitor(List feelProfiles) {
        FEEL = (FEELImpl) FEELBuilder.builder().withProfiles(feelProfiles).build();
    }

    @Override
    public Comparable defaultVisit(ASTNode n) {
        throw new UnsupportedOperationException("Gaps/Overlaps analysis cannot be performed for InputEntry with unary test containing: " + n.getText());
    }
    
    @Override
    public Comparable visit(NameRefNode n) {
        throw new UnsupportedOperationException("Gaps/Overlaps analysis cannot be performed for InputEntry with unary test containing symbol reference: '" + n.getText() + "'."); // ref DROOLS-4607
    }

    @Override
    public Comparable visit(QualifiedNameNode n) {
        throw new UnsupportedOperationException("Gaps/Overlaps analysis cannot be performed for InputEntry with unary test containing symbol reference: '" + n.getText() + "'."); // ref DROOLS-4607
    }

    @Override
    public Boolean visit(BooleanNode n) {
        return n.getValue();
    }

    @Override
    public BigDecimal visit(NumberNode n) {
        return n.getValue();
    }

    @Override
    public String visit(StringNode n) {
        return StringEvalHelper.unescapeString(n.getText());
    }

    @Override
    public Comparable visit(SignedUnaryNode n) {
        BaseNode signedExpr = n.getExpression();
        if (signedExpr instanceof NumberNode) {
            BigDecimal valueFromNode = (BigDecimal) signedExpr.accept(this);
            if (n.getSign() == Sign.NEGATIVE) {
                return BigDecimal.valueOf(-1).multiply(valueFromNode);
            } else {
                return valueFromNode;
            }
        } else {
            return defaultVisit(n);
        }
    }

    @Override
    public Comparable visit(FunctionInvocationNode n) {
        if (n.accept(new SupportedConstantValueVisitor())) {
            return blankEvaluate(n);
        } else {
            return defaultVisit(n);
        }
    }
    
    public static class DMNDTAnalyserOutputClauseVisitor extends DMNDTAnalyserValueFromNodeVisitor {

        public DMNDTAnalyserOutputClauseVisitor(List feelProfiles) {
            super(feelProfiles);
        }

        @Override
        public Comparable defaultVisit(ASTNode n) {
            return new DDTAOutputEntryExpression(n);
        }
        
        @Override
        public Comparable visit(NameRefNode n) {
            return defaultVisit(n); // symbols allowed in output clause
        }

        @Override
        public Comparable visit(QualifiedNameNode n) {
            return defaultVisit(n); // symbols allowed in output clause
        }

    }

    protected static class SupportedConstantValueVisitor extends DefaultedVisitor {

        public boolean areAllSupported(List nodes) {
            return nodes.stream().allMatch(n -> n.accept(this));
        }

        @Override
        public Boolean defaultVisit(ASTNode n) {
            return false;
        }
        
        @Override
        public Boolean visit(BooleanNode n) {
            return true;
        }

        @Override
        public Boolean visit(NumberNode n) {
            return true;
        }

        @Override
        public Boolean visit(StringNode n) {
            return true;
        }

        @Override
        public Boolean visit(SignedUnaryNode n) {
            BaseNode signedExpr = n.getExpression();
            if (signedExpr instanceof NumberNode) {
                return true;
            } else {
                return defaultVisit(n);
            }
        }

        @Override
        public Boolean visit(FunctionInvocationNode n) {
            String fnName = null;
            if (n.getName() instanceof NameRefNode) {
                // simple name
                fnName = n.getName().getText();
            }
            if (fnName == null) {
                throw new IllegalStateException("Name of function is not instance of NameRefNode!" + n.toString());
            }
            List params = n.getParams().getElements();
            switch (fnName) {
                case DATE:
                    if (params.size() == 1 || params.size() == 3) {
                        return areAllSupported(params);
                    }
                    break;
                case DATE_AND_TIME:
                    if (params.size() == 2 || params.size() == 1) {
                        return areAllSupported(params);
                    }
                    break;
                case TIME:
                    if (params.size() == 1 || params.size() == 4) {
                        return areAllSupported(params);
                    }
                    break;
                case NUMBER:
                    if (params.size() == 3) {
                        return areAllSupported(params);
                    }
                    break;
                case STRING:
                case DURATION:
                    if (params.size() == 1) {
                        return areAllSupported(params);
                    }
                    break;
                case YEARS_AND_MONTHS_DURATION:
                    if (params.size() == 2) {
                        return areAllSupported(params);
                    }
                    break;
                default:
                    return false;
            }
            return false;
        }
    }

    private Comparable blankEvaluate(FunctionInvocationNode n) {
        return (Comparable) n.evaluate(FEEL.newEvaluationContext(Collections.emptyList(), Collections.emptyMap()));
    }
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy