Browse Source

Verbesserung der Console(Formatierung), Implementierung aller Befehle im Parser + neue für das Starten / Stoppen von Scripts, Code-Flow-Handler, Exception-Handling

Kajetan Johannes Hammerle 8 years ago
parent
commit
00c3123abe

+ 0 - 3
nbproject/private/private.xml

@@ -3,9 +3,6 @@
     <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>
-            <file>file:/Users/kajetanjohannes/Dropbox/Projekte/Informatik/SnuviScript/src/me/hammerle/snuviscript/SnuviScript.java</file>
-            <file>file:/Users/kajetanjohannes/Dropbox/Projekte/Informatik/SnuviScript/src/me/hammerle/code/CodeParser.java</file>
-            <file>file:/Users/kajetanjohannes/Dropbox/Projekte/Informatik/SnuviScript/src/me/hammerle/code/Code.java</file>
             <file>file:/Users/kajetanjohannes/Dropbox/Projekte/Informatik/SnuviScript/src/me/hammerle/code/Script.java</file>
         </group>
     </open-files>

+ 45 - 11
src/me/hammerle/code/Code.java

@@ -2,8 +2,8 @@ package me.hammerle.code;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Stack;
-import me.hammerle.math.Fraction;
 
 public class Code implements Comparable<Code>
 {
@@ -19,7 +19,14 @@ public class Code implements Comparable<Code>
     
     public Code(String function, int level, int pars, int line, int subline, Object value, int jump)
     {
-        this.function = function;
+        if(function != null)
+        {
+            this.function = function.toLowerCase();
+        }
+        else
+        {
+            this.function = null;
+        }
         this.level = level;
         this.pars = pars;
         this.line = line;
@@ -40,6 +47,7 @@ public class Code implements Comparable<Code>
     
     public void executeFunction(Script sc, Stack<Object> stack)
     {
+        //System.out.println("AUSFÜHRUNG: " + this.toString());
         if(value != null)
         {
             if(value.getClass() == Variable.class)
@@ -50,7 +58,7 @@ public class Code implements Comparable<Code>
             stack.push(value);
             return;
         }
-        Object[] input = null;
+        Object[] input;
         if(pars > 0)
         {
             input = new Object[pars];
@@ -59,12 +67,21 @@ public class Code implements Comparable<Code>
                 input[i] = stack.pop();
             }
         }
-        Object output = CodeParser.parseFunction(sc, function, input, jump);
+        else
+        {
+            input = new Object[0];
+        }
+        Object output = CodeParser.parseFunction(sc, function, input);
         if(output != Void.TYPE)
         {
             stack.push(output);
         }
     }
+    
+    public String getFunction()
+    {
+        return function;
+    }
 
     @Override
     public String toString() 
@@ -120,6 +137,11 @@ public class Code implements Comparable<Code>
         return i;
     }
     
+    public int getJumpLine()
+    {
+        return jump;
+    }
+    
     // -----------------------------------------------------------------------------------
     // Code-Builder
     // -----------------------------------------------------------------------------------
@@ -128,6 +150,7 @@ public class Code implements Comparable<Code>
     
     private static int findEndOfLine(String code, int pos)
     {
+        int start = pos;
         int length = code.length();
         char c;
         boolean text = false;
@@ -151,13 +174,14 @@ public class Code implements Comparable<Code>
             }
             pos++;
         }
-        return -1;
+        return start;
     }
     
-    public static Code[] generate(String code)
+    public static Code[] generate(String code, HashMap<String, Integer> gotos)
     {
         ArrayList<Code> list = new ArrayList<>();
         sublines = 0;
+        String actual;
         int length = code.length();
         int level = 1;
         int pos = 0;
@@ -167,11 +191,18 @@ public class Code implements Comparable<Code>
         {
             old = pos;
             pos = findEndOfLine(code, pos);
+            actual = code.substring(old, pos).trim();
+            if(actual.startsWith("@"))
+            {
+                gotos.put(actual.substring(1), line);
+                pos++;
+                continue;
+            }
             switch(code.charAt(pos))
             {
                 case '{':
                     line++;
-                    splitFunctions(list, code.substring(old, pos).trim(), level, line);
+                    splitFunctions(list, actual, level, line);
                     level++;
                     break;
                 case '}': 
@@ -179,7 +210,7 @@ public class Code implements Comparable<Code>
                     break;
                 case ';': 
                     line++;
-                    splitFunctions(list, code.substring(old, pos).trim(), level, line);
+                    splitFunctions(list, actual, level, line);
                     break;
             }
             pos++;
@@ -198,6 +229,7 @@ public class Code implements Comparable<Code>
             switch(function)
             {
                 case "if":
+                case "else":
                 case "while":
                 case "try":
                 case "catch":
@@ -220,7 +252,9 @@ public class Code implements Comparable<Code>
             }
         }
         
-        list.forEach(c -> System.out.println(c.toString()));
+        //list.forEach(c -> System.out.println(c.toString()));
+        //gotos.forEach((k, v) -> System.out.println(k + "   " + v));
+        //System.exit(0);
         return list.toArray(new Code[list.size()]);
     } 
     
@@ -358,7 +392,7 @@ public class Code implements Comparable<Code>
         splitted.forEach(s -> splitFunctions(list, s, level, line));
     }
      
