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 index ba2dee1..cb65671 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Linter.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Linter.java @@ -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() }; diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Parser.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Parser.java index 0f70be0..626b0f5 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Parser.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/Parser.java @@ -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(); + 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)); } 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 d381dc1..69e30cf 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,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 modules; - public UseStatement(Expression expression) { - this.expression = expression; + public UseStatement(Collection 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,19 +39,9 @@ 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) { @@ -86,6 +66,6 @@ public final class UseStatement extends InterruptableNode implements Statement { @Override public String toString() { - return "use " + expression; + return "use " + String.join(", ", modules); } } diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/UseWithNonStringValueValidator.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/UseWithNonStringValueValidator.java deleted file mode 100644 index a8b2441..0000000 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/linters/UseWithNonStringValueValidator.java +++ /dev/null @@ -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())); - } -} diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/ConstantFolding.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/ConstantFolding.java index b0f06af..ea25ce5 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/ConstantFolding.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/ConstantFolding.java @@ -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 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)) { diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java index 6fb81e3..a903fa8 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java @@ -412,10 +412,6 @@ public abstract class OptimizationVisitor implements ResultVisitor { @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 implements ResultVisitor { } protected Statement consumeStatement(Node node) { - if (node instanceof Statement) { - return (Statement) node; + if (node instanceof Statement statement) { + return statement; } return new ExprStatement((Expression) node); } diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/VariablesGrabber.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/VariablesGrabber.java index 7e753a5..38b6c66 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/VariablesGrabber.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/optimization/VariablesGrabber.java @@ -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 t) { if (grabModuleConstants) { - // To get module variables we need to store current variables, clear all, then load module. - final Map currentVariables = new HashMap<>(Variables.variables()); - Variables.variables().clear(); - if (canLoadConstants(s.expression)) { - s.loadConstants(); - } - // Grab module variables - for (Map.Entry entry : Variables.variables().entrySet()) { + // To get module constants we need to store current constants, clear all, then load module. + final Map currentConstants = new HashMap<>(ScopeHandler.constants()); + ScopeHandler.constants().clear(); + s.loadConstants(); + // Grab module constants + for (Map.Entry 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 t) { for (Argument argument : in) { diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/AbstractVisitor.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/AbstractVisitor.java index 6455abf..11b17fd 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/AbstractVisitor.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/AbstractVisitor.java @@ -192,6 +192,6 @@ public abstract class AbstractVisitor implements Visitor { @Override public void visit(UseStatement st) { - st.expression.accept(this); + } } \ No newline at end of file diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/ModuleDetector.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/ModuleDetector.java index 3bfce12..f399392 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/ModuleDetector.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/ModuleDetector.java @@ -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); } } diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/PrintVisitor.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/PrintVisitor.java index 1da2dcc..093c0d8 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/PrintVisitor.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/visitors/PrintVisitor.java @@ -358,7 +358,7 @@ public class PrintVisitor implements ResultVisitor @Override public StringBuilder visit(UseStatement s, StringBuilder t) { t.append("use "); - s.expression.accept(this, t); + t.append(String.join(", ", s.modules)); return t; } diff --git a/ownlang-utils/src/main/java/com/annimon/ownlang/utils/ModulesInfoCreator.java b/ownlang-utils/src/main/java/com/annimon/ownlang/utils/ModulesInfoCreator.java index 333f4bf..d119fd3 100644 --- a/ownlang-utils/src/main/java/com/annimon/ownlang/utils/ModulesInfoCreator.java +++ b/ownlang-utils/src/main/java/com/annimon/ownlang/utils/ModulesInfoCreator.java @@ -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); } diff --git a/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Repl.java b/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Repl.java index fd4c503..10ee60e 100644 --- a/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Repl.java +++ b/ownlang-utils/src/main/java/com/annimon/ownlang/utils/Repl.java @@ -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()