Ver Fonte

剔除脚本部分

mxd há 5 anos atrás
pai
commit
98c7597888
82 ficheiros alterados com 16 adições e 4937 exclusões
  1. 5 0
      pom.xml
  2. 1 1
      src/main/java/org/ssssssss/magicapi/cache/SqlCache.java
  3. 1 1
      src/main/java/org/ssssssss/magicapi/dialect/DB2Dialect.java
  4. 1 1
      src/main/java/org/ssssssss/magicapi/dialect/Dialect.java
  5. 1 1
      src/main/java/org/ssssssss/magicapi/dialect/MySQLDialect.java
  6. 1 1
      src/main/java/org/ssssssss/magicapi/dialect/OracleDialect.java
  7. 1 1
      src/main/java/org/ssssssss/magicapi/dialect/PostgreSQLDialect.java
  8. 1 1
      src/main/java/org/ssssssss/magicapi/dialect/SQLServer2005Dialect.java
  9. 1 1
      src/main/java/org/ssssssss/magicapi/dialect/SQLServerDialect.java
  10. 1 1
      src/main/java/org/ssssssss/magicapi/functions/AssertFunctions.java
  11. 2 1
      src/main/java/org/ssssssss/magicapi/functions/DatabaseQuery.java
  12. 0 34
      src/main/java/org/ssssssss/script/MagicModuleLoader.java
  13. 0 31
      src/main/java/org/ssssssss/script/MagicScript.java
  14. 0 139
      src/main/java/org/ssssssss/script/MagicScriptContext.java
  15. 0 134
      src/main/java/org/ssssssss/script/MagicScriptDebugContext.java
  16. 0 64
      src/main/java/org/ssssssss/script/MagicScriptEngine.java
  17. 0 75
      src/main/java/org/ssssssss/script/MagicScriptError.java
  18. 0 9
      src/main/java/org/ssssssss/script/annotation/UnableCall.java
  19. 0 12
      src/main/java/org/ssssssss/script/exception/DebugTimeoutException.java
  20. 0 23
      src/main/java/org/ssssssss/script/exception/MagicScriptAssertException.java
  21. 0 40
      src/main/java/org/ssssssss/script/exception/MagicScriptException.java
  22. 0 10
      src/main/java/org/ssssssss/script/exception/ModuleNotFoundException.java
  23. 0 7
      src/main/java/org/ssssssss/script/exception/StringLiteralException.java
  24. 0 72
      src/main/java/org/ssssssss/script/functions/StreamExtension.java
  25. 0 52
      src/main/java/org/ssssssss/script/interpreter/AbstractReflection.java
  26. 0 77
      src/main/java/org/ssssssss/script/interpreter/AstInterpreter.java
  27. 0 514
      src/main/java/org/ssssssss/script/interpreter/JavaReflection.java
  28. 0 248
      src/main/java/org/ssssssss/script/parsing/CharacterStream.java
  29. 0 68
      src/main/java/org/ssssssss/script/parsing/GenericTokenParser.java
  30. 0 464
      src/main/java/org/ssssssss/script/parsing/Parser.java
  31. 0 222
      src/main/java/org/ssssssss/script/parsing/Span.java
  32. 0 31
      src/main/java/org/ssssssss/script/parsing/Token.java
  33. 0 189
      src/main/java/org/ssssssss/script/parsing/TokenStream.java
  34. 0 114
      src/main/java/org/ssssssss/script/parsing/TokenType.java
  35. 0 177
      src/main/java/org/ssssssss/script/parsing/Tokenizer.java
  36. 0 22
      src/main/java/org/ssssssss/script/parsing/ast/BooleanLiteral.java
  37. 0 17
      src/main/java/org/ssssssss/script/parsing/ast/Break.java
  38. 0 22
      src/main/java/org/ssssssss/script/parsing/ast/ByteLiteral.java
  39. 0 42
      src/main/java/org/ssssssss/script/parsing/ast/CharacterLiteral.java
  40. 0 17
      src/main/java/org/ssssssss/script/parsing/ast/Continue.java
  41. 0 22
      src/main/java/org/ssssssss/script/parsing/ast/DoubleLiteral.java
  42. 0 9
      src/main/java/org/ssssssss/script/parsing/ast/Expression.java
  43. 0 26
      src/main/java/org/ssssssss/script/parsing/ast/FloatLiteral.java
  44. 0 179
      src/main/java/org/ssssssss/script/parsing/ast/ForStatement.java
  45. 0 126
      src/main/java/org/ssssssss/script/parsing/ast/FunctionCall.java
  46. 0 32
      src/main/java/org/ssssssss/script/parsing/ast/FunctionStatement.java
  47. 0 74
      src/main/java/org/ssssssss/script/parsing/ast/IfStatement.java
  48. 0 40
      src/main/java/org/ssssssss/script/parsing/ast/Import.java
  49. 0 22
      src/main/java/org/ssssssss/script/parsing/ast/IntegerLiteral.java
  50. 0 40
      src/main/java/org/ssssssss/script/parsing/ast/LambdaFunction.java
  51. 0 15
      src/main/java/org/ssssssss/script/parsing/ast/LambdaParameter.java
  52. 0 25
      src/main/java/org/ssssssss/script/parsing/ast/ListLiteral.java
  53. 0 22
      src/main/java/org/ssssssss/script/parsing/ast/LongLiteral.java
  54. 0 43
      src/main/java/org/ssssssss/script/parsing/ast/MapLiteral.java
  55. 0 101
      src/main/java/org/ssssssss/script/parsing/ast/MapOrArrayAccess.java
  56. 0 141
      src/main/java/org/ssssssss/script/parsing/ast/MemberAccess.java
  57. 0 183
      src/main/java/org/ssssssss/script/parsing/ast/MethodCall.java
  58. 0 30
      src/main/java/org/ssssssss/script/parsing/ast/Node.java
  59. 0 15
      src/main/java/org/ssssssss/script/parsing/ast/NullLiteral.java
  60. 0 36
      src/main/java/org/ssssssss/script/parsing/ast/Return.java
  61. 0 22
      src/main/java/org/ssssssss/script/parsing/ast/ShortLiteral.java
  62. 0 46
      src/main/java/org/ssssssss/script/parsing/ast/StringLiteral.java
  63. 0 39
      src/main/java/org/ssssssss/script/parsing/ast/TernaryOperation.java
  64. 0 75
      src/main/java/org/ssssssss/script/parsing/ast/UnaryOperation.java
  65. 0 19
      src/main/java/org/ssssssss/script/parsing/ast/VariableAccess.java
  66. 0 23
      src/main/java/org/ssssssss/script/parsing/ast/VariableDefine.java
  67. 0 7
      src/main/java/org/ssssssss/script/parsing/ast/VariableSetter.java
  68. 0 51
      src/main/java/org/ssssssss/script/parsing/ast/binary/AddOperation.java
  69. 0 29
      src/main/java/org/ssssssss/script/parsing/ast/binary/AndOperation.java
  70. 0 31
      src/main/java/org/ssssssss/script/parsing/ast/binary/AssigmentOperation.java
  71. 0 79
      src/main/java/org/ssssssss/script/parsing/ast/binary/BinaryOperation.java
  72. 0 41
      src/main/java/org/ssssssss/script/parsing/ast/binary/DivisionOperation.java
  73. 0 21
      src/main/java/org/ssssssss/script/parsing/ast/binary/EqualOperation.java
  74. 0 41
      src/main/java/org/ssssssss/script/parsing/ast/binary/GreaterEqualOperation.java
  75. 0 41
      src/main/java/org/ssssssss/script/parsing/ast/binary/GreaterOperation.java
  76. 0 41
      src/main/java/org/ssssssss/script/parsing/ast/binary/LessEqualOperation.java
  77. 0 41
      src/main/java/org/ssssssss/script/parsing/ast/binary/LessOperation.java
  78. 0 41
      src/main/java/org/ssssssss/script/parsing/ast/binary/ModuloOperation.java
  79. 0 41
      src/main/java/org/ssssssss/script/parsing/ast/binary/MultiplicationOperation.java
  80. 0 21
      src/main/java/org/ssssssss/script/parsing/ast/binary/NotEqualOperation.java
  81. 0 29
      src/main/java/org/ssssssss/script/parsing/ast/binary/OrOperation.java
  82. 0 41
      src/main/java/org/ssssssss/script/parsing/ast/binary/SubtractionOperation.java

+ 5 - 0
pom.xml

@@ -33,6 +33,11 @@
         <developerConnection>scm:git:https://gitee.com/ssssssss-team/magic-api.git</developerConnection>
     </scm>
     <dependencies>
+        <dependency>
+            <groupId>org.ssssssss</groupId>
+            <artifactId>magic-script</artifactId>
+            <version>1.0.0</version>
+        </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter</artifactId>

+ 1 - 1
src/main/java/org/ssssssss/magicapi/cache/SqlCache.java

@@ -1,7 +1,7 @@
 package org.ssssssss.magicapi.cache;
 
 import org.ssssssss.magicapi.utils.MD5Utils;
-import org.ssssssss.script.functions.DatabaseQuery;
+import org.ssssssss.magicapi.functions.DatabaseQuery;
 
 import java.util.Arrays;
 

+ 1 - 1
src/main/java/org/ssssssss/magicapi/dialect/DB2Dialect.java

@@ -1,6 +1,6 @@
 package org.ssssssss.magicapi.dialect;
 