-    private static Object convertInput(String s)
+    public static Object convertInput(String s)
     {
         if(s == null)
         {
@@ -387,7 +421,7 @@ public class Code implements Comparable<Code>
         }
         try
         {
-            return new Fraction(Long.parseLong(s));
+            return Double.parseDouble(s);
         }
         catch(NumberFormatException ex)
         {

+ 463 - 311
src/me/hammerle/code/CodeParser.java

@@ -1,380 +1,532 @@
 package me.hammerle.code;
 
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
+import me.hammerle.exceptions.HoldCodeException;
 import me.hammerle.exceptions.IllegalStringException;
+import me.hammerle.exceptions.NoSuchMethodException;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Calendar;
+import java.util.Collections;
 import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
-import java.awt.Font;
-import javax.imageio.ImageIO;
-import me.hammerle.exceptions.IllegalColorException;
-import me.hammerle.graphics.*;
-import me.hammerle.snuviscript.SnuviScript;
+import java.util.function.BiFunction;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+import me.hammerle.console.ConsoleUtils;
+import me.hammerle.scheduler.SnuviScheduler;
 
 public class CodeParser 
-{    
-    @SuppressWarnings("unchecked")
-    public static Object parseFunction(Script sd, String function, Object[] args, int jump)
+{
+    private final static HashMap<String, BiFunction<Object[], Script, Object>> METHODS = new HashMap<>();
+    
+    private static void registerFunction(String s, BiFunction<Object[], Script, Object> f)
     {
-        try
+        METHODS.put(s, f);
+    }
+    
+    private static void registerConsumer(String s, BiConsumer<Object[], Script> f)
+    {
+        METHODS.put(s, (BiFunction<Object[], Script, Object>) (args, sc) -> 
         {
-            switch(function.toLowerCase())
-            {       
-                // Rechenoperationen
-                /*case "add":
-                    return args.stream().mapToDouble(s -> ScriptUtils.getDouble(s)).sum();
-                case "sub":
-                    return ScriptUtils.getDouble(args.get(0)) - ScriptUtils.getDouble(args.get(1));
-                case "mul":
-                    return ScriptUtils.getDouble(args.get(0)) * ScriptUtils.getDouble(args.get(1));
-                case "div":
-                    return ScriptUtils.getDouble(args.get(0)) / ScriptUtils.getDouble(args.get(1));
-                case "math.mod":
-                    return ScriptUtils.getDouble(args.get(0)) % ScriptUtils.getDouble(args.get(1));
-                case "math.abs":
-                    return Math.abs(ScriptUtils.getDouble(args.get(0)));
-                case "math.pow":
-                    return Math.pow(ScriptUtils.getDouble(args.get(0)), ScriptUtils.getDouble(args.get(1)));
-                case "math.root":
-                    return Math.pow(ScriptUtils.getDouble(args.get(0)), 1d / ScriptUtils.getDouble(args.get(1)));
-                case "math.sin":
-                    return Math.sin(ScriptUtils.getDouble(args.get(0)));
-                case "math.cos":
-                    return Math.cos(ScriptUtils.getDouble(args.get(0)));
-                case "math.e":
-                    return Math.E;
-                case "math.pi":
-                    return Math.PI;
-                case "math.ln":
-                    return Math.log(ScriptUtils.getDouble(args.get(0)));
-                case "math.log":
-                    return Math.log10(ScriptUtils.getDouble(args.get(0)));
-                case "math.random":
-                    return ScriptUtils.randomInt(ScriptUtils.getInteger(args.get(0)), ScriptUtils.getInteger(args.get(1)));
-                case "math.round":
-                    return ((Long) Math.round(ScriptUtils.getDouble(args.get(0)))).intValue();
-                case "math.rounddown":
-                    return Math.floor(ScriptUtils.getDouble(args.get(0)));
-                case "math.roundup":
-                    return Math.ceil(ScriptUtils.getDouble(args.get(0)));
-                case "math.roundcomma":
-                    return new BigDecimal(ScriptUtils.getDouble(args.get(0))).setScale(ScriptUtils.getInteger(args.get(1)), RoundingMode.HALF_UP);
-
-                // Variablen
-                case "getvar":
-                    return sd.getVar(args.get(0));
-                case "setvar":
-                    sd.setVar(args.get(0), args.get(1)); break;
-                case "removevar":
-                    sd.removeVar(args.get(0)); break;          
-
-                // Listen - Befehle                         
-                case "list.new":                                               
-                    sd.setVar(args.get(0), new ArrayList<>()); break; 
-                case "list.exists":                                               
-                    return sd.getVar(args.get(0)) instanceof List;
-                case "list.add":  
-                    ((List) sd.getVar(args.get(0))).add(args.get(1)); break;
-                case "list.remove":          
-                    ((List) sd.getVar(args.get(0))).remove(args.get(1)); break;
-                case "list.removeindex":           
-                    ((List) sd.getVar(args.get(0))).remove((int) args.get(1)); break;                
-                case "list.contains":                           
-                    return ((List) sd.getVar(args.get(0))).contains(args.get(1));
-                case "list.size":                           
-                    return ((List) sd.getVar(args.get(0))).size();
-                case "list.get":                           
-                    return ((List) sd.getVar(args.get(0))).get((int) args.get(1));
-                case "list.set":                           
-                    ((List) sd.getVar(args.get(0))).set((int) args.get(1), args.get(2)); break;
-                case "list.indexof":                           
-                    return ((List) sd.getVar(args.get(0))).indexOf(args.get(1));
-                case "list.sort": 
-                    sortList(args, sd); break;
-                case "list.reverse":          
-                    Collections.reverse((List<Object>) sd.getVar(args.get(0))); break;
-                case "list.shuffle":                           
-                    Collections.shuffle((List<Object>) sd.getVar(args.get(0))); break;
-
-                // Maps - Befehle                         
-                case "map.new":                                               
-                    sd.setVar(args.get(0), new HashMap<>()); break;
-                case "map.exists":                                               
-                    return sd.getVar(args.get(0)) instanceof HashMap; 
-                case "map.add":                           
-                    ((HashMap) sd.getVar(args.get(0))).put(args.get(1), args.get(2)); break;
-                case "map.remove":                           
-                    ((HashMap) sd.getVar(args.get(0))).remove(args.get(1)); break;
-                case "map.contains":                         
-                    return ((HashMap) sd.getVar(args.get(0))).containsKey(args.get(1));
-                case "map.get":                           
-                    return ((HashMap) sd.getVar(args.get(0))).get(args.get(1));
-
-                // Grafik
-                case "repaint":
-                    SnuviScript.screen.graphics.repaint(); break;
-                case "drawline":
-                    SnuviScript.screen.graphics.addGraphicObject(ScriptUtils.getInteger(args.get(0)), 
-                            new Line(ScriptUtils.getColor(args.get(1)),
-                            ScriptUtils.getInteger(args.get(2)), ScriptUtils.getInteger(args.get(3)),
-                            ScriptUtils.getInteger(args.get(4)), ScriptUtils.getInteger(args.get(5)))); break;
-                case "drawoval":
-                    SnuviScript.screen.graphics.addGraphicObject(ScriptUtils.getInteger(args.get(0)), 
-                            new Oval(ScriptUtils.getColor(args.get(1)),
-                            ScriptUtils.getInteger(args.get(2)), ScriptUtils.getInteger(args.get(3)),
-                            ScriptUtils.getInteger(args.get(4)), ScriptUtils.getInteger(args.get(5)))); break;
-                case "drawrec":
-                    SnuviScript.screen.graphics.addGraphicObject(ScriptUtils.getInteger(args.get(0)), 
-                            new Rectangle(ScriptUtils.getColor(args.get(1)),
-                            ScriptUtils.getInteger(args.get(2)), ScriptUtils.getInteger(args.get(3)),
-                            ScriptUtils.getInteger(args.get(4)), ScriptUtils.getInteger(args.get(5)))); break;
-                case "drawfulloval":
-                    SnuviScript.screen.graphics.addGraphicObject(ScriptUtils.getInteger(args.get(0)), 
-                            new FullOval(ScriptUtils.getColor(args.get(1)),
-                            ScriptUtils.getInteger(args.get(2)), ScriptUtils.getInteger(args.get(3)),
-                            ScriptUtils.getInteger(args.get(4)), ScriptUtils.getInteger(args.get(5)))); break;
-                case "drawfullrec":
-                    SnuviScript.screen.graphics.addGraphicObject(ScriptUtils.getInteger(args.get(0)), 
-                            new FullRectangle(ScriptUtils.getColor(args.get(1)),
-                            ScriptUtils.getInteger(args.get(2)), ScriptUtils.getInteger(args.get(3)),
-                            ScriptUtils.getInteger(args.get(4)), ScriptUtils.getInteger(args.get(5)))); break;
-                case "drawimage":
-                    drawImage(args); break;  
-                case "drawstring":
-                    drawString(args); break;
-                case "removegraphic":
-                    SnuviScript.screen.graphics.removeGraphicObject(ScriptUtils.getInteger(args.get(0))); break;
-                case "buffergraphic":
-                    SnuviScript.screen.graphics.loadGraphicObjectIntoBuffer(ScriptUtils.getInteger(args.get(0))); break;
-                case "setcolor":
-                    SnuviScript.screen.graphics.getBuffer().setColor(ScriptUtils.getColor(args.get(0))); break;
-                case "setx":
-                    ((StartPoint) SnuviScript.screen.graphics.getBuffer()).setX(ScriptUtils.getInteger(args.get(0))); break;
-                case "sety":
-                    ((StartPoint) SnuviScript.screen.graphics.getBuffer()).setY(ScriptUtils.getInteger(args.get(0))); break;
-                case "setx1":
-                    ((Line) SnuviScript.screen.graphics.getBuffer()).setFirstX(ScriptUtils.getInteger(args.get(0))); break;
-                case "sety1":
-                    ((Line) SnuviScript.screen.graphics.getBuffer()).setFirstY(ScriptUtils.getInteger(args.get(0))); break;
-                case "setx2":
-                    ((Line) SnuviScript.screen.graphics.getBuffer()).setSecondX(ScriptUtils.getInteger(args.get(0))); break;
-                case "sety2":
-                    ((Line) SnuviScript.screen.graphics.getBuffer()).setSecondY(ScriptUtils.getInteger(args.get(0))); break; 
-                case "setscreensize":
-                    SnuviScript.screen.setSize(ScriptUtils.getInteger(args.get(0)), ScriptUtils.getInteger(args.get(1)));
-                    SnuviScript.screen.graphics.setSize(SnuviScript.screen.getWidth(), SnuviScript.screen.getHeight() - 22); break;
-                case "getscreenx":
-                    return SnuviScript.screen.graphics.getWidth();
-                case "getscreeny":
-                    return SnuviScript.screen.graphics.getHeight();
+            f.accept(args, sc);
+            return Void.TYPE;
+        });
+    }
+    
+    private static void registerAlias(String s, String original)
+    {
+        registerFunction(s, METHODS.get(original)); 
+    }
+    
+    @SuppressWarnings("unchecked")
+    public static void initCodeParser()
+    {
+        registerFunction("nothing", (args, sc) -> 
+                0);
+        
+        // -------------------------------------------------------------    
+        // Script-Consolen-Bibliothek 
+        // -------------------------------------------------------------  
+        registerConsumer("script.list", (args, sc) -> 
+                { ScriptUtils.printDebug("The following scripts are active:"); ScriptControl.getScripts().forEach(s -> ScriptUtils.printDebug(s.getId() + " | " + s.getName()));}); 
+        registerConsumer("script.load", (args, sc) -> 
+                ScriptControl.startScriptFromFile(args[0].toString())); 
+        registerConsumer("clear", (args, sc) -> 
+                ConsoleUtils.clear()); 
+        registerConsumer("script.term", (args, sc) -> 
+                termScript(args, sc)); 
+        
+        // -------------------------------------------------------------    
+        // Event-Bibliothek 
+        // -------------------------------------------------------------  
+        registerConsumer("event.load", (args, sc) -> 
+                sc.loadEvent(args[0].toString())); 
+        registerConsumer("event.unload", (args, sc) -> 
+                sc.unloadEvent(args[0].toString())); 
+        registerFunction("event.isloaded", (args, sc) -> 
+                sc.isLoadedEvent(args[0].toString())); 
 
-                // Allgemeines
-                case "debug":
-                    System.out.println(args.get(0));
-                    break;
-                case "loadlib":
-                    sd.loadLibrary(args.get(0)); break;
-                case "lib":
-                    SnuviScript.scriptController.startLibrary(qd, args); return false;
-                case "reset":
-                    sd.resetOverflowProtection(); break;                   
-                case "wait":
-                    sd.resetOverflowProtection(); return false; 
-                case "term":
-                    SnuviScript.scriptController.term(sd); return false;
-                case "exit":
-                    System.exit(0); return false;
-                case "loadevent":
-                    sd.loadEvent(args.get(0)); break; 
-                case "unloadevent":
-                    sd.unloadEvent(args.get(0)); break; 
-                case "goto":
-                    sd.gotoLabel(args.get(0).toString()); break;
-                case "sgoto":
-                    scheduleGoto(args, sd); break;                    
+        // -------------------------------------------------------------    
+        // Mathe-Bibliothek 
+        // -------------------------------------------------------------    
+        registerFunction("math.mod", (args, sc) -> 
+                ((double) args[0]) % ((double) args[1]));
+        registerFunction("math.abs", (args, sc) -> 
+                Math.abs((double) args[0]));
+        registerFunction("math.pow", (args, sc) -> 
+                Math.pow((double) args[0], (double) args[1]));
+        registerFunction("math.root", (args, sc) -> 
+                Math.pow((double) args[0], 1d / ((double) args[1])));
+        registerFunction("math.sin", (args, sc) -> 
+                Math.sin((double) args[0]));
+        registerFunction("math.cos", (args, sc) -> 
+                Math.cos((double) args[0]));
+        registerFunction("math.tan", (args, sc) -> 
+                Math.tan((double) args[0]));
+        registerFunction("math.asin", (args, sc) -> 
+                Math.asin((double) args[0]));
+        registerFunction("math.acos", (args, sc) -> 
+                Math.acos((double) args[0]));
+        registerFunction("math.atan", (args, sc) -> 
+                Math.atan((double) args[0]));
+        registerFunction("math.e", (args, sc) -> 
+                Math.E);
+        registerFunction("math.pi", (args, sc) -> 
+                Math.PI);
+        registerFunction("math.ln", (args, sc) -> 
+                Math.log((double) args[0]));
+        registerFunction("math.log", (args, sc) -> 
+                Math.log10((double) args[0]));
+        registerFunction("math.random", (args, sc) -> 
+                ScriptUtils.randomInt(getInt(args[0]), getInt(args[1])));
+        registerFunction("math.round", (args, sc) -> 
+                Math.round((double) args[0]));
+        registerFunction("math.rounddown", (args, sc) -> 
+                Math.floor((double) args[0]));
+        registerFunction("math.roundup", (args, sc) -> 
+                Math.ceil((double) args[0]));
+        registerFunction("math.roundcomma", (args, sc) -> 
+                new BigDecimal(((double) args[0])).setScale(getInt(args[1]), RoundingMode.HALF_UP).doubleValue());
+        
+        // -------------------------------------------------------------  
+        // Listen-Bibliothek   
+        // -------------------------------------------------------------    
+        registerConsumer("list.new", (args, sc) ->                                                
+                sc.setVar(args[0].toString(), new ArrayList<>()));
+        registerFunction("list.exists", (args, sc) ->                                                
+                args[0] instanceof List); 
+        registerConsumer("list.add", (args, sc) ->                            
+                ((List) args[0]).add(args[1]));
+        registerConsumer("list.remove", (args, sc) ->                            
+                ((List) args[0]).remove(args[1]));
+        registerConsumer("list.removeindex", (args, sc) ->                            
+                ((List) args[0]).remove(getInt(args[1])));                
+        registerFunction("list.contains", (args, sc) ->                            
+                ((List) args[0]).contains(args[1]));
+        registerFunction("list.getsize", (args, sc) ->                            
+                ((List) args[0]).size());
+        registerFunction("list.getindex", (args, sc) ->                            
+                ((List) args[0]).get(getInt(args[1])));
+        registerConsumer("list.setindex", (args, sc) ->                            
+                ((List) args[0]).set(getInt(args[1]), args[2]));
+        registerConsumer("list.clear", (args, sc) ->                            
+                ((List) args[0]).clear());
+        registerFunction("list.getindexof", (args, sc) ->                            
+                ((List) args[0]).indexOf(args[1]));  
+        registerConsumer("list.sort", (args, sc) ->  
+                sortList((List<Object>) args[0], sc));
+        registerConsumer("list.reverse", (args, sc) ->                            
+                Collections.reverse((List<Object>) args[0])); 
+        registerConsumer("list.shuffle", (args, sc) ->                            
+                Collections.shuffle((List<Object>) args[0]));
 
-                // Conditions
-                case "if":
-                    ifFunction(args, sd); break;   
-                case "equal":
-                    return ((Comparable) args.get(0)).compareTo(args.get(1)) == 0;
-                case "less":
-                    return ((Comparable) args.get(0)).compareTo(args.get(1)) == -1;
-                case "greater":
-                    return ((Comparable) args.get(0)).compareTo(args.get(1)) == 1;
-                case "notequal":
-                    return ((Comparable) args.get(0)).compareTo(args.get(1)) != 0;
-                case "lessequal":
-                    return ((Comparable) args.get(0)).compareTo(args.get(1)) <= 0;
-                case "greaterequal":
-                    return ((Comparable) args.get(0)).compareTo(args.get(1)) >= 0;
-                case "invert":
-                    return args.stream().allMatch(s -> s.equals(true));
-                case "and":
-                    return args.stream().allMatch(s -> s.equals(true));
-                case "or":
-                    return args.stream().anyMatch(s -> s.equals(true));
-                    
-                // Sonstiges
-                case "concatlist":                           
-                    return String.join("", ((List) sd.getVar(args.get(0))).subList(ScriptUtils.getInteger(args.get(1)), ScriptUtils.getInteger(args.get(2))));
-                case "concatlistspace":                           
-                    return String.join(" ", ((List) sd.getVar(args.get(0))).subList(ScriptUtils.getInteger(args.get(1)), ScriptUtils.getInteger(args.get(2))));
-                case "split":  
-                    sd.setVar(args.get(0), new ArrayList<>(Arrays.asList(args.get(2).toString().split(args.get(1).toString())))); break;
-                case "concat":                           
-                    return args.stream().map(o -> o.toString()).collect(Collectors.joining());
-                case "concatspace":                           
-                    return args.stream().map(o -> o.toString()).collect(Collectors.joining(" "));
-                case "tolowercase":                           
-                    return args.get(0).toString().toLowerCase();
-                case "touppercase":                           
-                    return args.get(0).toString().toUpperCase();
+        // -------------------------------------------------------------  
+        // Map-Bibliothek   
+        // ------------------------------------------------------------- 
+        registerConsumer("map.new", (args, sc) ->                                                
+                sc.setVar(args[0].toString(), new HashMap<>())); 
+        registerFunction("map.exists", (args, sc) ->                                                
+                args[0] instanceof HashMap);  
+        registerConsumer("map.add", (args, sc) ->                            
+                ((HashMap) args[0]).put(args[1], args[2]));
+        registerConsumer("map.remove", (args, sc) ->                            
+                ((HashMap) args[0]).remove(args[1]));
+        registerFunction("map.contains", (args, sc) ->                            
+                ((HashMap) args[0]).containsKey(args[1]));
+        registerFunction("map.getsize", (args, sc) ->                            
+                ((HashMap) args[0]).size());
+        registerFunction("map.get", (args, sc) ->                            
+                ((HashMap) args[0]).get(args[1]));
+        registerConsumer("map.clear", (args, sc) ->                            
+                ((HashMap) args[0]).clear());
+        
+        // -------------------------------------------------------------  
+        // Set-Bibliothek   
+        // ------------------------------------------------------------- 
+        registerConsumer("set.new", (args, sc) ->                                                
+                sc.setVar(args[0].toString(), new HashSet<>())); 
+        registerFunction("set.exists", (args, sc) ->                                                
+                args[0] instanceof HashSet);  
+        registerConsumer("set.add", (args, sc) ->                            
+                ((HashSet) args[0]).add(args[1]));
+        registerConsumer("set.remove", (args, sc) ->                            
+                ((HashSet) args[0]).remove(args[1]));
+        registerFunction("set.contains", (args, sc) ->                            
+                ((HashSet) args[0]).contains(args[1]));
+        registerFunction("set.getsize", (args, sc) ->                            
+                ((HashSet) args[0]).size());
 
-                case "gettime":                           
-                    return System.currentTimeMillis(); 
-                case "nextday":        
-                    return getNextDay(args, sd);   
-                case "waitfor":    
-                    return waitFor(args, sd);
+        // -------------------------------------------------------------  
+        // Time-Bibliothek   
+        // -------------------------------------------------------------
+        registerFunction("time.get", (args, sc) ->                            
+                System.currentTimeMillis());
+        registerFunction("time.nextday", (args, sc) ->         
+                getNextDay(args));   
+        registerFunction("time.getyear", (args, sc) ->         
+                getYear(args));   
+        registerFunction("time.getmonth", (args, sc) ->         
+                getMonth(args));   
+        registerFunction("time.getday", (args, sc) ->         
+                getDay(args));   
+        registerFunction("time.gethour", (args, sc) ->         
+                getHour(args));   
+        registerFunction("time.getminute", (args, sc) ->         
+                getMinute(args));   
+        registerFunction("time.getsecond", (args, sc) ->         
+                getSecond(args));                   
 
-                // Is Valid Checker    
-                case "isvalidnumber":
-                    return generalValidChecker(() -> ScriptUtils.getDouble(args.get(0)));*/
+        // -------------------------------------------------------------    
+        // Ohne Bibliothek
+        // -------------------------------------------------------------    
+        registerFunction("add", (args, sc) -> 
+                Arrays.stream(args).mapToDouble(s -> (double) s).sum());
+        registerFunction("sub", (args, sc) -> 
+                ((double) args[0]) - ((double) args[1]));
+        registerFunction("inc", (args, sc) -> 
+                increaseVar(args[0], sc, 1)); 
+        registerFunction("dec", (args, sc) -> 
+                increaseVar(args[0], sc, -1));
+        registerFunction("mul", (args, sc) -> 
+                ((double) args[0]) * ((double) args[1]));
+        registerFunction("div", (args, sc) -> 
+                ((double) args[0]) / ((double) args[1]));
+        registerFunction("getvar", (args, sc) -> 
+                sc.getVar(args[0].toString()));
+        registerConsumer("setvar", (args, sc) -> 
+                sc.setVar(args[0].toString(), args[1]));
+        registerConsumer("removevar", (args, sc) -> 
+                sc.removeVar(args[0].toString()));
+        registerConsumer("debug", (args, sc) -> 
+                ConsoleUtils.sendMessage(ScriptUtils.connect(args, 0), null));
+        registerConsumer("reset", (args, sc) -> 
+                sc.resetLoopCounter());
+        registerConsumer("wait", (args, sc) -> 
+                { sc.resetLoopCounter(); throw new HoldCodeException(); });
+        registerConsumer("goto", (args, sc) -> 
+                sc.gotoLabel(args[0].toString()));
+        registerConsumer("sgoto", (args, sc) -> 
+                scheduleGoto(args, sc));
+        registerConsumer("gosub", (args, sc) -> 
+                sc.gotoLabelWithReturn(args[0].toString()));
+        registerConsumer("return", (args, sc) -> 
+                sc.doReturn());
+        registerConsumer("try", (args, sc) -> 
+                sc.saveTryJumpLine());                   
+        registerConsumer("catch", (args, sc) -> 
+                sc.gotoSpecialJumpLine());
+        registerConsumer("if", (args, sc) -> 
+                ifFunction(args, sc));   
+        registerConsumer("else", (args, sc) -> 
+                sc.gotoSpecialJumpLine());   
+        registerConsumer("while", (args, sc) -> 
+                whileFunction(args, sc)); 
+        registerFunction("equal", (args, sc) -> 
+                isEqual(args));
+        registerAlias("equals", "equal");
+        registerFunction("less", (args, sc) -> 
+                (double) args[0] < (double) args[1]);
+        registerFunction("greater", (args, sc) -> 
+                (double) args[0] > (double) args[1]);
+        registerFunction("notequal", (args, sc) -> 
+                !isEqual(args));
+        registerFunction("lessequal", (args, sc) -> 
+                (double) args[0] <= (double) args[1]);
+        registerFunction("greaterequal", (args, sc) -> 
+                (double) args[0] >= (double) args[1]);
+        registerFunction("invert", (args, sc) -> 
+                !((boolean) args[0]));
+        registerFunction("and", (args, sc) -> 
+                Arrays.stream(args).allMatch(s -> s.equals(true)));
+        registerFunction("or", (args, sc) -> 
+                Arrays.stream(args).anyMatch(s -> s.equals(true)));
+        registerFunction("concatlist", (args, sc) ->      
+                ((List<Object>) args[0]).stream().limit(getInt(args[3]) + 1).skip(getInt(args[2])).map(o -> o.toString()).collect(Collectors.joining(args[1].toString())));
+        registerConsumer("split", (args, sc) ->      
+                split(args, sc));             
+        registerFunction("concat", (args, sc) ->                            
+                ScriptUtils.connect(args, 0));
+        registerFunction("tolowercase", (args, sc) ->                            
+                ScriptUtils.connect(args, 0).toLowerCase());
+        registerFunction("touppercase", (args, sc) ->                            
+                ScriptUtils.connect(args, 0).toUpperCase());   
+        registerConsumer("waitfor", (args, sc) ->     
+                waitFor(args, sc));
+    }
+    
+    public static boolean printStack = false;
 
-                default:
-                    throw new NoSuchMethodException();                      
+    @SuppressWarnings("unchecked")
+    public static Object parseFunction(Script sc, String function, Object[] args) throws HoldCodeException
+    {
+        try
+        {
+            BiFunction<Object[], Script, Object> f = METHODS.get(function);
+            if(f == null)
+            {
+                throw new NoSuchMethodException(function);
             }
+            return METHODS.get(function).apply(args, sc);
         }
         catch(Exception ex)
         {
-            //ex.printStackTrace();
-            printQuestException(sd, ex, function);
-            return null;
+            if(ex instanceof HoldCodeException)
+            {
+                throw ex;
+            }
+            if(printStack)
+            {
+                ex.printStackTrace();
+            }
+            if(sc.getTryJumpLine() != -1)
+            {
+                sc.setVar("error", ex.getClass().getSimpleName());
+                sc.gotoTryJumpLine();
+                sc.resetTryJumpLine();
+                return Void.TYPE;
+            }
+            printQuestException(sc, ex, function + "(" + Arrays.stream(args).map(o -> String.valueOf(o)).collect(Collectors.joining(", ")) + ")");  
+            throw new HoldCodeException();
         }
     }
     
-    public static void printQuestException(Script sd, Exception ex, String line)
+    public static void printQuestException(Script sc, Exception ex, String line)
     {
-        sd.resetLoopCounter();
-        ScriptUtils.printDebug("Error in");
-        ScriptUtils.printDebugList("Script: " + sd.getName());
-        ScriptUtils.printDebugList("Zeile: " + line);
-        ScriptUtils.printDebugList("Exception: " + ex.getClass().getSimpleName());
+        sc.resetLoopCounter();
+        ScriptUtils.printError("Error in");
+        ScriptUtils.printErrorList("Script", sc.getName());
+        ScriptUtils.printErrorList("Zeile", line);
+        ScriptUtils.printErrorList("Zeilennummer", sc.getActiveCodeLine());
+        if(ex.getLocalizedMessage() == null)
+        {
+            ScriptUtils.printErrorList("Exception", ex.getClass().getSimpleName());
+        }
+        else
+        {
+            ScriptUtils.printErrorList("Exception", ex.getClass().getSimpleName() + " - " + ex.getLocalizedMessage());
+        }
         if(ex instanceof IllegalStringException)
         {
-            ScriptUtils.printDebugList("Ungültiger Wert: " + ((IllegalStringException) ex).getBadString());
+            ScriptUtils.printErrorList("Ungültiger Wert", ((IllegalStringException) ex).getBadString());
         }
     }
     
-    // -----------------------
-    // Script Befehle
-    // -----------------------
+    // -----------------------------------------------------------------------------------
+    // Functions
+    // -----------------------------------------------------------------------------------
     
-    private static void drawImage(List<Object> args) throws IOException 
+    private static void termScript(Object[] args, Script sc)
     {
-        BufferedImage image = ImageIO.read(new File(args.get(1).toString()));
-        if(args.size() >= 5)
+        if(args.length == 0)
+        {
+            ScriptControl.term(sc);
+            throw new HoldCodeException();
+        }
+        else if(args[0].toString().equals("all"))
         {
-            SnuviScript.screen.graphics.addGraphicObject(ScriptUtils.getInteger(args.get(0)), 
-                    new Image(image, ScriptUtils.getInteger(args.get(2)), ScriptUtils.getInteger(args.get(3)),        
-                    ScriptUtils.getInteger(args.get(4)), ScriptUtils.getInteger(args.get(5)),
-                    ScriptUtils.getInteger(args.get(6)), ScriptUtils.getInteger(args.get(7))));
-            return;
-        } 
-        SnuviScript.screen.graphics.addGraphicObject(ScriptUtils.getInteger(args.get(0)), 
-                    new Image(image, ScriptUtils.getInteger(args.get(2)), ScriptUtils.getInteger(args.get(3))));
+            ScriptControl.termScripts();
+            throw new HoldCodeException();
+        }
+        else
+        {
+            int i = getInt(args[0]);
+            ScriptControl.term(ScriptControl.getScript(i));
+            if(sc.getId() == i)
+            {
+                throw new HoldCodeException();
+            }
+        }
     }
     
-    private static void drawString(List<Object> args) throws IllegalColorException
+    private static void ifFunction(Object[] args, Script sc)
     {
-        SnuviScript.screen.graphics.addGraphicObject(ScriptUtils.getInteger(args.get(0)), 
-                new Text(ScriptUtils.getColor(args.get(1)), 
-                ScriptUtils.getInteger(args.get(2)), ScriptUtils.getInteger(args.get(3)),        
-                args.get(4).toString(), new Font(args.get(5).toString(), ScriptUtils.getInteger(args.get(6)), ScriptUtils.getInteger(args.get(7)))));
-    }
-
-    private static void ifFunction(List<Object> args, Script sd)
+        if(Arrays.stream(args).anyMatch(s -> (boolean) s == false))
+        {
+            sc.gotoSpecialJumpLine();
+            sc.jumpNextIfElse();
+        }
+    }  
+    
+    private static void whileFunction(Object[] args, Script sc)
     {
-        if(args.stream().allMatch(s -> s.equals(true)))
+        if(Arrays.stream(args).anyMatch(s -> (boolean) s == false))
         {
-            //sd.goDeeper();
+            sc.gotoSpecialJumpLine();
         }
-    }
+    } 
                   
-    private static void sortList(List<Object> args, Script sd) 
-    {     
-        //List<Object> list = (List<Object>) sd.getVar(args.get(0));
-        //sd.setVar(args.get(0), list.stream().sorted().collect(Collectors.toList()));
+    @SuppressWarnings(value = "unchecked")
+    private static void sortList(List<Object> args, Script sc) 
+    {
+        Collections.sort(args, (Object o1, Object o2) -> ((Comparable) o1).compareTo(o2));
     }
-                   
-    private static void scheduleGoto(List<Object> args, Script qd)
+    
+    private static void scheduleGoto(Object[] args, Script sc)
     {
-        /*SnuviScheduler.doScheduledTask(() -> 
+        SnuviScheduler.doScheduledTask(() -> 
         {
-            if(!sd.isValid())
+            if(!sc.isValid())
             {
                 return;
             }
             try
             {
-                sd.setCodeLine(sd.getGoto(args.get(0)));
-                continueCode(qd, null);
+                sc.gotoLabel(args[1].toString());
+                sc.setHalt(true);
+                sc.runCode();
             }
-            catch(GotoLabelNotFoundException ex)
+            catch(Exception ex)
             {
-                ScriptUtilities.printDebugMessage("Das Scheduled-Goto '" + args.get(0) + "' wurde nicht gefunden.");
+                printQuestException(sc, ex, "(Scheduled Goto)");
             }
-        }, Integer.parseInt(args.get(1)));*/
+        }, getInt(args[0]));
     }
-
-    private static String getNextDay(List<Object> args, Script qd)       
-    {
-        GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
-        cal.setTimeInMillis(Long.parseLong(args.get(0).toString()));
-        cal.set(Calendar.HOUR, 0);
-        cal.set(Calendar.SECOND, 0);
-        cal.set(Calendar.MINUTE, 0);
-        cal.set(Calendar.MILLISECOND, 0);
-        cal.add(Calendar.DAY_OF_YEAR, 1);
-        return String.valueOf(cal.getTimeInMillis());   
-    } 
     
-    private static boolean waitFor(List<Object> args, Script qd) throws UnsupportedOperationException
+    private static void waitFor(Object[] args, Script sc) throws UnsupportedOperationException
     {           
-        /*SnuviScript.scriptController.resetOverflowProtection();
-        int i = Integer.parseInt(args.get(0));
+        sc.resetLoopCounter();
+        int i = getInt(args[0]);
         if(i < 1)
         {
             throw new UnsupportedOperationException();
         }
+        sc.setHalt(true);
         SnuviScheduler.doScheduledTask(() -> 
         {                   
-            if(qd == null || !sd.isValid())
+            if(sc == null || !sc.isValid())
             {
                 return;
             }
-            sd.setWaiting(false);
-            sd.nextCodeLine();
-            continueCode(qd, null);
+            sc.setHalt(false);
+            sc.runCode();
         }, i); 
-        sd.setWaiting(true);*/
-        return false;
-    }
-
-    private static boolean generalValidChecker(Runnable r)
+        throw new HoldCodeException();
+    }   
+    
+    private static Number increaseVar(Object var, Script sc, int value)
     {
-        try
+        double n = ((double) sc.getVar(var.toString())) + value;
+        sc.setVar(var.toString(), n);
+        return n;
+    }   
+    
+    private static boolean isEqual(Object[] args)
+    {
+        if(args[0] == null)
         {
-            r.run();
-            return true;
+            return args[1] == null;
         }
-        catch(Exception ex)
+        else if(args[1] == null)
         {
-            return false;
+            return args[0] == null;
         }
+        else if(args[1] instanceof Number && args[0] instanceof Number)
+        {
+            return ((Number) args[0]).doubleValue() == ((Number) args[1]).doubleValue();
+        }
+        return args[0].equals(args[1]);
+    }
+    
+    private static void split(Object[] args, Script sc)
+    {
+        String[] parts = ScriptUtils.connect(args, 2).split(args[1].toString());
+        ArrayList<Object> list = new ArrayList<>();
+        for(String s : parts)
+        {
+            list.add(Code.convertInput(s));
+        }
+        sc.setVar(args[0].toString(), list);
     }   
-}
+    
+    // -------------------------------------------------------------------------    
+    // Int-Handler, weil die Objekte double immer zu Double konvertieren
+    // ------------------------------------------------------------------------- 
+    
+    private static int getInt(Object o)
+    {
+        return ((Double) o).intValue();
+    }
+    
+    // -------------------------------------------------------------------------    
+    // Zeit-Handler
+    // ------------------------------------------------------------------------- 
+    
+    private static long getNextDay(Object[] args)       
+    {
+        GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
+        cal.setTimeInMillis((long) args[0]);
+        cal.add(Calendar.DAY_OF_YEAR, 1);
+        cal.set(Calendar.HOUR, 0);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MINUTE, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        return cal.getTimeInMillis();   
+    } 
+    
+    private static int getYear(Object[] args)       
+    {
+        GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
+        cal.setTimeInMillis((long) args[0]);
+        return cal.get(Calendar.YEAR);   
+    }
+    
+    private static int getMonth(Object[] args)       
+    {
+        GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
+        cal.setTimeInMillis((long) args[0]);
+        return cal.get(Calendar.MONTH) + 1;   
+    }
+    
+    private static int getDay(Object[] args)       
+    {
+        GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
+        cal.setTimeInMillis((long) args[0]);
+        return cal.get(Calendar.DAY_OF_MONTH);   
+    }
+    
+    private static int getHour(Object[] args)       
+    {
+        GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
+        cal.setTimeInMillis((long) args[0]);
+        return cal.get(Calendar.HOUR_OF_DAY);   
+    }
+    
+    private static int getMinute(Object[] args)       
+    {
+        GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
+        cal.setTimeInMillis((long) args[0]);
+        return cal.get(Calendar.MINUTE);   
+    }
+    
+    private static int getSecond(Object[] args)       
+    {
+        GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
+        cal.setTimeInMillis((long) args[0]);
+        return cal.get(Calendar.SECOND);   
+    }
+}

