Browse Source

clean up of old code, bugfixes, refactoring, added missing functions, arrays + tests

Kajetan Johannes Hammerle 5 years ago
parent
commit
a6eef65970
100 changed files with 2693 additions and 2978 deletions
  1. 0 113
      src/me/hammerle/snuviscript/array/DynamicArray.java
  2. 508 694
      src/me/hammerle/snuviscript/code/Compiler.java
  3. 0 81
      src/me/hammerle/snuviscript/code/Function.java
  4. 56 218
      src/me/hammerle/snuviscript/code/FunctionRegistry.java
  5. 9 0
      src/me/hammerle/snuviscript/code/ISnuviLogger.java
  6. 5 1
      src/me/hammerle/snuviscript/code/ISnuviScheduler.java
  7. 26 0
      src/me/hammerle/snuviscript/code/InputProviderArrayPool.java
  8. 0 61
      src/me/hammerle/snuviscript/code/Instruction.java
  9. 0 28
      src/me/hammerle/snuviscript/code/JumpData.java
  10. 6 7
      src/me/hammerle/snuviscript/code/NamedFunction.java
  11. 298 166
      src/me/hammerle/snuviscript/code/Script.java
  12. 263 0
      src/me/hammerle/snuviscript/code/ScriptManager.java
  13. 0 35
      src/me/hammerle/snuviscript/code/SignInverter.java
  14. 0 206
      src/me/hammerle/snuviscript/code/SnuviParser.java
  15. 31 245
      src/me/hammerle/snuviscript/code/SnuviUtils.java
  16. 0 243
      src/me/hammerle/snuviscript/code/Syntax.java
  17. 0 37
      src/me/hammerle/snuviscript/compiler/Array.java
  18. 0 10
      src/me/hammerle/snuviscript/compiler/Break.java
  19. 0 10
      src/me/hammerle/snuviscript/compiler/Catch.java
  20. 0 479
      src/me/hammerle/snuviscript/compiler/Compiler.java
  21. 0 10
      src/me/hammerle/snuviscript/compiler/Continue.java
  22. 0 10
      src/me/hammerle/snuviscript/compiler/Else.java
  23. 0 10
      src/me/hammerle/snuviscript/compiler/ElseIf.java
  24. 0 10
      src/me/hammerle/snuviscript/compiler/For.java
  25. 0 31
      src/me/hammerle/snuviscript/compiler/Goto.java
  26. 0 10
      src/me/hammerle/snuviscript/compiler/If.java
  27. 0 6
      src/me/hammerle/snuviscript/compiler/Script2.java
  28. 0 10
      src/me/hammerle/snuviscript/compiler/Try.java
  29. 0 10
      src/me/hammerle/snuviscript/compiler/While.java
  30. 5 4
      src/me/hammerle/snuviscript/config/SnuviConfig.java
  31. 0 5
      src/me/hammerle/snuviscript/exceptions/CodeTooLongException.java
  32. 5 17
      src/me/hammerle/snuviscript/exceptions/PreScriptException.java
  33. 51 0
      src/me/hammerle/snuviscript/inputprovider/ArrayReturnWrapper.java
  34. 2 2
      src/me/hammerle/snuviscript/inputprovider/ConstantBoolean.java
  35. 2 2
      src/me/hammerle/snuviscript/inputprovider/ConstantDouble.java
  36. 2 15
      src/me/hammerle/snuviscript/inputprovider/ConstantNull.java
  37. 2 2
      src/me/hammerle/snuviscript/inputprovider/ConstantString.java
  38. 2 17
      src/me/hammerle/snuviscript/inputprovider/InputProvider.java
  39. 3 19
      src/me/hammerle/snuviscript/inputprovider/LocalVariable.java
  40. 5 12
      src/me/hammerle/snuviscript/inputprovider/ReturnWrapper.java
  41. 2 14
      src/me/hammerle/snuviscript/inputprovider/Variable.java
  42. 56 0
      src/me/hammerle/snuviscript/instructions/Array.java
  43. 15 0
      src/me/hammerle/snuviscript/instructions/Break.java
  44. 26 0
      src/me/hammerle/snuviscript/instructions/Catch.java
  45. 2 2
      src/me/hammerle/snuviscript/instructions/Constant.java
  46. 15 0
      src/me/hammerle/snuviscript/instructions/Continue.java
  47. 28 0
      src/me/hammerle/snuviscript/instructions/Else.java
  48. 37 0
      src/me/hammerle/snuviscript/instructions/ElseIf.java
  49. 31 0
      src/me/hammerle/snuviscript/instructions/EndIf.java
  50. 28 0
      src/me/hammerle/snuviscript/instructions/For.java
  51. 7 6
      src/me/hammerle/snuviscript/instructions/Function.java
  52. 56 0
      src/me/hammerle/snuviscript/instructions/Goto.java
  53. 30 0
      src/me/hammerle/snuviscript/instructions/If.java
  54. 45 0
      src/me/hammerle/snuviscript/instructions/IfGoto.java
  55. 13 17
      src/me/hammerle/snuviscript/instructions/Instruction.java
  56. 50 0
      src/me/hammerle/snuviscript/instructions/Return.java
  57. 3 2
      src/me/hammerle/snuviscript/instructions/SignInverter.java
  58. 25 0
      src/me/hammerle/snuviscript/instructions/Try.java
  59. 11 2
      src/me/hammerle/snuviscript/instructions/UserFunction.java
  60. 28 0
      src/me/hammerle/snuviscript/instructions/While.java
  61. 25 9
      src/me/hammerle/snuviscript/test/Test.java
  62. 6 0
      src/me/hammerle/snuviscript/test/TestLogger.java
  63. 8 7
      src/me/hammerle/snuviscript/test/TestScheduler.java
  64. 1 1
      src/me/hammerle/snuviscript/tokenizer/DataToken.java
  65. 1 1
      src/me/hammerle/snuviscript/tokenizer/StreamCharReader.java
  66. 1 1
      src/me/hammerle/snuviscript/tokenizer/Token.java
  67. 1 1
      src/me/hammerle/snuviscript/tokenizer/TokenType.java
  68. 14 10
      src/me/hammerle/snuviscript/tokenizer/Tokenizer.java
  69. 0 24
      src/me/hammerle/snuviscript/variable/ArrayVariable.java
  70. 0 45
      src/me/hammerle/snuviscript/variable/LocalArrayVariable.java
  71. 10 0
      test/arrays/array_dim1
  72. 37 0
      test/arrays/array_dim1.cout
  73. 3 0
      test/arrays/array_dim1.out
  74. 59 0
      test/arrays/array_dim1.tout
  75. 15 0
      test/arrays/array_dim2
  76. 72 0
      test/arrays/array_dim2.cout
  77. 6 0
      test/arrays/array_dim2.out
  78. 111 0
      test/arrays/array_dim2.tout
  79. 21 0
      test/arrays/array_dim3
  80. 111 0
      test/arrays/array_dim3.cout
  81. 24 0
      test/arrays/array_dim3.out
  82. 169 0
      test/arrays/array_dim3.tout
  83. 8 0
      test/basic/gosub
  84. 10 0
      test/basic/gosub.cout
  85. 3 0
      test/basic/gosub.out
  86. 28 0
      test/basic/gosub.tout
  87. 0 0
      test/basic/goto
  88. 0 0
      test/basic/goto.cout
  89. 0 0
      test/basic/goto.out
  90. 0 0
      test/basic/goto.tout
  91. 7 0
      test/basic/local
  92. 9 0
      test/basic/local.cout
  93. 1 0
      test/basic/local.out
  94. 21 0
      test/basic/local.tout
  95. 0 0
      test/basic/print
  96. 4 0
      test/basic/print.cout
  97. 0 0
      test/basic/print.out
  98. 0 0
      test/basic/print.tout
  99. 58 0
      test/calc/base.cout
  100. 60 0
      test/calc/mixed.cout

+ 0 - 113
src/me/hammerle/snuviscript/array/DynamicArray.java

