浏览代码

new bytecode compiler, has better syntax translating

Kajetan Johannes Hammerle 7 年之前
父节点
当前提交
746d838670

+ 1 - 0
.gitignore

@@ -1,2 +1,3 @@
 /build
 /dist
+/todo.html

+ 7 - 1
nbproject/private/private.xml

@@ -2,6 +2,12 @@
 <project-private xmlns="http://www.netbeans.org/ns/project-private/1">
     <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
     <open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
-        <group/>
+        <group>
+            <file>file:/home/kajetan/Dropbox/Projekte/Informatik/SnuviScript/src/me/hammerle/code/LineCompiler.java</file>
+            <file>file:/home/kajetan/Dropbox/Projekte/Informatik/SnuviScript/src/me/hammerle/code/Code.java</file>
+            <file>file:/home/kajetan/Dropbox/Projekte/Informatik/SnuviScript/Instruction%20List%20–%20SmileBasic.html</file>
+            <file>file:/home/kajetan/Dropbox/Projekte/Informatik/SnuviScript/src/me/hammerle/code/SnuviParser.java</file>
+            <file>file:/home/kajetan/Dropbox/Projekte/Informatik/SnuviScript/src/me/hammerle/snuviscript/SnuviScript.java</file>
+        </group>
     </open-files>
 </project-private>

+ 130 - 427
src/me/hammerle/code/Code.java

@@ -2,10 +2,8 @@ package me.hammerle.code;
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.Stack;
 import me.hammerle.exceptions.PreScriptException;
-import me.hammerle.exceptions.NoSuchMethodException;
 import me.hammerle.math.Fraction;
 
 public class Code
@@ -13,24 +11,26 @@ public class Code
     protected final int realLine;
     protected final String function;
     protected final int pars;
+    protected final byte layer;
     protected Object value;
     
-    private Code(String function, int pars, Object value, int realLine)
+    private Code(String function, int pars, Object value, int realLine, byte layer)
     {
         this.function = function;
         this.pars = pars;
         this.value = value;
         this.realLine = realLine;
+        this.layer = layer;
     }
     
-    public Code(String function, int pars, int realLine)
+    public Code(String function, int pars, int realLine, byte layer)
     {
-        this(function, pars, null, realLine);
+        this(function, pars, null, realLine, layer);
     }
     
-    public Code(Object value, int realLine)
+    public Code(Object value, int realLine, byte layer)
     {
-        this(null, 0, value, realLine);
+        this(null, 0, value, realLine, layer);
     }
     
     public void executeFunction(SnuviParser parser, Script sc, Stack<Object> stack)
@@ -73,39 +73,40 @@ public class Code
     @Override
     public String toString() 
     {
-        StringBuilder sb = new StringBuilder("(");
+        StringBuilder sb = new StringBuilder();
         sb.append(realLine);
-        sb.append(") ");
+        sb.append("| ");
+        
+        for(int i = -1; i < layer; i++)
+        {
+            sb.append('>');
+        }
+        sb.append(' ');
         
         if(function != null)
         {
-            sb.append("function '");
+            sb.append("call ");
             sb.append(function);
-            sb.append("' ");
-            for(int i = 0; i < pars; i++)
-            {
-                sb.append("X,");
-            }
-            if(pars > 0)
-            {
-                sb.deleteCharAt(sb.length() - 1);
-            }
+            sb.append(' ');
+            sb.append(pars);
+
             if(value != null)
             {
-                sb.append("(");
+                sb.append(" (");
                 sb.append(value);
                 sb.append(")");
             }
         }
         else
         {
-            sb.append("push '");
-            sb.append(value);
-            sb.append("' ");
+            sb.append("push ");
             if(value != null)
             {
                 sb.append(value.getClass().getSimpleName());
             }
+            sb.append(" '");
+            sb.append(value);
+            sb.append("'");
             return sb.toString();
         }
         return sb.toString();
@@ -122,7 +123,7 @@ public class Code
         int length = code.length();
         while(pos < length)
         {
-            if(!Character.isLetterOrDigit(code.charAt(pos)))
+            if(!Character.isLetterOrDigit(code.charAt(pos)) && code.charAt(pos) != '_')
             {
                 return pos;
             }
@@ -131,132 +132,6 @@ public class Code
         return -1;
     }
     
-    private static int findStartOfSyntax(StringBuilder code, int pos)
-    {
-        int bracketCounter = 0;
-        while(pos >= 0 && code.charAt(pos) == ' ')
-        {
-            pos--;
-        }
-        while(pos >= 0)
-        {
-            switch(code.charAt(pos))
-            {
-                case ';':
-                case '{':
-                case '}':
-                    if(bracketCounter != 0)
-                    {
-                        throw new PreScriptException(scriptName, countChar('\n', pos, code), "unbalanced ()"); 
-                    }
-                    return pos + 1;
-                case ' ':
-                case '+':
-                case '-':
-                case '*':
-                case '/':
-                case '^':
-                case '@':
-                case '=':
-                case '>':
-                case '<':
-                case '!':
-                case '%':
-                case ',':
-                case '&':
-                case '|':
-                    if(bracketCounter != 0)
-                    {
-                        break;
-                    }
-                    return pos + 1;
-                case ')':
-                    bracketCounter++;
-                    break;
-                case '(':
-                    if(bracketCounter == 0)
-                    {
-                        return pos + 1;
-                    }
-                    bracketCounter--;
-                    break;
-            }
-            pos--;
-        }
-        return 0;
-    }
-    
-    private static int findEndOfSyntax(StringBuilder code, int pos)
-    {
-        return findEndOfSyntax(code, pos, false);
-    }
-    
-    private static int findEndOfSyntax(StringBuilder code, int pos, boolean b)
-    {
-        int bracketCounter = 0;
-        char c;
-        while(pos < code.length() && code.charAt(pos) == ' ')
-        {
-            pos++;
-        }
-        while(pos < code.length())
-        {
-            c = code.charAt(pos);
-            if(b && c == '\n')
-            {
-                if(bracketCounter != 0)
-                {
-                    pos++;
-                    continue;
-                }
-                return pos;
-            }
-            switch(c)
-            {
-                case ';':
-                case '{':
-                case '}':
-                    if(bracketCounter != 0)
-                    {
-                        throw new PreScriptException(scriptName, countChar('\n', pos, code), "unbalanced ()"); 
-                    }
-                    return pos;
-                case ' ':
-                case '+':
-                case '-':
-                case '*':
-                case '/':
-                case '^':
-                case '@':
-                case '=':
-                case '>':
-                case '<':
-                case '!':
-                case '%':
-                case ',':
-                case '&':
-                case '|':
-                    if(bracketCounter != 0)
-                    {
-                        break;
-                    }
-                    return pos;
-                case '(':
-                    bracketCounter++;
-                    break;
-                case ')':
-                    if(bracketCounter == 0)
-                    {
-                        return pos;
-                    }
-                    bracketCounter--;
-                    break;
-            }
-            pos++;
-        }
-        return code.length();
-    }
-    
     private static int findChar(char c, StringBuilder code, int pos)
     {
         int length = code.length();
@@ -271,22 +146,6 @@ public class Code
         return -1;
     }
     
-    private static int findSyntax(String find, StringBuilder code, int pos)
-    {
-        int length = code.length();
-        String s = code.toString();
-        while(pos < length)
-        {
-            // additionel check for e.g. difference between + and +=
-            if(s.startsWith(find, pos) && !s.startsWith(find + "=", pos) && (pos == 0 || code.charAt(pos - 1) != '=')) 
-            {
-                return pos;
-            }
-            pos++;
-        }
-        return -1;
-    }
-    
     private static int findSyntaxIgnoreString(String find, StringBuilder code, int pos)
     {
         int length = code.length();
@@ -315,77 +174,6 @@ public class Code
         }
         return -1;
     }
