http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/c04fc99f/src/main/java/org/apache/sysml/parser/dml/Dml.g4 ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/parser/dml/Dml.g4 b/src/main/java/org/apache/sysml/parser/dml/Dml.g4 new file mode 100644 index 0000000..9d07dc9 --- /dev/null +++ b/src/main/java/org/apache/sysml/parser/dml/Dml.g4 @@ -0,0 +1,201 @@ +/* + * 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. + */ + +grammar Dml; + +@header +{ + // Commenting the package name and explicitly passing it in build.xml to maintain compatibility with maven plugin + // package org.apache.sysml.parser.dml; +} + +// DML Program is a list of expression +// For now, we only allow global function definitions (not nested or inside a while block) +dmlprogram: (blocks+=statement | functionBlocks+=functionStatement)* EOF; + +statement returns [ StatementInfo info ] +@init { + // This actions occurs regardless of how many alternatives in this rule + $info = new StatementInfo(); +} : + // ------------------------------------------ + // ImportStatement + 'source' '(' filePath = STRING ')' 'as' namespace=ID ';'* # ImportStatement + | 'setwd' '(' pathValue = STRING ')' ';'* # PathStatement + // ------------------------------------------ + // Treat function call as AssignmentStatement or MultiAssignmentStatement + // For backward compatibility and also since the behavior of foo() * A + foo() ... where foo returns A + // Convert FunctionCallIdentifier(paramExprs, ..) -> source + | // TODO: Throw an informative error if user doesnot provide the optional assignment + ( targetList+=dataIdentifier ('='|'<-') )? name=ID '(' (paramExprs+=parameterizedExpression (',' paramExprs+=parameterizedExpression)* )? ')' ';'* # FunctionCallAssignmentStatement + | '[' targetList+=dataIdentifier (',' targetList+=dataIdentifier)* ']' ('='|'<-') name=ID '(' (paramExprs+=parameterizedExpression (',' paramExprs+=parameterizedExpression)* )? ')' ';'* # FunctionCallMultiAssignmentStatement + // {notifyErrorListeners("Too many parentheses");} + // ------------------------------------------ + // AssignmentStatement + | targetList+=dataIdentifier op=('<-'|'=') 'ifdef' '(' commandLineParam=dataIdentifier ',' source=expression ')' ';'* # IfdefAssignmentStatement + | targetList+=dataIdentifier op=('<-'|'=') source=expression ';'* # AssignmentStatement + // ------------------------------------------ + // We don't support block statement + // | '{' body+=expression ';'* ( body+=expression ';'* )* '}' # BlockStatement + // ------------------------------------------ + // IfStatement + | 'if' '(' predicate=expression ')' (ifBody+=statement ';'* | '{' (ifBody+=statement ';'*)* '}') ('else' (elseBody+=statement ';'* | '{' (elseBody+=statement ';'*)* '}'))? # IfStatement + // ------------------------------------------ + // ForStatement & ParForStatement + | 'for' '(' iterVar=ID 'in' iterPred=iterablePredicate (',' parForParams+=strictParameterizedExpression)* ')' (body+=statement ';'* | '{' (body+=statement ';'* )* '}') # ForStatement + // Convert strictParameterizedExpression to HashMap<String, String> for parForParams + | 'parfor' '(' iterVar=ID 'in' iterPred=iterablePredicate (',' parForParams+=strictParameterizedExpression)* ')' (body+=statement ';'* | '{' (body+=statement ';'*)* '}') # ParForStatement + | 'while' '(' predicate=expression ')' (body+=statement ';'* | '{' (body+=statement ';'*)* '}') # WhileStatement + // ------------------------------------------ +; + +iterablePredicate returns [ ExpressionInfo info ] + @init { + // This actions occurs regardless of how many alternatives in this rule + $info = new ExpressionInfo(); + } : + from=expression ':' to=expression #IterablePredicateColonExpression + | ID '(' from=expression ',' to=expression ',' increment=expression ')' #IterablePredicateSeqExpression + ; + +functionStatement returns [ StatementInfo info ] +@init { + // This actions occurs regardless of how many alternatives in this rule + $info = new StatementInfo(); +} : + // ------------------------------------------ + // FunctionStatement & ExternalFunctionStatement + // small change: only allow typed arguments here ... instead of data identifier + name=ID ('<-'|'=') 'function' '(' ( inputParams+=typedArgNoAssign (',' inputParams+=typedArgNoAssign)* )? ')' ( 'return' '(' ( outputParams+=typedArgNoAssign (',' outputParams+=typedArgNoAssign)* )? ')' )? '{' (body+=statement ';'*)* '}' # InternalFunctionDefExpression + | name=ID ('<-'|'=') 'externalFunction' '(' ( inputParams+=typedArgNoAssign (',' inputParams+=typedArgNoAssign)* )? ')' ( 'return' '(' ( outputParams+=typedArgNoAssign (',' outputParams+=typedArgNoAssign)* )? ')' )? 'implemented' 'in' '(' ( otherParams+=strictParameterizedKeyValueString (',' otherParams+=strictParameterizedKeyValueString)* )? ')' ';'* # ExternalFunctionDefExpression + // ------------------------------------------ +; + + +// Other data identifiers are typedArgNoAssign, parameterizedExpression and strictParameterizedExpression +dataIdentifier returns [ ExpressionInfo dataInfo ] +@init { + // This actions occurs regardless of how many alternatives in this rule + $dataInfo = new ExpressionInfo(); + // $dataInfo.expr = new org.apache.sysml.parser.DataIdentifier(); +} : + // ------------------------------------------ + // IndexedIdentifier + name=ID '[' (rowLower=expression (':' rowUpper=expression)?)? ',' (colLower=expression (':' colUpper=expression)?)? ']' # IndexedExpression + // ------------------------------------------ + | ID # SimpleDataIdentifierExpression + | COMMANDLINE_NAMED_ID # CommandlineParamExpression + | COMMANDLINE_POSITION_ID # CommandlinePositionExpression +; +expression returns [ ExpressionInfo info ] +@init { + // This actions occurs regardless of how many alternatives in this rule + $info = new ExpressionInfo(); + // $info.expr = new org.apache.sysml.parser.BinaryExpression(org.apache.sysml.parser.Expression.BinaryOp.INVALID); +} : + // ------------------------------------------ + // BinaryExpression + // power + <assoc=right> left=expression op='^' right=expression # PowerExpression + // unary plus and minus + | op=('-'|'+') left=expression # UnaryExpression + // sequence - since we are only using this into for + //| left=expression op=':' right=expression # SequenceExpression + // matrix multiply + | left=expression op='%*%' right=expression # MatrixMulExpression + // modulus and integer division + | left=expression op=('%/%' | '%%' ) right=expression # ModIntDivExpression + // arithmetic multiply and divide + | left=expression op=('*'|'/') right=expression # MultDivExpression + // arithmetic addition and subtraction + | left=expression op=('+'|'-') right=expression # AddSubExpression + // ------------------------------------------ + // RelationalExpression + | left=expression op=('>'|'>='|'<'|'<='|'=='|'!=') right=expression # RelationalExpression + // ------------------------------------------ + // BooleanExpression + // boolean not + | op='!' left=expression # BooleanNotExpression + // boolean and + | left=expression op=('&'|'&&') right=expression # BooleanAndExpression + // boolean or + | left=expression op=('|'|'||') right=expression # BooleanOrExpression + + // --------------------------------- + // only applicable for builtin function expressions + | name=ID '(' (paramExprs+=parameterizedExpression (',' paramExprs+=parameterizedExpression)* )? ')' ';'* # BuiltinFunctionExpression + + // 4. Atomic + | '(' left=expression ')' # AtomicExpression + + // Should you allow indexed expression here ? + // | '[' targetList+=expression (',' targetList+=expression)* ']' # MultiIdExpression + + // | BOOLEAN # ConstBooleanIdExpression + | 'TRUE' # ConstTrueExpression + | 'FALSE' # ConstFalseExpression + | INT # ConstIntIdExpression + | DOUBLE # ConstDoubleIdExpression + | STRING # ConstStringIdExpression + | dataIdentifier # DataIdExpression + // Special + // | 'NULL' | 'NA' | 'Inf' | 'NaN' +; + +typedArgNoAssign : paramType=ml_type paramName=ID; +parameterizedExpression : (paramName=ID '=')? paramVal=expression; +strictParameterizedExpression : paramName=ID '=' paramVal=expression ; +strictParameterizedKeyValueString : paramName=ID '=' paramVal=STRING ; +ID : (ALPHABET (ALPHABET|DIGIT|'_')* '::')? ALPHABET (ALPHABET|DIGIT|'_')* + // Special ID cases: + // | 'matrix' // --> This is a special case which causes lot of headache + | 'as.scalar' | 'as.matrix' | 'as.double' | 'as.integer' | 'as.logical' | 'index.return' | 'lower.tail' +; +// Unfortunately, we have datatype name clashing with builtin function name: matrix :( +// Therefore, ugly work around for checking datatype +ml_type : valueType | dataType '[' valueType ']'; +// Note to reduce number of keywords, these are case-sensitive, +// To allow case-insenstive, 'int' becomes: ('i' | 'I') ('n' | 'N') ('t' | 'T') +valueType: 'int' | 'integer' | 'string' | 'boolean' | 'double' + | 'Int' | 'Integer' | 'String' | 'Boolean' | 'Double'; +dataType: + // 'scalar' # ScalarDataTypeDummyCheck + // | + ID # MatrixDataTypeCheck //{ if($ID.text.compareTo("matrix") != 0) { notifyErrorListeners("incorrect datatype"); } } + //| 'matrix' //---> See ID, this causes lot of headache + ; +INT : DIGIT+ [Ll]?; +// BOOLEAN : 'TRUE' | 'FALSE'; +DOUBLE: DIGIT+ '.' DIGIT* EXP? [Ll]? +| DIGIT+ EXP? [Ll]? +| '.' DIGIT+ EXP? [Ll]? +; +DIGIT: '0'..'9'; +ALPHABET : [a-zA-Z] ; +fragment EXP : ('E' | 'e') ('+' | '-')? INT ; +COMMANDLINE_NAMED_ID: '$' ALPHABET (ALPHABET|DIGIT|'_')*; +COMMANDLINE_POSITION_ID: '$' DIGIT+; + +// supports single and double quoted string with escape characters +STRING: '"' ( ESC | ~[\\"] )*? '"' | '\'' ( ESC | ~[\\'] )*? '\''; +fragment ESC : '\\' [abtnfrv"'\\] ; +// Comments, whitespaces and new line +LINE_COMMENT : '#' .*? '\r'? '\n' -> skip ; +MULTILINE_BLOCK_COMMENT : '/*' .*? '*/' -> skip ; +WHITESPACE : (' ' | '\t' | '\r' | '\n')+ -> skip ;
http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/c04fc99f/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticErrorListener.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticErrorListener.java b/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticErrorListener.java new file mode 100644 index 0000000..027ea08 --- /dev/null +++ b/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticErrorListener.java @@ -0,0 +1,115 @@ +/* + * 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.sysml.parser.dml; + +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.sysml.api.DMLScript; + +import java.util.Stack; + +public class DmlSyntacticErrorListener { + + + private static final Log LOG = LogFactory.getLog(DMLScript.class.getName()); + + public static class CustomDmlErrorListener extends BaseErrorListener { + + private boolean atleastOneError = false; + private Stack<String> currentFileName = new Stack<String>(); + + public void pushCurrentFileName(String currentFilePath) { + currentFileName.push(currentFilePath); + } + + public String peekFileName() { + return currentFileName.peek(); + } + + public String popFileName() { + return currentFileName.pop(); + } + + public void validationError(int line, int charPositionInLine, String msg) { + try { + setAtleastOneError(true); + // Print error messages with file name + if(currentFileName == null || currentFileName.empty()) { + LOG.error("line "+line+":"+charPositionInLine+" "+msg); + } + else { + String fileName = currentFileName.peek(); + LOG.error(fileName + " line "+line+":"+charPositionInLine+" "+msg); + } + } + catch(Exception e1) { + LOG.error("ERROR: while customizing error message:" + e1); + } + } + + public void validationWarning(int line, int charPositionInLine, String msg) { + try { + //atleastOneError = true; ---> not an error, just warning + // Print error messages with file name + if(currentFileName == null || currentFileName.empty()) + LOG.warn("line "+line+":"+charPositionInLine+" "+msg); + else { + String fileName = currentFileName.peek(); + LOG.warn(fileName + " line "+line+":"+charPositionInLine+" "+msg); + } + } + catch(Exception e1) { + LOG.warn("ERROR: while customizing error message:" + e1); + } + } + + @Override + public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, + int line, int charPositionInLine, + String msg, RecognitionException e) + { + try { + setAtleastOneError(true); + // Print error messages with file name + if(currentFileName == null || currentFileName.empty()) + LOG.error("line "+line+":"+charPositionInLine+" "+msg); + else { + String fileName = currentFileName.peek(); + LOG.error(fileName + " line "+line+":"+charPositionInLine+" "+msg); + } + } + catch(Exception e1) { + LOG.error("ERROR: while customizing error message:" + e1); + } + } + + public boolean isAtleastOneError() { + return atleastOneError; + } + + public void setAtleastOneError(boolean atleastOneError) { + this.atleastOneError = atleastOneError; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/c04fc99f/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidator.java b/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidator.java new file mode 100644 index 0000000..798ab40 --- /dev/null +++ b/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidator.java @@ -0,0 +1,1533 @@ +/* + * 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.sysml.parser.dml; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +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.sysml.parser.ConditionalPredicate; +import org.apache.sysml.parser.DMLProgram; +import org.apache.sysml.parser.DataIdentifier; +import org.apache.sysml.parser.DoubleIdentifier; +import org.apache.sysml.parser.Expression; +import org.apache.sysml.parser.Expression.DataOp; +import org.apache.sysml.parser.Expression.DataType; +import org.apache.sysml.parser.Expression.ValueType; +import org.apache.sysml.parser.dml.DmlParser.AddSubExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.AssignmentStatementContext; +import org.apache.sysml.parser.dml.DmlParser.AtomicExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.BooleanAndExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.BooleanNotExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.BooleanOrExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.BuiltinFunctionExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.CommandlineParamExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.CommandlinePositionExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.ConstDoubleIdExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.ConstFalseExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.ConstIntIdExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.ConstStringIdExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.ConstTrueExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.DataIdExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.DataIdentifierContext; +import org.apache.sysml.parser.dml.DmlParser.DmlprogramContext; +import org.apache.sysml.parser.dml.DmlParser.ExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.ExternalFunctionDefExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.ForStatementContext; +import org.apache.sysml.parser.dml.DmlParser.FunctionCallAssignmentStatementContext; +import org.apache.sysml.parser.dml.DmlParser.FunctionCallMultiAssignmentStatementContext; +import org.apache.sysml.parser.dml.DmlParser.FunctionStatementContext; +import org.apache.sysml.parser.dml.DmlParser.IfStatementContext; +import org.apache.sysml.parser.dml.DmlParser.IfdefAssignmentStatementContext; +import org.apache.sysml.parser.dml.DmlParser.ImportStatementContext; +import org.apache.sysml.parser.dml.DmlParser.IndexedExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.InternalFunctionDefExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.IterablePredicateColonExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.IterablePredicateSeqExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.MatrixDataTypeCheckContext; +import org.apache.sysml.parser.dml.DmlParser.MatrixMulExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.Ml_typeContext; +import org.apache.sysml.parser.dml.DmlParser.ModIntDivExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.MultDivExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.ParForStatementContext; +import org.apache.sysml.parser.dml.DmlParser.ParameterizedExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.PathStatementContext; +import org.apache.sysml.parser.dml.DmlParser.PowerExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.RelationalExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.SimpleDataIdentifierExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.StatementContext; +import org.apache.sysml.parser.dml.DmlParser.StrictParameterizedExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.StrictParameterizedKeyValueStringContext; +import org.apache.sysml.parser.dml.DmlParser.TypedArgNoAssignContext; +import org.apache.sysml.parser.dml.DmlParser.UnaryExpressionContext; +import org.apache.sysml.parser.dml.DmlParser.ValueTypeContext; +import org.apache.sysml.parser.dml.DmlParser.WhileStatementContext; +import org.apache.sysml.parser.AParserWrapper; +import org.apache.sysml.parser.AssignmentStatement; +import org.apache.sysml.parser.BinaryExpression; +import org.apache.sysml.parser.BooleanExpression; +import org.apache.sysml.parser.BooleanIdentifier; +import org.apache.sysml.parser.BuiltinFunctionExpression; +import org.apache.sysml.parser.ConstIdentifier; +import org.apache.sysml.parser.DataExpression; +import org.apache.sysml.parser.ExternalFunctionStatement; +import org.apache.sysml.parser.ForStatement; +import org.apache.sysml.parser.FunctionCallIdentifier; +import org.apache.sysml.parser.FunctionStatement; +import org.apache.sysml.parser.IfStatement; +import org.apache.sysml.parser.ImportStatement; +import org.apache.sysml.parser.IndexedIdentifier; +import org.apache.sysml.parser.IntIdentifier; +import org.apache.sysml.parser.IterablePredicate; +import org.apache.sysml.parser.LanguageException; +import org.apache.sysml.parser.MultiAssignmentStatement; +import org.apache.sysml.parser.OutputStatement; +import org.apache.sysml.parser.ParForStatement; +import org.apache.sysml.parser.ParameterExpression; +import org.apache.sysml.parser.ParameterizedBuiltinFunctionExpression; +import org.apache.sysml.parser.ParseException; +import org.apache.sysml.parser.PathStatement; +import org.apache.sysml.parser.PrintStatement; +import org.apache.sysml.parser.RelationalExpression; +import org.apache.sysml.parser.Statement; +import org.apache.sysml.parser.StatementBlock; +import org.apache.sysml.parser.StringIdentifier; +import org.apache.sysml.parser.WhileStatement; + +/** + * TODO: Refactor duplicated parser code dml/pydml (entire package). + * + */ +public class DmlSyntacticValidator implements DmlListener +{ + private DmlSyntacticValidatorHelper helper = null; + + private String _workingDir = "."; //current working directory + private String _currentPath = null; //current file path + private HashMap<String,String> argVals = null; + + public DmlSyntacticValidator(DmlSyntacticValidatorHelper helper, String currentPath, HashMap<String,String> argVals) { + this.helper = helper; + this.argVals = argVals; + + _currentPath = currentPath; + } + + // Functions we have to implement but don't really need it + @Override + public void enterAddSubExpression(AddSubExpressionContext ctx) { } + @Override + public void enterAssignmentStatement(AssignmentStatementContext ctx) {} + @Override + public void enterAtomicExpression(AtomicExpressionContext ctx) { } + @Override + public void enterBooleanAndExpression(BooleanAndExpressionContext ctx) { } + @Override + public void enterBooleanNotExpression(BooleanNotExpressionContext ctx) { } + @Override + public void enterBooleanOrExpression(BooleanOrExpressionContext ctx) { } + @Override + public void enterCommandlineParamExpression(CommandlineParamExpressionContext ctx) { } + @Override + public void enterCommandlinePositionExpression(CommandlinePositionExpressionContext ctx) { } + @Override + public void enterConstDoubleIdExpression(ConstDoubleIdExpressionContext ctx) { } + @Override + public void enterConstIntIdExpression(ConstIntIdExpressionContext ctx) { } + @Override + public void enterConstStringIdExpression(ConstStringIdExpressionContext ctx) { } + @Override + public void enterDataIdExpression(DataIdExpressionContext ctx) { } + + @Override + public void enterDmlprogram(DmlprogramContext ctx) { } + @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(); + } + } + } + @Override + public void enterExternalFunctionDefExpression(ExternalFunctionDefExpressionContext ctx) { } + @Override + public void enterForStatement(ForStatementContext ctx) {} + @Override + public void enterFunctionCallAssignmentStatement(FunctionCallAssignmentStatementContext ctx) { } + @Override + public void enterFunctionCallMultiAssignmentStatement(FunctionCallMultiAssignmentStatementContext ctx) { } + @Override + public void enterIfStatement(IfStatementContext ctx) { } + @Override + public void enterImportStatement(ImportStatementContext ctx) { } + @Override + public void enterIndexedExpression(IndexedExpressionContext ctx) { } + @Override + public void enterInternalFunctionDefExpression(InternalFunctionDefExpressionContext ctx) { } + public void enterMatrixMulExpression(MatrixMulExpressionContext ctx) { } + @Override + public void enterMl_type(Ml_typeContext ctx) { } + @Override + public void enterModIntDivExpression(ModIntDivExpressionContext ctx) { } + @Override + public void enterMultDivExpression(MultDivExpressionContext ctx) { } + @Override + public void enterParameterizedExpression(ParameterizedExpressionContext ctx) { } + @Override + public void enterParForStatement(ParForStatementContext ctx) { } + @Override + public void enterPathStatement(PathStatementContext ctx) { } + @Override + public void enterPowerExpression(PowerExpressionContext ctx) { } + @Override + public void enterRelationalExpression(RelationalExpressionContext ctx) { } + @Override + public void enterSimpleDataIdentifierExpression(SimpleDataIdentifierExpressionContext ctx) { } + @Override + public void enterStrictParameterizedExpression(StrictParameterizedExpressionContext ctx) { } + @Override + public void enterTypedArgNoAssign(TypedArgNoAssignContext ctx) { } + @Override + public void enterUnaryExpression(UnaryExpressionContext ctx) { } + @Override + public void enterValueType(ValueTypeContext ctx) { } + @Override + public void enterWhileStatement(WhileStatementContext ctx) { } + + @Override + public void visitErrorNode(ErrorNode arg0) { } + @Override + public void visitTerminal(TerminalNode arg0) { } + @Override + public void exitEveryRule(ParserRuleContext arg0) {} + // -------------------------------------------------------------------- + private void setFileLineColumn(Expression expr, ParserRuleContext ctx) { + // expr.setFilename(helper.getCurrentFileName()); + String txt = ctx.getText(); + expr.setFilename(_currentPath); + expr.setBeginLine(ctx.start.getLine()); + expr.setBeginColumn(ctx.start.getCharPositionInLine()); + expr.setEndLine(ctx.stop.getLine()); + expr.setEndColumn(ctx.stop.getCharPositionInLine()); + if(expr.getBeginColumn() == expr.getEndColumn() && expr.getBeginLine() == expr.getEndLine() && txt.length() > 1) { + expr.setEndColumn(expr.getBeginColumn() + txt.length() - 1); + } + } + + private void setFileLineColumn(Statement stmt, ParserRuleContext ctx) { + String txt = ctx.getText(); + stmt.setFilename(helper.getCurrentFileName()); + stmt.setBeginLine(ctx.start.getLine()); + stmt.setBeginColumn(ctx.start.getCharPositionInLine()); + stmt.setEndLine(ctx.stop.getLine()); + stmt.setEndColumn(ctx.stop.getCharPositionInLine()); + if(stmt.getBeginColumn() == stmt.getEndColumn() && stmt.getBeginLine() == stmt.getEndLine() && txt.length() > 1) { + stmt.setEndColumn(stmt.getBeginColumn() + txt.length() - 1); + } + } + + // 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) { + if(ctx.left.info.expr != null && ctx.right.info.expr != null) { + Expression.BinaryOp bop = Expression.getBinaryOp(ctx.op.getText()); + ctx.info.expr = new BinaryExpression(bop); + ((BinaryExpression)ctx.info.expr).setLeft(ctx.left.info.expr); + ((BinaryExpression)ctx.info.expr).setRight(ctx.right.info.expr); + setFileLineColumn(ctx.info.expr, ctx); + } + } + @Override + public void exitModIntDivExpression(ModIntDivExpressionContext ctx) { + if(ctx.left.info.expr != null && ctx.right.info.expr != null) { + Expression.BinaryOp bop = Expression.getBinaryOp(ctx.op.getText()); + ctx.info.expr = new BinaryExpression(bop); + ((BinaryExpression)ctx.info.expr).setLeft(ctx.left.info.expr); + ((BinaryExpression)ctx.info.expr).setRight(ctx.right.info.expr); + setFileLineColumn(ctx.info.expr, ctx); + } + } + + @Override + public void exitUnaryExpression(UnaryExpressionContext ctx) { + if(ctx.left.info.expr != null) { + String fileName = helper.getCurrentFileName(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + + if(ctx.left.info.expr instanceof IntIdentifier) { + if(ctx.op.getText().compareTo("-") == 0) { + ((IntIdentifier) ctx.left.info.expr).multiplyByMinusOne(); + } + ctx.info.expr = ctx.left.info.expr; + } + else if(ctx.left.info.expr instanceof DoubleIdentifier) { + if(ctx.op.getText().compareTo("-") == 0) { + ((DoubleIdentifier) ctx.left.info.expr).multiplyByMinusOne(); + } + ctx.info.expr = ctx.left.info.expr; + } + else { + Expression right = new IntIdentifier(1, fileName, line, col, line, col); + if(ctx.op.getText().compareTo("-") == 0) { + right = new IntIdentifier(-1, fileName, line, col, line, col); + } + + Expression.BinaryOp bop = Expression.getBinaryOp("*"); + ctx.info.expr = new BinaryExpression(bop); + ((BinaryExpression)ctx.info.expr).setLeft(ctx.left.info.expr); + ((BinaryExpression)ctx.info.expr).setRight(right); + } + setFileLineColumn(ctx.info.expr, ctx); + } + } + + @Override + public void exitMultDivExpression(MultDivExpressionContext ctx) { + Expression.BinaryOp bop = Expression.getBinaryOp(ctx.op.getText()); + ctx.info.expr = new BinaryExpression(bop); + ((BinaryExpression)ctx.info.expr).setLeft(ctx.left.info.expr); + ((BinaryExpression)ctx.info.expr).setRight(ctx.right.info.expr); + setFileLineColumn(ctx.info.expr, ctx); + } + @Override + public void exitPowerExpression(PowerExpressionContext ctx) { + Expression.BinaryOp bop = Expression.getBinaryOp(ctx.op.getText()); + ctx.info.expr = new BinaryExpression(bop); + ((BinaryExpression)ctx.info.expr).setLeft(ctx.left.info.expr); + ((BinaryExpression)ctx.info.expr).setRight(ctx.right.info.expr); + setFileLineColumn(ctx.info.expr, ctx); + } + + @Override + public void exitMatrixMulExpression(MatrixMulExpressionContext ctx) { + Expression.BinaryOp bop = Expression.getBinaryOp(ctx.op.getText()); + ctx.info.expr = new BinaryExpression(bop); + ((BinaryExpression)ctx.info.expr).setLeft(ctx.left.info.expr); + ((BinaryExpression)ctx.info.expr).setRight(ctx.right.info.expr); + setFileLineColumn(ctx.info.expr, ctx); + } + + // -------------------------------------------------------------------- + + @Override + public void exitRelationalExpression(RelationalExpressionContext ctx) { + if(ctx.left.info.expr != null && ctx.right.info.expr != null) { +// String fileName = helper.getCurrentFileName(); +// int line = ctx.start.getLine(); +// int col = ctx.start.getCharPositionInLine(); +// ArrayList<ParameterExpression> paramExpression = new ArrayList<ParameterExpression>(); +// paramExpression.add(new ParameterExpression(null, ctx.left.info.expr)); +// paramExpression.add(new ParameterExpression(null, ctx.right.info.expr)); +// ParameterExpression operator = new ParameterExpression(null, new StringIdentifier(ctx.op.getText(), fileName, line, col, line, col)); +// paramExpression.add(operator); +// +// try { +// BuiltinFunctionExpression bife = BuiltinFunctionExpression.getBuiltinFunctionExpression("ppred", paramExpression, fileName, line, col, line, col); +// if (bife != null){ +// // It is a builtin function +// ctx.info.expr = bife; +// return; +// } +// } +// catch(Exception e) {} +// helper.notifyErrorListeners("Cannot parse relational expression", ctx.getStart()); + + Expression.RelationalOp rop = Expression.getRelationalOp(ctx.op.getText()); + ctx.info.expr = new RelationalExpression(rop); + ((RelationalExpression)ctx.info.expr).setLeft(ctx.left.info.expr); + ((RelationalExpression)ctx.info.expr).setRight(ctx.right.info.expr); + setFileLineColumn(ctx.info.expr, ctx); + } + } + + // -------------------------------------------------------------------- + + @Override + public void exitBooleanAndExpression(BooleanAndExpressionContext ctx) { + if(ctx.left.info.expr != null && ctx.right.info.expr != null) { + Expression.BooleanOp bop = Expression.getBooleanOp(ctx.op.getText()); + ctx.info.expr = new BooleanExpression(bop); + ((BooleanExpression)ctx.info.expr).setLeft(ctx.left.info.expr); + ((BooleanExpression)ctx.info.expr).setRight(ctx.right.info.expr); + setFileLineColumn(ctx.info.expr, ctx); + } + } + + @Override + public void exitBooleanOrExpression(BooleanOrExpressionContext ctx) { + if(ctx.left.info.expr != null && ctx.right.info.expr != null) { + Expression.BooleanOp bop = Expression.getBooleanOp(ctx.op.getText()); + ctx.info.expr = new BooleanExpression(bop); + ((BooleanExpression)ctx.info.expr).setLeft(ctx.left.info.expr); + ((BooleanExpression)ctx.info.expr).setRight(ctx.right.info.expr); + setFileLineColumn(ctx.info.expr, ctx); + } + } + + @Override + public void exitBooleanNotExpression(BooleanNotExpressionContext ctx) { + if(ctx.left.info.expr != null) { + Expression.BooleanOp bop = Expression.getBooleanOp(ctx.op.getText()); + ctx.info.expr = new BooleanExpression(bop); + ((BooleanExpression)ctx.info.expr).setLeft(ctx.left.info.expr); + setFileLineColumn(ctx.info.expr, ctx); + } + } + + // -------------------------------------------------------------------- + + @Override + public void exitAtomicExpression(AtomicExpressionContext ctx) { + ctx.info.expr = ctx.left.info.expr; + setFileLineColumn(ctx.info.expr, ctx); + } + +// @Override +// public void exitConstBooleanIdExpression(ConstBooleanIdExpressionContext ctx) { +// boolean val = false; +// if(ctx.getText().compareTo("TRUE") == 0) { +// val = true; +// } +// else if(ctx.getText().compareTo("FALSE") == 0) { +// val = false; +// } +// else { +// helper.notifyErrorListeners("cannot parse the boolean value: \'" + ctx.getText() + "\'", ctx.getStart()); +// return; +// } +// int linePosition = ctx.start.getLine(); +// int charPosition = ctx.start.getCharPositionInLine(); +// ctx.info.expr = new BooleanIdentifier(val, helper.getCurrentFileName(), linePosition, charPosition, linePosition, charPosition); +// setFileLineColumn(ctx.info.expr, ctx); +// } + + @Override + public void exitConstDoubleIdExpression(ConstDoubleIdExpressionContext ctx) { + try { + double val = Double.parseDouble(ctx.getText()); + int linePosition = ctx.start.getLine(); + int charPosition = ctx.start.getCharPositionInLine(); + ctx.info.expr = new DoubleIdentifier(val, helper.getCurrentFileName(), linePosition, charPosition, linePosition, charPosition); + setFileLineColumn(ctx.info.expr, ctx); + } + catch(Exception e) { + helper.notifyErrorListeners("cannot parse the double value: \'" + ctx.getText() + "\'", ctx.getStart()); + return; + } + } + + @Override + public void exitConstIntIdExpression(ConstIntIdExpressionContext ctx) { + try { + long val = Long.parseLong(ctx.getText()); + int linePosition = ctx.start.getLine(); + int charPosition = ctx.start.getCharPositionInLine(); + ctx.info.expr = new IntIdentifier(val, helper.getCurrentFileName(), linePosition, charPosition, linePosition, charPosition); + setFileLineColumn(ctx.info.expr, ctx); + } + catch(Exception e) { + helper.notifyErrorListeners("cannot parse the integer value: \'" + ctx.getText() + "\'", ctx.getStart()); + return; + } + } + + @Override + public void exitConstStringIdExpression(ConstStringIdExpressionContext ctx) { + String val = ""; + String text = ctx.getText(); + if( (text.startsWith("\"") && text.endsWith("\"")) || + (text.startsWith("\'") && text.endsWith("\'"))) { + if(text.length() > 2) { + val = text.substring(1, text.length()-1); + } + } + else { + helper.notifyErrorListeners("something wrong while parsing string ... strange", ctx.start); + return; + } + + int linePosition = ctx.start.getLine(); + int charPosition = ctx.start.getCharPositionInLine(); + ctx.info.expr = new StringIdentifier(val, helper.getCurrentFileName(), linePosition, charPosition, linePosition, charPosition); + setFileLineColumn(ctx.info.expr, ctx); + } + + // -------------------------------------------------------------------- + + @Override + public void exitDataIdExpression(DataIdExpressionContext ctx) { + ctx.info.expr = ctx.dataIdentifier().dataInfo.expr; + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + ctx.info.expr.setAllPositions(helper.getCurrentFileName(), line, col, line, col); + setFileLineColumn(ctx.info.expr, ctx); +// if(ctx.getChild(0) instanceof DataIdentifierContext) { +// ctx.info.expr = ctx.dataIdentifier().dataInfo.expr; +// } +// else { +// String msg = "cannot evaluate data expression ... strange"; +// helper.notifyErrorListeners(msg, ctx.start); +// } + } + + @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); + } + + @Override + public void exitIndexedExpression(IndexedExpressionContext ctx) { + ctx.dataInfo.expr = new IndexedIdentifier(ctx.name.getText(), false, false); + setFileLineColumn(ctx.dataInfo.expr, ctx); + try { + ArrayList< ArrayList<Expression> > exprList = new ArrayList< ArrayList<Expression> >(); + + ArrayList<Expression> rowIndices = new ArrayList<Expression>(); + ArrayList<Expression> colIndices = new ArrayList<Expression>(); + + 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)); + + if(!isRowLower && !isRowUpper) { + // both not set + rowIndices.add(null); rowIndices.add(null); + } + else if(isRowLower && isRowUpper) { + // both set + rowIndices.add(ctx.rowLower.info.expr); + rowIndices.add(ctx.rowUpper.info.expr); + } + else if(isRowLower && !isRowUpper) { + // only row set + rowIndices.add(ctx.rowLower.info.expr); + } + else { + helper.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(ctx.colLower.info.expr); + colIndices.add(ctx.colUpper.info.expr); + } + else if(isColLower && !isColUpper) { + colIndices.add(ctx.colLower.info.expr); + } + else { + helper.notifyErrorListeners("incorrect index expression for column", ctx.start); + return; + } + + +// boolean rowIndexLowerSet = false; +// boolean colIndexLowerSet = false; +// +// if(ctx.rowLower != null && !ctx.rowLower.isEmpty() && (ctx.rowLower.info.expr != null)) { +// rowIndices.add(ctx.rowLower.info.expr); +// rowIndexLowerSet = true; +// } +// else { +// rowIndices.add(null); +// } +// if(ctx.rowUpper != null && !ctx.rowUpper.isEmpty() && (ctx.rowUpper.info.expr != null)) { +// rowIndices.add(ctx.rowUpper.info.expr); +// if(!rowIndexLowerSet) { +// helper.notifyErrorListeners("incorrect index expression for row", ctx.start); +// return; +// } +// } +// if(ctx.colLower != null && !ctx.colLower.isEmpty() && (ctx.colLower.info.expr != null)) { +// colIndices.add(ctx.colLower.info.expr); +// colIndexLowerSet = true; +// } +// else { +// colIndices.add(null); +// } +// if(ctx.colUpper != null && !ctx.colUpper.isEmpty() && (ctx.colUpper.info.expr != null)) { +// colIndices.add(ctx.colUpper.info.expr); +// if(!colIndexLowerSet) { +// helper.notifyErrorListeners("incorrect index expression for column", ctx.start); +// return; +// } +// } + exprList.add(rowIndices); + exprList.add(colIndices); + ((IndexedIdentifier) ctx.dataInfo.expr).setIndices(exprList); + } + catch(Exception e) { + helper.notifyErrorListeners("cannot set the indices", ctx.start); + return; + } + } + + private ConstIdentifier getConstIdFromString(String varValue, Token start) { + // Both varName and varValue are correct + int linePosition = start.getLine(); + int charPosition = start.getCharPositionInLine(); + try { + long val = Long.parseLong(varValue); + return new IntIdentifier(val, helper.getCurrentFileName(), linePosition, charPosition, linePosition, charPosition); + } + catch(Exception e) { + try { + double val = Double.parseDouble(varValue); + return new DoubleIdentifier(val, helper.getCurrentFileName(), linePosition, charPosition, linePosition, charPosition); + } + catch(Exception e1) { + try { + if(varValue.compareTo("TRUE") == 0 || varValue.compareTo("FALSE") == 0) { + boolean val = false; + if(varValue.compareTo("TRUE") == 0) { + val = true; + } + return new BooleanIdentifier(val, helper.getCurrentFileName(), linePosition, charPosition, linePosition, charPosition); + } + else { + String val = ""; + String text = varValue; + if( (text.startsWith("\"") && text.endsWith("\"")) || + (text.startsWith("\'") && text.endsWith("\'"))) { + if(text.length() > 2) { + val = text.substring(1, text.length()-1); + } + } + else { + val = text; + // the commandline parameters can be passed without any quotes +// helper.notifyErrorListeners("something wrong while parsing string ... strange", start); +// return null; + } + return new StringIdentifier(val, helper.getCurrentFileName(), linePosition, charPosition, linePosition, charPosition); + } + } + catch(Exception e3) { + helper.notifyErrorListeners("unable to cast the commandline parameter into int/double/boolean/string", start); + return null; + } + } + } + + } + + private void fillExpressionInfoCommandLineParameters(String varName, ExpressionInfo dataInfo, Token start) { + + if(!varName.startsWith("$")) { + helper.notifyErrorListeners("commandline param doesnot start with $ ... strange", start); + return; + } + + String varValue = null; + for(Map.Entry<String, String> arg : this.argVals.entrySet()) { + if(arg.getKey().trim().compareTo(varName) == 0) { + if(varValue != null) { + helper.notifyErrorListeners("multiple values passed for the parameter " + varName + " via commandline", start); + return; + } + else { + varValue = arg.getValue().trim(); + } + } + } + + if(varValue == null) { + // helper.notifyErrorListeners("the parameter " + varName + " either needs to be passed through commandline or initialized to default value", start); + return; + } + + // Command line param cannot be empty string + // If you want to pass space, please quote it + if(varValue.trim().compareTo("") == 0) + return; + + dataInfo.expr = getConstIdFromString(varValue, start); + } + + @Override + public void exitCommandlineParamExpression(CommandlineParamExpressionContext ctx) { + handleCommandlineArgumentExpression(ctx); + } + + @Override + public void exitCommandlinePositionExpression(CommandlinePositionExpressionContext ctx) { + handleCommandlineArgumentExpression(ctx); + } + + /** + * + * @param ctx + */ + private void handleCommandlineArgumentExpression(DataIdentifierContext ctx) + { + String varName = ctx.getText().trim(); + fillExpressionInfoCommandLineParameters(varName, ctx.dataInfo, ctx.start); + + 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( AParserWrapper.IGNORE_UNSPECIFIED_ARGS ) { + ctx.dataInfo.expr = getConstIdFromString(" ", ctx.start); + helper.raiseWarning(msg, ctx.start); + } + else { + helper.notifyErrorListeners(msg, ctx.start); + } + } + } + } + + // -------------------------------------------------------------------- + + @Override + public void exitImportStatement(ImportStatementContext ctx) + { + //prepare import filepath + String filePath = ctx.filePath.getText(); + String namespace = DMLProgram.DEFAULT_NAMESPACE; + if(ctx.namespace != null && ctx.namespace.getText() != null && !ctx.namespace.getText().isEmpty()) { + namespace = ctx.namespace.getText(); + } + if((filePath.startsWith("\"") && filePath.endsWith("\"")) || + filePath.startsWith("'") && filePath.endsWith("'")) { + filePath = filePath.substring(1, filePath.length()-1); + } + + //concatenate working directory to filepath + filePath = _workingDir + File.separator + filePath; + + DMLProgram prog = null; + try { + prog = (new DMLParserWrapper()).doParse(filePath, null, argVals); + } catch (ParseException e) { + helper.notifyErrorListeners("Exception found during importing a program from file " + filePath, ctx.start); + return; + } + // Custom logic whether to proceed ahead or not. Better than the current exception handling mechanism + if(prog == null) { + helper.notifyErrorListeners("One or more errors found during importing a program from file " + filePath, ctx.start); + return; + } + else { + ctx.info.namespaces = new HashMap<String, DMLProgram>(); + ctx.info.namespaces.put(namespace, prog); + ctx.info.stmt = new ImportStatement(); + ((ImportStatement) ctx.info.stmt).setCompletePath(filePath); + ((ImportStatement) ctx.info.stmt).setFilePath(ctx.filePath.getText()); + ((ImportStatement) ctx.info.stmt).setNamespace(namespace); + } + } + + @Override + public void exitAssignmentStatement(AssignmentStatementContext ctx) { + if(ctx.targetList == null || ctx.targetList.size() != 1) { + helper.notifyErrorListeners("incorrect parsing for assignment", ctx.start); + return; + } + String targetListText = ctx.targetList.get(0).getText(); + if(targetListText.startsWith("$")) { + helper.notifyErrorListeners("assignment of commandline parameters is not allowed. (Quickfix: try using someLocalVariable=ifdef(" + targetListText + ", default value))", ctx.start); + return; + } + + DataIdentifier target = null; + if(ctx.targetList.get(0).dataInfo.expr instanceof DataIdentifier) { + target = (DataIdentifier) ctx.targetList.get(0).dataInfo.expr; + Expression source = ctx.source.info.expr; + + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + try { + ctx.info.stmt = new AssignmentStatement(target, source, line, col, line, col); + setFileLineColumn(ctx.info.stmt, ctx); + } catch (LanguageException e) { + // TODO: extract more meaningful info from this exception. + helper.notifyErrorListeners("invalid assignment", ctx.targetList.get(0).start); + return; + } + } + else { + helper.notifyErrorListeners("incorrect lvalue ... strange", ctx.targetList.get(0).start); + return; + } + + } + + + private void setAssignmentStatement(DataIdentifier target, Expression expression, StatementContext ctx) { + try { + ctx.info.stmt = new AssignmentStatement(target, expression, ctx.start.getLine(), ctx.start.getCharPositionInLine(), ctx.start.getLine(), ctx.start.getCharPositionInLine()); + setFileLineColumn(ctx.info.stmt, ctx); + } catch (LanguageException e) { + // TODO: extract more meaningful info from this exception. + helper.notifyErrorListeners("invalid function call", ctx.start); + return; + } + } + + private void setPrintStatement(FunctionCallAssignmentStatementContext ctx, String functionName) { + ArrayList<ParameterExpression> paramExpression = helper.getParameterExpressionList(ctx.paramExprs); + if(paramExpression.size() != 1) { + helper.notifyErrorListeners(functionName + "() has only one parameter", ctx.start); + return; + } + Expression expr = paramExpression.get(0).getExpr(); + if(expr == null) { + helper.notifyErrorListeners("cannot process " + functionName + "() function", ctx.start); + return; + } + try { + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + ctx.info.stmt = new PrintStatement(functionName, expr, line, col, line, col); + setFileLineColumn(ctx.info.stmt, ctx); + } catch (LanguageException e) { + helper.notifyErrorListeners("cannot process " + functionName + "() function", ctx.start); + return; + } + } + + private void setOutputStatement(FunctionCallAssignmentStatementContext ctx) { + ArrayList<ParameterExpression> paramExpression = helper.getParameterExpressionList(ctx.paramExprs); + if(paramExpression.size() < 2){ + helper.notifyErrorListeners("incorrect usage of write function (atleast 2 arguments required)", ctx.start); + return; + } + if(paramExpression.get(0).getExpr() instanceof DataIdentifier) { + // && paramExpression.get(0).getName() == null + // correct usage of identifier + // if(paramExpression.get(1).getName() == null) { + String fileName = helper.getCurrentFileName(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + HashMap<String, Expression> varParams = new HashMap<String, Expression>(); + 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(DataOp.WRITE, varParams, fileName, line, col, line, col); + ctx.info.stmt = new OutputStatement((DataIdentifier) paramExpression.get(0).getExpr(), DataOp.WRITE, fileName, line, col, line, col); + setFileLineColumn(ctx.info.stmt, ctx); + ((OutputStatement)ctx.info.stmt).setExprParams(dataExpression); + return; + //} + } + + helper.notifyErrorListeners("incorrect usage of write function", ctx.start); + return; + + } + + @Override + public void exitFunctionCallAssignmentStatement(FunctionCallAssignmentStatementContext ctx) { + String fullyQualifiedFunctionName = ctx.name.getText(); + String [] fnNames = fullyQualifiedFunctionName.split("::"); + String functionName = ""; + String namespace = ""; + if(fnNames.length == 1) { + namespace = DMLProgram.DEFAULT_NAMESPACE; + functionName = fnNames[0].trim(); + } + else if(fnNames.length == 2) { + namespace = fnNames[0].trim(); + functionName = fnNames[1].trim(); + } + else { + helper.notifyErrorListeners("incorrect function name", ctx.name); + return; + } + + if((functionName.compareTo("print") == 0 || functionName.compareTo("stop") == 0 ) && namespace.compareTo(DMLProgram.DEFAULT_NAMESPACE) == 0) { + setPrintStatement(ctx, functionName); + return; + } + else if(functionName.compareTo("write") == 0 + && namespace.compareTo(DMLProgram.DEFAULT_NAMESPACE) == 0) { + setOutputStatement(ctx); + return; + } + + boolean ignoreLValue = false; + if(ctx.targetList == null || ctx.targetList.size() == 0 || ctx.targetList.get(0).isEmpty()) { + helper.notifyErrorListeners("function call needs to have lvalue (Quickfix: change it to \'tmpVar = " + functionName + "(...)\')", ctx.name); + return; + } + String fileName = helper.getCurrentFileName(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + + ArrayList<ParameterExpression> paramExpression = helper.getParameterExpressionList(ctx.paramExprs); +// if(functionName.compareTo("read") == 0 && paramExpression.size() > 0 && paramExpression.get(0).getName() == null) { +// paramExpression.get(0).setName(DataExpression.IO_FILENAME); +// } + + FunctionCallIdentifier functCall = new FunctionCallIdentifier(paramExpression); + try { + functCall.setFunctionName(functionName); + functCall.setFunctionNamespace(namespace); + } catch (ParseException e1) { + helper.notifyErrorListeners("unable to process function " + functionName, ctx.start); + return; + } + + DataIdentifier target = null; + if(!ignoreLValue) { + if(ctx.targetList.get(0).dataInfo.expr instanceof DataIdentifier) { + target = (DataIdentifier) ctx.targetList.get(0).dataInfo.expr; + } + else { + helper.notifyErrorListeners("incorrect lvalue ... strange", ctx.targetList.get(0).start); + //target = new DataIdentifier(); // so as not to avoid null pointer + return; + } + } + + if(!functionName.contains("::") || functionName.startsWith(DMLProgram.DEFAULT_NAMESPACE)) { + // In global namespace, so it can be a builtin function + if(!helper.validateBuiltinFunctions(ctx)) { + return; // it is a built-in function and validation failed, so donot proceed ahead. + } + // Double verification: verify passed function name is a (non-parameterized) built-in function. + try { + BuiltinFunctionExpression bife = BuiltinFunctionExpression.getBuiltinFunctionExpression(functionName, functCall.getParamExprs(), fileName, line, col, line, col); + if (bife != null){ + // It is a builtin function + setAssignmentStatement(target, bife, ctx); + return; + } + + ParameterizedBuiltinFunctionExpression pbife = ParameterizedBuiltinFunctionExpression.getParamBuiltinFunctionExpression(functionName, functCall.getParamExprs(), fileName, line, col, line, col); + if (pbife != null){ + // It is a parameterized builtin function + setAssignmentStatement(target, pbife, ctx); + return; + } + + // built-in read, rand ... + DataExpression dbife = DataExpression.getDataExpression(functionName, functCall.getParamExprs(), fileName, line, col, line, col); + if (dbife != null){ + setAssignmentStatement(target, dbife, ctx); + return; + } + } catch(Exception e) { + helper.notifyErrorListeners("unable to process builtin function expression " + functionName + ":" + e.getMessage(), ctx.start); + return ; + } + } + + setAssignmentStatement(target, functCall, ctx); + } + + @Override + public void exitBuiltinFunctionExpression(BuiltinFunctionExpressionContext ctx) { +// if(!helper.validateBuiltinFunctions(ctx)) { +// return; // it is a built-in function and validation failed, so donot proceed ahead. +// } + // Double verification: verify passed function name is a (non-parameterized) built-in function. + String functionName = ctx.name.getText(); + String fileName = helper.getCurrentFileName(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + ArrayList<ParameterExpression> paramExpression = helper.getParameterExpressionList(ctx.paramExprs); +// if(functionName.compareTo("read") == 0 && paramExpression.size() > 0 && paramExpression.get(0).getName() == null) { +// paramExpression.get(0).setName(DataExpression.IO_FILENAME); +// } + + try { + BuiltinFunctionExpression bife = BuiltinFunctionExpression.getBuiltinFunctionExpression(functionName, paramExpression, fileName, line, col, line, col); + if (bife != null){ + // It is a builtin function + ctx.info.expr = bife; + setFileLineColumn(ctx.info.expr, ctx); + return; + } + + ParameterizedBuiltinFunctionExpression pbife = ParameterizedBuiltinFunctionExpression.getParamBuiltinFunctionExpression(functionName, paramExpression, fileName, line, col, line, col); + if (pbife != null){ + // It is a parameterized builtin function + ctx.info.expr = pbife; + setFileLineColumn(ctx.info.expr, ctx); + return; + } + + // built-in read, rand ... + DataExpression dbife = DataExpression.getDataExpression(functionName, paramExpression, fileName, line, col, line, col); + if (dbife != null){ + ctx.info.expr = dbife; + setFileLineColumn(ctx.info.expr, ctx); + return; + } + + } catch(Exception e) { + helper.notifyErrorListeners("unable to process builtin function expression " + functionName + ":" + e.getMessage(), ctx.start); + return ; + } + helper.notifyErrorListeners("only builtin functions allowed as part of expression", ctx.start); + } + + private void setMultiAssignmentStatement(ArrayList<DataIdentifier> target, Expression expression, StatementContext ctx) { + ctx.info.stmt = new MultiAssignmentStatement(target, expression); + ctx.info.stmt.setAllPositions(helper.getCurrentFileName(), ctx.start.getLine(), ctx.start.getCharPositionInLine(), ctx.start.getLine(), ctx.start.getCharPositionInLine()); + setFileLineColumn(ctx.info.stmt, ctx); + } + + @Override + public void exitFunctionCallMultiAssignmentStatement( + FunctionCallMultiAssignmentStatementContext ctx) { + String fullyQualifiedFunctionName = ctx.name.getText(); + String [] fnNames = fullyQualifiedFunctionName.split("::"); + String functionName = ""; + String namespace = ""; + if(fnNames.length == 1) { + namespace = DMLProgram.DEFAULT_NAMESPACE; + functionName = fnNames[0].trim(); + } + else if(fnNames.length == 2) { + namespace = fnNames[0].trim(); + functionName = fnNames[1].trim(); + } + else { + helper.notifyErrorListeners("incorrect function name", ctx.name); + return; + } + + String fileName = helper.getCurrentFileName(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + + ArrayList<ParameterExpression> paramExpression = helper.getParameterExpressionList(ctx.paramExprs); +// if(functionName.compareTo("read") == 0 && paramExpression.size() > 0 && paramExpression.get(0).getName() == null) { +// paramExpression.get(0).setName(DataExpression.IO_FILENAME); +// } + + FunctionCallIdentifier functCall = new FunctionCallIdentifier(paramExpression); + try { + functCall.setFunctionName(functionName); + functCall.setFunctionNamespace(namespace); + } catch (ParseException e1) { + helper.notifyErrorListeners("unable to process function " + functionName, ctx.start); + return; + } + + ArrayList<DataIdentifier> targetList = new ArrayList<DataIdentifier>(); + for(DataIdentifierContext dataCtx : ctx.targetList) { + if(dataCtx.dataInfo.expr instanceof DataIdentifier) { + targetList.add((DataIdentifier) dataCtx.dataInfo.expr); + } + else { + helper.notifyErrorListeners("incorrect lvalue ... strange", dataCtx.start); + //target = new DataIdentifier(); // so as not to avoid null pointer + return; + } + } + + if(!functionName.contains("::") || functionName.startsWith(DMLProgram.DEFAULT_NAMESPACE)) { + // In global namespace, so it can be a builtin function +// if(!helper.validateBuiltinFunctions(ctx)) { +// return; // it is a built-in function and validation failed, so donot proceed ahead. +// } + // Double verification: verify passed function name is a (non-parameterized) built-in function. + try { + BuiltinFunctionExpression bife = BuiltinFunctionExpression.getBuiltinFunctionExpression(functionName, functCall.getParamExprs(), fileName, line, col, line, col); + if (bife != null){ + // It is a builtin function + setMultiAssignmentStatement(targetList, bife, ctx); + return; + } + + ParameterizedBuiltinFunctionExpression pbife = ParameterizedBuiltinFunctionExpression.getParamBuiltinFunctionExpression(functionName, functCall.getParamExprs(), fileName, line, col, line, col); + if (pbife != null){ + // It is a parameterized builtin function + setMultiAssignmentStatement(targetList, pbife, ctx); + return; + } + + // built-in read, rand ... + DataExpression dbife = DataExpression.getDataExpression(functionName, functCall.getParamExprs(), fileName, line, col, line, col); + if (dbife != null){ + setMultiAssignmentStatement(targetList, dbife, ctx); + return; + } + } catch(Exception e) { + helper.notifyErrorListeners("unable to process builtin function expression " + functionName + ":" + e.getMessage(), ctx.start); + return; + } + } + + setMultiAssignmentStatement(targetList, functCall, ctx); + } + + private StatementBlock getStatementBlock(Statement current) { + return DMLParserWrapper.getStatementBlock(current); + } + + @Override + public void exitIfStatement(IfStatementContext ctx) { + IfStatement ifStmt = new IfStatement(); + ConditionalPredicate predicate = new ConditionalPredicate(ctx.predicate.info.expr); + ifStmt.setConditionalPredicate(predicate); + String fileName = helper.getCurrentFileName(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + ifStmt.setAllPositions(fileName, line, col, line, col); + + 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); + String fileName = helper.getCurrentFileName(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + whileStmt.setAllPositions(fileName, line, col, line, col); + + 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(); + String fileName = helper.getCurrentFileName(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + + DataIdentifier iterVar = new DataIdentifier(ctx.iterVar.getText()); + HashMap<String, String> parForParamValues = null; + Expression incrementExpr = new IntIdentifier(1, fileName, line, col, line, col); + if(ctx.iterPred.info.increment != null) { + incrementExpr = ctx.iterPred.info.increment; + } + IterablePredicate predicate = new IterablePredicate(iterVar, ctx.iterPred.info.from, ctx.iterPred.info.to, incrementExpr, parForParamValues, fileName, line, col, line, col); + 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; + setFileLineColumn(ctx.info.stmt, ctx); + } + + @Override + public void exitParForStatement(ParForStatementContext ctx) { + ParForStatement parForStmt = new ParForStatement(); + String fileName = helper.getCurrentFileName(); + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + + DataIdentifier iterVar = new DataIdentifier(ctx.iterVar.getText()); + HashMap<String, String> parForParamValues = new HashMap<String, String>(); + if(ctx.parForParams != null && ctx.parForParams.size() > 0) { + for(StrictParameterizedExpressionContext parForParamCtx : ctx.parForParams) { + parForParamValues.put(parForParamCtx.paramName.getText(), parForParamCtx.paramVal.getText()); + } + } + + Expression incrementExpr = new IntIdentifier(1, fileName, line, col, line, col); + + if( ctx.iterPred.info.increment != null ) { + incrementExpr = ctx.iterPred.info.increment; + } + IterablePredicate predicate = new IterablePredicate(iterVar, ctx.iterPred.info.from, ctx.iterPred.info.to, incrementExpr, parForParamValues, fileName, line, col, line, col); + 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; + setFileLineColumn(ctx.info.stmt, ctx); + } + + + @Override + public void exitDmlprogram(DmlprogramContext ctx) { } + + + // ---------------------------------------------------------------------- + @Override + public void exitValueType(ValueTypeContext ctx) { } + @Override + public void exitMl_type(Ml_typeContext ctx) { } + + private ArrayList<DataIdentifier> getFunctionParameters(List<TypedArgNoAssignContext> ctx) { + ArrayList<DataIdentifier> retVal = new ArrayList<DataIdentifier>(); + for(TypedArgNoAssignContext paramCtx : ctx) { + DataIdentifier dataId = new DataIdentifier(paramCtx.paramName.getText()); + String dataType = null; + String valueType = null; + + if(paramCtx.paramType == null || paramCtx.paramType.dataType() == null + || paramCtx.paramType.dataType().getText() == null || paramCtx.paramType.dataType().getText().isEmpty()) { + dataType = "scalar"; + } + else { + dataType = paramCtx.paramType.dataType().getText(); + } + + if(dataType.compareTo("matrix") == 0 || dataType.compareTo("Matrix") == 0) { + // matrix + dataId.setDataType(DataType.MATRIX); + } + else if(dataType.compareTo("scalar") == 0 || dataType.compareTo("Scalar") == 0) { + // scalar + dataId.setDataType(DataType.SCALAR); + } + else { + helper.notifyErrorListeners("invalid datatype " + dataType, paramCtx.start); + return null; + } + + valueType = paramCtx.paramType.valueType().getText(); + if(valueType.compareTo("int") == 0 || valueType.compareTo("integer") == 0 + || valueType.compareTo("Int") == 0 || valueType.compareTo("Integer") == 0) { + dataId.setValueType(ValueType.INT); + } + else if(valueType.compareTo("string") == 0 || valueType.compareTo("String") == 0) { + dataId.setValueType(ValueType.STRING); + } + else if(valueType.compareTo("boolean") == 0 || valueType.compareTo("Boolean") == 0) { + dataId.setValueType(ValueType.BOOLEAN); + } + else if(valueType.compareTo("double") == 0 || valueType.compareTo("Double") == 0) { + dataId.setValueType(ValueType.DOUBLE); + } + else if(valueType.compareTo("bool") == 0) { + helper.notifyErrorListeners("invalid valuetype " + valueType + " (Quickfix: use \'boolean\' instead)", paramCtx.start); + return null; + } + else { + helper.notifyErrorListeners("invalid valuetype " + valueType, paramCtx.start); + return null; + } + retVal.add(dataId); + } + return retVal; + } + + @Override + public void exitInternalFunctionDefExpression(InternalFunctionDefExpressionContext ctx) { + FunctionStatement functionStmt = new FunctionStatement(); + + ArrayList<DataIdentifier> functionInputs = getFunctionParameters(ctx.inputParams); + functionStmt.setInputParams(functionInputs); + + // set function outputs + ArrayList<DataIdentifier> functionOutputs = getFunctionParameters(ctx.outputParams); + functionStmt.setOutputParams(functionOutputs); + + // set function name + functionStmt.setName(ctx.name.getText()); + + + if(ctx.body.size() > 0) { + // handle function body + // Create arraylist of one statement block + ArrayList<StatementBlock> body = new ArrayList<StatementBlock>(); + for(StatementContext stmtCtx : ctx.body) { + body.add(getStatementBlock(stmtCtx.info.stmt)); + } + functionStmt.setBody(body); + functionStmt.mergeStatementBlocks(); + } + else { + helper.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 exitExternalFunctionDefExpression(ExternalFunctionDefExpressionContext ctx) { + ExternalFunctionStatement functionStmt = new ExternalFunctionStatement(); + + ArrayList<DataIdentifier> functionInputs = getFunctionParameters(ctx.inputParams); + functionStmt.setInputParams(functionInputs); + + // set function outputs + ArrayList<DataIdentifier> functionOutputs = getFunctionParameters(ctx.outputParams); + functionStmt.setOutputParams(functionOutputs); + + // set function name + functionStmt.setName(ctx.name.getText()); + + // set other parameters + HashMap<String, String> otherParams = new HashMap<String,String>(); + boolean atleastOneClassName = false; + for(StrictParameterizedKeyValueStringContext otherParamCtx : ctx.otherParams){ + String paramName = otherParamCtx.paramName.getText(); + String val = ""; + String text = otherParamCtx.paramVal.getText(); + // First unquote the string + if( (text.startsWith("\"") && text.endsWith("\"")) || + (text.startsWith("\'") && text.endsWith("\'"))) { + if(text.length() > 2) { + val = text.substring(1, text.length()-1); + } + // Empty value allowed + } + else { + helper.notifyErrorListeners("the value of user parameter for external function should be of type string", ctx.start); + return; + } + otherParams.put(paramName, val); + if(paramName.compareTo("classname") == 0) { + atleastOneClassName = true; + } + } + functionStmt.setOtherParams(otherParams); + if(!atleastOneClassName) { + helper.notifyErrorListeners("the parameter \'className\' needs to be passed for externalFunction", ctx.start); + return; + } + +// if(ctx.body.size() > 0) { +// // handle function body +// // Create arraylist of one statement block +// ArrayList<StatementBlock> body = new ArrayList<StatementBlock>(); +// for(StatementContext stmtCtx : ctx.body) { +// body.add(getStatementBlock(stmtCtx.info.stmt)); +// } +// ((ExternalFunctionStatement) functionStmt).setBody(body); +// ((ExternalFunctionStatement) functionStmt).mergeStatementBlocks(); +// } +// else { +// helper.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 = ctx.pathValue.getText(); + if((filePath.startsWith("\"") && filePath.endsWith("\"")) || + filePath.startsWith("'") && filePath.endsWith("'")) { + filePath = filePath.substring(1, filePath.length()-1); + } + + _workingDir = filePath; + ctx.info.stmt = stmt; + } + + @Override + public void exitIfdefAssignmentStatement(IfdefAssignmentStatementContext ctx) { + if(!ctx.commandLineParam.getText().startsWith("$")) { + helper.notifyErrorListeners("the first argument of ifdef function should be a commandline argument parameter (which starts with $)", ctx.commandLineParam.start); + return; + } + + if(ctx.targetList == null || ctx.targetList.size() != 1) { + helper.notifyErrorListeners("incorrect parsing for ifdef function", ctx.start); + return; + } + String targetListText = ctx.targetList.get(0).getText(); + if(targetListText.startsWith("$")) { + helper.notifyErrorListeners("lhs of ifdef function cannot be a commandline parameters. Use local variable instead", ctx.start); + return; + } + + DataIdentifier target = null; + if(ctx.targetList.get(0).dataInfo.expr instanceof DataIdentifier) { + target = (DataIdentifier) ctx.targetList.get(0).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; + } + + int line = ctx.start.getLine(); + int col = ctx.start.getCharPositionInLine(); + try { + ctx.info.stmt = new AssignmentStatement(target, source, line, col, line, col); + setFileLineColumn(ctx.info.stmt, ctx); + } catch (LanguageException e) { + helper.notifyErrorListeners("invalid assignment for ifdef function", ctx.targetList.get(0).start); + return; + } + + } + else { + helper.notifyErrorListeners("incorrect lvalue in ifdef function... strange", ctx.targetList.get(0).start); + return; + } + + } + + // ---------------------------------------------------------------------- + @Override + public void exitParameterizedExpression(ParameterizedExpressionContext ctx) { } + + + @Override + public void exitStrictParameterizedExpression(StrictParameterizedExpressionContext ctx) { } + + @Override + public void exitTypedArgNoAssign(TypedArgNoAssignContext ctx) { } + @Override + public void enterIfdefAssignmentStatement(IfdefAssignmentStatementContext ctx) { } + @Override + public void enterMatrixDataTypeCheck(MatrixDataTypeCheckContext ctx) { } + @Override + public void exitMatrixDataTypeCheck(MatrixDataTypeCheckContext ctx) { + if( ctx.ID().getText().compareTo("matrix") == 0 + || ctx.ID().getText().compareTo("Matrix") == 0 + || ctx.ID().getText().compareTo("Scalar") == 0 + || ctx.ID().getText().compareTo("scalar") == 0 + ) { + // Do nothing + } + else { + helper.notifyErrorListeners("incorrect datatype (expected matrix or scalar)", ctx.start); + } + } + + @Override + public void enterBuiltinFunctionExpression(BuiltinFunctionExpressionContext ctx) {} + @Override + public void enterStrictParameterizedKeyValueString(StrictParameterizedKeyValueStringContext ctx) { } + @Override + public void exitStrictParameterizedKeyValueString(StrictParameterizedKeyValueStringContext ctx) {} + @Override + public void enterIterablePredicateColonExpression(IterablePredicateColonExpressionContext ctx) {} + @Override + public void enterIterablePredicateSeqExpression(IterablePredicateSeqExpressionContext ctx) { } + + @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().compareTo("seq") != 0) { + helper.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; + ctx.info.increment = ctx.increment.info.expr; + } + + @Override + public void enterConstFalseExpression(ConstFalseExpressionContext ctx) { } + @Override + public void enterConstTrueExpression(ConstTrueExpressionContext ctx) { } + + @Override + public void exitConstFalseExpression(ConstFalseExpressionContext ctx) { + boolean val = false; + int linePosition = ctx.start.getLine(); + int charPosition = ctx.start.getCharPositionInLine(); + ctx.info.expr = new BooleanIdentifier(val, helper.getCurrentFileName(), linePosition, charPosition, linePosition, charPosition); + setFileLineColumn(ctx.info.expr, ctx); + } + + + @Override + public void exitConstTrueExpression(ConstTrueExpressionContext ctx) { + boolean val = true; + int linePosition = ctx.start.getLine(); + int charPosition = ctx.start.getCharPositionInLine(); + ctx.info.expr = new BooleanIdentifier(val, helper.getCurrentFileName(), linePosition, charPosition, linePosition, charPosition); + setFileLineColumn(ctx.info.expr, ctx); + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/c04fc99f/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidatorHelper.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidatorHelper.java b/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidatorHelper.java new file mode 100644 index 0000000..a1bd06f --- /dev/null +++ b/src/main/java/org/apache/sysml/parser/dml/DmlSyntacticValidatorHelper.java @@ -0,0 +1,108 @@ +/* + * 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.sysml.parser.dml; + +import java.util.ArrayList; +import java.util.List; + +import org.antlr.v4.runtime.Token; + +import org.apache.sysml.parser.DMLProgram; +import org.apache.sysml.parser.dml.DmlParser.FunctionCallAssignmentStatementContext; +import org.apache.sysml.parser.dml.DmlParser.ParameterizedExpressionContext; +import org.apache.sysml.parser.dml.DmlSyntacticErrorListener.CustomDmlErrorListener; + +public class DmlSyntacticValidatorHelper { + + private CustomDmlErrorListener _errorListener = null; + + public DmlSyntacticValidatorHelper(CustomDmlErrorListener errorListener) { + this._errorListener = errorListener; + } + + public void notifyErrorListeners(String message, int line, int charPositionInLine) { + this._errorListener.validationError(line, charPositionInLine, message); + } + + public void notifyErrorListeners(String message, Token op) { + this._errorListener.validationError(op.getLine(), op.getCharPositionInLine(), message); + } + + public void raiseWarning(String message, Token op) { + this._errorListener.validationWarning(op.getLine(), op.getCharPositionInLine(), message); + } + + public String getCurrentFileName() { + return _errorListener.peekFileName(); + } + +// public static void setInfoForArithmeticOp(org.apache.sysml.parser.Expression current, +// org.apache.sysml.parser.Expression left, +// org.apache.sysml.parser.Expression right, String opStr) { +// try { +// // PLUS, MINUS, MULT, DIV, MODULUS, INTDIV, MATMULT, POW, INVALID +// org.apache.sysml.parser.Expression.BinaryOp bop = org.apache.sysml.parser.Expression.getBinaryOp(opStr); +// current = new org.apache.sysml.parser.BinaryExpression(bop); +// ((org.apache.sysml.parser.BinaryExpression)current).setLeft(left); +// ((org.apache.sysml.parser.BinaryExpression)current).setRight(right); +// ((org.apache.sysml.parser.BinaryExpression)current).setFilename(DmlSyntacticErrorListener.currentFileName.peek()); +// } +// catch(Exception e) { +// System.out.println("In setInfoForArithmeticOp>>"); +// e.printStackTrace(); +// } +// } + +// public static void setInfoForBooleanOp(org.apache.sysml.parser.Expression current, +// org.apache.sysml.parser.Expression left, +// org.apache.sysml.parser.Expression right, String opStr) { +// org.apache.sysml.parser.Expression.BooleanOp bop = org.apache.sysml.parser.Expression.getBooleanOp(opStr); +// current = new org.apache.sysml.parser.BooleanExpression(bop); +// ((org.apache.sysml.parser.BooleanExpression)current).setLeft(left); +// ((org.apache.sysml.parser.BooleanExpression)current).setRight(right); +// ((org.apache.sysml.parser.BooleanExpression)current).setFilename(DmlSyntacticErrorListener.currentFileName.peek()); +// } + + public boolean validateBuiltinFunctions(FunctionCallAssignmentStatementContext ctx) { + String functionName = ctx.name.getText().replaceAll(" ", "").trim(); + if(functionName.compareTo("write") == 0 || functionName.compareTo(DMLProgram.DEFAULT_NAMESPACE + "::write") == 0) { + return validateBuiltinWriteFunction(ctx); + } + return true; + } + + private boolean validateBuiltinWriteFunction(FunctionCallAssignmentStatementContext ctx) { + + return true; + } + + public ArrayList<org.apache.sysml.parser.ParameterExpression> getParameterExpressionList(List<ParameterizedExpressionContext> paramExprs) { + ArrayList<org.apache.sysml.parser.ParameterExpression> retVal = new ArrayList<org.apache.sysml.parser.ParameterExpression>(); + for(ParameterizedExpressionContext ctx : paramExprs) { + String paramName = null; + if(ctx.paramName != null && ctx.paramName.getText() != null && !ctx.paramName.getText().isEmpty()) { + paramName = ctx.paramName.getText(); + } + org.apache.sysml.parser.ParameterExpression myArg = new org.apache.sysml.parser.ParameterExpression(paramName, ctx.paramVal.info.expr); + retVal.add(myArg); + } + return retVal; + } +} http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/c04fc99f/src/main/java/org/apache/sysml/parser/dml/ExpressionInfo.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/parser/dml/ExpressionInfo.java b/src/main/java/org/apache/sysml/parser/dml/ExpressionInfo.java new file mode 100644 index 0000000..436c409 --- /dev/null +++ b/src/main/java/org/apache/sysml/parser/dml/ExpressionInfo.java @@ -0,0 +1,31 @@ +/* + * 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.sysml.parser.dml; + + +public class ExpressionInfo { + + public org.apache.sysml.parser.Expression expr = null; + + // For parfor and for + public org.apache.sysml.parser.Expression from = null; + public org.apache.sysml.parser.Expression to = null; + public org.apache.sysml.parser.Expression increment = null; +} http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/c04fc99f/src/main/java/org/apache/sysml/parser/dml/StatementInfo.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/parser/dml/StatementInfo.java b/src/main/java/org/apache/sysml/parser/dml/StatementInfo.java new file mode 100644 index 0000000..fd4c50e --- /dev/null +++ b/src/main/java/org/apache/sysml/parser/dml/StatementInfo.java @@ -0,0 +1,36 @@ +/* + * 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.sysml.parser.dml; + +import java.util.HashMap; +import org.apache.sysml.parser.DMLProgram; + +public class StatementInfo { + + public org.apache.sysml.parser.Statement stmt = null; + + // Valid only for import statements + public HashMap<String,DMLProgram> namespaces = null; + + // Valid only for function statement + //public String namespace = DMLProgram.DEFAULT_NAMESPACE; + public String functionName = ""; + +} http://git-wip-us.apache.org/repos/asf/incubator-systemml/blob/c04fc99f/src/main/java/org/apache/sysml/parser/pydml/ExpressionInfo.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/sysml/parser/pydml/ExpressionInfo.java b/src/main/java/org/apache/sysml/parser/pydml/ExpressionInfo.java new file mode 100644 index 0000000..6cf5773 --- /dev/null +++ b/src/main/java/org/apache/sysml/parser/pydml/ExpressionInfo.java @@ -0,0 +1,32 @@ +/* + * 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.sysml.parser.pydml; + +/** + * This class exists solely to prevent compiler warnings. + * + * <p> + * The ExpressionInfo and StatementInfo classes are shared among both parsers + * (R-like and Python-like dialects), and Antlr-generated code assumes that + * these classes are present in the parser's namespace. + */ +class ExpressionInfo extends org.apache.sysml.parser.dml.ExpressionInfo { + +}