+ 141 - 4
src/me/hammerle/code/Script.java

@@ -1,6 +1,8 @@
 package me.hammerle.code;
 
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Stack;
 import me.hammerle.exceptions.CodeTooLongException;
 import me.hammerle.exceptions.GotoLabelNotFoundException;
 
@@ -11,12 +13,20 @@ public class Script
 
     private final HashMap<String, Object> variables;    
     private final HashMap<String, Integer> gotos;
+    private final HashSet<String> events;
+    private final Stack<Object> valueStack;
+    private final Stack<Integer> returnStack;
     
     private final Code[] code;
     private int position;
 
     private int loopCounter;
     
+    private boolean halt;
+    private boolean valid;
+    
+    private int tryJumpLine;
+    
     public Script(int id, String name, String code)
     {       
         this.id = id;
@@ -24,12 +34,20 @@ public class Script
         
         variables = new HashMap<>();
         gotos = new HashMap<>();
+        events = new HashSet<>();
+        valueStack = new Stack<>();
+        returnStack = new Stack<>();
         
-        this.code = Code.generate(code);
+        this.code = Code.generate(code, gotos);
         
         position = 0;
 
         loopCounter = 0;
+        
+        halt = false;
+        valid = true;
+        
+        tryJumpLine = -1;
     }
     
     // -----------------------------------------------------------------------------------