-import org.ssssssss.script.functions.DatabaseQuery;
+import org.ssssssss.magicapi.functions.DatabaseQuery;
 
 public class DB2Dialect implements Dialect {
     @Override

+ 1 - 1
src/main/java/org/ssssssss/magicapi/dialect/Dialect.java

@@ -1,6 +1,6 @@
 package org.ssssssss.magicapi.dialect;
 
-import org.ssssssss.script.functions.DatabaseQuery;
+import org.ssssssss.magicapi.functions.DatabaseQuery;
 
 public interface Dialect {
 

+ 1 - 1
src/main/java/org/ssssssss/magicapi/dialect/MySQLDialect.java

@@ -1,6 +1,6 @@
 package org.ssssssss.magicapi.dialect;
 
-import org.ssssssss.script.functions.DatabaseQuery;
+import org.ssssssss.magicapi.functions.DatabaseQuery;
 
 public class MySQLDialect implements Dialect {
 

+ 1 - 1
src/main/java/org/ssssssss/magicapi/dialect/OracleDialect.java

@@ -1,6 +1,6 @@
 package org.ssssssss.magicapi.dialect;
 
-import org.ssssssss.script.functions.DatabaseQuery;
+import org.ssssssss.magicapi.functions.DatabaseQuery;
 
 public class OracleDialect implements Dialect {
 

+ 1 - 1
src/main/java/org/ssssssss/magicapi/dialect/PostgreSQLDialect.java

@@ -1,6 +1,6 @@
 package org.ssssssss.magicapi.dialect;
 
-import org.ssssssss.script.functions.DatabaseQuery;
+import org.ssssssss.magicapi.functions.DatabaseQuery;
 
 public class PostgreSQLDialect implements Dialect {
     @Override

+ 1 - 1
src/main/java/org/ssssssss/magicapi/dialect/SQLServer2005Dialect.java

@@ -1,7 +1,7 @@
 package org.ssssssss.magicapi.dialect;
 
 import org.apache.commons.lang3.StringUtils;
-import org.ssssssss.script.functions.DatabaseQuery;
+import org.ssssssss.magicapi.functions.DatabaseQuery;
 
 public class SQLServer2005Dialect implements Dialect {
     @Override

+ 1 - 1
src/main/java/org/ssssssss/magicapi/dialect/SQLServerDialect.java

@@ -1,6 +1,6 @@
 package org.ssssssss.magicapi.dialect;
 
-import org.ssssssss.script.functions.DatabaseQuery;
+import org.ssssssss.magicapi.functions.DatabaseQuery;
 
 public class SQLServerDialect implements Dialect {
     @Override

+ 1 - 1
src/main/java/org/ssssssss/script/functions/AssertFunctions.java → src/main/java/org/ssssssss/magicapi/functions/AssertFunctions.java

@@ -1,4 +1,4 @@
-package org.ssssssss.script.functions;
+package org.ssssssss.magicapi.functions;
 
 import org.apache.commons.lang3.StringUtils;
 import org.ssssssss.script.exception.MagicScriptAssertException;

+ 2 - 1
src/main/java/org/ssssssss/script/functions/DatabaseQuery.java → src/main/java/org/ssssssss/magicapi/functions/DatabaseQuery.java

@@ -1,4 +1,4 @@
-package org.ssssssss.script.functions;
+package org.ssssssss.magicapi.functions;
 
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.core.RowMapper;
@@ -13,6 +13,7 @@ import org.ssssssss.magicapi.model.PageResult;
 import org.ssssssss.magicapi.provider.PageProvider;
 import org.ssssssss.script.MagicScriptContext;
 import org.ssssssss.script.annotation.UnableCall;
+import org.ssssssss.script.functions.StreamExtension;
 import org.ssssssss.script.parsing.GenericTokenParser;
 import org.ssssssss.script.parsing.Parser;
 import org.ssssssss.script.parsing.TokenStream;

+ 0 - 34
src/main/java/org/ssssssss/script/MagicModuleLoader.java

@@ -1,34 +0,0 @@
-package org.ssssssss.script;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
-
-public class MagicModuleLoader {
-
-	private static Map<String,Object> modules = new ConcurrentHashMap<>();
-
-	private static Function<String,Object> classLoader = (className)->{
-		try{
-			return Class.forName(className);
-		}catch(Exception e){
-			return null;
-		}
-	};
-
-	public static void setClassLoader(Function<String,Object> classLoader){
-		MagicModuleLoader.classLoader = classLoader;
-	}
-
-	public static void addModule(String moduleName, Object target){
-		modules.put(moduleName, target);
-	}
-
-	public static Object loadModule(String moduleName){
-		return modules.get(moduleName);
-	}
-
-	public static Object loadClass(String className){
-		return classLoader.apply(className);
-	}
-}

+ 0 - 31
src/main/java/org/ssssssss/script/MagicScript.java

@@ -1,31 +0,0 @@
-package org.ssssssss.script;
-
-
-import org.ssssssss.script.interpreter.AstInterpreter;
-import org.ssssssss.script.parsing.Parser;
-import org.ssssssss.script.parsing.ast.Node;
-
-import java.util.List;
-
-public class MagicScript {
-    private final List<Node> nodes;
-
-    private MagicScript(List<Node> nodes) {
-        this.nodes = nodes;
-    }
-
-    public static MagicScript create(String source) {
-        return new MagicScript(Parser.parse(source));
-    }
-
-    public List<Node> getNodes() {
-        return nodes;
-    }
-
-    /**
-     * Renders the magicScript using the MagicScriptContext to resolve variable values referenced in the magicScript.
-     **/
-    Object execute(MagicScriptContext context) {
-        return AstInterpreter.interpret(this, context);
-    }
-}

+ 0 - 139
src/main/java/org/ssssssss/script/MagicScriptContext.java

@@ -1,139 +0,0 @@
-package org.ssssssss.script;
-
-import org.ssssssss.script.interpreter.AstInterpreter;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-
-/**
- * <p>
- * A magicScript context stores mappings from variable names to user provided variable values. A {@link MagicScript} is given a context
- * for rendering to resolve variable values it references in magicScript expressions.
- * </p>
- *
- * <p>
- * Internally, a magicScript context is a stack of these mappings, similar to scopes in a programming language, and used as such by
- * the {@link AstInterpreter}.
- * </p>
- */
-public class MagicScriptContext {
-	private final static ThreadLocal<MagicScriptContext> CONTEXT_THREAD_LOCAL = new ThreadLocal<>();
-	private final List<Map<String, Object>> scopes = new ArrayList<Map<String, Object>>();
-
-	/**
-	 * Keeps track of previously allocated, unused scopes. New scopes are first tried to be retrieved from this pool to avoid
-	 * generating garbage.
-	 **/
-	private final List<Map<String, Object>> freeScopes = new ArrayList<Map<String, Object>>();
-
-	public MagicScriptContext() {
-		push();
-	}
-
-	public MagicScriptContext(Map<String, Object> variables) {
-		this();
-		if (variables != null) {
-			for (Map.Entry<String, Object> entry : variables.entrySet()) {
-				set(entry.getKey(), entry.getValue());
-			}
-		}
-	}
-
-	public static MagicScriptContext get() {
-		return CONTEXT_THREAD_LOCAL.get();
-	}
-
-	public static void remove() {
-		CONTEXT_THREAD_LOCAL.remove();
-	}
-
-	public static void set(MagicScriptContext context) {
-		CONTEXT_THREAD_LOCAL.set(context);
-	}
-
-	/**
-	 * Sets the value of the variable with the given name. If the variable already exists in one of the scopes, that variable is
-	 * set. Otherwise the variable is set on the last pushed scope.
-	 */
-	public MagicScriptContext set(String name, Object value) {
-		for (int i = scopes.size() - 1; i >= 0; i--) {
-			Map<String, Object> ctx = scopes.get(i);
-			if (ctx.isEmpty()) {
-				continue;
-			}
-			if (ctx.containsKey(name)) {
-				ctx.put(name, value);
-				return this;
-			}
-		}
-
-		scopes.get(scopes.size() - 1).put(name, value);
-		return this;
-	}
-
-	/**
-	 * Sets the value of the variable with the given name on the last pushed scope
-	 **/
-	public MagicScriptContext setOnCurrentScope(String name, Object value) {
-		scopes.get(scopes.size() - 1).put(name, value);
-		return this;
-	}
-
-	/**
-	 * Internal. Returns the value of the variable with the given name, walking the scope stack from top to bottom, similar to how
-	 * scopes in programming languages are searched for variables.
-	 */
-	public Object get(String name) {
-		for (int i = scopes.size() - 1; i >= 0; i--) {
-			Map<String, Object> ctx = scopes.get(i);
-			if (ctx.isEmpty()) {
-				continue;
-			}
-			Object value = ctx.get(name);
-			if (value != null) {
-				return value;
-			}
-		}
-		return null;
-	}
-
-	public String getString(String name) {
-		return getString(name, null);
-	}
-
-	public String getString(String name, String defaultValue) {
-		Object value = get(name);
-		return value == null ? defaultValue : value.toString();
-	}
-
-	/**
-	 * Internal. Returns all variables currently defined in this context.
-	 */
-	public Map<String, Object> getVariables() {
-		Map<String, Object> variables = new HashMap<>();
-		for (Map<String, Object> scope : scopes) {
-			variables.putAll(scope);
-		}
-		return variables;
-	}
-
-	/**
-	 * Internal. Pushes a new "scope" onto the stack.
-	 **/
-	public void push() {
-		Map<String, Object> newScope = freeScopes.size() > 0 ? freeScopes.remove(freeScopes.size() - 1) : new HashMap<String, Object>();
-		scopes.add(newScope);
-	}
-
-	/**
-	 * Internal. Pops the top of the "scope" stack.
-	 **/
-	public void pop() {
-		Map<String, Object> oldScope = scopes.remove(scopes.size() - 1);
-		oldScope.clear();
-		freeScopes.add(oldScope);
-	}
-}

+ 0 - 134
src/main/java/org/ssssssss/script/MagicScriptDebugContext.java

@@ -1,134 +0,0 @@
-package org.ssssssss.script;
-
-import org.ssssssss.script.parsing.Span;
-
-import java.util.*;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-public class MagicScriptDebugContext extends MagicScriptContext {
-
-	private String id = UUID.randomUUID().toString().replace("-", "");
-
-	private static Map<String, MagicScriptDebugContext> contextMap = new ConcurrentHashMap<>();
-
-	public List<Integer> breakpoints;
-
-	private BlockingQueue<String> producer = new LinkedBlockingQueue<>();
-
-	private BlockingQueue<String> consumer = new LinkedBlockingQueue<>();
-
-	private Object returnValue;
-
-	private Span.Line line;
-
-	private boolean running = true;
-
-	private boolean exception = false;
-
-	private int timeout = 60;
-
-	public MagicScriptDebugContext() {
-	}
-
-	public MagicScriptDebugContext(Map<String, Object> variables) {
-		super(variables);
-		contextMap.put(this.id, this);
-	}
-
-	public void setTimeout(int timeout) {
-		this.timeout = timeout;
-	}
-
-	public List<Integer> getBreakpoints() {
-		return breakpoints;
-	}
-
-	public void setBreakpoints(List<Integer> breakpoints) {
-		this.breakpoints = breakpoints;
-	}
-
-	public String pause(Span.Line line) throws InterruptedException {
-		this.line = line;
-		consumer.offer(this.id);
-		return producer.poll(timeout, TimeUnit.SECONDS);
-	}
-
-	public void await() throws InterruptedException {
-		consumer.take();
-	}
-
-	public void singal() throws InterruptedException {
-		producer.offer(this.id);
-		await();
-	}
-
-	public Object getReturnValue() {
-		return returnValue;
-	}
-
-	public void setReturnValue(Object returnValue) {
-		this.running = false;
-		this.returnValue = returnValue;
-		contextMap.remove(this.id);
-		consumer.offer(this.id);
-	}
-
-	public boolean isRunning() {
-		return running;
-	}
-
-	public Map<String, Object> getDebugInfo() {
-		List<Map<String, Object>> varList = new ArrayList<>();
-		Set<Map.Entry<String, Object>> entries = super.getVariables().entrySet();
-		for (Map.Entry<String, Object> entry : entries) {
-			Object value = entry.getValue();
-			Map<String, Object> variable = new HashMap<>();
-			variable.put("name", entry.getKey());
-			if (value != null) {
-				variable.put("value", value.toString());
-				variable.put("type", value.getClass());
-			}else{
-				variable.put("value", "null");
-			}
-			varList.add(variable);
-		}
-		varList.sort((o1, o2) -> {
-			Object k1 = o1.get("name");
-			Object k2 = o2.get("name");
-			if(k1 == null){
-				return -1;
-			}
-			if(k2 == null){
-				return 1;
-			}
-			return k1.toString().compareTo(k2.toString());
-		});
-		Map<String, Object> info = new HashMap<>();
-		info.put("variables", varList);
-		info.put("range", Arrays.asList(line.getLineNumber(), line.getStartCol(), line.getEndLineNumber(), line.getEndCol()));
-		return info;
-	}
-
-	public Span.Line getLine() {
-		return line;
-	}
-
-	public String getId() {
-		return id;
-	}
-
-	public boolean isException() {
-		return exception;
-	}
-
-	public void setException(boolean exception) {
-		this.exception = exception;
-	}
-
-	public static MagicScriptDebugContext getDebugContext(String id) {
-		return contextMap.get(id);
-	}
-}

+ 0 - 64
src/main/java/org/ssssssss/script/MagicScriptEngine.java

@@ -1,64 +0,0 @@
-package org.ssssssss.script;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.ssssssss.script.exception.DebugTimeoutException;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.function.BiFunction;
-
-public class MagicScriptEngine {
-
-	private static Map<String, Object> defaultImports = new ConcurrentHashMap<>();
-
-	private static ExecutorService service = Executors.newCachedThreadPool();
-
-	static {
-		addDefaultImport("range", (BiFunction<Integer, Integer, Iterator<Integer>>) (from, to) -> new Iterator<Integer>() {
-			int idx = from;
-
-			public boolean hasNext() {
-				return idx <= to;
-			}
-
-			public Integer next() {
-				return idx++;
-			}
-		});
-	}
-
-	public static void addDefaultImport(String name, Object target) {
-		defaultImports.put(name, target);
-	}
-
-	public static Object execute(String script, MagicScriptContext context) {
-		Iterator<Map.Entry<String, Object>> iterator = defaultImports.entrySet().iterator();
-		while (iterator.hasNext()) {
-			Map.Entry<String, Object> entry = iterator.next();
-			context.set(entry.getKey(), entry.getValue());
-		}
-		MagicScript magicScript = MagicScript.create(script);
-		if (context instanceof MagicScriptDebugContext) {
-			MagicScriptDebugContext debugContext = (MagicScriptDebugContext) context;
-			service.submit(() -> {
-				try {
-					debugContext.setReturnValue(magicScript.execute(debugContext));
-				} catch (Exception e) {
-					debugContext.setException(true);
-					debugContext.setReturnValue(e);
-				}
-			});
-			try {
-				debugContext.await();
-			} catch (InterruptedException e) {
-				throw new DebugTimeoutException(e);
-			}
-			return debugContext.isRunning() ? debugContext.getDebugInfo() : debugContext.getReturnValue();
-		}
-		return magicScript.execute(context);
-	}
-}

+ 0 - 75
src/main/java/org/ssssssss/script/MagicScriptError.java

@@ -1,75 +0,0 @@
-package org.ssssssss.script;
-
-import org.ssssssss.script.exception.MagicScriptException;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.TokenStream;
-
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * All errors reported by the library go through the static functions of this class.
- */
-public class MagicScriptError {
-
-	/**
-	 * <p>
-	 * Create an error message based on the provided message and stream, highlighting the line on which the error happened. If the
-	 * stream has more tokens, the next token will be highlighted. Otherwise the end of the source of the stream will be
-	 * highlighted.
-	 * </p>
-	 *
-	 * <p>
-	 * Throws a {@link RuntimeException}
-	 * </p>
-	 */
-	public static void error(String message, TokenStream stream) {
-		if (stream.hasMore()) {
-			error(message, stream.consume().getSpan());
-		} else {
-			error(message, stream.getPrev().getSpan());
-		}
-	}
-
-	/**
-	 * Create an error message based on the provided message and location, highlighting the location in the line on which the
-	 * error happened. Throws a {@link MagicScriptException}
-	 **/
-	public static void error(String message, Span location, Throwable cause) {
-
-		Span.Line line = location.getLine();
-		Throwable parent = cause == null ? null : cause.getCause();
-		while (parent != null) {
-			if (parent instanceof InvocationTargetException) {
-				cause = parent.getCause();
-				if (cause != null) {
-					message += ";" + cause.getMessage();
-				}
-				break;
-			}
-			parent = parent.getCause();
-		}
-		String errorMessage = "Script Error : " + message + "\n\n";
-		errorMessage += line.getText();
-		errorMessage += "\n";
-		int errorStart = location.getStart() - line.getStart();
-		int errorEnd = errorStart + location.getText().length() - 1;
-		for (int i = 0, n = line.getText().length(); i < n; i++) {
-			boolean useTab = line.getText().charAt(i) == '\t';
-			errorMessage += i >= errorStart && i <= errorEnd ? "^" : useTab ? "\t" : " ";
-		}
-		if (cause == null) {
-			throw new MagicScriptException(errorMessage, message, line);
-		} else {
-			throw new MagicScriptException(errorMessage, message, cause, line);
-		}
-	}
-
-	/**
-	 * Create an error message based on the provided message and location, highlighting the location in the line on which the
-	 * error happened. Throws a {@link MagicScriptException}
-	 **/
-	public static void error(String message, Span location) {
-		error(message, location, null);
-	}
-
-}

+ 0 - 9
src/main/java/org/ssssssss/script/annotation/UnableCall.java

@@ -1,9 +0,0 @@
-package org.ssssssss.script.annotation;
-
-import java.lang.annotation.*;
-
-@Target({ElementType.METHOD, ElementType.FIELD})
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface UnableCall {
-}

+ 0 - 12
src/main/java/org/ssssssss/script/exception/DebugTimeoutException.java

@@ -1,12 +0,0 @@
-package org.ssssssss.script.exception;
-
-public class DebugTimeoutException extends RuntimeException {
-
-	public DebugTimeoutException() {
-		super("debug超时");
-	}
-
-	public DebugTimeoutException(Throwable cause) {
-		super(cause);
-	}
-}

+ 0 - 23
src/main/java/org/ssssssss/script/exception/MagicScriptAssertException.java

@@ -1,23 +0,0 @@
-package org.ssssssss.script.exception;
-
-public class MagicScriptAssertException extends MagicScriptException {
-
-	private int code;
-
-	private String message;
-
-	public MagicScriptAssertException(int code, String message) {
-		this.code = code;
-		this.message = message;
-	}
-
-	public int getCode() {
-		return code;
-	}
-
-	@Override
-	public String getMessage() {
-		return message;
-	}
-
-}

+ 0 - 40
src/main/java/org/ssssssss/script/exception/MagicScriptException.java

@@ -1,40 +0,0 @@
-package org.ssssssss.script.exception;
-
-import org.ssssssss.script.parsing.Span;
-
-public class MagicScriptException extends RuntimeException {
-	private static final long serialVersionUID = 1L;
-	private String simpleMessage;
-	private Span.Line line;
-
-	public MagicScriptException() {
-	}
-
-	public MagicScriptException(String errorMessage, String simpleMessage, Span.Line line) {
-		super(errorMessage);
-		this.simpleMessage = simpleMessage;
-		this.line = line;
-	}
-
-	public MagicScriptException(String errorMessage, Span.Line line) {
-		this(errorMessage, errorMessage, line);
-	}
-
-	public MagicScriptException(String errorMessage) {
-		this(errorMessage, errorMessage, null);
-	}
-
-	public MagicScriptException(String message, String simpleMessage, Throwable cause, Span.Line line) {
-		super(message, cause);
-		this.simpleMessage = simpleMessage;
-		this.line = line;
-	}
-
-	public String getSimpleMessage() {
-		return simpleMessage;
-	}
-
-	public Span.Line getLine() {
-		return line;
-	}
-}

+ 0 - 10
src/main/java/org/ssssssss/script/exception/ModuleNotFoundException.java

@@ -1,10 +0,0 @@
-package org.ssssssss.script.exception;
-
-import org.ssssssss.script.parsing.Span;
-
-public class ModuleNotFoundException extends MagicScriptException {
-
-	public ModuleNotFoundException(String errorMessage, Span.Line line) {
-		super(errorMessage, line);
-	}
-}

+ 0 - 7
src/main/java/org/ssssssss/script/exception/StringLiteralException.java

@@ -1,7 +0,0 @@
-package org.ssssssss.script.exception;
-
-public class StringLiteralException extends RuntimeException {
-
-	private static final long serialVersionUID = 1L;
-
-}

+ 0 - 72
src/main/java/org/ssssssss/script/functions/StreamExtension.java

@@ -1,72 +0,0 @@
-package org.ssssssss.script.functions;
-
-import org.ssssssss.script.exception.MagicScriptException;
-
-import java.lang.reflect.Array;
-import java.util.*;
-import java.util.function.Function;
-import java.util.stream.IntStream;
-
-public class StreamExtension {
-
-    private static Object toOriginType(Object target, List<Object> results) {
-        if (target instanceof Collection) {
-            return results;
-        } else if (target.getClass().isArray()) {
-            return results.toArray();
-        } else if (target instanceof Iterator) {
-            return results;
-        } else if (target instanceof Enumeration) {
-            return results;
-        }
-        return null;
-    }
-
-    public static List<Object> arrayLikeToList(Object arrayLike) {
-        if (arrayLike != null && arrayLike.getClass().isArray()) {
-            int len = Array.getLength(arrayLike);
-            List<Object> value = new ArrayList<>();
-            for (int i = 0; i < len; i++) {
-                value.add(Array.get(arrayLike, i));
-            }
-            return value;
-        } else if (arrayLike instanceof Collection) {
-            return new ArrayList<>((Collection<?>) arrayLike);
-        } else if (arrayLike.getClass().isArray()) {
-            List<Object> list = new ArrayList<>(Array.getLength(arrayLike));
-            IntStream.range(0, Array.getLength(arrayLike)).forEach(i -> list.add(Array.get(arrayLike, i)));
-            return list;
-        } else if (arrayLike instanceof Iterator) {
-            List<Object> list = new ArrayList<>();
-            Iterator<Object> it = (Iterator<Object>) arrayLike;
-            it.forEachRemaining(list::add);
-            return list;
-        } else if (arrayLike instanceof Enumeration) {
-            Enumeration<Object> en = (Enumeration<Object>) arrayLike;
-            return Collections.list(en);
-        }
-		throw new MagicScriptException("不支持的类型:" + arrayLike.getClass());
-    }
-
-    public static Object map(Object target, Function<Object[], Object> function) {
-        List<Object> objects = arrayLikeToList(target);
-        List<Object> results = new ArrayList<>(objects.size());
-        for (int i = 0, len = objects.size(); i < len; i++) {
-            Object object = objects.get(i);
-            results.add(function.apply(new Object[]{object, i, len}));
-        }
-        return toOriginType(target, results);
-    }
-
-    public static Object filter(Object target, Function<Object[], Object> function) {
-        List<Object> objects = arrayLikeToList(target);
-        List<Object> results = new ArrayList<>(objects.size());
-        for (int i = 0, len = objects.size(); i < len; i++) {
-            Object object = objects.get(i);
-            if (Objects.equals(true, function.apply(new Object[]{object, i, len}))) {
-                results.add(object);
-            }
-        }
-        return toOriginType(target, results);
-    }
-}

+ 0 - 52
src/main/java/org/ssssssss/script/interpreter/AbstractReflection.java

@@ -1,52 +0,0 @@
-package org.ssssssss.script.interpreter;
-
-/**
- * Used by {@link AstInterpreter} to access fields and methods of objects. This is a singleton class used by all
- * {@link AstInterpreter} instances. Replace the default implementation via {@link #setInstance(AbstractReflection)}. The implementation
- * must be thread-safe.
- */
-public abstract class AbstractReflection {
-    private static AbstractReflection instance = new JavaReflection();
-
-    /**
-     * Returns the Reflection instance used to fetch field and call methods
-     **/
-    public synchronized static AbstractReflection getInstance() {
-        return instance;
-    }
-
-    /**
-     * Sets the Reflection instance to be used by all Template interpreters
-     **/
-    public synchronized static void setInstance(AbstractReflection abstractReflection) {
-        instance = abstractReflection;
-    }
-
-    /**
-     * Returns an opaque handle to a field with the given name or null if the field could not be found
-     **/
-    public abstract Object getField(Object obj, String name);
-
-    /**
-     * Returns an opaque handle to the method with the given name best matching the signature implied by the given arguments, or
-     * null if the method could not be found. If obj is an instance of Class, the matching static method is returned. If the name
-     * is null and the object is a {@link FunctionalInterface}, the first declared method on the object is returned.
-     **/
-    public abstract Object getMethod(Object obj, String name, Object... arguments);
-
-    public abstract Object getExtensionMethod(Object obj, String name, Object... arguments);
-
-    public abstract void registerExtensionClass(Class<?> target, Class<?> clazz);
-
-    /**
-     * Returns the value of the field from the object. The field must have been previously retrieved via
-     * {@link #getField(Object, String)}.
-     **/
-    public abstract Object getFieldValue(Object obj, Object field);
-
-    /**
-     * Calls the method on the object with the given arguments. The method must have been previously retrieved via
-     * {@link #getMethod(Object, String, Object...)}.
-     **/
-    public abstract Object callMethod(Object obj, Object method, Object... arguments);
-}

+ 0 - 77
src/main/java/org/ssssssss/script/interpreter/AstInterpreter.java

@@ -1,77 +0,0 @@
-package org.ssssssss.script.interpreter;
-
-import org.ssssssss.script.MagicScript;
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptDebugContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.exception.DebugTimeoutException;
-import org.ssssssss.script.exception.MagicScriptException;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Break;
-import org.ssssssss.script.parsing.ast.Continue;
-import org.ssssssss.script.parsing.ast.Node;
-import org.ssssssss.script.parsing.ast.Return;
-
-import java.util.List;
-
-/**
- * <p>
- * Interprets a Template given a MagicScriptContext to lookup variable values in and writes the evaluation results to an output
- * stream. Uses the global {@link AbstractReflection} instance as returned by {@link AbstractReflection#getInstance()} to access members and call
- * methods.
- * </p>
- *
- * <p>
- * The interpeter traverses the AST as stored in {@link MagicScript#getNodes()}. the interpeter has a method for each AST node type
- * be written to the output stream.
- * </p>
- **/
-public class AstInterpreter {
-    public static Object interpret(MagicScript magicScript, MagicScriptContext context) {
-        try {
-            MagicScriptContext.set(context);
-            Object value = interpretNodeList(magicScript.getNodes(), context);
-            if (value == Return.RETURN_SENTINEL) {
-                return ((Return.ReturnValue) value).getValue();
-            }
-            return null;
-        } catch (Throwable t) {
-            if (t instanceof MagicScriptException || t instanceof DebugTimeoutException) {
-                throw t;
-            } else {
-                MagicScriptError.error("执行表达式出错 " + t.getMessage(), magicScript.getNodes().get(0).getSpan(), t);
-                return null; // never reached
-            }
-        } finally {
-            Return.RETURN_SENTINEL.setValue(null);
-            MagicScriptContext.remove();
-        }
-    }
-
-    public static Object interpretNodeList(List<Node> nodes, MagicScriptContext context) {
-        if (nodes != null) {
-            for (int i = 0, n = nodes.size(); i < n; i++) {
-                Node node = nodes.get(i);
-                if(context instanceof MagicScriptDebugContext){
-                    MagicScriptDebugContext debugContext = (MagicScriptDebugContext) context;
-                    Span.Line line = node.getSpan().getLine();
-                    if(debugContext.getBreakpoints().contains(line.getLineNumber())){
-                        try {
-                            if(debugContext.pause(line) == null){
-                                debugContext.setReturnValue(null);
-                                throw new DebugTimeoutException();
-                            }
-                        } catch (InterruptedException e) {
-                            throw new DebugTimeoutException(e);
-                        }
-                    }
-                }
-                Object value = node.evaluate(context);
-                if (value == Break.BREAK_SENTINEL || value == Continue.CONTINUE_SENTINEL || value == Return.RETURN_SENTINEL) {
-                    return value;
-                }
-            }
-        }
-        return null;
-    }
-}

+ 0 - 514
src/main/java/org/ssssssss/script/interpreter/JavaReflection.java

@@ -1,514 +0,0 @@
-package org.ssssssss.script.interpreter;
-
-import org.ssssssss.script.annotation.UnableCall;
-import org.ssssssss.script.functions.StreamExtension;
-
-import java.lang.reflect.*;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
-
-
-public class JavaReflection extends AbstractReflection {
-    private final Map<Class<?>, Map<String, Field>> fieldCache = new ConcurrentHashMap<Class<?>, Map<String, Field>>();
-    private final Map<Class<?>, Map<MethodSignature, Method>> methodCache = new ConcurrentHashMap<Class<?>, Map<MethodSignature, Method>>();
-    private final Map<Class<?>, Map<String, List<Method>>> extensionmethodCache = new ConcurrentHashMap<>();
-
-    public JavaReflection() {
-        registerExtensionClass(Collection.class, StreamExtension.class);
-        registerExtensionClass(Object[].class, StreamExtension.class);
-        registerExtensionClass(Enumeration.class, StreamExtension.class);
-        registerExtensionClass(Iterator.class, StreamExtension.class);
-    }
-
-    /**
-     * Returns the <code>apply()</code> method of a functional interface.
-     **/
-    private static Method findApply(Class<?> cls) {
-        for (Method method : cls.getDeclaredMethods()) {
-            if ("apply".equals(method.getName())) {
-                return method;
-            }
-        }
-        return null;
-    }
-
-    private static int calcToObjectDistanceWithInterface(Class<?>[] interfaces, int distance, int score) {
-        if (interfaces == null) {
-            return distance;
-        }
-        return Arrays.stream(interfaces).mapToInt(i -> {
-            int v = calcToObjectDistanceWithInterface(i.getInterfaces(), distance, score + 2);
-            return v + distance + score;
-        }).sum();
-    }
-
-    private static int calcToObjectDistance(Class<?> clazz) {
-        return calcToObjectDistance(clazz, 0);
-    }
-
-    private static int calcToObjectDistance(Class<?> clazz, int distance) {
-        if (clazz == null) {
-            return distance + 3;
-        }
-        if (Object.class.equals(clazz)) {
-            return distance;
-        }
-        int interfaceScore = calcToObjectDistanceWithInterface(clazz.getInterfaces(), distance + 2, 0);
-        if (clazz.isInterface()) {
-            return interfaceScore;
-        }
-        int classScore = calcToObjectDistance(clazz.getSuperclass(), distance + 3);
-        return classScore + interfaceScore;
-    }
-
-    private static int matchTypes(Class<?>[] parameterTypes, Class<?>[] otherTypes) {
-        if(parameterTypes.length != otherTypes.length){
-            return -1;
-        }
-        int score = 0;
-        for (int ii = 0, nn = parameterTypes.length; ii < nn; ii++) {
-            Class<?> type = parameterTypes[ii];
-            Class<?> otherType = otherTypes[ii];
-            if (Null.class.equals(type)) {
-                score++;
-            } else if (!otherType.isAssignableFrom(type)) {
-                score++;
-                if (!isPrimitiveAssignableFrom(type, otherType)) {
-                    score++;
-                    if (!isCoercible(type, otherType)) {
-                        score = -1;
-                        break;
-                    } else {
-                        score++;
-                    }
-                }
-            }
-        }
-        return score;
-    }
-
-    private static Method findMethod(List<Method> methods, Class<?>[] parameterTypes) {
-        Method foundMethod = null;
-        int foundScore = 0;
-        for (Method method : methods) {
-            // Check if the types match.
-            Class<?>[] otherTypes = method.getParameterTypes();
-            int score = matchTypes(parameterTypes, otherTypes);
-            if (score == -1 && method.isVarArgs()) {
-                score = -1;
-                int fixedParaLength = otherTypes.length - 1;
-                if (parameterTypes.length >= fixedParaLength) {
-                    Class<?>[] argTypes = new Class<?>[fixedParaLength];
-                    System.arraycopy(parameterTypes, 0, argTypes, 0, fixedParaLength);
-                    score = matchTypes(argTypes, otherTypes);
-                    if (score > -1) {
-                        Class<?> target = otherTypes[fixedParaLength].getComponentType();
-                        for (int i = fixedParaLength; i < parameterTypes.length; i++) {
-                            Class<?> type = parameterTypes[i];
-                            if (Null.class.equals(type)) {
-                                score++;
-                            } else if (!target.isAssignableFrom(type)) {
-                                score++;
-                                if (!isPrimitiveAssignableFrom(type, target)) {
-                                    score++;
-                                    if (!isCoercible(type, target)) {
-                                        score = -1;
-                                        break;
-                                    } else {
-                                        score++;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            if (score > -1) {
-                if (foundMethod == null) {
-                    foundMethod = method;
-                    foundScore = score;
-                } else {
-                    if (score < foundScore) {
-                        foundScore = score;
-                        foundMethod = method;
-                    }
-                }
-            }
-        }
-        return foundMethod;
-    }
-
-    /**
-     * Returns the method best matching the given signature, including type coercion, or null.
-     **/
-    private static Method findMethod(Class<?> cls, String name, Class<?>[] parameterTypes) {
-        Method[] methods = cls.getDeclaredMethods();
-        List<Method> methodList = new ArrayList<>();
-        for (int i = 0, n = methods.length; i < n; i++) {
-            Method method = methods[i];
-            if (!method.getName().equals(name)) {
-                continue;
-            }
-            if (method.getAnnotation(UnableCall.class) != null) {
-                continue;
-            }
-            methodList.add(method);
-        }
-        Method method = findMethod(methodList, parameterTypes);
-        return method;
-    }
-
-    /**
-     * Returns whether the from type can be assigned to the to type, assuming either type is a (boxed) primitive type. We can
-     * relax the type constraint a little, as we'll invoke a method via reflection. That means the from type will always be boxed,
-     * as the {@link Method#invoke(Object, Object...)} method takes objects.
-     **/
-    private static boolean isPrimitiveAssignableFrom(Class<?> from, Class<?> to) {
-        if ((from == Boolean.class || from == boolean.class) && (to == boolean.class || to == Boolean.class)) {
-            return true;
-        }
-        if ((from == Integer.class || from == int.class) && (to == int.class || to == Integer.class)) {
-            return true;
-        }
-        if ((from == Float.class || from == float.class) && (to == float.class || to == Float.class)) {
-            return true;
-        }
-        if ((from == Double.class || from == double.class) && (to == double.class || to == Double.class)) {
-            return true;
-        }
-        if ((from == Byte.class || from == byte.class) && (to == byte.class || to == Byte.class)) {
-            return true;
-        }
-        if ((from == Short.class || from == short.class) && (to == short.class || to == Short.class)) {
-            return true;
-        }
-        if ((from == Long.class || from == long.class) && (to == long.class || to == Long.class)) {
-            return true;
-        }
-        if ((from == Character.class || from == char.class) && (to == char.class || to == Character.class)) {
-            return true;
-        }
-        return false;
-    }
-
-    public static String[] getStringTypes(Object[] objects) {
-        String[] parameterTypes = new String[objects == null ? 0 : objects.length];
-        if (objects != null) {
-            for (int i = 0, len = objects.length; i < len; i++) {
-                Object value = objects[i];
-                parameterTypes[i] = value == null ? "null" : value.getClass().getSimpleName();
-            }
-        }
-        return parameterTypes;
-    }
-
-    /**
-     * Returns whether the from type can be coerced to the to type. The coercion rules follow those of Java. See JLS 5.1.2
-     * https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html
-     **/
-    private static boolean isCoercible(Class<?> from, Class<?> to) {
-        if (from == Integer.class || from == int.class) {
-            return to == float.class || to == Float.class || to == double.class || to == Double.class || to == long.class || to == Long.class;
-        }
-
-        if (from == Float.class || from == float.class) {
-            return to == double.class || to == Double.class;
-        }
-
-        if (from == Double.class || from == double.class) {
-            return false;
-        }
-
-        if (from == Character.class || from == char.class) {
-            return to == int.class || to == Integer.class || to == float.class || to == Float.class || to == double.class || to == Double.class || to == long.class
-                    || to == Long.class;
-        }
-
-        if (from == Byte.class || from == byte.class) {
-            return to == int.class || to == Integer.class || to == float.class || to == Float.class || to == double.class || to == Double.class || to == long.class
-                    || to == Long.class || to == short.class || to == Short.class;
-        }
-
-        if (from == Short.class || from == short.class) {
-            return to == int.class || to == Integer.class || to == float.class || to == Float.class || to == double.class || to == Double.class || to == long.class
-                    || to == Long.class;
-        }
-
-        if (from == Long.class || from == long.class) {
-            return to == float.class || to == Float.class || to == double.class || to == Double.class;
-        }
-
-        if (from == int[].class || from == Integer[].class) {
-            return to == Object[].class || to == float[].class || to == Float[].class || to == double[].class || to == Double[].class || to == long[].class || to == Long[].class;
-        }
-
-        return false;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    public Object getField(Object obj, String name) {
-        Class cls = obj instanceof Class ? (Class) obj : obj.getClass();
-        Map<String, Field> fields = fieldCache.get(cls);
-        if (fields == null) {
-            fields = new ConcurrentHashMap<>();
-            fieldCache.put(cls, fields);
-        }
-
-        Field field = fields.get(name);
-        if (field == null) {
-            try {
-                field = cls.getDeclaredField(name);
-                if (field.getAnnotation(UnableCall.class) != null) {
-                    field = null;
-                } else {
-                    field.setAccessible(true);
-                    fields.put(name, field);
-                }
-            } catch (Throwable t) {
-                // fall through, try super classes
-            }
-
-            if (field == null) {
-                Class parentClass = cls.getSuperclass();
-                while (parentClass != Object.class && parentClass != null) {
-                    try {
-                        field = parentClass.getDeclaredField(name);
-                        if (field.getAnnotation(UnableCall.class) != null) {
-                            field = null;
-                        } else {
-                            field.setAccessible(true);
-                            fields.put(name, field);
-                        }
-                    } catch (NoSuchFieldException e) {
-                        // fall through
-                    }
-                    parentClass = parentClass.getSuperclass();
-                }
-            }
-        }
-
-        return field;
-    }
-
-    @Override
-    public Object getFieldValue(Object obj, Object field) {
-        Field javaField = (Field) field;
-        try {
-            return javaField.get(obj);
-        } catch (Throwable e) {
-            throw new RuntimeException("Couldn't get value of field '" + javaField.getName() + "' from object of type '" + obj.getClass().getSimpleName() + "'");
-        }
-    }
-
-    @Override
-    public void registerExtensionClass(Class<?> target, Class<?> clazz) {
-        Method[] methods = clazz.getDeclaredMethods();
-        if (methods != null) {
-            Map<String, List<Method>> cachedMethodMap = extensionmethodCache.get(target);
-            if (cachedMethodMap == null) {
-                cachedMethodMap = new HashMap<>();
-                extensionmethodCache.put(target, cachedMethodMap);
-            }
-            for (Method method : methods) {
-                if (Modifier.isStatic(method.getModifiers()) && method.getParameterCount() > 0 && method.getAnnotation(UnableCall.class) == null) {
-                    List<Method> cachedList = cachedMethodMap.get(method.getName());
-                    if (cachedList == null) {
-                        cachedList = new ArrayList<>();
-                        cachedMethodMap.put(method.getName(), cachedList);
-                    }
-                    cachedList.add(method);
-                }
-            }
-            Collection<List<Method>> methodsValues = cachedMethodMap.values();
-            for (List<Method> methodList : methodsValues) {
-                methodList.sort((m1, m2) -> {
-                    int sum1 = Arrays.stream(m1.getParameterTypes()).mapToInt(JavaReflection::calcToObjectDistance).sum();
-                    int sum2 = Arrays.stream(m2.getParameterTypes()).mapToInt(JavaReflection::calcToObjectDistance).sum();
-                    return sum2 - sum1;
-                });
-            }
-        }
-    }
-
-    @Override
-    public Object getExtensionMethod(Object obj, String name, Object... arguments) {
-        Class<?> cls = obj instanceof Class ? (Class<?>) obj : obj.getClass();
-        if (cls.isArray()) {
-            cls = Object[].class;
-        }
-        return getExtensionMethod(cls, name, arguments);
-    }
-
-    private Object getExtensionMethod(Class<?> cls, String name, Object... arguments) {
-        if (cls == null) {
-            cls = Object.class;
-        }
-        Map<String, List<Method>> methodMap = extensionmethodCache.get(cls);
-        if (methodMap != null) {
-            List<Method> methodList = methodMap.get(name);
-            if (methodList != null) {
-                Class<?>[] parameterTypes = new Class[arguments.length + 1];
-                parameterTypes[0] = cls;
-                for (int i = 0; i < arguments.length; i++) {
-                    parameterTypes[i + 1] = arguments[i] == null ? Null.class : arguments[i].getClass();
-                }
-                return findMethod(methodList, parameterTypes);
-            }
-        }
-        if (cls != Object.class) {
-            Class<?>[] interfaces = cls.getInterfaces();
-            if (interfaces != null) {
-                for (Class<?> clazz : interfaces) {
-                    Object method = getExtensionMethod(clazz, name, arguments);
-                    if (method != null) {
-                        return method;
-                    }
-                }
-            }
-            return getExtensionMethod(cls.getSuperclass(), name, arguments);
-        }
-        return null;
-    }
-
-    @Override
-    public Object getMethod(Object obj, String name, Object... arguments) {
-        Class<?> cls = obj instanceof Class ? (Class<?>) obj : (obj instanceof Function ? Function.class : obj.getClass());
-        Map<MethodSignature, Method> methods = methodCache.get(cls);
-        if (methods == null) {
-            methods = new ConcurrentHashMap<>();
-            methodCache.put(cls, methods);
-        }
-
-        Class<?>[] parameterTypes = new Class[arguments.length];
-        for (int i = 0; i < arguments.length; i++) {
-            parameterTypes[i] = arguments[i] == null ? Null.class : arguments[i].getClass();
-        }
-
-        JavaReflection.MethodSignature signature = new MethodSignature(name, parameterTypes);
-        Method method = methods.get(signature);
-
-        if (method == null) {
-            try {
-                if (name == null) {
-                    method = findApply(cls);
-                } else {
-                    method = findMethod(cls, name, parameterTypes);
-                    if (method == null) {
-                        method = findMethod(cls, name, new Class<?>[]{Object[].class});
-                    }
-                }
-                method.setAccessible(true);
-                methods.put(signature, method);
-            } catch (Throwable e) {
-                // fall through
-            }
-
-            if (method == null) {
-                Class<?> parentClass = cls.getSuperclass();
-                while (parentClass != Object.class && parentClass != null) {
-                    try {
-                        if (name == null) {
-                            method = findApply(parentClass);
-                        } else {
-                            method = findMethod(parentClass, name, parameterTypes);
-                        }
-                        method.setAccessible(true);
-                        methods.put(signature, method);
-                    } catch (Throwable e) {
-                        // fall through
-                    }
-                    parentClass = parentClass.getSuperclass();
-                }
-            }
-        }
-
-        return method;
-    }
-
-    @Override
-    public Object callMethod(Object obj, Object method, Object... arguments) {
-        Method javaMethod = (Method) method;
-        try {
-            if (javaMethod.isVarArgs()) {
-                int count = javaMethod.getParameterCount();
-                Object[] args = new Object[count];
-                if (arguments != null) {
-                    for (int i = 0; i < count - 1; i++) {
-                        args[i] = arguments[i];
-                    }
-                    if (arguments.length - count + 1 > 0) {
-                        int len = arguments.length - count + 1;
-                        Object varArgs = Array.newInstance(javaMethod.getParameterTypes()[count - 1].getComponentType(), len);
-                        System.arraycopy(arguments, count - 1, varArgs, 0, len);
-                        args[count - 1] = varArgs;
-                    }
-                }
-                return javaMethod.invoke(obj, args);
-            } else {
-                return javaMethod.invoke(obj, arguments);
-            }
-        } catch (Throwable t) {
-           if (obj == null && t instanceof InvocationTargetException) {
-                Throwable t2 = ((InvocationTargetException) t).getTargetException();
-                throw new RuntimeException(t2);
-            } else {
-                throw new RuntimeException("Couldn't call method '" + javaMethod.getName() + "' with arguments '" + Arrays.toString(arguments)
-                        + "' on object of type '" + obj.getClass().getSimpleName() + "'.", t);
-            }
-        }
-    }
-
-    private static final class Null {
-
-    }
-
-    private static class MethodSignature {
-        private final String name;
-        @SuppressWarnings("rawtypes")
-        private final Class[] parameters;
-        private final int hashCode;
-
-        @SuppressWarnings("rawtypes")
-        public MethodSignature(String name, Class[] parameters) {
-            this.name = name;
-            this.parameters = parameters;
-            final int prime = 31;
-            int hash = 1;
-            hash = prime * hash + ((name == null) ? 0 : name.hashCode());
-            hash = prime * hash + Arrays.hashCode(parameters);
-            hashCode = hash;
-        }
-
-        @Override
-        public int hashCode() {
-            return hashCode;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj == null) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            JavaReflection.MethodSignature other = (JavaReflection.MethodSignature) obj;
-            if (name == null) {
-                if (other.name != null) {
-                    return false;
-                }
-            } else if (!name.equals(other.name)) {
-                return false;
-            }
-            if (!Arrays.equals(parameters, other.parameters)) {
-                return false;
-            }
-            return true;
-        }
-    }
-}

+ 0 - 248
src/main/java/org/ssssssss/script/parsing/CharacterStream.java

@@ -1,248 +0,0 @@
-package org.ssssssss.script.parsing;
-
-import javax.xml.transform.Source;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Wraps a the content of a {@link Source} and handles traversing the contained characters. Manages a current {@link Span} via
- * the {@link #startSpan()} and {@link #endSpan()} methods.
- */
-public class CharacterStream {
-	private final String source;
-	private final int end;
-	private int index = 0;
-	private int spanStart = 0;
-
-	private List<Integer> newLines = new ArrayList<>();
-
-	public CharacterStream(String source) {
-		this(source, 0, source.length());
-	}
-
-	public CharacterStream(String source, int start, int end) {
-		if (start > end) {
-			throw new IllegalArgumentException("Start must be <= end.");
-		}
-		if (start < 0) {
-			throw new IndexOutOfBoundsException("Start must be >= 0.");
-		}
-		if (start > Math.max(0, source.length() - 1)) {
-			throw new IndexOutOfBoundsException("Start outside of string.");
-		}
-		if (end > source.length()) {
-			throw new IndexOutOfBoundsException("End outside of string.");
-		}
-		this.source = source;
-		this.index = start;
-		this.end = end;
-		newLines.add(0);
-		for (int i = index; i < end; i++) {
-			if (this.source.charAt(i) == '\n') {
-				newLines.add(i);
-			}
-		}
-	}
-
-	public int getRowIndex(int index) {
-		int size = newLines.size();
-		int rowIndex = 1;
-		while (size > rowIndex) {
-			if (newLines.get(rowIndex) > index) {
-				break;
-			}
-			rowIndex++;
-		}
-		return rowIndex;
-	}
-
-	public int getCol(int row, int index) {
-		return index - newLines.get(row - 1);
-	}
-
-	public String substring(int startIndex, int endIndex) {
-		return this.source.substring(startIndex, endIndex);
-	}
-
-	/**
-	 * Returns whether there are more characters in the stream
-	 **/
-	public boolean hasMore() {
-		return index < end;
-	}
-
-	/**
-	 * Returns the next character without advancing the stream
-	 **/
-	public char peek() {
-		if (!hasMore()) {
-			throw new RuntimeException("No more characters in stream.");
-		}
-		return source.charAt(index++);
-	}
-
-	public Span getSpan(int start, int end) {
-		return new Span(this.source, start, end);
-	}
-
-	/**
-	 * Returns the next character and advance the stream
-	 **/
-	public char consume() {
-		if (!hasMore()) {
-			throw new RuntimeException("No more characters in stream.");
-		}
-		return source.charAt(index++);
-	}
-
-
-	/**
-	 * Matches the given needle with the next characters. Returns true if the needle is matched, false otherwise. If there's a
-	 * match and consume is true, the stream is advanced by the needle's length.
-	 */
-	public boolean match(String needle, boolean consume) {
-		int needleLength = needle.length();
-		if (needleLength + index > end) {
-			return false;
-		}
-		for (int i = 0, j = index; i < needleLength; i++, j++) {
-			if (index >= end) {
-				return false;
-			}
-			if (needle.charAt(i) != source.charAt(j)) {
-				return false;
-			}
-		}
-		if (consume) {
-			index += needleLength;
-		}
-		return true;
-	}
-
-	/**
-	 * Returns whether the next character is a digit and optionally consumes it.
-	 **/
-	public boolean matchDigit(boolean consume) {
-		if (index >= end) {
-			return false;
-		}
-		char c = source.charAt(index);
-		if (Character.isDigit(c)) {
-			if (consume) {
-				index++;
-			}
-			return true;
-		}
-		return false;
-	}
-
-	/**
-	 * Returns whether the next character is the start of an identifier and optionally consumes it. Adheres to
-	 * {@link Character#isJavaIdentifierStart(char)}.
-	 **/
-	public boolean matchIdentifierStart(boolean consume) {
-		if (index >= end) {
-			return false;
-		}
-		char c = source.charAt(index);
-		if (Character.isJavaIdentifierStart(c) || c == '@') {
-			if (consume) {
-				index++;
-			}
-			return true;
-		}
-		return false;
-	}
-
-	/**
-	 * Returns whether the next character is the start of an identifier and optionally consumes it. Adheres to
-	 * {@link Character#isJavaIdentifierPart(char)}.
-	 **/
-	public boolean matchIdentifierPart(boolean consume) {
-		if (index >= end) {
-			return false;
-		}
-		char c = source.charAt(index);
-		if (Character.isJavaIdentifierPart(c)) {
-			if (consume) {
-				index++;
-			}
-			return true;
-		}
-		return false;
-	}
-
-	public void skipLine() {
-		while (true) {
-			if (index >= end) {
-				return;
-			}
-			char c = source.charAt(index++);
-			if (c == '\n') {
-				break;
-			}
-		}
-	}
-
-	public void skipUntil(String chars) {
-		while (true) {
-			if (index >= end) {
-				return;
-			}
-			boolean matched = true;
-			for (int i = 0, len = chars.length(); i < len && index + i < end; i++) {
-				if (chars.charAt(i) != source.charAt(index + i)) {
-					matched = false;
-					break;
-				}
-			}
-			this.index += matched ? chars.length() : 1;
-			if (matched) {
-				break;
-			}
-		}
-	}
-
-	/**
-	 * Skips any number of successive whitespace characters.
-	 **/
-	public void skipWhiteSpace() {
-		while (true) {
-			if (index >= end) {
-				return;
-			}
-			char c = source.charAt(index);
-			if (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
-				index++;
-				continue;
-			} else {
-				break;
-			}
-		}
-	}
-
-	/**
-	 * Start a new Span at the current stream position. Call {@link #endSpan()} to complete the span.
-	 **/
-	public void startSpan() {
-		spanStart = index;
-	}
-
-	/**
-	 * Completes the span started with {@link #startSpan()} at the current stream position.
-	 **/
-	public Span endSpan() {
-		return new Span(source, spanStart, index);
-	}
-
-	public boolean isSpanEmpty() {
-		return spanStart == this.index;
-	}
-
-	/**
-	 * Returns the current character position in the stream.
-	 **/
-	public int getPosition() {
-		return index;
-	}
-}

+ 0 - 68
src/main/java/org/ssssssss/script/parsing/GenericTokenParser.java

@@ -1,68 +0,0 @@
-package org.ssssssss.script.parsing;
-
-import java.util.function.Function;
-
-
-public class GenericTokenParser {
-
-	private String open;
-
-	private String close;
-
-	private boolean skipStr;
-
-	public GenericTokenParser(String open, String close, boolean skipStr) {
-		this.open = open;
-		this.close = close;
-		this.skipStr = skipStr;
-	}
-
-	public String parse(String source, Function<String, String> handler) {
-		CharacterStream stream = new CharacterStream(source);
-		StringBuilder builder = new StringBuilder();
-		while (stream.hasMore()) {
-			builder.append(parseStream(stream, null, handler));
-		}
-		return builder.toString();
-	}
-
-	private String parseStream(CharacterStream stream, String expect, Function<String, String> handler) {
-		StringBuilder builder = new StringBuilder();
-		while (stream.hasMore()) {
-			if (expect != null && stream.match(expect, true)) {
-				return builder.toString();
-			}
-			if (stream.match(open, true)) {
-				String value = handler.apply(parseStream(stream, close, handler));
-				if (value != null) {
-					builder.append(value);
-				}
-			} else {
-				char ch = stream.consume();
-				builder.append(ch);
-				if (skipStr && ch == '\'') {
-					builder.append(consumeUntil(stream, "'"));
-				} else if (skipStr && ch == '"') {
-					builder.append(consumeUntil(stream, "\""));
-				} else if (ch == '{') {
-					builder.append(parseStream(stream, "}", handler)).append("}");
-				}
-			}
-		}
-		return builder.toString();
-	}
-
-	private String consumeUntil(CharacterStream stream, String str) {
-		int start = stream.getPosition();
-		while (stream.hasMore()) {
-			if (stream.match("\\", true)) {
-				stream.consume();
-			}
-			if (stream.match(str, true)) {
-				break;
-			}
-			stream.consume();
-		}
-		return stream.substring(start, stream.getPosition());
-	}
-}

+ 0 - 464
src/main/java/org/ssssssss/script/parsing/Parser.java

@@ -1,464 +0,0 @@
-package org.ssssssss.script.parsing;
-
-
-import org.ssssssss.script.MagicScript;
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.interpreter.AstInterpreter;
-import org.ssssssss.script.parsing.ast.*;
-import org.ssssssss.script.parsing.ast.binary.BinaryOperation;
-
-import javax.xml.transform.Source;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-
-/**
- * Parses a {@link Source} into a {@link MagicScript}. The implementation is a simple recursive descent parser with a lookahead of
- * 1.
- **/
-public class Parser {
-
-    private static final TokenType[][] binaryOperatorPrecedence = new TokenType[][]{new TokenType[]{TokenType.Assignment},
-            new TokenType[]{TokenType.Or, TokenType.And, TokenType.Xor}, new TokenType[]{TokenType.Equal, TokenType.NotEqual},
-            new TokenType[]{TokenType.Less, TokenType.LessEqual, TokenType.Greater, TokenType.GreaterEqual}, new TokenType[]{TokenType.Plus, TokenType.Minus},
-            new TokenType[]{TokenType.ForwardSlash, TokenType.Asterisk, TokenType.Percentage}};
-    private static final TokenType[] unaryOperators = new TokenType[]{TokenType.Not, TokenType.Plus, TokenType.Minus};
-
-    /**
-     * Parses a {@link Source} into a {@link MagicScript}.
-     **/
-    public static List<Node> parse(String source) {
-        List<Node> nodes = new ArrayList<Node>();
-        TokenStream stream = new TokenStream(new Tokenizer().tokenize(source));
-        while (stream.hasMore()) {
-            Node node = parseStatement(stream);
-            if (node != null) {
-                nodes.add(node);
-            }
-        }
-        return nodes;
-    }
-
-    private static Node parseStatement(TokenStream tokens) {
-        return parseStatement(tokens, false);
-    }
-
-    private static Node parseStatement(TokenStream tokens, boolean expectRightCurly) {
-        Node result = null;
-        if (tokens.match("import", false)) {
-            result = parseImport(tokens);
-        } else if (tokens.match("var", false)) {
-            result = parseVarDefine(tokens);
-        } else if (tokens.match("if", false)) {
-            result = parseIfStatement(tokens);
-        } else if (tokens.match("return", false)) {
-            result = parseReturn(tokens);
-        } else if (tokens.match("for", false)) {
-            result = parseForStatement(tokens);
-        } else if (tokens.match("continue", false)) {
-            result = new Continue(tokens.consume().getSpan());
-        } else if (tokens.match("break", false)) {
-            result = new Break(tokens.consume().getSpan());
-        } else {
-            result = parseExpression(tokens, expectRightCurly);
-        }
-        // consume semi-colons as statement delimiters
-        while (tokens.match(";", true)) {
-            ;
-        }
-        return result;
-    }
-
-    private static Import parseImport(TokenStream stream) {
-        Span opening = stream.expect("import").getSpan();
-        if (stream.hasMore()) {
-            Token expected = stream.consume();
-            String packageName = null;
-            boolean isStringLiteral = expected.getType() == TokenType.StringLiteral;
-            if (isStringLiteral) {
-                packageName = new StringLiteral(expected.getSpan()).getValue();
-            } else if (expected.getType() == TokenType.Identifier) {
-                packageName = expected.getSpan().getText();
-            } else {
-                MagicScriptError.error("Expected identifier or string, but got stream is " + expected.getType().getError(), stream.getPrev().getSpan());
-            }
-            String varName = packageName;
-            if (isStringLiteral || stream.match("as",false)) {
-                stream.expect("as");
-                expected = stream.expect(TokenType.Identifier);
-                varName = expected.getSpan().getText();
-            }
-            return new Import(new Span(opening, expected.getSpan()), packageName, varName, !isStringLiteral);
-        }
-        MagicScriptError.error("Expected identifier or string, but got stream is EOF", stream.getPrev().getSpan());
-        return null;
-    }
-
-    private static VariableDefine parseVarDefine(TokenStream stream) {
-        Span opening = stream.expect("var").getSpan();
-        TokenType expected = null;
-        if (stream.hasMore()) {
-            expected = TokenType.Identifier;
-            Token token = stream.expect(expected);
-            String variableName = token.getSpan().getText();
-            expected = TokenType.Assignment;
-            if (stream.hasMore()) {
-                stream.expect(expected);
-                Expression right = parseExpression(stream);
-                return new VariableDefine(new Span(opening, stream.getPrev().getSpan()), variableName, right);
-            }
-        }
-        MagicScriptError.error("Expected " + expected.getError() + ", but got stream is EOF", stream.getPrev().getSpan());
-        return null;
-    }
-
-    private static FunctionStatement parseFunctionStatement(TokenStream stream) {
-        Span openingFunction = stream.expect("function").getSpan();
-        stream.expect("(");
-        List<String> parameters = new ArrayList<>();
-        while (stream.hasMore() && stream.match(TokenType.Identifier, false)) {
-            Token token = stream.consume();
-            parameters.add(token.getSpan().getText());
-            if (!stream.hasMore()) {
-                MagicScriptError.error("function Did not closing ", stream.prev().getSpan());
-            }
-            if (!stream.match(TokenType.Comma, true)) {
-                if (!stream.match(TokenType.RightParantheses, false)) {
-                    MagicScriptError.error("Did not find closing ).", stream.prev().getSpan());
-                } else {
-                    break;
-                }
-            }
-        }
-        stream.expect(")");
-        stream.expect("{");
-        List<Node> childNodes = new ArrayList<>();
-        while (stream.hasMore() && !stream.match(false, "}")) {
-            childNodes.add(parseStatement(stream, true));
-        }
-        Span closingEnd = expectCloseing(stream);
-        return new FunctionStatement(new Span(openingFunction, closingEnd), childNodes, parameters);
-    }
-
-    private static ForStatement parseForStatement(TokenStream stream) {
-        Span openingFor = stream.expect("for").getSpan();
-        stream.expect("(");
-        Span index = null;
-        Span value = stream.expect(TokenType.Identifier).getSpan();
-
-        if (stream.match(TokenType.Comma, true)) {
-            index = value;
-            value = stream.expect(TokenType.Identifier).getSpan();
-        }
-
-        stream.expect("in");
-
-        Expression mapOrArray = parseExpression(stream);
-        stream.expect(")");
-        stream.expect("{");
-        List<Node> body = new ArrayList<Node>();
-        while (stream.hasMore() && !stream.match(false, "}")) {
-            body.add(parseStatement(stream, true));
-        }
-        Span closingEnd = expectCloseing(stream);
-        return new ForStatement(new Span(openingFor, closingEnd), index, value, mapOrArray, body);
-    }
-
-    private static Span expectCloseing(TokenStream stream) {
-        if (!stream.hasMore()) {
-            MagicScriptError.error("Did not find closing }.", stream.prev().getSpan());
-        }
-        return stream.expect("}").getSpan();
-    }
-
-    private static Node parseIfStatement(TokenStream stream) {
-        Span openingIf = stream.expect("if").getSpan();
-        Expression condition = parseExpression(stream);
-        stream.expect("{");
-        List<Node> trueBlock = new ArrayList<Node>();
-        while (stream.hasMore() && !stream.match("}", false)) {
-            Node node = parseStatement(stream, true);
-            if (node != null) {
-                trueBlock.add(node);
-            }
-        }
-        expectCloseing(stream);
-        List<IfStatement> elseIfs = new ArrayList<IfStatement>();
-        List<Node> falseBlock = new ArrayList<Node>();
-        while (stream.hasMore() && stream.match("else", true)) {
-            if (stream.hasMore() && stream.match("if", false)) {
-                Span elseIfOpening = stream.expect("if").getSpan();
-                Expression elseIfCondition = parseExpression(stream);
-                stream.expect("{");
-                List<Node> elseIfBlock = new ArrayList<Node>();
-                while (stream.hasMore() && !stream.match("}", false)) {
-                    Node node = parseStatement(stream, true);
-                    if (node != null) {
-                        elseIfBlock.add(node);
-                    }
-                }
-                expectCloseing(stream);
-                Span elseIfSpan = new Span(elseIfOpening, elseIfBlock.size() > 0 ? elseIfBlock.get(elseIfBlock.size() - 1).getSpan() : elseIfOpening);
-                elseIfs.add(new IfStatement(elseIfSpan, elseIfCondition, elseIfBlock, new ArrayList<IfStatement>(), new ArrayList<Node>()));
-            } else {
-                stream.expect("{");
-                while (stream.hasMore() && !stream.match("}", false)) {
-                    falseBlock.add(parseStatement(stream, true));
-                }
-                expectCloseing(stream);
-                break;
-            }
-        }
-        Span closingEnd = stream.getPrev().getSpan();
-
-        return new IfStatement(new Span(openingIf, closingEnd), condition, trueBlock, elseIfs, falseBlock);
-    }
-
-    private static Node parseReturn(TokenStream tokens) {
-        Span returnSpan = tokens.expect("return").getSpan();
-        if (tokens.match(";", false)) return new Return(returnSpan, null);
-        Expression returnValue = parseExpression(tokens);
-        return new Return(new Span(returnSpan, returnValue.getSpan()), returnValue);
-    }
-
-    public static Expression parseExpression(TokenStream stream) {
-        return parseTernaryOperator(stream);
-    }
-
-    public static Expression parseExpression(TokenStream stream, boolean expectRightCurly) {
-        return parseTernaryOperator(stream, expectRightCurly);
-    }
-
-    private static Expression parseTernaryOperator(TokenStream stream, boolean expectRightCurly) {
-        Expression condition = parseBinaryOperator(stream, 0, expectRightCurly);
-        if (stream.match(TokenType.Questionmark, true)) {
-            Expression trueExpression = parseTernaryOperator(stream, expectRightCurly);
-            stream.expect(TokenType.Colon);
-            Expression falseExpression = parseTernaryOperator(stream, expectRightCurly);
-            return new TernaryOperation(condition, trueExpression, falseExpression);
-        } else {
-            return condition;
-        }
-    }
-
-    private static Expression parseTernaryOperator(TokenStream stream) {
-        return parseTernaryOperator(stream, false);
-    }
-
-    private static Expression parseBinaryOperator(TokenStream stream, int level, boolean expectRightCurly) {
-        int nextLevel = level + 1;
-        Expression left = nextLevel == binaryOperatorPrecedence.length ? parseUnaryOperator(stream, expectRightCurly) : parseBinaryOperator(stream, nextLevel, expectRightCurly);
-
-        TokenType[] operators = binaryOperatorPrecedence[level];
-        while (stream.hasMore() && stream.match(false, operators)) {
-            Token operator = stream.consume();
-            Expression right = nextLevel == binaryOperatorPrecedence.length ? parseUnaryOperator(stream, expectRightCurly) : parseBinaryOperator(stream, nextLevel, expectRightCurly);
-            left = BinaryOperation.create(left, operator, right);
-        }
-
-        return left;
-    }
-
-
-    private static Expression parseUnaryOperator(TokenStream stream, boolean expectRightCurly) {
-        if (stream.match(false, unaryOperators)) {
-            return new UnaryOperation(stream.consume(), parseUnaryOperator(stream, expectRightCurly));
-        } else {
-            if (stream.match(TokenType.LeftParantheses, false)) {    //(
-                Span openSpan = stream.expect(TokenType.LeftParantheses).getSpan();
-                int index = stream.makeIndex();
-                List<String> parameters = new ArrayList<>();
-                while(stream.match(TokenType.Identifier,false)){
-                    Token identifier = stream.expect(TokenType.Identifier);
-                    parameters.add(identifier.getSpan().getText());
-                    if(stream.match(TokenType.Comma,true)){ //,
-                        continue;
-                    }
-                    if(stream.match(TokenType.RightParantheses,true)){  //)
-                        if(stream.match(TokenType.Lambda,true)){   // =>
-                            return parseLambdaBody(stream, openSpan, parameters);
-                        }
-                        break;
-                    }
-                }
-                if(stream.match(TokenType.RightParantheses,true) && stream.match(TokenType.Lambda, true)){
-                    return parseLambdaBody(stream, openSpan, parameters);
-                }
-                stream.resetIndex(index);
-                Expression expression = parseExpression(stream);
-                stream.expect(TokenType.RightParantheses);
-                return expression;
-            } else {
-                return parseAccessOrCallOrLiteral(stream,expectRightCurly);
-            }
-        }
-    }
-
-    private static Expression parseLambdaBody(TokenStream stream, Span openSpan, List<String> parameters) {
-        int index = stream.makeIndex();
-        List<Node> childNodes = new ArrayList<>();
-        try {
-            Expression expression = parseExpression(stream);
-            childNodes.add(new Return(new Span("return", 0, 6), expression));
-            return new LambdaFunction(new Span(openSpan, expression.getSpan()), parameters, childNodes);
-        } catch (Exception e) {
-            stream.resetIndex(index);
-            if (stream.match(TokenType.LeftCurly, true)) {
-                while (stream.hasMore() && !stream.match(false, "}")) {
-                    childNodes.add(parseStatement(stream, true));
-                }
-                Span closeSpan = expectCloseing(stream);
-                return new LambdaFunction(new Span(openSpan, closeSpan), parameters, childNodes);
-            } else {
-                Node node = parseStatement(stream);
-                childNodes.add(new Return(new Span("return", 0, 6), node));
-                return new LambdaFunction(new Span(openSpan, node.getSpan()), parameters, childNodes);
-            }
-        }
-    }
-
-    private static Expression parseAccessOrCallOrLiteral(TokenStream stream, boolean expectRightCurly) {
-        if (expectRightCurly && stream.match("}", false)) {
-            return null;
-        } else if (stream.match("function", false)) {
-            return parseFunctionStatement(stream);
-        } else if (stream.match(TokenType.Identifier, false)) {
-            return parseAccessOrCall(stream, TokenType.Identifier);
-        } else if (stream.match(TokenType.LeftCurly, false)) {
-            return parseMapLiteral(stream);
-        } else if (stream.match(TokenType.LeftBracket, false)) {
-            return parseListLiteral(stream);
-        } else if (stream.match(TokenType.StringLiteral, false)) {
-            if (stream.hasNext()) {
-                if (stream.next().getType() == TokenType.Period) {
-                    stream.prev();
-                    return parseAccessOrCall(stream, TokenType.StringLiteral);
-                }
-                stream.prev();
-            }
-
-            return new StringLiteral(stream.expect(TokenType.StringLiteral).getSpan());
-        } else if (stream.match(TokenType.BooleanLiteral, false)) {
-            return new BooleanLiteral(stream.expect(TokenType.BooleanLiteral).getSpan());
-        } else if (stream.match(TokenType.DoubleLiteral, false)) {
-            return new DoubleLiteral(stream.expect(TokenType.DoubleLiteral).getSpan());
-        } else if (stream.match(TokenType.FloatLiteral, false)) {
-            return new FloatLiteral(stream.expect(TokenType.FloatLiteral).getSpan());
-        } else if (stream.match(TokenType.ByteLiteral, false)) {
-            return new ByteLiteral(stream.expect(TokenType.ByteLiteral).getSpan());
-        } else if (stream.match(TokenType.ShortLiteral, false)) {
-            return new ShortLiteral(stream.expect(TokenType.ShortLiteral).getSpan());
-        } else if (stream.match(TokenType.IntegerLiteral, false)) {
-            return new IntegerLiteral(stream.expect(TokenType.IntegerLiteral).getSpan());
-        } else if (stream.match(TokenType.LongLiteral, false)) {
-            return new LongLiteral(stream.expect(TokenType.LongLiteral).getSpan());
-        } else if (stream.match(TokenType.CharacterLiteral, false)) {
-            return new CharacterLiteral(stream.expect(TokenType.CharacterLiteral).getSpan());
-        } else if (stream.match(TokenType.NullLiteral, false)) {
-            return new NullLiteral(stream.expect(TokenType.NullLiteral).getSpan());
-        } else {
-            MagicScriptError.error("Expected a variable, field, map, array, function or method call, or literal.", stream);
-            return null; // not reached
-        }
-    }
-
-
-    private static Expression parseMapLiteral(TokenStream stream) {
-        Span openCurly = stream.expect(TokenType.LeftCurly).getSpan();
-
-        List<Token> keys = new ArrayList<>();
-        List<Expression> values = new ArrayList<>();
-        while (stream.hasMore() && !stream.match("}", false)) {
-            if (stream.match(TokenType.StringLiteral, false)) {
-                keys.add(stream.expect(TokenType.StringLiteral));
-            } else {
-                keys.add(stream.expect(TokenType.Identifier));
-            }
-
-            stream.expect(":");
-            values.add(parseExpression(stream));
-            if (!stream.match("}", false)) {
-                stream.expect(TokenType.Comma);
-            }
-        }
-        Span closeCurly = stream.expect("}").getSpan();
-        return new MapLiteral(new Span(openCurly, closeCurly), keys, values);
-    }
-
-    private static Expression parseListLiteral(TokenStream stream) {
-        Span openBracket = stream.expect(TokenType.LeftBracket).getSpan();
-
-        List<Expression> values = new ArrayList<>();
-        while (stream.hasMore() && !stream.match(TokenType.RightBracket, false)) {
-            values.add(parseExpression(stream));
-            if (!stream.match(TokenType.RightBracket, false)) {
-                stream.expect(TokenType.Comma);
-            }
-        }
-
-        Span closeBracket = stream.expect(TokenType.RightBracket).getSpan();
-        return new ListLiteral(new Span(openBracket, closeBracket), values);
-    }
-
-    private static Expression parseAccessOrCall(TokenStream stream, TokenType tokenType) {
-        //Span identifier = stream.expect(TokenType.Identifier);
-        //Expression result = new VariableAccess(identifier);
-        Span identifier = stream.expect(tokenType).getSpan();
-        if (tokenType == TokenType.Identifier && stream.match(TokenType.Lambda, true)) {
-            return parseLambdaBody(stream, identifier, Arrays.asList(identifier.getText()));
-        }
-        Expression result = tokenType == TokenType.StringLiteral ? new StringLiteral(identifier) : new VariableAccess(identifier);
-
-        while (stream.hasMore() && stream.match(false, TokenType.LeftParantheses, TokenType.LeftBracket, TokenType.Period)) {
-
-            // function or method call
-            if (stream.match(TokenType.LeftParantheses, false)) {
-                List<Expression> arguments = parseArguments(stream);
-                Span closingSpan = stream.expect(TokenType.RightParantheses).getSpan();
-                if (result instanceof VariableAccess || result instanceof MapOrArrayAccess)
-                    result = new FunctionCall(new Span(result.getSpan(), closingSpan), result, arguments);
-                else if (result instanceof MemberAccess) {
-                    result = new MethodCall(new Span(result.getSpan(), closingSpan), (MemberAccess)result, arguments);
-                } else {
-                    MagicScriptError.error("Expected a variable, field or method.", stream);
-                }
-            }
-
-            // map or array access
-            else if (stream.match(TokenType.LeftBracket, true)) {
-                Expression keyOrIndex = parseExpression(stream);
-                Span closingSpan = stream.expect(TokenType.RightBracket).getSpan();
-                result = new MapOrArrayAccess(new Span(result.getSpan(), closingSpan), result, keyOrIndex);
-            }
-
-            // field or method access
-            else if (stream.match(TokenType.Period, true)) {
-                identifier = stream.expect(TokenType.Identifier).getSpan();
-                result = new MemberAccess(result, identifier);
-            }
-        }
-
-        return result;
-    }
-
-    /**
-     * Does not consume the closing parentheses.
-     **/
-    private static List<Expression> parseArguments(TokenStream stream) {
-        stream.expect(TokenType.LeftParantheses);
-        List<Expression> arguments = new ArrayList<Expression>();
-        while (stream.hasMore() && !stream.match(TokenType.RightParantheses, false)) {
-            arguments.add(parseExpression(stream));
-            if (!stream.match(TokenType.RightParantheses, false)) stream.expect(TokenType.Comma);
-        }
-        return arguments;
-    }
-
-    public static void main(String[] args) {
-        System.out.println(AstInterpreter.interpret(MagicScript.create("return message!=null&&message.length()>=3"), new MagicScriptContext(new HashMap<>())));
-        ;
-    }
-}

+ 0 - 222
src/main/java/org/ssssssss/script/parsing/Span.java

@@ -1,222 +0,0 @@
-package org.ssssssss.script.parsing;
-
-/**
- * A span within a source string denoted by start and end index, with the latter being exclusive.
- */
-public class Span {
-	/**
-	 * the source string this span refers to
-	 **/
-	private final String source;
-	/**
-	 * Cached String instance to reduce pressure on GC
-	 **/
-	private final String cachedText;
-	/**
-	 * start index in source string, starting at 0
-	 **/
-	private int start;
-	/**
-	 * end index in source string, exclusive, starting at 0
-	 **/
-	private int end;
-
-	private Line line;
-
-	public Span(String source) {
-		this(source, 0, source.length());
-	}
-
-
-	public Span(String source, int start, int end) {
-		if (start > end) {
-			throw new IllegalArgumentException("Start must be <= end.");
-		}
-		if (start < 0) {
-			throw new IndexOutOfBoundsException("Start must be >= 0.");
-		}
-//        if (start > source.length() - 1) {
-//            throw new IndexOutOfBoundsException("Start outside of string.");
-//        }
-		if (end > source.length()) {
-			throw new IndexOutOfBoundsException("End outside of string.");
-		}
-
-		this.source = source;
-		this.start = start;
-		this.end = end;
-		this.cachedText = source.substring(start, end);
-	}
-
-	public Span(Span start, Span end) {
-		if (!start.source.equals(end.source)) {
-			throw new IllegalArgumentException("The two spans do not reference the same source.");
-		}
-		if (start.start > end.end) {
-			throw new IllegalArgumentException("Start must be <= end.");
-		}
-		if (start.start < 0) {
-			throw new IndexOutOfBoundsException("Start must be >= 0.");
-		}
-		if (start.start > start.source.length() - 1) {
-			throw new IndexOutOfBoundsException("Start outside of string.");
-		}
-		if (end.end > start.source.length()) {
-			throw new IndexOutOfBoundsException("End outside of string.");
-		}
-
-		this.source = start.source;
-		this.start = start.start;
-		this.end = end.end;
-		this.cachedText = source.substring(this.start, this.end);
-	}
-
-
-	/**
-	 * Returns the text referenced by this span
-	 **/
-	public String getText() {
-		return cachedText;
-	}
-
-	/**
-	 * Returns the index of the first character of this span.
-	 **/
-	public int getStart() {
-		return start;
-	}
-
-	/**
-	 * Returns the index of the last character of this span plus 1.
-	 **/
-	public int getEnd() {
-		return end;
-	}
-
-	/**
-	 * Returns the source string this span references.
-	 **/
-	public String getSource() {
-		return source;
-	}
-
-	@Override
-	public String toString() {
-		return "Span [text=" + getText() + ", start=" + start + ", end=" + end + "]";
-	}
-
-	/**
-	 * Returns the line this span is on. Does not return a correct result for spans across multiple lines.
-	 **/
-	public Line getLine() {
-	    if(this.line != null){
-	        return this.line;
-        }
-		int lineStart = start;
-		while (lineStart < end) {
-			if (lineStart < 0) {
-				break;
-			}
-			char c = source.charAt(lineStart);
-			if (c == '\n') {
-				lineStart = lineStart + 1;
-				break;
-			}
-			lineStart--;
-		}
-		if (lineStart < 0) {
-			lineStart = 0;
-		}
-
-		int lineEnd = end;
-		while (true) {
-			if (lineEnd > source.length() - 1) {
-				break;
-			}
-			char c = source.charAt(lineEnd);
-			if (c == '\n') {
-				break;
-			}
-			lineEnd++;
-		}
-
-		int lineNumber = 0;
-		int idx = lineStart;
-		while (idx > 0 && idx < end) {
-			char c = source.charAt(idx);
-			if (c == '\n') {
-				lineNumber++;
-			}
-			idx--;
-		}
-		lineNumber++;
-		idx = lineStart + 1;
-		int endLineNumber = lineNumber;
-        while (idx < lineEnd) {
-            char c = source.charAt(idx);
-            if (c == '\n') {
-                endLineNumber++;
-            }
-            idx++;
-        }
-        int startCol = this.start - lineStart + 1;
-        int endCol = startCol + this.end - this.start - 1;
-		this.line = new Line(source, lineStart, lineEnd, lineNumber,endLineNumber,startCol,endCol);
-		return this.line;
-	}
-
-	/**
-	 * A line within a Source
-	 **/
-	public static class Line {
-		private final String source;
-		private final int start;
-		private final int end;
-		private final int lineNumber;
-        private final int endLineNumber;
-		private final int startCol;
-		private final int endCol;
-
-		public Line(String source, int start, int end, int lineNumber,int endLineNumber,int startCol,int endCol) {
-			this.source = source;
-			this.start = start;
-			this.end = end;
-			this.lineNumber = lineNumber;
-			this.endLineNumber = endLineNumber;
-			this.startCol = startCol;
-			this.endCol = endCol;
-		}
-
-        public int getStartCol() {
-            return startCol;
-        }
-
-        public int getEndCol() {
-            return endCol;
-        }
-
-        public String getSource() {
-			return source;
-		}
-
-		public int getStart() {
-			return start;
-		}
-
-		public int getEnd() {
-			return end;
-		}
-
-        public int getEndLineNumber() {
-            return endLineNumber;
-        }
-
-        public int getLineNumber() {
-			return lineNumber;
-		}
-
-		public String getText() {
-			return source.substring(start, end);
-		}
-	}
-}

+ 0 - 31
src/main/java/org/ssssssss/script/parsing/Token.java

@@ -1,31 +0,0 @@
-package org.ssssssss.script.parsing;
-
-/**
- * A token produced by the {@link Tokenizer}.
- */
-public class Token {
-    private final TokenType type;
-    private final Span span;
-
-    public Token(TokenType type, Span span) {
-        this.type = type;
-        this.span = span;
-    }
-
-    public TokenType getType() {
-        return type;
-    }
-
-    public Span getSpan() {
-        return span;
-    }
-
-    public String getText() {
-        return span.getText();
-    }
-
-    @Override
-    public String toString() {
-        return "Token [type=" + type + ", span=" + span + "]";
-    }
-}

+ 0 - 189
src/main/java/org/ssssssss/script/parsing/TokenStream.java

@@ -1,189 +0,0 @@
-package org.ssssssss.script.parsing;
-
-import org.ssssssss.script.MagicScriptError;
-
-import javax.xml.transform.Source;
-import java.util.List;
-
-
-/**
- * Iterates over a list of {@link Token} instances, provides methods to match expected tokens and throw errors in case of a
- * mismatch.
- */
-public class TokenStream {
-    private final List<Token> tokens;
-    private final int end;
-    private int index;
-    private int makeIndex;
-
-    public TokenStream(List<Token> tokens) {
-        this.tokens = tokens;
-        this.index = 0;
-        this.end = tokens.size();
-    }
-
-    /**
-     * Returns whether there are more tokens in the stream.
-     **/
-    public boolean hasMore() {
-        return index < end;
-    }
-
-    public boolean hasNext() {
-        return index + 1 < end;
-    }
-
-    public boolean hasPrev() {
-        return index > 0;
-    }
-
-    public int makeIndex(){
-        this.makeIndex = index;
-        return index;
-    }
-    public void resetIndex(){
-        this.index = this.makeIndex;
-    }
-    public void resetIndex(int index){
-        this.index = index;
-    }
-
-    /**
-     * Consumes the next token and returns it.
-     **/
-    public Token consume() {
-        if (!hasMore()) {
-            throw new RuntimeException("Reached the end of the source.");
-        }
-        return tokens.get(index++);
-    }
-
-    public Token next() {
-        if (!hasMore()) {
-            throw new RuntimeException("Reached the end of the source.");
-        }
-        return tokens.get(++index);
-    }
-
-    public Token prev() {
-        if (index == 0) {
-            throw new RuntimeException("Reached the end of the source.");
-        }
-        return tokens.get(--index);
-    }
-
-    public Token getPrev() {
-        if (index == 0) {
-            throw new RuntimeException("Reached the end of the source.");
-        }
-        return tokens.get(index - 1);
-    }
-
-    /**
-     * Checks if the next token has the give type and optionally consumes, or throws an error if the next token did not match the
-     * type.
-     */
-    public Token expect(TokenType type) {
-        boolean result = match(type, true);
-        if (!result) {
-            Token token = index < tokens.size() ? tokens.get(index) : null;
-            Span span = token != null ? token.getSpan() : null;
-            if (span == null) {
-                MagicScriptError.error("Expected '" + type.getError() + "', but reached the end of the source.", this);
-            } else {
-                MagicScriptError.error("Expected '" + type.getError() + "', but got '" + token.getText() + "'", span);
-            }
-            return null; // never reached
-        } else {
-            return tokens.get(index - 1);
-        }
-    }
-
-    /**
-     * Checks if the next token matches the given text and optionally consumes, or throws an error if the next token did not match
-     * the text.
-     */
-    public Token expect(String text) {
-        boolean result = match(text, true);
-        if (!result) {
-            Token token = index < tokens.size() ? tokens.get(index) : null;
-            Span span = token != null ? token.getSpan() : null;
-            if (span == null) {
-                MagicScriptError.error("Expected '" + text + "', but reached the end of the source.", this);
-            } else {
-                MagicScriptError.error("Expected '" + text + "', but got '" + token.getText() + "'", span);
-            }
-            return null; // never reached
-        } else {
-            return tokens.get(index - 1);
-        }
-    }
-
-    /**
-     * Matches and optionally consumes the next token in case of a match. Returns whether the token matched.
-     */
-    public boolean match(TokenType type, boolean consume) {
-        if (index >= end) {
-            return false;
-        }
-        if (tokens.get(index).getType() == type) {
-            if (consume) {
-                index++;
-            }
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Matches and optionally consumes the next token in case of a match. Returns whether the token matched.
-     */
-    public boolean match(String text, boolean consume) {
-        if (index >= end) {
-            return false;
-        }
-        if (tokens.get(index).getText().equals(text)) {
-            if (consume) {
-                index++;
-            }
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Matches any of the token types and optionally consumes the next token in case of a match. Returns whether the token
-     * matched.
-     */
-    public boolean match(boolean consume, TokenType... types) {
-        for (TokenType type : types) {
-            if (match(type, consume)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Matches any of the token texts and optionally consumes the next token in case of a match. Returns whether the token
-     * matched.
-     */
-    public boolean match(boolean consume, String... tokenTexts) {
-        for (String text : tokenTexts) {
-            if (match(text, consume)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns the {@link Source} this stream wraps.
-     */
-    public String getSource() {
-        if (tokens.size() == 0) {
-            return null;
-        }
-        return tokens.get(0).getSpan().getSource();
-    }
-}

+ 0 - 114
src/main/java/org/ssssssss/script/parsing/TokenType.java

@@ -1,114 +0,0 @@
-package org.ssssssss.script.parsing;
-
-import java.util.Arrays;
-import java.util.Comparator;
-
-/**
- * Enumeration of token types. A token type consists of a representation for error messages, and may optionally specify a literal
- * to be used by the {@link CharacterStream} to recognize the token. Token types are sorted by their literal length to easy
- * matching of token types with common prefixes, e.g. "<" and "<=". Token types with longer literals are matched first.
- */
-public enum TokenType {
-    // @off
-    Period(".", "."),
-    Lambda("=>", "=>"),
-    Comma(",", ","),
-    Semicolon(";", ";"),
-    Colon(":", ":"),
-    Plus("+", "+"),
-    Minus("-", "-"),
-    Asterisk("*", "*"),
-    ForwardSlash("/", "/"),
-    PostSlash("\\", "\\"),
-    Percentage("%", "%"),
-    LeftParantheses("(", ")"),
-    RightParantheses(")", ")"),
-    LeftBracket("[", "["),
-    RightBracket("]", "]"),
-    LeftCurly("{", "{"),
-    RightCurly("}"), // special treatment!
-    Less("<", "<"),
-    Greater(">", ">"),
-    LessEqual("<=", "<="),
-    GreaterEqual(">=", ">="),
-    Equal("==", "=="),
-    NotEqual("!=", "!="),
-    Assignment("=", "="),
-    And("&&", "&&"),
-    Or("||", "||"),
-    Xor("^", "^"),
-    Not("!", "!"),
-    Questionmark("?", "?"),
-    DoubleQuote("\"", "\""),
-    SingleQuote("'", "'"),
-    BooleanLiteral("true or false"),
-    DoubleLiteral("a double floating point number"),
-    FloatLiteral("a floating point number"),
-    LongLiteral("a long integer number"),
-    IntegerLiteral("an integer number"),
-    ShortLiteral("a short integer number"),
-    ByteLiteral("a byte integer number"),
-    CharacterLiteral("a character"),
-    StringLiteral("a string"),
-    NullLiteral("null"),
-    Identifier("an identifier");
-    // @on
-
-    private static TokenType[] values;
-
-    static {
-        // Sort the token types by their literal length. The character stream uses this
-        // this order to match tokens with the longest length first.
-        values = TokenType.values();
-        Arrays.sort(values, new Comparator<TokenType>() {
-            @Override
-            public int compare(TokenType o1, TokenType o2) {
-                if (o1.literal == null && o2.literal == null) {
-                    return 0;
-                }
-                if (o1.literal == null && o2.literal != null) {
-                    return 1;
-                }
-                if (o1.literal != null && o2.literal == null) {
-                    return -1;
-                }
-                return o2.literal.length() - o1.literal.length();
-            }
-        });
-    }
-
-    private final String literal;
-    private final String error;
-
-    TokenType(String error) {
-        this.literal = null;
-        this.error = error;
-    }
-
-    TokenType(String literal, String error) {
-        this.literal = literal;
-        this.error = error;
-    }
-
-    /**
-     * Returns an array of token types, sorted in descending order based on their literal length. This is used by the
-     * {@link CharacterStream} to match token types with the longest literal first. E.g. "<=" will be matched before "<".
-     **/
-    public static TokenType[] getSortedValues() {
-        return values;
-    }
-
-    /**
-     * The literal to match, may be null.
-     **/
-    public String getLiteral() {
-        return literal;
-    }
-
-    /**
-     * The error string to use when reporting this token type in an error message.
-     **/
-    public String getError() {
-        return error;
-    }
-}

+ 0 - 177
src/main/java/org/ssssssss/script/parsing/Tokenizer.java

@@ -1,177 +0,0 @@
-package org.ssssssss.script.parsing;
-
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.exception.StringLiteralException;
-
-import java.util.ArrayList;
-import java.util.List;
-
-
-public class Tokenizer {
-
-    public List<Token> tokenize(String source) {
-        CharacterStream stream = new CharacterStream(source, 0, source.length());
-        List<Token> tokens = new ArrayList<Token>();
-        int leftCount = 0;
-        int rightCount = 0;
-        outer:
-        while (stream.hasMore()) {
-            stream.skipWhiteSpace();
-            if (stream.match("//", true)) {    //注释
-                stream.skipLine();
-                continue;
-            }
-            if (stream.match("/*", true)) {    //多行注释
-                stream.skipUntil("*/");
-                continue;
-            }
-            if (stream.matchDigit(false)) {
-                TokenType type = TokenType.IntegerLiteral;
-                stream.startSpan();
-                while (stream.matchDigit(true)) {
-                    ;
-                }
-                if (stream.match(TokenType.Period.getLiteral(), true)) {
-                    type = TokenType.FloatLiteral;
-                    while (stream.matchDigit(true)) {
-                        ;
-                    }
-                }
-                if (stream.match("b", true) || stream.match("B", true)) {
-                    if (type == TokenType.FloatLiteral) {
-                        MagicScriptError.error("Byte literal can not have a decimal point.", stream.endSpan());
-                    }
-                    type = TokenType.ByteLiteral;
-                } else if (stream.match("s", true) || stream.match("S", true)) {
-                    if (type == TokenType.FloatLiteral) {
-                        MagicScriptError.error("Short literal can not have a decimal point.", stream.endSpan());
-                    }
-                    type = TokenType.ShortLiteral;
-                } else if (stream.match("l", true) || stream.match("L", true)) {
-                    if (type == TokenType.FloatLiteral) {
-                        MagicScriptError.error("Long literal can not have a decimal point.", stream.endSpan());
-                    }
-                    type = TokenType.LongLiteral;
-                } else if (stream.match("f", true) || stream.match("F", true)) {
-                    type = TokenType.FloatLiteral;
-                } else if (stream.match("d", true) || stream.match("D", true)) {
-                    type = TokenType.DoubleLiteral;
-                }
-                Span numberSpan = stream.endSpan();
-                tokens.add(new Token(type, numberSpan));
-                continue;
-            }
-
-            // String literal
-            if (stream.match(TokenType.SingleQuote.getLiteral(), true)) {
-                stream.startSpan();
-                boolean matchedEndQuote = false;
-                while (stream.hasMore()) {
-                    // Note: escape sequences like \n are parsed in StringLiteral
-                    if (stream.match("\\", true)) {
-                        stream.consume();
-                    }
-                    if (stream.match(TokenType.SingleQuote.getLiteral(), true)) {
-                        matchedEndQuote = true;
-                        break;
-                    }
-                    stream.consume();
-                }
-                if (!matchedEndQuote) {
-                    MagicScriptError.error("字符串没有结束符\'", stream.endSpan(), new StringLiteralException());
-                }
-                Span stringSpan = stream.endSpan();
-                stringSpan = stream.getSpan(stringSpan.getStart() - 1, stringSpan.getEnd());
-                tokens.add(new Token(TokenType.StringLiteral, stringSpan));
-                continue;
-            }
-
-            // String literal
-            if (stream.match("\"\"\"", true)) {
-                stream.startSpan();
-                boolean matchedEndQuote = false;
-                while (stream.hasMore()) {
-                    // Note: escape sequences like \n are parsed in StringLiteral
-                    if (stream.match("\\", true)) {
-                        stream.consume();
-                    }
-                    if (stream.match("\"\"\"", true)) {
-                        matchedEndQuote = true;
-                        break;
-                    }
-                    stream.consume();
-                }
-                if (!matchedEndQuote) {
-                    MagicScriptError.error("多行字符串没有结束符\"\"\"", stream.endSpan(), new StringLiteralException());
-                }
-                Span stringSpan = stream.endSpan();
-                stringSpan = stream.getSpan(stringSpan.getStart() - 1, stringSpan.getEnd() - 2);
-                tokens.add(new Token(TokenType.StringLiteral, stringSpan));
-                continue;
-            }
-
-            // String literal
-            if (stream.match(TokenType.DoubleQuote.getLiteral(), true)) {
-                stream.startSpan();
-                boolean matchedEndQuote = false;
-                while (stream.hasMore()) {
-                    // Note: escape sequences like \n are parsed in StringLiteral
-                    if (stream.match("\\", true)) {
-                        stream.consume();
-                    }
-                    if (stream.match(TokenType.DoubleQuote.getLiteral(), true)) {
-                        matchedEndQuote = true;
-                        break;
-                    }
-                    stream.consume();
-                }
-                if (!matchedEndQuote) {
-                    MagicScriptError.error("字符串没有结束符\"", stream.endSpan(), new StringLiteralException());
-                }
-                Span stringSpan = stream.endSpan();
-                stringSpan = stream.getSpan(stringSpan.getStart() - 1, stringSpan.getEnd());
-                tokens.add(new Token(TokenType.StringLiteral, stringSpan));
-                continue;
-            }
-
-            // Identifier, keyword, boolean literal, or null literal
-            if (stream.matchIdentifierStart(true)) {
-                stream.startSpan();
-                while (stream.matchIdentifierPart(true)) {
-                    ;
-                }
-                Span identifierSpan = stream.endSpan();
-                identifierSpan = stream.getSpan(identifierSpan.getStart() - 1, identifierSpan.getEnd());
-                if ("true".equals(identifierSpan.getText()) || "false".equals(identifierSpan.getText())) {
-                    tokens.add(new Token(TokenType.BooleanLiteral, identifierSpan));
-                } else if ("null".equals(identifierSpan.getText())) {
-                    tokens.add(new Token(TokenType.NullLiteral, identifierSpan));
-                } else {
-                    tokens.add(new Token(TokenType.Identifier, identifierSpan));
-                }
-                continue;
-            }
-            // Simple tokens
-            for (TokenType t : TokenType.getSortedValues()) {
-                if (t.getLiteral() != null) {
-                    if (stream.match(t.getLiteral(), true)) {
-                        if (t == TokenType.LeftCurly) {
-                            leftCount++;
-                        }
-                        tokens.add(new Token(t, stream.getSpan(stream.getPosition() - t.getLiteral().length(), stream.getPosition())));
-                        continue outer;
-                    }
-                }
-            }
-            if (leftCount != rightCount && stream.match("}", true)) {
-                rightCount++;
-                tokens.add(new Token(TokenType.RightCurly, stream.getSpan(stream.getPosition() - 1, stream.getPosition())));
-                continue outer;
-            }
-            if (stream.hasMore()) {
-                MagicScriptError.error("Unknown token", stream.getSpan( stream.getPosition(), stream.getPosition() + 1));
-            }
-        }
-        return tokens;
-    }
-}

+ 0 - 22
src/main/java/org/ssssssss/script/parsing/ast/BooleanLiteral.java

@@ -1,22 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class BooleanLiteral extends Expression {
-    private final Boolean value;
-
-    public BooleanLiteral(Span literal) {
-        super(literal);
-        this.value = Boolean.parseBoolean(literal.getText());
-    }
-
-    public Boolean getValue() {
-        return value;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return value;
-    }
-}

+ 0 - 17
src/main/java/org/ssssssss/script/parsing/ast/Break.java

@@ -1,17 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class Break extends Node {
-    public static final Object BREAK_SENTINEL = new Object();
-
-    public Break(Span span) {
-        super(span);
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return BREAK_SENTINEL;
-    }
-}

+ 0 - 22
src/main/java/org/ssssssss/script/parsing/ast/ByteLiteral.java

@@ -1,22 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class ByteLiteral extends Expression {
-    private final Byte value;
-
-    public ByteLiteral(Span literal) {
-        super(literal);
-        this.value = Byte.parseByte(literal.getText().substring(0, literal.getText().length() - 1));
-    }
-
-    public Byte getValue() {
-        return value;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return value;
-    }
-}

+ 0 - 42
src/main/java/org/ssssssss/script/parsing/ast/CharacterLiteral.java

@@ -1,42 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-
-public class CharacterLiteral extends Expression {
-    private final Character value;
-
-    public CharacterLiteral(Span literal) {
-        super(literal);
-
-        String text = literal.getText();
-        if (text.length() > 3) {
-            if (text.charAt(2) == 'n') {
-                value = '\n';
-            } else if (text.charAt(2) == 'r') {
-                value = '\r';
-            } else if (text.charAt(2) == 't') {
-                value = '\t';
-            } else if (text.charAt(2) == '\\') {
-                value = '\\';
-            } else if (text.charAt(2) == '\'') {
-                value = '\'';
-            } else {
-                MagicScriptError.error("Unknown escape sequence '" + literal.getText() + "'.", literal);
-                value = 0; // never reached
-            }
-        } else {
-            this.value = literal.getText().charAt(1);
-        }
-    }
-
-    public Character getValue() {
-        return value;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return value;
-    }
-}

+ 0 - 17
src/main/java/org/ssssssss/script/parsing/ast/Continue.java

@@ -1,17 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class Continue extends Node {
-    public static final Object CONTINUE_SENTINEL = new Object();
-
-    public Continue(Span span) {
-        super(span);
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return CONTINUE_SENTINEL;
-    }
-}

+ 0 - 22
src/main/java/org/ssssssss/script/parsing/ast/DoubleLiteral.java

@@ -1,22 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class DoubleLiteral extends Expression {
-    private final Double value;
-
-    public DoubleLiteral(Span literal) {
-        super(literal);
-        this.value = Double.parseDouble(literal.getText().substring(0, literal.getText().length() - 1));
-    }
-
-    public Double getValue() {
-        return value;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return value;
-    }
-}

+ 0 - 9
src/main/java/org/ssssssss/script/parsing/ast/Expression.java

@@ -1,9 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.parsing.Span;
-
-public abstract class Expression extends Node {
-    public Expression(Span span) {
-        super(span);
-    }
-}

+ 0 - 26
src/main/java/org/ssssssss/script/parsing/ast/FloatLiteral.java

@@ -1,26 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class FloatLiteral extends Expression {
-    private final Float value;
-
-    public FloatLiteral(Span literal) {
-        super(literal);
-        String text = literal.getText();
-        if (text.charAt(text.length() - 1) == 'f') {
-            text = text.substring(0, text.length() - 1);
-        }
-        this.value = Float.parseFloat(text);
-    }
-
-    public Float getValue() {
-        return value;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return value;
-    }
-}

+ 0 - 179
src/main/java/org/ssssssss/script/parsing/ast/ForStatement.java

@@ -1,179 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.interpreter.AstInterpreter;
-import org.ssssssss.script.parsing.Span;
-
-import java.lang.reflect.Array;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-public class ForStatement extends Node {
-    private final Span indexOrKeyName;
-    private final Span valueName;
-    private final Expression mapOrArray;
-    private final List<Node> body;
-
-    public ForStatement(Span span, Span indexOrKeyName, Span valueName, Expression mapOrArray, List<Node> body) {
-        super(span);
-        this.indexOrKeyName = indexOrKeyName;
-        this.valueName = valueName;
-        this.mapOrArray = mapOrArray;
-        this.body = body;
-    }
-
-    /**
-     * Returns null if no index or key name was given
-     **/
-    public Span getIndexOrKeyName() {
-        return indexOrKeyName;
-    }
-
-    public Span getValueName() {
-        return valueName;
-    }
-
-    public Expression getMapOrArray() {
-        return mapOrArray;
-    }
-
-    public List<Node> getBody() {
-        return body;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        Object mapOrArray = getMapOrArray().evaluate(context);
-        if (mapOrArray == null) MagicScriptError.error("Expected a map or array, got null.", getMapOrArray().getSpan());
-        String valueName = getValueName().getText();
-
-        if (mapOrArray instanceof Map) {
-            Map map = (Map) mapOrArray;
-            if (getIndexOrKeyName() != null) {
-                context.push();
-                String keyName = getIndexOrKeyName().getText();
-                for (Object entry : map.entrySet()) {
-                    Map.Entry e = (Map.Entry) entry;
-                    context.setOnCurrentScope(keyName, e.getKey());
-                    context.setOnCurrentScope(valueName, e.getValue());
-                    Object breakOrContinueOrReturn = AstInterpreter.interpretNodeList(getBody(), context);
-                    if (breakOrContinueOrReturn == Break.BREAK_SENTINEL) {
-                        break;
-                    }
-                    if (breakOrContinueOrReturn == Return.RETURN_SENTINEL) {
-                        context.pop();
-                        return breakOrContinueOrReturn;
-                    }
-                }
-                context.pop();
-            } else {
-                context.push();
-                for (Object value : map.values()) {
-                    context.setOnCurrentScope(valueName, value);
-                    Object breakOrContinueOrReturn = AstInterpreter.interpretNodeList(getBody(), context);
-                    if (breakOrContinueOrReturn == Break.BREAK_SENTINEL) {
-                        break;
-                    }
-                    if (breakOrContinueOrReturn == Return.RETURN_SENTINEL) {
-                        context.pop();
-                        return breakOrContinueOrReturn;
-                    }
-                }
-                context.pop();
-            }
-        } else if (mapOrArray instanceof Iterable) {
-            if (getIndexOrKeyName() != null) {
-                context.push();
-                String keyName = getIndexOrKeyName().getText();
-                Iterator iter = ((Iterable) mapOrArray).iterator();
-                int i = 0;
-                while (iter.hasNext()) {
-                    context.setOnCurrentScope(keyName, i++);
-                    context.setOnCurrentScope(valueName, iter.next());
-                    Object breakOrContinueOrReturn = AstInterpreter.interpretNodeList(getBody(), context);
-                    if (breakOrContinueOrReturn == Break.BREAK_SENTINEL) {
-                        break;
-                    }
-                    if (breakOrContinueOrReturn == Return.RETURN_SENTINEL) {
-                        context.pop();
-                        return breakOrContinueOrReturn;
-                    }
-                }
-                context.pop();
-            } else {
-                Iterator iter = ((Iterable) mapOrArray).iterator();
-                context.push();
-                while (iter.hasNext()) {
-                    context.setOnCurrentScope(valueName, iter.next());
-                    Object breakOrContinueOrReturn = AstInterpreter.interpretNodeList(getBody(), context);
-                    if (breakOrContinueOrReturn == Break.BREAK_SENTINEL) {
-                        break;
-                    }
-                    if (breakOrContinueOrReturn == Return.RETURN_SENTINEL) {
-                        context.pop();
-                        return breakOrContinueOrReturn;
-                    }
-                }
-                context.pop();
-            }
-        } else if (mapOrArray instanceof Iterator) {
-            if (getIndexOrKeyName() != null) {
-                MagicScriptError.error("Can not do indexed/keyed for loop on an iterator.", getMapOrArray().getSpan());
-            } else {
-                Iterator iter = (Iterator) mapOrArray;
-                context.push();
-                while (iter.hasNext()) {
-                    context.setOnCurrentScope(valueName, iter.next());
-                    Object breakOrContinueOrReturn = AstInterpreter.interpretNodeList(getBody(), context);
-                    if (breakOrContinueOrReturn == Break.BREAK_SENTINEL) {
-                        break;
-                    }
-                    if (breakOrContinueOrReturn == Return.RETURN_SENTINEL) {
-                        context.pop();
-                        return breakOrContinueOrReturn;
-                    }
-                }
-                context.pop();
-            }
-        } else if (mapOrArray != null && mapOrArray.getClass().isArray()) {
-            int len = Array.getLength(mapOrArray);
-            if (getIndexOrKeyName() != null) {
-                context.push();
-                String keyName = getIndexOrKeyName().getText();
-                for (int i = 0; i < len; i++) {
-                    context.setOnCurrentScope(keyName, i);
-                    context.setOnCurrentScope(valueName, Array.get(mapOrArray, i));
-                    Object breakOrContinueOrReturn = AstInterpreter.interpretNodeList(getBody(), context);
-                    if (breakOrContinueOrReturn == Break.BREAK_SENTINEL) {
-                        break;
-                    }
-                    if (breakOrContinueOrReturn == Return.RETURN_SENTINEL) {
-                        context.pop();
-                        return breakOrContinueOrReturn;
-                    }
-                }
-                context.pop();
-            } else {
-                context.push();
-                for (int i = 0; i < len; i++) {
-                    context.setOnCurrentScope(valueName, Array.get(mapOrArray, i));
-                    Object breakOrContinueOrReturn = AstInterpreter.interpretNodeList(getBody(), context);
-                    if (breakOrContinueOrReturn == Break.BREAK_SENTINEL) {
-                        break;
-                    }
-                    if (breakOrContinueOrReturn == Return.RETURN_SENTINEL) {
-                        context.pop();
-                        return breakOrContinueOrReturn;
-                    }
-                }
-                context.pop();
-            }
-        } else {
-            MagicScriptError.error("Expected a map, an array or an iterable, got " + mapOrArray, getMapOrArray().getSpan());
-        }
-        return null;
-    }
-}

+ 0 - 126
src/main/java/org/ssssssss/script/parsing/ast/FunctionCall.java

@@ -1,126 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.interpreter.AbstractReflection;
-import org.ssssssss.script.interpreter.AstInterpreter;
-import org.ssssssss.script.parsing.Span;
-
-import java.util.List;
-import java.util.function.Function;
-
-public class FunctionCall extends Expression {
-    private final Expression function;
-    private final List<Expression> arguments;
-    private final ThreadLocal<Object[]> cachedArguments;
-    private Object cachedFunction;
-
-    public FunctionCall(Span span, Expression function, List<Expression> arguments) {
-        super(span);
-        this.function = function;
-        this.arguments = arguments;
-        this.cachedArguments = new ThreadLocal<Object[]>();
-    }
-
-    public Expression getFunction() {
-        return function;
-    }
-
-    public List<Expression> getArguments() {
-        return arguments;
-    }
-
-    public Object getCachedFunction() {
-        return cachedFunction;
-    }
-
-    public void setCachedFunction(Object cachedFunction) {
-        this.cachedFunction = cachedFunction;
-    }
-
-    public Object[] getCachedArguments() {
-        Object[] args = cachedArguments.get();
-        if (args == null) {
-            args = new Object[arguments.size()];
-            cachedArguments.set(args);
-        }
-        return args;
-    }
-
-    /**
-     * Must be invoked when this node is done evaluating so we don't leak memory
-     **/
-    public void clearCachedArguments() {
-        Object[] args = getCachedArguments();
-        for (int i = 0; i < args.length; i++) {
-            args[i] = null;
-        }
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        try {
-            Object[] argumentValues = getCachedArguments();
-            List<Expression> arguments = getArguments();
-            for (int i = 0, n = argumentValues.length; i < n; i++) {
-                Expression expr = arguments.get(i);
-                argumentValues[i] = expr.evaluate(context);
-            }
-
-            // This is a special case to handle magicScript level macros. If a call to a macro is
-            // made, evaluating the function expression will result in an exception, as the
-            // function name can't be found in the context. Instead we need to manually check
-            // if the function expression is a VariableAccess and if so, if it can be found
-            // in the context.
-            Object function = null;
-            if (getFunction() instanceof VariableAccess) {
-                VariableAccess varAccess = (VariableAccess) getFunction();
-                function = context.get(varAccess.getVariableName().getText());
-            }  else {
-                function = getFunction().evaluate(context);
-            }
-            if (function instanceof Function) {
-                return ((Function<Object[],Object>) function).apply(argumentValues);
-            }else if (function instanceof FunctionStatement) {
-                FunctionStatement statement = (FunctionStatement) function;
-                context.push();
-                List<String> parameters = statement.getParameters();
-                for (int i = 0; i < argumentValues.length && i < parameters.size(); i++) {
-                    context.setOnCurrentScope(parameters.get(i), argumentValues[i]);
-                }
-                Object retVal = AstInterpreter.interpretNodeList(statement.getChildNodes(), context);
-                context.pop();
-                if (retVal == Return.RETURN_SENTINEL)
-                    return ((Return.ReturnValue) retVal).getValue();
-                else
-                    return null;
-            }
-            if (function != null) {
-                Object method = getCachedFunction();
-                if (method != null) {
-                    try {
-                        return AbstractReflection.getInstance().callMethod(function, method, argumentValues);
-                    } catch (Throwable t) {
-                        // fall through
-                    }
-                }
-                method = AbstractReflection.getInstance().getMethod(function, null, argumentValues);
-                if (method == null) {
-                    MagicScriptError.error("Couldn't find function.", getSpan());
-                }
-                setCachedFunction(method);
-                try {
-                    return AbstractReflection.getInstance().callMethod(function, method, argumentValues);
-                } catch (Throwable t) {
-                    MagicScriptError.error(t.getMessage(), getSpan(), t);
-                    return null; // never reached
-                }
-            } else {
-                MagicScriptError.error("Couldn't find function " + getFunction(), getSpan());
-                return null; // never reached
-            }
-        } finally {
-            clearCachedArguments();
-        }
-    }
-}

+ 0 - 32
src/main/java/org/ssssssss/script/parsing/ast/FunctionStatement.java

@@ -1,32 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-import java.util.List;
-
-public class FunctionStatement extends Expression {
-
-    private List<Node> childNodes;
-
-    private List<String> parameters;
-
-    public FunctionStatement(Span span, List<Node> childNodes, List<String> parameters) {
-        super(span);
-        this.childNodes = childNodes;
-        this.parameters = parameters;
-    }
-
-    public List<Node> getChildNodes() {
-        return childNodes;
-    }
-
-    public List<String> getParameters() {
-        return parameters;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return this;
-    }
-}

+ 0 - 74
src/main/java/org/ssssssss/script/parsing/ast/IfStatement.java

@@ -1,74 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.interpreter.AstInterpreter;
-import org.ssssssss.script.parsing.Span;
-
-import java.util.List;
-
-public class IfStatement extends Node {
-    private final Expression condition;
-    private final List<Node> trueBlock;
-    private final List<IfStatement> elseIfs;
-    private final List<Node> falseBlock;
-
-    public IfStatement(Span span, Expression condition, List<Node> trueBlock, List<IfStatement> elseIfs, List<Node> falseBlock) {
-        super(span);
-        this.condition = condition;
-        this.trueBlock = trueBlock;
-        this.elseIfs = elseIfs;
-        this.falseBlock = falseBlock;
-    }
-
-    public Expression getCondition() {
-        return condition;
-    }
-
-    public List<Node> getTrueBlock() {
-        return trueBlock;
-    }
-
-    public List<IfStatement> getElseIfs() {
-        return elseIfs;
-    }
-
-    public List<Node> getFalseBlock() {
-        return falseBlock;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        Object condition = getCondition().evaluate(context);
-        if (!(condition instanceof Boolean))
-            MagicScriptError.error("Expected a condition evaluating to a boolean, got " + condition, getCondition().getSpan());
-        if ((Boolean) condition) {
-            context.push();
-            Object breakOrContinueOrReturn = AstInterpreter.interpretNodeList(getTrueBlock(), context);
-            context.pop();
-            return breakOrContinueOrReturn;
-        }
-
-        if (getElseIfs().size() > 0) {
-            for (IfStatement elseIf : getElseIfs()) {
-                condition = elseIf.getCondition().evaluate(context);
-                if (!(condition instanceof Boolean))
-                    MagicScriptError.error("Expected a condition evaluating to a boolean, got " + condition, elseIf.getCondition().getSpan());
-                if ((Boolean) condition) {
-                    context.push();
-                    Object breakOrContinueOrReturn = AstInterpreter.interpretNodeList(elseIf.getTrueBlock(), context);
-                    context.pop();
-                    return breakOrContinueOrReturn;
-                }
-            }
-        }
-
-        if (getFalseBlock().size() > 0) {
-            context.push();
-            Object breakOrContinueOrReturn = AstInterpreter.interpretNodeList(getFalseBlock(), context);
-            context.pop();
-            return breakOrContinueOrReturn;
-        }
-        return null;
-    }
-}

+ 0 - 40
src/main/java/org/ssssssss/script/parsing/ast/Import.java

@@ -1,40 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicModuleLoader;
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.exception.ModuleNotFoundException;
-import org.ssssssss.script.parsing.Span;
-
-public class Import extends Node {
-
-	private String packageName;
-
-	private String variableName;
-
-	private boolean module;
-
-	public Import(Span span, String packageName, String variableName, boolean module) {
-		super(span);
-		this.packageName = packageName;
-		this.variableName = variableName;
-		this.module = module;
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-        if (this.module) {
-            Object target = MagicModuleLoader.loadModule(packageName);
-            if (target == null) {
-                throw new ModuleNotFoundException(String.format("module [%s] not found.", this.packageName), getSpan().getLine());
-            }
-            context.set(variableName, target);
-        }else{
-            Object target = MagicModuleLoader.loadClass(packageName);
-            if (target == null) {
-                throw new ModuleNotFoundException(String.format("class [%s] not found.", this.packageName), getSpan().getLine());
-            }
-            context.set(variableName, target);
-        }
-		return null;
-	}
-}

+ 0 - 22
src/main/java/org/ssssssss/script/parsing/ast/IntegerLiteral.java

@@ -1,22 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class IntegerLiteral extends Expression {
-    private final Integer value;
-
-    public IntegerLiteral(Span literal) {
-        super(literal);
-        this.value = Integer.parseInt(literal.getText());
-    }
-
-    public Integer getValue() {
-        return value;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return value;
-    }
-}

+ 0 - 40
src/main/java/org/ssssssss/script/parsing/ast/LambdaFunction.java

@@ -1,40 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.interpreter.AstInterpreter;
-import org.ssssssss.script.parsing.Span;
-
-import java.util.List;
-import java.util.function.Function;
-
-public class LambdaFunction extends Expression{
-    private List<String> parameters;
-    private List<Node> childNodes;
-
-    public LambdaFunction(Span span,List<String> parameters,List<Node> childNodes) {
-        super(span);
-        this.parameters = parameters;
-        this.childNodes = childNodes;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return (Function<Object[], Object>) args -> {
-            context.push();
-            Object value;
-            try {
-                for (int i = 0; i < parameters.size() && i < args.length; i++) {
-                    context.setOnCurrentScope(parameters.get(i),args[i]);
-                }
-                value = AstInterpreter.interpretNodeList(childNodes, context);
-                if(value instanceof Return.ReturnValue){
-                    value = ((Return.ReturnValue)value).getValue();
-                }
-            } finally {
-                Return.RETURN_SENTINEL.setValue(null);
-            }
-            context.pop();
-            return value;
-        };
-    }
-}

+ 0 - 15
src/main/java/org/ssssssss/script/parsing/ast/LambdaParameter.java

@@ -1,15 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class LambdaParameter extends Expression {
-    public LambdaParameter(Span span) {
-        super(span);
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return null;
-    }
-}

+ 0 - 25
src/main/java/org/ssssssss/script/parsing/ast/ListLiteral.java

@@ -1,25 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ListLiteral extends Expression {
-    public final List<Expression> values;
-
-    public ListLiteral(Span span, List<Expression> values) {
-        super(span);
-        this.values = values;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        List<Object> list = new ArrayList<>();
-        for (int i = 0, n = values.size(); i < n; i++) {
-            list.add(values.get(i).evaluate(context));
-        }
-        return list;
-    }
-}

+ 0 - 22
src/main/java/org/ssssssss/script/parsing/ast/LongLiteral.java

@@ -1,22 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class LongLiteral extends Expression {
-    private final Long value;
-
-    public LongLiteral(Span literal) {
-        super(literal);
-        this.value = Long.parseLong(literal.getText().substring(0, literal.getText().length() - 1));
-    }
-
-    public Long getValue() {
-        return value;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return value;
-    }
-}

+ 0 - 43
src/main/java/org/ssssssss/script/parsing/ast/MapLiteral.java

@@ -1,43 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.Token;
-import org.ssssssss.script.parsing.TokenType;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class MapLiteral extends Expression {
-    private final List<Token> keys;
-    private final List<Expression> values;
-
-    public MapLiteral(Span span, List<Token> keys, List<Expression> values) {
-        super(span);
-        this.keys = keys;
-        this.values = values;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        Map<String, Object> map = new HashMap<>();
-        for (int i = 0, n = keys.size(); i < n; i++) {
-            Object value = values.get(i).evaluate(context);
-            Token tokenKey = keys.get(i);
-            String key = tokenKey.getSpan().getText();
-            if (tokenKey.getType() == TokenType.StringLiteral) {
-                key = (String) new StringLiteral(tokenKey.getSpan()).evaluate(context);
-            } else if (key != null && key.startsWith("$")) {
-                Object objKey = context.get(key.substring(1));
-                if (objKey != null) {
-                    key = objKey.toString();
-                } else {
-                    key = null;
-                }
-            }
-            map.put(key, value);
-        }
-        return map;
-    }
-}

+ 0 - 101
src/main/java/org/ssssssss/script/parsing/ast/MapOrArrayAccess.java

@@ -1,101 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-
-import java.util.List;
-import java.util.Map;
-
-public class MapOrArrayAccess extends Expression implements VariableSetter {
-    private final Expression mapOrArray;
-    private final Expression keyOrIndex;
-
-    public MapOrArrayAccess(Span span, Expression mapOrArray, Expression keyOrIndex) {
-        super(span);
-        this.mapOrArray = mapOrArray;
-        this.keyOrIndex = keyOrIndex;
-    }
-
-    /**
-     * Returns an expression that must evaluate to a map or array.
-     **/
-    public Expression getMapOrArray() {
-        return mapOrArray;
-    }
-
-    /**
-     * Returns an expression that is used as the key or index to fetch a map or array element.
-     **/
-    public Expression getKeyOrIndex() {
-        return keyOrIndex;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        Object mapOrArray = getMapOrArray().evaluate(context);
-        if (mapOrArray == null) {
-            return null;
-        }
-        Object keyOrIndex = getKeyOrIndex().evaluate(context);
-        if (keyOrIndex == null) {
-            return null;
-        }
-
-        if (mapOrArray instanceof Map) {
-            return ((Map) mapOrArray).get(keyOrIndex);
-        } else if (mapOrArray instanceof List) {
-            if (!(keyOrIndex instanceof Number)) {
-                MagicScriptError.error("List index must be an integer, but was " + keyOrIndex.getClass().getSimpleName(), getKeyOrIndex().getSpan());
-            }
-            int index = ((Number) keyOrIndex).intValue();
-            return ((List) mapOrArray).get(index);
-        } else {
-            if (!(keyOrIndex instanceof Number)) {
-                MagicScriptError.error("Array index must be an integer, but was " + keyOrIndex.getClass().getSimpleName(), getKeyOrIndex().getSpan());
-            }
-            int index = ((Number) keyOrIndex).intValue();
-            if (mapOrArray instanceof int[]) {
-                return ((int[]) mapOrArray)[index];
-            } else if (mapOrArray instanceof float[]) {
-                return ((float[]) mapOrArray)[index];
-            } else if (mapOrArray instanceof double[]) {
-                return ((double[]) mapOrArray)[index];
-            } else if (mapOrArray instanceof boolean[]) {
-                return ((boolean[]) mapOrArray)[index];
-            } else if (mapOrArray instanceof char[]) {
-                return ((char[]) mapOrArray)[index];
-            } else if (mapOrArray instanceof short[]) {
-                return ((short[]) mapOrArray)[index];
-            } else if (mapOrArray instanceof long[]) {
-                return ((long[]) mapOrArray)[index];
-            } else if (mapOrArray instanceof byte[]) {
-                return ((byte[]) mapOrArray)[index];
-            } else if (mapOrArray instanceof String) {
-                return Character.toString(((String) mapOrArray).charAt(index));
-            } else {
-                return ((Object[]) mapOrArray)[index];
-            }
-        }
-    }
-
-    @Override
-    public void setValue(MagicScriptContext context, Object value) {
-        Object mapOrArray = getMapOrArray().evaluate(context);
-        if (mapOrArray != null) {
-            Object keyOrIndex = getKeyOrIndex().evaluate(context);
-            if (keyOrIndex != null) {
-                if (mapOrArray instanceof Map) {
-                    ((Map) mapOrArray).put(keyOrIndex, value);
-                } else if (mapOrArray instanceof List) {
-                    if (!(keyOrIndex instanceof Number)) {
-                        MagicScriptError.error("List index must be an integer, but was " + keyOrIndex.getClass().getSimpleName(), getKeyOrIndex().getSpan());
-                    }
-                    int index = ((Number) keyOrIndex).intValue();
-                    ((List) mapOrArray).set(index, value);
-                }
-            }
-        }
-    }
-}

+ 0 - 141
src/main/java/org/ssssssss/script/parsing/ast/MemberAccess.java

@@ -1,141 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.exception.MagicScriptException;
-import org.ssssssss.script.interpreter.AbstractReflection;
-import org.ssssssss.script.interpreter.AstInterpreter;
-import org.ssssssss.script.parsing.Span;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
-
-public class MemberAccess extends Expression {
-	private final Expression object;
-	private final Span name;
-	private Object cachedMember;
-
-	public MemberAccess(Expression object, Span name) {
-		super(name);
-		this.object = object;
-		this.name = name;
-	}
-
-	/**
-	 * Returns the object on which to access the member.
-	 **/
-	public Expression getObject() {
-		return object;
-	}
-
-	/**
-	 * The name of the member.
-	 **/
-	public Span getName() {
-		return name;
-	}
-
-	/**
-	 * Returns the cached member descriptor as returned by {@link AbstractReflection#getField(Object, String)} or
-	 * {@link AbstractReflection#getMethod(Object, String, Object...)}. See {@link #setCachedMember(Object)}.
-	 **/
-	public Object getCachedMember() {
-		return cachedMember;
-	}
-
-	/**
-	 * Sets the member descriptor as returned by {@link AbstractReflection#getField(Object, String)} or
-	 * {@link AbstractReflection#getMethod(Object, String, Object...)} for faster member lookups. Called by {@link AstInterpreter} the
-	 * first time this node is evaluated. Subsequent evaluations can use the cached descriptor, avoiding a costly reflective
-	 * lookup.
-	 **/
-	public void setCachedMember(Object cachedMember) {
-		this.cachedMember = cachedMember;
-	}
-
-	@SuppressWarnings("rawtypes")
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object object = getObject().evaluate(context);
-		if (object == null) {
-			return null;
-		}
-
-		// special case for array.length
-		if (object.getClass().isArray() && "length".equals(getName().getText())) {
-			return Array.getLength(object);
-		}
-
-		// special case for map, allows to do map.key instead of map[key]
-		if (object instanceof Map) {
-			Map map = (Map) object;
-			return map.get(getName().getText());
-		}
-
-		Object field = getCachedMember();
-		if (field != null) {
-			try {
-				return AbstractReflection.getInstance().getFieldValue(object, field);
-			} catch (Throwable t) {
-				// fall through
-			}
-		}
-		String text = getName().getText();
-		field = AbstractReflection.getInstance().getField(object, text);
-		if (field == null) {
-			String methodName;
-			if (text.length() > 1) {
-				methodName = text.substring(0, 1).toUpperCase() + text.substring(1);
-			} else {
-				methodName = text.toUpperCase();
-			}
-			MemberAccess access = new MemberAccess(this.object, new Span("get" + methodName));
-			MethodCall methodCall = new MethodCall(getName(), access, Collections.emptyList());
-			try {
-				return methodCall.evaluate(context);
-			} catch (MagicScriptException e) {
-				if (ExceptionUtils.indexOfThrowable(e, InvocationTargetException.class) > -1) {
-					MagicScriptError.error(String.format("在%s中调用方法get%s发生异常"
-							, object.getClass()
-							, methodName), getSpan(), e);
-					return null;
-				}
-				access = new MemberAccess(this.object, new Span("get"));
-				methodCall = new MethodCall(getName(), access, Arrays.asList(new StringLiteral(getName())));
-				try {
-					return methodCall.evaluate(context);
-				} catch (MagicScriptException e3) {
-					if (ExceptionUtils.indexOfThrowable(e3, InvocationTargetException.class) > -1) {
-						MagicScriptError.error(String.format("在%s中调用方法get发生异常"
-								, object.getClass()
-								, methodName), getSpan(), e);
-						return null;
-					}
-					access = new MemberAccess(this.object, new Span("is" + methodName));
-					methodCall = new MethodCall(getName(), access, Collections.emptyList());
-					try {
-						return methodCall.evaluate(context);
-					} catch (MagicScriptException e1) {
-						if (ExceptionUtils.indexOfThrowable(e1, InvocationTargetException.class) > -1) {
-							MagicScriptError.error(String.format("在%s中调用方法is%s发生异常"
-									, object.getClass()
-									, methodName), getSpan(), e);
-							return null;
-						}
-						MagicScriptError.error(String.format("在%s中找不到属性%s或者方法get%s、方法is%s"
-								, object.getClass()
-								, getName().getText()
-								, methodName
-								, methodName), getSpan());
-					}
-				}
-			}
-		}
-		setCachedMember(field);
-		return AbstractReflection.getInstance().getFieldValue(object, field);
-	}
-}

+ 0 - 183
src/main/java/org/ssssssss/script/parsing/ast/MethodCall.java

@@ -1,183 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.apache.commons.lang3.StringUtils;
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.interpreter.AbstractReflection;
-import org.ssssssss.script.interpreter.AstInterpreter;
-import org.ssssssss.script.interpreter.JavaReflection;
-import org.ssssssss.script.parsing.Span;
-
-import java.lang.reflect.Array;
-import java.util.List;
-
-public class MethodCall extends Expression {
-    private final MemberAccess method;
-    private final List<Expression> arguments;
-    private final ThreadLocal<Object[]> cachedArguments;
-    private Object cachedMethod;
-    private boolean cachedMethodStatic;
-
-    public MethodCall(Span span, MemberAccess method, List<Expression> arguments) {
-        super(span);
-        this.method = method;
-        this.arguments = arguments;
-        this.cachedArguments = new ThreadLocal<>();
-    }
-
-    /**
-     * Returns the object on which to call the method.
-     **/
-    public Expression getObject() {
-        return method.getObject();
-    }
-
-    /**
-     * Returns the method to call.
-     **/
-    public MemberAccess getMethod() {
-        return method;
-    }
-
-    /**
-     * Returns the list of expressions to be passed to the function as arguments.
-     **/
-    public List<Expression> getArguments() {
-        return arguments;
-    }
-
-    /**
-     * Returns the cached member descriptor as returned by {@link AbstractReflection#getMethod(Object, String, Object...)}. See
-     **/
-    public Object getCachedMethod() {
-        return cachedMethod;
-    }
-
-    /**
-     * Sets the method descriptor as returned by {@link AbstractReflection#getMethod(Object, String, Object...)} for faster lookups.
-     * Called by {@link AstInterpreter} the first time this node is evaluated. Subsequent evaluations can use the cached
-     * descriptor, avoiding a costly reflective lookup.
-     **/
-    public void setCachedMethod(Object cachedMethod) {
-        this.cachedMethod = cachedMethod;
-    }
-
-    /**
-     * Returns a scratch buffer to store arguments in when calling the function in {@link AstInterpreter}. Avoids generating
-     * garbage.
-     **/
-    public Object[] getCachedArguments() {
-        Object[] args = cachedArguments.get();
-        if (args == null) {
-            args = new Object[arguments.size()];
-            cachedArguments.set(args);
-        }
-        return args;
-    }
-
-    /**
-     * Must be invoked when this node is done evaluating so we don't leak memory
-     **/
-    public void clearCachedArguments() {
-        Object[] args = getCachedArguments();
-        for (int i = 0; i < args.length; i++) {
-            args[i] = null;
-        }
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        try {
-            Object object = getObject().evaluate(context);
-            if (object == null) {
-                return null;
-            }
-            Object[] argumentValues = getCachedArguments();
-            List<Expression> arguments = getArguments();
-            for (int i = 0, n = argumentValues.length; i < n; i++) {
-                Expression expr = arguments.get(i);
-                argumentValues[i] = expr.evaluate(context);
-            }
-            // Otherwise try to find a corresponding method or field pointing to a lambda.
-            Object method = getCachedMethod();
-            if (method != null) {
-                try {
-                    if (isCachedMethodStatic()) {
-                        return AbstractReflection.getInstance().callMethod(null, method, object,argumentValues);
-                    }
-                    return AbstractReflection.getInstance().callMethod(object, method, argumentValues);
-                } catch (Throwable t) {
-                    MagicScriptError.error(t.getMessage(), getSpan(), t);
-                    return null; // never reached
-                }
-            }
-
-            method = AbstractReflection.getInstance().getMethod(object, getMethod().getName().getText(), argumentValues);
-            if (method != null) {
-                // found the method on the object, call it
-                setCachedMethod(method);
-                try {
-                    return AbstractReflection.getInstance().callMethod(object, method, argumentValues);
-                } catch (Throwable t) {
-                    MagicScriptError.error(t.getMessage(), getSpan(), t);
-                    return null; // never reached
-                }
-            }
-            method = AbstractReflection.getInstance().getExtensionMethod(object, getMethod().getName().getText(), argumentValues);
-            if (method != null) {
-                try {
-                    int argumentLength = argumentValues == null ? 0 : argumentValues.length;
-                    Object[] parameters = new Object[argumentLength + 1];
-                    if (argumentLength > 0) {
-                        for (int i = 0; i < argumentLength; i++) {
-                            parameters[i + 1] = argumentValues[i];
-                        }
-                    }
-                    parameters[0] = object;
-                    if (object.getClass().isArray()) {
-                        Object[] objs = new Object[Array.getLength(object)];
-                        for (int i = 0, len = objs.length; i < len; i++) {
-                            Array.set(objs, i, Array.get(object, i));
-                        }
-                        parameters[0] = objs;
-                    }
-                    return AbstractReflection.getInstance().callMethod(object, method, parameters);
-                } catch (Throwable t) {
-                    MagicScriptError.error(t.getMessage(), getSpan(), t);
-                    // fall through
-                    return null;
-                }
-            } else {
-                // didn't find the method on the object, try to find a field pointing to a lambda
-                Object field = AbstractReflection.getInstance().getField(object, getMethod().getName().getText());
-                String className = object instanceof Class ? ((Class<?>) object).getName() : object.getClass().getName();
-                if (field == null) {
-                    MagicScriptError.error("在'" + className + "'中找不到方法 " + getMethod().getName().getText() + "(" + StringUtils.join(JavaReflection.getStringTypes(argumentValues), ",") + ")",
-                            getSpan());
-                }
-                Object function = AbstractReflection.getInstance().getFieldValue(object, field);
-                method = AbstractReflection.getInstance().getMethod(function, null, argumentValues);
-                if (method == null) {
-                    MagicScriptError.error("在'" + className + "'中找不到方法 " + getMethod().getName().getText() + "(" + StringUtils.join(JavaReflection.getStringTypes(argumentValues), ",") + ")",
-                            getSpan());
-                }
-                try {
-                    return AbstractReflection.getInstance().callMethod(function, method, argumentValues);
-                } catch (Throwable t) {
-                    MagicScriptError.error(t.getMessage(), getSpan(), t);
-                    return null; // never reached
-                }
-            }
-        } finally {
-            clearCachedArguments();
-        }
-    }
-
-    public boolean isCachedMethodStatic() {
-        return cachedMethodStatic;
-    }
-
-    public void setCachedMethodStatic(boolean cachedMethodStatic) {
-        this.cachedMethodStatic = cachedMethodStatic;
-    }
-}

+ 0 - 30
src/main/java/org/ssssssss/script/parsing/ast/Node.java

@@ -1,30 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-
-public abstract class Node {
-    private final Span span;
-
-    public Node(Span span) {
-        this.span = span;
-    }
-
-    public Span getSpan() {
-        return span;
-    }
-
-    @Override
-    public String toString() {
-        return span.getText();
-    }
-
-    public abstract Object evaluate(MagicScriptContext context);
-
-    protected void validate(boolean value, String message, Span location) {
-        if (value) {
-            MagicScriptError.error(message, location);
-        }
-    }
-}

+ 0 - 15
src/main/java/org/ssssssss/script/parsing/ast/NullLiteral.java

@@ -1,15 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class NullLiteral extends Expression {
-    public NullLiteral(Span span) {
-        super(span);
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return null;
-    }
-}

+ 0 - 36
src/main/java/org/ssssssss/script/parsing/ast/Return.java

@@ -1,36 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class Return extends Node {
-
-    public static final ReturnValue RETURN_SENTINEL = new ReturnValue();
-    private final Node returnValue;
-
-    public Return(Span span, Node returnValue) {
-        super(span);
-        this.returnValue = returnValue;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        RETURN_SENTINEL.setValue(returnValue != null ? returnValue.evaluate(context) : null);
-        return RETURN_SENTINEL;
-    }
-
-    /**
-     * A sentital of which only one instance exists. Uses thread local storage to store an (optional) return value. See
-     **/
-    public static class ReturnValue {
-        private final ThreadLocal<Object> value = new ThreadLocal<Object>();
-
-        public Object getValue() {
-            return value.get();
-        }
-
-        public void setValue(Object value) {
-            this.value.set(value);
-        }
-    }
-}

+ 0 - 22
src/main/java/org/ssssssss/script/parsing/ast/ShortLiteral.java

@@ -1,22 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class ShortLiteral extends Expression {
-    private final Short value;
-
-    public ShortLiteral(Span literal) {
-        super(literal);
-        this.value = Short.parseShort(literal.getText().substring(0, literal.getText().length() - 1));
-    }
-
-    public Short getValue() {
-        return value;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return value;
-    }
-}

+ 0 - 46
src/main/java/org/ssssssss/script/parsing/ast/StringLiteral.java

@@ -1,46 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.CharacterStream;
-import org.ssssssss.script.parsing.Span;
-
-public class StringLiteral extends Expression {
-    private final String value;
-
-    public StringLiteral(Span literal) {
-        super(literal);
-        String text = getSpan().getText();
-        String unescapedValue = text.substring(1, text.length() - 1);
-        StringBuilder builder = new StringBuilder();
-
-        CharacterStream stream = new CharacterStream(unescapedValue);
-        while (stream.hasMore()) {
-            if (stream.match("\\\\", true)) {
-                builder.append('\\');
-            } else if (stream.match("\\n", true)) {
-                builder.append('\n');
-            } else if (stream.match("\\r", true)) {
-                builder.append('\r');
-            } else if (stream.match("\\t", true)) {
-                builder.append('\t');
-            } else if (stream.match("\\\"", true)) {
-                builder.append('"');
-            } else {
-                builder.append(stream.consume());
-            }
-        }
-        value = builder.toString();
-    }
-
-    /**
-     * Returns the literal without quotes
-     **/
-    public String getValue() {
-        return value;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return value;
-    }
-}

+ 0 - 39
src/main/java/org/ssssssss/script/parsing/ast/TernaryOperation.java

@@ -1,39 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-
-public class TernaryOperation extends Expression {
-    private final Expression condition;
-    private final Expression trueExpression;
-    private final Expression falseExpression;
-
-    public TernaryOperation(Expression condition, Expression trueExpression, Expression falseExpression) {
-        super(new Span(condition.getSpan(), falseExpression.getSpan()));
-        this.condition = condition;
-        this.trueExpression = trueExpression;
-        this.falseExpression = falseExpression;
-    }
-
-    public Expression getCondition() {
-        return condition;
-    }
-
-    public Expression getTrueExpression() {
-        return trueExpression;
-    }
-
-    public Expression getFalseExpression() {
-        return falseExpression;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        Object condition = getCondition().evaluate(context);
-        if (!(condition instanceof Boolean)) {
-            MagicScriptError.error("Condition of ternary operator must be a boolean, got " + condition + ".", getSpan());
-        }
-        return ((Boolean) condition) ? getTrueExpression().evaluate(context) : getFalseExpression().evaluate(context);
-    }
-}

+ 0 - 75
src/main/java/org/ssssssss/script/parsing/ast/UnaryOperation.java

@@ -1,75 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Token;
-import org.ssssssss.script.parsing.TokenType;
-
-public class UnaryOperation extends Expression {
-
-    private final UnaryOperator operator;
-    private final Expression operand;
-
-    public UnaryOperation(Token operator, Expression operand) {
-        super(operator.getSpan());
-        this.operator = UnaryOperator.getOperator(operator);
-        this.operand = operand;
-    }
-
-    public UnaryOperator getOperator() {
-        return operator;
-    }
-
-    public Expression getOperand() {
-        return operand;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        Object operand = getOperand().evaluate(context);
-
-        if (getOperator() == UnaryOperator.Negate) {
-            if (operand instanceof Integer) {
-                return -(Integer) operand;
-            } else if (operand instanceof Float) {
-                return -(Float) operand;
-            } else if (operand instanceof Double) {
-                return -(Double) operand;
-            } else if (operand instanceof Byte) {
-                return -(Byte) operand;
-            } else if (operand instanceof Short) {
-                return -(Short) operand;
-            } else if (operand instanceof Long) {
-                return -(Long) operand;
-            } else {
-                MagicScriptError.error("Operand of operator '" + getOperator().name() + "' must be a number, got " + operand, getSpan());
-                return null; // never reached
-            }
-        } else if (getOperator() == UnaryOperator.Not) {
-            if (!(operand instanceof Boolean)) {
-                MagicScriptError.error("Operand of operator '" + getOperator().name() + "' must be a boolean", getSpan());
-            }
-            return !(Boolean) operand;
-        } else {
-            return operand;
-        }
-    }
-
-    public static enum UnaryOperator {
-        Not, Negate, Positive;
-
-        public static UnaryOperator getOperator(Token op) {
-            if (op.getType() == TokenType.Not) {
-                return UnaryOperator.Not;
-            }
-            if (op.getType() == TokenType.Plus) {
-                return UnaryOperator.Positive;
-            }
-            if (op.getType() == TokenType.Minus) {
-                return UnaryOperator.Negate;
-            }
-            MagicScriptError.error("Unknown unary operator " + op + ".", op.getSpan());
-            return null; // not reached
-        }
-    }
-}

+ 0 - 19
src/main/java/org/ssssssss/script/parsing/ast/VariableAccess.java

@@ -1,19 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class VariableAccess extends Expression {
-    public VariableAccess(Span name) {
-        super(name);
-    }
-
-    public Span getVariableName() {
-        return getSpan();
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        return context.get(getSpan().getText());
-    }
-}

+ 0 - 23
src/main/java/org/ssssssss/script/parsing/ast/VariableDefine.java

@@ -1,23 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-
-public class VariableDefine extends Node {
-
-    private Expression right;
-
-    private String variableName;
-
-    public VariableDefine(Span span, String variableName, Expression right) {
-        super(span);
-        this.variableName = variableName;
-        this.right = right;
-    }
-
-    @Override
-    public Object evaluate(MagicScriptContext context) {
-        context.set(variableName, right.evaluate(context));
-        return null;
-    }
-}

+ 0 - 7
src/main/java/org/ssssssss/script/parsing/ast/VariableSetter.java

@@ -1,7 +0,0 @@
-package org.ssssssss.script.parsing.ast;
-
-import org.ssssssss.script.MagicScriptContext;
-
-public interface VariableSetter {
-    public void setValue(MagicScriptContext context, Object value);
-}

+ 0 - 51
src/main/java/org/ssssssss/script/parsing/ast/binary/AddOperation.java

@@ -1,51 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-import java.util.Objects;
-
-public class AddOperation extends BinaryOperation {
-
-	public AddOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		Object right = getRightOperand().evaluate(context);
-		if (left instanceof String || right instanceof String) {
-			return left + Objects.toString(right);
-		}
-		if (right == null) {
-			MagicScriptError.error(getRightOperand().getSpan().getText() + " is undefined.", getRightOperand().getSpan());
-		}
-		if (left == null) {
-			MagicScriptError.error(getLeftOperand().getSpan().getText() + " is undefined.", getLeftOperand().getSpan());
-		}
-		if (left instanceof Double || right instanceof Double) {
-			return ((Number) left).doubleValue() + ((Number) right).doubleValue();
-		}
-		if (left instanceof Float || right instanceof Float) {
-			return ((Number) left).floatValue() + ((Number) right).floatValue();
-		}
-		if (left instanceof Long || right instanceof Long) {
-			return ((Number) left).longValue() + ((Number) right).longValue();
-		}
-		if (left instanceof Integer || right instanceof Integer) {
-			return ((Number) left).intValue() + ((Number) right).intValue();
-		}
-		if (left instanceof Short || right instanceof Short) {
-			return ((Number) left).shortValue() + ((Number) right).shortValue();
-		}
-		if (left instanceof Byte || right instanceof Byte) {
-			return ((Number) left).byteValue() + ((Number) right).byteValue();
-		}
-
-		MagicScriptError.error("Operands for + operator must be numbers or strings, got " + left + ", " + right + ".", getSpan());
-		return null; // never reached
-	}
-}

+ 0 - 29
src/main/java/org/ssssssss/script/parsing/ast/binary/AndOperation.java

@@ -1,29 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-public class AndOperation extends BinaryOperation {
-
-	public AndOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		if (!(left instanceof Boolean)) {
-			MagicScriptError.error("Left operand must be a boolean, got " + left + ".", getLeftOperand().getSpan());
-		}
-		if (!(Boolean) left) {
-			return false;
-		}
-		Object right = getRightOperand().evaluate(context);
-		if (!(right instanceof Boolean)) {
-			MagicScriptError.error("Right operand must be a boolean, got " + right + ".", getRightOperand().getSpan());
-		}
-		return (Boolean) left && (Boolean) right;
-	}
-}

+ 0 - 31
src/main/java/org/ssssssss/script/parsing/ast/binary/AssigmentOperation.java

@@ -1,31 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-import org.ssssssss.script.parsing.ast.VariableAccess;
-import org.ssssssss.script.parsing.ast.VariableSetter;
-
-public class AssigmentOperation extends BinaryOperation {
-
-	public AssigmentOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		if (getLeftOperand() instanceof VariableSetter) {
-			VariableSetter variableSetter = (VariableSetter) getLeftOperand();
-			Object value = getRightOperand().evaluate(context);
-			variableSetter.setValue(context, value);
-			return null;
-		}
-		if (!(getLeftOperand() instanceof VariableAccess)) {
-			MagicScriptError.error("Can only assign to top-level variables in context.", getLeftOperand().getSpan());
-		}
-		Object value = getRightOperand().evaluate(context);
-		context.set(((VariableAccess) getLeftOperand()).getVariableName().getText(), value);
-		return null;
-	}
-}

+ 0 - 79
src/main/java/org/ssssssss/script/parsing/ast/binary/BinaryOperation.java

@@ -1,79 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.Token;
-import org.ssssssss.script.parsing.ast.Expression;
-
-public abstract class BinaryOperation extends Expression {
-
-	private Expression leftOperand;
-	private Expression rightOperand;
-
-	public BinaryOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(span);
-		this.leftOperand = leftOperand;
-		this.rightOperand = rightOperand;
-	}
-
-	public static Expression create(Expression left, Token operator, Expression right) {
-		Expression expression = null;
-		Span span = operator.getSpan();
-		switch (operator.getType()) {
-			case Assignment:
-				expression = new AssigmentOperation(left, span, right);
-				break;
-			case Plus:
-				expression = new AddOperation(left, span, right);
-				break;
-			case Minus:
-				expression = new SubtractionOperation(left, span, right);
-				break;
-			case Asterisk:
-				expression = new MultiplicationOperation(left, span, right);
-				break;
-			case ForwardSlash:
-				expression = new DivisionOperation(left, span, right);
-				break;
-			case Percentage:
-				expression = new ModuloOperation(left, span, right);
-				break;
-			case Less:
-				expression = new LessOperation(left, span, right);
-				break;
-			case LessEqual:
-				expression = new LessEqualOperation(left, span, right);
-				break;
-			case Greater:
-				expression = new GreaterOperation(left, span, right);
-				break;
-			case GreaterEqual:
-				expression = new GreaterEqualOperation(left, span, right);
-				break;
-			case Equal:
-				expression = new EqualOperation(left, span, right);
-				break;
-			case NotEqual:
-				expression = new NotEqualOperation(left, span, right);
-				break;
-			case And:
-				expression = new AndOperation(left, span, right);
-				break;
-			case Or:
-				expression = new OrOperation(left, span, right);
-				break;
-			default:
-				MagicScriptError.error("Binary operator " + operator + " not implemented", span);
-		}
-		return expression;
-	}
-
-	public Expression getLeftOperand() {
-		return leftOperand;
-	}
-
-	public Expression getRightOperand() {
-		return rightOperand;
-	}
-
-}

+ 0 - 41
src/main/java/org/ssssssss/script/parsing/ast/binary/DivisionOperation.java

@@ -1,41 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-public class DivisionOperation extends BinaryOperation {
-
-	public DivisionOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		if (left == null) {
-			MagicScriptError.error(getLeftOperand().getSpan().getText() + " is undefined.", getLeftOperand().getSpan());
-		}
-		Object right = getRightOperand().evaluate(context);
-		if (right == null) {
-			MagicScriptError.error(getRightOperand().getSpan().getText() + " is undefined.", getRightOperand().getSpan());
-		}
-		if (left instanceof Double || right instanceof Double) {
-			return ((Number) left).doubleValue() / ((Number) right).doubleValue();
-		} else if (left instanceof Float || right instanceof Float) {
-			return ((Number) left).floatValue() / ((Number) right).floatValue();
-		} else if (left instanceof Long || right instanceof Long) {
-			return ((Number) left).longValue() / ((Number) right).longValue();
-		} else if (left instanceof Integer || right instanceof Integer) {
-			return ((Number) left).intValue() / ((Number) right).intValue();
-		} else if (left instanceof Short || right instanceof Short) {
-			return ((Number) left).shortValue() / ((Number) right).shortValue();
-		} else if (left instanceof Byte || right instanceof Byte) {
-			return ((Number) left).byteValue() / ((Number) right).byteValue();
-		} else {
-			MagicScriptError.error("Operands for / operator must be numbers" + left + ", " + right + ".", getSpan());
-			return null; // never reached
-		}
-	}
-}

+ 0 - 21
src/main/java/org/ssssssss/script/parsing/ast/binary/EqualOperation.java

@@ -1,21 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-import java.util.Objects;
-
-public class EqualOperation extends BinaryOperation {
-
-	public EqualOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		Object right = getRightOperand().evaluate(context);
-		return Objects.equals(left, right);
-	}
-}

+ 0 - 41
src/main/java/org/ssssssss/script/parsing/ast/binary/GreaterEqualOperation.java

@@ -1,41 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-public class GreaterEqualOperation extends BinaryOperation {
-
-	public GreaterEqualOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		if (left == null) {
-			MagicScriptError.error(getLeftOperand().getSpan().getText() + " is undefined.", getLeftOperand().getSpan());
-		}
-		Object right = getRightOperand().evaluate(context);
-		if (right == null) {
-			MagicScriptError.error(getRightOperand().getSpan().getText() + " is undefined.", getRightOperand().getSpan());
-		}
-		if (left instanceof Double || right instanceof Double) {
-			return ((Number) left).doubleValue() >= ((Number) right).doubleValue();
-		} else if (left instanceof Float || right instanceof Float) {
-			return ((Number) left).floatValue() >= ((Number) right).floatValue();
-		} else if (left instanceof Long || right instanceof Long) {
-			return ((Number) left).longValue() >= ((Number) right).longValue();
-		} else if (left instanceof Integer || right instanceof Integer) {
-			return ((Number) left).intValue() >= ((Number) right).intValue();
-		} else if (left instanceof Short || right instanceof Short) {
-			return ((Number) left).shortValue() >= ((Number) right).shortValue();
-		} else if (left instanceof Byte || right instanceof Byte) {
-			return ((Number) left).byteValue() >= ((Number) right).byteValue();
-		} else {
-			MagicScriptError.error("Operands for >= operator must be numbers" + left + ", " + right + ".", getSpan());
-			return null; // never reached
-		}
-	}
-}

+ 0 - 41
src/main/java/org/ssssssss/script/parsing/ast/binary/GreaterOperation.java

@@ -1,41 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-public class GreaterOperation extends BinaryOperation {
-
-	public GreaterOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		if (left == null) {
-			MagicScriptError.error(getLeftOperand().getSpan().getText() + " is undefined.", getLeftOperand().getSpan());
-		}
-		Object right = getRightOperand().evaluate(context);
-		if (right == null) {
-			MagicScriptError.error(getRightOperand().getSpan().getText() + " is undefined.", getRightOperand().getSpan());
-		}
-		if (left instanceof Double || right instanceof Double) {
-			return ((Number) left).doubleValue() > ((Number) right).doubleValue();
-		} else if (left instanceof Float || right instanceof Float) {
-			return ((Number) left).floatValue() > ((Number) right).floatValue();
-		} else if (left instanceof Long || right instanceof Long) {
-			return ((Number) left).longValue() > ((Number) right).longValue();
-		} else if (left instanceof Integer || right instanceof Integer) {
-			return ((Number) left).intValue() > ((Number) right).intValue();
-		} else if (left instanceof Short || right instanceof Short) {
-			return ((Number) left).shortValue() > ((Number) right).shortValue();
-		} else if (left instanceof Byte || right instanceof Byte) {
-			return ((Number) left).byteValue() > ((Number) right).byteValue();
-		} else {
-			MagicScriptError.error("Operands for > operator must be numbers" + left + ", " + right + ".", getSpan());
-			return null; // never reached
-		}
-	}
-}

+ 0 - 41
src/main/java/org/ssssssss/script/parsing/ast/binary/LessEqualOperation.java

@@ -1,41 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-public class LessEqualOperation extends BinaryOperation {
-
-	public LessEqualOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		if (left == null) {
-			MagicScriptError.error(getLeftOperand().getSpan().getText() + " is undefined.", getLeftOperand().getSpan());
-		}
-		Object right = getRightOperand().evaluate(context);
-		if (right == null) {
-			MagicScriptError.error(getRightOperand().getSpan().getText() + " is undefined.", getRightOperand().getSpan());
-		}
-		if (left instanceof Double || right instanceof Double) {
-			return ((Number) left).doubleValue() <= ((Number) right).doubleValue();
-		} else if (left instanceof Float || right instanceof Float) {
-			return ((Number) left).floatValue() <= ((Number) right).floatValue();
-		} else if (left instanceof Long || right instanceof Long) {
-			return ((Number) left).longValue() <= ((Number) right).longValue();
-		} else if (left instanceof Integer || right instanceof Integer) {
-			return ((Number) left).intValue() <= ((Number) right).intValue();
-		} else if (left instanceof Short || right instanceof Short) {
-			return ((Number) left).shortValue() <= ((Number) right).shortValue();
-		} else if (left instanceof Byte || right instanceof Byte) {
-			return ((Number) left).byteValue() <= ((Number) right).byteValue();
-		} else {
-			MagicScriptError.error("Operands for <= operator must be numbers" + left + ", " + right + ".", getSpan());
-			return null; // never reached
-		}
-	}
-}

+ 0 - 41
src/main/java/org/ssssssss/script/parsing/ast/binary/LessOperation.java

@@ -1,41 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-public class LessOperation extends BinaryOperation {
-
-	public LessOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		if (left == null) {
-			MagicScriptError.error(getLeftOperand().getSpan().getText() + " is undefined.", getLeftOperand().getSpan());
-		}
-		Object right = getRightOperand().evaluate(context);
-		if (right == null) {
-			MagicScriptError.error(getRightOperand().getSpan().getText() + " is undefined.", getRightOperand().getSpan());
-		}
-		if (left instanceof Double || right instanceof Double) {
-			return ((Number) left).doubleValue() < ((Number) right).doubleValue();
-		} else if (left instanceof Float || right instanceof Float) {
-			return ((Number) left).floatValue() < ((Number) right).floatValue();
-		} else if (left instanceof Long || right instanceof Long) {
-			return ((Number) left).longValue() < ((Number) right).longValue();
-		} else if (left instanceof Integer || right instanceof Integer) {
-			return ((Number) left).intValue() < ((Number) right).intValue();
-		} else if (left instanceof Short || right instanceof Short) {
-			return ((Number) left).shortValue() < ((Number) right).shortValue();
-		} else if (left instanceof Byte || right instanceof Byte) {
-			return ((Number) left).byteValue() < ((Number) right).byteValue();
-		} else {
-			MagicScriptError.error("Operands for < operator must be numbers" + left + ", " + right + ".", getSpan());
-			return null; // never reached
-		}
-	}
-}

+ 0 - 41
src/main/java/org/ssssssss/script/parsing/ast/binary/ModuloOperation.java

@@ -1,41 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-public class ModuloOperation extends BinaryOperation {
-
-	public ModuloOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		if (left == null) {
-			MagicScriptError.error(getLeftOperand().getSpan().getText() + " is undefined.", getLeftOperand().getSpan());
-		}
-		Object right = getRightOperand().evaluate(context);
-		if (right == null) {
-			MagicScriptError.error(getRightOperand().getSpan().getText() + " is undefined.", getRightOperand().getSpan());
-		}
-		if (left instanceof Double || right instanceof Double) {
-			return ((Number) left).doubleValue() % ((Number) right).doubleValue();
-		} else if (left instanceof Float || right instanceof Float) {
-			return ((Number) left).floatValue() % ((Number) right).floatValue();
-		} else if (left instanceof Long || right instanceof Long) {
-			return ((Number) left).longValue() % ((Number) right).longValue();
-		} else if (left instanceof Integer || right instanceof Integer) {
-			return ((Number) left).intValue() % ((Number) right).intValue();
-		} else if (left instanceof Short || right instanceof Short) {
-			return ((Number) left).shortValue() % ((Number) right).shortValue();
-		} else if (left instanceof Byte || right instanceof Byte) {
-			return ((Number) left).byteValue() % ((Number) right).byteValue();
-		} else {
-			MagicScriptError.error("Operands for % operator must be numbers" + left + ", " + right + ".", getSpan());
-			return null; // never reached
-		}
-	}
-}

+ 0 - 41
src/main/java/org/ssssssss/script/parsing/ast/binary/MultiplicationOperation.java

@@ -1,41 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-public class MultiplicationOperation extends BinaryOperation {
-
-	public MultiplicationOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		if (left == null) {
-			MagicScriptError.error(getLeftOperand().getSpan().getText() + " is undefined.", getLeftOperand().getSpan());
-		}
-		Object right = getRightOperand().evaluate(context);
-		if (right == null) {
-			MagicScriptError.error(getRightOperand().getSpan().getText() + " is undefined.", getRightOperand().getSpan());
-		}
-		if (left instanceof Double || right instanceof Double) {
-			return ((Number) left).doubleValue() * ((Number) right).doubleValue();
-		} else if (left instanceof Float || right instanceof Float) {
-			return ((Number) left).floatValue() * ((Number) right).floatValue();
-		} else if (left instanceof Long || right instanceof Long) {
-			return ((Number) left).longValue() * ((Number) right).longValue();
-		} else if (left instanceof Integer || right instanceof Integer) {
-			return ((Number) left).intValue() * ((Number) right).intValue();
-		} else if (left instanceof Short || right instanceof Short) {
-			return ((Number) left).shortValue() * ((Number) right).shortValue();
-		} else if (left instanceof Byte || right instanceof Byte) {
-			return ((Number) left).byteValue() * ((Number) right).byteValue();
-		} else {
-			MagicScriptError.error("Operands for * operator must be numbers" + left + ", " + right + ".", getSpan());
-			return null; // never reached
-		}
-	}
-}

+ 0 - 21
src/main/java/org/ssssssss/script/parsing/ast/binary/NotEqualOperation.java

@@ -1,21 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-import java.util.Objects;
-
-public class NotEqualOperation extends BinaryOperation {
-
-	public NotEqualOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		Object right = getRightOperand().evaluate(context);
-		return !Objects.equals(left, right);
-	}
-}

+ 0 - 29
src/main/java/org/ssssssss/script/parsing/ast/binary/OrOperation.java

@@ -1,29 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-public class OrOperation extends BinaryOperation {
-
-	public OrOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		if (!(left instanceof Boolean)) {
-			MagicScriptError.error("Left operand must be a boolean, got " + left + ".", getLeftOperand().getSpan());
-		}
-		if ((Boolean) left) {
-			return true;
-		}
-		Object right = getRightOperand().evaluate(context);
-		if (!(right instanceof Boolean)) {
-			MagicScriptError.error("Right operand must be a boolean, got " + right + ".", getRightOperand().getSpan());
-		}
-		return (Boolean) left || (Boolean) right;
-	}
-}

+ 0 - 41
src/main/java/org/ssssssss/script/parsing/ast/binary/SubtractionOperation.java

@@ -1,41 +0,0 @@
-package org.ssssssss.script.parsing.ast.binary;
-
-import org.ssssssss.script.MagicScriptContext;
-import org.ssssssss.script.MagicScriptError;
-import org.ssssssss.script.parsing.Span;
-import org.ssssssss.script.parsing.ast.Expression;
-
-public class SubtractionOperation extends BinaryOperation {
-
-	public SubtractionOperation(Expression leftOperand, Span span, Expression rightOperand) {
-		super(leftOperand, span, rightOperand);
-	}
-
-	@Override
-	public Object evaluate(MagicScriptContext context) {
-		Object left = getLeftOperand().evaluate(context);
-		if (left == null) {
-			MagicScriptError.error(getLeftOperand().getSpan().getText() + " is undefined.", getLeftOperand().getSpan());
-		}
-		Object right = getRightOperand().evaluate(context);
-		if (right == null) {
-			MagicScriptError.error(getRightOperand().getSpan().getText() + " is undefined.", getRightOperand().getSpan());
-		}
-		if (left instanceof Double || right instanceof Double) {
-			return ((Number) left).doubleValue() - ((Number) right).doubleValue();
-		} else if (left instanceof Float || right instanceof Float) {
-			return ((Number) left).floatValue() - ((Number) right).floatValue();
-		} else if (left instanceof Long || right instanceof Long) {
-			return ((Number) left).longValue() - ((Number) right).longValue();
-		} else if (left instanceof Integer || right instanceof Integer) {
-			return ((Number) left).intValue() - ((Number) right).intValue();
-		} else if (left instanceof Short || right instanceof Short) {
-			return ((Number) left).shortValue() - ((Number) right).shortValue();
-		} else if (left instanceof Byte || right instanceof Byte) {
-			return ((Number) left).byteValue() - ((Number) right).byteValue();
-		} else {
-			MagicScriptError.error("Operands for - operator must be numbers" + left + ", " + right + ".", getSpan());
-			return null; // never reached
-		}
-	}
-}