/* * 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.parser; import notaql.model.AttributeSpecification; import notaql.model.EvaluationException; import notaql.model.path.InputPath; import notaql.model.path.OutputPath; import notaql.model.vdata.*; import notaql.model.vdata.aggregation.*; import notaql.parser.antlr.NotaQL2BaseVisitor; import notaql.parser.antlr.NotaQL2Parser; import org.antlr.v4.runtime.misc.NotNull; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; /** * Created by thomas on 03.12.14. */ public class VDataVisitor extends NotaQL2BaseVisitor<VData> { private final TransformationParser transformationParser; public VDataVisitor(TransformationParser transformationParser) { this.transformationParser = transformationParser; } @Override public VData visitAbsoluteInputPathVData(@NotNull NotaQL2Parser.AbsoluteInputPathVDataContext ctx) { final InputPath inputPath = transformationParser.getInputPathVisitor().visit(ctx.absoluteInputPath()); return new InputVData(inputPath); } @Override public VData visitAtomVData(@NotNull NotaQL2Parser.AtomVDataContext ctx) { return new AtomVData(transformationParser.getAtomValueVisitor().visit(ctx.atom())); } @Override public VData visitBracedVData(@NotNull NotaQL2Parser.BracedVDataContext ctx) { return visit(ctx.vData()); } @Override public VData visitMultiplicatedVData(@NotNull NotaQL2Parser.MultiplicatedVDataContext ctx) { final VData left = visit(ctx.vData(0)); final VData right = visit(ctx.vData(1)); switch (ctx.op.getType()) { case NotaQL2Parser.STAR: return new ArithmeticVData(left, right, ArithmeticVData.Operation.MULTIPLY); case NotaQL2Parser.DIV: return new ArithmeticVData(left, right, ArithmeticVData.Operation.DIVIDE); } throw new EvaluationException("Unknown arithmetic operator: " + NotaQL2Parser.tokenNames[ctx.op.getType()]); } @Override public VData visitAddedVData(@NotNull NotaQL2Parser.AddedVDataContext ctx) { final VData left = visit(ctx.vData(0)); final VData right = visit(ctx.vData(1)); switch (ctx.op.getType()) { case NotaQL2Parser.PLUS: return new ArithmeticVData(left, right, ArithmeticVData.Operation.ADD); case NotaQL2Parser.MINUS: return new ArithmeticVData(left, right, ArithmeticVData.Operation.SUBTRACT); } throw new EvaluationException("Unknown arithmetic operator: " + NotaQL2Parser.tokenNames[ctx.op.getType()]); } @Override public VData visitAggregateVData(@NotNull NotaQL2Parser.AggregateVDataContext ctx) { final NotaQL2Parser.AggregationFunctionContext aggrCtx = ctx.aggregationFunction(); // TODO: could be more generic switch (aggrCtx.function.getType()) { case NotaQL2Parser.SUM: return new SumVData(visit(aggrCtx.vData())); case NotaQL2Parser.AVG: return new AvgVData(visit(aggrCtx.vData())); case NotaQL2Parser.MIN: return new ExtremumVData(visit(aggrCtx.vData()), ExtremumVData.Function.MIN); case NotaQL2Parser.MAX: return new ExtremumVData(visit(aggrCtx.vData()), ExtremumVData.Function.MAX); case NotaQL2Parser.COUNT: return new CountVData(); case NotaQL2Parser.IMPLODE: return new ImplodeVData(visit(aggrCtx.vData())); case NotaQL2Parser.LIST: return new ListVData(visit(aggrCtx.vData())); } throw new EvaluationException("Unknown aggregation function operator: " + NotaQL2Parser.tokenNames[aggrCtx.function.getType()]); } @Override public VData visitConstructorVData(@NotNull NotaQL2Parser.ConstructorVDataContext ctx) { return visit(ctx.constructorFunction()); } @Override public VData visitObjectConstructorFunction(@NotNull NotaQL2Parser.ObjectConstructorFunctionContext ctx) { final List<AttributeSpecification> specifications = new LinkedList<>(); for (NotaQL2Parser.AttributeSpecificationContext specificationCtx : ctx.attributeSpecification()) { final OutputPath outputPath = transformationParser.getOutputPathVisitor().visit(specificationCtx.genericOutputPath()); final VData vData = visit(specificationCtx.vData()); specifications.add(new AttributeSpecification(outputPath, vData)); } return new ObjectVData(specifications); } @Override public VData visitGenericConstructorFunction(@NotNull NotaQL2Parser.GenericConstructorFunctionContext ctx) { final ConstructorVData constructor = transformationParser.getOutEngineEvaluator().getConstructor(ctx.Name().getText()); if(constructor == null) throw new EvaluationException("Unknown constructor: " + ctx.Name().getText()); final List<AttributeSpecification> specifications = new LinkedList<>(); for (NotaQL2Parser.AttributeSpecificationContext specificationCtx : ctx.attributeSpecification()) { final OutputPath outputPath = transformationParser.getOutputPathVisitor().visit(specificationCtx.genericOutputPath()); final VData vData = visit(specificationCtx.vData()); specifications.add(new AttributeSpecification(outputPath, vData)); } constructor.init(specifications.toArray(new AttributeSpecification[specifications.size()])); return constructor; } @Override public VData visitGenericFunction(@NotNull NotaQL2Parser.GenericFunctionContext ctx) { // TODO: make the functions in the in and out engines pluggable as well; Also generify AVG, etc.. FunctionVData function = transformationParser.getInEngineEvaluator().getFunction(ctx.Name().getText()); if(function == null) function = transformationParser.getOutEngineEvaluator().getFunction(ctx.Name().getText()); final List<VData> vDatas = ctx.vData().stream().map(this::visit).collect(Collectors.toList()); final VData[] vDataArray = vDatas.toArray(new VData[vDatas.size()]); if(function != null) { function.init(vDataArray); return function; } return new GenericFunctionVData(ctx.Name().getText(), vDataArray); } @Override public VData visitRelativeInputPathVData(@NotNull NotaQL2Parser.RelativeInputPathVDataContext ctx) { final InputPath inputPath = transformationParser.getInputPathVisitor().visit(ctx.relativeInputPath()); return new InputVData(inputPath); } }