@@ -46,6 +64,75 @@ public class Script
         return name;
     }
     
+    public boolean isHalt() 
+    {
+        return halt;
+    }
+    
+    public void setHalt(boolean b) 
+    {
+        halt = b;
+    }
+    
+    public boolean isValid() 
+    {
+        return valid;
+    }
+    
+    public void setInvalid() 
+    {
+        valid = false;
+    }
+    
+    public int getActiveCodeLine()
+    {
+        return position;
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // Event-Handling
+    // -----------------------------------------------------------------------------------
+    
+    public void loadEvent(String s)
+    {
+        events.add(s);
+    }
+    
+    public boolean isLoadedEvent(String s)
+    {
+        return events.contains(s);
+    }
+    
+    public void unloadEvent(String s)
+    {
+        events.remove(s);
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // Script-Flow
+    // -----------------------------------------------------------------------------------
+    
+    public void runCode() 
+    {
+        if(this.isValid())
+        {
+            try
+            {
+                while(position < code.length)
+                {
+                    code[position].executeFunction(this, valueStack);
+                    position++;
+                }
+                ScriptControl.term(this);
+            }
+            catch(Exception ex)
+            {
+                //ex.printStackTrace();
+                // Nothing to do here, Exception wird für Benutzer ausgegeben
+            }
+        }
+    }
+    
     // -----------------------------------------------------------------------------------
     // Variablen
     // -----------------------------------------------------------------------------------
@@ -66,10 +153,10 @@ public class Script
     }
     
     // -----------------------------------------------------------------------------------
-    // Goto
+    // Goto, Return
     // -----------------------------------------------------------------------------------
     
-    public void gotoLabel(String label) throws GotoLabelNotFoundException, CodeTooLongException
+    public void gotoLabel(String label)
     {
         try
         {
@@ -80,7 +167,7 @@ public class Script
                 resetLoopCounter();
                 throw new CodeTooLongException();
             }
-            position = i;
+            position = i - 1;
         }
         catch(NullPointerException ex)
         {
@@ -92,4 +179,54 @@ public class Script
     {
         loopCounter = 0;
     }
+    
+    public void gotoLabelWithReturn(String label)
+    {
+        returnStack.push(position);
+        gotoLabel(label);
+    }
+    
+    public void doReturn()
+    {
+        position = returnStack.pop(); 
+    }
+    
+    public void gotoSpecialJumpLine()
+    {
+        position += code[position].getJumpLine() - 1;
+    }
+    
+    public void jumpNextIfElse()
+    {
+        String s = code[position + 1].getFunction();
+        if(s == null || !s.equals("else"))
+        {
+            return;
+        }
+        position++;
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // try
+    // -----------------------------------------------------------------------------------
+    
+    public void gotoTryJumpLine()
+    {
+        position = tryJumpLine; 
+    }
+    
+    public void saveTryJumpLine()
+    {
+        tryJumpLine = position + code[position].getJumpLine();
+    }
+    
+    public void resetTryJumpLine()
+    {
+        tryJumpLine = -1;
+    }
+    
+    public int getTryJumpLine()
+    {
+        return tryJumpLine; 
+    }
 }

+ 29 - 37
src/me/hammerle/code/ScriptControl.java

@@ -2,68 +2,60 @@ package me.hammerle.code;
 
 import java.util.Collection;
 import java.util.HashMap;
+import me.hammerle.scheduler.SnuviScheduler;
 
 public class ScriptControl
 {
-    private int idCounter;
-    private final HashMap<Integer, Script> scripts;
-    
-    public ScriptControl() 
-    {
-        scripts = new HashMap<>();
-        idCounter = 0;
-    }    
+    private static int idCounter = 0;
+    private final static HashMap<Integer, Script> SCRIPTS = new HashMap<>();
     
     // -------------------------------------------------------------------------
     // Script - Verwaltung
     // -------------------------------------------------------------------------
 
-    public Script getScript(int id)
+    public static Script getScript(int id)
     {
-        return scripts.get(id);
+        return SCRIPTS.get(id);
     }
     
-    public void removeScripts()
+    public static void term(Script sc)
     {
-        //scripts.values().forEach(sd -> sd.setValid(false));
-        scripts.clear();
+        if(sc == null)
+        {
+            return;
+        }
+        sc.setInvalid();
+        SnuviScheduler.doScheduledTask(() -> SCRIPTS.remove(sc.getId()));
     }
     
-    public Collection<Script> getScripts()
+    public static void termScripts()
     {
-        return scripts.values();
+        SCRIPTS.values().forEach(sc -> sc.setInvalid());
+        SnuviScheduler.doScheduledTask(() -> SCRIPTS.clear());
     }
     
-    private void add(Script sd)
+    public static Collection<Script> getScripts()
     {
-        scripts.put(sd.getId(), sd);
+        return SCRIPTS.values();
     }
     
-    public void term(Script sd)
-    {
-        /*if(sd == null)
-        {
-            return;
-        }
-        activeScript = sd.getIdBefore();
-        ScriptData sda = getActiveScript();
-        sda.setVar("return", sd.getVar("return"));
-        sd.setValid(false);
-        int id = sd.getId();
-        SnuviScheduler.doScheduledTask(() -> scripts.remove(id));
-        sda.nextCodeLine();
-        CodeParser.continueCode(sda, null);*/
-    }
-
     // -----------------------
     // Scripts laden und starten
     // -----------------------
   
-    /*public void startScript(String scriptName)
+    public static void startScriptFromFile(String scriptName)
+    { 
+        Script sd = new Script(idCounter, scriptName, String.join("", ScriptUtils.readCode(scriptName)));
+        SCRIPTS.put(idCounter, sd);
+        idCounter++;
+        sd.runCode();
+    }
+    
+    public static void startScriptFromCode(String code)
     { 
-        Script sd = new Script(idCounter, scriptName);
+        Script sd = new Script(idCounter, "CONSOLE-" + idCounter, code);
+        SCRIPTS.put(idCounter, sd);
         idCounter++;
-        add(sd);
         sd.runCode();
-    }*/
+    }
 }

+ 29 - 26
src/me/hammerle/code/ScriptUtils.java

@@ -1,7 +1,14 @@
 package me.hammerle.code;
 
 import java.awt.Color;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Random;
+import java.util.stream.Collectors;
+import me.hammerle.console.ConsoleUtils;
 import me.hammerle.exceptions.IllegalColorException;
 
 public class ScriptUtils
@@ -20,19 +27,18 @@ public class ScriptUtils
     }
     
     public static void printError(Object message)
