diff --git a/src/cz/zipek/sqflint/SQFLint.java b/src/cz/zipek/sqflint/SQFLint.java index 3b025b4..6bc8378 100644 --- a/src/cz/zipek/sqflint/SQFLint.java +++ b/src/cz/zipek/sqflint/SQFLint.java @@ -1,8 +1,10 @@ package cz.zipek.sqflint; import cz.zipek.sqflint.linter.Linter; +import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Paths; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.cli.CommandLine; @@ -30,6 +32,8 @@ public static void main(String[] args) { options.addOption("nw", "no-warning", false, "skip warnings"); options.addOption("we", "warning-as-error", false, "output warnings as errors"); options.addOption("oc", "output-code", false, "output ERR return code when any error is encountered"); + options.addOption("cp", "check-paths", false, "check for path existence for exevm and preprocessfile"); + options.addOption("r", "root", true, "root for path checking (path to file is used if file is specified)"); options.addOption("h", "help", false, ""); try { @@ -51,9 +55,11 @@ public static void main(String[] args) { linter = new Linter(System.in); } else if (cmd.getArgs().length == 1) { String filename = cmd.getArgs()[0]; + String root = Paths.get(filename).toAbsolutePath().getParent().toString(); try { linter = new Linter(new java.io.FileInputStream(filename)); + linter.setRootPath(root); } catch (FileNotFoundException ex) { System.out.println("SQF Parser Version 1.1: File " + filename + " not found."); } @@ -66,6 +72,11 @@ public static void main(String[] args) { linter.setOutputVariables(cmd.hasOption("v")); linter.setExitCodeEnabled(cmd.hasOption("oc")); linter.setWarningAsError(cmd.hasOption("we")); + linter.setCheckPaths(cmd.hasOption("cp")); + + if (cmd.hasOption("r")) { + linter.setRootPath(cmd.getOptionValue("r")); + } try { System.exit(linter.start()); diff --git a/src/cz/zipek/sqflint/linter/Linter.java b/src/cz/zipek/sqflint/linter/Linter.java index e5cee1c..d180b97 100644 --- a/src/cz/zipek/sqflint/linter/Linter.java +++ b/src/cz/zipek/sqflint/linter/Linter.java @@ -10,6 +10,7 @@ import cz.zipek.sqflint.parser.TokenMgrError; import cz.zipek.sqflint.preprocessor.SQFInclude; import cz.zipek.sqflint.preprocessor.SQFMacro; +import cz.zipek.sqflint.sqf.operators.ExecVMOperator; import cz.zipek.sqflint.sqf.operators.Operator; import cz.zipek.sqflint.sqf.operators.ParamsOperator; import java.io.BufferedReader; @@ -40,6 +41,8 @@ public class Linter extends SQFParser { private boolean outputVariables = false; private boolean exitCodeEnabled = false; private boolean warningAsError = false; + private boolean checkPaths = false; + private String rootPath = null; private final Map commands = new HashMap<>(); private final Set ignoredVariables = new HashSet<>(); @@ -59,6 +62,7 @@ public Linter(InputStream stream) { ignoredVariables.addAll(Arrays.asList(new String[] { "_this", "_x", "_foreachindex" })); operators.put("params", new ParamsOperator()); + operators.put("execvm", new ExecVMOperator()); } public int start() throws IOException { @@ -377,4 +381,32 @@ public void setWarningAsError(boolean warningAsError) { public Map getOperators() { return operators; } + + /** + * @return the checkPaths + */ + public boolean isCheckPaths() { + return checkPaths; + } + + /** + * @param checkPaths the checkPaths to set + */ + public void setCheckPaths(boolean checkPaths) { + this.checkPaths = checkPaths; + } + + /** + * @return the rootPath + */ + public String getRootPath() { + return rootPath; + } + + /** + * @param rootPath the rootPath to set + */ + public void setRootPath(String rootPath) { + this.rootPath = rootPath; + } } diff --git a/src/cz/zipek/sqflint/sqf/SQFExpression.java b/src/cz/zipek/sqflint/sqf/SQFExpression.java index 65ad752..66939b1 100644 --- a/src/cz/zipek/sqflint/sqf/SQFExpression.java +++ b/src/cz/zipek/sqflint/sqf/SQFExpression.java @@ -101,5 +101,10 @@ public void analyze(Linter source, SQFBlock context) { source.getOperators().get(ident).analyze(source, context, this); } } + + // We're going left to right + if (right != null) { + right.analyze(source, context); + } } } diff --git a/src/cz/zipek/sqflint/sqf/SQFForExpressionStatement.java b/src/cz/zipek/sqflint/sqf/SQFForExpressionStatement.java index 5b27531..35abb2f 100644 --- a/src/cz/zipek/sqflint/sqf/SQFForExpressionStatement.java +++ b/src/cz/zipek/sqflint/sqf/SQFForExpressionStatement.java @@ -80,7 +80,7 @@ && getVariable().getMain() instanceof SQFString) { SQFString lit = (SQFString)getVariable().getMain(); String ident = lit.getStringContents() .toLowerCase(); - + SQFVariable var = source.getVariable(ident); var.usage.add(lit.getContents()); var.definitions.add(lit.getContents()); diff --git a/src/cz/zipek/sqflint/sqf/SQFWhileStatement.java b/src/cz/zipek/sqflint/sqf/SQFWhileStatement.java index 670c29e..34d9199 100644 --- a/src/cz/zipek/sqflint/sqf/SQFWhileStatement.java +++ b/src/cz/zipek/sqflint/sqf/SQFWhileStatement.java @@ -23,6 +23,8 @@ */ package cz.zipek.sqflint.sqf; +import cz.zipek.sqflint.linter.Linter; + /** * * @author Jan Zípek @@ -35,4 +37,11 @@ public SQFWhileStatement(SQFBlock cond, SQFBlock bl) { condition = cond; block = bl; } + + @Override + public void analyze(Linter source, SQFBlock context) { + if (condition != null) condition.analyze(source, context); + if (block != null) block.analyze(source, context); + } + } diff --git a/src/cz/zipek/sqflint/sqf/operators/ExecVMOperator.java b/src/cz/zipek/sqflint/sqf/operators/ExecVMOperator.java new file mode 100644 index 0000000..7e9ca54 --- /dev/null +++ b/src/cz/zipek/sqflint/sqf/operators/ExecVMOperator.java @@ -0,0 +1,56 @@ +/* + * The MIT License + * + * Copyright 2016 Jan Zípek . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package cz.zipek.sqflint.sqf.operators; + +import cz.zipek.sqflint.linter.Linter; +import cz.zipek.sqflint.linter.Warning; +import cz.zipek.sqflint.parser.Token; +import cz.zipek.sqflint.sqf.SQFBlock; +import cz.zipek.sqflint.sqf.SQFExpression; +import cz.zipek.sqflint.sqf.SQFLiteral; +import cz.zipek.sqflint.sqf.SQFString; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * + * @author Jan Zípek + */ +public class ExecVMOperator extends Operator { + @Override + public void analyze(Linter source, SQFBlock context, SQFExpression expression) { + // Check for existence of loaded file, if allowed + if (source.isCheckPaths() && source.getRootPath() != null) { + if (expression.getRight() != null + && expression.getRight().getMain() != null + && expression.getRight().getMain() instanceof SQFString + ) { + SQFString param = (SQFString)expression.getRight().getMain(); + if (!Files.exists(Paths.get(source.getRootPath(), param.getStringContents()))) { + source.getWarnings().add(new Warning(param.getContents(), "File '" + param.getStringContents() + "' doesn't exists.")); + } + } + } + } +}