/*
* Software Name : ATK
*
* Copyright (C) 2007 - 2012 France Télécom
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ------------------------------------------------------------------
* File Name : ValidateSyntax.java
*
* Created : 26/10/2009
* Author(s) : France Telecom
*/
package com.orange.atk.interpreter.estimators;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import com.orange.atk.interpreter.ast.ASTBOOLEAN;
import com.orange.atk.interpreter.ast.ASTCOMMENT;
import com.orange.atk.interpreter.ast.ASTFLOAT;
import com.orange.atk.interpreter.ast.ASTFUNCTION;
import com.orange.atk.interpreter.ast.ASTINCLUDE;
import com.orange.atk.interpreter.ast.ASTLOOP;
import com.orange.atk.interpreter.ast.ASTNUMBER;
import com.orange.atk.interpreter.ast.ASTSETVAR;
import com.orange.atk.interpreter.ast.ASTSTRING;
import com.orange.atk.interpreter.ast.ASTStart;
import com.orange.atk.interpreter.ast.ASTTABLE;
import com.orange.atk.interpreter.ast.ASTVARIABLE;
import com.orange.atk.interpreter.ast.FunctionDictionnary;
import com.orange.atk.interpreter.ast.Node;
import com.orange.atk.interpreter.ast.SimpleNode;
import com.orange.atk.interpreter.atkCore.ActionToExecute;
import com.orange.atk.interpreter.parser.ATKScriptParserTreeConstants;
import com.orange.atk.interpreter.parser.ATKScriptParserVisitor;
import com.orange.atk.interpreter.parser.ParseException;
import com.orange.atk.platform.Platform;
/**
* This visitor try to prevent from error during interpretation of the script.
* It verifies : <br>
* _ Negatives values for loop
* _ Undefined Variables
* _ Redefined Variables
* _ Correct
* @author tsyv5124
*
*/
public class ValidateSyntax implements ATKScriptParserVisitor {
private HashSet<String> definedVariables;
//The string[] represent the signature of the function
//string[0] is name of the function
//string[1] ..string[n] is arguments quality of the function
// keyword STRING or INTEGER or INTEGERPOSITIVE
private FunctionDictionnary functionDictionnary;
//Set it at True when The Verification is on the full Tree.
//Forget Variables Verification.
private boolean partialVerification;
private String scriptPath;
public ValidateSyntax(String scriptPath, Boolean partial) {
definedVariables = new HashSet<String>();
functionDictionnary = new FunctionDictionnary();
partialVerification = partial;
this.scriptPath = scriptPath;
}
public Object visit(SimpleNode node, Object data) {
// nothing
return null;
}
/**
* return the text which sums the errors
*/
public Object visit(ASTStart node, Object data) {
String errortext = "";
//TODO:the first node should be a StartMainlog
for (int i=0; i<node.jjtGetNumChildren() ; i++)
errortext += node.jjtGetChild(i).jjtAccept(this, data);
return errortext;
}
//nothing to do
public Object visit(ASTCOMMENT node, Object data) {
return "";
}
public Object visit(ASTFUNCTION node, Object data) {
String childerrortext="";
String functionname = node.getValue();
String errortext ="";
/* if (functionname.contains(ASTtoTSTVisitor.COUNTLINESEP))
functionname = functionname.substring(functionname.indexOf(ASTtoTSTVisitor.COUNTLINESEP)+ASTtoTSTVisitor.COUNTLINESEP.length());
Logger.getLogger(this.getClass() ).debug("VALIDATE ===========>"+functionname);*/
//build the method signature
List<String> signature = new ArrayList<String>();
signature.add(functionname);
for (int i=0; i<node.jjtGetNumChildren(); i++){
Node fils = node.jjtGetChild(i);
if(fils.jjtGetID()==ATKScriptParserTreeConstants.JJTVARIABLE) {
childerrortext += (String) fils.jjtAccept(this, data);
signature.add("UNKNOWN");
}
if( fils.jjtGetID()==ATKScriptParserTreeConstants.JJTNUMBER)
signature.add("INTEGER");
if(fils.jjtGetID()==ATKScriptParserTreeConstants.JJTSTRING )
signature.add("STRING");
if(fils.jjtGetID()==ATKScriptParserTreeConstants.JJTFLOAT )
signature.add("FLOAT");
if(fils.jjtGetID()==ATKScriptParserTreeConstants.JJTBOOLEAN)
signature.add("BOOLEAN");
}
//conclusion
if (! functionDictionnary.isExist( signature )) {
errortext="function "+functionname+" unknow. Nearly signatures : \r\n";
for(String [] el: functionDictionnary.getSignatures(signature.get(0))) {
errortext+=" "+el[0]+"(";
for (int i=1; i<el.length; i++){
if ( i!=1 )
errortext+=" , ";
errortext+=el[i];
}
errortext += ")\r\n";
}
}
return childerrortext + errortext ;
}
/**
* Add new defined variables to the table.
* Verify that's not a redefinition.
*/
public Object visit(ASTSETVAR node, Object data) {
String errortext="";
String variable = "_"+((ASTSTRING)node.jjtGetChild(0)).getValue().trim();
if (!definedVariables.add(variable))
errortext = "Variable \""+variable+
"\" already defined. \r\n";
return errortext;
}
/**
* Verify that loop repetition aren't negative.
* Continue the vérification inside the loop body
*/
public Object visit(ASTLOOP node, Object data) {
String errortext = "";
try {
int loopnumber = Integer.valueOf(((ASTNUMBER) node.jjtGetChild(0)).getValue());
if (loopnumber < 0)
errortext = "Negative loop Number ("+loopnumber+"). \r\n";
} catch(ClassCastException e){
ASTVARIABLE nodechild = ((ASTVARIABLE) node.jjtGetChild(0));
if ( !partialVerification &&
!definedVariables.contains(nodechild.getValue() ) )
errortext = "Variable "+nodechild.getValue()+" Undefined.\r\n";
}
//continue in body of the loop
for (int i=1; i<node.jjtGetNumChildren() ; i++)
errortext += node.jjtGetChild(i).jjtAccept(this, data);
return errortext;
}
//nothing to do
public Object visit(ASTSTRING node, Object data) {
return "";
}
//nothing to do
public Object visit(ASTNUMBER node, Object data) {
return "";
}
//nothing to do
public Object visit(ASTTABLE node, Object data) {
return "";
}
/**
* Verify that the variable is already defined
*/
public Object visit(ASTVARIABLE node, Object data) {
String errorString = "";
if ( !partialVerification &&
!definedVariables.contains(node.getValue().trim()) )
errorString = "Variable "+node.getValue().trim()+" undefined.\r\n";
return errorString;
}
public Object visit(ASTINCLUDE node, Object data) {
String errorString = "";
String include = ((ASTSTRING)node.jjtGetChild(0)).getValue();
try {
ActionToExecute.fetchIncludeScript(this, node, scriptPath, include);
} catch (FileNotFoundException e) {
errorString = "File "
+ include
+ " could not be include. Possible reasons are : "
+ Platform.LINE_SEP
+ " - The script must be saved before including other scripts"
+ Platform.LINE_SEP
+ " - The named file does not exist"
+ Platform.LINE_SEP
+ " - The named file is a directory rather than a regular file"
+ Platform.LINE_SEP
+ " - You do not have enough rights to read the file";
} catch (ParseException e) {
errorString = "File " + include + " is not valid";
}
return errorString;
}
public Object visit(ASTBOOLEAN node, Object data) {
return "";
}
public Object visit(ASTFLOAT node, Object data) {
return "";
}
}