-    {
-        System.out.println("Fehler: " + message);
-        System.exit(0);
+    { 
+        ConsoleUtils.sendMessage(String.valueOf(message), Color.RED);
     }
     
-    public static void printDebug(Object message)
+    public static void printErrorList(Object message, Object message2)
     {
-        System.out.println(message);
+        ConsoleUtils.sendMessage(" - " + message + " " + message2, Color.RED);
     }
     
-    public static void printDebugList(Object message)
+    public static void printDebug(Object message)
     {
-        System.out.println(" - " + message);
+        ConsoleUtils.sendMessage(String.valueOf(message), null);
     }
     
     public static int randomInt(int min, int max)
@@ -42,32 +48,29 @@ public class ScriptUtils
         return randomNum;
     }
     
-    
-    public static Object getNumber(String s)
+    public static String connect(Object[] o, int skip)
     {
-        double d = Double.parseDouble(s);
-        if((int) d == d)
-        {
-            return (int) d;
-        }
-        return d;
+        return Arrays.stream(o, skip, o.length).map(ob -> String.valueOf(ob)).collect(Collectors.joining());
     }
     
-    public static int getInteger(Object o)
+    public static List<String> readCode(String filename)
     {
-        if(o instanceof Double)
+        File script = new File(filename + ".snuvi");  
+        if(script.exists())
         {
-            return (int) (double) o;
+            try 
+            {
+                return Files.readAllLines(script.toPath());
+            } 
+            catch (IOException ex) 
+            {
+                ScriptUtils.printError("File '" + filename + "' cannot be read.");
+            }
         }
-        return (int) o;
-    }
-    
-    public static double getDouble(Object o)
-    {
-        if(o instanceof Integer)
+        else
         {
-            return (double) (int) o;
+            ScriptUtils.printError("File '" + filename + "' does not exist.");
         }
-        return (double) o;
+        return null;
     }
 }