-    
-    private static void changeBiSyntax(String syntax, String f, StringBuilder sb, boolean b)
-    {
-        int pos = -1;
-        int end;
-        int start;
-        int slength = syntax.length();
-        StringBuilder newSyntax;
-        while(pos < sb.length())
-        {
-            pos = findSyntax(syntax, sb, pos + 1);
-            if(pos == -1)
-            {
-                break;
-            }
-            start = findStartOfSyntax(sb, pos - 1);
-            end = findEndOfSyntax(sb, pos + slength);
-            newSyntax = new StringBuilder(f);
-            newSyntax.append("(");
-            if(b)
-            {
-                newSyntax.append("\"");
-            }
-            newSyntax.append(sb.substring(start, pos).trim());
-            if(b)
-            {
-                newSyntax.append("\"");
-            }
-            if(end > pos)
-            {
-                newSyntax.append(",");
-                newSyntax.append(sb.substring(pos + slength, end).trim());
-            }
-            newSyntax.append(")");
-            pos -= end - start - newSyntax.length();
-            //System.out.println(sb.substring(start, end) + "   ===>    " + newSyntax);
-            sb.replace(start, end, newSyntax.toString());    
-        }
-    }
-    
-    private static void changeUnSyntax(String syntax, String f, StringBuilder sb)
-    {
-        int pos = -1;
-        int end;
-        int start;
-        int slength = syntax.length();
-        String first;
-        StringBuilder newSyntax;
-        while(pos < sb.length())
-        {
-            pos = findSyntax(syntax, sb, pos + 1);
-            if(pos == -1)
-            {
-                break;
-            }
-            start = findStartOfSyntax(sb, pos - 1);
-            end = findEndOfSyntax(sb, pos + slength);
-            newSyntax = new StringBuilder("setvar(\"");
-            first = sb.substring(start, pos).trim();
-            newSyntax.append(first);
-            newSyntax.append("\",");
-            newSyntax.append(f);
-            newSyntax.append("(");
-            newSyntax.append(first);
-            newSyntax.append(",");
-            newSyntax.append(sb.substring(pos + slength, end).trim());
-            newSyntax.append("))");
-            pos -= end - start - newSyntax.length();
-            sb.replace(start, end, newSyntax.toString());
-        }
-    }
 
     public static int countChar(char find, int end, StringBuilder code)
     {
@@ -403,32 +191,7 @@ public class Code
         return counter;
     }
     
-    private static void addKeyWordBrackets(String keyWord, StringBuilder sb)
-    {
-        String with = keyWord + "()";
-        int length = keyWord.length();
-        int pos = 0;
-        while(true)
-        {
-            pos = sb.indexOf(keyWord, pos);
-            if(pos + length >= sb.length())
-            {
-                throw new PreScriptException(scriptName, countChar('\n', pos, sb), "unexpected keyword"); 
-            }
-            else if(pos == -1 || 
-                (pos >= 1 && Character.isLetterOrDigit(sb.charAt(pos - 1))) ||
-                (Character.isLetterOrDigit(sb.charAt(pos + length))))
-            {
-                break;
-            }
-            else if(sb.charAt(pos + length) != '(')
-            {
-                sb.replace(pos, pos + length, with);
-            }
-            pos += length;
-        }
-    }
-    
+    @SuppressWarnings("")
     private static String removeNonSyntax(String s)
     {
         StringBuilder sb = new StringBuilder(s);
@@ -448,21 +211,10 @@ public class Code
         return sb.toString();
     }
     
