Simplify use statement to take variable WORD only arguments

This commit is contained in:
aNNiMON 2023-09-09 15:51:36 +03:00 committed by Victor Melnik
parent 589856fbf3
commit 59f8c4109e
12 changed files with 45 additions and 142 deletions

View File

@ -6,7 +6,6 @@ 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;
import com.annimon.ownlang.parser.linters.UseWithNonStringValueValidator;
public final class Linter {
@ -22,7 +21,6 @@ public final class Linter {
public void execute() {
final Visitor[] validators = new Visitor[] {
new UseWithNonStringValueValidator(),
new AssignValidator(),
new DefaultFunctionsOverrideValidator()
};

View File

@ -5,12 +5,7 @@ import com.annimon.ownlang.lib.NumberValue;
import com.annimon.ownlang.lib.StringValue;
import com.annimon.ownlang.lib.UserDefinedFunction;
import com.annimon.ownlang.parser.ast.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
*
@ -145,7 +140,7 @@ public final class Parser {
return new ReturnStatement(expression());
}
if (match(TokenType.USE)) {
return new UseStatement(expression());
return useStatement();
}
if (match(TokenType.INCLUDE)) {
return new IncludeStatement(expression());
@ -168,13 +163,21 @@ public final class Parser {
return assignmentStatement();
}
private UseStatement useStatement() {
final var modules = new HashSet<String>();
do {
modules.add(consume(TokenType.WORD).text());
} while (match(TokenType.COMMA));
return new UseStatement(modules);
}
private Statement assignmentStatement() {
if (match(TokenType.EXTRACT)) {
return destructuringAssignment();
}
final Expression expression = expression();
if (expression instanceof Statement) {
return (Statement) expression;
if (expression instanceof Statement statement) {
return statement;
}
throw new ParseException("Unknown statement: " + get(0));
}

View File

@ -1,11 +1,8 @@
package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.ArrayValue;
import com.annimon.ownlang.lib.Types;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.modules.Module;
import java.lang.reflect.Method;
import java.util.Collection;
/**
*
@ -16,24 +13,17 @@ public final class UseStatement extends InterruptableNode implements Statement {
private static final String PACKAGE = "com.annimon.ownlang.modules.%s.%s";
private static final String INIT_CONSTANTS_METHOD = "initConstants";
public final Expression expression;
public final Collection<String> modules;
public UseStatement(Expression expression) {
this.expression = expression;
public UseStatement(Collection<String> modules) {
this.modules = modules;
}
@Override
public void execute() {
super.interruptionCheck();
final Value value = expression.eval();
switch (value.type()) {
case Types.ARRAY -> {
for (Value module : ((ArrayValue) value)) {
loadModule(module.asString());
}
}
case Types.STRING -> loadModule(value.asString());
default -> throw typeException(value);
for (String module : modules) {
loadModule(module);
}
}
@ -49,20 +39,10 @@ public final class UseStatement extends InterruptableNode implements Statement {
}
public void loadConstants() {
if (expression instanceof ArrayExpression ae) {
for (Expression expr : ae.elements) {
loadConstants(expr.eval().asString());
for (String module : modules) {
loadConstants(module);
}
}
if (expression instanceof ValueExpression ve) {
loadConstants(ve.value.asString());
}
}
private TypeException typeException(Value value) {
return new TypeException("Array or string required in 'use' statement, " +
"got " + Types.typeToString(value.type()) + " " + value);
}
private void loadConstants(String moduleName) {
try {
@ -86,6 +66,6 @@ public final class UseStatement extends InterruptableNode implements Statement {
@Override
public String toString() {
return "use " + expression;
return "use " + String.join(", ", modules);
}
}

View File

@ -1,53 +0,0 @@
package com.annimon.ownlang.parser.linters;
import com.annimon.ownlang.Console;
import com.annimon.ownlang.lib.Types;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.parser.ast.*;
public final class UseWithNonStringValueValidator extends LintVisitor {
@Override
public void visit(IncludeStatement st) {
super.visit(st);
applyVisitor(st, this);
}
@Override
public void visit(UseStatement st) {
super.visit(st);
if (st.expression instanceof ArrayExpression ae) {
for (Expression expr : ae.elements) {
if (!checkExpression(expr)) {
return;
}
}
} else {
if (!checkExpression(st.expression)) {
return;
}
}
}
private boolean checkExpression(Expression expr) {
if (expr instanceof ValueExpression valueExpr) {
final Value value = valueExpr.value;
if (value.type() != Types.STRING) {
warnWrongType(value);
return false;
}
return true;
} else {
Console.error(String.format(
"Warning: `use` with %s, not ValueExpression", expr.getClass().getSimpleName()));
return false;
}
}
private void warnWrongType(Value value) {
Console.error(String.format(
"Warning: `use` with %s - %s, not string",
Types.typeToString(value.type()), value.asString()));
}
}

View File

@ -1,12 +1,7 @@
package com.annimon.ownlang.parser.optimization;
import com.annimon.ownlang.exceptions.OperationIsNotSupportedException;
import com.annimon.ownlang.parser.ast.BinaryExpression;
import com.annimon.ownlang.parser.ast.ConditionalExpression;
import com.annimon.ownlang.parser.ast.FunctionDefineStatement;
import com.annimon.ownlang.parser.ast.Node;
import com.annimon.ownlang.parser.ast.UnaryExpression;
import com.annimon.ownlang.parser.ast.ValueExpression;
import com.annimon.ownlang.parser.ast.*;
import com.annimon.ownlang.parser.visitors.VisitorUtils;
import java.util.HashSet;
import java.util.Set;
@ -104,6 +99,11 @@ public class ConstantFolding extends OptimizationVisitor<Void> implements Optimi
return super.visit(s, t);
}
@Override
public Node visit(UseStatement s, Void unused) {
return null;
}
@Override
public Node visit(FunctionDefineStatement s, Void t) {
if (OPERATORS.contains(s.name)) {

View File

@ -412,10 +412,6 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
@Override
public Node visit(UseStatement s, T t) {
final Node expression = s.expression.accept(this, t);
if (expression != s.expression) {
return new UseStatement((Expression) expression);
}
return s;
}
@ -450,8 +446,8 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
}
protected Statement consumeStatement(Node node) {
if (node instanceof Statement) {
return (Statement) node;
if (node instanceof Statement statement) {
return statement;
}
return new ExprStatement((Expression) node);
}

View File

@ -1,5 +1,6 @@
package com.annimon.ownlang.parser.optimization;
import com.annimon.ownlang.lib.ScopeHandler;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.Variables;
import com.annimon.ownlang.parser.ast.*;
@ -99,36 +100,22 @@ public class VariablesGrabber extends OptimizationVisitor<Map<String, VariableIn
@Override
public Node visit(UseStatement s, Map<String, VariableInfo> t) {
if (grabModuleConstants) {
// To get module variables we need to store current variables, clear all, then load module.
final Map<String, Value> currentVariables = new HashMap<>(Variables.variables());
Variables.variables().clear();
if (canLoadConstants(s.expression)) {
// To get module constants we need to store current constants, clear all, then load module.
final Map<String, Value> currentConstants = new HashMap<>(ScopeHandler.constants());
ScopeHandler.constants().clear();
s.loadConstants();
}
// Grab module variables
for (Map.Entry<String, Value> entry : Variables.variables().entrySet()) {
// Grab module constants
for (Map.Entry<String, Value> entry : ScopeHandler.constants().entrySet()) {
final VariableInfo var = variableInfo(t, entry.getKey());
var.value = entry.getValue();
t.put(entry.getKey(), var);
}
// Restore previous variables
Variables.variables().putAll(currentVariables);
// Restore previous constants
ScopeHandler.constants().putAll(currentConstants);
}
return super.visit(s, t);
}
private boolean canLoadConstants(Expression expression) {
if (expression instanceof ArrayExpression ae) {
for (Expression expr : ae.elements) {
if (!isValue(expr)) {
return false;
}
}
return true;
}
return isValue(expression);
}
@Override
protected boolean visit(Arguments in, Arguments out, Map<String, VariableInfo> t) {
for (Argument argument : in) {

View File

@ -192,6 +192,6 @@ public abstract class AbstractVisitor implements Visitor {
@Override
public void visit(UseStatement st) {
st.expression.accept(this);
}
}

View File

@ -23,14 +23,7 @@ public class ModuleDetector extends AbstractVisitor {
@Override
public void visit(UseStatement st) {
if (st.expression instanceof ArrayExpression ae) {
for (Expression expr : ae.elements) {
modules.add(expr.eval().asString());
}
}
if (st.expression instanceof ValueExpression ve) {
modules.add(ve.value.asString());
}
modules.addAll(st.modules);
super.visit(st);
}
}

View File

@ -358,7 +358,7 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
@Override
public StringBuilder visit(UseStatement s, StringBuilder t) {
t.append("use ");
s.expression.accept(this, t);
t.append(String.join(", ", s.modules));
return t;
}

View File

@ -30,14 +30,13 @@ public final class ModulesInfoCreator {
for (String moduleName : moduleNames) {
final String moduleClassPath = String.format("com.annimon.ownlang.modules.%s.%s", moduleName, moduleName);
Class<?> moduleClass = Class.forName(moduleClassPath);
Functions.getFunctions().clear();
Variables.variables().clear();
ScopeHandler.resetScope();
final Module module = (Module) moduleClass.getDeclaredConstructor().newInstance();
module.init();
final ModuleInfo moduleInfo = new ModuleInfo(moduleName);
moduleInfo.functions.addAll(Functions.getFunctions().keySet());
moduleInfo.constants.putAll(Variables.variables());
moduleInfo.functions.addAll(ScopeHandler.functions().keySet());
moduleInfo.constants.putAll(ScopeHandler.constants());
moduleInfo.types.addAll(listValues(moduleClass));
moduleInfos.add(moduleInfo);
}

View File

@ -135,7 +135,7 @@ public final class Repl {
final int maxCols = 2;
final int size = commands.size();
for (int i = 0; i < size; i += maxCols) {
// Pad to max length and print in tab-separatex maxCols columns
// Pad to max length and print in tab-separated maxCols columns
System.out.println(commands
.subList(i, Math.min(size, i + maxCols))
.stream()