From ce14581bf4c1aaa226d04fa3e1c9296ba6314ac3 Mon Sep 17 00:00:00 2001 From: aNNiMON Date: Sun, 1 Oct 2023 14:42:27 +0300 Subject: [PATCH] Show linter results after validation --- .../main/java/com/annimon/ownlang/Main.java | 1 + .../com/annimon/ownlang/parser/Linter.java | 38 ------------------ .../ownlang/parser/ast/UseStatement.java | 10 +++++ .../parser/linters/AssignValidator.java | 20 +++++++--- .../DefaultFunctionsOverrideValidator.java | 21 ++++++---- .../ownlang/parser/linters/LintVisitor.java | 8 +++- .../ownlang/parser/linters/LinterResult.java | 11 ++++++ .../ownlang/parser/linters/LinterStage.java | 39 +++++++++++++++++++ .../annimon/ownlang/stages/LinterStage.java | 13 ------- 9 files changed, 96 insertions(+), 65 deletions(-) delete mode 100644 ownlang-parser/src/main/java/com/annimon/ownlang/parser/Linter.java create mode 100644 ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LinterResult.java create mode 100644 ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LinterStage.java delete mode 100644 ownlang-parser/src/main/java/com/annimon/ownlang/stages/LinterStage.java diff --git a/ownlang-desktop/src/main/java/com/annimon/ownlang/Main.java b/ownlang-desktop/src/main/java/com/annimon/ownlang/Main.java index ccd0d7a..d654436 100644 --- a/ownlang-desktop/src/main/java/com/annimon/ownlang/Main.java +++ b/ownlang-desktop/src/main/java/com/annimon/ownlang/Main.java @@ -4,6 +4,7 @@ import com.annimon.ownlang.exceptions.OwnLangParserException; import com.annimon.ownlang.exceptions.StoppedException; import com.annimon.ownlang.parser.*; import com.annimon.ownlang.parser.ast.Statement; +import com.annimon.ownlang.parser.linters.LinterStage; import com.annimon.ownlang.stages.*; import com.annimon.ownlang.utils.Repl; import com.annimon.ownlang.utils.Sandbox; diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Linter.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Linter.java deleted file mode 100644 index cb65671..0000000 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Linter.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.annimon.ownlang.parser; - -import com.annimon.ownlang.Console; -import com.annimon.ownlang.lib.ScopeHandler; -import com.annimon.ownlang.parser.ast.Statement; -import com.annimon.ownlang.parser.ast.Visitor; -import com.annimon.ownlang.parser.linters.AssignValidator; -import com.annimon.ownlang.parser.linters.DefaultFunctionsOverrideValidator; - -public final class Linter { - - public static void lint(Statement program) { - new Linter(program).execute(); - } - - private final Statement program; - - private Linter(Statement program) { - this.program = program; - } - - public void execute() { - final Visitor[] validators = new Visitor[] { - new AssignValidator(), - new DefaultFunctionsOverrideValidator() - }; - resetState(); - for (Visitor validator : validators) { - program.accept(validator); - resetState(); - } - Console.println("Lint validation complete!"); - } - - private void resetState() { - ScopeHandler.resetScope(); - } -} diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/UseStatement.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/UseStatement.java index 06c5165..c4d9054 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/UseStatement.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/UseStatement.java @@ -1,5 +1,6 @@ package com.annimon.ownlang.parser.ast; +import com.annimon.ownlang.lib.Function; import com.annimon.ownlang.lib.ModuleLoader; import com.annimon.ownlang.lib.Value; import com.annimon.ownlang.modules.Module; @@ -34,6 +35,15 @@ public final class UseStatement extends InterruptableNode implements Statement { } return result; } + + public Map loadFunctions() { + final var result = new LinkedHashMap(); + for (String moduleName : modules) { + final Module module = ModuleLoader.load(moduleName); + result.putAll(module.functions()); + } + return result; + } @Override public void accept(Visitor visitor) { diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/AssignValidator.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/AssignValidator.java index 1ce2b76..70149f1 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/AssignValidator.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/AssignValidator.java @@ -1,23 +1,31 @@ package com.annimon.ownlang.parser.linters; import com.annimon.ownlang.Console; -import com.annimon.ownlang.lib.ScopeHandler; import com.annimon.ownlang.parser.ast.*; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; /** * * @author aNNiMON */ -public final class AssignValidator extends LintVisitor { +final class AssignValidator extends LintVisitor { + + private final Set moduleConstants = new HashSet<>(); + + AssignValidator(Collection results) { + super(results); + } @Override public void visit(AssignmentExpression s) { super.visit(s); if (s.target instanceof VariableExpression varExpr) { final String variable = varExpr.name; - if (ScopeHandler.isConstantExists(variable)) { - Console.error(String.format( - "Warning: variable \"%s\" overrides constant", variable)); + if (moduleConstants.contains(variable)) { + results.add(new LinterResult(LinterResult.Severity.WARNING, + String.format("Variable \"%s\" overrides constant", variable))); } } } @@ -31,6 +39,6 @@ public final class AssignValidator extends LintVisitor { @Override public void visit(UseStatement st) { super.visit(st); - st.execute(); + moduleConstants.addAll(st.loadConstants().keySet()); } } diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/DefaultFunctionsOverrideValidator.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/DefaultFunctionsOverrideValidator.java index 285f157..f5cbde0 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/DefaultFunctionsOverrideValidator.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/DefaultFunctionsOverrideValidator.java @@ -1,17 +1,24 @@ package com.annimon.ownlang.parser.linters; -import com.annimon.ownlang.Console; -import com.annimon.ownlang.lib.ScopeHandler; import com.annimon.ownlang.parser.ast.*; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; -public final class DefaultFunctionsOverrideValidator extends LintVisitor { +final class DefaultFunctionsOverrideValidator extends LintVisitor { + + private final Set moduleFunctions = new HashSet<>(); + + DefaultFunctionsOverrideValidator(Collection results) { + super(results); + } @Override public void visit(FunctionDefineStatement s) { super.visit(s); - if (ScopeHandler.isFunctionExists(s.name)) { - Console.error(String.format( - "Warning: function \"%s\" overrides default module function", s.name)); + if (moduleFunctions.contains(s.name)) { + results.add(new LinterResult(LinterResult.Severity.WARNING, + String.format("Function \"%s\" overrides default module function", s.name))); } } @@ -24,6 +31,6 @@ public final class DefaultFunctionsOverrideValidator extends LintVisitor { @Override public void visit(UseStatement st) { super.visit(st); - st.execute(); + moduleFunctions.addAll(st.loadFunctions().keySet()); } } diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LintVisitor.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LintVisitor.java index c6fa5a9..a97f919 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LintVisitor.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LintVisitor.java @@ -5,8 +5,14 @@ import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.ast.Visitor; import com.annimon.ownlang.parser.visitors.AbstractVisitor; import com.annimon.ownlang.parser.visitors.VisitorUtils; +import java.util.Collection; -public abstract class LintVisitor extends AbstractVisitor { +abstract class LintVisitor extends AbstractVisitor { + protected final Collection results; + + LintVisitor(Collection results) { + this.results = results; + } protected void applyVisitor(IncludeStatement s, Visitor visitor) { final Statement program = VisitorUtils.includeProgram(s); diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LinterResult.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LinterResult.java new file mode 100644 index 0000000..d02d1e3 --- /dev/null +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LinterResult.java @@ -0,0 +1,11 @@ +package com.annimon.ownlang.parser.linters; + +record LinterResult(Severity severity, String message) { + + enum Severity { ERROR, WARNING } + + @Override + public String toString() { + return severity.name() + ": " + message; + } +} diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LinterStage.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LinterStage.java new file mode 100644 index 0000000..4972620 --- /dev/null +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/LinterStage.java @@ -0,0 +1,39 @@ +package com.annimon.ownlang.parser.linters; + +import com.annimon.ownlang.Console; +import com.annimon.ownlang.lib.ScopeHandler; +import com.annimon.ownlang.parser.ast.Statement; +import com.annimon.ownlang.parser.ast.Visitor; +import com.annimon.ownlang.stages.Stage; +import com.annimon.ownlang.stages.StagesData; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public class LinterStage implements Stage { + + @Override + public Statement perform(StagesData stagesData, Statement input) { + final List results = new ArrayList<>(); + final Visitor[] validators = new Visitor[] { + new AssignValidator(results), + new DefaultFunctionsOverrideValidator(results) + }; + + ScopeHandler.resetScope(); + for (Visitor validator : validators) { + input.accept(validator); + ScopeHandler.resetScope(); + } + + results.sort(Comparator.comparing(LinterResult::severity)); + Console.println(String.format("Lint validation completed. %d results found!", results.size())); + for (LinterResult r : results) { + switch (r.severity()) { + case ERROR -> Console.error(r.toString()); + case WARNING -> Console.println(r.toString()); + } + } + return input; + } +} diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/stages/LinterStage.java b/ownlang-parser/src/main/java/com/annimon/ownlang/stages/LinterStage.java deleted file mode 100644 index 66cbc96..0000000 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/stages/LinterStage.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.annimon.ownlang.stages; - -import com.annimon.ownlang.parser.Linter; -import com.annimon.ownlang.parser.ast.Statement; - -public class LinterStage implements Stage { - - @Override - public Statement perform(StagesData stagesData, Statement input) { - Linter.lint(input); - return input; - } -}