-    public static Code[] generate(SnuviParser parser, String scriptName, String code, HashMap<String, Integer> gotos)
+    private static void removeComments(StringBuilder sb)
     {
-        System.out.println("START GENERATE");
-        long startTime = System.currentTimeMillis();
-        
-        Code.scriptName = scriptName;
-        
         int old = 0;
         int pos;
-        StringBuilder sb = new StringBuilder(code);
-        
-        // ---------------------------------------------------------------------
-        // comments
-        // ---------------------------------------------------------------------
-        
         while(true)
         {
             old = findSyntaxIgnoreString("/*", sb, old);
@@ -493,12 +245,12 @@ public class Code
             }
             sb.delete(old, pos + 1);
         }
-        
-        // ---------------------------------------------------------------------
-        // replacing Strings with #... to get rid of " 
-        // ---------------------------------------------------------------------
-        
-        pos = 0;
+    }
+    
+    private static HashMap<String, String> replaceStrings(StringBuilder sb)
+    {
+        int old;
+        int pos = 0;
         String replacement;
         String text;
         int stringIndex = 0;
@@ -527,12 +279,13 @@ public class Code
             }
             pos++;
         }
-        
-        // ---------------------------------------------------------------------
-        // allowing labels without ;
-        // ---------------------------------------------------------------------
-        
-        old = 0;
+        return strings;
+    }
+    
+    private static void formatLabels(StringBuilder sb)
+    {
+        int pos;
+        int old = 0;
         while(true)
         {
             pos = findChar('@', sb, old);
@@ -552,58 +305,34 @@ public class Code
                 sb.insert(pos, ';');
             }
         }