@@ -1,113 +0,0 @@
-package me.hammerle.snuviscript.array;
-
-import me.hammerle.snuviscript.code.InputProvider;
-import me.hammerle.snuviscript.variable.Variable;
-import java.lang.reflect.Array;
-import me.hammerle.snuviscript.code.SnuviUtils;
-import me.hammerle.snuviscript.code.Script;
-import me.hammerle.snuviscript.variable.LocalVariable;
-
-public class DynamicArray extends InputProvider
-{
-    protected Variable var;
-    protected InputProvider[] input;
-    
-    public DynamicArray(Variable var, InputProvider[] input)
-    {
-        this.var = var;
-        this.input = input;
-    }
-
-    public int getLength(Script sc)
-    {
-        return Array.getLength(var.getArray(sc));
-    }
-    
-    public void init(Script sc) throws Exception
-    {
-        int[] dims = new int[input.length];
-        for(int i = 0; i < dims.length; i++)
-        {
-            dims[i] = input[i].getInt(sc);
-        }
-        var.set(sc, Array.newInstance(Object.class, dims));
-    }
-    
-    @Override
-    public Object getArray(Script sc) throws Exception
-    {
-        Object ob = var.getArray(sc);
-        for(InputProvider in : input) 
-        {
-            ob = Array.get(ob, in.getInt(sc));
-        }
-        return ob;
-    }
-    
-    public Object getLastArray(Script sc) throws Exception
-    {
-        Object ob = var.getArray(sc);
-        int end = input.length - 1;
-        for(int j = 0; j < end; j++)
-        {
-            ob = Array.get(ob, input[j].getInt(sc));
-        }
-        return ob;
-    }
-    
-    @Override
-    public void set(Script sc, Object o) throws Exception
-    {
-        Array.set(getLastArray(sc), input[input.length - 1].getInt(sc), o);
-    }
-
-    @Override
-    public Object get(Script sc) throws Exception
-    {
-        return Array.get(getLastArray(sc), input[input.length - 1].getInt(sc));
-    }
-    
-    @Override
-    public double getDouble(Script sc) throws Exception
-    {
-        return (double) get(sc);
-    }
-    
-    @Override
-    public String getString(Script sc) throws Exception
-    {
-        Object last = getLastArray(sc);
-        int index = input[input.length - 1].getInt(sc);
-        try
-        {
-            return String.valueOf(Array.get(last, index));
-        }
-        catch(IllegalArgumentException ex)
-        {
-            return SnuviUtils.getArrayString(Array.get(last, index));
-        }
-    }
-
-    @Override
-    public String toString() 
-    {
-        StringBuilder sb = new StringBuilder(var.getName());
-        if(var instanceof LocalVariable)
-        {
-            sb.append("#");
-            sb.append("L");
-        }
-        sb.append("[");
-        for(InputProvider in : input)
-        {
-            sb.append(in);
-            sb.append(", ");
-        }
-        if(input.length > 0)
-        {
-            sb.delete(sb.length() - 2, sb.length());
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-}

+ 508 - 694
src/me/hammerle/snuviscript/code/Compiler.java

@@ -1,831 +1,645 @@
 package me.hammerle.snuviscript.code;
 
+import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Stack;
-import me.hammerle.snuviscript.constants.ConstantDouble;
-import me.hammerle.snuviscript.constants.ConstantNull;
-import me.hammerle.snuviscript.constants.ConstantString;
-import me.hammerle.snuviscript.array.DynamicArray;
-import me.hammerle.snuviscript.constants.ConstantBoolean;
-import me.hammerle.snuviscript.variable.ArrayVariable;
-import me.hammerle.snuviscript.variable.LocalArrayVariable;
-import me.hammerle.snuviscript.variable.LocalVariable;
-import me.hammerle.snuviscript.variable.Variable;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.inputprovider.ConstantBoolean;
+import me.hammerle.snuviscript.inputprovider.ConstantDouble;
+import me.hammerle.snuviscript.inputprovider.ConstantNull;
+import me.hammerle.snuviscript.inputprovider.ConstantString;
 import me.hammerle.snuviscript.exceptions.PreScriptException;
+import me.hammerle.snuviscript.tokenizer.Token;
+import me.hammerle.snuviscript.tokenizer.TokenType;
+import static me.hammerle.snuviscript.tokenizer.TokenType.*;
+import me.hammerle.snuviscript.inputprovider.LocalVariable;
+import me.hammerle.snuviscript.inputprovider.Variable;
+import me.hammerle.snuviscript.instructions.Array;
+import me.hammerle.snuviscript.instructions.Break;
+import me.hammerle.snuviscript.instructions.Catch;
+import me.hammerle.snuviscript.instructions.Constant;
+import me.hammerle.snuviscript.instructions.Continue;
+import me.hammerle.snuviscript.instructions.Else;
+import me.hammerle.snuviscript.instructions.ElseIf;
+import me.hammerle.snuviscript.instructions.EndIf;
+import me.hammerle.snuviscript.instructions.For;
+import me.hammerle.snuviscript.instructions.Function;
+import me.hammerle.snuviscript.instructions.Goto;
+import me.hammerle.snuviscript.instructions.If;
+import me.hammerle.snuviscript.instructions.IfGoto;
+import me.hammerle.snuviscript.instructions.Instruction;
+import me.hammerle.snuviscript.instructions.Return;
+import me.hammerle.snuviscript.instructions.Try;
+import me.hammerle.snuviscript.instructions.UserFunction;
+import me.hammerle.snuviscript.instructions.While;
 
-public class Compiler 
+public class Compiler
 {
-    public static Instruction[] compile(
-            Script sc, List<String> sCode, HashMap<String, Integer> labels, 
-            HashMap<String, Integer> functions, HashMap<String, HashMap<String, Integer>> localLabels)
-    {
-        Compiler compiler = new Compiler(sCode, labels, functions, localLabels);
-        Instruction[] instructions = compiler.compile();
-        sc.vars = compiler.vars;
-        return instructions;
-    }
-    
-    private final List<String> sCode;
-    private final HashMap<String, Variable> vars = new HashMap<>();
-    private final HashMap<String, Integer> labels;
-    
-    private final HashMap<String, Variable> localVars = new HashMap<>();
-    private final HashMap<String, Integer> functions;
-    private final HashMap<String, HashMap<String, Integer>> localLabels;
-    private String currentFunction = null;
+    private int index = 0;
+    private Token[] tokens = null;
+    private final ArrayList<Instruction> instr = new ArrayList<>();
     
-    private final LinkedList<Instruction> code = new LinkedList<>();;
-    private int line = 0;
-    private int layer = 0;
+    private HashMap<String, Integer> labels = null;
+    private HashMap<String, HashMap<String, Integer>> localLabels = null;
+    private HashMap<String, Variable> vars = null;
+    private final HashMap<String, LocalVariable> localVars = new HashMap<>();
+    private HashMap<String, Integer> functions = null;
     
-    private JumpData tryState = null;
+    private final Stack<Break> breakStack = new Stack<>();
+    private final Stack<Continue> continueStack = new Stack<>();
     
-    private class JumpWrapper
+    private String inFunction = null;
+    private boolean lineExpression = false;
+
+    private void addConstant(int line, InputProvider ip)
     {
-        private final JumpData data;
-        private final String function;
-        
-        public JumpWrapper(JumpData data, String function)
-        {
-            this.data = data;
-            this.function = function;
-        }
+        instr.add(new Constant(line, ip));
     }
     
-    private final Stack<JumpWrapper> jumps = new Stack<>();
-    private final Stack<JumpWrapper> loopJumps = new Stack<>();
-    private final LinkedList<JumpData> breakContinueJumps = new LinkedList<>();
-    
-    private final HashMap<String, String> strings = new HashMap<>();
-    private int stringCounter = 0;
-    
-    private Compiler(List<String> sCode, HashMap<String, Integer> labels, 
-            HashMap<String, Integer> functions, HashMap<String, HashMap<String, Integer>> localLabels)
+    private void addFunction(int line, int args, String name)
     {
-        this.sCode = sCode;
-        this.labels = labels;       
-        this.functions = functions;
-        this.localLabels = localLabels;
+        instr.add(new Function(line, args, FunctionRegistry.getFunction(name)));
     }
     
-    private void addCodeInstruction(String function, InputProvider[] input)
+    private void addGoto(int line, int jump)
     {
-        code.add(new Instruction(line + 1, (byte) layer, new Function(FunctionLoader.getFunction(function), input)));
+        Goto g = new Goto(line, 0);
+        g.setJump(jump);
+        instr.add(g);
     }
     
-    private void addLabel(String name, int line)
+    private boolean match(TokenType... types)
     {
-        if(currentFunction != null)
+        for(TokenType type : types)
         {
-            HashMap<String, Integer> map = localLabels.get(currentFunction);
-            if(map.put(name, line) != null)
+            if(check(type))
             {
-                throw new PreScriptException("label duplicate", line);
+                advance();
+                return true;
             }
         }
-        else if(labels.put(name, line) != null)
+        return false;
+    }
+
+    private boolean check(TokenType type)
+    {
+        if(isAtEnd())
+        {
+            return false;
+        }
+        return peek().getType() == type;
+    }
+
+    private Token advance()
+    {
+        if(!isAtEnd())
         {
-            throw new PreScriptException("label duplicate", line);
+            index++;
         }
+        return previous();
+    }
+
+    private boolean isAtEnd()
+    {
+        return peek().getType() == EOF;
+    }
+
+    private Token peek()
+    {
+        return tokens[index];
+    }
+
+    private Token previous()
+    {
+        return tokens[index - 1];
     }
     
-    private Instruction[] compile()
+    private Token consume(TokenType type) 
     {
-        int size = sCode.size();
-        //System.out.println("__________________________________");
-        
-        StringBuilder sb = new StringBuilder();
-        String replacement;
-        String check;
-        int pos;
-        int old = 0;
-        boolean text = false;
-        boolean comment = false;
-        int labelIndex;
-        
-        for(line = 0; line < size; line++)
+        if(check(type))
         {
-            pos = sb.length();
-            sb.append(sCode.get(line));
-            
-            while(pos < sb.length())
-            {
-                if(comment)
-                {
-                    if(pos + 1 < sb.length() && sb.charAt(pos) == '*' && sb.charAt(pos + 1) == '/')
-                    {
-                        comment = false;
-                        sb.delete(old, pos + 2);
-                        pos = old - 1;
-                    }
-                    pos++;
-                    continue;
-                }
-                else if(text)
-                {
-                    if(sb.charAt(pos) == '"')
-                    {
-                        replacement = "#" + stringCounter++;
-                        strings.put(replacement, sb.substring(old, pos + 1));
-                        text = false;
-                        sb.replace(old, pos + 1, replacement);
-                        pos = old - 1 + replacement.length();
-                    }
-                    pos++;
-                    continue;
-                }
-                switch(sb.charAt(pos))
-                {
-                    case '/':
-                        if(pos + 1 < sb.length())
-                        {
-                            switch(sb.charAt(pos + 1))
-                            {
-                                case '/':
-                                    sb.delete(pos, sb.length());
-                                    break;
-                                case '*':
-                                    comment = true;
-                                    old = pos;
-                                    pos++;
-                                    break;
-                            }
-                        }
-                        break;
-                    case '}':
-                        sb.delete(0, pos + 1);
-                        pos = -1;
-                        layer--;
-                        if(jumps.isEmpty())
-                        {
-                            throw new PreScriptException("} without a corresponding function and / or {", line);
-                        }
-                        JumpWrapper data = jumps.pop();
-                        switch(data.function)
-                        {
-                            case "function":
-                            {
-                                data.data.setRelativeJump(code.size() + 1);
-                                currentFunction = null;
-                                layer++;
-                                addCodeInstruction("return", new InputProvider[] {});
-                                layer--;
-                                break;
-                            }
-                            case "try":
-                            {
-                                tryState = data.data;
-                                break;
-                            }
-                            case "catch":
-                            {
-                                data.data.setRelativeJump(code.size());
-                                break;
-                            }
-                            case "else":
-                            case "elseif":
-                            case "if":
-                            {
-                                data.data.setRelativeJump(code.size() + 1);
-                                addCodeInstruction("endif", new InputProvider[] {});
-                                break;
-                            }
-                            case "for":
-                            {
-                                loopJumps.pop();
-                                createBreakContinue(code.size());
-                                JumpData jump = data.data;
-                                jump.setRelativeJump(code.size());
-                                addCodeInstruction("next", new InputProvider[] {new JumpData(-jump.getInt(null) - 1)});
-                                break;
-                            }
-                            case "while":
-                            {
-                                loopJumps.pop();
-                                createBreakContinue(code.size());
+            return advance();
+        }
+        throw new PreScriptException(String.format("expected %s got %s", type, peek().getType()), peek().getLine());
+    }  
 
-                                JumpData jump = data.data;
-                                jump.setRelativeJump(code.size() + 1);
-                                addCodeInstruction("wend", new InputProvider[] {new JumpData(-jump.getInt(null) - 1)});
-                                break;
-                            }
-                        }
-                        break;
-                    case '{':
-                        int currentJumps = jumps.size();
-                        check = sb.toString();
-                        if(check.startsWith("function "))
-                        {
-                            if(currentFunction != null)
-                            {
-                                throw new PreScriptException("function not allowed in another function", line);
-                            }
-                            int index = check.indexOf("(");
-                            if(index == -1)
-                            {
-                                throw new PreScriptException("missing function syntax", line);
-                            }
-                            currentFunction = check.substring(9, index).toLowerCase();
-                            functions.put(currentFunction, code.size());
-                            localLabels.put(currentFunction, new HashMap<>());
-                            int endIndex = check.indexOf(")", index);
-                            if(index == -1)
-                            {
-                                throw new PreScriptException("missing function syntax", line);
-                            }
-                            String[] inputs;
-                            if(index + 1 == endIndex)
-                            {
-                                inputs = new String[0];
-                            }
-                            else
-                            {
-                                inputs = check.substring(index + 1, endIndex).split("[ ]*,[ ]*");
-                            }
-                            InputProvider[] in = new InputProvider[inputs.length + 1];
-                            for(int i = 1; i < in.length; i++)
-                            {
-                                in[i] = new ConstantString(inputs[i - 1]);
-                            }
-                            JumpData jump = new JumpData(code.size());
-                            in[0] = jump;
-                            jumps.add(new JumpWrapper(jump, "function"));
-                            addCodeInstruction("function", in);
-                           
-                            pos = endIndex + 1;
-                            boolean b = true;
-                            while(b)
-                            {
-                                switch(sb.charAt(pos))
-                                {
-                                    case '{':
-                                        b = false;
-                                        break;
-                                    case '\n':
-                                    case ' ':
-                                        break;
-                                    default:
-                                        throw new PreScriptException("invalid character between function and {", line);
-                                }
-                                pos++;
-                            }
-                            
-                            layer++;
-                            sb.delete(0, pos);
-                        }
-                        else
-                        {
-                            check = sb.substring(0, pos);
-                            compileLine(check);
-                            sb.delete(0, pos + 1);
-                            layer++;
-                            if(currentJumps == jumps.size())
-                            {
-                                throw new PreScriptException("{ without a corresponding function", line);
-                            }
-                        }
-                        pos = -1;
-                        break;
-                    case ';':
-                        compileLine(sb.substring(0, pos).trim());
-                        sb.delete(0, pos + 1);
-                        pos = -1;
-                        break;
-                    case '"':
-                        text = true;
-                        old = pos;
-                        break;
-                }
-                pos++;
-            }
-            if(!text && !comment)
-            {
-                labelIndex = sb.indexOf("@");
-                if(labelIndex != -1)
-                {
-                    String label = sb.toString().trim();
-                    if(label.charAt(0) != '@')
-                    {
-                        throw new PreScriptException("you seriously fucked up the syntax here", line);
-                    }
-                    addLabel(label.substring(1), code.size() - 1);
-                    sb = new StringBuilder();
-                }
-            }
+    private void noReturnForLastFunction()
+    {
+        instr.get(instr.size() - 1).setNoReturn();
+    }
+    
+    public Instruction[] compile(Token[] tokens, HashMap<String, Integer> labels, 
+            HashMap<String, Variable> vars, HashMap<String, Integer> functions,
+            HashMap<String, HashMap<String, Integer>> localLabels)
+    {
+        this.tokens = tokens;
+        index = 0;
+        instr.clear();
+        this.labels = labels;
+        this.localLabels = localLabels;
+        this.vars = vars;
+        this.functions = functions;
+        localVars.clear();
+        inFunction = null;
+
+        while(!isAtEnd())
+        {
+            line();
         }
         
-        //System.out.println("__________________________________");
-        
-        Instruction[] input = code.toArray(new Instruction[code.size()]);
+        this.tokens = null;
+        this.labels = null;
+        this.vars = null;
+        this.functions = null;
+        localVars.clear();
         
-        /*for(Instruction in : input)
-        {
-            System.out.println(in);
+        Instruction[] code = instr.toArray(new Instruction[instr.size()]);
+        instr.clear();
+        return code;
+    }
+    
+    private void line()
+    {
+        int oldIndex = index;
+        Token t = advance();
+        switch(t.getType())
+        {
+            case LABEL: handleLabel(); break;
+            case IF: handleIf(); break;
+            case SEMICOLON: break;
+            case FOR: handleFor(); break;
+            case BREAK: 
+                Break b = new Break(previous().getLine());
+                breakStack.add(b);
+                instr.add(b); 
+                consume(SEMICOLON);
+                break;
+            case CONTINUE:
+                Continue c = new Continue(previous().getLine());
+                continueStack.add(c);
+                instr.add(c);
+                consume(SEMICOLON);
+                break;
+            case FUNCTION: handleUserFunction(); break;
+            case RETURN: handleReturn(); break;
+            case WHILE: handleWhile(); break;
+            case TRY: handleTry(); break;
+            default:
+                index = oldIndex;
+                lineExpression = false;
+                expression();
+                if(!lineExpression)
+                {
+                    throw new PreScriptException("missing statement", t.getLine());
+                }
+                consume(SEMICOLON);
         }
-        System.out.println("__________________________________");*/
-        /*labels.entrySet().stream().forEach((e) -> 
-        {
-            System.out.println("LABEL " + e.getKey() + " " + e.getValue());
-        });*/
-        //System.out.println("__________________________________");
-        return input;
+        noReturnForLastFunction();
     }
     
-    private void compileLine(String currentCode)
+    private void handleLabel()
     {
-        //System.out.println(">>>"  + currentCode);
-        String[] parts = SnuviUtils.split(strings, currentCode, line);
-        //System.out.println(">>> " + String.join("_", parts));
-        if(tryState != null)
+        String name = previous().getData().toString();
+        name = name.substring(1); // cut off @ at start
+        if(inFunction != null)
         {
-            switch(parts.length)
+            HashMap<String, Integer> llabel = localLabels.get(inFunction);
+            if(llabel == null)
             {
-                case 0: return;
-                case 1: 
-                    if(!parts[0].equals("catch"))
-                    {
-                        throw new PreScriptException("no catch after try", line);
-                    }
-                    if(tryState == null)
-                    {
-                        throw new PreScriptException("catch without try", line);
-                    }
-                    tryState.setRelativeJump(code.size());
-                    JumpData jump = new JumpData(code.size());
-                    addCodeInstruction("catch", new InputProvider[] {jump});
-                    jumps.push(new JumpWrapper(jump, "catch"));
-                    tryState = null;
-                    return;
-                default:
-                    throw new PreScriptException("invalid catch after try", line);
+                llabel = new HashMap<>();
+                localLabels.put(inFunction, llabel);
             }
+            llabel.put(name, instr.size() - 1);
         }
-        
-        if(parts.length == 0)
+        else
         {
-            return;
+            labels.put(name, instr.size() - 1);
         }
-        else if(parts[0].equals("return"))
-        {
-            addCodeInstruction("return", compileFunction(parts, true));
-            return;
-        }
-        else if(parts[0].startsWith("@"))
-        {
-            if(parts.length > 1)
+    }
+    
+    private void handleIf()
+    {
+        Token t = previous();
+        consume(OPEN_BRACKET);
+        expression();
+        If i = new If(t.getLine());
+        instr.add(i);
+        consume(CLOSE_BRACKET);
+        consume(OPEN_CURVED_BRACKET);
+        while(!match(CLOSE_CURVED_BRACKET))
+        {
+            line();
+        }
+        i.setJump(instr.size() - 1);
+        handleElseIf();
+        instr.add(new EndIf(instr.get(instr.size() - 1).getLine()));
+    }
+    
+    private void handleElseIf()
+    {
+        while(match(ELSEIF))
+        {
+            Token t = previous();
+            consume(OPEN_BRACKET);
+            expression();
+            ElseIf e = new ElseIf(t.getLine());
+            instr.add(e);
+            consume(CLOSE_BRACKET);
+            consume(OPEN_CURVED_BRACKET);
+            while(!match(CLOSE_CURVED_BRACKET))
             {
-                throw new PreScriptException("arguments after label", line);
+                line();
             }
-            addLabel(parts[0].substring(1), code.size() - 1);
-            return;
+            e.setJump(instr.size() - 1);
         }
-        
-        String input;
-        if(parts.length == 1)
+        handleElse();
+    }
+
+    private void handleElse()
+    {
+        if(match(ELSE))
         {
-            int bPos = parts[0].indexOf('(');
-            if(bPos != -1)
+            Else e = new Else(previous().getLine());
+            instr.add(e);
+            consume(OPEN_CURVED_BRACKET);
+            while(!match(CLOSE_CURVED_BRACKET))
             {
-                input = parts[0].substring(0, bPos);
-                parts = SnuviUtils.split(strings, parts[0].substring(bPos + 1, parts[0].length() - 1), line);
-            }
-            else
-            {
-                switch(parts[0])
-                {
-                    case "try":
-                    {
-                        JumpData jump = new JumpData(code.size());
-                        addCodeInstruction("try", new InputProvider[] {jump});
-                        jumps.push(new JumpWrapper(jump, "try"));
-                        return;
-                    }
-                    case "else":
-                    {
-                        JumpData jump = new JumpData(code.size());
-                        addCodeInstruction("else", new InputProvider[] {jump});
-                        jumps.push(new JumpWrapper(jump, "else"));
-                        return;
-                    }
-                    case "while":
-                        throw new PreScriptException("missing syntax at while", line);
-                    case "if":
-                        throw new PreScriptException("missing syntax at if", line);
-                    case "elseif":
-                        throw new PreScriptException("missing syntax at elseif", line);
-                    case "for":
-                        throw new PreScriptException("missing syntax at for", line);             
-                    case "break":
-                    {
-                        if(loopJumps.isEmpty())
-                        {
-                            throw new PreScriptException("break without a loop", line);
-                        }
-                        JumpData jump = new JumpData(code.size() - 1);
-                        breakContinueJumps.add(jump);
-                        addCodeInstruction("break", new InputProvider[] {jump});
-                        return;
-                    }
-                    case "continue":
-                    {
-                        if(loopJumps.isEmpty())
-                        {
-                            throw new PreScriptException("continue without a loop", line);
-                        }
-                        JumpData jump = new JumpData(code.size());
-                        breakContinueJumps.add(jump);
-                        addCodeInstruction("continue", new InputProvider[] {jump});
-                        return;
-                    }
-                }
-                return;
-            }
-        }
-        else
-        {
-            switch(parts[0])
-            {           
-                case "++":
-                    addCodeInstruction("p++", compileFunction(new String[] {parts[1]}, false));
-                    return;
-                case "--":
-                    addCodeInstruction("p--", compileFunction(new String[] {parts[1]}, false));
-                    return;
-            }
-            switch(parts[1])
-            {           
-                case "++":
-                case "--":
-                    input = parts[1];
-                    parts = new String[] {parts[0]};
-                    break;
-                case "=":
-                case "+=":
-                case "-=":
-                case "*=":
-                case "/=":
-                case "%=":
-                case "<<=":
-                case ">>=":
-                case "&=":
-                case "^=":
-                case "|=":
-                {
-                    input = parts[1];
-                    parts[1] = ",";
-                    break;
-                }
-                default:
-                    throw new PreScriptException("unknown operation " + parts[1], line);
+                line();
             }
-        }
-        switch(input)
-        {
-            case "break":
-                throw new PreScriptException("break does not accept arguments", line);
-            case "continue":
-                throw new PreScriptException("continue does not accept arguments", line);      
-        }
-        //System.out.println(input + "  " + String.join("__", parts));
-        
-        switch(input)
-        {
-            case "elseif":
-                createIf("elseif", parts);
-                break;
-            case "if":
-                createIf("if", parts);
-                break;
-            case "for":
-                createFor(parts);
-                break;
-            case "while":
-                createWhile(parts);
-                break;
-            default:
-                addCodeInstruction(input, compileFunction(parts, false));
+            e.setJump(instr.size() - 1);
         }
     }
     
-    private void addSyntax(LinkedList<InputProvider> list, Syntax sy)
+    private void handleFor()
     {
-        int pars = sy.getParameters();
-        if(pars > list.size())
+        Token t = previous();
+        consume(OPEN_BRACKET);    
+        if(!match(SEMICOLON))
         {
-            throw new PreScriptException("missing syntax argument", line);
+            expression();
+            consume(SEMICOLON);
+            noReturnForLastFunction();
         }
-        if(sy == Syntax.UNARY_SUB)
+        
+        int forConditionStart = instr.size() - 1;
+        if(!match(SEMICOLON))
         {
-            list.add(new SignInverter(list.pollLast()));
-            return;
+            expression();
+            consume(SEMICOLON);
         }
-        InputProvider[] input = new InputProvider[pars];
-        for(int j = input.length - 1; j >= 0; j--)
+        Goto forGoto = new Goto(instr.get(instr.size() - 1).getLine(), 0);
+        instr.add(forGoto);
+        
+        int forLoopFunctionStart = instr.size() - 1;
+        if(!match(CLOSE_BRACKET))
         {
-            input[j] = list.pollLast();
+            expression();
+            consume(CLOSE_BRACKET);
+            noReturnForLastFunction();
         }
-        list.add(new Function(FunctionLoader.getFunction(sy.getFunction()), input));
+        Goto conditionGoto = new Goto(instr.get(instr.size() - 1).getLine(), 0);
+        conditionGoto.setJump(forConditionStart);
+        instr.add(conditionGoto);
+        
+        int forStart = instr.size() - 1;
+        forGoto.setJump(forStart);
+        For f = new For(t.getLine()); 
+        instr.add(f);
+        consume(OPEN_CURVED_BRACKET);
+        while(!match(CLOSE_CURVED_BRACKET))
+        {
+            line();
+        }
+        Goto loopFunctionGoto = new Goto(instr.get(instr.size() - 1).getLine(), 0);
+        loopFunctionGoto.setJump(forLoopFunctionStart);
+        instr.add(loopFunctionGoto);
+        int forEnd = instr.size() - 1;
+        f.setJump(forEnd);
+        
+        setBreakContinueJumps(forLoopFunctionStart, forEnd);
     }
     
-    private void validateStackCounter(int stackCounter)
+    private void setBreakContinueJumps(int start, int end)
     {
-        if(stackCounter < 0)
+        while(!continueStack.empty())
+        {
+            continueStack.pop().setJump(start);
+        }
+        while(!breakStack.empty())
         {
-            throw new PreScriptException("missing syntax argument", line);
+            breakStack.pop().setJump(end);
         }
     }
     
-    private InputProvider[] compileFunction(String[] parts, boolean first)
+    private void handleUserFunction()
     {
-        LinkedList<InputProvider> list = new LinkedList<>();
-        int stackCounter = 0;
-        
-        Stack<Syntax> syntax = new Stack<>();
-        int bottom = first ? 1 : 0;
-        Syntax sy;
-        for(int i = bottom; i < parts.length; i++)
+        consume(LITERAL);
+        Token t = previous();
+        consume(OPEN_BRACKET);
+        ArrayList<String> list = new ArrayList<>();
+        if(!match(CLOSE_BRACKET))
         {
-            if(parts[i].equals(","))
-            {
-                // finding a comma means pushing all syntax functions
-                while(!syntax.isEmpty())
-                {
-                    addSyntax(list, syntax.pop());
-                }
-                stackCounter = 0;
-                continue;
-            }
-            sy = Syntax.getSyntax(parts[i]);
-            if(sy != Syntax.UNKNOWN)
+            while(true)
             {
-                if(stackCounter <= 0)
-                {
-                    switch(sy)
-                    {
-                        case INVERT:
-                            break;
-                        case BIT_INVERT:
-                            break;
-                        case SUB:
-                            sy = Syntax.UNARY_SUB;
-                            break;
-                        case POST_INC:
-                            sy = Syntax.INC;
-                            break;
-                        case POST_DEC:
-                            sy = Syntax.DEC;
-                            break;
-                        default:
-                            throw new PreScriptException("missing syntax argument", line);
-                    }
-                }
-                else
-                {
-                    switch(sy)
-                    {
-                        case INVERT:
-                        case BIT_INVERT:
-                            throw new PreScriptException("missing syntax argument", line);
-                    }
-                }
-                // pushing weaker functions
-                int weight = sy.getWeight();
-                while(!syntax.isEmpty() && syntax.peek().getWeight() <= weight)
+                consume(LITERAL);
+                list.add(previous().getData().toString());
+                if(match(CLOSE_BRACKET))
                 {
-                    addSyntax(list, syntax.pop());
+                    break;
                 }
-                validateStackCounter(stackCounter);
-                syntax.add(sy);
-                stackCounter -= sy.getParameters() - 1;
-                continue;
+                consume(COMMA);
             }
-            stackCounter++;
-            list.add(convertString(parts[i]));
-        }
-        // pushing left over syntax functions because no comma happened
-        while(!syntax.isEmpty())
-        {
-            addSyntax(list, syntax.pop());
-        }
-        validateStackCounter(stackCounter);
-        return list.toArray(new InputProvider[list.size()]);
+        }  
+        String name = t.getData().toString().toLowerCase();
+        UserFunction uf = new UserFunction(t.getLine(), name, list.toArray(new String[list.size()]));
+        functions.put(name, instr.size());
+        instr.add(uf);
+        consume(OPEN_CURVED_BRACKET);
+        inFunction = name;
+        while(!match(CLOSE_CURVED_BRACKET))
+        {
+            line();
+        }
+        inFunction = null;
+        instr.add(new Return(instr.get(instr.size() - 1).getLine(), 0));
+        uf.setJump(instr.size() - 1);
     }
     
-    private InputProvider convertString(String input)
+    private void handleReturn()
     {
-        if(input.startsWith("@"))
+        Token t = previous();
+        int args = 0;
+        if(!match(SEMICOLON))
         {
-            return new ConstantString(input.substring(1));
+            args = 1;
+            expression();
+            consume(SEMICOLON);
         }
-        else if(input.startsWith("\"") && input.endsWith("\""))
-        {
-            return new ConstantString(input.substring(1, input.length() - 1));
-        }
-        else if(input.equals("true"))
-        {
-            return ConstantBoolean.TRUE;
-        }
-        else if(input.equals("false"))
+        instr.add(new Return(t.getLine(), args));
+    }
+    
+    private void handleWhile()
+    {
+        int whileStart = instr.size() - 1;
+        Token t = previous();
+        consume(OPEN_BRACKET);
+        expression();
+        While w = new While(t.getLine());
+        instr.add(w);
+        consume(CLOSE_BRACKET);
+        consume(OPEN_CURVED_BRACKET);
+        while(!match(CLOSE_CURVED_BRACKET))
+        {
+            line();
+        }
+        addGoto(instr.get(instr.size() - 1).getLine(), whileStart);
+        int whileEnd = instr.size() - 1;
+        w.setJump(whileEnd);
+        setBreakContinueJumps(whileStart, whileEnd);
+    }
+    
+    private void handleTry()
+    {
+        Try t = new Try(previous().getLine());
+        instr.add(t);
+        consume(OPEN_CURVED_BRACKET);
+        while(!match(CLOSE_CURVED_BRACKET))
         {
-            return ConstantBoolean.FALSE;
+            line();
         }
-        else if(input.equals("null"))
+        consume(CATCH);
+        Catch c = new Catch(previous().getLine());
+        instr.add(c);
+        t.setJump(instr.size() - 1);
+        consume(OPEN_CURVED_BRACKET);
+        while(!match(CLOSE_CURVED_BRACKET))
         {
-            return ConstantNull.NULL;
+            line();
         }
-        else if(SnuviUtils.isNumber(input))
+        c.setJump(instr.size() - 1);
+    }
+
+    private void expression()
+    {
+        assignment();
+    }
+    
+    private void assignment()
+    {
+        logicalOr();
+        if(match(SET, ADD_SET, SUB_SET, MUL_SET, DIV_SET, MOD_SET, LEFT_SHIFT_SET, 
+                RIGHT_SHIFT_SET, BIT_AND_SET, BIT_XOR_SET, BIT_OR_SET))
         {
-            return new ConstantDouble(Double.parseDouble(input));
+            Token t = previous();
+            assignment();
+            addFunction(t.getLine(), 2, t.getType().getName());
+            lineExpression = true;
         }
-        else if(SnuviUtils.isFunction(input))
+    }   
+    
+    private void logicalOr()
+    {
+        logicalAnd();
+        while(match(OR))
         {
-            int bPos = input.indexOf('(');
-            String[] parts = SnuviUtils.split(strings, input.substring(bPos + 1, input.length() - 1), line);
-            if(parts.length > 0)
-            {
-                return new Function(FunctionLoader.getFunction(input.substring(0, bPos)), compileFunction(parts, false));
-            }
-            else
-            {
-                return new Function(FunctionLoader.getFunction(input.substring(0, bPos)), new InputProvider[0]);
-            }
+            Token t = previous();
+            IfGoto ifGoto = new IfGoto(t.getLine(), true);
+            instr.add(ifGoto);
+            logicalAnd();
+            ifGoto.setJump(instr.size());
+            addFunction(t.getLine(), 2, t.getType().getName());
         }
-        else if(SnuviUtils.isArray(input))
+    }  
+    
+    private void logicalAnd()
+    {
+        equality();
+        while(match(AND))
         {
-            int bPos = input.indexOf('[');
-            String[] parts = SnuviUtils.split(strings, input.substring(bPos + 1, input.length() - 1), line);
-            if(parts.length > 0)
-            {
-                return createArray(input.substring(0, bPos), compileFunction(parts, false));
-            }
-            else
-            {
-                return createArray(input.substring(0, bPos), new InputProvider[0]);
-            }
+            Token t = previous();
+            IfGoto ifGoto = new IfGoto(t.getLine(), false);
+            instr.add(ifGoto);
+            equality();
+            ifGoto.setJump(instr.size());
+            addFunction(t.getLine(), 2, t.getType().getName());
         }
-        else
+    }  
+
+    private void equality()
+    {
+        comparison();
+        while(match(EQUAL, NOT_EQUAL))
         {
-            return getOrCreateVariable(input);
+            Token t = previous();
+            comparison();
+            addFunction(t.getLine(), 2, t.getType().getName());
         }
     }
-    
-    public static Object convert(String input)
+
+    private void comparison()
     {
-        if(input == null)
+        addition();
+        while(match(GREATER, GREATER_EQUAL, LESS, LESS_EQUAL))
         {
-            return null;
+            Token t = previous();
+            addition();
+            addFunction(t.getLine(), 2, t.getType().getName());
         }
-        input = input.trim();
-        if(input.equals("true"))
-        {
-            return true;
-        }
-        else if(input.equals("false"))
+    }
+
+    private void addition()
+    {
+        multiplication();
+        while(match(SUB, ADD))
         {
-            return false;
+            Token t = previous();
+            multiplication();
+            addFunction(t.getLine(), 2, t.getType().getName());
         }
-        else if(input.equals("null"))
+    }
+
+    private void multiplication()
+    {
+        unary();
+        while(match(DIV, MUL, MOD))
         {
-            return null;
+            Token t = previous();
+            unary();
+            addFunction(t.getLine(), 2, t.getType().getName());
         }
-        else if(input.startsWith("\"") && input.endsWith("\""))
+    }
+
+    private void unary()
+    {
+        if(match(INVERT, BIT_INVERT, SUB, INC, DEC))
         {
-            if(input.length() == 1)
+            Token t = previous();
+            unary();
+            addFunction(t.getLine(), 1, t.getType().getName());
+            if(t.getType() == INC || t.getType() == DEC)
             {
-                return "\"";
+                lineExpression = true;
             }
-            return input.substring(1, input.length() - 1);
+            return;
         }
-        try
+        postUnary();
+    }
+    
+    private void postUnary()
+    {
+        primary();
+        while(match(INC, DEC))
         {
-            return Double.parseDouble(input);
+            Token t = previous();
+            addFunction(t.getLine(), 1, "p" + t.getType().getName());
+            lineExpression = true;
         }
-        catch(NumberFormatException ex)
-        {
-            return input;
+    }
+
+    private void primary()
+    {
+        Token t = advance();
+        switch(t.getType())
+        {
+            case FALSE: addConstant(t.getLine(), ConstantBoolean.FALSE); return;
+            case TRUE: addConstant(t.getLine(), ConstantBoolean.TRUE); return;
+            case NULL: addConstant(t.getLine(), ConstantNull.NULL); return;
+            case STRING: addConstant(t.getLine(), new ConstantString(t.getData().toString())); return;
+            case LABEL: addConstant(t.getLine(), new ConstantString(t.getData().toString().substring(1))); return;
+            case NUMBER: addConstant(t.getLine(), new ConstantDouble((Double) t.getData())); return;
+            case OPEN_BRACKET:
+                expression();
+                consume(CLOSE_BRACKET);
+                return;
+            case LITERAL:
+                if(match(OPEN_SQUARE_BRACKET))
+                {
+                    handleArray(t);
+                }
+                else if(match(OPEN_BRACKET))
+                {
+                    handleFunction(t);
+                }
+                else
+                {
+                    addConstant(t.getLine(), getVariable(t.getData().toString()));
+                }
+                return;
         }
+        throw new PreScriptException(String.format("unexpected token %s", t.getType()), t.getLine());
     }
     
-    private Variable getOrCreateVariable(String var)
+    public void handleFunction(Token t)
     {
-        if(currentFunction != null && var.charAt(0) != '$')
+        int args = 0;
+        if(peek().getType() != CLOSE_BRACKET)
         {
-            Variable oldVar = localVars.get(var);
-            if(oldVar == null)
+            while(true)
             {
-                oldVar = new LocalVariable(var);
-                localVars.put(var, oldVar);
+                args++;
+                expression();
+                if(match(CLOSE_BRACKET))
+                {
+                    break;
+                }
+                consume(COMMA);
             }
-            return oldVar;
         }
         else
         {
-            if(var.charAt(0) == '$')
-            {
-                var = var.substring(1);
-            }                     
-            Variable oldVar = vars.get(var);
-            if(oldVar == null)
-            {
-                oldVar = new Variable(var);
-                vars.put(var, oldVar);
-            }
-            return oldVar;
+            consume(CLOSE_BRACKET);
         }
+        addFunction(t.getLine(), args, t.getData().toString());
+        lineExpression = true;
     }
     
-    private DynamicArray createArray(String var, InputProvider[] in)
+    public void handleArray(Token t)
     {
-        if(currentFunction != null)
+        if(peek().getType() == CLOSE_SQUARE_BRACKET)
         {
-            Variable oldVar = localVars.get(var);
-            if(oldVar == null)
-            {
-                oldVar = new LocalArrayVariable(var);
-                localVars.put(var, oldVar);
-            }
-            return new DynamicArray(oldVar, in);    
+            throw new PreScriptException("empty array access", peek().getLine());
         }
-        else
+        int args = 0;
+        while(true)
         {
-            Variable oldVar = vars.get(var);
-            if(oldVar == null)
+            args++;
+            expression();
+            if(match(CLOSE_SQUARE_BRACKET))
             {
-                oldVar = new ArrayVariable(var);
-                vars.put(var, oldVar);
+                break;
             }
-            return new DynamicArray(oldVar, in);
+            consume(COMMA);
         }
+        instr.add(new Array(t.getLine(), args, getVariable(t.getData().toString())));
     }
     
-    private void createIf(String name, String[] parts)
-    {
-        InputProvider[] input = compileFunction(parts, false);
-        InputProvider[] realInput = new InputProvider[input.length + 1];
-
-        System.arraycopy(input, 0, realInput, 0, input.length);
-        JumpData jump = new JumpData(code.size());
-        realInput[input.length] = jump;
-        jumps.push(new JumpWrapper(jump, name));
-        
-        addCodeInstruction(name, realInput);
-    }
-    
-    private void createFor(String[] parts)
+    private Variable getVariable(String name)
     {
-        // expected syntax
-        // for(var, start, end, step)
-        // for(var, start, end)
-        InputProvider[] input = compileFunction(parts, false);
-        if(input.length != 3 && input.length != 4)
+        boolean global = name.startsWith("$");
+        if(inFunction != null && !global)
         {
-            throw new PreScriptException("missing 'for' syntax at", line);
+            LocalVariable v = localVars.get(name);
+            if(v != null)
+            {
+                return v;
+            }
+            v = new LocalVariable(name);
+            localVars.put(name, v);
+            return v;
         }
-        InputProvider[] realInput = new InputProvider[5];
-
-        System.arraycopy(input, 0, realInput, 0, input.length);
         
-        if(input.length == 3)
+        if(global)
         {
-            realInput[3] = new ConstantDouble(1.0);
+            name = name.substring(1);
         }
         
-        JumpData jump = new JumpData(code.size());
-        realInput[4] = jump;
-        JumpWrapper wrapper = new JumpWrapper(jump, "for");
-        jumps.push(wrapper);
-        loopJumps.push(wrapper);
-        
-        addCodeInstruction("for", realInput);
-    }
-    
-    private void createWhile(String[] parts)
-    {
-        // expected syntax
-        // while(condition)
-        InputProvider[] input = compileFunction(parts, false);
-        if(input.length != 1)
+        Variable v = vars.get(name);
+        if(v != null)
         {
-            throw new PreScriptException("invalid conditions at 'while'", line);
+            return v;
         }
-        InputProvider[] realInput = new InputProvider[2];
-        realInput[0] = input[0];
-        
-        JumpData jump = new JumpData(code.size());
-        realInput[1] = jump;
-        
-        JumpWrapper wrapper = new JumpWrapper(jump, "while");
-        jumps.push(wrapper);
-        loopJumps.push(wrapper);
-
-        addCodeInstruction("while", realInput);
-    }
-    
-    private void createBreakContinue(int current)
-    {
-        breakContinueJumps.forEach(jump -> jump.setRelativeJump(current));
-        breakContinueJumps.clear();
+        v = new Variable(name);
+        vars.put(name, v);
+        return v;
     }
 }

+ 0 - 81
src/me/hammerle/snuviscript/code/Function.java

@@ -1,81 +0,0 @@
-package me.hammerle.snuviscript.code;
-
-import me.hammerle.snuviscript.variable.Variable;
-import me.hammerle.snuviscript.variable.ArrayVariable;
-import me.hammerle.snuviscript.variable.LocalArrayVariable;
-
-public class Function extends InputProvider
-{
-    private final BasicFunction function;
-    private final InputProvider[] input;
-    
-    public Function(BasicFunction function, InputProvider[] input)
-    {
-        this.function = function;
-        this.input = input;
-    }
-    
-    public InputProvider[] getArguments()
-    {
-        return input;
-    }
-
-    @Override
-    public String toString() 
-    {
-        StringBuilder sb = new StringBuilder(function.getName());
-        sb.append("(");
-        for(InputProvider in : input)
-        {
-            sb.append(in);
-            sb.append(", ");
-        }
-        if(input.length > 0)
-        {
-            sb.delete(sb.length() - 2, sb.length());
-        }
-        sb.append(")");
-        return sb.toString();
-    }
-
-    @Override
-    public Object get(Script sc) throws Exception
-    {
-        return function.execute(sc, input);
-    }
-    
-    @Override
-    public Object getArray(Script sc) throws Exception
-    {
-        Object o = function.execute(sc, input);
-        if(o instanceof ArrayVariable || o instanceof LocalArrayVariable)
-        {
-            return o;
-        }
-        return null;
-    }
-    
-    @Override
-    public double getDouble(Script sc) throws Exception
-    {
-        return (double) function.execute(sc, input);
-    }
-    
-    @Override
-    public String getString(Script sc) throws Exception
-    {
-        return String.valueOf(function.execute(sc, input));
-    }
-    
-    @Override
-    public boolean getBoolean(Script sc) throws Exception
-    {
-        return (Boolean) function.execute(sc, input);
-    }
-    
-    @Override
-    public Variable getVariable(Script sc) throws Exception
-    {
-        return (Variable) function.execute(sc, input);
-    }
-}

+ 56 - 218
src/me/hammerle/snuviscript/code/FunctionLoader.java → src/me/hammerle/snuviscript/code/FunctionRegistry.java

@@ -1,5 +1,6 @@
 package me.hammerle.snuviscript.code;
 
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 import java.io.File;
 import java.nio.charset.StandardCharsets;
 import java.lang.reflect.Array;
@@ -19,18 +20,15 @@ import java.util.Iterator;
 import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
-import me.hammerle.snuviscript.array.DynamicArray;
 import me.hammerle.snuviscript.config.SnuviConfig;
-import me.hammerle.snuviscript.variable.ArrayVariable;
-import me.hammerle.snuviscript.variable.Variable;
 
-public class FunctionLoader 
+public class FunctionRegistry 
 {
-    private static final HashMap<String, BasicFunction> FUNCTIONS = new HashMap<>();
+    private static final HashMap<String, NamedFunction> FUNCTIONS = new HashMap<>();
     
     protected static void registerFunction(String name, String fname, ExceptionBiFunction<Script, InputProvider[], Object> f)
     {
-        FUNCTIONS.put(name, new BasicFunction(fname, f));
+        FUNCTIONS.put(name, new NamedFunction(fname, f));
     }
     
     protected static void registerFunction(String name, ExceptionBiFunction<Script, InputProvider[], Object> f)
@@ -43,51 +41,13 @@ public class FunctionLoader
         FUNCTIONS.put(alias, FUNCTIONS.get(original));
     }
     
-    public static BasicFunction getFunction(String f)
+    public static NamedFunction getFunction(String f)
     {
         final String function = f.toLowerCase();
-        return FUNCTIONS.getOrDefault(function, new BasicFunction(function, (sc, in) -> 
+        return FUNCTIONS.getOrDefault(function, new NamedFunction(function, (sc, in) -> 
         {
-            Integer sub = sc.functions.get(function);
-            if(sub == null)
-            {
-                throw new NullPointerException("function " + function + " does not exist");
-            }
-            InputProvider[] arguments = sc.code[sub].getArguments();
-            // push storage for local vars
-            HashMap<String, Variable> vars = new HashMap<>();
-            if(in.length != arguments.length - 1)
-            {
-                throw new NullPointerException("invalid number of arguments at function '" + function + "'");
-            }
-            // generate local vars
-            String s;
-            Variable v;
-            for(int i = 0; i < in.length; i++)
-            {
-                s = arguments[i + 1].getString(sc);
-                if(in[i].isArray(sc))
-                {
-                    v = new ArrayVariable(s);
-                    v.set(sc, in[i].getArray(sc));
-                }
-                else
-                {
-                    v = new Variable(s);
-                    v.set(sc, in[i].get(sc));
-                }
-                vars.put(s, v);
-            }
-            
-            sc.currentFunction = function;
-            sc.localVars.push(vars);
-            sc.returnStack.push(sc.currentLine);
-            sc.currentLine = sub + 1;
-            Object r = sc.run();
-            sc.currentLine = sc.returnStack.pop();
-            sc.localVars.pop();
-            sc.currentFunction = null;
-            return r;
+            sc.handleFunction(function, in);
+            return Void.TYPE;
         }));
     }
     
@@ -99,13 +59,13 @@ public class FunctionLoader
         registerFunction("nothing", (sc, in) -> Void.TYPE);
         registerFunction("error", (sc, in) -> 
         {
-            sc.printStackTrace = !sc.printStackTrace;
-            return sc.printStackTrace;
+            sc.setStackTrace(in[0].getBoolean(sc));
+            return Void.TYPE;
         });
         registerFunction("", (sc, in) -> in[0].get(sc));
         registerFunction("test", (sc, in) -> 
         {
-            //sc.parser.startScript(true, ".sbasic", "./test2");  
+            //sc.getScriptManager().startScript(true, ".sbasic", "./test2");  
             return Void.TYPE;
         });
         
@@ -114,12 +74,16 @@ public class FunctionLoader
         // --------------------------------------------------------------------- 
         registerFunction("event.load", (sc, in) ->
         {
-            sc.events.add(in[0].getString(sc));
+            String event = in[0].getString(sc);
+            sc.loadEvent(event);
+            sc.getScriptManager().loadEventSafe(event, sc);
             return Void.TYPE;
         });
         registerFunction("event.unload", (sc, in) ->
         {
-            sc.events.remove(in[0].getString(sc));
+            String event = in[0].getString(sc);
+            sc.unloadEvent(in[0].getString(sc));
+            sc.getScriptManager().unloadEventSafe(event, sc);
             return Void.TYPE;
         });
         registerFunction("event.isloaded", (sc, in) -> sc.isEventLoaded(in[0].getString(sc)));
@@ -130,7 +94,7 @@ public class FunctionLoader
         registerFunction("script.get", (sc, in) -> 
         {
             String name = in[0].getString(sc);
-            for(Script script : sc.parser.getScripts())
+            for(Script script : sc.getScriptManager().getScripts())
             {
                 if(script.getName().equals(name))
                 {
@@ -142,13 +106,15 @@ public class FunctionLoader
         registerFunction("script.getall", (sc, in) -> 
         {
             String name = in[0].getString(sc);
-            return sc.parser.getScripts().stream()
+            return sc.getScriptManager().getScripts().stream()
                     .filter(script -> script.getName().equals(name))
                     .collect(Collectors.toList());
         });
         registerFunction("script.term", (sc, in) -> 
         {
-            sc.parser.termSafe((Script) in[0].get(sc));
+            Script other = (Script) in[0].get(sc);
+            other.term();
+            sc.getScriptManager().removeScriptSafe(other);
             return Void.TYPE;
         });
         
@@ -254,13 +220,19 @@ public class FunctionLoader
         // ---------------------------------------------------------------------   
         registerFunction("array.new", (sc, in) -> 
         {
-            for(InputProvider input : in)
+            if(in.length == 0)
             {
-                ((DynamicArray) input).init(sc);
+                throw new ArrayIndexOutOfBoundsException("missing array dimension");
             }
-            return Void.TYPE;
+            int[] dim = new int[in.length];
+            for(int i = 0; i < in.length; i++)
+            {
+                dim[i] = in[i].getInt(sc);
+            }
+            return Array.newInstance(Object.class, dim);
         });
-        registerFunction("array.getsize", (sc, in) -> (double) Array.getLength(in[0].getArray(sc)));
+        registerFunction("array.getsize", (sc, in) -> (double) Array.getLength(in[0].get(sc)));
+        registerAlias("array.getsize", "array.length");
         
         /*
         registerFunction("array.swap", (sc, in) ->                                           
@@ -430,7 +402,7 @@ public class FunctionLoader
                 ArrayList<Object> list = new ArrayList<>();
                 for(String part : parts)
                 {
-                    list.add(Compiler.convert(part));
+                    list.add(SnuviUtils.convert(part));
                 }
                 return list;
             }
@@ -440,7 +412,7 @@ public class FunctionLoader
                 ArrayList<Object> list = new ArrayList<>();
                 for(String part : parts)
                 {
-                    list.add(Compiler.convert(part));
+                    list.add(SnuviUtils.convert(part));
                 }
                 in[0].set(sc, list);
                 return Void.TYPE;
@@ -563,7 +535,7 @@ public class FunctionLoader
         // elementary calculating
         registerFunction("+", (sc, in) -> in[0].getDouble(sc) + in[1].getDouble(sc));
         registerAlias("+", "add");
-        registerFunction("-", (sc, in) -> in[0].getDouble(sc) - in[1].getDouble(sc));
+        registerFunction("-", (sc, in) -> in.length == 1 ? -in[0].getDouble(sc) : in[0].getDouble(sc) - in[1].getDouble(sc));
         registerAlias("-", "sub");
         registerFunction("*", (sc, in) -> in[0].getDouble(sc) * in[1].getDouble(sc));
         registerAlias("*", "mul");
@@ -675,48 +647,23 @@ public class FunctionLoader
         {
             sc.getVar(in[0].getString(sc)).set(sc, null);
             return Void.TYPE;
-        });  
-        
+        });
         
         registerFunction("wait", (sc, in) -> 
         {
-            sc.isWaiting = true;
+            sc.setWaiting();
             return Void.TYPE;
         });
         
-        // try - catch
-        registerFunction("try", (sc, in) -> 
-        {
-            sc.catchLine = sc.currentLine + in[0].getInt(sc);
-            return Void.TYPE;
-        });              
-        registerFunction("catch", (sc, in) -> 
-        {
-            if(sc.catchLine != -1)
-            {
-                sc.currentLine += in[0].getInt(sc);
-            }
-            return Void.TYPE;
-        });  
-        
         // branching
-        registerFunction("function", (sc, in) -> 
-        {
-            sc.currentLine += in[0].getInt(sc);
-            return Void.TYPE;
-        });  
         registerFunction("goto", (sc, in) -> 
         {
-            sc.currentLine = sc.getLabel(in[0].getString(sc));
+            sc.gotoLabel(in[0].getString(sc), true);
             return Void.TYPE;
         });   
         registerFunction("ignoregoto", (sc, in) -> 
         {
-            Integer i = sc.getLabel(in[0].getString(sc));
-            if(i != null)
-            {
-                sc.currentLine = i;
-            }
+            sc.gotoLabel(in[0].getString(sc), false);
             return Void.TYPE;
         }); 
         registerAlias("ignoregoto", "igoto");
@@ -727,133 +674,25 @@ public class FunctionLoader
             {
                 throw new IllegalArgumentException("time units can't be negative");
             }
-            int label = sc.getLabel(in[1].getString(sc));
-            sc.scheduler.scheduleTask(() -> 
+            String label = in[1].getString(sc);
+            sc.getScriptManager().getScheduler().scheduleTask(() -> 
             {
-                if(!sc.isValid || sc.isHolded)
+                if(sc.shouldTerm())
                 {
                     return;
                 }
-                sc.currentLine = label + 1;
+                sc.gotoLabel(label, true, 1);
                 sc.run();
-                if(!sc.isValid)
+                if(sc.shouldTerm())
                 {
-                    sc.parser.termUnsafe(sc);
+                    sc.getScriptManager().removeScriptSafe(sc);
                 }
             }, time);
             return Void.TYPE;
         });
         registerFunction("gosub", (sc, in) -> 
         {
-            sc.returnStack.push(sc.currentLine);
-            sc.currentLine = sc.getLabel(in[0].getString(sc));
-            return Void.TYPE;
-        });
-        registerFunction("return", (sc, in) -> 
-        {
-            if(sc.returnStack.isEmpty())
-            {
-                sc.end();
-                sc.returnValue = in.length > 0 ? in[0].get(sc) : null;
-            }
-            else
-            {
-                if(sc.localVars.empty())
-                {
-                    sc.currentLine = sc.returnStack.pop();
-                }
-                else
-                {
-                    sc.end();
-                    sc.returnValue = in.length > 0 ? in[0].get(sc) : null;
-                }
-            }
-            return Void.TYPE;
-        });
-        registerFunction("if", (sc, in) -> 
-        {
-            sc.ifState = in[0].getBoolean(sc);
-            if(!sc.ifState)
-            {
-                sc.currentLine += in[1].getInt(sc);
-            }
-            return Void.TYPE;
-        });
-        registerFunction("endif", (sc, in) -> 
-        {
-            sc.ifState = true;
-            return Void.TYPE;
-        });
-        registerFunction("elseif", (sc, in) -> 
-        {
-            if(sc.ifState)
-            {
-                sc.currentLine += in[1].getInt(sc);
-            }
-            else
-            {
-                sc.ifState = in[0].getBoolean(sc);
-                if(!sc.ifState)
-                {
-                    sc.currentLine += in[1].getInt(sc);
-                }
-            }
-            return Void.TYPE;
-        });
-        registerFunction("else", (sc, in) -> 
-        {
-            if(sc.ifState)
-            {
-                sc.currentLine += in[0].getInt(sc);
-            }
-            sc.ifState = true;
-            return Void.TYPE;
-        });  
-        registerFunction("while", (sc, in) -> 
-        {
-            if(!in[0].getBoolean(sc))
-            {
-                sc.currentLine += in[1].getInt(sc);
-            }
-            return Void.TYPE;
-        });
-        registerFunction("wend", (sc, in) -> 
-        {
-            sc.currentLine += in[0].getInt(sc);
-            return Void.TYPE;
-        });
-        registerFunction("for", (sc, in) -> 
-        {
-            // for(var, start, end, step)
-            double start = in[1].getDouble(sc);
-            in[0].set(sc, start);           
-            if(start > in[2].getDouble(sc))
-            {
-                sc.currentLine += in[4].getInt(sc);
-            }
-            return Void.TYPE;
-        });
-        registerFunction("next", (sc, in) -> 
-        {
-            int line = sc.currentLine + in[0].getInt(sc);
-            InputProvider[] f = sc.code[line].getArguments();
-            // for(var, start, end, step)
-            double current = f[0].getDouble(sc) + f[3].getDouble(sc);
-            f[0].set(sc, current);
-            if(current <= f[2].getDouble(sc))
-            {
-                sc.currentLine = line;
-            }
-            return Void.TYPE;
-        });
-        registerFunction("continue", (sc, in) -> 
-        {
-            sc.currentLine += in[0].getInt(sc);
-            return Void.TYPE;
-        });
-        registerFunction("break", (sc, in) -> 
-        {
-            sc.currentLine += in[0].getInt(sc);
+            sc.goSub(in[0].getString(sc));
             return Void.TYPE;
         });
         
@@ -910,7 +749,7 @@ public class FunctionLoader
         });
         registerFunction("print", (sc, in) -> 
         {
-            sc.logger.print(SnuviUtils.connect(sc, in, 0), null, "print", sc.name, sc, sc.getActiveRealLine());
+            sc.getScriptManager().getLogger().print(SnuviUtils.connect(sc, in, 0), null, "print", sc.getName(), sc, sc.getActiveSourceLine());
             return Void.TYPE;
         });
         registerFunction("waitfor", (sc, in) ->    
@@ -920,27 +759,26 @@ public class FunctionLoader
             {
                 throw new IllegalArgumentException("time units can't be negative");
             }
-            sc.isHolded = true;
-            sc.scheduler.scheduleTask(() -> 
+            sc.setHolded(true);
+            sc.setWaiting();
+            sc.getScriptManager().getScheduler().scheduleTask(() -> 
             {           
-                // activate this again on NullPointerException
-                // if(sc == null || !sc.isValid)
-                if(sc.isValid)
+                if(!sc.shouldTerm())
                 {
-                    sc.isHolded = false;
+                    sc.setHolded(false);
                     sc.run();
-                    if(!sc.isValid)
+                    if(sc.shouldTerm())
                     {
-                        sc.parser.termUnsafe(sc);
+                        sc.getScriptManager().removeScriptSafe(sc);
                     }
                 }
             }, l); 
-            sc.isWaiting = true;
             return Void.TYPE;
         });
         registerFunction("term", (sc, in) -> 
         {
-            sc.parser.termSafe(sc);
+            sc.term();
+            sc.getScriptManager().removeScriptSafe(sc);
             return Void.TYPE;
         });
                

+ 9 - 0
src/me/hammerle/snuviscript/code/ISnuviLogger.java

@@ -13,4 +13,13 @@ public interface ISnuviLogger
      * @param line an involved script line, -1 if no line is involved
      */
     public void print(String message, Exception ex, String function, String scriptname, Script sc, int line);
+    
+    /** Prints messages depending on the implementation.
+     *
+     * @param message a message, can be null
+     */
+    public default void print(String message)
+    {
+        print(message, null, null, null, null, -1);
+    }
 }

+ 5 - 1
src/me/hammerle/snuviscript/code/ISnuviScheduler.java

@@ -2,6 +2,10 @@ package me.hammerle.snuviscript.code;
 
 public interface ISnuviScheduler 
 {
-    public int scheduleTask(Runnable r);  
+    public default int scheduleTask(Runnable r)
+    {
+        return scheduleTask(r, 0);
+    }
+    
     public int scheduleTask(Runnable r, long delay);
 }

+ 26 - 0
src/me/hammerle/snuviscript/code/InputProviderArrayPool.java

@@ -0,0 +1,26 @@
+package me.hammerle.snuviscript.code;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+
+public class InputProviderArrayPool
+{
+    private final static int POOL_SIZE = 10;
+    private final static InputProvider[][] IN = new InputProvider[POOL_SIZE][];
+    
+    static
+    {
+        for(int i = 0; i < IN.length; i++)
+        {
+            IN[i] = new InputProvider[i];
+        }
+    }
+    
+    public static InputProvider[] get(int length)
+    {
+        if(length < 0 || length >= POOL_SIZE)
+        {
+            return new InputProvider[length];
+        }
+        return IN[length];
+    }
+}

+ 0 - 61
src/me/hammerle/snuviscript/code/Instruction.java

@@ -1,61 +0,0 @@
-package me.hammerle.snuviscript.code;
-
-public class Instruction
-{
-    private final int realLine;
-    private final byte layer;   
-    private final InputProvider input;
-    
-    public Instruction(int realLine, byte layer, InputProvider input)
-    {
-        this.realLine = realLine;
-        this.layer = layer;
-        this.input = input;
-    }
-
-    public int getLayer() 
-    {
-        return layer;
-    }
-    
-    public int getRealLine() 
-    {
-        return realLine;
-    }
-    
-    public InputProvider[] getArguments()
-    {
-        if(input instanceof Function)
-        {
-            return ((Function) input).getArguments();
-        }
-        return null; 
-    }
-    
-    @Override
-    public String toString() 
-    {
-        StringBuilder sb = new StringBuilder();
-        sb.append(realLine);
-        
-        for(int j = sb.length(); j < 10; j++)
-        {
-            sb.insert(0, "0");
-        }
-        
-        sb.append(" | ");
-        
-        for(int j = 0; j < layer; j++)
-        {
-            sb.append("    ");
-        }
-        
-        sb.append(input);
-        return sb.toString();
-    }
-    
-    public void execute(Script sc) throws Exception
-    {
-        input.get(sc);
-    }
-}

+ 0 - 28
src/me/hammerle/snuviscript/code/JumpData.java

@@ -1,28 +0,0 @@
-package me.hammerle.snuviscript.code;
-
-public class JumpData extends InputProvider
-{
-    private int jump;
-    
-    public JumpData(int jump)
-    {
-        this.jump = jump;
-    }
-
-    @Override
-    public int getInt(Script sc) 
-    {
-        return jump;
-    }
-
-    public void setRelativeJump(int jump) 
-    {
-        this.jump = jump - this.jump - 1;
-    }
-
-    @Override
-    public String toString() 
-    {
-        return "jump_" + jump;
-    }
-}

+ 6 - 7
src/me/hammerle/snuviscript/code/BasicFunction.java → src/me/hammerle/snuviscript/code/NamedFunction.java

@@ -1,11 +1,13 @@
 package me.hammerle.snuviscript.code;
 
-public final class BasicFunction 
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+
+public final class NamedFunction 
 {
     private final String name;
     private final ExceptionBiFunction<Script, InputProvider[], Object> f;
     
-    public BasicFunction(String name, ExceptionBiFunction<Script, InputProvider[], Object> f)
+    public NamedFunction(String name, ExceptionBiFunction<Script, InputProvider[], Object> f)
     {
         this.name = name;
         this.f = f;
@@ -18,9 +20,6 @@ public final class BasicFunction
     
     public Object execute(Script sc, InputProvider[] input) throws Exception
     {
-        sc.currentCommand = name;
-        Object o = f.apply(sc, input);
-        sc.currentCommand = name;
-        return o;
-    }
+        return f.apply(sc, input);
+    } 
 }

+ 298 - 166
src/me/hammerle/snuviscript/code/Script.java

@@ -1,64 +1,92 @@
 package me.hammerle.snuviscript.code;
 
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Stack;
 import java.util.function.Consumer;
-import me.hammerle.snuviscript.variable.LocalVariable;
-import me.hammerle.snuviscript.variable.Variable;
+import me.hammerle.snuviscript.exceptions.PreScriptException;
+import me.hammerle.snuviscript.inputprovider.ReturnWrapper;
+import me.hammerle.snuviscript.tokenizer.Tokenizer;
+import me.hammerle.snuviscript.inputprovider.Variable;
+import me.hammerle.snuviscript.instructions.Instruction;
+import me.hammerle.snuviscript.instructions.UserFunction;
 
 public final class Script 
 {
-    protected final String simpleName;
-    protected final String name;
-    protected final int id;
+    private static int idCounter = 0;
     
-    protected SnuviParser parser;
-    protected ISnuviLogger logger;
-    protected ISnuviScheduler scheduler;
+    private final int id;
+    private final String name;
+    private final ScriptManager sm;
     
-    protected int currentLine;
-    protected Instruction[] code;
-    // waiting scripts stop executing and run again on an event
-    protected boolean isWaiting;
-    // holded scripts do not receive events
-    protected boolean isHolded;
-    // not valid means the script is waiting for its termination
-    protected boolean isValid;
-    // states if event broadcasts should be received, otherwise only direct event calls work
-    protected boolean receiveEventBroadcast;
-    // stores the used cpuTime, schedules the script if too high
-    protected long cpuTime;
+    private int lineIndex = 0;
+    private final Instruction[] code;
+    private final Stack<InputProvider> dataStack = new Stack<>();
+    private final Stack<Integer> returnStack = new Stack<>();
     
-    protected int catchLine;
-    protected String currentCommand;
-    protected boolean ifState;
+    private final HashMap<String, Integer> labels = new HashMap<>();
+    private final HashMap<String, HashMap<String, Integer>> localLabels = new HashMap<>();
+    private final HashMap<String, Variable> vars = new HashMap<>();
+    private final Stack<HashMap<String, Variable>> localVars = new Stack<>();   
+    private final HashMap<String, Integer> functions = new HashMap<>();
     
-    private final HashMap<String, Integer> labels;
-    protected final Stack<Integer> returnStack;
-    protected HashMap<String, Variable> vars;
-    protected final HashSet<String> events;
+    private boolean ifState = true;
+    private Stack<Integer> stackElements = new Stack<>();
+    private int errorLine = -1;
+    private Stack<String> inFunction = new Stack<>();
+    private Stack<Boolean> returnVarPop = new Stack<>();
     
-    // local function stuff
-    protected final Stack<HashMap<String, Variable>> localVars;
-    protected final HashMap<String, Integer> functions;
-    protected final HashMap<String, HashMap<String, Integer>> localLabels;
-    protected String currentFunction = null;
+    // states if event broadcasts should be received, otherwise only direct event calls work
+    private boolean eventBroadcast;
+    // waiting scripts stop executing and run again on an event
+    private boolean isWaiting;
+    // holded scripts do not receive events
+    private boolean isHolded;
+    private boolean stackTrace;
     
-    protected Object returnValue;
-    protected boolean printStackTrace;
+    private HashSet<String> loadedEvents = new HashSet<>();
     
     private final Consumer<Script> onStart;
     private final Consumer<Script> onTerm;
     
-    private final List<AutoCloseable> closeables = new ArrayList<>();
+    private final ArrayList<AutoCloseable> closeables = new ArrayList<>();
     
-    public Script(SnuviParser parser, List<String> code, String simpleName, String name,  int id, 
-            Consumer<Script> onStart, Consumer<Script> onTerm, boolean receiveEventBroadcast)
+    public Script(ScriptManager sm, Consumer<Script> onStart, Consumer<Script> onTerm, String name, String... path)
     {
-        this.parser = parser;
+        this.id = idCounter++;
+        this.name = name;
+        this.sm = sm;
+        this.onStart = onStart;
+        this.onTerm = onTerm;
+        Tokenizer t = new Tokenizer();
+        InputStream[] streams = new InputStream[path.length];
+        for(int i = 0; i < streams.length; i++)
+        {
+            try
+            {
+                streams[i] = new FileInputStream(path[i]);
+            }
+            catch(FileNotFoundException ex)
+            {
+                throw new PreScriptException(ex.getMessage(), -1);
+            }
+        }
+        Compiler c = new Compiler();
+        this.code = c.compile(t.tokenize(streams), labels, vars, functions, localLabels);
+        
+        /*int i = 0;
+        for(Instruction in : code)
+        {
+            System.out.printf("%3d: %5b | %s\n", i, in.shouldNotReturnValue(), in);
+            i++;
+        }*/
+        
+        /*this.parser = parser;
         this.logger = parser.getLogger();
         this.scheduler = parser.getScheduler();
         this.labels = new HashMap<>();
@@ -84,209 +112,244 @@ public final class Script
         this.functions = new HashMap<>();
         this.localLabels = new HashMap<>();
         
-        this.code = Compiler.compile(this, code, labels, functions, localLabels);
+        this.code = OldCompiler.compile(this, code, labels, functions, localLabels);*/
     }
     
-    public HashMap<String, Variable> getLocalVars()
+    private void pushIfNotNull(InputProvider in)
     {
-        return localVars.peek();
+        if(in != null)
+        {
+            dataStack.push(in);
+        }
     }
     
-    // -------------------------------------------------------------------------
-    // flow handling
-    // -------------------------------------------------------------------------
-    
-    public Object run()
+    public void run()
     {
-        if(isHolded)
-        {
-            return returnValue;
-        }
-        int length = code.length;
-        returnValue = null;
         isWaiting = false;
-        cpuTime = 0;
-        long time;
-        while(currentLine < length && !isWaiting)
-        {
-            time = System.nanoTime();
+        //System.out.println("_________________________");
+        long endTime = System.nanoTime() + 15_000_000;
+        int count = 0;
+        while(lineIndex < code.length && !isWaiting && !isHolded)
+        {  
             try
             {
-                //System.out.println("EXECUTE: " + code[currentLine]);
-                //System.out.println("LINE 1: " + currentLine);
-                code[currentLine].execute(this);
-                //System.out.println("LINE 2: " + currentLine);
-                currentLine++;
+                Instruction instr = code[lineIndex];
+                //System.out.println("EXECUTE: " + instr + " " + dataStack);
+                if(instr.getArguments() > 0)
+                {
+                    InputProvider[] args = InputProviderArrayPool.get(instr.getArguments());
+                    for(int i = args.length - 1; i >= 0; i--)
+                    {
+                        args[i] = dataStack.pop();
+                    }
+                    pushIfNotNull(instr.execute(this, args));
+                }
+                else
+                {
+                    pushIfNotNull(instr.execute(this, new InputProvider[0]));
+                }
+                //System.out.println("AFTER EXECUTE: " + dataStack);
+                lineIndex++;
             }
             catch(Exception ex)
             {
-                if(printStackTrace)
+                if(stackTrace)
                 {
                     ex.printStackTrace();
                 }
-                if(catchLine != -1)
+                if(errorLine != -1)
                 {
-                    currentLine = catchLine + 1; // + 1 because currentLine++ isn't happening
-                    catchLine = -1;
-                    setVar("error", ex.getClass().getSimpleName());
+                    int elements = stackElements.pop();
+                    while(dataStack.size() > elements)
+                    {
+                        dataStack.pop();
+                    }
+                    
+                    lineIndex = errorLine + 1;
+                    errorLine = -1;
                     continue;
                 }
-                int line = (currentLine < length) ? code[currentLine].getRealLine() + 1 : -1;
-                logger.print(ex.getLocalizedMessage(), ex, currentCommand, name, this, line);
-                //ex.printStackTrace();
-                return returnValue;
+                sm.getLogger().print(ex.getLocalizedMessage(), ex, 
+                        code[lineIndex].getName(), name, this, code[lineIndex].getLine());
+                break;
             }
-            time = System.nanoTime() - time;
-            cpuTime += time;
-            if(cpuTime > 15_000_000)
+            
+            count++;
+            if(System.nanoTime() > endTime)
             {
-                isWaiting = true;
                 isHolded = true;
-                scheduler.scheduleTask(() -> 
+                sm.getScheduler().scheduleTask(() -> 
                 {           
-                    if(isValid)
+                    if(!shouldTerm())
                     {
                         isHolded = false;
                         run();
                     }
                 }, 1);
-                return Void.TYPE;
+                break;
             }
         }
-        if(currentLine >= length && !isWaiting && localVars.empty())
+        //System.out.println(count + " " + (15_000_000 / count));
+        if(shouldTerm() && !dataStack.isEmpty())
         {
-            parser.termSafe(this);
+            sm.getLogger().print(String.format("data stack is not empty %s", dataStack));
         }
-        return returnValue;
+    }
+
+    public String getName() 
+    {
+        return name;
+    }
+
+    public int getId() 
+    {
+        return id;
     }
     
-    public void end()
+    public int getActiveSourceLine()
     {
-        currentLine = code.length;
+        if(lineIndex >= 0 && lineIndex < code.length)
+        {
+            return code[lineIndex].getLine();
+        }
+        return -1;
     }
     
-    public int getActiveRealLine()
+    public ScriptManager getScriptManager()
     {
-        return code[currentLine].getRealLine();
+        return sm;
     }
     
-    // -------------------------------------------------------------------------
-    // general stuff
-    // -------------------------------------------------------------------------
-
-    public String getSimpleName() 
+    private HashMap<String, Integer> getLabels()
     {
-        return simpleName;
+        return inFunction.isEmpty() ? labels : localLabels.get(inFunction.peek());
     }
-
-    public String getName() 
+    
+    public void gotoLabel(String label, boolean error, int add)
     {
-        return name;
+        lineIndex = getLabels().getOrDefault(label, error ? null : lineIndex) + add;
     }
     
-    public int getId() 
+    public void gotoLabel(String label, boolean error)
     {
-        return id;
+        gotoLabel(label, error, 0);
     }
-
-    public ISnuviLogger getLogger()
+    
+    public void goSub(String label)
     {
-        return logger;
+        int line = getLabels().get(label);
+        returnStack.push(lineIndex);
+        lineIndex = line;
+        returnVarPop.push(false);
     }
     
-    public boolean isStackTracePrinted()
+    public void jumpTo(int jump)
     {
-        return printStackTrace;
+        lineIndex = jump;
     }
     
-    public Variable getVar(String name)
+    public void setIfState(boolean state)
     {
-        HashMap<String, Variable> map;
-        if(!localVars.isEmpty())
-        {
-            map = localVars.peek();
-            Variable var = map.get(name);
-            if(var == null)
-            {
-                var = new LocalVariable(name);
-                map.put(name, var);
-            }
-            return var;
-        }
-        else
+        ifState = state;
+    }
+    
+    public boolean getIfState()
+    {
+        return ifState;
+    }
+    
+    public void setErrorLine(int line)
+    {
+        errorLine = line;
+        if(line != -1)
         {
-            map = vars;
-            Variable var = map.get(name);
-            if(var == null)
-            {
-                var = new Variable(name);
-                map.put(name, var);
-            }
-            return var;
+            stackElements.push(dataStack.size());
         }
     }
     
-    public void setVar(String name, Object value)
+    public void handleFunction(String function, InputProvider[] in) throws Exception
     {
-        HashMap<String, Variable> map;
-        if(!localVars.isEmpty())
+        Integer sub = functions.get(function);
+        if(sub == null)
         {
-            map = localVars.peek();
-            Variable var = map.get(name);
-            if(var == null)
-            {
-                var = new LocalVariable(name);
-                map.put(name, var);
-            }
-            var.set(this, value);
+            throw new IllegalArgumentException(String.format("function '%s' does not exist", function));
+        }
+        UserFunction uf = (UserFunction) code[sub];
+        String[] args = uf.getArgumentNames();
+        
+        HashMap<String, Variable> lvars = new HashMap<>();
+        if(in.length != args.length)
+        {
+            throw new IllegalArgumentException(String.format("invalid number of arguments at function '%s'", function));
         }
-        else
+        
+        for(int i = 0; i < in.length; i++)
         {
-            map = vars;
-            Variable var = map.get(name);
-            if(var == null)
-            {
-                var = new Variable(name);
-                map.put(name, var);
-            }
-            var.set(this, value);
+            Variable v = new Variable(args[i]);
+            v.set(this, in[i].get(this));
+            lvars.put(args[i], v);
         }
+        
+        localVars.push(lvars);
+        returnStack.push(lineIndex);
+        lineIndex = sub;
+        inFunction.push(function);
+        returnVarPop.push(true);
     }
     
-    protected Integer getLabel(String name)
+    public void handleReturn(ReturnWrapper wrapper)
     {
-        if(localVars.isEmpty())
+        if(returnVarPop.pop())
         {
-            return labels.get(name);
+            inFunction.pop();
+            localVars.pop();
+            if(wrapper != null)
+            {
+                dataStack.add(wrapper);
+            }
         }
-        else
+        lineIndex = returnStack.pop();
+    }
+    
+    public Variable getOrAddLocalVariable(String name)
+    {
+        HashMap<String, Variable> map = localVars.peek();
+        Variable v = map.get(name);
+        if(v != null)
         {
-            return localLabels.get(currentFunction).get(name);
+            return v;
         }
+        v = new Variable(name);
+        map.put(name, v);
+        return v;
     }
-
-    // -------------------------------------------------------------------------
-    // event handling
-    // -------------------------------------------------------------------------
     
-    public boolean isEventLoaded(String s)
+    public InputProvider peekDataStack()
     {
-        return events.contains(s);
+        return dataStack.peek();
     }
     
-    // -------------------------------------------------------------------------
-    // onStart onTerm
-    // -------------------------------------------------------------------------
+    public void setEventBroadcast(boolean eventBroadcast)
+    {
+        this.eventBroadcast = eventBroadcast;
+    }
     
-    public void onStart()
+    public boolean shouldReceiveEventBroadcast()
     {
-        if(onStart != null)
-        {
-            onStart.accept(this);
-        }
+        return eventBroadcast;
     }
     
-    public synchronized void onTerm()
+    public void term()
+    {
+        lineIndex = code.length;
+    }
+    
+    public boolean shouldTerm()
+    {
+        return lineIndex < 0 || lineIndex >= code.length;
+    }
+    
+    public void onTerm()
     {
         if(onTerm != null)
         {
@@ -294,18 +357,75 @@ public final class Script
         }
         closeables.forEach(c -> 
         {
-            logger.print("prepared statement not closed", null, null, name, this, -1);
+            sm.getLogger().print("prepared statement not closed", null, null, name, this, -1);
             try
             {
                 c.close();
             }
             catch(Exception ex)
             {
-                logger.print("cannot close closeable in script", ex, null, name, this, -1);
+                sm.getLogger().print("cannot close closeable in script", ex, null, name, this, -1);
             }
         });
     }
     
+    public void onStart()
+    {
+        if(onStart != null)
+        {
+            onStart.accept(this);
+        }
+    }
+    
+    public void setHolded(boolean b)
+    {
+        isHolded = b;
+    }
+    
+    public boolean isHolded()
+    {
+        return isHolded;
+    }
+    
+    public void setWaiting()
+    {
+        isWaiting = true;
+    }
+    
+    public void setVar(String name, Object value)
+    {
+        Variable v = vars.get(name);
+        if(v != null)
+        {
+            v.set(this, value);
+        }
+    }
+    
+    public Variable getVar(String name)
+    {
+        return vars.get(name);
+    }
+    
+    public boolean isEventLoaded(String event)
+    {
+        return loadedEvents.contains(event);
+    }
+    
+    public boolean loadEvent(String event)
+    {
+        return loadedEvents.add(event);
+    }
+    
+    public boolean unloadEvent(String event)
+    {
+        return loadedEvents.remove(event);
+    }
+    
+    public void setStackTrace(boolean b)
+    {
+        stackTrace = b;
+    }
+    
     public synchronized void addCloseable(AutoCloseable closeable)
     {
         closeables.add(closeable);
@@ -315,4 +435,16 @@ public final class Script
     {
         closeables.remove(closeable);
     }
+
+    @Override
+    public int hashCode()
+    {
+        return id;
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        return o != null && o instanceof Script && ((Script) o).id == id;
+    }
 }

+ 263 - 0
src/me/hammerle/snuviscript/code/ScriptManager.java

@@ -0,0 +1,263 @@
+package me.hammerle.snuviscript.code;
+
+import java.util.ArrayList;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.function.Consumer;
+import me.hammerle.snuviscript.exceptions.PreScriptException;
+
+public class ScriptManager 
+{
+    private final ISnuviLogger logger;
+    private final ISnuviScheduler scheduler;
+    
+    private final HashMap<Integer, Script> scripts = new HashMap<>();
+    private final HashMap<String, HashSet<Script>> loadedEvents = new HashMap<>();
+    
+    private boolean isIterating = false;
+    private final ArrayList<Script> addList = new ArrayList<>();
+    private final ArrayList<Script> removeList = new ArrayList<>();
+    private final ArrayList<Runnable> eventAddList = new ArrayList<>();
+    
+    public ScriptManager(ISnuviLogger logger, ISnuviScheduler scheduler)
+    {
+        this.logger = logger;
+        this.scheduler = scheduler;
+    }
+
+    public ISnuviLogger getLogger() 
+    {
+        return logger;
+    }
+
+    public ISnuviScheduler getScheduler() 
+    {
+        return scheduler;
+    }
+    
+    // -------------------------------------------------------------------------
+    // function registry
+    // -------------------------------------------------------------------------
+
+    public void registerFunction(String s, ExceptionBiFunction<Script, InputProvider[], Object> f)
+    {
+        FunctionRegistry.registerFunction(s, f);
+    }
+    
+    public void registerAlias(String original, String alias)
+    {
+        FunctionRegistry.registerAlias(original, alias);
+    }
+    
+    // -------------------------------------------------------------------------
+    // script controller
+    // -------------------------------------------------------------------------
+    
+    public Script getScript(int id)
+    {
+        return scripts.get(id);
+    }
+    
+    private void removeScriptUnsafe(Script sc)
+    {
+        sc.onTerm();
+        scripts.remove(sc.getId());
+        loadedEvents.values().forEach(list -> list.remove(sc));
+    }
+    
+    private void addScript(Script sc)
+    {
+        scripts.put(sc.getId(), sc);
+        sc.onStart();
+        sc.run();
+        if(sc.shouldTerm())
+        {
+            removeScriptUnsafe(sc);
+        }
+    }
+    
+    private void handleQueues()
+    {
+        if(!removeList.isEmpty())
+        {
+            removeList.forEach(sc -> removeScriptUnsafe(sc));
+            removeList.clear();
+        }
+        if(!addList.isEmpty())
+        {
+            addList.forEach(sc -> addScript(sc));
+            addList.clear();
+        }
+        if(!eventAddList.isEmpty())
+        {
+            eventAddList.forEach(r -> r.run());
+            eventAddList.clear();
+        }
+    }
+    
+    public void removeScriptSafe(Script sc)
+    {
+        if(isIterating)
+        {
+            removeList.add(sc);
+        }
+        else
+        {
+            removeScriptUnsafe(sc);
+        }
+    }
+    
+    public boolean removeScriptsSafe()
+    {
+        if(isIterating)
+        {
+            return false;
+        }
+        scripts.values().forEach(sc -> sc.onTerm());
+        scripts.clear();
+        loadedEvents.values().forEach(list -> list.clear());
+        return true;
+    }
+    
+    public Collection<Script> getScripts()
+    {
+        return scripts.values();
+    }
+    
+    public Script startScript(boolean rEventBroadcast, Consumer<Script> onStart, Consumer<Script> onTerm, String name, String... paths)
+    { 
+        if(paths.length == 0)
+        {
+            return null;
+        }
+        try
+        {            
+            Script sc = new Script(this, onStart, onTerm, name, paths);
+            sc.setEventBroadcast(rEventBroadcast);
+            if(isIterating)
+            {
+                addList.add(sc);
+            }
+            else
+            {
+                addScript(sc);
+            }
+            return sc;
+        }
+        catch(PreScriptException ex)
+        {
+            logger.print(ex.getLocalizedMessage(), ex, null, paths[0], null, ex.getLine());
+            return null;
+        }
+    }
+    
+    public Script startScript(boolean rEventBroadcast, String name, String... paths)
+    { 
+        return startScript(rEventBroadcast, null, null, name, paths);
+    }
+    
+    // -------------------------------------------------------------------------
+    // event
+    // -------------------------------------------------------------------------
+    
+    private void loadEventUnsafe(String event, Script sc)
+    {
+        HashSet<Script> set = loadedEvents.get(event);
+        if(set == null)
+        {
+            set = new HashSet<>();
+            loadedEvents.put(event, set);
+        }
+        set.add(sc);
+    }
+    
+    private void unloadEventUnsafe(String event, Script sc)
+    {
+        HashSet<Script> set = loadedEvents.get(event);
+        if(set != null)
+        {
+            set.remove(sc);
+        }
+    }
+    
+    public void loadEventSafe(String event, Script sc)
+    {
+        if(isIterating)
+        {
+            eventAddList.add(() -> loadEventUnsafe(event, sc));
+        }
+        else
+        {
+            loadEventUnsafe(event, sc);
+        }
+    }
+    
+    public void unloadEventSafe(String event, Script sc)
+    {
+        if(isIterating)
+        {
+            eventAddList.add(() -> unloadEventUnsafe(event, sc));
+        }
+        else
+        {
+            unloadEventUnsafe(event, sc);
+        }
+    }
+    
+    public void callEvent(String name, Consumer<Script> before, Consumer<Script> after)
+    {
+        if(isIterating)
+        {
+            logger.print(String.format("'%s' called while executing another event", name), null, null, null, null, -1);
+            return;
+        }
+        HashSet<Script> set = loadedEvents.get(name);
+        if(set == null)
+        {
+            return;
+        }
+        
+        isIterating = true;
+        set.stream().filter(sc -> sc.shouldReceiveEventBroadcast() && !sc.isHolded())
+                .forEach(sc -> 
+                {
+                    sc.setVar("event", name);
+                    if(before != null)
+                    {
+                        before.accept(sc);
+                    }
+                    sc.run();
+                    if(after != null)
+                    {
+                        after.accept(sc);
+                    }
+                });
+        isIterating = false;
+        handleQueues();
+    }
+    
+    public boolean callEvent(String name, Script sc, Consumer<Script> before, Consumer<Script> after)
+    {
+        if(sc.isEventLoaded(name) && !sc.isHolded())
+        {
+            sc.setVar("event", name);
+            if(before != null)
+            {
+                before.accept(sc);
+            }
+            sc.run();
+            if(after != null)
+            {
+                after.accept(sc);
+            }
+            if(sc.shouldTerm())
+            {
+                removeScriptUnsafe(sc);
+            }
+            return true;
+        }
+        return false;
+    }
+}

+ 0 - 35
src/me/hammerle/snuviscript/code/SignInverter.java

@@ -1,35 +0,0 @@
-package me.hammerle.snuviscript.code;
-
-public class SignInverter extends InputProvider
-{
-    private final InputProvider input;
-    
-    public SignInverter(InputProvider input)
-    {
-        this.input = input;
-    }
-    
-    @Override
-    public Object get(Script sc) throws Exception
-    {
-        return -input.getDouble(sc);
-    }
-    
-    @Override
-    public double getDouble(Script sc) throws Exception
-    {
-        return -input.getDouble(sc);
-    }
-    
-    @Override
-    public String getString(Script sc) throws Exception
-    {
-        return String.valueOf(get(sc));
-    }
-    
-    @Override
-    public String toString() 
-    {
-        return "-(" + input + ")";
-    }
-}

+ 0 - 206
src/me/hammerle/snuviscript/code/SnuviParser.java

@@ -1,206 +0,0 @@
-package me.hammerle.snuviscript.code;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
-import me.hammerle.snuviscript.exceptions.PreScriptException;
-
-public class SnuviParser 
-{
-    private final ISnuviLogger logger;
-    private final ISnuviScheduler scheduler;
-    
-    private int idCounter;
-    private final HashMap<Integer, Script> scripts;
-    private final LinkedList<Integer> termQueue;
-    
-    public SnuviParser(ISnuviLogger logger, ISnuviScheduler scheduler)
-    {
-        this.logger = logger;
-        this.scheduler = scheduler;
-        
-        scripts = new HashMap<>();
-        termQueue = new LinkedList<>();
-        idCounter = 0;
-    }
-
-    public ISnuviLogger getLogger() 
-    {
-        return logger;
-    }
-
-    public ISnuviScheduler getScheduler() 
-    {
-        return scheduler;
-    }
-    
-    // -----------------------------------------------------------------------------------
-    // function registry
-    // -----------------------------------------------------------------------------------
-
-    public void registerFunction(String s, ExceptionBiFunction<Script, InputProvider[], Object> f)
-    {
-        FunctionLoader.registerFunction(s, f);
-    }
-    
-    public void registerAlias(String original, String alias)
-    {
-        FunctionLoader.registerAlias(original, alias);
-    }
-    
-    // -----------------------------------------------------------------------------------
-    // script controller
-    // -----------------------------------------------------------------------------------
-    
-    public Script getScript(int id)
-    {
-        return scripts.get(id);
-    }
-    
-    public boolean termUnsafe(Script sc)
-    {
-        if(sc == null)
-        {
-            return false;
-        }
-        sc.isValid = false;
-        sc.onTerm();
-        return scripts.remove(sc.id) != null;
-    }
-    
-    public void termSafe(Script sc)
-    {
-        if(sc == null)
-        {
-            return;
-        }
-        sc.isHolded = true;
-        sc.isWaiting = true;
-        sc.isValid = false;
-        termQueue.add(sc.id);
-    }
-    
-    private void term()
-    {
-        if(!termQueue.isEmpty())
-        {
-            termQueue.forEach(i -> 
-            {
-                Script sc = scripts.remove(i);
-                if(sc != null)
-                {
-                    sc.onTerm();
-                }
-            });
-            termQueue.clear();
-        }
-    }
-    
-    public void termAllUnsafe()
-    {
-        scripts.values().forEach(sc -> 
-        {
-            sc.onTerm();
-            sc.isValid = false;
-            
-        });
-        scripts.clear();
-    }
-    
-    public Collection<Script> getScripts()
-    {
-        return scripts.values();
-    }
-    
-    public Script startScript(boolean rEventBroadcast, Consumer<Script> onStart, Consumer<Script> onTerm, String end, String... paths)
-    { 
-        if(paths.length == 0)
-        {
-            return null;
-        }
-        try
-        {            
-            List<String> code = SnuviUtils.readCode(end, paths);
-            String simpleName = paths[0].substring(paths[0].lastIndexOf('/') + 1);
-            Script sc = new Script(this, code, simpleName, paths[0], idCounter++, onStart, onTerm, rEventBroadcast);
-            scripts.put(sc.id, sc);
-            sc.onStart();
-            //long l = System.nanoTime();
-            sc.run();
-            //l = System.nanoTime() - l;
-            //System.out.println("time " + l);
-            term();
-            return sc;
-        }
-        catch(PreScriptException ex)
-        {
-            //ex.printStackTrace();
-            logger.print(ex.getLocalizedMessage(), ex, null, paths[0], null, ex.getEndLine() + 1);
-            return null;
-        }
-    }
-    
-    public Script startScript(boolean rEventBroadcast, String end, String... paths)
-    { 
-        return startScript(rEventBroadcast, null, null, end, paths);
-    }
-    
-    // -----------------------------------------------------------------------------------
-    // event
-    // -----------------------------------------------------------------------------------
-    
-    public void callEvent(String name, Consumer<Script> before, Consumer<Script> after, Predicate<Script> check)
-    {
-        scripts.values().stream()
-                .filter(sc -> sc.receiveEventBroadcast && !sc.isHolded && sc.isWaiting)
-                .filter(sc -> sc.isEventLoaded(name))
-                .filter(check)
-                .forEach(sc -> 
-                {
-                    sc.setVar("event", name);
-                    if(before != null)
-                    {
-                        before.accept(sc);
-                    }
-                    sc.run();
-                    if(after != null)
-                    {
-                        after.accept(sc);
-                    }
-                });
-        term();
-    }
-    
-    public void callEvent(String name, Consumer<Script> before, Consumer<Script> after)
-    {
-        callEvent(name, before, after, sc -> true);
-    }
-    
-    public boolean callEvent(String name, Script sc, Consumer<Script> before, Consumer<Script> after, boolean check)
-    {
-        if(sc.isEventLoaded(name) && !sc.isHolded && sc.isWaiting && check)
-        {
-            sc.setVar("event", name);
-            if(before != null)
-            {
-                before.accept(sc);
-            }
-            sc.run();
-            if(after != null)
-            {
-                after.accept(sc);
-            }
-            term();
-            return true;
-        }
-        return false;
-    }
-    
-    public boolean callEvent(String name, Script sc, Consumer<Script> before, Consumer<Script> after)
-    {
-        return callEvent(name, sc, before, after, true);
-    }
-}

+ 31 - 245
src/me/hammerle/snuviscript/code/SnuviUtils.java

@@ -1,17 +1,7 @@
 package me.hammerle.snuviscript.code;
 
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Array;
-import java.nio.charset.MalformedInputException;
-import java.nio.file.Files;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 import java.util.Random;
-import java.util.regex.Pattern;
-import me.hammerle.snuviscript.exceptions.PreScriptException;
 
 public class SnuviUtils 
 {
@@ -22,28 +12,6 @@ public class SnuviUtils
         return RANDOM.nextInt((max - min) + 1) + min;
     }
     
-    // - in the number is handled somewhere else
-    private static final Pattern NUMBER_PATTERN = Pattern.compile("^[-]{0,1}[0-9]*[.]{0,1}[0-9]*");
-    
-    public static boolean isNumber(String s)
-    {
-        return NUMBER_PATTERN.matcher(s).matches();
-    }
-    
-    private static final Pattern FUNCTION_PATTERN = Pattern.compile("^[a-zA-Z.]*\\(.*\\)");
-    
-    public static boolean isFunction(String s)
-    {
-        return FUNCTION_PATTERN.matcher(s).matches();
-    }
-    
-    private static final Pattern ARRAY_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9_]*\\[[^\\]]*\\]");
-    
-    public static boolean isArray(String s)
-    {
-        return ARRAY_PATTERN.matcher(s).matches();
-    }
-    
     public static String toString(double d)
     {
         if(d == (int) d)
@@ -53,179 +21,6 @@ public class SnuviUtils
         return String.valueOf(d);
     }
     
-    // -------------------------------------------------------------------------
-    // line splitter
-    // -------------------------------------------------------------------------
-      
-    private static void addNonEmptyString(HashMap<String, String> strings, LinkedList<String> list, String s)
-    {
-        s = s.trim();
-        if(!s.isEmpty())
-        {
-            if(s.startsWith("#"))
-            {
-                String text = strings.get(s);
-                if(text != null)
-                {
-                    list.add(text);
-                    return;
-                }
-            }
-            list.add(s);
-        }
-    }
-    
-    private static int findNextClosingBracket(int pos, StringBuilder sb, int line)
-    {
-        int brackets = 0;
-        int length = sb.length();
-        while(pos < length)
-        {
-            switch(sb.charAt(pos))
-            {
-                case ')':
-                    brackets--;
-                    if(brackets == 0)
-                    {
-                        return pos;
-                    }
-                    else if(brackets < 0)
-                    {
-                        throw new PreScriptException(") without (", line);
-                    }
-                    break;
-                case '(':
-                    brackets++;
-                    break;
-            }
-            pos++;
-        }
-        throw new PreScriptException("( without )", line);
-    }
-    
-    private static int findNextClosingSBracket(int pos, StringBuilder sb, int line)
-    {
-        int brackets = 0;
-        int length = sb.length();
-        while(pos < length)
-        {
-            switch(sb.charAt(pos))
-            {
-                case ']':
-                    brackets--;
-                    if(brackets == 0)
-                    {
-                        return pos;
-                    }
-                    else if(brackets < 0)
-                    {
-                        throw new PreScriptException("] without [", line);
-                    }
-                    break;
-                case '[':
-                    brackets++;
-                    break;
-            }
-            pos++;
-        }
-        throw new PreScriptException("[ without ]", line);
-    }
-    
-    public static String[] split(HashMap<String, String> strings, String s, int line)
-    {
-        LinkedList<String> list = new LinkedList<>();
-        
-        int old = 0;
-        int pos = 0;
-        
-        StringBuilder sb = new StringBuilder(s);
-        int length = sb.length();
-        char c;
-        while(pos < length)
-        {
-            c = sb.charAt(pos);
-            if(!Character.isLetterOrDigit(c))
-            {
-                switch(c)
-                {
-                    case '_':
-                    case '.':
-                    case '#':
-                    case '$':
-                    case '@':
-                        break;
-                    case ')':
-                        throw new PreScriptException(") without (", line);
-                    case '(':   
-                        pos = findNextClosingBracket(pos, sb, line) + 1;
-                        addNonEmptyString(strings, list, sb.substring(old, pos));
-                        old = pos;
-                        continue;
-                    case ']':
-                        throw new PreScriptException("] without [", line);
-                    case '[':   
-                        pos = findNextClosingSBracket(pos, sb, line) + 1;
-                        addNonEmptyString(strings, list, sb.substring(old, pos));
-                        old = pos;
-                        continue;
-                    case '\t':
-                    case ' ':
-                        addNonEmptyString(strings, list, sb.substring(old, pos));
-                        old = pos + 1;
-                        pos = old;
-                        continue;
-                    case ',':   
-                        addNonEmptyString(strings, list, sb.substring(old, pos));
-                        addNonEmptyString(strings, list, ",");
-                        old = pos + 1;
-                        pos = old;
-                        continue;
-                    default:
-                        addNonEmptyString(strings, list, sb.substring(old, pos));
-                        //System.out.println(old + " " + pos);
-                        old = pos;
-                        pos++;
-                        while(pos <= length && Syntax.getSyntax(sb.substring(old, pos)) != Syntax.UNKNOWN)
-                        {
-                            pos++;
-                        }
-                        pos--;
-                        if(old == pos)
-                        {
-                            throw new PreScriptException("unknown syntax '" + c + "'", line);
-                        }
-                        addNonEmptyString(strings, list, sb.substring(old, pos));
-                        old = pos;
-                        continue;
-                }
-            }
-            pos++;
-        }
-        if(old < length)
-        {
-            addNonEmptyString(strings, list, sb.substring(old));
-        }
-        
-        return list.toArray(new String[list.size()]);
-    }
-    
-    public static String getArrayString(Object array)
-    {
-        StringBuilder sb = new StringBuilder("[");
-        int length = Array.getLength(array) - 1;
-        for(int i = 0; i < length; i++)
-        {
-            sb.append(Array.get(array, i));
-            sb.append(", ");
-        }
-        if(length > 0)
-        {
-            sb.append(Array.get(array, length));
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-    
     // -------------------------------------------------------------------------
     // connectors
     // -------------------------------------------------------------------------
@@ -255,49 +50,40 @@ public class SnuviUtils
         return sb.toString();
     }
     
-    // -------------------------------------------------------------------------
-    // file stuff
-    // -------------------------------------------------------------------------
-    
-    public static List<String> readCode(String ending, String... filenames)
+    public static Object convert(String input)
     {
-        LinkedList<List<String>> lists = new LinkedList<>();
-        List<String> list;
-        File script;
-        int lines = 0;
-        for(String filename : filenames)
+        if(input == null)
         {
-            script = new File("./" + filename + ending);
-            if(script.exists())
-            {
-                try
-                {
-                    list = Files.readAllLines(script.toPath());
-                    lines += list.size();
-                    lists.add(list);
-                } 
-                catch (MalformedInputException ex) 
-                {
-                    throw new PreScriptException("'" + script.getPath() + "' contains an illegal character, change file encoding", 0);
-                }
-                catch (IOException ex) 
-                {
-                    throw new PreScriptException("file '" + script.getPath() + "' cannot be read", 0);
-                }
-            }
-            else
+            return null;
+        }
+        input = input.trim();
+        if(input.equals("true"))
+        {
+            return true;
+        }
+        else if(input.equals("false"))
+        {
+            return false;
+        }
+        else if(input.equals("null"))
+        {
+            return null;
+        }
+        else if(input.startsWith("\"") && input.endsWith("\""))
+        {
+            if(input.length() == 1)
             {
-                throw new PreScriptException("file '" + script.getPath() + "' does not exist", 0);
+                return "\"";
             }
+            return input.substring(1, input.length() - 1);
+        }
+        try
+        {
+            return Double.parseDouble(input);
+        }
+        catch(NumberFormatException ex)
+        {
+            return input;
         }
-        
-        ArrayList<String> mergedList = new ArrayList<>(lines);
-        lists.forEach(l -> mergedList.addAll(l));
-        return mergedList;
-    }
-    
-    public static List<String> readCode(String filename)
-    {
-        return readCode(filename, ".snuvi");
     }
 }

+ 0 - 243
src/me/hammerle/snuviscript/code/Syntax.java

@@ -1,243 +0,0 @@
-package me.hammerle.snuviscript.code;
-
-public enum Syntax
-{
-    UNKNOWN(" ", 0, 0),
-    INC("++", 2, 1),
-    POST_INC("p++", 2, 1),
-    DEC("--", 2, 1),
-    POST_DEC("p--", 2, 1),
-    INVERT("!", 2, 1),
-    BIT_INVERT("~", 2, 1),
-    MUL("*", 3),
-    DIV("/", 3),
-    MOD("%", 3),
-    ADD("+", 4),
-    SUB("-", 4),
-    UNARY_SUB(" ", 0, 1),
-    LEFT_SHIFT("<<", 6),
-    RIGHT_SHIFT(">>", 6),
-    SMALLER("<", 7),
-    SMALLER_EQUAL("<=", 7),
-    GREATER(">", 7),
-    GREATER_EQUAL(">=", 7),
-    EQUAL("==", 8),
-    NOT_EQUAL("!=", 8),
-    BIT_AND("&", 9),
-    BIT_XOR("^", 10),
-    BIT_OR("|", 11),
-    AND("&&", 12),
-    OR("||", 13),
-    SET("=", 15),
-    ADD_SET("+=", 15),
-    SUB_SET("-=", 15),
-    MUL_SET("*=", 15),
-    DIV_SET("/=", 15),
-    MOD_SET("%=", 15),
-    LEFT_SHIFT_SET("<<=", 15),
-    RIGHT_SHIFT_SET(">>=", 15),
-    BIT_AND_SET("&=", 15),
-    BIT_XOR_SET("^=", 15),
-    BIT_OR_SET("|=", 15);
-
-    public static Syntax getSyntax(String s)
-    {   
-        int size = s.length();
-        if(size > 0)
-        {
-            switch(s.charAt(0))
-            {
-                case '~':
-                    if(size == 1)
-                    {
-                        return BIT_INVERT;
-                    }
-                    break;
-                case '*':
-                    if(size == 1)
-                    {
-                        return MUL;
-                    }
-                    else if(size == 2 && s.charAt(1) == '=')
-                    {
-                        return MUL_SET;
-                    }
-                    break;
-                case '/':
-                    if(size == 1)
-                    {
-                        return DIV;
-                    }
-                    else if(size == 2 && s.charAt(1) == '=')
-                    {
-                        return DIV_SET;
-                    }
-                    break;
-                case '+':
-                    if(size == 1)
-                    {
-                        return ADD;
-                    }
-                    else if(size == 2)
-                    {
-                        switch(s.charAt(1))
-                        {
-                            case '=':  return ADD_SET;
-                            case '+':  return POST_INC;
-                        }
-                    }
-                    break;
-                case '-':
-                    if(size == 1)
-                    {
-                        return SUB;
-                    }
-                    else if(size == 2)
-                    {
-                        switch(s.charAt(1))
-                        {
-                            case '=':  return SUB_SET;
-                            case '-':  return POST_DEC;
-                        }
-                    }
-                    break;
-                case '^':
-                    if(size == 1)
-                    {
-                        return BIT_XOR;
-                    }
-                    else if(size == 2 && s.charAt(1) == '=')
-                    {
-                        return BIT_XOR_SET;
-                    }
-                    break;
-                case '<':
-                    if(size == 1)
-                    {
-                        return SMALLER;
-                    }
-                    else if(size == 2)
-                    {
-                        switch(s.charAt(1))
-                        {
-                            case '<': return LEFT_SHIFT;
-                            case '=': return SMALLER_EQUAL;
-                        }
-                    }
-                    else if(size == 3 && s.charAt(1) == '<' && s.charAt(2) == '=')
-                    {
-                        return LEFT_SHIFT_SET;
-                    }
-                    break;
-                case '>':
-                    if(size == 1)
-                    {
-                        return GREATER;
-                    }
-                    else if(size == 2)
-                    {
-                        switch(s.charAt(1))
-                        {
-                            case '>': return RIGHT_SHIFT;
-                            case '=': return GREATER_EQUAL;
-                        }
-                    }
-                    else if(size == 3 && s.charAt(1) == '>' && s.charAt(2) == '=')
-                    {
-                        return RIGHT_SHIFT_SET;
-                    }
-                    break;
-                case '!':
-                    if(size == 1)
-                    {
-                        return INVERT;
-                    }
-                    else if(size == 2 && s.charAt(1) == '=')
-                    {
-                        return NOT_EQUAL;
-                    }
-                    break;
-                case '=':
-                    if(size == 1)
-                    {
-                        return SET;
-                    }
-                    else if(size == 2 && s.charAt(1) == '=')
-                    {
-                        return EQUAL;
-                    }
-                    break;
-                case '&':
-                    if(size == 1)
-                    {
-                        return BIT_AND;
-                    }
-                    else if(size == 2)
-                    {
-                        switch(s.charAt(1))
-                        {
-                            case '&': return AND;
-                            case '=': return BIT_AND_SET;
-                        }
-                    }
-                    break;
-                case '|':
-                    if(size == 1)
-                    {
-                        return BIT_OR;
-                    }
-                    else if(size == 2)
-                    {
-                        switch(s.charAt(1))
-                        {
-                            case '|': return OR;
-                            case '=': return BIT_OR_SET;
-                        }
-                    }
-                    break;
-                case '%':
-                    if(size == 1)
-                    {
-                        return MOD;
-                    }
-                    else if(size == 2 && s.charAt(1) == '=')
-                    {
-                        return MOD_SET;
-                    }
-                    break;
-            }
-        }
-        return UNKNOWN;
-    }
-    
-    private int weight;
-    private String function;
-    private byte pars;
-
-    Syntax(String function, int weight, int pars)
-    {
-        this.weight = weight;
-        this.function = function;
-        this.pars = (byte) pars;
-    }   
-    
-    Syntax(String function, int weight)
-    {
-        this(function, weight, 2);
-    }  
-
-    public String getFunction() 
-    {
-        return function;
-    }
-
-    public int getWeight() 
-    {
-        return weight;
-    }
-    
-    public byte getParameters()
-    {
-        return pars;
-    }
-}

+ 0 - 37
src/me/hammerle/snuviscript/compiler/Array.java

@@ -1,37 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-import me.hammerle.snuviscript.code.InputProvider;
-import me.hammerle.snuviscript.code.Script;
-import me.hammerle.snuviscript.variable.Variable;
-
-public class Array extends Instruction
-{
-    private final int arguments;
-    private final ReturnWrapper wrapper = new ReturnWrapper();
-    private final Variable v;
-    
-    public Array(int line, int arguments, Variable v)
-    {
-        super(line);
-        this.arguments = arguments;
-        this.v = v;
-    }
-    
-    @Override
-    public InputProvider execute(Script sc, InputProvider[] in) throws Exception
-    {
-        Object o = v.get(sc);
-        for(InputProvider ip : in)
-        {
-            o = java.lang.reflect.Array.get(o, ip.getInt(sc));
-        }
-        wrapper.setValue(o);
-        return wrapper;
-    }
-
-    @Override
-    public int getArguments()
-    {
-        return arguments;
-    }
-}

+ 0 - 10
src/me/hammerle/snuviscript/compiler/Break.java

@@ -1,10 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-public class Break extends Goto
-{
-    public Break(int line)
-    {
-        super(line, 0);
-    }
-    
-}

+ 0 - 10
src/me/hammerle/snuviscript/compiler/Catch.java

@@ -1,10 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-public class Catch extends Goto
-{
-    public Catch(int line)
-    {
-        super(line, 0);
-    }
-    
-}

+ 0 - 479
src/me/hammerle/snuviscript/compiler/Compiler.java

@@ -1,479 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import me.hammerle.snuviscript.code.FunctionLoader;
-import me.hammerle.snuviscript.code.ISnuviLogger;
-import me.hammerle.snuviscript.code.InputProvider;
-import me.hammerle.snuviscript.constants.ConstantBoolean;
-import me.hammerle.snuviscript.constants.ConstantDouble;
-import me.hammerle.snuviscript.constants.ConstantNull;
-import me.hammerle.snuviscript.constants.ConstantString;
-import me.hammerle.snuviscript.exceptions.PreScriptException;
-import me.hammerle.snuviscript.token.Token;
-import me.hammerle.snuviscript.token.TokenType;
-import static me.hammerle.snuviscript.token.TokenType.*;
-import me.hammerle.snuviscript.variable.Variable;
-
-public class Compiler
-{
-    private final ISnuviLogger logger;
-    private int index = 0;
-    private Token[] tokens = null;
-    private final ArrayList<Instruction> instr = new ArrayList<>();
-    private final HashMap<String, Integer> labels = new HashMap<>();
-    private final HashMap<String, Variable> vars = new HashMap<>();
-
-    public Compiler(ISnuviLogger logger)
-    {
-        this.logger = logger;
-    }
-    
-    private void addConstant(int line, InputProvider ip)
-    {
-        instr.add(new Constant(line, ip));
-    }
-    
-    private void addFunction(int line, int args, String name)
-    {
-        instr.add(new Function(line, args, FunctionLoader.getFunction(name)));
-    }
-    
-    private boolean match(TokenType... types)
-    {
-        for(TokenType type : types)
-        {
-            if(check(type))
-            {
-                advance();
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean check(TokenType type)
-    {
-        if(isAtEnd())
-        {
-            return false;
-        }
-        return peek().getType() == type;
-    }
-
-    private Token advance()
-    {
-        if(!isAtEnd())
-        {
-            index++;
-        }
-        return previous();
-    }
-
-    private boolean isAtEnd()
-    {
-        return peek().getType() == EOF;
-    }
-
-    private Token peek()
-    {
-        return tokens[index];
-    }
-
-    private Token previous()
-    {
-        return tokens[index - 1];
-    }
-    
-    private Token consume(TokenType type) 
-    {
-        if(check(type))
-        {
-            return advance();
-        }
-        throw new PreScriptException(String.format("exptected %s got %s", type, peek().getType()), peek().getLine());
-    }  
-
-    public Script2 compile(Token[] tokens)
-    {
-        this.tokens = tokens;
-        index = 0;
-        instr.clear();
-        labels.clear();
-        vars.clear();
-
-        while(!isAtEnd())
-        {
-            line();
-        }
-        
-        for(Instruction i : instr)
-        {
-            logger.print(i.toString(), null, null, null, null, -1);
-        }
-        
-        return null;
-    }
-    
-    private void line()
-    {
-        int oldIndex = index;
-        Token t = advance();
-        switch(t.getType())
-        {
-            case IF: handleIf(); break;
-            case LABEL: labels.put(previous().getData().toString(), instr.size()); break;
-            case SEMICOLON: break;
-            case FOR: handleFor(); break;
-            case BREAK: 
-                instr.add(new Break(previous().getLine())); 
-                consume(SEMICOLON);
-                break;
-            case CONTINUE:
-                instr.add(new Continue(previous().getLine()));
-                consume(SEMICOLON);
-                break;
-            case FUNCTION: handleUserFunction(); break;
-            case RETURN: handleReturn(); break;
-            case WHILE: handleWhile(); break;
-            case TRY: handleTry(); break;
-            default:
-                index = oldIndex;
-                expression();
-                consume(SEMICOLON);
-        }
-    }
-    
-    private void handleIf()
-    {
-        Token t = previous();
-        consume(OPEN_BRACKET);
-        expression();
-        instr.add(new If(t.getLine()));
-        consume(CLOSE_BRACKET);
-        consume(OPEN_CURVED_BRACKET);
-        while(!match(CLOSE_CURVED_BRACKET))
-        {
-            line();
-        }
-        handleElseIf();
-    }
-    
-    private void handleElseIf()
-    {
-        while(match(ELSEIF))
-        {
-            Token t = previous();
-            consume(OPEN_BRACKET);
-            expression();
-            instr.add(new Else(t.getLine()));
-            consume(CLOSE_BRACKET);
-            consume(OPEN_CURVED_BRACKET);
-            while(!match(CLOSE_CURVED_BRACKET))
-            {
-                line();
-            }
-        }
-        handleElse();
-    }
-
-    private void handleElse()
-    {
-        if(match(ELSE))
-        {
-            instr.add(new Else(previous().getLine()));
-            consume(OPEN_CURVED_BRACKET);
-            while(!match(CLOSE_CURVED_BRACKET))
-            {
-                line();
-            }
-        }
-    }
-    
-    private void handleFor()
-    {
-        Token t = previous();
-        consume(OPEN_BRACKET);    
-        if(!match(SEMICOLON))
-        {
-            expression();
-            consume(SEMICOLON);
-        }
-        if(!match(SEMICOLON))
-        {
-            expression();
-            consume(SEMICOLON);
-        }
-        if(!match(CLOSE_BRACKET))
-        {
-            expression();
-            consume(CLOSE_BRACKET);
-        }
-        instr.add(new For(t.getLine()));
-        consume(OPEN_CURVED_BRACKET);
-        while(!match(CLOSE_CURVED_BRACKET))
-        {
-            line();
-        }
-    }
-    
-    private void handleUserFunction()
-    {
-        consume(LITERAL);
-        Token t = previous();
-        consume(OPEN_BRACKET);
-        ArrayList<String> list = new ArrayList<>();
-        if(!match(CLOSE_BRACKET))
-        {
-            while(true)
-            {
-                consume(LITERAL);
-                list.add(previous().getData().toString());
-                if(match(CLOSE_BRACKET))
-                {
-                    break;
-                }
-                consume(COMMA);
-            }
-        }  
-        instr.add(new UserFunction(t.getLine(), t.getData().toString(), list.toArray(new String[list.size()])));
-        consume(OPEN_CURVED_BRACKET);
-        while(!match(CLOSE_CURVED_BRACKET))
-        {
-            line();
-        }
-    }
-    
-    private void handleReturn()
-    {
-        if(!match(SEMICOLON))
-        {
-            expression();
-            consume(SEMICOLON);
-        }
-    }
-    
-    private void handleWhile()
-    {
-        Token t = previous();
-        consume(OPEN_BRACKET);
-        expression();
-        instr.add(new While(t.getLine()));
-        consume(CLOSE_BRACKET);
-        consume(OPEN_CURVED_BRACKET);
-        while(!match(CLOSE_CURVED_BRACKET))
-        {
-            line();
-        }
-    }
-    
-    private void handleTry()
-    {
-        instr.add(new Try(previous().getLine()));
-        consume(OPEN_CURVED_BRACKET);
-        while(!match(CLOSE_CURVED_BRACKET))
-        {
-            line();
-        }
-        consume(CATCH);
-        instr.add(new Catch(previous().getLine()));
-        consume(OPEN_CURVED_BRACKET);
-        while(!match(CLOSE_CURVED_BRACKET))
-        {
-            line();
-        }
-    }
-
-    private void expression()
-    {
-        assignment();
-    }
-    
-    private void assignment()
-    {
-        logicalOr();
-        if(match(SET, ADD_SET, SUB_SET, MUL_SET, DIV_SET, MOD_SET, LEFT_SHIFT_SET, 
-                RIGHT_SHIFT_SET, BIT_AND_SET, BIT_XOR_SET, BIT_OR_SET))
-        {
-            Token t = previous();
-            assignment();
-            addFunction(t.getLine(), 2, t.getType().getName());
-        }
-    }   
-    
-    private void logicalOr()
-    {
-        logicalAnd();
-        while(match(OR))
-        {
-            Token t = previous();
-            logicalAnd();
-            addFunction(t.getLine(), 2, t.getType().getName());
-        }
-    }  
-    
-    private void logicalAnd()
-    {
-        equality();
-        while(match(AND))
-        {
-            Token t = previous();
-            equality();
-            addFunction(t.getLine(), 2, t.getType().getName());
-        }
-    }  
-
-    private void equality()
-    {
-        comparison();
-        while(match(EQUAL, NOT_EQUAL))
-        {
-            Token t = previous();
-            comparison();
-            addFunction(t.getLine(), 2, t.getType().getName());
-        }
-    }
-
-    private void comparison()
-    {
-        addition();
-        while(match(GREATER, GREATER_EQUAL, LESS, LESS_EQUAL))
-        {
-            Token t = previous();
-            addition();
-            addFunction(t.getLine(), 2, t.getType().getName());
-        }
-    }
-
-    private void addition()
-    {
-        multiplication();
-        while(match(SUB, ADD))
-        {
-            Token t = previous();
-            multiplication();
-            addFunction(t.getLine(), 2, t.getType().getName());
-        }
-    }
-
-    private void multiplication()
-    {
-        unary();
-        while(match(DIV, MUL))
-        {
-            Token t = previous();
-            unary();
-            addFunction(t.getLine(), 2, t.getType().getName());
-        }
-    }
-
-    private void unary()
-    {
-        if(match(INVERT, BIT_INVERT, SUB, INC, DEC))
-        {
-            Token t = previous();
-            unary();
-            addFunction(t.getLine(), 1, t.getType().getName());
-            return;
-        }
-        postUnary();
-    }
-    
-    private void postUnary()
-    {
-        primary();
-        while(match(INC, DEC))
-        {
-            Token t = previous();
-            addFunction(t.getLine(), 1, "p" + t.getType().getName());
-        }
-    }
-
-    private void primary()
-    {
-        Token t = advance();
-        switch(t.getType())
-        {
-            case FALSE: addConstant(t.getLine(), ConstantBoolean.FALSE); return;
-            case TRUE: addConstant(t.getLine(), ConstantBoolean.FALSE); return;
-            case NULL: addConstant(t.getLine(), ConstantNull.NULL); return;
-            case STRING: addConstant(t.getLine(), new ConstantString(t.getData().toString())); return;
-            case LABEL: addConstant(t.getLine(), new ConstantString(t.getData().toString().substring(1))); return;
-            case NUMBER: addConstant(t.getLine(), new ConstantDouble((Double) t.getData())); return;
-            case OPEN_BRACKET:
-                expression();
-                consume(CLOSE_BRACKET);
-                return;
-            case LITERAL:
-                if(match(OPEN_SQUARE_BRACKET))
-                {
-                    handleArray(t);
-                }
-                else if(match(OPEN_BRACKET))
-                {
-                    handleFunction(t);
-                }
-                else
-                {
-                    addConstant(t.getLine(), getVariable(t.getData().toString()));
-                }
-                return;
-        }
-        throw new PreScriptException(String.format("unexpected token %s", t.getType()), t.getLine());
-    }
-    
-    public void handleFunction(Token t)
-    {
-        int args = 0;
-        if(peek().getType() != CLOSE_BRACKET)
-        {
-            while(true)
-            {
-                args++;
-                expression();
-                if(match(CLOSE_BRACKET))
-                {
-                    break;
-                }
-                consume(COMMA);
-            }
-        }
-        else
-        {
-            consume(CLOSE_BRACKET);
-        }
-        addFunction(t.getLine(), args, t.getData().toString());
-    }
-    
-    public void handleArray(Token t)
-    {
-        if(peek().getType() == CLOSE_SQUARE_BRACKET)
-        {
-            throw new PreScriptException("empty array access", peek().getLine());
-        }
-        int args = 0;
-        while(true)
-        {
-            args++;
-            expression();
-            if(match(CLOSE_SQUARE_BRACKET))
-            {
-                break;
-            }
-            consume(COMMA);
-        }
-        instr.add(new Array(t.getLine(), args, getVariable(t.getData().toString())));
-    }
-    
-    private Variable getVariable(String name)
-    {
-        Variable v = vars.get(name);
-        if(v != null)
-        {
-            return v;
-        }
-        v = new Variable(name);
-        vars.put(name, v);
-        return v;
-    }
-}

+ 0 - 10
src/me/hammerle/snuviscript/compiler/Continue.java

@@ -1,10 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-public class Continue extends Goto
-{
-    public Continue(int line)
-    {
-        super(line, 0);
-    }
-    
-}

+ 0 - 10
src/me/hammerle/snuviscript/compiler/Else.java

@@ -1,10 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-public class Else extends Goto
-{
-    public Else(int line)
-    {
-        super(line, 0);
-    }
-    
-}

+ 0 - 10
src/me/hammerle/snuviscript/compiler/ElseIf.java

@@ -1,10 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-public class ElseIf extends Goto
-{
-    public ElseIf(int line)
-    {
-        super(line, 1);
-    }
-    
-}

+ 0 - 10
src/me/hammerle/snuviscript/compiler/For.java

@@ -1,10 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-public class For extends Goto
-{
-    public For(int line)
-    {
-        super(line, 2);
-    }
-    
-}

+ 0 - 31
src/me/hammerle/snuviscript/compiler/Goto.java

@@ -1,31 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-public class Goto extends Instruction
-{
-    private int jump;
-    private final int arguments;
-    
-    public Goto(int line, int arguments)
-    {
-        super(line);
-        this.arguments = arguments;
-    }
-
-    @Override
-    public int getArguments()
-    {
-        return arguments;
-    }
-    
-    @Override
-    public void setJump(int value)
-    {
-        jump = value;
-    }
-
-    @Override
-    public int getJump()
-    {
-        return jump;
-    }
-}

+ 0 - 10
src/me/hammerle/snuviscript/compiler/If.java

@@ -1,10 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-public class If extends Goto
-{
-    public If(int line)
-    {
-        super(line, 1);
-    }
-    
-}

+ 0 - 6
src/me/hammerle/snuviscript/compiler/Script2.java

@@ -1,6 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-public class Script2
-{
-    
-}

+ 0 - 10
src/me/hammerle/snuviscript/compiler/Try.java

@@ -1,10 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-public class Try extends Goto
-{
-    public Try(int line)
-    {
-        super(line, 0);
-    }
-    
-}

+ 0 - 10
src/me/hammerle/snuviscript/compiler/While.java

@@ -1,10 +0,0 @@
-package me.hammerle.snuviscript.compiler;
-
-public class While extends Goto
-{
-    public While(int line)
-    {
-        super(line, 1);
-    }
-    
-}

+ 5 - 4
src/me/hammerle/snuviscript/config/SnuviConfig.java

@@ -10,7 +10,7 @@ import java.util.TreeMap;
 import java.util.stream.Collectors;
 import me.hammerle.snuviscript.code.ISnuviLogger;
 import me.hammerle.snuviscript.code.Script;
-import me.hammerle.snuviscript.code.Compiler;
+import me.hammerle.snuviscript.code.SnuviUtils;
 
 public class SnuviConfig
 {            
@@ -39,12 +39,13 @@ public class SnuviConfig
     
     public SnuviConfig(Script sc, String path, String name)
     {    
-        this(sc, sc.getLogger(), path, name);
+        //this(sc, sc.getLogger(), path, name);
+        this(sc, null, path, name);
     }
     
     private void print(String message, Exception ex)
     {
-        logger.print(message, ex, null, sc == null ? null : sc.getName(), sc, sc == null ? -1 : sc.getActiveRealLine());
+        logger.print(message, ex, null, sc == null ? null : sc.getName(), sc, sc == null ? -1 : -1/*sc.getActiveRealLine()*/);
     }
     
     private void print(String message)
@@ -72,7 +73,7 @@ public class SnuviConfig
                 }
                 else
                 {                
-                    conf.put(s.substring(0, b).trim(), Compiler.convert(s.substring(b + 1)));
+                    conf.put(s.substring(0, b).trim(), SnuviUtils.convert(s.substring(b + 1)));
                 }
             });
         } 

+ 0 - 5
src/me/hammerle/snuviscript/exceptions/CodeTooLongException.java

@@ -1,5 +0,0 @@
-package me.hammerle.snuviscript.exceptions;
-
-public class CodeTooLongException extends RuntimeException
-{
-}

+ 5 - 17
src/me/hammerle/snuviscript/exceptions/PreScriptException.java

@@ -2,28 +2,16 @@ package me.hammerle.snuviscript.exceptions;
 
 public class PreScriptException extends RuntimeException
 {
-    private final int startLine;
-    private final int endLine;
+    private final int line;
     
-    public PreScriptException(String message, int startLine, int endLine) 
+    public PreScriptException(String message, int line) 
     {
         super(message);
-        this.endLine = endLine;
-        this.startLine = startLine;
+        this.line = line;
     }
     
-    public PreScriptException(String message, int endLine) 
+    public int getLine()
     {
-        this(message, -1, endLine);
-    }
-    
-    public int getStartLine()
-    {
-        return startLine;
-    }
-
-    public int getEndLine()
-    {
-        return endLine;
+        return line;
     }
 }

+ 51 - 0
src/me/hammerle/snuviscript/inputprovider/ArrayReturnWrapper.java

@@ -0,0 +1,51 @@
+package me.hammerle.snuviscript.inputprovider;
+
+import me.hammerle.snuviscript.code.Script;
+
+public class ArrayReturnWrapper extends InputProvider
+{
+    private Object array;
+    private int index;
+    
+    public void setValue(Object o, int index)
+    {
+        this.array = o;
+        this.index = index;
+    }
+
+    @Override
+    public Object get(Script sc) throws Exception
+    {
+        return java.lang.reflect.Array.get(array, index);
+    }
+    
+    @Override
+    public void set(Script sc, Object o) throws Exception
+    {
+        java.lang.reflect.Array.set(array, index, o);
+    }
+    
+    @Override
+    public double getDouble(Script sc) throws Exception
+    {
+        return (double) get(sc);
+    }
+    
+    @Override
+    public String getString(Script sc) throws Exception
+    {
+        return String.valueOf(get(sc));
+    }
+    
+    @Override
+    public boolean getBoolean(Script sc) throws Exception
+    {
+        return (Boolean) get(sc);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("ArrayReturnWrapper(%s, %d)", array, index);
+    }
+}

+ 2 - 2
src/me/hammerle/snuviscript/constants/ConstantBoolean.java → src/me/hammerle/snuviscript/inputprovider/ConstantBoolean.java

@@ -1,6 +1,6 @@
-package me.hammerle.snuviscript.constants;
+package me.hammerle.snuviscript.inputprovider;
 
-import me.hammerle.snuviscript.code.InputProvider;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 import me.hammerle.snuviscript.code.Script;
 
 public class ConstantBoolean extends InputProvider

+ 2 - 2
src/me/hammerle/snuviscript/constants/ConstantDouble.java → src/me/hammerle/snuviscript/inputprovider/ConstantDouble.java

@@ -1,6 +1,6 @@
-package me.hammerle.snuviscript.constants;
+package me.hammerle.snuviscript.inputprovider;
 
-import me.hammerle.snuviscript.code.InputProvider;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 import me.hammerle.snuviscript.code.Script;
 import me.hammerle.snuviscript.code.SnuviUtils;
 

+ 2 - 15
src/me/hammerle/snuviscript/constants/ConstantNull.java → src/me/hammerle/snuviscript/inputprovider/ConstantNull.java

@@ -1,8 +1,7 @@
-package me.hammerle.snuviscript.constants;
+package me.hammerle.snuviscript.inputprovider;
 
-import me.hammerle.snuviscript.code.InputProvider;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 import me.hammerle.snuviscript.code.Script;
-import me.hammerle.snuviscript.variable.Variable;
 
 public class ConstantNull extends InputProvider
 {
@@ -29,16 +28,4 @@ public class ConstantNull extends InputProvider
     {
         return "null";
     }
-    
-    @Override
-    public Variable getVariable(Script sc)
-    {
-        return null;
-    }
-    
-    @Override
-    public Object getArray(Script sc)
-    {
-        return null;
-    }
 }

+ 2 - 2
src/me/hammerle/snuviscript/constants/ConstantString.java → src/me/hammerle/snuviscript/inputprovider/ConstantString.java

@@ -1,6 +1,6 @@
-package me.hammerle.snuviscript.constants;
+package me.hammerle.snuviscript.inputprovider;
 
-import me.hammerle.snuviscript.code.InputProvider;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 import me.hammerle.snuviscript.code.Script;
 
 public class ConstantString extends InputProvider

+ 2 - 17
src/me/hammerle/snuviscript/code/InputProvider.java → src/me/hammerle/snuviscript/inputprovider/InputProvider.java

@@ -1,6 +1,6 @@
-package me.hammerle.snuviscript.code;
+package me.hammerle.snuviscript.inputprovider;
 
-import me.hammerle.snuviscript.variable.Variable;
+import me.hammerle.snuviscript.code.Script;
 
 public abstract class InputProvider 
 {
@@ -49,23 +49,8 @@ public abstract class InputProvider
         throw new ClassCastException();
     }
     
-    public Variable getVariable(Script sc) throws Exception
-    {
-        throw new ClassCastException();
-    }
-    
     public void set(Script sc, Object o) throws Exception
     {
         throw new ClassCastException();
     }
-    
-    public Object getArray(Script sc) throws Exception
-    {
-        return null;
-    }
-    
-    public boolean isArray(Script sc)
-    {
-        return false;
-    }
 }

+ 3 - 19
src/me/hammerle/snuviscript/variable/LocalVariable.java → src/me/hammerle/snuviscript/inputprovider/LocalVariable.java

@@ -1,6 +1,5 @@
-package me.hammerle.snuviscript.variable;
+package me.hammerle.snuviscript.inputprovider;
 
-import java.util.HashMap;
 import me.hammerle.snuviscript.code.Script;
 
 public class LocalVariable extends Variable
@@ -40,18 +39,9 @@ public class LocalVariable extends Variable
         return getVariable(sc).getBoolean(sc);
     }
     
-    @Override
-    public Variable getVariable(Script sc)
+    private Variable getVariable(Script sc)
     {
-        HashMap<String, Variable> map = sc.getLocalVars();
-        Variable v = map.get(name);
-        if(v != null)
-        {
-            return v;
-        }
-        v = new Variable(name);
-        map.put(name, v);
-        return v;
+        return sc.getOrAddLocalVariable(name);
     }
     
     @Override
@@ -59,10 +49,4 @@ public class LocalVariable extends Variable
     {
         getVariable(sc).set(sc, o);
     }
-    
-    @Override
-    public Object getArray(Script sc)
-    {
-        return getVariable(sc).getArray(sc);
-    }
 }

+ 5 - 12
src/me/hammerle/snuviscript/compiler/ReturnWrapper.java → src/me/hammerle/snuviscript/inputprovider/ReturnWrapper.java

@@ -1,8 +1,7 @@
-package me.hammerle.snuviscript.compiler;
+package me.hammerle.snuviscript.inputprovider;
 
-import me.hammerle.snuviscript.code.InputProvider;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 import me.hammerle.snuviscript.code.Script;
-import me.hammerle.snuviscript.variable.Variable;
 
 public class ReturnWrapper extends InputProvider
 {
@@ -19,12 +18,6 @@ public class ReturnWrapper extends InputProvider
         return o;
     }
     
-    @Override
-    public Object getArray(Script sc) throws Exception
-    {
-        return o;
-    }
-    
     @Override
     public double getDouble(Script sc) throws Exception
     {
@@ -42,10 +35,10 @@ public class ReturnWrapper extends InputProvider
     {
         return (Boolean) o;
     }
-    
+
     @Override
-    public Variable getVariable(Script sc) throws Exception
+    public String toString()
     {
-        return (Variable) o;
+        return String.format("ReturnWrapper(%s)", o);
     }
 }

+ 2 - 14
src/me/hammerle/snuviscript/variable/Variable.java → src/me/hammerle/snuviscript/inputprovider/Variable.java

@@ -1,7 +1,7 @@
-package me.hammerle.snuviscript.variable;
+package me.hammerle.snuviscript.inputprovider;
 
 import me.hammerle.snuviscript.code.Script;
-import me.hammerle.snuviscript.code.InputProvider;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 
 public class Variable extends InputProvider
 {
@@ -49,21 +49,9 @@ public class Variable extends InputProvider
         return (boolean) o;
     }
     
-    @Override
-    public Variable getVariable(Script sc) 
-    {
-        return this;
-    }
-    
     @Override
     public void set(Script sc, Object o)
     {
         this.o = o;
     }
-    
-    @Override
-    public Object getArray(Script sc)
-    {
-        return o;
-    }
 }

+ 56 - 0
src/me/hammerle/snuviscript/instructions/Array.java

@@ -0,0 +1,56 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.ArrayReturnWrapper;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+import me.hammerle.snuviscript.inputprovider.Variable;
+
+public class Array extends Instruction
+{
+    private final int arguments;
+    private final ArrayReturnWrapper wrapper = new ArrayReturnWrapper();
+    private final Variable v;
+    
+    public Array(int line, int arguments, Variable v)
+    {
+        super(line);
+        this.arguments = arguments;
+        this.v = v;
+    }
+    
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] in) throws Exception
+    {
+        Object o = v.get(sc);
+        for(int i = 0; i < in.length - 1; i++)
+        {
+            o = java.lang.reflect.Array.get(o, in[i].getInt(sc));
+        }
+        wrapper.setValue(o, in[in.length - 1].getInt(sc));
+        return wrapper;
+    }
+
+    @Override
+    public int getArguments()
+    {
+        return arguments;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append("push ");
+        sb.append(v);
+        if(arguments > 0)
+        {
+            sb.append("[");
+            for(int i = 1; i < arguments; i++)
+            {
+                sb.append(",");
+            }
+            sb.append("]");
+        }
+        return sb.toString();
+    }
+}

+ 15 - 0
src/me/hammerle/snuviscript/instructions/Break.java

@@ -0,0 +1,15 @@
+package me.hammerle.snuviscript.instructions;
+
+public class Break extends Goto
+{
+    public Break(int line)
+    {
+        super(line, 0);
+    }
+
+    @Override
+    public String getName()
+    {
+        return "break";
+    }
+}

+ 26 - 0
src/me/hammerle/snuviscript/instructions/Catch.java

@@ -0,0 +1,26 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+
+public class Catch extends Goto
+{
+    public Catch(int line)
+    {
+        super(line, 0);
+    }
+
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        sc.jumpTo(getJump());
+        sc.setErrorLine(-1);
+        return null;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return "catch";
+    }
+}

+ 2 - 2
src/me/hammerle/snuviscript/compiler/Constant.java → src/me/hammerle/snuviscript/instructions/Constant.java

@@ -1,6 +1,6 @@
-package me.hammerle.snuviscript.compiler;
+package me.hammerle.snuviscript.instructions;
 
-import me.hammerle.snuviscript.code.InputProvider;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 import me.hammerle.snuviscript.code.Script;
 
 public class Constant extends Instruction

+ 15 - 0
src/me/hammerle/snuviscript/instructions/Continue.java

@@ -0,0 +1,15 @@
+package me.hammerle.snuviscript.instructions;
+
+public class Continue extends Goto
+{
+    public Continue(int line)
+    {
+        super(line, 0);
+    }
+    
+    @Override
+    public String getName()
+    {
+        return "continue";
+    }
+}

+ 28 - 0
src/me/hammerle/snuviscript/instructions/Else.java

@@ -0,0 +1,28 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+
+public class Else extends Goto
+{
+    public Else(int line)
+    {
+        super(line, 0);
+    }
+    
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        if(sc.getIfState())
+        {
+            sc.jumpTo(getJump());
+        }
+        return null;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return "else";
+    }
+}

+ 37 - 0
src/me/hammerle/snuviscript/instructions/ElseIf.java

@@ -0,0 +1,37 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+
+public class ElseIf extends Goto
+{
+    public ElseIf(int line)
+    {
+        super(line, 1);
+    }
+    
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        if(!sc.getIfState())
+        {
+            boolean b = o[0].getBoolean(sc);
+            sc.setIfState(b);
+            if(!b)
+            {
+                sc.jumpTo(getJump());
+            }
+        }
+        else
+        {
+            sc.jumpTo(getJump());
+        }
+        return null;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return "elseif";
+    }
+}