+ 37 - 6
src/me/hammerle/console/BlackBox.java

@@ -2,20 +2,26 @@ package me.hammerle.console;
 
 import java.awt.Color;
 import java.awt.Font;
+import javax.swing.JScrollBar;
 import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
+import javax.swing.JTextPane;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyledDocument;
 
 public class BlackBox extends JScrollPane
 {
-    protected final JTextArea area;
+    private final StyledDocument doc;
+    protected final JTextPane area;
     protected final Console c;
     
     public BlackBox(Console c)
     {
         this.c = c;
         
-        area = new JTextArea();
-        area.setLineWrap(true);
+        area = new JTextPane();
+        //area.setLineWrap(true);
         area.setBackground(Color.black);
         area.setFont(new Font("Monaco", Font.PLAIN, 16));
         area.setForeground(Color.white);
@@ -25,10 +31,35 @@ public class BlackBox extends JScrollPane
         super.setViewportView(area);
         super.setBackground(Color.black);
         super.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+        
+        doc = area.getStyledDocument();
+    }
+    
+    public void append(String s, Color c)
+    {
+        Style style = null;
+        if(c != null)
+        {
+            style = doc.getStyle(s);
+            if(style == null)
+            {
+                style = area.addStyle(c.toString(), null);
+                StyleConstants.setForeground(style, c);
+            }
+        }
+        try 
+        {
+            doc.insertString(doc.getLength(), s, style);
+        } 
+        catch (BadLocationException ex) 
+        {
+        }
+        scrollToBottom();
     }
     
-    public JTextArea getTextArea()
+    protected void scrollToBottom()
     {
-        return area;
+        JScrollBar v = this.getVerticalScrollBar();
+        v.setValue(v.getMaximum());
     }
 }

