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.ast.Visitor;
|
||||||
import com.annimon.ownlang.parser.linters.AssignValidator;
|
import com.annimon.ownlang.parser.linters.AssignValidator;
|
||||||
import com.annimon.ownlang.parser.linters.DefaultFunctionsOverrideValidator;
|
import com.annimon.ownlang.parser.linters.DefaultFunctionsOverrideValidator;
|
||||||
import com.annimon.ownlang.parser.linters.UseWithNonStringValueValidator;
|
|
||||||
|
|
||||||
public final class Linter {
|
public final class Linter {
|
||||||
|
|
||||||
@ -22,7 +21,6 @@ public final class Linter {
|
|||||||
|
|
||||||
public void execute() {
|
public void execute() {
|
||||||
final Visitor[] validators = new Visitor[] {
|
final Visitor[] validators = new Visitor[] {
|
||||||
new UseWithNonStringValueValidator(),
|
|
||||||
new AssignValidator(),
|
new AssignValidator(),
|
||||||
new DefaultFunctionsOverrideValidator()
|
new DefaultFunctionsOverrideValidator()
|
||||||
};
|
};
|
||||||
|
@ -5,12 +5,7 @@ import com.annimon.ownlang.lib.NumberValue;
|
|||||||
import com.annimon.ownlang.lib.StringValue;
|
import com.annimon.ownlang.lib.StringValue;
|
||||||
import com.annimon.ownlang.lib.UserDefinedFunction;
|
import com.annimon.ownlang.lib.UserDefinedFunction;
|
||||||
import com.annimon.ownlang.parser.ast.*;
|
import com.annimon.ownlang.parser.ast.*;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.EnumMap;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -145,7 +140,7 @@ public final class Parser {
|
|||||||
return new ReturnStatement(expression());
|
return new ReturnStatement(expression());
|
||||||
}
|
}
|
||||||
if (match(TokenType.USE)) {
|
if (match(TokenType.USE)) {
|
||||||
return new UseStatement(expression());
|
return useStatement();
|
||||||
}
|
}
|
||||||
if (match(TokenType.INCLUDE)) {
|
if (match(TokenType.INCLUDE)) {
|
||||||
return new IncludeStatement(expression());
|
return new IncludeStatement(expression());
|
||||||
@ -168,13 +163,21 @@ public final class Parser {
|
|||||||
return assignmentStatement();
|
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() {
|
private Statement assignmentStatement() {
|
||||||
if (match(TokenType.EXTRACT)) {
|
if (match(TokenType.EXTRACT)) {
|
||||||
return destructuringAssignment();
|
return destructuringAssignment();
|
||||||
}
|
}
|
||||||
final Expression expression = expression();
|
final Expression expression = expression();
|
||||||
if (expression instanceof Statement) {
|
if (expression instanceof Statement statement) {
|
||||||
return (Statement) expression;
|
return statement;
|
||||||
}
|
}
|
||||||
throw new ParseException("Unknown statement: " + get(0));
|
throw new ParseException("Unknown statement: " + get(0));
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
package com.annimon.ownlang.parser.ast;
|
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 com.annimon.ownlang.modules.Module;
|
||||||
import java.lang.reflect.Method;
|
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 PACKAGE = "com.annimon.ownlang.modules.%s.%s";
|
||||||
private static final String INIT_CONSTANTS_METHOD = "initConstants";
|
private static final String INIT_CONSTANTS_METHOD = "initConstants";
|
||||||
|
|
||||||
public final Expression expression;
|
public final Collection<String> modules;
|
||||||
|
|
||||||
public UseStatement(Expression expression) {
|
public UseStatement(Collection<String> modules) {
|
||||||
this.expression = expression;
|
this.modules = modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
super.interruptionCheck();
|
super.interruptionCheck();
|
||||||
final Value value = expression.eval();
|
for (String module : modules) {
|
||||||
switch (value.type()) {
|
loadModule(module);
|
||||||
case Types.ARRAY -> {
|
|
||||||
for (Value module : ((ArrayValue) value)) {
|
|
||||||
loadModule(module.asString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case Types.STRING -> loadModule(value.asString());
|
|
||||||
default -> throw typeException(value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,19 +39,9 @@ public final class UseStatement extends InterruptableNode implements Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void loadConstants() {
|
public void loadConstants() {
|
||||||
if (expression instanceof ArrayExpression ae) {
|
for (String module : modules) {
|
||||||
for (Expression expr : ae.elements) {
|
loadConstants(module);
|
||||||
loadConstants(expr.eval().asString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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) {
|
private void loadConstants(String moduleName) {
|
||||||
@ -86,6 +66,6 @@ public final class UseStatement extends InterruptableNode implements Statement {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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;
|
package com.annimon.ownlang.parser.optimization;
|
||||||
|
|
||||||
import com.annimon.ownlang.exceptions.OperationIsNotSupportedException;
|
import com.annimon.ownlang.exceptions.OperationIsNotSupportedException;
|
||||||
import com.annimon.ownlang.parser.ast.BinaryExpression;
|
import com.annimon.ownlang.parser.ast.*;
|
||||||
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.visitors.VisitorUtils;
|
import com.annimon.ownlang.parser.visitors.VisitorUtils;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -104,6 +99,11 @@ public class ConstantFolding extends OptimizationVisitor<Void> implements Optimi
|
|||||||
return super.visit(s, t);
|
return super.visit(s, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node visit(UseStatement s, Void unused) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node visit(FunctionDefineStatement s, Void t) {
|
public Node visit(FunctionDefineStatement s, Void t) {
|
||||||
if (OPERATORS.contains(s.name)) {
|
if (OPERATORS.contains(s.name)) {
|
||||||
|
@ -412,10 +412,6 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node visit(UseStatement s, T t) {
|
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;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,8 +446,8 @@ public abstract class OptimizationVisitor<T> implements ResultVisitor<Node, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Statement consumeStatement(Node node) {
|
protected Statement consumeStatement(Node node) {
|
||||||
if (node instanceof Statement) {
|
if (node instanceof Statement statement) {
|
||||||
return (Statement) node;
|
return statement;
|
||||||
}
|
}
|
||||||
return new ExprStatement((Expression) node);
|
return new ExprStatement((Expression) node);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.annimon.ownlang.parser.optimization;
|
package com.annimon.ownlang.parser.optimization;
|
||||||
|
|
||||||
|
import com.annimon.ownlang.lib.ScopeHandler;
|
||||||
import com.annimon.ownlang.lib.Value;
|
import com.annimon.ownlang.lib.Value;
|
||||||
import com.annimon.ownlang.lib.Variables;
|
import com.annimon.ownlang.lib.Variables;
|
||||||
import com.annimon.ownlang.parser.ast.*;
|
import com.annimon.ownlang.parser.ast.*;
|
||||||
@ -99,36 +100,22 @@ public class VariablesGrabber extends OptimizationVisitor<Map<String, VariableIn
|
|||||||
@Override
|
@Override
|
||||||
public Node visit(UseStatement s, Map<String, VariableInfo> t) {
|
public Node visit(UseStatement s, Map<String, VariableInfo> t) {
|
||||||
if (grabModuleConstants) {
|
if (grabModuleConstants) {
|
||||||
// To get module variables we need to store current variables, clear all, then load module.
|
// To get module constants we need to store current constants, clear all, then load module.
|
||||||
final Map<String, Value> currentVariables = new HashMap<>(Variables.variables());
|
final Map<String, Value> currentConstants = new HashMap<>(ScopeHandler.constants());
|
||||||
Variables.variables().clear();
|
ScopeHandler.constants().clear();
|
||||||
if (canLoadConstants(s.expression)) {
|
s.loadConstants();
|
||||||
s.loadConstants();
|
// Grab module constants
|
||||||
}
|
for (Map.Entry<String, Value> entry : ScopeHandler.constants().entrySet()) {
|
||||||
// Grab module variables
|
|
||||||
for (Map.Entry<String, Value> entry : Variables.variables().entrySet()) {
|
|
||||||
final VariableInfo var = variableInfo(t, entry.getKey());
|
final VariableInfo var = variableInfo(t, entry.getKey());
|
||||||
var.value = entry.getValue();
|
var.value = entry.getValue();
|
||||||
t.put(entry.getKey(), var);
|
t.put(entry.getKey(), var);
|
||||||
}
|
}
|
||||||
// Restore previous variables
|
// Restore previous constants
|
||||||
Variables.variables().putAll(currentVariables);
|
ScopeHandler.constants().putAll(currentConstants);
|
||||||
}
|
}
|
||||||
return super.visit(s, t);
|
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
|
@Override
|
||||||
protected boolean visit(Arguments in, Arguments out, Map<String, VariableInfo> t) {
|
protected boolean visit(Arguments in, Arguments out, Map<String, VariableInfo> t) {
|
||||||
for (Argument argument : in) {
|
for (Argument argument : in) {
|
||||||
|
@ -192,6 +192,6 @@ public abstract class AbstractVisitor implements Visitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(UseStatement st) {
|
public void visit(UseStatement st) {
|
||||||
st.expression.accept(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,14 +23,7 @@ public class ModuleDetector extends AbstractVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(UseStatement st) {
|
public void visit(UseStatement st) {
|
||||||
if (st.expression instanceof ArrayExpression ae) {
|
modules.addAll(st.modules);
|
||||||
for (Expression expr : ae.elements) {
|
|
||||||
modules.add(expr.eval().asString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (st.expression instanceof ValueExpression ve) {
|
|
||||||
modules.add(ve.value.asString());
|
|
||||||
}
|
|
||||||
super.visit(st);
|
super.visit(st);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,7 +358,7 @@ public class PrintVisitor implements ResultVisitor<StringBuilder, StringBuilder>
|
|||||||
@Override
|
@Override
|
||||||
public StringBuilder visit(UseStatement s, StringBuilder t) {
|
public StringBuilder visit(UseStatement s, StringBuilder t) {
|
||||||
t.append("use ");
|
t.append("use ");
|
||||||
s.expression.accept(this, t);
|
t.append(String.join(", ", s.modules));
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,14 +30,13 @@ public final class ModulesInfoCreator {
|
|||||||
for (String moduleName : moduleNames) {
|
for (String moduleName : moduleNames) {
|
||||||
final String moduleClassPath = String.format("com.annimon.ownlang.modules.%s.%s", moduleName, moduleName);
|
final String moduleClassPath = String.format("com.annimon.ownlang.modules.%s.%s", moduleName, moduleName);
|
||||||
Class<?> moduleClass = Class.forName(moduleClassPath);
|
Class<?> moduleClass = Class.forName(moduleClassPath);
|
||||||
Functions.getFunctions().clear();
|
ScopeHandler.resetScope();
|
||||||
Variables.variables().clear();
|
|
||||||
final Module module = (Module) moduleClass.getDeclaredConstructor().newInstance();
|
final Module module = (Module) moduleClass.getDeclaredConstructor().newInstance();
|
||||||
module.init();
|
module.init();
|
||||||
|
|
||||||
final ModuleInfo moduleInfo = new ModuleInfo(moduleName);
|
final ModuleInfo moduleInfo = new ModuleInfo(moduleName);
|
||||||
moduleInfo.functions.addAll(Functions.getFunctions().keySet());
|
moduleInfo.functions.addAll(ScopeHandler.functions().keySet());
|
||||||
moduleInfo.constants.putAll(Variables.variables());
|
moduleInfo.constants.putAll(ScopeHandler.constants());
|
||||||
moduleInfo.types.addAll(listValues(moduleClass));
|
moduleInfo.types.addAll(listValues(moduleClass));
|
||||||
moduleInfos.add(moduleInfo);
|
moduleInfos.add(moduleInfo);
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ public final class Repl {
|
|||||||
final int maxCols = 2;
|
final int maxCols = 2;
|
||||||
final int size = commands.size();
|
final int size = commands.size();
|
||||||
for (int i = 0; i < size; i += maxCols) {
|
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
|
System.out.println(commands
|
||||||
.subList(i, Math.min(size, i + maxCols))
|
.subList(i, Math.min(size, i + maxCols))
|
||||||
.stream()
|
.stream()
|
||||||
|
Loading…
Reference in New Issue
Block a user