+ 31 - 0
src/me/hammerle/snuviscript/instructions/EndIf.java

@@ -0,0 +1,31 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+
+public class EndIf extends Instruction
+{
+    public EndIf(int line)
+    {
+        super(line);
+    }
+
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        sc.setIfState(true);
+        return null;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "endif";
+    }   
+
+    @Override
+    public String toString()
+    {
+        return getName();
+    }
+}

+ 28 - 0
src/me/hammerle/snuviscript/instructions/For.java

@@ -0,0 +1,28 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+
+public class For extends Goto
+{
+    public For(int line)
+    {
+        super(line, 1);
+    }
+
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        if(!o[0].getBoolean(sc))
+        {
+            sc.jumpTo(getJump());
+        }
+        return null;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "for";
+    }
+}

+ 7 - 6
src/me/hammerle/snuviscript/compiler/Function.java → src/me/hammerle/snuviscript/instructions/Function.java

@@ -1,16 +1,17 @@
-package me.hammerle.snuviscript.compiler;
+package me.hammerle.snuviscript.instructions;
 
-import me.hammerle.snuviscript.code.BasicFunction;
-import me.hammerle.snuviscript.code.InputProvider;
+import me.hammerle.snuviscript.inputprovider.ReturnWrapper;
+import me.hammerle.snuviscript.code.NamedFunction;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 import me.hammerle.snuviscript.code.Script;
 
 public class Function extends Instruction
 {
-    private final BasicFunction function;
+    private final NamedFunction function;
     private final int arguments;
     private final ReturnWrapper wrapper = new ReturnWrapper();
     
-    public Function(int line, int arguments, BasicFunction function)
+    public Function(int line, int arguments, NamedFunction function)
     {
         super(line);
         this.function = function;
@@ -21,7 +22,7 @@ public class Function extends Instruction
     public InputProvider execute(Script sc, InputProvider[] in) throws Exception
     {
         Object o = function.execute(sc, in);
-        if(o == Void.TYPE)
+        if(o == Void.TYPE || shouldNotReturnValue())
         {
             return null;
         }

+ 56 - 0
src/me/hammerle/snuviscript/instructions/Goto.java

@@ -0,0 +1,56 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+
+public class Goto extends Instruction
+{
+    private int jump;
+    private final int arguments;
+    
+    public Goto(int line, int arguments)
+    {
+        super(line);
+        this.arguments = arguments;
+    }
+
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        sc.jumpTo(jump);
+        return null;
+    }
+
+    @Override
+    public int getArguments()
+    {
+        return arguments;
+    }
+    
+    public void setJump(int value)
+    {
+        jump = value;
+    }
+
+    public int getJump()
+    {
+        return jump;
+    }
+    
+    @Override
+    public String getName()
+    {
+        return "goto";
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getName());
+        sb.append("(");
+        sb.append(jump);
+        sb.append(")");
+        return sb.toString();
+    }
+}

+ 30 - 0
src/me/hammerle/snuviscript/instructions/If.java

@@ -0,0 +1,30 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+
+public class If extends Goto
+{
+    public If(int line)
+    {
+        super(line, 1);
+    }
+    
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        boolean b = o[0].getBoolean(sc);
+        sc.setIfState(b);
+        if(!b)
+        {
+            sc.jumpTo(getJump());
+        }
+        return null;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "if";
+    }
+}