+    }
+    
+    public static Code[] generate(SnuviParser parser, String scriptName, String code, HashMap<String, Integer> gotos)
+    {
+        System.out.print("Starting '" + scriptName + "' ... ");
+        long startTime = System.currentTimeMillis();
+        
+        Code.scriptName = scriptName;
+        
+        StringBuilder sb = new StringBuilder(code);
         
         // ---------------------------------------------------------------------
-        // allowing key words without ()
+        // comments
         // ---------------------------------------------------------------------
-
-        addKeyWordBrackets("else", sb);        
-        addKeyWordBrackets("try", sb);   
-        addKeyWordBrackets("catch", sb);   
+        
+        removeComments(sb);
         
         // ---------------------------------------------------------------------
-        // replacing of function syntax
+        // replacing Strings with #... to get rid of " 
         // ---------------------------------------------------------------------
- 
-        changeBiSyntax("^", "math.pow", sb, false);
-        changeBiSyntax("/", "div", sb, false);
-        changeBiSyntax("%", "math.mod", sb, false);
-        changeBiSyntax("*", "mul", sb, false);
-        changeBiSyntax("-", "sub", sb, false);
-        changeBiSyntax("+", "add", sb, false);
-
-        changeBiSyntax("==", "equal", sb, false);
-        changeBiSyntax("!=", "notequal", sb, false);
-        changeBiSyntax("<", "less", sb, false);
-        changeBiSyntax(">", "greater", sb, false);
-        changeBiSyntax(">=", "greaterequal", sb, false);
-        changeBiSyntax("<=", "lessequal", sb, false);
-
-        changeBiSyntax("||", "or", sb, false);
-        changeBiSyntax("&&", "and", sb, false);
-
-        changeUnSyntax("+=", "add", sb);
-        changeUnSyntax("-=", "sub", sb);
-        changeUnSyntax("/=", "div", sb);
-        changeUnSyntax("*=", "mul", sb);
-
-        changeBiSyntax("=", "setvar", sb, true); 
+        
+        HashMap<String, String> strings = replaceStrings(sb);
         
         // ---------------------------------------------------------------------
-        // numbers like -5 turn to sub(,5) --> fixing
+        // allowing labels without ;
         // ---------------------------------------------------------------------
         
-        pos = 0;
-        while(true)
-        {
-            pos = findSyntax("sub(,", sb, pos);
-            if(pos == -1)
-            {
-                break;
-            }
-            sb.insert(pos + 4, '0');
-            pos++;
-        }
+        formatLabels(sb);
         
         code = sb.toString();
         
@@ -614,8 +343,8 @@ public class Code
         ArrayList<String> lines = new ArrayList<>();
         int lineCounter = 1;
         ArrayList<Integer> realCodeLine = new ArrayList<>();
-        old = 0;
-        pos = 0;
+        int old = 0;
+        int pos = 0;
         int length = code.length();
         int counter = 0;
         int bracketCounter = 0;
@@ -689,26 +418,34 @@ public class Code
         // ---------------------------------------------------------------------
         // generating byte code
         // ---------------------------------------------------------------------
-        
+
+        LineCompiler compiler = new LineCompiler(parser, scriptName);
         ArrayList<Code> co = new ArrayList<>();    
-        Stack<Integer> parCounter = new Stack<>();
-        char current;
-        char previous;
-        int layer = 0;
         int line;
-        boolean noFunction;
-        LinkedList<Integer> whileStart = new LinkedList<>();
+        byte layer = 0;
         String s;
         for(int i = 0; i < lines.size(); i++)
         {
             s = lines.get(i);
-            if(s.isEmpty())
+            //System.out.println(s);
+            if(s.isEmpty() || s.equals("{"))
             {
                 continue;
             }
-            else if(s.startsWith("while"))
+            else if(lines.get(Math.min(i + 1, lines.size() - 1)).equals("{"))
+            {
+                layer++;
+                if(s.equals("try") || s.equals("catch") || s.equals("else"))
+                {
+                    co.add(new Code(s, 0, realCodeLine.get(i), layer));
+                    continue;
+                }
+            }
+            else if(s.equals("}"))
             {
-                whileStart.push(co.size());
+                layer--;
+                co.add(new Code("gotoline", 0, realCodeLine.get(i), layer));
+                continue;
             }
             else if(s.charAt(0) == '@')
             {
@@ -716,68 +453,8 @@ public class Code
                 continue;
             }
             line = realCodeLine.get(i);
-            previous = ',';
-            noFunction = true;
-            pos = s.length() - 1;
-            while(pos >= 0)
-            {
-                current = s.charAt(pos);
-                switch(current)
-                {
-                    case ')':
-                        parCounter.add(0);
-                        if(previous != ',' && previous != ')')
-                        {
-                            throw new PreScriptException(scriptName, line, "unexpected )");
-                        }
-                        old = pos;
-                        break;
-                    case '(':
-                        if(previous != ')')
-                        {
-                            parCounter.set(parCounter.size() - 1, parCounter.lastElement() + 1);
-                            if(noFunction)
-                            {
-                                co.add(new Code(Code.convertInput(strings, s.substring(pos + 1, old), true), line));
-                            }
-                        }
-                        old = pos;
-                        pos--;
-                        while(pos >= 0 && (Character.isLetterOrDigit(s.charAt(pos)) 
-                                || s.charAt(pos) == '_' || s.charAt(pos) == '.'))
-                        {
-                            pos--;
-                        }
-                        pos++;
-                        String functionName = s.substring(pos, old).toLowerCase();
-                        if(!parser.isRegisteredFunction(functionName))
-                        {
-                            throw new NoSuchMethodException(scriptName, line, functionName);
-                        }
-                        co.add(new Code(functionName, parCounter.pop(), line));
-                        noFunction = false;
-                        break;
-                    case ',':
-                        parCounter.set(parCounter.size() - 1, parCounter.lastElement() + 1);
-                        if(noFunction)
-                        {
-                            co.add(new Code(Code.convertInput(strings, s.substring(pos + 1, old), true), line));
-                        }
-                        old = pos;
-                        noFunction = true;
-                        break;
-                    case '{':
-                        layer++;
-                        co.add(new Code("goto", 0, layer, line));
-                        break;
-                    case '}':
-                        co.add(new Code("goto", 0, layer, line));
-                        layer--;
-                        break;
-                }
-                pos--;
-                previous = current;
-            }
+            compiler.reset(line, layer, s);
+            compiler.compile(co, strings);
         }
         
         // ---------------------------------------------------------------------
@@ -785,49 +462,74 @@ public class Code
         // ---------------------------------------------------------------------
         
         Code[] c = co.toArray(new Code[co.size()]);
+        //java.util.Arrays.stream(c).forEach(cod -> System.out.println(cod.toString()));
+        
+        //System.exit(0);
+        int oldLayer = 0;
+        int newLayer;
         for(int i = 0; i < c.length; i++)
         {
-            if("goto".equals(c[i].function) && c[i].value != null)
+            newLayer = c[i].layer;
+            if(oldLayer < newLayer)
             {
-                Object value = c[i].value;
-                if((int) value <= 0)
+                int j = findKeyWord(i, c);
+                if(j == 0)
                 {
-                    continue;
+                    //java.util.Arrays.stream(c).forEach(cod -> System.out.println(cod.toString()));
+                    throw new PreScriptException(scriptName, c[i].realLine, "well, fuck this, this should never happen");
                 }
-                for(int j = i + 1; j < c.length; j++)
+                boolean jumpBack = j < 0;
+                j = Math.abs(j);
+                int k;
+                for(k = j; k < c.length; k++)
                 {
-                    if(value.equals(c[j].value))
+                    if(c[k].layer < newLayer)
                     {
-                        c[i].value = j - i;
-                        switch(c[i-1].function)
-                        {   
-                            case "while":
-                                c[j].value = whileStart.pollLast() - j - 1;
-                                break;
-                            /*case "if":
-                            case "else":
-                            case "try":
-                            case "catch":
-                                c[j].value = 0;
-                                break;*/
-                            default:
-                                c[j].value = 0;
-                                break;
-                        }
                         break;
                     }
                 }
-            }        
+                c[j].value = k - j;
+                if(jumpBack)
+                {
+                    c[k].value = i - k - 1;
+                }
+                else
+                {
+                    c[k].value = 0;
+                }
+            }
+            oldLayer = newLayer;
         }
 
         // end
-        System.out.println("END GENERATE - " + (System.currentTimeMillis() - startTime));  
+        System.out.println((System.currentTimeMillis() - startTime) + " ms");  
         //java.util.Arrays.stream(c).forEach(cod -> System.out.println(cod.toString()));
         //gotos.forEach((k, v) -> System.out.println("Lable " + k + "   " + v));   
         //System.exit(0);
         return c;
     }     
     
+    private static int findKeyWord(int start, Code[] c)
+    {
+        for(int j = start; j < c.length; j++)
+        {
+            if(c[j].function != null)
+            {
+                switch(c[j].function)
+                {
+                    case "while":
+                        return -j;
+                    case "if":
+                    case "else":
+                    case "try":
+                    case "catch":
+                        return j;
+                }
+            }
+        }
+        return 0;
+    }
+    
     public static Object convertInput(HashMap<String, String> map, String s, boolean variable)
     {
         if(s == null)
@@ -895,3 +597,4 @@ public class Code
         return convertInput(null, s, false);
     }
 }
+// 916

+ 2 - 2
src/me/hammerle/code/ISnuviLogger.java

