Show linter results after validation

This commit is contained in:
aNNiMON 2023-10-01 14:42:27 +03:00 committed by Victor Melnik
parent 2578f0a6b4
commit ce14581bf4
9 changed files with 96 additions and 65 deletions

View File

@ -4,6 +4,7 @@ import com.annimon.ownlang.exceptions.OwnLangParserException;
import com.annimon.ownlang.exceptions.StoppedException; import com.annimon.ownlang.exceptions.StoppedException;
import com.annimon.ownlang.parser.*; import com.annimon.ownlang.parser.*;
import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.ast.Statement;
import com.annimon.ownlang.parser.linters.LinterStage;
import com.annimon.ownlang.stages.*; import com.annimon.ownlang.stages.*;
import com.annimon.ownlang.utils.Repl; import com.annimon.ownlang.utils.Repl;
import com.annimon.ownlang.utils.Sandbox; import com.annimon.ownlang.utils.Sandbox;

View File

@ -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();
}
}

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.parser.ast; package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.lib.Function;
import com.annimon.ownlang.lib.ModuleLoader; import com.annimon.ownlang.lib.ModuleLoader;
import com.annimon.ownlang.lib.Value; import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.modules.Module; import com.annimon.ownlang.modules.Module;
@ -35,6 +36,15 @@ public final class UseStatement extends InterruptableNode implements Statement {
return result; return result;
} }
public Map<String, Function> loadFunctions() {
final var result = new LinkedHashMap<String, Function>();
for (String moduleName : modules) {
final Module module = ModuleLoader.load(moduleName);
result.putAll(module.functions());
}
return result;
}
@Override @Override
public void accept(Visitor visitor) { public void accept(Visitor visitor) {
visitor.visit(this); visitor.visit(this);

View File

@ -1,23 +1,31 @@
package com.annimon.ownlang.parser.linters; package com.annimon.ownlang.parser.linters;
import com.annimon.ownlang.Console; import com.annimon.ownlang.Console;
import com.annimon.ownlang.lib.ScopeHandler;
import com.annimon.ownlang.parser.ast.*; import com.annimon.ownlang.parser.ast.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/** /**
* *
* @author aNNiMON * @author aNNiMON
*/ */
public final class AssignValidator extends LintVisitor { final class AssignValidator extends LintVisitor {
private final Set<String> moduleConstants = new HashSet<>();
AssignValidator(Collection<LinterResult> results) {
super(results);
}
@Override @Override
public void visit(AssignmentExpression s) { public void visit(AssignmentExpression s) {
super.visit(s); super.visit(s);
if (s.target instanceof VariableExpression varExpr) { if (s.target instanceof VariableExpression varExpr) {
final String variable = varExpr.name; final String variable = varExpr.name;
if (ScopeHandler.isConstantExists(variable)) { if (moduleConstants.contains(variable)) {
Console.error(String.format( results.add(new LinterResult(LinterResult.Severity.WARNING,
"Warning: variable \"%s\" overrides constant", variable)); String.format("Variable \"%s\" overrides constant", variable)));
} }
} }
} }
@ -31,6 +39,6 @@ public final class AssignValidator extends LintVisitor {
@Override @Override
public void visit(UseStatement st) { public void visit(UseStatement st) {
super.visit(st); super.visit(st);
st.execute(); moduleConstants.addAll(st.loadConstants().keySet());
} }
} }

View File

@ -1,17 +1,24 @@
package com.annimon.ownlang.parser.linters; package com.annimon.ownlang.parser.linters;
import com.annimon.ownlang.Console;
import com.annimon.ownlang.lib.ScopeHandler;
import com.annimon.ownlang.parser.ast.*; 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<String> moduleFunctions = new HashSet<>();
DefaultFunctionsOverrideValidator(Collection<LinterResult> results) {
super(results);
}
@Override @Override
public void visit(FunctionDefineStatement s) { public void visit(FunctionDefineStatement s) {
super.visit(s); super.visit(s);
if (ScopeHandler.isFunctionExists(s.name)) { if (moduleFunctions.contains(s.name)) {
Console.error(String.format( results.add(new LinterResult(LinterResult.Severity.WARNING,
"Warning: function \"%s\" overrides default module function", s.name)); String.format("Function \"%s\" overrides default module function", s.name)));
} }
} }
@ -24,6 +31,6 @@ public final class DefaultFunctionsOverrideValidator extends LintVisitor {
@Override @Override
public void visit(UseStatement st) { public void visit(UseStatement st) {
super.visit(st); super.visit(st);
st.execute(); moduleFunctions.addAll(st.loadFunctions().keySet());
} }
} }

View File

@ -5,8 +5,14 @@ import com.annimon.ownlang.parser.ast.Statement;
import com.annimon.ownlang.parser.ast.Visitor; import com.annimon.ownlang.parser.ast.Visitor;
import com.annimon.ownlang.parser.visitors.AbstractVisitor; import com.annimon.ownlang.parser.visitors.AbstractVisitor;
import com.annimon.ownlang.parser.visitors.VisitorUtils; 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<LinterResult> results;
LintVisitor(Collection<LinterResult> results) {
this.results = results;
}
protected void applyVisitor(IncludeStatement s, Visitor visitor) { protected void applyVisitor(IncludeStatement s, Visitor visitor) {
final Statement program = VisitorUtils.includeProgram(s); final Statement program = VisitorUtils.includeProgram(s);

View File

@ -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;
}
}

View File

@ -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<Statement, Statement> {
@Override
public Statement perform(StagesData stagesData, Statement input) {
final List<LinterResult> 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;
}
}

View File

@ -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<Statement, Statement> {
@Override
public Statement perform(StagesData stagesData, Statement input) {
Linter.lint(input);
return input;
}
}