+ 45 - 0
src/me/hammerle/snuviscript/instructions/IfGoto.java

@@ -0,0 +1,45 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+
+public class IfGoto extends Goto
+{
+    private final boolean check;
+    
+    public IfGoto(int line, boolean check)
+    {
+        super(line, 0);
+        this.check = check;
+    }
+
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        boolean b = sc.peekDataStack().getBoolean(sc);
+        if(b == check)
+        {
+            sc.jumpTo(getJump());
+        }
+        return null;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "if goto";
+    }
+    
+    @Override
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getName());
+        sb.append("(");
+        sb.append(getJump());
+        sb.append(", ");
+        sb.append(check);
+        sb.append(")");
+        return sb.toString();
+    }
+}

+ 13 - 17
src/me/hammerle/snuviscript/compiler/Instruction.java → src/me/hammerle/snuviscript/instructions/Instruction.java

@@ -1,17 +1,27 @@
-package me.hammerle.snuviscript.compiler;
+package me.hammerle.snuviscript.instructions;
 
-import me.hammerle.snuviscript.code.InputProvider;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 import me.hammerle.snuviscript.code.Script;
 
 public abstract class Instruction
 {
-    private final static String[] VARS = new String[0];
     private final int line;
+    private boolean noReturn = false;
     
     public Instruction(int line)
     {
         this.line = line;
     }
+    
+    public void setNoReturn()
+    {
+        noReturn = true;
+    }
+    
+    public boolean shouldNotReturnValue()
+    {
+        return noReturn;
+    }
 
     public int getLine()
     {
@@ -28,20 +38,6 @@ public abstract class Instruction
         return 0;
     }
     
-    public void setJump(int value)
-    {
-    }
-    
-    public int getJump()
-    {
-        return 0;
-    }
-    
-    public String[] getVars()
-    {
-        return VARS;
-    }
-    
     public String getName()
     {
         return "";

+ 50 - 0
src/me/hammerle/snuviscript/instructions/Return.java

@@ -0,0 +1,50 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+import me.hammerle.snuviscript.inputprovider.ReturnWrapper;
+
+public class Return extends Instruction
+{
+    private final int arguments;
+    private final ReturnWrapper wrapper = new ReturnWrapper();
+    
+    public Return(int line, int arguments)
+    {
+        super(line);
+        this.arguments = arguments;
+    }
+
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        if(o.length > 0)
+        {
+            wrapper.setValue(o[0].get(sc));
+            sc.handleReturn(wrapper);
+        }
+        else
+        {
+            sc.handleReturn(null);
+        }
+        return null;
+    }
+
+    @Override
+    public int getArguments()
+    {
+        return arguments;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "return";
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("return(%d)", arguments);
+    }
+}

+ 3 - 2
src/me/hammerle/snuviscript/compiler/SignInverter.java → src/me/hammerle/snuviscript/instructions/SignInverter.java

@@ -1,6 +1,7 @@
-package me.hammerle.snuviscript.compiler;
+package me.hammerle.snuviscript.instructions;
 
-import me.hammerle.snuviscript.code.InputProvider;
+import me.hammerle.snuviscript.inputprovider.ReturnWrapper;
+import me.hammerle.snuviscript.inputprovider.InputProvider;
 import me.hammerle.snuviscript.code.Script;
 
 public class SignInverter extends Instruction

+ 25 - 0
src/me/hammerle/snuviscript/instructions/Try.java

@@ -0,0 +1,25 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+
+public class Try extends Goto
+{
+    public Try(int line)
+    {
+        super(line, 0);
+    }
+
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        sc.setErrorLine(getJump());
+        return null;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "try";
+    }
+}

