/* * Copyright 2015 by Thomas Lottermann * * Licensed 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 notaql.evaluation; import notaql.datamodel.NullValue; import notaql.datamodel.NumberValue; import notaql.datamodel.Step; import notaql.datamodel.Value; import notaql.datamodel.fixation.Fixation; import notaql.evaluation.values.PartialArithmeticValue; import notaql.evaluation.values.PartialNullValue; import notaql.model.EvaluationException; import notaql.model.vdata.ArithmeticVData; import notaql.model.vdata.VData; import notaql.evaluation.values.ResolvingUtils; import java.util.Arrays; import java.util.LinkedList; import java.util.List; /** * Evaluates arithmetic expressions. */ public class ArithmeticVDataEvaluator implements Evaluator, Reducer { private static final long serialVersionUID = 7619497803530166986L; /** * In this execution the left and right value are evaluated for the current evaluation level. * In case the evaluation can be done completely (we retrieve fully resolved values), we can evaluate the operation. * In case some values are still unresolved: we need to return a temporary ArithmeticValue which can be evaluated * in the next step. * * @param vData * @param fixation * @return A list of evaluation results being either a PartialArithmeticValue or a completely resolved NumberValue */ @Override public List<ValueEvaluationResult> evaluate(VData vData, Fixation fixation) { assert vData instanceof ArithmeticVData; final ArithmeticVData arithmeticVData = (ArithmeticVData) vData; final List<ValueEvaluationResult> result = new LinkedList<>(); final List<ValueEvaluationResult> leftEval = EvaluatorService.getInstance().evaluate(arithmeticVData.getLeft(), fixation); for (ValueEvaluationResult leftResult : leftEval) { final List<ValueEvaluationResult> rightEval = EvaluatorService.getInstance().evaluate(arithmeticVData.getRight(), fixation); final Value leftValue = leftResult.getValue(); boolean leftUnresolved = ResolvingUtils.isUnresolved(leftValue); for (ValueEvaluationResult rightResult : rightEval) { final Value rightValue = rightResult.getValue(); if(leftUnresolved || ResolvingUtils.isUnresolved(rightValue)) { result.add( new ValueEvaluationResult( new PartialArithmeticValue(leftValue, rightValue) , rightResult.getFixation() ) ); continue; } final NumberValue calculation = arithmeticVData.calculate(leftValue, rightValue); result.add(new ValueEvaluationResult(calculation, rightResult.getFixation())); } } return result; } @Override public boolean canReduce(VData vData) { return true; } @Override public List<Class<? extends VData>> getProcessedClasses() { return Arrays.asList(ArithmeticVData.class); } @Override public Value reduce(VData vData, Value v1, Value v2) { assert vData instanceof ArithmeticVData; final ArithmeticVData arithmeticVData = (ArithmeticVData) vData; if(v1 instanceof NullValue && v2 instanceof NullValue) return createIdentity(vData); if(v1 instanceof NullValue) return v2; if(v2 instanceof NullValue) return v1; if(v1 instanceof NumberValue) return v1; if(v2 instanceof NumberValue) return v2; if(!(v1 instanceof PartialArithmeticValue && v2 instanceof PartialArithmeticValue)) throw new EvaluationException("Reduce on arithmetic VData, but no ArithmeticValue given."); final PartialArithmeticValue pv1 = (PartialArithmeticValue) v1; final PartialArithmeticValue pv2 = (PartialArithmeticValue) v2; Value pv1l = pv1.get(new Step<>(PartialArithmeticValue.Position.LEFT)); Value pv1r = pv1.get(new Step<>(PartialArithmeticValue.Position.RIGHT)); Value pv2l = pv2.get(new Step<>(PartialArithmeticValue.Position.LEFT)); Value pv2r = pv2.get(new Step<>(PartialArithmeticValue.Position.RIGHT)); if(ResolvingUtils.isUnresolved(pv1l)) { assert ResolvingUtils.isUnresolved(pv2l); assert !ResolvingUtils.isUnresolved(pv1r); assert !ResolvingUtils.isUnresolved(pv2r); assert pv1r.equals(pv2r); return new PartialArithmeticValue(EvaluatorService.getInstance().reduce(arithmeticVData.getLeft(), pv1l, pv2l), pv1r); } assert ResolvingUtils.isUnresolved(pv1r); assert ResolvingUtils.isUnresolved(pv2r); assert !ResolvingUtils.isUnresolved(pv2l); assert pv1l.equals(pv2l); return new PartialArithmeticValue(pv1l, EvaluatorService.getInstance().reduce(arithmeticVData.getRight(), pv1r, pv2r)); } @Override public Value createIdentity(VData vData) { return new PartialNullValue(); } @Override public Value finalize(VData vData, Value value) { assert vData instanceof ArithmeticVData; final ArithmeticVData arithmeticVData = (ArithmeticVData) vData; if(value instanceof NumberValue) return value; assert value instanceof PartialArithmeticValue; final PartialArithmeticValue pv = (PartialArithmeticValue) value; return arithmeticVData.calculate( pv.get(new Step<>(PartialArithmeticValue.Position.LEFT)), pv.get(new Step<>(PartialArithmeticValue.Position.RIGHT)) ); } }