| /* |
| * 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.apache.sysds.parser.dml; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Map.Entry; |
| import java.util.regex.Pattern; |
| import java.util.stream.Collectors; |
| |
| import org.antlr.v4.runtime.ParserRuleContext; |
| import org.antlr.v4.runtime.Token; |
| import org.antlr.v4.runtime.tree.ErrorNode; |
| import org.antlr.v4.runtime.tree.TerminalNode; |
| import org.apache.sysds.api.DMLScript; |
| import org.apache.sysds.common.Builtins; |
| import org.apache.sysds.common.Types.DataType; |
| import org.apache.sysds.common.Types.ValueType; |
| import org.apache.sysds.conf.ConfigurationManager; |
| import org.apache.sysds.conf.CompilerConfig.ConfigType; |
| import org.apache.sysds.parser.AssignmentStatement; |
| import org.apache.sysds.parser.BinaryExpression; |
| import org.apache.sysds.parser.BooleanExpression; |
| import org.apache.sysds.parser.BooleanIdentifier; |
| import org.apache.sysds.parser.BuiltinConstant; |
| import org.apache.sysds.parser.BuiltinFunctionExpression; |
| import org.apache.sysds.parser.ConditionalPredicate; |
| import org.apache.sysds.parser.ConstIdentifier; |
| import org.apache.sysds.parser.DMLProgram; |
| import org.apache.sysds.parser.DataExpression; |
| import org.apache.sysds.parser.DataIdentifier; |
| import org.apache.sysds.parser.DoubleIdentifier; |
| import org.apache.sysds.parser.Expression; |
| import org.apache.sysds.parser.ExpressionList; |
| import org.apache.sysds.parser.ForStatement; |
| import org.apache.sysds.parser.FunctionCallIdentifier; |
| import org.apache.sysds.parser.FunctionDictionary; |
| import org.apache.sysds.parser.FunctionStatement; |
| import org.apache.sysds.parser.FunctionStatementBlock; |
| import org.apache.sysds.parser.IfStatement; |
| import org.apache.sysds.parser.ImportStatement; |
| import org.apache.sysds.parser.IndexedIdentifier; |
| import org.apache.sysds.parser.IntIdentifier; |
| import org.apache.sysds.parser.IterablePredicate; |
| import org.apache.sysds.parser.LanguageException; |
| import org.apache.sysds.parser.MultiAssignmentStatement; |
| import org.apache.sysds.parser.OutputStatement; |
| import org.apache.sysds.parser.ParForStatement; |
| import org.apache.sysds.parser.ParameterExpression; |
| import org.apache.sysds.parser.ParameterizedBuiltinFunctionExpression; |
| import org.apache.sysds.parser.ParseException; |
| import org.apache.sysds.parser.ParserWrapper; |
| import org.apache.sysds.parser.PathStatement; |
| import org.apache.sysds.parser.PrintStatement; |
| import org.apache.sysds.parser.RelationalExpression; |
| import org.apache.sysds.parser.Statement; |
| import org.apache.sysds.parser.StatementBlock; |
| import org.apache.sysds.parser.StringIdentifier; |
| import org.apache.sysds.parser.WhileStatement; |
| import org.apache.sysds.parser.Expression.DataOp; |
| import org.apache.sysds.parser.dml.DmlParser.AccumulatorAssignmentStatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.AddSubExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.AssignmentStatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.AtomicExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.BooleanAndExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.BooleanNotExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.BooleanOrExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.BuiltinFunctionExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.CommandlineParamExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.CommandlinePositionExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.ConstDoubleIdExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.ConstFalseExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.ConstIntIdExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.ConstStringIdExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.ConstTrueExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.DataIdExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.DataIdentifierContext; |
| import org.apache.sysds.parser.dml.DmlParser.ExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.ExternalFunctionDefExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.ForStatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.FunctionCallAssignmentStatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.FunctionCallMultiAssignmentStatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.FunctionStatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.IfStatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.IfdefAssignmentStatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.ImportStatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.IndexedExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.InternalFunctionDefExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.IterablePredicateColonExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.IterablePredicateSeqExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.MatrixDataTypeCheckContext; |
| import org.apache.sysds.parser.dml.DmlParser.MatrixMulExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.Ml_typeContext; |
| import org.apache.sysds.parser.dml.DmlParser.ModIntDivExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.MultDivExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.MultiIdExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.ParForStatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.ParameterizedExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.PathStatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.PowerExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.ProgramrootContext; |
| import org.apache.sysds.parser.dml.DmlParser.RelationalExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.SimpleDataIdentifierExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.StatementContext; |
| import org.apache.sysds.parser.dml.DmlParser.StrictParameterizedExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.StrictParameterizedKeyValueStringContext; |
| import org.apache.sysds.parser.dml.DmlParser.TypedArgAssignContext; |
| import org.apache.sysds.parser.dml.DmlParser.TypedArgNoAssignContext; |
| import org.apache.sysds.parser.dml.DmlParser.UnaryExpressionContext; |
| import org.apache.sysds.parser.dml.DmlParser.ValueTypeContext; |
| import org.apache.sysds.parser.dml.DmlParser.WhileStatementContext; |
| import org.apache.sysds.runtime.DMLRuntimeException; |
| import org.apache.sysds.runtime.util.UtilFunctions; |
| |
| public class DmlSyntacticValidator implements DmlListener { |
| |
| private static final String DEF_WORK_DIR = "."; |
| |
| //externally loaded dml scripts filename (unmodified) / script |
| protected static ThreadLocal<HashMap<String, String>> _tScripts = new ThreadLocal<HashMap<String, String>>() { |
| @Override protected HashMap<String, String> initialValue() { return new HashMap<>(); } |
| }; |
| //imported scripts to prevent infinite recursion, modified filename / namespace |
| protected static ThreadLocal<HashMap<String, String>> _f2NS = new ThreadLocal<HashMap<String, String>>() { |
| @Override protected HashMap<String, String> initialValue() { return new HashMap<>(); } |
| }; |
| |
| protected final CustomErrorListener errorListener; |
| protected final String currentFile; |
| protected String _workingDir = DEF_WORK_DIR; |
| protected Map<String,String> argVals = null; |
| protected String sourceNamespace = null; |
| // Map namespaces to full paths as defined only from source statements in this script (i.e., currentFile) |
| protected HashMap<String, String> sources; |
| // Names of new internal and external functions defined in this script (i.e., currentFile) |
| protected Set<String> functions; |
| // DML-bodied builtin functions |
| protected FunctionDictionary<FunctionStatementBlock> builtinFuns; |
| |
| public DmlSyntacticValidator(CustomErrorListener errorListener, Map<String,String> argVals, String sourceNamespace, Set<String> prepFunctions) { |
| this.errorListener = errorListener; |
| currentFile = errorListener.getCurrentFileName(); |
| this.argVals = argVals; |
| this.sourceNamespace = sourceNamespace; |
| sources = new HashMap<>(); |
| functions = (null != prepFunctions) ? prepFunctions : new HashSet<>(); |
| builtinFuns = new FunctionDictionary<>(); |
| } |
| |
| |
| /** |
| * Obtain the namespace separator ({@code ::} for DML |
| * that is used to specify a namespace and a function in that namespace. |
| * |
| * @return The namespace separator |
| */ |
| public String namespaceResolutionOp() { |
| return "::"; |
| } |
| |
| public String trueStringLiteral() { |
| return "TRUE"; |
| } |
| public String falseStringLiteral() { |
| return "FALSE"; |
| } |
| |
| protected ArrayList<ParameterExpression> getParameterExpressionList(List<ParameterizedExpressionContext> paramExprs) { |
| ArrayList<ParameterExpression> retVal = new ArrayList<>(); |
| for(ParameterizedExpressionContext ctx : paramExprs) { |
| String paramName = null; |
| if(ctx.paramName != null && ctx.paramName.getText() != null && !ctx.paramName.getText().isEmpty()) { |
| paramName = ctx.paramName.getText(); |
| } |
| ParameterExpression myArg = new ParameterExpression(paramName, ctx.paramVal.info.expr); |
| retVal.add(myArg); |
| } |
| return retVal; |
| } |
| |
| @Override |
| public void enterEveryRule(ParserRuleContext arg0) { |
| if(arg0 instanceof StatementContext) { |
| if(((StatementContext) arg0).info == null) { |
| ((StatementContext) arg0).info = new StatementInfo(); |
| } |
| } |
| if(arg0 instanceof FunctionStatementContext) { |
| if(((FunctionStatementContext) arg0).info == null) { |
| ((FunctionStatementContext) arg0).info = new StatementInfo(); |
| } |
| } |
| if(arg0 instanceof ExpressionContext) { |
| if(((ExpressionContext) arg0).info == null) { |
| ((ExpressionContext) arg0).info = new ExpressionInfo(); |
| } |
| } |
| if(arg0 instanceof DataIdentifierContext) { |
| if(((DataIdentifierContext) arg0).dataInfo == null) { |
| ((DataIdentifierContext) arg0).dataInfo = new ExpressionInfo(); |
| } |
| } |
| } |
| |
| // ----------------------------------------------------------------- |
| // Binary, Unary & Relational Expressions |
| // ----------------------------------------------------------------- |
| |
| // For now do no type checking, let validation handle it. |
| // This way parser doesn't have to open metadata file |
| @Override |
| public void exitAddSubExpression(AddSubExpressionContext ctx) { |
| binaryExpressionHelper(ctx, ctx.left.info, ctx.right.info, ctx.info, ctx.op.getText()); |
| } |
| |
| @Override |
| public void exitModIntDivExpression(ModIntDivExpressionContext ctx) { |
| binaryExpressionHelper(ctx, ctx.left.info, ctx.right.info, ctx.info, ctx.op.getText()); |
| } |
| |
| @Override |
| public void exitUnaryExpression(UnaryExpressionContext ctx) { |
| unaryExpressionHelper(ctx, ctx.left.info, ctx.info, ctx.op.getText()); |
| } |
| |
| @Override |
| public void exitMultDivExpression(MultDivExpressionContext ctx) { |
| binaryExpressionHelper(ctx, ctx.left.info, ctx.right.info, ctx.info, ctx.op.getText()); |
| } |
| @Override |
| public void exitPowerExpression(PowerExpressionContext ctx) { |
| binaryExpressionHelper(ctx, ctx.left.info, ctx.right.info, ctx.info, ctx.op.getText()); |
| } |
| |
| @Override |
| public void exitMatrixMulExpression(MatrixMulExpressionContext ctx) { |
| binaryExpressionHelper(ctx, ctx.left.info, ctx.right.info, ctx.info, ctx.op.getText()); |
| } |
| |
| @Override |
| public void exitRelationalExpression(RelationalExpressionContext ctx) { |
| relationalExpressionHelper(ctx, ctx.left.info, ctx.right.info, ctx.info, ctx.op.getText()); |
| } |
| |
| @Override |
| public void exitBooleanAndExpression(BooleanAndExpressionContext ctx) { |
| booleanExpressionHelper(ctx, ctx.left.info, ctx.right.info, ctx.info, ctx.op.getText()); |
| } |
| |
| @Override |
| public void exitBooleanOrExpression(BooleanOrExpressionContext ctx) { |
| booleanExpressionHelper(ctx, ctx.left.info, ctx.right.info, ctx.info, ctx.op.getText()); |
| } |
| |
| @Override |
| public void exitBooleanNotExpression(BooleanNotExpressionContext ctx) { |
| unaryBooleanExpressionHelper(ctx, ctx.left.info, ctx.info, ctx.op.getText()); |
| } |
| |
| @Override |
| public void exitAtomicExpression(AtomicExpressionContext ctx) { |
| ctx.info.expr = ctx.left.info.expr; |
| setFileLineColumn(ctx.info.expr, ctx); |
| } |
| |
| // ----------------------------------------------------------------- |
| // Constant Expressions |
| // ----------------------------------------------------------------- |
| |
| @Override |
| public void exitConstFalseExpression(ConstFalseExpressionContext ctx) { |
| booleanIdentifierHelper(ctx, false, ctx.info); |
| } |
| |
| @Override |
| public void exitConstTrueExpression(ConstTrueExpressionContext ctx) { |
| booleanIdentifierHelper(ctx, true, ctx.info); |
| } |
| |
| @Override |
| public void exitConstDoubleIdExpression(ConstDoubleIdExpressionContext ctx) { |
| constDoubleIdExpressionHelper(ctx, ctx.info); |
| } |
| |
| @Override |
| public void exitConstIntIdExpression(ConstIntIdExpressionContext ctx) { |
| constIntIdExpressionHelper(ctx, ctx.info); |
| } |
| |
| @Override |
| public void exitConstStringIdExpression(ConstStringIdExpressionContext ctx) { |
| constStringIdExpressionHelper(ctx, ctx.info); |
| } |
| |
| |
| // ----------------------------------------------------------------- |
| // Identifier Based Expressions |
| // ----------------------------------------------------------------- |
| |
| @Override |
| public void exitDataIdExpression(DataIdExpressionContext ctx) { |
| exitDataIdExpressionHelper(ctx, ctx.info, ctx.dataIdentifier().dataInfo); |
| } |
| |
| @Override |
| public void exitSimpleDataIdentifierExpression(SimpleDataIdentifierExpressionContext ctx) { |
| // This is either a function, or variable with namespace |
| // By default, it assigns to a data type |
| ctx.dataInfo.expr = new DataIdentifier(ctx.getText()); |
| setFileLineColumn(ctx.dataInfo.expr, ctx); |
| } |
| |
| /** |
| * DML uses 1-based indexing.; |
| * |
| * @param ctx the parse tree |
| */ |
| @Override |
| public void exitIndexedExpression(IndexedExpressionContext ctx) { |
| boolean isRowLower = (ctx.rowLower != null && !ctx.rowLower.isEmpty() && (ctx.rowLower.info.expr != null)); |
| boolean isRowUpper = (ctx.rowUpper != null && !ctx.rowUpper.isEmpty() && (ctx.rowUpper.info.expr != null)); |
| boolean isColLower = (ctx.colLower != null && !ctx.colLower.isEmpty() && (ctx.colLower.info.expr != null)); |
| boolean isColUpper = (ctx.colUpper != null && !ctx.colUpper.isEmpty() && (ctx.colUpper.info.expr != null)); |
| ExpressionInfo rowLower = isRowLower ? ctx.rowLower.info : null; |
| ExpressionInfo rowUpper = isRowUpper ? ctx.rowUpper.info : null; |
| ExpressionInfo colLower = isColLower ? ctx.colLower.info : null; |
| ExpressionInfo colUpper = isColUpper ? ctx.colUpper.info : null; |
| |
| ctx.dataInfo.expr = new IndexedIdentifier(ctx.name.getText(), false, false); |
| setFileLineColumn(ctx.dataInfo.expr, ctx); |
| |
| try { |
| ArrayList< ArrayList<Expression> > exprList = new ArrayList<>(); |
| |
| ArrayList<Expression> rowIndices = new ArrayList<>(); |
| ArrayList<Expression> colIndices = new ArrayList<>(); |
| |
| |
| if(!isRowLower && !isRowUpper) { |
| // both not set |
| rowIndices.add(null); rowIndices.add(null); |
| } |
| else if(isRowLower && isRowUpper) { |
| // both set |
| rowIndices.add(rowLower.expr); |
| rowIndices.add(rowUpper.expr); |
| } |
| else if(isRowLower && !isRowUpper) { |
| // only row set |
| rowIndices.add(rowLower.expr); |
| } |
| else { |
| notifyErrorListeners("incorrect index expression for row", ctx.start); |
| return; |
| } |
| |
| if(!isColLower && !isColUpper) { |
| // both not set |
| colIndices.add(null); colIndices.add(null); |
| } |
| else if(isColLower && isColUpper) { |
| colIndices.add(colLower.expr); |
| colIndices.add(colUpper.expr); |
| } |
| else if(isColLower && !isColUpper) { |
| colIndices.add(colLower.expr); |
| } |
| else { |
| notifyErrorListeners("incorrect index expression for column", ctx.start); |
| return; |
| } |
| exprList.add(rowIndices); |
| exprList.add(colIndices); |
| ((IndexedIdentifier) ctx.dataInfo.expr).setIndices(exprList); |
| } |
| catch(Exception e) { |
| notifyErrorListeners("cannot set the indices", ctx.start); |
| return; |
| } |
| } |
| |
| |
| // ----------------------------------------------------------------- |
| // Command line parameters (begin with a '$') |
| // ----------------------------------------------------------------- |
| |
| @Override |
| public void exitCommandlineParamExpression(CommandlineParamExpressionContext ctx) { |
| handleCommandlineArgumentExpression(ctx); |
| } |
| |
| @Override |
| public void exitCommandlinePositionExpression(CommandlinePositionExpressionContext ctx) { |
| handleCommandlineArgumentExpression(ctx); |
| } |
| |
| private void handleCommandlineArgumentExpression(DataIdentifierContext ctx) |
| { |
| String varName = ctx.getText().trim(); |
| fillExpressionInfoCommandLineParameters(ctx, varName, ctx.dataInfo); |
| |
| if(ctx.dataInfo.expr == null) { |
| if(!(ctx.parent instanceof IfdefAssignmentStatementContext)) { |
| String msg = "The parameter " + varName + " either needs to be passed " |
| + "through commandline or initialized to default value."; |
| if( ConfigurationManager.getCompilerConfigFlag(ConfigType.IGNORE_UNSPECIFIED_ARGS) ) { |
| ctx.dataInfo.expr = getConstIdFromString(ctx, " "); |
| if (!ConfigurationManager.getCompilerConfigFlag(ConfigType.MLCONTEXT)) { |
| raiseWarning(msg, ctx.start); |
| } |
| } |
| else { |
| notifyErrorListeners(msg, ctx.start); |
| } |
| } |
| } |
| } |
| |
| |
| // ----------------------------------------------------------------- |
| // "source" statement |
| // ----------------------------------------------------------------- |
| |
| @Override |
| public void exitImportStatement(ImportStatementContext ctx) { |
| String filePath = getWorkingFilePath(UtilFunctions.unquote(ctx.filePath.getText())); |
| String namespace = getNamespaceSafe(ctx.namespace); |
| setupContextInfo(ctx.info, namespace, filePath, ctx.filePath.getText(), |
| parseAndAddImportedFunctions(namespace, filePath, ctx)); |
| } |
| |
| // ----------------------------------------------------------------- |
| // Assignment Statement |
| // ----------------------------------------------------------------- |
| |
| @Override |
| public void exitAssignmentStatement(AssignmentStatementContext ctx) { |
| if(ctx.targetList == null) { |
| notifyErrorListeners("incorrect parsing for assignment", ctx.start); |
| return; |
| } |
| exitAssignmentStatementHelper(ctx, ctx.targetList.getText(), ctx.targetList.dataInfo, ctx.targetList.start, ctx.source.info, ctx.info); |
| } |
| |
| |
| // ----------------------------------------------------------------- |
| // Control Statements - Guards & Loops |
| // ----------------------------------------------------------------- |
| |
| public ConvertedDMLSyntax convertToDMLSyntax(ParserRuleContext ctx, String namespace, String functionName, ArrayList<ParameterExpression> paramExpression, Token fnName) { |
| return new ConvertedDMLSyntax(namespace, functionName, paramExpression); |
| } |
| |
| protected Expression handleLanguageSpecificFunction(ParserRuleContext ctx, String functionName, |
| ArrayList<ParameterExpression> paramExpressions) { |
| return null; |
| } |
| |
| |
| @Override |
| public void exitFunctionCallAssignmentStatement(FunctionCallAssignmentStatementContext ctx) { |
| |
| Set<String> printStatements = new HashSet<>(); |
| printStatements.add("print"); |
| printStatements.add("stop"); |
| printStatements.add("assert"); |
| |
| Set<String> outputStatements = new HashSet<>(); |
| outputStatements.add("write"); |
| |
| String [] fnNames = getQualifiedNames (ctx.name.getText()); |
| if (fnNames == null) { |
| String errorMsg = "incorrect function name (only namespace " + namespaceResolutionOp() + " functionName allowed. Hint: If you are trying to use builtin functions, you can skip the namespace)"; |
| notifyErrorListeners(errorMsg, ctx.name); |
| return; |
| } |
| String namespace = fnNames[0]; |
| String functionName = fnNames[1]; |
| ArrayList<ParameterExpression> paramExpression = getParameterExpressionList(ctx.paramExprs); |
| |
| castAsScalarDeprecationCheck(functionName, ctx); |
| |
| boolean hasLHS = ctx.targetList != null; |
| functionCallAssignmentStatementHelper(ctx, printStatements, outputStatements, hasLHS ? ctx.targetList.dataInfo.expr : null, ctx.info, ctx.name, |
| hasLHS ? ctx.targetList.start : null, namespace, functionName, paramExpression, hasLHS); |
| } |
| |
| // TODO: remove this when castAsScalar has been removed from DML/PYDML |
| private void castAsScalarDeprecationCheck(String functionName, ParserRuleContext ctx) { |
| if ("castAsScalar".equalsIgnoreCase(functionName)) { |
| raiseWarning("castAsScalar() has been deprecated. Please use as.scalar().", ctx.start); |
| } |
| } |
| |
| @Override |
| public void exitBuiltinFunctionExpression(BuiltinFunctionExpressionContext ctx) { |
| // Double verification: verify passed function name is a (non-parameterized) built-in function. |
| String[] names = getQualifiedNames(ctx.name.getText()); |
| if(names == null) { |
| notifyErrorListeners("incorrect function name (only namespace " + namespaceResolutionOp() + " functionName allowed. Hint: If you are trying to use builtin functions, you can skip the namespace)", ctx.name); |
| return; |
| } |
| String namespace = names[0]; |
| String functionName = names[1]; |
| |
| ArrayList<ParameterExpression> paramExpression = getParameterExpressionList(ctx.paramExprs); |
| castAsScalarDeprecationCheck(functionName, ctx); |
| |
| ConvertedDMLSyntax convertedSyntax = convertToDMLSyntax(ctx, namespace, functionName, paramExpression, ctx.name); |
| if(convertedSyntax == null) { |
| return; |
| } |
| else { |
| functionName = convertedSyntax.functionName; |
| paramExpression = convertedSyntax.paramExpression; |
| } |
| |
| // handle built-in functions |
| ctx.info.expr = buildForBuiltInFunction(ctx, functionName, paramExpression); |
| if( ctx.info.expr != null ) |
| return; |
| |
| // handle user-defined functions |
| ctx.info.expr = createFunctionCall(ctx, namespace, functionName, paramExpression); |
| } |
| |
| |
| @Override |
| public void exitFunctionCallMultiAssignmentStatement( |
| FunctionCallMultiAssignmentStatementContext ctx) { |
| String[] names = getQualifiedNames(ctx.name.getText()); |
| if(names == null) { |
| notifyErrorListeners("incorrect function name (only namespace.functionName allowed. Hint: If you are trying to use builtin functions, you can skip the namespace)", ctx.name); |
| return; |
| } |
| String namespace = names[0]; |
| String functionName = names[1]; |
| |
| ArrayList<ParameterExpression> paramExpression = getParameterExpressionList(ctx.paramExprs); |
| ConvertedDMLSyntax convertedSyntax = convertToDMLSyntax(ctx, namespace, functionName, paramExpression, ctx.name); |
| if(convertedSyntax == null) { |
| return; |
| } |
| else { |
| namespace = convertedSyntax.namespace; |
| functionName = convertedSyntax.functionName; |
| paramExpression = convertedSyntax.paramExpression; |
| } |
| |
| FunctionCallIdentifier functCall = new FunctionCallIdentifier(paramExpression); |
| functCall.setFunctionName(functionName); |
| functCall.setFunctionNamespace(namespace); |
| |
| final ArrayList<DataIdentifier> targetList = new ArrayList<>(); |
| for(DataIdentifierContext dataCtx : ctx.targetList) { |
| if(dataCtx.dataInfo.expr instanceof DataIdentifier) { |
| targetList.add((DataIdentifier) dataCtx.dataInfo.expr); |
| } |
| else { |
| notifyErrorListeners("incorrect type for variable ", dataCtx.start); |
| return; |
| } |
| } |
| |
| if(namespace.equals(DMLProgram.DEFAULT_NAMESPACE)) { |
| Expression e = buildForBuiltInFunction(ctx, functionName, paramExpression); |
| if( e != null ) { |
| setMultiAssignmentStatement(targetList, e, ctx, ctx.info); |
| return; |
| } |
| handleDMLBodiedBuiltinFunction(functionName, namespace, ctx); |
| } |
| |
| // Override default namespace for imported non-built-in function |
| String inferNamespace = (sourceNamespace != null && sourceNamespace.length() > 0 && DMLProgram.DEFAULT_NAMESPACE.equals(namespace)) ? sourceNamespace : namespace; |
| functCall.setFunctionNamespace(inferNamespace); |
| |
| setMultiAssignmentStatement(targetList, functCall, ctx, ctx.info); |
| } |
| |
| private void handleDMLBodiedBuiltinFunction(String functionName, String namespace, ParserRuleContext ctx) { |
| if( Builtins.contains(functionName, true, false) ) { |
| //load and add builtin DML-bodied functions |
| String filePath = Builtins.getFilePath(functionName); |
| FunctionDictionary<FunctionStatementBlock> prog = |
| parseAndAddImportedFunctions(namespace, filePath, ctx).getDefaultFunctionDictionary(); |
| if( prog != null ) //robustness for existing functions |
| for( Entry<String,FunctionStatementBlock> f : prog.getFunctions().entrySet() ) |
| builtinFuns.addFunction(f.getKey(), f.getValue()); |
| } |
| } |
| |
| public static Map<String,FunctionStatementBlock> loadAndParseBuiltinFunction(String name, String namespace) { |
| if( !Builtins.contains(name, true, false) ) { |
| throw new DMLRuntimeException("Function " |
| + DMLProgram.constructFunctionKey(namespace, name)+" is not a builtin function."); |
| } |
| //load and add builtin DML-bodied functions (via tmp validator instance) |
| //including nested builtin function calls unless already loaded |
| DmlSyntacticValidator tmp = new DmlSyntacticValidator( |
| new CustomErrorListener(), new HashMap<>(), namespace, new HashSet<>()); |
| String filePath = Builtins.getFilePath(name); |
| FunctionDictionary<FunctionStatementBlock> dict = tmp |
| .parseAndAddImportedFunctions(namespace, filePath, null) |
| .getDefaultFunctionDictionary(); |
| |
| //construct output map of all functions |
| return dict.getFunctions(); |
| } |
| |
| |
| // ----------------------------------------------------------------- |
| // Control Statements - Guards & Loops |
| // ----------------------------------------------------------------- |
| |
| private static StatementBlock getStatementBlock(Statement current) { |
| return ParserWrapper.getStatementBlock(current); |
| } |
| |
| @Override |
| public void exitIfStatement(IfStatementContext ctx) { |
| IfStatement ifStmt = new IfStatement(); |
| ConditionalPredicate predicate = new ConditionalPredicate(ctx.predicate.info.expr); |
| ifStmt.setConditionalPredicate(predicate); |
| ifStmt.setCtxValuesAndFilename(ctx, currentFile); |
| |
| if(ctx.ifBody.size() > 0) { |
| for(StatementContext stmtCtx : ctx.ifBody) |
| ifStmt.addStatementBlockIfBody(getStatementBlock(stmtCtx.info.stmt)); |
| ifStmt.mergeStatementBlocksIfBody(); |
| } |
| |
| if(ctx.elseBody.size() > 0) { |
| for(StatementContext stmtCtx : ctx.elseBody) |
| ifStmt.addStatementBlockElseBody(getStatementBlock(stmtCtx.info.stmt)); |
| ifStmt.mergeStatementBlocksElseBody(); |
| } |
| |
| ctx.info.stmt = ifStmt; |
| setFileLineColumn(ctx.info.stmt, ctx); |
| } |
| |
| @Override |
| public void exitWhileStatement(WhileStatementContext ctx) { |
| WhileStatement whileStmt = new WhileStatement(); |
| ConditionalPredicate predicate = new ConditionalPredicate(ctx.predicate.info.expr); |
| whileStmt.setPredicate(predicate); |
| whileStmt.setCtxValuesAndFilename(ctx, currentFile); |
| |
| if(ctx.body.size() > 0) { |
| for(StatementContext stmtCtx : ctx.body) |
| whileStmt.addStatementBlock(getStatementBlock(stmtCtx.info.stmt)); |
| whileStmt.mergeStatementBlocks(); |
| } |
| |
| ctx.info.stmt = whileStmt; |
| setFileLineColumn(ctx.info.stmt, ctx); |
| } |
| |
| @Override |
| public void exitForStatement(ForStatementContext ctx) { |
| ForStatement forStmt = new ForStatement(); |
| |
| DataIdentifier iterVar = new DataIdentifier(ctx.iterVar.getText()); |
| HashMap<String, String> parForParamValues = null; |
| Expression incrementExpr = null; //1/-1 |
| if(ctx.iterPred.info.increment != null) { |
| incrementExpr = ctx.iterPred.info.increment; |
| } |
| IterablePredicate predicate = new IterablePredicate(ctx, iterVar, ctx.iterPred.info.from, ctx.iterPred.info.to, |
| incrementExpr, parForParamValues, currentFile); |
| forStmt.setPredicate(predicate); |
| |
| if(ctx.body.size() > 0) { |
| for(StatementContext stmtCtx : ctx.body) |
| forStmt.addStatementBlock(getStatementBlock(stmtCtx.info.stmt)); |
| forStmt.mergeStatementBlocks(); |
| } |
| ctx.info.stmt = forStmt; |
| } |
| |
| @Override |
| public void exitParForStatement(ParForStatementContext ctx) { |
| ParForStatement parForStmt = new ParForStatement(); |
| |
| DataIdentifier iterVar = new DataIdentifier(ctx.iterVar.getText()); |
| HashMap<String, String> parForParamValues = new HashMap<>(); |
| if(ctx.parForParams != null && ctx.parForParams.size() > 0) { |
| for(StrictParameterizedExpressionContext parForParamCtx : ctx.parForParams) { |
| String paramVal = parForParamCtx.paramVal.getText(); |
| if( argVals.containsKey(paramVal) ) |
| paramVal = argVals.get(paramVal); |
| parForParamValues.put(parForParamCtx.paramName.getText(), paramVal); |
| } |
| } |
| |
| Expression incrementExpr = null; //1/-1 |
| if( ctx.iterPred.info.increment != null ) { |
| incrementExpr = ctx.iterPred.info.increment; |
| } |
| IterablePredicate predicate = new IterablePredicate(ctx, iterVar, ctx.iterPred.info.from, ctx.iterPred.info.to, |
| incrementExpr, parForParamValues, currentFile); |
| parForStmt.setPredicate(predicate); |
| if(ctx.body.size() > 0) { |
| for(StatementContext stmtCtx : ctx.body) |
| parForStmt.addStatementBlock(getStatementBlock(stmtCtx.info.stmt)); |
| parForStmt.mergeStatementBlocks(); |
| } |
| ctx.info.stmt = parForStmt; |
| } |
| |
| private ArrayList<DataIdentifier> getFunctionParametersNoAssign(List<TypedArgNoAssignContext> ctx) { |
| ArrayList<DataIdentifier> retVal = new ArrayList<>(ctx.size()); |
| for(TypedArgNoAssignContext paramCtx : ctx) { |
| DataIdentifier dataId = new DataIdentifier(paramCtx.paramName.getText()); |
| String dataType = (paramCtx.paramType == null || paramCtx.paramType.dataType() == null |
| || paramCtx.paramType.dataType().getText() == null || paramCtx.paramType.dataType().getText().isEmpty()) ? |
| "scalar" : paramCtx.paramType.dataType().getText(); |
| String valueType = paramCtx.paramType.valueType().getText(); |
| |
| //check and assign data type |
| checkValidDataType(dataType, paramCtx.start); |
| if( !setDataAndValueType(dataId, dataType, valueType, paramCtx.start, false, true) ) |
| return null; |
| retVal.add(dataId); |
| } |
| return retVal; |
| } |
| |
| private ArrayList<DataIdentifier> getFunctionParametersAssign(List<TypedArgAssignContext> ctx) { |
| ArrayList<DataIdentifier> retVal = new ArrayList<>(ctx.size()); |
| for(TypedArgAssignContext paramCtx : ctx) { |
| DataIdentifier dataId = new DataIdentifier(paramCtx.paramName.getText()); |
| String dataType = (paramCtx.paramType == null || paramCtx.paramType.dataType() == null |
| || paramCtx.paramType.dataType().getText() == null || paramCtx.paramType.dataType().getText().isEmpty()) ? |
| "scalar" : paramCtx.paramType.dataType().getText(); |
| String valueType = paramCtx.paramType.valueType().getText(); |
| |
| //check and assign data type |
| checkValidDataType(dataType, paramCtx.start); |
| if( !setDataAndValueType(dataId, dataType, valueType, paramCtx.start, false, true) ) |
| return null; |
| retVal.add(dataId); |
| } |
| return retVal; |
| } |
| |
| private static ArrayList<Expression> getFunctionDefaults(List<TypedArgAssignContext> ctx) { |
| return new ArrayList<>(ctx.stream().map(arg -> |
| (arg.paramVal!=null)?arg.paramVal.info.expr:null).collect(Collectors.toList())); |
| } |
| |
| @Override |
| public void exitIterablePredicateColonExpression(IterablePredicateColonExpressionContext ctx) { |
| ctx.info.from = ctx.from.info.expr; |
| ctx.info.to = ctx.to.info.expr; |
| ctx.info.increment = null; |
| } |
| |
| @Override |
| public void exitIterablePredicateSeqExpression(IterablePredicateSeqExpressionContext ctx) { |
| if(!ctx.ID().getText().equals("seq")) { |
| notifyErrorListeners("incorrect function:\'" + ctx.ID().getText() + "\'. expected \'seq\'", ctx.start); |
| return; |
| } |
| ctx.info.from = ctx.from.info.expr; |
| ctx.info.to = ctx.to.info.expr; |
| if(ctx.increment != null && ctx.increment.info != null) |
| ctx.info.increment = ctx.increment.info.expr; |
| } |
| |
| |
| // ----------------------------------------------------------------- |
| // Internal & External Functions Definitions |
| // ----------------------------------------------------------------- |
| |
| @Override |
| public void exitInternalFunctionDefExpression(InternalFunctionDefExpressionContext ctx) { |
| //populate function statement |
| FunctionStatement functionStmt = new FunctionStatement(); |
| functionStmt.setName(ctx.name.getText()); |
| functionStmt.setInputParams(getFunctionParametersAssign(ctx.inputParams)); |
| functionStmt.setInputDefaults(getFunctionDefaults(ctx.inputParams)); |
| functionStmt.setOutputParams(getFunctionParametersNoAssign(ctx.outputParams)); |
| |
| if(ctx.body.size() > 0) { |
| // handle function body |
| // Create arraylist of one statement block |
| ArrayList<StatementBlock> body = new ArrayList<>(); |
| for(StatementContext stmtCtx : ctx.body) { |
| body.add(getStatementBlock(stmtCtx.info.stmt)); |
| } |
| functionStmt.setBody(body); |
| functionStmt.mergeStatementBlocks(); |
| } |
| else { |
| notifyErrorListeners("functions with no statements are not allowed", ctx.start); |
| return; |
| } |
| |
| ctx.info.stmt = functionStmt; |
| setFileLineColumn(ctx.info.stmt, ctx); |
| ctx.info.functionName = ctx.name.getText(); |
| } |
| |
| @Override |
| public void exitPathStatement(PathStatementContext ctx) { |
| PathStatement stmt = new PathStatement(ctx.pathValue.getText()); |
| String filePath = UtilFunctions.unquote(ctx.pathValue.getText()); |
| _workingDir = filePath; |
| ctx.info.stmt = stmt; |
| } |
| |
| @Override |
| public void exitIfdefAssignmentStatement(IfdefAssignmentStatementContext ctx) { |
| if(!ctx.commandLineParam.getText().startsWith("$")) { |
| notifyErrorListeners("the first argument of ifdef function should be a commandline argument parameter (which starts with $)", ctx.commandLineParam.start); |
| return; |
| } |
| |
| if(ctx.targetList == null) { |
| notifyErrorListeners("ifdef assignment needs an lvalue ", ctx.start); |
| return; |
| } |
| String targetListText = ctx.targetList.getText(); |
| if(targetListText.startsWith("$")) { |
| notifyErrorListeners("lhs of ifdef function cannot be a commandline parameters. Use local variable instead", ctx.start); |
| return; |
| } |
| |
| DataIdentifier target = null; |
| if(ctx.targetList.dataInfo.expr instanceof DataIdentifier) { |
| target = (DataIdentifier) ctx.targetList.dataInfo.expr; |
| Expression source = null; |
| if(ctx.commandLineParam.dataInfo.expr != null) { |
| // Since commandline parameter is set |
| // The check of following is done in fillExpressionInfoCommandLineParameters: |
| // Command line param cannot be empty string |
| // If you want to pass space, please quote it |
| source = ctx.commandLineParam.dataInfo.expr; |
| } |
| else { |
| source = ctx.source.info.expr; |
| } |
| |
| try { |
| ctx.info.stmt = new AssignmentStatement(ctx, target, source, currentFile); |
| } catch (LanguageException e) { |
| notifyErrorListeners("invalid assignment for ifdef function", ctx.targetList.start); |
| return; |
| } |
| |
| } |
| else { |
| notifyErrorListeners("incorrect lvalue in ifdef function ", ctx.targetList.start); |
| return; |
| } |
| } |
| |
| @Override |
| public void exitAccumulatorAssignmentStatement(AccumulatorAssignmentStatementContext ctx) { |
| if(ctx.targetList == null) { |
| notifyErrorListeners("incorrect parsing for accumulator assignment", ctx.start); |
| return; |
| } |
| //process as default assignment statement |
| exitAssignmentStatementHelper(ctx, ctx.targetList.getText(), |
| ctx.targetList.dataInfo, ctx.targetList.start, ctx.source.info, ctx.info); |
| //mark as accumulator |
| ((AssignmentStatement)ctx.info.stmt).setAccumulator(true); |
| } |
| |
| @Override |
| public void exitMatrixDataTypeCheck(MatrixDataTypeCheckContext ctx) { |
| checkValidDataType(ctx.ID().getText(), ctx.start); |
| } |
| |
| |
| // ----------------------------------------------------------------- |
| // Not overridden |
| // ----------------------------------------------------------------- |
| |
| @Override public void visitTerminal(TerminalNode node) {} |
| |
| @Override public void visitErrorNode(ErrorNode node) {} |
| |
| @Override public void exitEveryRule(ParserRuleContext ctx) {} |
| |
| @Override public void enterModIntDivExpression(ModIntDivExpressionContext ctx) {} |
| |
| @Override public void enterExternalFunctionDefExpression(ExternalFunctionDefExpressionContext ctx) {} |
| |
| @Override public void enterBooleanNotExpression(BooleanNotExpressionContext ctx) {} |
| |
| @Override public void enterPowerExpression(PowerExpressionContext ctx) {} |
| |
| @Override public void enterInternalFunctionDefExpression(InternalFunctionDefExpressionContext ctx) {} |
| |
| @Override public void enterBuiltinFunctionExpression(BuiltinFunctionExpressionContext ctx) {} |
| |
| @Override public void enterConstIntIdExpression(ConstIntIdExpressionContext ctx) {} |
| |
| @Override public void enterAtomicExpression(AtomicExpressionContext ctx) {} |
| |
| @Override public void enterIfdefAssignmentStatement(IfdefAssignmentStatementContext ctx) {} |
| |
| @Override public void enterAccumulatorAssignmentStatement(AccumulatorAssignmentStatementContext ctx) {} |
| |
| @Override public void enterConstStringIdExpression(ConstStringIdExpressionContext ctx) {} |
| |
| @Override public void enterConstTrueExpression(ConstTrueExpressionContext ctx) {} |
| |
| @Override public void enterParForStatement(ParForStatementContext ctx) {} |
| |
| @Override public void enterUnaryExpression(UnaryExpressionContext ctx) {} |
| |
| @Override public void enterImportStatement(ImportStatementContext ctx) {} |
| |
| @Override public void enterPathStatement(PathStatementContext ctx) {} |
| |
| @Override public void enterWhileStatement(WhileStatementContext ctx) {} |
| |
| @Override public void enterCommandlineParamExpression(CommandlineParamExpressionContext ctx) {} |
| |
| @Override public void enterFunctionCallAssignmentStatement(FunctionCallAssignmentStatementContext ctx) {} |
| |
| @Override public void enterAddSubExpression(AddSubExpressionContext ctx) {} |
| |
| @Override public void enterIfStatement(IfStatementContext ctx) {} |
| |
| @Override public void enterConstDoubleIdExpression(ConstDoubleIdExpressionContext ctx) {} |
| |
| @Override public void enterMatrixMulExpression(MatrixMulExpressionContext ctx) {} |
| |
| @Override public void enterMatrixDataTypeCheck(MatrixDataTypeCheckContext ctx) {} |
| |
| @Override public void enterCommandlinePositionExpression(CommandlinePositionExpressionContext ctx) {} |
| |
| @Override public void enterIterablePredicateColonExpression(IterablePredicateColonExpressionContext ctx) {} |
| |
| @Override public void enterAssignmentStatement(AssignmentStatementContext ctx) {} |
| |
| @Override public void enterValueType(ValueTypeContext ctx) {} |
| |
| @Override public void exitValueType(ValueTypeContext ctx) {} |
| |
| @Override public void enterMl_type(Ml_typeContext ctx) {} |
| |
| @Override public void exitMl_type(Ml_typeContext ctx) {} |
| |
| @Override public void enterBooleanAndExpression(BooleanAndExpressionContext ctx) {} |
| |
| @Override public void enterForStatement(ForStatementContext ctx) {} |
| |
| @Override public void enterRelationalExpression(RelationalExpressionContext ctx) {} |
| |
| @Override public void enterTypedArgNoAssign(TypedArgNoAssignContext ctx) {} |
| |
| @Override public void exitTypedArgNoAssign(TypedArgNoAssignContext ctx) {} |
| |
| @Override public void enterTypedArgAssign(TypedArgAssignContext ctx) {} |
| |
| @Override public void exitTypedArgAssign(TypedArgAssignContext ctx) {} |
| |
| @Override public void enterStrictParameterizedExpression(StrictParameterizedExpressionContext ctx) {} |
| |
| @Override public void exitStrictParameterizedExpression(StrictParameterizedExpressionContext ctx) {} |
| |
| @Override public void enterMultDivExpression(MultDivExpressionContext ctx) {} |
| |
| @Override public void enterConstFalseExpression(ConstFalseExpressionContext ctx) {} |
| |
| @Override public void enterStrictParameterizedKeyValueString(StrictParameterizedKeyValueStringContext ctx) {} |
| |
| @Override public void exitStrictParameterizedKeyValueString(StrictParameterizedKeyValueStringContext ctx) {} |
| |
| @Override public void enterProgramroot(ProgramrootContext ctx) {} |
| |
| @Override |
| public void exitProgramroot(ProgramrootContext ctx) { |
| //take over dml-bodied builtin functions into list of script functions |
| for( Entry<String,FunctionStatementBlock> e : builtinFuns.getFunctions().entrySet() ) { |
| FunctionStatementContext fn = new FunctionStatementContext(); |
| fn.info = new StatementInfo(); |
| fn.info.stmt = e.getValue().getStatement(0); |
| fn.info.functionName = e.getKey(); |
| //existing user-function overrides builtin function |
| if( !containsFunction(ctx, e.getKey()) ) |
| ctx.functionBlocks.add(fn); |
| } |
| } |
| |
| private static boolean containsFunction(ProgramrootContext ctx, String fname) { |
| for( FunctionStatementContext fn : ctx.functionBlocks ) |
| if( fn.info.functionName.equals(fname) ) |
| return true; |
| return false; |
| } |
| |
| @Override public void enterDataIdExpression(DataIdExpressionContext ctx) {} |
| |
| @Override public void enterIndexedExpression(IndexedExpressionContext ctx) {} |
| |
| @Override public void enterParameterizedExpression(ParameterizedExpressionContext ctx) {} |
| |
| @Override public void exitParameterizedExpression(ParameterizedExpressionContext ctx) {} |
| |
| @Override public void enterFunctionCallMultiAssignmentStatement(FunctionCallMultiAssignmentStatementContext ctx) {} |
| |
| @Override public void enterIterablePredicateSeqExpression(IterablePredicateSeqExpressionContext ctx) {} |
| |
| @Override public void enterSimpleDataIdentifierExpression(SimpleDataIdentifierExpressionContext ctx) {} |
| |
| @Override public void enterBooleanOrExpression(BooleanOrExpressionContext ctx) {} |
| |
| @Override |
| public void enterMultiIdExpression(MultiIdExpressionContext ctx) { } |
| |
| @Override |
| public void exitMultiIdExpression(MultiIdExpressionContext ctx) { |
| ArrayList<Expression> values = new ArrayList<>(); |
| for(ExpressionContext elem : ctx.targetList) { |
| values.add(elem.info.expr); |
| } |
| ctx.info.expr = new ExpressionList(values); |
| } |
| |
| @Override |
| public void exitExternalFunctionDefExpression(ExternalFunctionDefExpressionContext ctx) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| // internal helpers |
| |
| public static void init() { |
| _f2NS.get().clear(); |
| } |
| |
| public static void init(Map<String, String> scripts) { |
| _f2NS.get().clear(); |
| _tScripts.get().clear(); |
| for( Entry<String,String> e : scripts.entrySet() ) |
| _tScripts.get().put(getDefWorkingFilePath(e.getKey()), e.getValue()); |
| } |
| |
| protected void notifyErrorListeners(String message, Token op) { |
| if (!DMLScript.VALIDATOR_IGNORE_ISSUES) { |
| errorListener.validationError(op.getLine(), op.getCharPositionInLine(), message); |
| } |
| } |
| |
| protected void raiseWarning(String message, Token op) { |
| errorListener.validationWarning(op.getLine(), op.getCharPositionInLine(), message); |
| } |
| |
| /** |
| * Obtain the namespace and the function name as a two-element array based |
| * on the fully-qualified function name. If no namespace is supplied in |
| * front of the function name, the default namespace will be used. |
| * |
| * @param fullyQualifiedFunctionName |
| * Namespace followed by separator ({@code ::} for DML and |
| * {@code .} for PYDML) followed by function name (for example, |
| * {@code mynamespace::myfunctionname}), or only function name if |
| * the default namespace is used (for example, |
| * {@code myfunctionname}). |
| * @return Two-element array consisting of namespace and function name, or |
| * {@code null}. |
| */ |
| protected String[] getQualifiedNames(String fullyQualifiedFunctionName) { |
| String splitStr = Pattern.quote(namespaceResolutionOp()); |
| String [] fnNames = fullyQualifiedFunctionName.split(splitStr); |
| String functionName = ""; |
| String namespace = ""; |
| if(fnNames.length == 1) { |
| namespace = DMLProgram.DEFAULT_NAMESPACE; |
| functionName = fnNames[0].trim(); |
| } |
| else if(fnNames.length == 2) { |
| namespace = getQualifiedNamespace(fnNames[0].trim()); |
| functionName = fnNames[1].trim(); |
| } |
| else |
| return null; |
| |
| String[] retVal = new String[2]; |
| retVal[0] = namespace; |
| retVal[1] = functionName; |
| return retVal; |
| } |
| |
| protected String getQualifiedNamespace(String namespace) { |
| String path = sources.get(namespace); |
| return (path != null && path.length() > 0) ? path : namespace; |
| } |
| |
| public String getWorkingFilePath(String filePath) { |
| return getWorkingFilePath(filePath, _workingDir); |
| } |
| |
| public static String getDefWorkingFilePath(String filePath) { |
| return getWorkingFilePath(filePath, DEF_WORK_DIR); |
| } |
| |
| private static String getWorkingFilePath(String filePath, String workingDir) { |
| //NOTE: the use of File.separator would lead to OS-specific inconsistencies, |
| //which is problematic for second order functions such as eval or paramserv. |
| //Since this is unnecessary, we now use "/" independent of the use OS. |
| return !new File(filePath).isAbsolute() ? workingDir + "/" + filePath : filePath; |
| } |
| |
| public String getNamespaceSafe(Token ns) { |
| return (ns != null && ns.getText() != null && !ns.getText().isEmpty()) ? |
| ns.getText() : DMLProgram.DEFAULT_NAMESPACE; |
| } |
| |
| protected void validateNamespace(String namespace, String filePath, ParserRuleContext ctx) { |
| // error out if different scripts from different file paths are bound to the same namespace |
| if( !DMLProgram.DEFAULT_NAMESPACE.equals(namespace) ) { |
| if( sources.containsKey(namespace) && !sources.get(namespace).equals(filePath) ) |
| notifyErrorListeners("Namespace Conflict: '" + namespace |
| + "' already defined as " + sources.get(namespace), ctx.start); |
| else |
| sources.put(namespace, filePath); |
| } |
| } |
| |
| protected void setupContextInfo(StatementInfo info, String namespace, |
| String filePath, String filePath2, DMLProgram prog ) { |
| info.namespaces = new HashMap<>(); |
| if(prog != null) { |
| info.namespaces.put(getQualifiedNamespace(namespace), prog.getDefaultFunctionDictionary()); |
| for( Entry<String, FunctionDictionary<FunctionStatementBlock>> e : prog.getNamespaces().entrySet() ) |
| info.namespaces.put(getQualifiedNamespace(e.getKey()), e.getValue()); |
| ImportStatement istmt = new ImportStatement(); |
| istmt.setCompletePath(filePath); |
| istmt.setFilename(filePath2); |
| istmt.setNamespace(namespace); |
| info.stmt = istmt; |
| } |
| } |
| |
| protected void setFileLineColumn(Expression expr, ParserRuleContext ctx) { |
| expr.setCtxValuesAndFilename(ctx, currentFile); |
| } |
| |
| protected void setFileLineColumn(Statement stmt, ParserRuleContext ctx) { |
| stmt.setCtxValuesAndFilename(ctx, currentFile); |
| } |
| |
| // -------------------------------------------------------------------- |
| // HELPER METHODS FOR OVERRIDDEN VISITOR FUNCTIONS |
| // -------------------------------------------------------------------- |
| |
| protected void binaryExpressionHelper(ParserRuleContext ctx, ExpressionInfo left, ExpressionInfo right, |
| ExpressionInfo me, String op) { |
| if(left.expr != null && right.expr != null) { |
| Expression.BinaryOp bop = Expression.getBinaryOp(op); |
| BinaryExpression be = new BinaryExpression(bop); |
| be = new BinaryExpression(bop); |
| be.setLeft(left.expr); |
| be.setRight(right.expr); |
| me.expr = be; |
| setFileLineColumn(me.expr, ctx); |
| } |
| } |
| |
| protected void relationalExpressionHelper(ParserRuleContext ctx, ExpressionInfo left, ExpressionInfo right, |
| ExpressionInfo me, String op) { |
| if(left.expr != null && right.expr != null) { |
| Expression.RelationalOp rop = Expression.getRelationalOp(op); |
| RelationalExpression re = new RelationalExpression(rop); |
| re.setLeft(left.expr); |
| re.setRight(right.expr); |
| me.expr = re; |
| setFileLineColumn(me.expr, ctx); |
| } |
| } |
| |
| protected void booleanExpressionHelper(ParserRuleContext ctx, ExpressionInfo left, ExpressionInfo right, |
| ExpressionInfo me, String op) { |
| if(left.expr != null && right.expr != null) { |
| Expression.BooleanOp bop = Expression.getBooleanOp(op); |
| BooleanExpression re = new BooleanExpression(bop); |
| re.setLeft(left.expr); |
| re.setRight(right.expr); |
| me.expr = re; |
| setFileLineColumn(me.expr, ctx); |
| } |
| } |
| |
| |
| |
| protected void unaryExpressionHelper(ParserRuleContext ctx, ExpressionInfo left, ExpressionInfo me, String op) { |
| if(left.expr != null) { |
| if(left.expr instanceof IntIdentifier) { |
| if(op.equals("-")) { |
| ((IntIdentifier) left.expr).multiplyByMinusOne(); |
| } |
| me.expr = left.expr; |
| } |
| else if(left.expr instanceof DoubleIdentifier) { |
| if(op.equals("-")) { |
| ((DoubleIdentifier) left.expr).multiplyByMinusOne(); |
| } |
| me.expr = left.expr; |
| } |
| else { |
| Expression right = new IntIdentifier(ctx, 1, currentFile); |
| if(op.equals("-")) { |
| right = new IntIdentifier(ctx, -1, currentFile); |
| } |
| |
| Expression.BinaryOp bop = Expression.getBinaryOp("*"); |
| BinaryExpression be = new BinaryExpression(bop); |
| be.setLeft(left.expr); |
| be.setRight(right); |
| me.expr = be; |
| } |
| setFileLineColumn(me.expr, ctx); |
| } |
| } |
| |
| protected void unaryBooleanExpressionHelper(ParserRuleContext ctx, ExpressionInfo left, ExpressionInfo me, |
| String op) { |
| if(left.expr != null) { |
| Expression.BooleanOp bop = Expression.getBooleanOp(op); |
| BooleanExpression be = new BooleanExpression(bop); |
| be.setLeft(left.expr); |
| me.expr = be; |
| setFileLineColumn(me.expr, ctx); |
| } |
| } |
| |
| |
| protected void constDoubleIdExpressionHelper(ParserRuleContext ctx, ExpressionInfo me) { |
| try { |
| double val = Double.parseDouble(ctx.getText()); |
| me.expr = new DoubleIdentifier(ctx, val, currentFile); |
| } |
| catch(Exception e) { |
| notifyErrorListeners("cannot parse the float value: \'" + ctx.getText() + "\'", ctx.getStart()); |
| return; |
| } |
| } |
| |
| protected void constIntIdExpressionHelper(ParserRuleContext ctx, ExpressionInfo me) { |
| try { |
| long val = Long.parseLong(ctx.getText()); |
| me.expr = new IntIdentifier(ctx, val, currentFile); |
| } |
| catch(Exception e) { |
| notifyErrorListeners("cannot parse the int value: \'" + ctx.getText() + "\'", ctx.getStart()); |
| return; |
| } |
| } |
| |
| protected String extractStringInQuotes(String text, boolean inQuotes) { |
| String val = null; |
| if(inQuotes) { |
| if( (text.startsWith("\"") && text.endsWith("\"")) || |
| (text.startsWith("\'") && text.endsWith("\'"))) { |
| if(text.length() > 2) { |
| val = text.substring(1, text.length()-1) |
| .replaceAll("\\\\b","\b") |
| .replaceAll("\\\\t","\t") |
| .replaceAll("\\\\n","\n") |
| .replaceAll("\\\\f","\f") |
| .replaceAll("\\\\r","\r") |
| .replace("\\'","'") |
| .replace("\\\"","\""); |
| } |
| else if(text.equals("\"\"") || text.equals("\'\'")) { |
| val = ""; |
| } |
| } |
| } |
| else { |
| val = text.replaceAll("\\\\b","\b") |
| .replaceAll("\\\\t","\t") |
| .replaceAll("\\\\n","\n") |
| .replaceAll("\\\\f","\f") |
| .replaceAll("\\\\r","\r") |
| .replace("\\'","'") |
| .replace("\\\"","\""); |
| } |
| return val; |
| } |
| |
| protected void constStringIdExpressionHelper(ParserRuleContext ctx, ExpressionInfo me) { |
| String val = extractStringInQuotes(ctx.getText(), true); |
| if(val == null) { |
| notifyErrorListeners("incorrect string literal ", ctx.start); |
| return; |
| } |
| |
| me.expr = new StringIdentifier(ctx, val, currentFile); |
| } |
| |
| protected void booleanIdentifierHelper(ParserRuleContext ctx, boolean val, ExpressionInfo info) { |
| info.expr = new BooleanIdentifier(ctx, val, currentFile); |
| setFileLineColumn(info.expr, ctx); |
| } |
| |
| protected void exitDataIdExpressionHelper(ParserRuleContext ctx, ExpressionInfo me, ExpressionInfo dataInfo) { |
| // inject builtin constant |
| if (dataInfo.expr instanceof DataIdentifier) { |
| DataIdentifier id = ((DataIdentifier) dataInfo.expr); |
| if (BuiltinConstant.contains(id.getName())) { |
| dataInfo.expr = new DoubleIdentifier(BuiltinConstant.valueOf(id.getName()).get(), dataInfo.expr); |
| } |
| } |
| me.expr = dataInfo.expr; |
| // If "The parameter $X either needs to be passed through commandline or initialized to default value" validation |
| // error occurs, then dataInfo.expr is null which would cause a null pointer exception with the following code. |
| // Therefore, check for null so that parsing can continue so all parsing issues can be determined. |
| if (me.expr != null) { |
| me.expr.setCtxValuesAndFilename(ctx, currentFile); |
| } |
| } |
| |
| protected ConstIdentifier getConstIdFromString(ParserRuleContext ctx, String varValue) { |
| // Compare to "True/TRUE" |
| if(varValue.equals(trueStringLiteral())) |
| return new BooleanIdentifier(ctx, true, currentFile); |
| |
| // Compare to "False/FALSE" |
| if(varValue.equals(falseStringLiteral())) |
| return new BooleanIdentifier(ctx, false, currentFile); |
| |
| // Check for long literal |
| // NOTE: we use exception handling instead of Longs.tryParse for backwards compatibility with guava <14.1 |
| // Also the alternative of Ints.tryParse and falling back to double would not be lossless in all cases. |
| try { |
| long lval = Long.parseLong(varValue); |
| return new IntIdentifier(ctx, lval, currentFile); |
| } |
| catch(Exception ex) { |
| //continue |
| } |
| |
| // Check for double literal |
| // NOTE: we use exception handling instead of Doubles.tryParse for backwards compatibility with guava <14.0 |
| try { |
| double dval = Double.parseDouble(varValue); |
| return new DoubleIdentifier(ctx, dval, currentFile); |
| } |
| catch(Exception ex) { |
| //continue |
| } |
| |
| // Otherwise it is a string literal (optionally enclosed within single or double quotes) |
| String val = ""; |
| String text = varValue; |
| if( (text.startsWith("\"") && text.endsWith("\"")) || (text.startsWith("\'") && text.endsWith("\'"))) { |
| if(text.length() > 2) { |
| val = extractStringInQuotes(text, true); |
| } |
| } |
| else { |
| // the commandline parameters can be passed without any quotes |
| val = extractStringInQuotes(text, false); |
| } |
| return new StringIdentifier(ctx, val, currentFile); |
| } |
| |
| |
| protected void fillExpressionInfoCommandLineParameters(ParserRuleContext ctx, String varName, ExpressionInfo dataInfo) { |
| |
| if(!varName.startsWith("$")) { |
| notifyErrorListeners("commandline param does not start with $", ctx.start); |
| return; |
| } |
| |
| String varValue = null; |
| for(Map.Entry<String, String> arg : this.argVals.entrySet()) { |
| if(arg.getKey().equals(varName)) { |
| if(varValue != null) { |
| notifyErrorListeners("multiple values passed for the parameter " + varName + " via commandline", ctx.start); |
| return; |
| } |
| else { |
| varValue = arg.getValue(); |
| } |
| } |
| } |
| |
| if(varValue == null) { |
| return; |
| } |
| |
| // Command line param cannot be empty string |
| // If you want to pass space, please quote it |
| if(varValue.equals("")) |
| return; |
| |
| dataInfo.expr = getConstIdFromString(ctx, varValue); |
| } |
| |
| protected void exitAssignmentStatementHelper(ParserRuleContext ctx, String lhs, ExpressionInfo dataInfo, |
| Token lhsStart, ExpressionInfo rhs, StatementInfo info) { |
| if(lhs.startsWith("$")) { |
| notifyErrorListeners("assignment of commandline parameters is not allowed. (Quickfix: try using someLocalVariable=ifdef(" + lhs + ", default value))", ctx.start); |
| return; |
| } |
| |
| DataIdentifier target = null; |
| if(dataInfo.expr instanceof DataIdentifier) { |
| target = (DataIdentifier) dataInfo.expr; |
| Expression source = rhs.expr; |
| try { |
| info.stmt = new AssignmentStatement(ctx, target, source, currentFile); |
| } catch (LanguageException e) { |
| // TODO: extract more meaningful info from this exception. |
| notifyErrorListeners("invalid assignment: " + e.getMessage(), lhsStart); |
| return; |
| } |
| } |
| else { |
| notifyErrorListeners("incorrect lvalue in assignment statement", lhsStart); |
| return; |
| } |
| } |
| |
| |
| // ----------------------------------------------------------------- |
| // Helper Functions for exit*FunctionCall*AssignmentStatement |
| // ----------------------------------------------------------------- |
| |
| protected void setPrintStatement(ParserRuleContext ctx, String functionName, |
| ArrayList<ParameterExpression> paramExpression, StatementInfo thisinfo) { |
| if (DMLScript.VALIDATOR_IGNORE_ISSUES == true) { // create dummy print statement |
| try { |
| thisinfo.stmt = new PrintStatement(ctx, functionName, currentFile); |
| } catch (LanguageException e) { |
| e.printStackTrace(); |
| } |
| return; |
| } |
| int numParams = paramExpression.size(); |
| if (numParams == 0) { |
| notifyErrorListeners(functionName + "() must have more than 0 parameters", ctx.start); |
| return; |
| } else if (numParams == 1) { |
| Expression expr = paramExpression.get(0).getExpr(); |
| if(expr == null) { |
| notifyErrorListeners("cannot process " + functionName + "() function", ctx.start); |
| return; |
| } |
| try { |
| List<Expression> expList = new ArrayList<>(); |
| expList.add(expr); |
| thisinfo.stmt = new PrintStatement(ctx, functionName, expList, currentFile); |
| } catch (LanguageException e) { |
| notifyErrorListeners("cannot process " + functionName + "() function", ctx.start); |
| return; |
| } |
| } else if (numParams > 1) { |
| if ("stop".equals(functionName)) { |
| notifyErrorListeners("stop() function cannot have more than 1 parameter", ctx.start); |
| return; |
| } |
| |
| Expression firstExp = paramExpression.get(0).getExpr(); |
| if (firstExp == null) { |
| notifyErrorListeners("cannot process " + functionName + "() function", ctx.start); |
| return; |
| } |
| if (!(firstExp instanceof StringIdentifier)) { |
| notifyErrorListeners("printf-style functionality requires first print parameter to be a string", ctx.start); |
| return; |
| } |
| try { |
| List<Expression> expressions = new ArrayList<>(); |
| for (ParameterExpression pe : paramExpression) { |
| Expression expression = pe.getExpr(); |
| expressions.add(expression); |
| } |
| thisinfo.stmt = new PrintStatement(ctx, functionName, expressions, currentFile); |
| } catch (LanguageException e) { |
| notifyErrorListeners("cannot process " + functionName + "() function", ctx.start); |
| return; |
| } |
| } |
| } |
| |
| protected void setOutputStatement(ParserRuleContext ctx, |
| ArrayList<ParameterExpression> paramExpression, StatementInfo info) { |
| if(paramExpression.size() < 2){ |
| notifyErrorListeners("incorrect usage of write function (at least 2 arguments required)", ctx.start); |
| return; |
| } |
| if(paramExpression.get(0).getExpr() instanceof DataIdentifier) { |
| HashMap<String, Expression> varParams = new HashMap<>(); |
| varParams.put(DataExpression.IO_FILENAME, paramExpression.get(1).getExpr()); |
| for(int i = 2; i < paramExpression.size(); i++) { |
| // DataExpression.FORMAT_TYPE, DataExpression.DELIM_DELIMITER, DataExpression.DELIM_HAS_HEADER_ROW, DataExpression.DELIM_SPARSE |
| varParams.put(paramExpression.get(i).getName(), paramExpression.get(i).getExpr()); |
| } |
| |
| DataExpression dataExpression = new DataExpression(ctx, DataOp.WRITE, varParams, currentFile); |
| info.stmt = new OutputStatement(ctx, (DataIdentifier) paramExpression.get(0).getExpr(), DataOp.WRITE, |
| currentFile); |
| ((OutputStatement)info.stmt).setExprParams(dataExpression); |
| } |
| else { |
| notifyErrorListeners("incorrect usage of write function", ctx.start); |
| } |
| } |
| |
| protected void setAssignmentStatement(ParserRuleContext ctx, StatementInfo info, DataIdentifier target, Expression expression) { |
| try { |
| info.stmt = new AssignmentStatement(ctx, target, expression, currentFile); |
| } catch (LanguageException e) { |
| // TODO: extract more meaningful info from this exception. |
| notifyErrorListeners("invalid function call", ctx.start); |
| return; |
| } |
| } |
| |
| /** |
| * Information about built in functions converted to a common format between |
| * PyDML and DML for the runtime. |
| */ |
| public static class ConvertedDMLSyntax { |
| public final String namespace; |
| public final String functionName; |
| public final ArrayList<ParameterExpression> paramExpression; |
| public ConvertedDMLSyntax(String namespace, String functionName, |
| ArrayList<ParameterExpression> paramExpression) { |
| this.namespace = namespace; |
| this.functionName = functionName; |
| this.paramExpression = paramExpression; |
| } |
| } |
| |
| /** Creates a builtin function expression. |
| * |
| * @param ctx antlr rule context |
| * @param functionName Name of the builtin function |
| * @param paramExpressions Array of parameter names and values |
| * @return expression if found otherwise null |
| */ |
| protected Expression buildForBuiltInFunction(ParserRuleContext ctx, String functionName, ArrayList<ParameterExpression> paramExpressions) { |
| // In global namespace, so it can be a builtin function |
| // Double verification: verify passed function name is a (non-parameterized) built-in function. |
| try { |
| if (functions.contains(functionName)) { |
| // It is a user function definition (which takes precedence if name same as built-in) |
| return null; |
| } |
| |
| Expression lsf = handleLanguageSpecificFunction(ctx, functionName, paramExpressions); |
| if (lsf != null) { |
| setFileLineColumn(lsf, ctx); |
| return lsf; |
| } |
| |
| BuiltinFunctionExpression bife = BuiltinFunctionExpression.getBuiltinFunctionExpression(ctx, functionName, paramExpressions, currentFile); |
| if (bife != null) { |
| // It is a builtin function |
| return bife; |
| } |
| |
| ParameterizedBuiltinFunctionExpression pbife = ParameterizedBuiltinFunctionExpression |
| .getParamBuiltinFunctionExpression(ctx, functionName, paramExpressions, currentFile); |
| if (pbife != null){ |
| // It is a parameterized builtin function |
| return pbife; |
| } |
| |
| // built-in read, rand ... |
| DataExpression dbife = DataExpression.getDataExpression(ctx, functionName, paramExpressions, currentFile, errorListener); |
| if (dbife != null){ |
| return dbife; |
| } |
| } |
| catch(Exception e) { |
| notifyErrorListeners("unable to process builtin function expression " + functionName + ":" + e.getMessage(), ctx.start); |
| } |
| return null; |
| } |
| |
| |
| protected void functionCallAssignmentStatementHelper(final ParserRuleContext ctx, |
| Set<String> printStatements, Set<String> outputStatements, final Expression dataInfo, |
| final StatementInfo info, final Token nameToken, Token targetListToken, String namespace, |
| String functionName, ArrayList<ParameterExpression> paramExpression, boolean hasLHS) { |
| ConvertedDMLSyntax convertedSyntax = convertToDMLSyntax(ctx, namespace, functionName, paramExpression, nameToken); |
| if(convertedSyntax == null) { |
| return; |
| } |
| else { |
| namespace = convertedSyntax.namespace; |
| functionName = convertedSyntax.functionName; |
| paramExpression = convertedSyntax.paramExpression; |
| } |
| |
| // For builtin functions without LHS |
| if(namespace.equals(DMLProgram.DEFAULT_NAMESPACE) && !functions.contains(functionName)) { |
| if (printStatements.contains(functionName)){ |
| setPrintStatement(ctx, functionName, paramExpression, info); |
| return; |
| } |
| else if (outputStatements.contains(functionName)){ |
| setOutputStatement(ctx, paramExpression, info); |
| return; |
| } |
| } |
| |
| DataIdentifier target = null; |
| if(dataInfo instanceof DataIdentifier) { |
| target = (DataIdentifier) dataInfo; |
| } |
| else if (dataInfo != null) { |
| notifyErrorListeners("incorrect lvalue for function call ", targetListToken); |
| return; |
| } |
| |
| // For builtin functions with LHS |
| if(namespace.equals(DMLProgram.DEFAULT_NAMESPACE) && !functions.contains(functionName)){ |
| Expression e = buildForBuiltInFunction(ctx, functionName, paramExpression); |
| if( e != null ) { |
| setAssignmentStatement(ctx, info, target, e); |
| return; |
| } |
| handleDMLBodiedBuiltinFunction(functionName, namespace, ctx); |
| } |
| |
| // handle user-defined functions |
| setAssignmentStatement(ctx, info, target, |
| createFunctionCall(ctx, namespace, functionName, paramExpression)); |
| } |
| |
| protected FunctionCallIdentifier createFunctionCall(ParserRuleContext ctx, |
| String namespace, String functionName, ArrayList<ParameterExpression> paramExpression) { |
| FunctionCallIdentifier functCall = new FunctionCallIdentifier(paramExpression); |
| functCall.setFunctionName(functionName); |
| String inferNamespace = (sourceNamespace != null && sourceNamespace.length() > 0 |
| && DMLProgram.DEFAULT_NAMESPACE.equals(namespace)) ? sourceNamespace : namespace; |
| functCall.setFunctionNamespace(inferNamespace); |
| functCall.setCtxValuesAndFilename(ctx, currentFile); |
| return functCall; |
| } |
| |
| protected void setMultiAssignmentStatement(ArrayList<DataIdentifier> target, Expression expression, ParserRuleContext ctx, StatementInfo info) { |
| info.stmt = new MultiAssignmentStatement(target, expression); |
| info.stmt.setCtxValuesAndFilename(ctx, currentFile); |
| } |
| |
| // ----------------------------------------------------------------- |
| // End of Helper Functions for exit*FunctionCall*AssignmentStatement |
| // ----------------------------------------------------------------- |
| |
| /** |
| * Indicates if the given data type string is a valid data type. |
| * |
| * @param datatype data type (matrix, frame, or scalar) |
| * @param start antlr token |
| */ |
| protected void checkValidDataType(String datatype, Token start) { |
| boolean validMatrixType = datatype.equals("matrix") || datatype.equals("Matrix") |
| || datatype.equals("frame") || datatype.equals("Frame") |
| || datatype.equals("list") || datatype.equals("List") |
| || datatype.equals("scalar") || datatype.equals("Scalar"); |
| if( !validMatrixType ) |
| notifyErrorListeners("incorrect datatype (expected matrix, frame, list, or scalar)", start); |
| } |
| |
| protected boolean setDataAndValueType(DataIdentifier dataId, String dataType, String valueType, Token start, boolean shortVt, boolean helpBool) { |
| if( dataType.equalsIgnoreCase("matrix") ) |
| dataId.setDataType(DataType.MATRIX); |
| else if( dataType.equalsIgnoreCase("frame") ) |
| dataId.setDataType(DataType.FRAME); |
| else if( dataType.equalsIgnoreCase("list") ) |
| dataId.setDataType(DataType.LIST); |
| else if( dataType.equalsIgnoreCase("scalar") ) |
| dataId.setDataType(DataType.SCALAR); |
| |
| if( (shortVt && valueType.equals("int")) |
| || valueType.equals("int") || valueType.equals("integer") |
| || valueType.equals("Int") || valueType.equals("Integer")) { |
| dataId.setValueType(ValueType.INT64); |
| } |
| else if( (shortVt && valueType.equals("str")) |
| || valueType.equals("string") || valueType.equals("String")) { |
| dataId.setValueType(ValueType.STRING); |
| } |
| else if( (shortVt && valueType.equals("bool")) |
| || valueType.equals("boolean") || valueType.equals("Boolean")) { |
| dataId.setValueType(ValueType.BOOLEAN); |
| } |
| else if( (shortVt && valueType.equals("float") ) |
| || valueType.equals("double") || valueType.equals("Double")) { |
| dataId.setValueType(ValueType.FP64); |
| } |
| else if(valueType.equals("unknown") || (!shortVt && valueType.equals("Unknown"))) { |
| dataId.setValueType(ValueType.UNKNOWN); |
| } |
| else if(helpBool && valueType.equals("bool")) { |
| notifyErrorListeners("invalid valuetype " + valueType + " (Quickfix: use \'boolean\' instead)", start); |
| return false; |
| } |
| else { |
| notifyErrorListeners("invalid valuetype " + valueType, start); |
| return false; |
| } |
| return true; |
| } |
| |
| private DMLProgram parseAndAddImportedFunctions(String namespace, String filePath, ParserRuleContext ctx) { |
| //validate namespace w/ awareness of dml-bodied builtin functions |
| validateNamespace(namespace, filePath, ctx); |
| |
| //read and parse namespace files |
| String scriptID = DMLProgram.constructFunctionKey(namespace, filePath); |
| DMLProgram prog = null; |
| if (!_f2NS.get().containsKey(scriptID)) { |
| _f2NS.get().put(scriptID, namespace); |
| try { |
| prog = new DMLParserWrapper().doParse(filePath, |
| _tScripts.get().get(filePath), getQualifiedNamespace(namespace), argVals); |
| } |
| catch (ParseException e) { |
| notifyErrorListeners(e.getMessage(), ctx.start); |
| return prog; |
| } |
| if(prog == null) { |
| notifyErrorListeners("One or more errors found during importing a program from file " + filePath, ctx.start); |
| return prog; |
| } |
| } |
| else { |
| // Skip redundant parsing (to prevent potential infinite recursion) and |
| // create empty program for this context to allow processing to continue. |
| prog = new DMLProgram(); |
| } |
| return prog; |
| } |
| } |