+ 11 - 2
src/me/hammerle/snuviscript/compiler/UserFunction.java → src/me/hammerle/snuviscript/instructions/UserFunction.java

@@ -1,4 +1,7 @@
-package me.hammerle.snuviscript.compiler;
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
 
 public class UserFunction extends Goto
 {
@@ -13,7 +16,13 @@ public class UserFunction extends Goto
     }
 
     @Override
-    public String[] getVars()
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        sc.jumpTo(getJump());
+        return null;
+    }
+    
+    public String[] getArgumentNames()
     {
         return vars;
     }

+ 28 - 0
src/me/hammerle/snuviscript/instructions/While.java

@@ -0,0 +1,28 @@
+package me.hammerle.snuviscript.instructions;
+
+import me.hammerle.snuviscript.inputprovider.InputProvider;
+import me.hammerle.snuviscript.code.Script;
+
+public class While extends Goto
+{
+    public While(int line)
+    {
+        super(line, 1);
+    }
+    
+    @Override
+    public InputProvider execute(Script sc, InputProvider[] o) throws Exception
+    {
+        if(!o[0].getBoolean(sc))
+        {
+            sc.jumpTo(getJump());
+        }
+        return null;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "while";
+    }
+}

+ 25 - 9
src/me/hammerle/snuviscript/test/Test.java