@@ -2,8 +2,8 @@ package me.hammerle.code;
 
 public interface ISnuviLogger 
 {
-    public void printException(Exception ex, String scriptname, int line);
-    public void printException(Exception ex, Script s, int line);
+    public void printException(Exception ex, String function, String scriptname, int line);
+    public void printException(Exception ex, String function, Script s, int line);
     
     public void printWarning(String s);
     public void printInfo(String s);

+ 237 - 0
src/me/hammerle/code/LineCompiler.java

@@ -0,0 +1,237 @@
+package me.hammerle.code;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Stack;
+import me.hammerle.exceptions.NoSuchMethodException;
+import me.hammerle.exceptions.PreScriptException;
+import me.hammerle.math.Fraction;
+
+public class LineCompiler 
+{
+    private int realLine;
+    // counts brackets to know if we are in a function
+    private int bracketCounter;
+    // last special character to stop push
+    private final Stack<Integer> lastSpecial;
+    // comma counter, for functions
+    private final Stack<Integer> commaCounter;
+    // store for adding function on next successfull push
+    private final HashMap<Integer, String> nextFunction;
+    // stores if a function was just called
+    private boolean function;
+    
+    private String line;
+    private byte layer;
+    
+    private SnuviParser parser;
+    private String scriptName;
+    
+    public LineCompiler(SnuviParser parser, String scriptName)
+    {
+        realLine = 0;
+        bracketCounter = 0;
+        lastSpecial = new Stack<>();
+        commaCounter = new Stack<>();
+        nextFunction = new HashMap<>();
+        function = false;
+        line = "";
+        layer = 0;
+        this.parser = parser;
+        this.scriptName = scriptName;
+    }
+
+    public void reset(int realLine, byte layer, String line) 
+    {
+        this.realLine = realLine;
+        bracketCounter = 0;
+        lastSpecial.clear();
+        lastSpecial.push(line.length());
+        commaCounter.clear();
+        nextFunction.clear();
+        function = false;
+        this.line = line;
+        this.layer = layer;
+    }
+    
+    private boolean push(HashMap<String, String> strings, ArrayList<Code> co, int index)
+    {
+        if(function)
+        {
+            //System.out.println("push last result");
+            if(index + 1 != lastSpecial.peek())
+            {
+                co.add(new Code(Code.convertInput(strings, line.substring(index + 1, lastSpecial.pop()), true), realLine, layer));
+            }
+        }
+        else
+        {
+            co.add(new Code(Code.convertInput(strings, line.substring(index + 1, lastSpecial.pop()), true), realLine, layer));
+        }
+        String sNextFunction = nextFunction.remove(bracketCounter);
+        if(sNextFunction != null)
+        {
+            if(sNextFunction.equals("sub") && !co.isEmpty())
+            {
+                Code c = co.get(co.size() - 1);
+                if("".equals(c.value))
+                {
+                    c.value = new Fraction(0);
+                }
+            }
+            co.add(new Code(sNextFunction, 2, realLine, layer));
+            return true;
+        }
+        return false;
+    }
+    
+    private boolean isAllowedChar(char c)
+    {
+        return Character.isLetterOrDigit(c) || c == '.' || c == '_';
+    }
+    
+    public void compile(ArrayList<Code> co, HashMap<String, String> strings)
+    {
+        int old;
+        int j = line.length() - 1;    
+        int commas;
+        String syntax;
+        while(j >= 0)
+        {
+            syntax = null;
+            switch(line.charAt(j))
+            {
+                case '+': syntax = "add"; break;
+                case '-': syntax = "sub"; break;
+                case '*': syntax = "mul"; break;
+                case '/': syntax = "div"; break;
+                case '%': syntax = "math.mod"; break;
+                case '^': syntax = "math.pow"; break;
+                case '<': syntax = "less"; break;
+                case '>': syntax = "greater"; break;
+                /* 
+                    changeBiSyntax("||", "or", sb, false);
+                    changeBiSyntax("&&", "and", sb, false);
+                */  
+                case '=':
+                {
+                    char before = line.charAt(j - 1);
+                    switch(before)
+                    {
+                        case '=': syntax = "equal"; break;
+                        case '!': syntax = "notequal"; break;
+                        case '>': syntax = "greaterequal"; break;
+                        case '<': syntax = "lessequal"; break;
+                    }
+                    if(syntax != null)
+                    {
+                        function = push(strings, co, j);
+                        nextFunction.put(bracketCounter, syntax);
+                        j--;
+                        lastSpecial.push(j);
+                        j--;
+                        continue;
+                    }
+                    function = push(strings, co, j);
+                    //if(function)
+                    //{
+                        //System.out.println("push last result");
+                    //}
+                    int checker = j - 2;
+                    while(checker >= 0)
+                    {
+                        if(!isAllowedChar(line.charAt(checker)))
+                        {
+                            throw new PreScriptException(scriptName, realLine, "unexpected character");
+                        }
+                        checker--;
+                    }
+                    String var;
+                    switch(before)
+                    {
+                        case '+': syntax = "add"; break;
+                        case '-': syntax = "sub"; break;
+                        case '*': syntax = "mul"; break;
+                        case '/': syntax = "div"; break;
+                        default:
+                            var = line.substring(0, j);
+                            co.add(new Code(var, realLine, layer));
+                    }
+                    if(syntax != null)
+                    {
+                        var = line.substring(0, j - 1);
+                        co.add(new Code(Code.convertInput(strings, var, true), realLine, layer));
+                        co.add(new Code(syntax, 2, realLine, layer));
+                        //System.out.println("push last result");
+                        co.add(new Code(var, realLine, layer));
+                    }
+                    co.add(new Code("setvar", 2, realLine, layer));
+                    j = -1;
+                    continue;
+                }
+                case ')':
+                {
+                    bracketCounter++;
+                    lastSpecial.push(j);
+                    commaCounter.push(0);
+                    break;
+                }
+                case ',':
+                {
+                    commaCounter.push(commaCounter.pop() + 1);
+                    function = push(strings, co, j);
+                    lastSpecial.push(j);
+                    break;
+                }
+                case '(':
+                {
+                    commas = commaCounter.pop() + 1;
+                    //if(function)
+                    //{
+                        //System.out.println("push last result");
+                    //}
+                    if(line.charAt(j + 1) != ')')
+                    {
+                        if(j + 1 != lastSpecial.peek())
+                        {
+                            co.add(new Code(Code.convertInput(strings, line.substring(j + 1, lastSpecial.pop()), true), realLine, layer));
+                        }
+                    }
+                    else
+                    {
+                        commas = 0;
+                    }
+                    String sNextFunction = nextFunction.remove(bracketCounter);
+                    if(sNextFunction != null)
+                    {
+                        co.add(new Code(sNextFunction, 2, realLine, layer));
+                        //System.out.println("push last result");
+                    }
+                    bracketCounter--;
+                    function = true;
+                    old = j;
+                    j--;
+                    while(j >= 0 && isAllowedChar(line.charAt(j)))
+                    {
+                        j--;
+                    }
+                    j++;
+                    String functionName = line.substring(j, old);
+                    if(!parser.isRegisteredFunction(functionName))
+                    {
+                        throw new NoSuchMethodException(scriptName, realLine, functionName);
+                    }
+                    co.add(new Code(functionName, commas, realLine, layer));
+                    lastSpecial.push(j);
+                }
+            }
+            if(syntax != null)
+            {
+                function = push(strings, co, j);
+                nextFunction.put(bracketCounter, syntax);
+                lastSpecial.push(j);
+            }
+            j--;
+        }
+    }
+}

+ 9 - 12
src/me/hammerle/code/Script.java

@@ -227,7 +227,7 @@ public class Script
                 isRunning = false;
                 if(ex.getClass() != HoldCodeException.class)
                 {
-                    parser.logger.printException(ex, this, getActiveRealCodeLine());
+                    parser.logger.printException(ex, code[position].function, this, getActiveRealCodeLine());
                 }
                 position++;
             }
