mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Show linter results after validation
This commit is contained in:
parent
2578f0a6b4
commit
ce14581bf4
@ -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;
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
||||||
@ -34,6 +35,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) {
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user