@@ -3,17 +3,20 @@ package me.hammerle.snuviscript.test;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.function.BiConsumer;
-import me.hammerle.snuviscript.code.SnuviParser;
-import me.hammerle.snuviscript.token.Tokenizer;
-import me.hammerle.snuviscript.token.Token;
-import me.hammerle.snuviscript.compiler.Compiler;
+import me.hammerle.snuviscript.code.Script;
+import me.hammerle.snuviscript.code.ScriptManager;
+import me.hammerle.snuviscript.tokenizer.Tokenizer;
+import me.hammerle.snuviscript.tokenizer.Token;
+import me.hammerle.snuviscript.code.Compiler;
+import me.hammerle.snuviscript.instructions.Instruction;
 
 public class Test
 {
     private static final TestScheduler SCHEDULER = new TestScheduler();
     private static final TestLogger LOGGER = new TestLogger();
-    private static final SnuviParser PARSER = new SnuviParser(LOGGER, SCHEDULER);
+    private static final ScriptManager PARSER = new ScriptManager(LOGGER, SCHEDULER);
     private static int done = 0;
     private static int tests = 0;  
     
@@ -21,7 +24,12 @@ public class Test
     {
         testTokenizer();
         testCompiler();
-        //testOutput();
+        testOutput();
+        
+        LOGGER.reset();
+        PARSER.startScript(true, "test", "./test/test.test");
+        PARSER.callEvent("testevent", null, null);
+        LOGGER.printAll();
     }
     
     private static void testOutput()
@@ -33,7 +41,9 @@ public class Test
             tests++;
                 
             LOGGER.reset();
-            PARSER.startScript(true, "", inFile.getPath());
+            
+            Script sc = new Script(PARSER, null, null, inFile.getName(), inFile.getPath());
+            sc.run();
 
             if(LOGGER.check(checkFile))
             {
@@ -78,7 +88,7 @@ public class Test
     {
         done = 0;
         tests = 0; 
-        final Compiler c = new Compiler(LOGGER);
+        final Compiler c = new Compiler();
         forEachFile(new File("./test"), ".cout", (inFile, checkFile) -> 
         {
             tests++;
@@ -88,7 +98,13 @@ public class Test
                 {
                     Tokenizer tokenizer = new Tokenizer();
                     LOGGER.reset();
-                    c.compile(tokenizer.tokenize(in));
+                    Instruction[] instr = c.compile(tokenizer.tokenize(in), 
+                            new HashMap<>(), new HashMap<>(), new HashMap<>(), 
+                            new HashMap<>());
+                    for(Instruction i : instr)
+                    {
+                        LOGGER.print(i.toString(), null, null, null, null, -1);
+                    }
                     if(LOGGER.check(checkFile))
                     {
                         done++;

+ 6 - 0
src/me/hammerle/snuviscript/test/TestLogger.java

@@ -31,6 +31,12 @@ public class TestLogger implements ISnuviLogger
         list.clear();
     }
     
+    public void printAll()
+    {
+        list.stream().forEach(s -> System.out.println(s));
+        list.clear();
+    }
+    
     public boolean check(File f)
     {
         if(!f.exists())

+ 8 - 7
src/me/hammerle/snuviscript/test/TestScheduler.java

@@ -1,20 +1,21 @@
 package me.hammerle.snuviscript.test;
 
+import java.util.ArrayList;
 import me.hammerle.snuviscript.code.ISnuviScheduler;
 
 public class TestScheduler implements ISnuviScheduler
 {
-    @Override
-    public int scheduleTask(Runnable r)
-    {
-        System.out.println("Schedule");
-        return 0;
-    }
-
+    private final ArrayList<Runnable> list = new ArrayList<>();
+    
     @Override
     public int scheduleTask(Runnable r, long delay)
     {
+        list.add(r);
         return 0;
     }
     
+    public void execute()
+    {
+        list.forEach(r -> r.run());
+    }
 }

+ 1 - 1
src/me/hammerle/snuviscript/token/DataToken.java → src/me/hammerle/snuviscript/tokenizer/DataToken.java

@@ -1,4 +1,4 @@
-package me.hammerle.snuviscript.token;
+package me.hammerle.snuviscript.tokenizer;
 
 public class DataToken extends Token
 {

+ 1 - 1
src/me/hammerle/snuviscript/token/StreamCharReader.java → src/me/hammerle/snuviscript/tokenizer/StreamCharReader.java

@@ -1,4 +1,4 @@
-package me.hammerle.snuviscript.token;
+package me.hammerle.snuviscript.tokenizer;
 
 import java.io.IOException;
 import java.io.InputStream;

+ 1 - 1
src/me/hammerle/snuviscript/token/Token.java → src/me/hammerle/snuviscript/tokenizer/Token.java

@@ -1,4 +1,4 @@
-package me.hammerle.snuviscript.token;
+package me.hammerle.snuviscript.tokenizer;
 
 public class Token
 {

+ 1 - 1
src/me/hammerle/snuviscript/token/TokenType.java → src/me/hammerle/snuviscript/tokenizer/TokenType.java

@@ -1,4 +1,4 @@
-package me.hammerle.snuviscript.token;
+package me.hammerle.snuviscript.tokenizer;
 
 public enum TokenType
 {

+ 14 - 10
src/me/hammerle/snuviscript/token/Tokenizer.java → src/me/hammerle/snuviscript/tokenizer/Tokenizer.java

@@ -1,9 +1,9 @@
-package me.hammerle.snuviscript.token;
+package me.hammerle.snuviscript.tokenizer;
 
 import java.io.InputStream;
 import java.util.ArrayList;
 import me.hammerle.snuviscript.exceptions.PreScriptException;
-import static me.hammerle.snuviscript.token.TokenType.*;
+import static me.hammerle.snuviscript.tokenizer.TokenType.*;
 
 public class Tokenizer
 {
@@ -68,15 +68,19 @@ public class Tokenizer
         }
     }
     
-    public Token[] tokenize(InputStream in)
+    public Token[] tokenize(InputStream... streams)
     {
-        stream = new StreamCharReader(in);
         tokens.clear();
-        line = 1;
-        int c;
-        while((c = Tokenizer.this.next()) != -1)
+        for(InputStream in : streams)
         {
-            handleChar(c);
+            line = 1;
+            stream = new StreamCharReader(in);
+            
+            int c;
+            while((c = Tokenizer.this.next()) != -1)
+            {
+                handleChar(c);
+            }
         }
         add(EOF);
         return tokens.toArray(new Token[tokens.size()]);
@@ -84,7 +88,7 @@ public class Tokenizer
     
     private void handleChar(int c)
     {
-        if(Character.isLetter(c) || c == '_')
+        if(Character.isLetter(c) || c == '_' || c == '.')
         {
             handleLiteral(c, TokenType.LITERAL);
         }
@@ -106,7 +110,7 @@ public class Tokenizer
         while(true)
         {
             int data = peek();
-            if(!Character.isLetterOrDigit(data) && data != '_')
+            if(!Character.isLetterOrDigit(data) && data != '_' && data != '.')
             {
                 break;
             }

+ 0 - 24
src/me/hammerle/snuviscript/variable/ArrayVariable.java

@@ -1,24 +0,0 @@
-package me.hammerle.snuviscript.variable;
-
-import me.hammerle.snuviscript.code.SnuviUtils;
-import me.hammerle.snuviscript.code.Script;
-
-public class ArrayVariable extends Variable
-{
-    public ArrayVariable(String name) 
-    {
-        super(name);
-    }
-    
-    @Override
-    public String getString(Script sc) 
-    {
-        return SnuviUtils.getArrayString(get(sc));
-    }
-
-    @Override
-    public boolean isArray(Script sc) 
-    {
-        return true;
-    }
-}

+ 0 - 45
src/me/hammerle/snuviscript/variable/LocalArrayVariable.java

@@ -1,45 +0,0 @@
-package me.hammerle.snuviscript.variable;
-
-import java.util.HashMap;
-import me.hammerle.snuviscript.code.SnuviUtils;
-import me.hammerle.snuviscript.code.Script;
-
-public class LocalArrayVariable extends LocalVariable
-{
-    public LocalArrayVariable(String name) 
-    {
-        super(name);
-    }
-    
-    @Override
-    public String getString(Script sc) 
-    {
-        return SnuviUtils.getArrayString(get(sc));
-    }
-    
-    @Override
-    public Variable getVariable(Script sc) 
-    {
-        HashMap<String, Variable> map = sc.getLocalVars();
-        Variable v = map.get(name);
-        if(v != null)
-        {
-            return v;
-        }
-        v = new ArrayVariable(name);
-        map.put(name, v);
-        return v;
-    }
-    
-    @Override
-    public String toString() 
-    {
-        return name + "#L[]";
-    }
-    
-    @Override
-    public boolean isArray(Script sc) 
-    {
-        return true;
-    }
-}

+ 10 - 0
test/arrays/array_dim1

@@ -0,0 +1,10 @@
+a = array.new(3);
+for(i = 0; i < array.length(a); i++)
+{
+    a[i] = i;
+}
+for(i = 0; i < array.length(a); i++)
+{
+    print(a[i]);
+}
+

+ 37 - 0
test/arrays/array_dim1.cout

@@ -0,0 +1,37 @@
+push a
+push 3
+use array.new(1)
+use =(2)
+push i
+push 0
+use =(2)
+push i
+push a
+use array.getsize(1)
+use <(2)
+goto(14)
+push i
+use p++(1)
+goto(6)
+for(20)
+push i
+push a[]
+push i
+use =(2)
+goto(11)
+push i
+push 0
+use =(2)
+push i
+push a
+use array.getsize(1)
+use <(2)
+goto(31)
+push i
+use p++(1)
+goto(23)
+for(36)
+push i
+push a[]
+use print(1)
+goto(28)

+ 3 - 0
test/arrays/array_dim1.out

@@ -0,0 +1,3 @@
+0.0
+1.0
+2.0

+ 59 - 0
test/arrays/array_dim1.tout

@@ -0,0 +1,59 @@
+(1, LITERAL, "a")
+(1, SET)
+(1, LITERAL, "array.new")
+(1, OPEN_BRACKET)
+(1, NUMBER, 3.0)
+(1, CLOSE_BRACKET)
+(1, SEMICOLON)
+(2, FOR)
+(2, OPEN_BRACKET)
+(2, LITERAL, "i")
+(2, SET)
+(2, NUMBER, 0.0)
+(2, SEMICOLON)
+(2, LITERAL, "i")
+(2, LESS)
+(2, LITERAL, "array.length")
+(2, OPEN_BRACKET)
+(2, LITERAL, "a")
+(2, CLOSE_BRACKET)
+(2, SEMICOLON)
+(2, LITERAL, "i")
+(2, INC)
+(2, CLOSE_BRACKET)
+(3, OPEN_CURVED_BRACKET)
+(4, LITERAL, "a")
+(4, OPEN_SQUARE_BRACKET)
+(4, LITERAL, "i")
+(4, CLOSE_SQUARE_BRACKET)
+(4, SET)
+(4, LITERAL, "i")
+(4, SEMICOLON)
+(5, CLOSE_CURVED_BRACKET)
+(6, FOR)
+(6, OPEN_BRACKET)
+(6, LITERAL, "i")
+(6, SET)
+(6, NUMBER, 0.0)
+(6, SEMICOLON)
+(6, LITERAL, "i")
+(6, LESS)
+(6, LITERAL, "array.length")
+(6, OPEN_BRACKET)
+(6, LITERAL, "a")
+(6, CLOSE_BRACKET)
+(6, SEMICOLON)
+(6, LITERAL, "i")
+(6, INC)
+(6, CLOSE_BRACKET)
+(7, OPEN_CURVED_BRACKET)
+(8, LITERAL, "print")
+(8, OPEN_BRACKET)
+(8, LITERAL, "a")
+(8, OPEN_SQUARE_BRACKET)
+(8, LITERAL, "i")
+(8, CLOSE_SQUARE_BRACKET)
+(8, CLOSE_BRACKET)
+(8, SEMICOLON)
+(9, CLOSE_CURVED_BRACKET)
+(11, EOF)

+ 15 - 0
test/arrays/array_dim2

@@ -0,0 +1,15 @@
+a = array.new(3, 2);
+for(x = 0; x < array.length(a); x++)
+{
+    for(y = 0; y < array.length(a[x]); y++)
+    {
+        a[x, y] = x * 2 + y;
+    }
+}
+for(x = 0; x < array.length(a); x++)
+{
+    for(y = 0; y < array.length(a[x]); y++)
+    {
+        print(a[x, y]);
+    }
+}

+ 72 - 0
test/arrays/array_dim2.cout

@@ -0,0 +1,72 @@
+push a
+push 3
+push 2
+use array.new(2)
+use =(2)
+push x
+push 0
+use =(2)
+push x
+push a
+use array.getsize(1)
+use <(2)
+goto(15)
+push x
+use p++(1)
+goto(7)
+for(40)
+push y
+push 0
+use =(2)
+push y
+push x
+push a[]
+use array.getsize(1)
+use <(2)
+goto(28)
+push y
+use p++(1)
+goto(19)
+for(39)
+push x
+push y
+push a[,]
+push x
+push 2
+use *(2)
+push y
+use +(2)
+use =(2)
+goto(25)
+goto(12)
+push x
+push 0
+use =(2)
+push x
+push a
+use array.getsize(1)
+use <(2)
+goto(51)
+push x
+use p++(1)
+goto(43)
+for(71)
+push y
+push 0
+use =(2)
+push y
+push x
+push a[]
+use array.getsize(1)
+use <(2)
+goto(64)
+push y
+use p++(1)
+goto(55)
+for(70)
+push x
+push y
+push a[,]
+use print(1)
+goto(61)
+goto(48)

+ 6 - 0
test/arrays/array_dim2.out

@@ -0,0 +1,6 @@
+0.0
+1.0
+2.0
+3.0
+4.0
+5.0

+ 111 - 0
test/arrays/array_dim2.tout

@@ -0,0 +1,111 @@
+(1, LITERAL, "a")
+(1, SET)
+(1, LITERAL, "array.new")
+(1, OPEN_BRACKET)
+(1, NUMBER, 3.0)
+(1, COMMA)
+(1, NUMBER, 2.0)
+(1, CLOSE_BRACKET)
+(1, SEMICOLON)
+(2, FOR)
+(2, OPEN_BRACKET)
+(2, LITERAL, "x")
+(2, SET)
+(2, NUMBER, 0.0)
+(2, SEMICOLON)
+(2, LITERAL, "x")
+(2, LESS)
+(2, LITERAL, "array.length")
+(2, OPEN_BRACKET)
+(2, LITERAL, "a")
+(2, CLOSE_BRACKET)
+(2, SEMICOLON)
+(2, LITERAL, "x")
+(2, INC)
+(2, CLOSE_BRACKET)
+(3, OPEN_CURVED_BRACKET)
+(4, FOR)
+(4, OPEN_BRACKET)
+(4, LITERAL, "y")
+(4, SET)
+(4, NUMBER, 0.0)
+(4, SEMICOLON)
+(4, LITERAL, "y")
+(4, LESS)
+(4, LITERAL, "array.length")
+(4, OPEN_BRACKET)
+(4, LITERAL, "a")
+(4, OPEN_SQUARE_BRACKET)
+(4, LITERAL, "x")
+(4, CLOSE_SQUARE_BRACKET)
+(4, CLOSE_BRACKET)
+(4, SEMICOLON)
+(4, LITERAL, "y")
+(4, INC)
+(4, CLOSE_BRACKET)
+(5, OPEN_CURVED_BRACKET)
+(6, LITERAL, "a")
+(6, OPEN_SQUARE_BRACKET)
+(6, LITERAL, "x")
+(6, COMMA)
+(6, LITERAL, "y")
+(6, CLOSE_SQUARE_BRACKET)
+(6, SET)
+(6, LITERAL, "x")
+(6, MUL)
+(6, NUMBER, 2.0)
+(6, ADD)
+(6, LITERAL, "y")
+(6, SEMICOLON)
+(7, CLOSE_CURVED_BRACKET)
+(8, CLOSE_CURVED_BRACKET)
+(9, FOR)
+(9, OPEN_BRACKET)
+(9, LITERAL, "x")
+(9, SET)
+(9, NUMBER, 0.0)
+(9, SEMICOLON)
+(9, LITERAL, "x")
+(9, LESS)
+(9, LITERAL, "array.length")
+(9, OPEN_BRACKET)
+(9, LITERAL, "a")
+(9, CLOSE_BRACKET)
+(9, SEMICOLON)
+(9, LITERAL, "x")
+(9, INC)
+(9, CLOSE_BRACKET)
+(10, OPEN_CURVED_BRACKET)
+(11, FOR)
+(11, OPEN_BRACKET)
+(11, LITERAL, "y")
+(11, SET)
+(11, NUMBER, 0.0)
+(11, SEMICOLON)
+(11, LITERAL, "y")
+(11, LESS)
+(11, LITERAL, "array.length")
+(11, OPEN_BRACKET)
+(11, LITERAL, "a")
+(11, OPEN_SQUARE_BRACKET)
+(11, LITERAL, "x")
+(11, CLOSE_SQUARE_BRACKET)
+(11, CLOSE_BRACKET)
+(11, SEMICOLON)
+(11, LITERAL, "y")
+(11, INC)
+(11, CLOSE_BRACKET)
+(12, OPEN_CURVED_BRACKET)
+(13, LITERAL, "print")
+(13, OPEN_BRACKET)
+(13, LITERAL, "a")
+(13, OPEN_SQUARE_BRACKET)
+(13, LITERAL, "x")
+(13, COMMA)
+(13, LITERAL, "y")
+(13, CLOSE_SQUARE_BRACKET)
+(13, CLOSE_BRACKET)
+(13, SEMICOLON)
+(14, CLOSE_CURVED_BRACKET)
+(15, CLOSE_CURVED_BRACKET)
+(16, EOF)

+ 21 - 0
test/arrays/array_dim3

@@ -0,0 +1,21 @@
+a = array.new(4, 3, 2);
+for(x = 0; x < array.length(a); x++)
+{
+    for(y = 0; y < array.length(a[x]); y++)
+    {
+        for(z = 0; z < array.length(a[x, y]); z++)
+        {
+            a[x, y, z] = x * 3 * 2 + y * 2 + z;
+        }
+    }
+}
+for(x = 0; x < array.length(a); x++)
+{
+    for(y = 0; y < array.length(a[x]); y++)
+    {
+        for(z = 0; z < array.length(a[x, y]); z++)
+        {
+            print(a[x, y, z]);
+        }
+    }
+}

+ 111 - 0
test/arrays/array_dim3.cout

@@ -0,0 +1,111 @@
+push a
+push 4
+push 3
+push 2
+use array.new(3)
+use =(2)
+push x
+push 0
+use =(2)
+push x
+push a
+use array.getsize(1)
+use <(2)
+goto(16)
+push x
+use p++(1)
+goto(8)
+for(63)
+push y
+push 0
+use =(2)
+push y
+push x
+push a[]
+use array.getsize(1)
+use <(2)
+goto(29)
+push y
+use p++(1)
+goto(20)
+for(62)
+push z
+push 0
+use =(2)
+push z
+push x
+push y
+push a[,]
+use array.getsize(1)
+use <(2)
+goto(43)
+push z
+use p++(1)
+goto(33)
+for(61)
+push x
+push y
+push z
+push a[,,]
+push x
+push 3
+use *(2)
+push 2
+use *(2)
+push y
+push 2
+use *(2)
+use +(2)
+push z
+use +(2)
+use =(2)
+goto(40)
+goto(26)
+goto(13)
+push x
+push 0
+use =(2)
+push x
+push a
+use array.getsize(1)
+use <(2)
+goto(74)
+push x
+use p++(1)
+goto(66)
+for(110)
+push y
+push 0
+use =(2)
+push y
+push x
+push a[]
+use array.getsize(1)
+use <(2)
+goto(87)
+push y
+use p++(1)
+goto(78)
+for(109)
+push z
+push 0
+use =(2)
+push z
+push x
+push y
+push a[,]
+use array.getsize(1)
+use <(2)
+goto(101)
+push z
+use p++(1)
+goto(91)
+for(108)
+push x
+push y
+push z
+push a[,,]
+use print(1)
+goto(98)
+goto(84)
+goto(71)

+ 24 - 0
test/arrays/array_dim3.out

@@ -0,0 +1,24 @@
+0.0
+1.0
+2.0
+3.0
+4.0
+5.0
+6.0
+7.0
+8.0
+9.0
+10.0
+11.0
+12.0
+13.0
+14.0
+15.0
+16.0
+17.0
+18.0
+19.0
+20.0
+21.0
+22.0
+23.0

+ 169 - 0
test/arrays/array_dim3.tout

@@ -0,0 +1,169 @@
+(1, LITERAL, "a")
+(1, SET)
+(1, LITERAL, "array.new")
+(1, OPEN_BRACKET)
+(1, NUMBER, 4.0)
+(1, COMMA)
+(1, NUMBER, 3.0)
+(1, COMMA)
+(1, NUMBER, 2.0)
+(1, CLOSE_BRACKET)
+(1, SEMICOLON)
+(2, FOR)
+(2, OPEN_BRACKET)
+(2, LITERAL, "x")
+(2, SET)
+(2, NUMBER, 0.0)
+(2, SEMICOLON)
+(2, LITERAL, "x")
+(2, LESS)
+(2, LITERAL, "array.length")
+(2, OPEN_BRACKET)
+(2, LITERAL, "a")
+(2, CLOSE_BRACKET)
+(2, SEMICOLON)
+(2, LITERAL, "x")
+(2, INC)
+(2, CLOSE_BRACKET)
+(3, OPEN_CURVED_BRACKET)
+(4, FOR)
+(4, OPEN_BRACKET)
+(4, LITERAL, "y")
+(4, SET)
+(4, NUMBER, 0.0)
+(4, SEMICOLON)
+(4, LITERAL, "y")
+(4, LESS)
+(4, LITERAL, "array.length")
+(4, OPEN_BRACKET)
+(4, LITERAL, "a")
+(4, OPEN_SQUARE_BRACKET)
+(4, LITERAL, "x")
+(4, CLOSE_SQUARE_BRACKET)
+(4, CLOSE_BRACKET)
+(4, SEMICOLON)
+(4, LITERAL, "y")
+(4, INC)
+(4, CLOSE_BRACKET)
+(5, OPEN_CURVED_BRACKET)
+(6, FOR)
+(6, OPEN_BRACKET)
+(6, LITERAL, "z")
+(6, SET)
+(6, NUMBER, 0.0)
+(6, SEMICOLON)
+(6, LITERAL, "z")
+(6, LESS)
+(6, LITERAL, "array.length")
+(6, OPEN_BRACKET)
+(6, LITERAL, "a")
+(6, OPEN_SQUARE_BRACKET)
+(6, LITERAL, "x")
+(6, COMMA)
+(6, LITERAL, "y")
+(6, CLOSE_SQUARE_BRACKET)
+(6, CLOSE_BRACKET)
+(6, SEMICOLON)
+(6, LITERAL, "z")
+(6, INC)
+(6, CLOSE_BRACKET)
+(7, OPEN_CURVED_BRACKET)
+(8, LITERAL, "a")
+(8, OPEN_SQUARE_BRACKET)
+(8, LITERAL, "x")
+(8, COMMA)
+(8, LITERAL, "y")
+(8, COMMA)
+(8, LITERAL, "z")
+(8, CLOSE_SQUARE_BRACKET)
+(8, SET)
+(8, LITERAL, "x")
+(8, MUL)
+(8, NUMBER, 3.0)
+(8, MUL)
+(8, NUMBER, 2.0)
+(8, ADD)
+(8, LITERAL, "y")
+(8, MUL)
+(8, NUMBER, 2.0)
+(8, ADD)
+(8, LITERAL, "z")
+(8, SEMICOLON)
+(9, CLOSE_CURVED_BRACKET)
+(10, CLOSE_CURVED_BRACKET)
+(11, CLOSE_CURVED_BRACKET)
+(12, FOR)
+(12, OPEN_BRACKET)
+(12, LITERAL, "x")
+(12, SET)
+(12, NUMBER, 0.0)
+(12, SEMICOLON)
+(12, LITERAL, "x")
+(12, LESS)
+(12, LITERAL, "array.length")
+(12, OPEN_BRACKET)
+(12, LITERAL, "a")
+(12, CLOSE_BRACKET)
+(12, SEMICOLON)
+(12, LITERAL, "x")
+(12, INC)
+(12, CLOSE_BRACKET)
+(13, OPEN_CURVED_BRACKET)
+(14, FOR)
+(14, OPEN_BRACKET)
+(14, LITERAL, "y")
+(14, SET)
+(14, NUMBER, 0.0)
+(14, SEMICOLON)
+(14, LITERAL, "y")
+(14, LESS)
+(14, LITERAL, "array.length")
+(14, OPEN_BRACKET)
+(14, LITERAL, "a")
+(14, OPEN_SQUARE_BRACKET)
+(14, LITERAL, "x")
+(14, CLOSE_SQUARE_BRACKET)
+(14, CLOSE_BRACKET)
+(14, SEMICOLON)
+(14, LITERAL, "y")
+(14, INC)
+(14, CLOSE_BRACKET)
+(15, OPEN_CURVED_BRACKET)
+(16, FOR)
+(16, OPEN_BRACKET)
+(16, LITERAL, "z")
+(16, SET)
+(16, NUMBER, 0.0)
+(16, SEMICOLON)
+(16, LITERAL, "z")
+(16, LESS)
+(16, LITERAL, "array.length")
+(16, OPEN_BRACKET)
+(16, LITERAL, "a")
+(16, OPEN_SQUARE_BRACKET)
+(16, LITERAL, "x")
+(16, COMMA)
+(16, LITERAL, "y")
+(16, CLOSE_SQUARE_BRACKET)
+(16, CLOSE_BRACKET)
+(16, SEMICOLON)
+(16, LITERAL, "z")
+(16, INC)
+(16, CLOSE_BRACKET)
+(17, OPEN_CURVED_BRACKET)
+(18, LITERAL, "print")
+(18, OPEN_BRACKET)
+(18, LITERAL, "a")
+(18, OPEN_SQUARE_BRACKET)
+(18, LITERAL, "x")
+(18, COMMA)
+(18, LITERAL, "y")
+(18, COMMA)
+(18, LITERAL, "z")
+(18, CLOSE_SQUARE_BRACKET)
+(18, CLOSE_BRACKET)
+(18, SEMICOLON)
+(19, CLOSE_CURVED_BRACKET)
+(20, CLOSE_CURVED_BRACKET)
+(21, CLOSE_CURVED_BRACKET)
+(22, EOF)

+ 8 - 0
test/basic/gosub

@@ -0,0 +1,8 @@
+print("start");
+gosub(@sub);
+gosub("sub");
+term();
+
+@sub
+print("hi");
+return;

+ 10 - 0
test/basic/gosub.cout

@@ -0,0 +1,10 @@
+push "start"
+use print(1)
+push "sub"
+use gosub(1)
+push "sub"
+use gosub(1)
+use term(0)
+push "hi"
+use print(1)
+return(0)

+ 3 - 0
test/basic/gosub.out

@@ -0,0 +1,3 @@
+start
+hi
+hi

+ 28 - 0
test/basic/gosub.tout

@@ -0,0 +1,28 @@
+(1, LITERAL, "print")
+(1, OPEN_BRACKET)
+(1, STRING, "start")
+(1, CLOSE_BRACKET)
+(1, SEMICOLON)
+(2, LITERAL, "gosub")
+(2, OPEN_BRACKET)
+(2, LABEL, "@sub")
+(2, CLOSE_BRACKET)
+(2, SEMICOLON)
+(3, LITERAL, "gosub")
+(3, OPEN_BRACKET)
+(3, STRING, "sub")
+(3, CLOSE_BRACKET)
+(3, SEMICOLON)
+(4, LITERAL, "term")
+(4, OPEN_BRACKET)
+(4, CLOSE_BRACKET)
+(4, SEMICOLON)
+(6, LABEL, "@sub")
+(7, LITERAL, "print")
+(7, OPEN_BRACKET)
+(7, STRING, "hi")
+(7, CLOSE_BRACKET)
+(7, SEMICOLON)
+(8, RETURN)
+(8, SEMICOLON)
+(9, EOF)

+ 0 - 0
test/goto → test/basic/goto


+ 0 - 0
test/goto.cout → test/basic/goto.cout


+ 0 - 0
test/goto.out → test/basic/goto.out


+ 0 - 0
test/goto.tout → test/basic/goto.tout


+ 7 - 0
test/basic/local

@@ -0,0 +1,7 @@
+print(get());
+
+function get()
+{
+    a = 5;
+    return a;
+}

+ 9 - 0
test/basic/local.cout

@@ -0,0 +1,9 @@
+use get(0)
+use print(1)
+get(8)
+push a#L
+push 5
+use =(2)
+push a#L
+return(1)
+return(0)

+ 1 - 0
test/basic/local.out

@@ -0,0 +1 @@
+5.0

+ 21 - 0
test/basic/local.tout

@@ -0,0 +1,21 @@
+(1, LITERAL, "print")
+(1, OPEN_BRACKET)
+(1, LITERAL, "get")
+(1, OPEN_BRACKET)
+(1, CLOSE_BRACKET)
+(1, CLOSE_BRACKET)
+(1, SEMICOLON)
+(3, FUNCTION)
+(3, LITERAL, "get")
+(3, OPEN_BRACKET)
+(3, CLOSE_BRACKET)
+(4, OPEN_CURVED_BRACKET)
+(5, LITERAL, "a")
+(5, SET)
+(5, NUMBER, 5.0)
+(5, SEMICOLON)
+(6, RETURN)
+(6, LITERAL, "a")
+(6, SEMICOLON)
+(7, CLOSE_CURVED_BRACKET)
+(8, EOF)

+ 0 - 0
test/print → test/basic/print


+ 4 - 0
test/basic/print.cout

@@ -0,0 +1,4 @@
+push "HI"
+use print(1)
+push "HI2"
+use print(1)

+ 0 - 0
test/print.out → test/basic/print.out


+ 0 - 0
test/print.tout → test/basic/print.tout


+ 58 - 0
test/calc/base.cout

@@ -0,0 +1,58 @@
+push 1
+push 1
+use +(2)
+use print(1)
+push 1
+push 3
+use -(1)
+use +(2)
+use print(1)
+push 1
+push 3
+use -(2)
+use print(1)
+push 1
+push 3
+use -(1)
+use -(2)
+use print(1)
+push 4
+push 3
+use *(2)
+use print(1)
+push 6
+push 3
+use -(1)
+use *(2)
+use print(1)
+push 6
+use -(1)
+push 4
+use *(2)
+use print(1)
+push 6
+use -(1)
+push 4
+use -(1)
+use *(2)
+use print(1)
+push 4
+push 2
+use /(2)
+use print(1)
+push 6
+push 2
+use -(1)
+use /(2)
+use print(1)
+push 6
+use -(1)
+push 3
+use /(2)
+use print(1)
+push 6
+use -(1)
+push 2
+use -(1)
+use /(2)
+use print(1)

+ 60 - 0
test/calc/mixed.cout

@@ -0,0 +1,60 @@
+push 2
+push 3
+push 4
+use *(2)
+use +(2)
+use print(1)
+push 2
+push 3
+use +(2)
+push 4
+use *(2)
+use print(1)
+push 2
+push 3
+push 4
+use *(2)
+use +(2)
+push 2
+use +(2)
+use print(1)
+push 2
+push 3
+push 4
+push 2
+use +(2)
+use *(2)
+use +(2)
+use print(1)
+push 2
+push 3
+push 4
+push 2
+use +(2)
+use *(2)
+use +(2)
+use print(1)
+push 2
+push 3
+use -(1)
+push 4
+push 2
+use +(2)
+use *(2)
+use +(2)
+use print(1)
+push 2
+push 3
+push 4
+use -(1)
+push 2
+use +(2)
+use *(2)
+use +(2)
+use print(1)
+push 2
+push 3
+use -(2)
+push 4
+use *(2)
+use print(1)

Some files were not shown because too many files changed in this diff