@@ -286,7 +286,7 @@ public class Script
         if(loopCounter > 50)
         {
             resetLoopCounter();
-            parser.logger.printException(new CodeTooLongException(), this, getActiveRealCodeLine());
+            parser.logger.printException(new CodeTooLongException(), null, this, getActiveRealCodeLine());
             throw new HoldCodeException();
         }
     }
@@ -311,7 +311,7 @@ public class Script
         }
         catch(NullPointerException ex)
         {
-            parser.logger.printException(new GotoLabelNotFoundException(label), this, getActiveRealCodeLine());
+            parser.logger.printException(new GotoLabelNotFoundException(label), "goto", this, getActiveRealCodeLine());
             throw new HoldCodeException();
         }
     }  
@@ -332,21 +332,21 @@ public class Script
         position = returnStack.pop(); 
     }
     
-    public void jump(int i)
+    public void jump()
     {
-        position += i;
+        position += (int) code[position].value;
     }
     
-    public void jumpNextDoElse()
+    public void jumpDoElse()
     {
+        position += (int) code[position].value;
         if(code.length <= position + 1)
         {
             return;
         }
-        position += (int) code[position + 1].value + 1;
         if("else".equals(code[position + 1].function))
         {
-            position += 2;
+            position++;
         }
     }
     
@@ -361,14 +361,11 @@ public class Script
     
     public void saveTryJumpLine()
     {
-        System.out.println("WUSI");
-        tryJumpLine = position + ((int) code[position + 1].value) + 2;
+        tryJumpLine = position + ((int) code[position].value) + 1;
         if(!"catch".equals(code[tryJumpLine].function))
         {
             throw new IllegalStateException("try without catch");
         }
-        tryJumpLine++;
-        System.out.println(tryJumpLine);
     }
     
     public void resetTryJumpLine()

+ 99 - 16
src/me/hammerle/code/SnuviParser.java

@@ -24,6 +24,7 @@ import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import jdk.internal.org.objectweb.asm.tree.JumpInsnNode;
 import me.hammerle.exceptions.FileIOException;
 import me.hammerle.exceptions.PreScriptException;
 import me.hammerle.math.Fraction;
@@ -93,6 +94,11 @@ public class SnuviParser
                 0);
         registerFunction("", (args, sc) -> 
                 args[0]);
+        registerConsumer("gotoline", (args, sc) -> 
+                {
+                    sc.jump();
+                    sc.incLoopCounter();
+                });
         registerConsumer("error", (args, sc) -> 
                 printStack = !printStack);       
         
@@ -212,6 +218,68 @@ public class SnuviParser
                 Collections.reverse((List<Object>) args[0])); 
         registerConsumer("list.shuffle", (args, sc) ->                            
                 Collections.shuffle((List<Object>) args[0]));