+ 8 - 2
src/me/hammerle/console/ConsoleUtils.java

@@ -1,11 +1,17 @@
 package me.hammerle.console;
 
+import java.awt.Color;
 import me.hammerle.snuviscript.SnuviScript;
 
 public class ConsoleUtils 
 {
-    public static void sendMessage(String s)
+    public static void sendMessage(String s, Color c)
     {
-        SnuviScript.console.output.pushText(s);
+        SnuviScript.console.output.pushText(s, c);
+    }
+    
+    public static void clear()
+    {
+        SnuviScript.console.output.clear();
     }
 }

+ 6 - 4
src/me/hammerle/console/InputBox.java

@@ -1,7 +1,9 @@
 package me.hammerle.console;
 
+import java.awt.Color;
 import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
+import me.hammerle.code.ScriptControl;
 
 public class InputBox extends BlackBox
 {
@@ -15,15 +17,15 @@ public class InputBox extends BlackBox
             {
                 if(e.getKeyCode() == KeyEvent.VK_ENTER)
                 {
-                    if(e.isAltDown())
+                    if(e.isShiftDown())
                     {
-                        area.append("\n");
+                        append("\n", null);
                         e.consume();
                     }
                     else
                     {
-                        // HIER WIRD CODE AUSGEFÜHRT
-                        c.output.pushText(area.getText());
+                        ConsoleUtils.sendMessage("> " + area.getText(), Color.GRAY);
+                        ScriptControl.startScriptFromCode(area.getText());
                         area.setText(null);
                         e.consume();
                     }

+ 8 - 2
src/me/hammerle/console/OutputBox.java

@@ -1,5 +1,6 @@
 package me.hammerle.console;
 
+import java.awt.Color;
 import java.awt.Dimension;
 
 public class OutputBox extends BlackBox
@@ -12,8 +13,13 @@ public class OutputBox extends BlackBox
         area.setText("--- Hello " + System.getProperty("user.name") + " ---\n");
     }
     
-    public void pushText(String s)
+    public void pushText(String s, Color c)
     {
-        area.append("> " + s + "\n");
+        append(s + "\n", c);
+    }
+    
+    public void clear()
+    {
+        area.setText("");
     }
 }

+ 1 - 1
src/me/hammerle/exceptions/CodeTooLongException.java

@@ -1,6 +1,6 @@
 package me.hammerle.exceptions;
 
-public class CodeTooLongException extends Exception
+public class CodeTooLongException extends RuntimeException
 {
     
 }

+ 6 - 0
src/me/hammerle/exceptions/HoldCodeException.java

@@ -0,0 +1,6 @@
+package me.hammerle.exceptions;
+
+public class HoldCodeException extends RuntimeException
+{
+    
+}

+ 1 - 1
src/me/hammerle/exceptions/IllegalStringException.java

@@ -1,6 +1,6 @@
 package me.hammerle.exceptions;
 
-public class IllegalStringException extends Exception
+public class IllegalStringException extends RuntimeException
 {
     private final String s;
     

+ 9 - 0
src/me/hammerle/exceptions/NoSuchMethodException.java

@@ -0,0 +1,9 @@
+package me.hammerle.exceptions;
+
+public class NoSuchMethodException extends IllegalStringException
+{
+    public NoSuchMethodException(String s) 
+    {
+        super(s);
+    }
+}

+ 0 - 32
src/me/hammerle/files/FileUtils.java

@@ -1,32 +0,0 @@
-package me.hammerle.files;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.List;
-import me.hammerle.code.ScriptUtils;
-import me.hammerle.console.ConsoleUtils;
-
-public class FileUtils 
-{
-    public static List<String> readCode(String filename)
-    {
-        File script = new File(filename + ".sv");  
-        if(script.exists())
-        {
-            try 
-            {
-                return Files.readAllLines(script.toPath());
-            } 
-            catch (IOException ex) 
-            {
-                ConsoleUtils.sendMessage("File '" + filename + "' cannot be read.");
-            }
-        }
-        else
-        {
-            ScriptUtils.printError("File '" + filename + "' does not exist.");
-        }
-        return null;
-    }
-}

+ 2 - 2
src/me/hammerle/math/Fraction.java

@@ -130,7 +130,7 @@ public class Fraction implements Cloneable, Comparable<Fraction>
         return this;
     }
     
-    public Fraction mul(long f)
+    private Fraction mul(long f)
     {
         boolean b = true;
         while(b)
@@ -161,7 +161,7 @@ public class Fraction implements Cloneable, Comparable<Fraction>
         return this;
     }
     
-    public Fraction div(long f)
+    private Fraction div(long f)
     {
         boolean b = true;
         while(b)

+ 3 - 16
src/me/hammerle/snuviscript/SnuviScript.java

@@ -1,6 +1,6 @@
 package me.hammerle.snuviscript;
 
-import me.hammerle.code.Script;
+import me.hammerle.code.CodeParser;
 import me.hammerle.console.Console;
 import me.hammerle.code.ScriptEngine;
 import me.hammerle.code.ScriptControl;
@@ -14,25 +14,12 @@ public class SnuviScript
     
     public static void main(String[] args) 
     {
-        //console = new Console();
+        CodeParser.initCodeParser();
+        console = new Console();
         
         /*for(String s : GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames())
         {
             System.out.println(s);
         }*/
-        
-        String s = "if(equal(list.getIndex(args, 1), \"remove\")) \n{\n" +
-"	setVar(\"mailid\", list.getIndex(args, 2));\n" +
-"	try() \n	{\n" +
-"		add(mailid, 1); \n" +
-"	} \n	catch() \n	{\n" +
-"		player.speak(player, \"§3Mail\", \"Zahl erwartet: %mail remove <mailid>\");\n" +
-"		goto(\"wait\");\n" +
-"	}\n" +
-"	gmap.remove(concat(\"mailin-\", player.getUuid(player)), mailid);\n" +
-"	gmap.remove(concat(\"mailout-\", player.getUuid(player)), mailid);\n" +
-"	goto(\"wait\");\n}";
-        System.out.println(s);
-        Script test = new Script(1, "Test", s);
     }   
 }