mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Simplify use statement to take variable WORD only arguments
This commit is contained in:
parent
589856fbf3
commit
59f8c4109e
@ -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()
|
||||
};
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
@ -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)) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -192,6 +192,6 @@ public abstract class AbstractVisitor implements Visitor {
|
||||
|
||||
@Override
|
||||
public void visit(UseStatement st) {
|
||||
st.expression.accept(this);
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user