+        
+        // -------------------------------------------------------------------------------  
+        // arrays
+        // -------------------------------------------------------------------------------    
+        registerConsumer("array.new", (args, sc) ->                                                
+                sc.setVar(args[0].toString(), new Object[ScriptUtils.getInt(args[1])]));
+        registerConsumer("array.set", (args, sc) ->                            
+                ((Object[]) args[0])[ScriptUtils.getInt(args[1])] = args[2]);
+        registerFunction("array.get", (args, sc) ->                            
+                ((Object[]) args[0])[ScriptUtils.getInt(args[1])]);
+        registerFunction("array.getsize", (args, sc) ->                            
+                ((Object[]) args[0]).length);
+        registerConsumer("array.swap", (args, sc) ->                                           
+                {
+                    Object[] o = (Object[]) args[0];
+                    int first = ScriptUtils.getInt(args[1]);
+                    int sec = ScriptUtils.getInt(args[2]);
+                    Object helper = o[first];
+                    o[first] = o[sec];
+                    o[sec] = helper;
+                });
+        registerConsumer("array.sort", (args, sc) ->  
+                {
+                    if(args.length <= 1)
+                    {
+                        Arrays.sort((Object[]) args[0]);
+                    }
+                    else
+                    {
+                        Arrays.sort((Object[]) args[0], ScriptUtils.getInt(args[1]), ScriptUtils.getInt(args[2]));
+                    }
+                });
+        registerConsumer("array.copy", (args, sc) ->  
+                {
+                    int first = ScriptUtils.getInt(args[2]);
+                    System.arraycopy((Object[]) args[0], first, (Object[]) args[1], 
+                            ScriptUtils.getInt(args[4]), ScriptUtils.getInt(args[3]) - first + 1);
+                });
+        registerConsumer("array.rsort", (args, sc) ->    
+                {
+                    if(args.length <= 1)
+                    {
+                        Arrays.sort((Object[]) args[0], (Object o, Object o1) -> -((Comparable) o).compareTo(o));
+                    }
+                    else
+                    {
+                        Arrays.sort((Object[]) args[0], ScriptUtils.getInt(args[1]), 
+                                ScriptUtils.getInt(args[2]), (Object o, Object o1) -> -((Comparable) o).compareTo(o)); 
+                    }
+                });
+        registerConsumer("array.fill", (args, sc) ->     
+                {
+                    if(args.length <= 2)
+                    {
+                        Arrays.fill((Object[]) args[0], args[1]);
+                    }
+                    else
+                    {
+                        Arrays.fill((Object[]) args[0], ScriptUtils.getInt(args[1]), ScriptUtils.getInt(args[2]), args[1]); 
+                    }
+                });
+                
 
         // -------------------------------------------------------------------------------  
         // maps
@@ -232,6 +300,10 @@ public class SnuviParser
                 ((HashMap) args[0]).get(args[1]));
         registerConsumer("map.clear", (args, sc) ->                            
                 ((HashMap) args[0]).clear());
+        registerConsumer("map.keys", (args, sc) ->                            
+                sc.setVar(args[0].toString(), ((HashMap) args[1]).keySet().stream().collect(Collectors.toList())));
+        registerConsumer("map.values", (args, sc) ->                            
+                sc.setVar(args[0].toString(), ((HashMap) args[1]).values().stream().collect(Collectors.toList())));
         
         // -------------------------------------------------------------------------------  
         // sets
@@ -315,6 +387,10 @@ public class SnuviParser
                 args[0].toString().trim());
         registerFunction("text.charat", (args, sc) ->         
                 String.valueOf(args[0].toString().charAt(getInt(args[1]))));
+        registerFunction("text.charcode", (args, sc) ->         
+                new Fraction(args[0].toString().charAt(getInt(args[1]))));
+        registerFunction("text.fromcode", (args, sc) ->         
+                new String(new char[] {(char) ScriptUtils.getInt(args[0])}));
         
         // -------------------------------------------------------------------------------    
         // files
@@ -371,13 +447,16 @@ public class SnuviParser
         registerConsumer("return", (args, sc) -> 
                 sc.doReturn());
         registerConsumer("try", (args, sc) -> 
-                {sc.saveTryJumpLine(); sc.jump(1);});                   
+                sc.saveTryJumpLine());                   
         registerConsumer("catch", (args, sc) -> 
-                sc.resetTryJumpLine());
+                {
+                    sc.resetTryJumpLine();
+                    sc.jump();
+                });
         registerConsumer("if", (args, sc) -> 
                 ifFunction(args, sc));   
         registerConsumer("else", (args, sc) -> 
-                {});   
+                sc.jump());   
         registerConsumer("while", (args, sc) -> 
                 whileFunction(args, sc)); 
         registerFunction("equal", (args, sc) -> 
@@ -403,6 +482,14 @@ public class SnuviParser
                 waitFor(args, sc));
         registerConsumer("term", (args, sc) -> 
                 { termSafe(sc); throw new HoldCodeException(); }); 
+        registerConsumer("swap", (args, sc) ->                                           
+                {
+                    String first = args[0].toString();
+                    String sec = args[1].toString();
+                    Object helper = sc.getVar(first);
+                    sc.setVar(first, sc.getVar(sec));
+                    sc.setVar(sec, helper);
+                });
     }
     
     @SuppressWarnings("unchecked")
@@ -429,7 +516,7 @@ public class SnuviParser
                 sc.resetTryJumpLine();
                 return Void.TYPE;
             }
-            logger.printException(ex, sc, sc.getActiveRealCodeLine());
+            logger.printException(ex, function, sc, sc.getActiveRealCodeLine());
             sc.resetLoopCounter();
             throw new HoldCodeException();
         }
@@ -509,7 +596,7 @@ public class SnuviParser
         }
         catch(PreScriptException ex)
         {
-            logger.printException(ex, script, ex.getLine());
+            logger.printException(ex, null, script, ex.getLine());
             return null;
         }
     }
@@ -537,10 +624,10 @@ public class SnuviParser
                 {
                     if(t instanceof PreScriptException)
                     {
-                        logger.printException((Exception) t, scriptName, ((PreScriptException) t).getLine());
+                        logger.printException((Exception) t, null, scriptName, ((PreScriptException) t).getLine());
                         return null;
                     }
-                    logger.printException((Exception) t, scriptName, -1);
+                    logger.printException((Exception) t, null, scriptName, -1);
                     return null;
                 }
             }
