// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.indexinglanguage.expressions; import com.yahoo.document.DataType; import com.yahoo.language.Linguistics; import com.yahoo.language.process.Embedder; import com.yahoo.language.simple.SimpleLinguistics; import com.yahoo.vespa.indexinglanguage.ScriptParser; import com.yahoo.vespa.indexinglanguage.ScriptParserContext; import com.yahoo.vespa.indexinglanguage.parser.IndexingInput; import com.yahoo.vespa.indexinglanguage.parser.ParseException; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @author Simon Thoresen Hult */ public final class StatementExpression extends ExpressionList { /** The names of the fields consumed by this. */ private final List inputFields; /** The name of the (last) output field this statement will write to, or null if none */ private String outputField; public StatementExpression(Expression... lst) { this(Arrays.asList(lst)); } public StatementExpression(Iterable lst) { this(filterList(lst), null); } private StatementExpression(Iterable list, Object unused) { super(list, resolveInputType(list)); inputFields = List.copyOf(InputExpression.InputFieldNameExtractor.runOn(this)); } /** Returns the input fields which are (perhaps optionally) consumed by some expression in this statement. */ public List getInputFields() { return inputFields; } @Override protected void doExecute(ExecutionContext context) { for (Expression expression : this) { context.execute(expression); } } @Override protected void doVerify(VerificationContext context) { for (Expression expression : this) { if (expression instanceof OutputExpression) outputField = ((OutputExpression)expression).getFieldName(); } if (outputField != null) context.setOutputField(outputField); for (Expression expression : this) context.execute(expression); } private static DataType resolveInputType(Iterable lst) { for (Expression exp : lst) { DataType type = exp.requiredInputType(); if (type != null) return type; type = exp.createdOutputType(); if (type != null) return null; } return null; } @Override public DataType createdOutputType() { for (int i = size(); --i >= 0; ) { DataType type = get(i).createdOutputType(); if (type != null) return type; } return null; } @Override public String toString() { return asList().stream().map(Expression::toString).collect(Collectors.joining(" | ")); } @Override public boolean equals(Object obj) { return super.equals(obj) && obj instanceof StatementExpression; } /** Creates an expression with simple lingustics for testing */ public static StatementExpression fromString(String expression) throws ParseException { return fromString(expression, new SimpleLinguistics(), Embedder.throwsOnUse.asMap()); } public static StatementExpression fromString(String expression, Linguistics linguistics, Map embedders) throws ParseException { return newInstance(new ScriptParserContext(linguistics, embedders).setInputStream(new IndexingInput(expression))); } public static StatementExpression newInstance(ScriptParserContext config) throws ParseException { return ScriptParser.parseStatement(config); } private static List filterList(Iterable lst) { List ret = new LinkedList<>(); for (Expression exp : lst) { if (exp instanceof StatementExpression) { ret.addAll(filterList((StatementExpression)exp)); } else if (exp != null) { ret.add(exp); } } return ret; } }