@@ -626,19 +713,15 @@ public class SnuviParser
     {
         if(Arrays.stream(args).anyMatch(s -> !((boolean) s)))
         {
-            sc.jumpNextDoElse();
-        }
-        else
-        {
-            sc.jump(1);
+            sc.jumpDoElse();
         }
     }  
     
     private void whileFunction(Object[] args, Script sc)
     {
-        if(Arrays.stream(args).allMatch(s -> ((boolean) s)))
+        if(Arrays.stream(args).anyMatch(s -> !((boolean) s)))
         {
-            sc.jump(1);
+            sc.jump();
         }
     } 
                   
@@ -668,7 +751,7 @@ public class SnuviParser
             }
             catch(Exception ex)
             {
-                logger.printException(ex, sc, sc.getActiveRealCodeLine());
+                logger.printException(ex, "sgoto", sc, sc.getActiveRealCodeLine());
             }
         }, time);
     }
@@ -764,7 +847,7 @@ public class SnuviParser
                     throw new FileIOException(ex.getMessage());
                 }
             }
-            Files.write(Paths.get(f.toURI()), (List<String>) args[1], StandardCharsets.UTF_8);
+            Files.write(Paths.get(f.toURI()), (List) args[1], StandardCharsets.UTF_8);
         }
         catch(UnsupportedOperationException | SecurityException | IOException ex)
         {

+ 59 - 31
src/me/hammerle/snuviscript/SnuviScript.java

@@ -13,14 +13,14 @@ public class SnuviScript
         ISnuviLogger logger = new ISnuviLogger() 
         {
             @Override
-            public void printException(Exception ex, Script s, int line) 
+            public void printException(Exception ex, String function, Script s, int line) 
             {
                 System.out.println("Exception " + ex);
                 System.out.println("Line: " + line);
             }
 
             @Override
-            public void printException(Exception ex, String s, int line) 
+            public void printException(Exception ex, String function, String s, int line) 
             {
                 System.out.println("Exception " + ex + " " + s + " " + line);
             }
@@ -58,40 +58,68 @@ public class SnuviScript
         parser.registerConsumer("deb.ug", (o, sc) -> System.out.println(o[0]));
         //parser.registerFunction("ggv", (o, sc) -> o[0]);
         //parser.registerFunction("read.item", (o, sc) -> o[0]);
-        
-        /*StringBuilder sb = new StringBuilder("wusi = 1;\n");
-        int counter = 0;
-        for(int i = 0; i < 1000; i++)
+             
+        /*for(int j = 1; j < Integer.MAX_VALUE; j *= 2)
         {
-            switch(counter)
+            System.out.println("Size " + j);
+            StringBuilder sb = new StringBuilder("error(); wusi = 1;\n");
+            sb.append("time = time.get();");
+            int counter = 0;
+            for(int i = 0; i < j; i++)
             {
-                case 0: sb.append("wusi += 1;\n"); break;
-                case 1: sb.append("wusi *= 2;\n"); break;
-                case 2: sb.append("wusi = wusi - 1;\n"); break;
-                case 3: sb.append("wusi /= 2;\n"); break;
-                case 4: sb.append("wusi += 1;\n"); break;
+                switch(counter)
+                {
+                    case 0: sb.append("wusi += 1;\n"); break;
+                    case 1: sb.append("wusi *= 2;\n"); break;
+                    case 2: sb.append("wusi = wusi - 1;\n"); break;
+                    case 3: sb.append("wusi /= 2;\n"); break;
+                    case 4: sb.append("wusi += 1;\n"); break;
+                }
+                counter++;
+                if(counter >= 5)
+                {
+                    counter = 0;
+                }
             }
-            counter++;
-            if(counter >= 5)
+            sb.append("debug(wusi);");
+            sb.append("debug(concat(\"time \", time.get() - time));");*/
+
+            /*String s = "debug(\"Start\");\n" +
+    "wusi = time.get();\n" +
+    "if(wusi >= 0)\n" +
+    "{\n" +
+    "    debug(\"ja\");\n" +
+    "    while(wusi < 10)\n" +
+    "    {\n" +
+    "        hallo = wusi;\n" +
+    "        while(hallo < 3)\n" +
+    "        {\n" +
+    "            debug(\"hallo\");\n" +
+    "            hallo += 1;\n" +
+    "        }\n" +
+    "        debug(wusi);\n" +
+    "        wusi += 1;\n" +
+    "    }\n" +
+    "}\n" +
+    "else\n" +
+    "{\n" +
+    "    debug(\"nein\");\n" +
+    "}\n" +
+    "debug(\"Ende\");";*/
+            String s = "debug(add(1, 1));";
+            //String s = "error(); debug(1+1);";
+            //System.out.println(s);
+            //System.out.println("___________");
+            //parser.startScript(Script.class, "test", sb.toString(), true);
+            try
             {
-                counter = 0;
+                parser.startScript("test", s.toString());
             }
-        }
-        sb.append("debug(wusi);");*/
-        
-        String s = "debug(catcher);";
-        //System.out.println(s);
-        //System.out.println("___________");
-        //parser.startScript(Script.class, "test", sb.toString(), true);
-        try
-        {
-            parser.startScript("test", s);
-        }
-        catch(PreScriptException ex)
-        {
-            //ex.printStackTrace();
-            logger.printException(ex, "test", ex.getLine());
-        }
+            catch(PreScriptException ex)
+            {
+                logger.printException(ex, "none" , "test", ex.getLine());
+            }
+        //}
         //parser.getScript(0).runCode();
 
         //Fraction f = Fraction.fromDouble(Fraction.PI.doubleValue());