Browse Source

added ++ and --, implemented most functions of snuvi script

Kajetan Johannes Hammerle 6 years ago
parent
commit
d3b7a3d078

+ 1 - 1
src/me/hammerle/snuviscript/SnuviScript.java

@@ -11,7 +11,7 @@ public class SnuviScript
     public static void main(String[] args) throws IOException 
     {
         List<String> lines = Files.readAllLines(new File("./test.sbasic").toPath());
-        Script sc = new Script(lines);
+        Script sc = new Script(null, lines, "test");
         System.out.println("\n" + sc.run());
     }  
 }

+ 3 - 3
src/me/hammerle/snuviscript/array/DynamicArray.java

@@ -3,7 +3,7 @@ package me.hammerle.snuviscript.array;
 import me.hammerle.snuviscript.code.InputProvider;
 import me.hammerle.snuviscript.variable.Variable;
 import java.lang.reflect.Array;
-import me.hammerle.snuviscript.code.DataUtils;
+import me.hammerle.snuviscript.code.Utils;
 import me.hammerle.snuviscript.code.Script;
 import me.hammerle.snuviscript.variable.LocalVariable;
 import me.hammerle.snuviscript.math.Fraction;
@@ -97,7 +97,7 @@ public class DynamicArray extends InputProvider
         }
         catch(IllegalArgumentException ex)
         {
-            return DataUtils.getArrayString(Array.get(last, index));
+            return Utils.getArrayString(Array.get(last, index));
         }
     }
 
@@ -105,9 +105,9 @@ public class DynamicArray extends InputProvider
     public String toString() 
     {
         StringBuilder sb = new StringBuilder(var.getName());
-        sb.append("#");
         if(var instanceof LocalVariable)
         {
+            sb.append("#");
             sb.append("L");
         }
         sb.append("[");

+ 1 - 1
src/me/hammerle/snuviscript/code/BasicFunction.java

@@ -2,7 +2,7 @@ package me.hammerle.snuviscript.code;
 
 import java.util.function.BiFunction;
 
-public class BasicFunction 
+public final class BasicFunction 
 {
     private final String name;
     private final BiFunction<Script, InputProvider[], Object> f;

+ 59 - 14
src/me/hammerle/snuviscript/code/Compiler.java

@@ -23,7 +23,9 @@ public class Compiler
     {
         Compiler compiler = new Compiler(sc, sCode, labels, locale);
         compiler.lineOffset = lineOffset;
-        return compiler.compile();
+        Instruction[] instructions = compiler.compile();
+        sc.vars = compiler.vars;
+        return instructions;
     }
     
     private final List<String> sCode;
@@ -312,7 +314,7 @@ public class Compiler
             return;
         }
         //System.out.println(">>>"  + currentCode);
-        String[] parts = DataUtils.split(strings, currentCode, line);
+        String[] parts = Utils.split(strings, currentCode, line);
         //System.out.println(">>> " + String.join("_", parts));
         
         if(parts.length == 0)
@@ -341,7 +343,7 @@ public class Compiler
             if(bPos != -1)
             {
                 input = parts[0].substring(0, bPos);
-                parts = DataUtils.split(strings, parts[0].substring(bPos + 1, parts[0].length() - 1), line);
+                parts = Utils.split(strings, parts[0].substring(bPos + 1, parts[0].length() - 1), line);
             }
             else
             {
@@ -381,8 +383,23 @@ public class Compiler
         }
         else
         {
+            switch(parts[0])
+            {           
+                case "++":
+                    addCodeInstruction("p+", compileFunction(new String[] {parts[1]}, false));
+                    return;
+                case "--":
+                    addCodeInstruction("p-", compileFunction(new String[] {parts[1]}, false));
+                    return;
+            }
             switch(parts[1])
             {           
+                case "++":
+                case "--":
+                    input = parts[1];
+                    parts = new String[] {parts[0]};
+                    //System.out.println(String.join("__", parts));
+                    break;
                 case "=":
                 case "+=":
                 case "-=":
@@ -481,14 +498,21 @@ public class Compiler
             {
                 if(stackCounter <= 0)
                 {
-                    if(sy == Syntax.SUB)
-                    {
-                        sy = Syntax.UNARY_SUB;
-                    }
-                    else
+                    switch(sy)
                     {
-                        throw new PreScriptException("missing syntax argument", line);
+                        case SUB:
+                            sy = Syntax.UNARY_SUB;
+                            break;
+                        case INC:
+                            sy = Syntax.POST_INC;
+                            break;
+                        case DEC:
+                            sy = Syntax.POST_DEC;
+                            break;
+                        default:
+                            throw new PreScriptException("missing syntax argument", line);
                     }
+                    System.out.println(syntax);
                 }
                 // pushing weaker functions
                 int weight = sy.getWeight();
@@ -535,14 +559,14 @@ public class Compiler
         {
             return ConstantNull.NULL;
         }
-        else if(DataUtils.isNumber(input))
+        else if(Utils.isNumber(input))
         {
             return new ConstantFraction(Fraction.fromDouble(Double.parseDouble(input)));
         }
-        else if(DataUtils.isFunction(input))
+        else if(Utils.isFunction(input))
         {
             int bPos = input.indexOf('(');
-            String[] parts = DataUtils.split(strings, input.substring(bPos + 1, input.length() - 1), line);
+            String[] parts = Utils.split(strings, input.substring(bPos + 1, input.length() - 1), line);
             if(parts.length > 0)
             {
                 return new Function(FunctionLoader.getFunction(input.substring(0, bPos)), compileFunction(parts, false));
@@ -552,10 +576,10 @@ public class Compiler
                 return new Function(FunctionLoader.getFunction(input.substring(0, bPos)), new InputProvider[0]);
             }
         }
-        else if(DataUtils.isArray(input))
+        else if(Utils.isArray(input))
         {
             int bPos = input.indexOf('[');
-            String[] parts = DataUtils.split(strings, input.substring(bPos + 1, input.length() - 1), line);
+            String[] parts = Utils.split(strings, input.substring(bPos + 1, input.length() - 1), line);
             if(parts.length > 0)
             {
                 return createArray(input.substring(0, bPos), compileFunction(parts, false));
@@ -571,6 +595,27 @@ public class Compiler
         }
     }
     
+    public static Object convert(String input)
+    {
+        if(input.equals("true"))
+        {
+            return true;
+        }
+        else if(input.equals("false"))
+        {
+            return false;
+        }
+        else if(input.equals("null"))
+        {
+            return null;
+        }
+        else if(Utils.isNumber(input))
+        {
+            return Fraction.fromDouble(Double.parseDouble(input));
+        }
+        return input;
+    }
+    
     private Variable getOrCreateVariable(String var)
     {
         if(locale)

+ 552 - 376
src/me/hammerle/snuviscript/code/FunctionLoader.java

@@ -1,10 +1,29 @@
 package me.hammerle.snuviscript.code;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.lang.reflect.Array;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.time.ZonedDateTime;
+import java.util.List;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
 import java.util.HashMap;
-import java.util.Random;
+import java.util.Map;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.BiFunction;
 import java.util.stream.Collectors;
 import me.hammerle.snuviscript.array.DynamicArray;
+import me.hammerle.snuviscript.config.SnuviConfig;
+import me.hammerle.snuviscript.exceptions.AssertionException;
+import me.hammerle.snuviscript.exceptions.FileIOException;
 import me.hammerle.snuviscript.variable.ArrayVariable;
 import me.hammerle.snuviscript.variable.Variable;
 import me.hammerle.snuviscript.math.Fraction;
@@ -13,14 +32,14 @@ public class FunctionLoader
 {
     private static final HashMap<String, BasicFunction> FUNCTIONS = new HashMap<>();
     
-    public static void registerFunction(String name, BasicFunction function)
+    public static void registerFunction(String name, String fname, BiFunction<Script, InputProvider[], Object> f)
     {
-        FUNCTIONS.put(name, function);
+        FUNCTIONS.put(name, new BasicFunction(fname, f));
     }
     
-    public static void registerFunction(BasicFunction function)
+    public static void registerFunction(String name, BiFunction<Script, InputProvider[], Object> f)
     {
-        registerFunction(function.getName(), function);
+        registerFunction(name, name, f);
     }
     
     public static void registerAlias(String original, String alias)
@@ -28,8 +47,9 @@ public class FunctionLoader
         FUNCTIONS.put(alias, FUNCTIONS.get(original));
     }
     
-    public static BasicFunction getFunction(String function)
+    public static BasicFunction getFunction(String f)
     {
+        final String function = f.toLowerCase();
         return FUNCTIONS.getOrDefault(function, new BasicFunction(function, (sc, in) -> 
         {
             Script sub = sc.subScripts.get(function);
@@ -77,225 +97,524 @@ public class FunctionLoader
         }));
     }
     
-    private static final Random[] RND;
-    
     static
     {
-        RND = new Random[8];
-        for(int i = 0; i < 8; i++)
+        // ---------------------------------------------------------------------    
+        // system stuff
+        // --------------------------------------------------------------------- 
+        registerFunction("nothing", (sc, in) -> Void.TYPE);
+        registerFunction("error", (sc, in) -> 
         {
-            RND[i] = new Random();
-        }
-        // ---------------------------------------------------------------------
-        // brackets
-        // ---------------------------------------------------------------------
-        registerFunction("", new BasicFunction("", (sc, in) -> 
+            sc.printStackTrace = !sc.printStackTrace;
+            return Void.TYPE;
+        });
+        registerFunction("", (sc, in) -> in[0].get(sc));
+        
+        // ---------------------------------------------------------------------  
+        // event
+        // --------------------------------------------------------------------- 
+        registerFunction("event.load", (sc, in) ->
         {
-            return in[0].get(sc);
-        }));
-        // ---------------------------------------------------------------------
-        // elementary arithmetic
-        // ---------------------------------------------------------------------
-        registerFunction("+", new BasicFunction("ADD", (sc, in) -> 
+            sc.loadEvent(in[0].getString(sc)); 
+            return Void.TYPE;
+        });
+        registerFunction("event.unload", (sc, in) ->
         {
-            return in[0].getFraction(sc).add(in[1].getFraction(sc));
-        }));
-        registerFunction("-", new BasicFunction("SUB", (sc, in) -> 
+            sc.unloadEvent(in[0].getString(sc)); 
+            return Void.TYPE;
+        });
+        registerFunction("event.isloaded", (sc, in) -> sc.isEventLoaded(in[0].getString(sc)));
+
+        // ---------------------------------------------------------------------    
+        // bit
+        // --------------------------------------------------------------------- 
+        
+        registerFunction(">>", (sc, in) -> in[0].getFraction(sc).rightShift(in[1].getInt(sc)));
+        registerFunction("<<", (sc, in) -> in[0].getFraction(sc).leftShift(in[1].getInt(sc)));
+        registerFunction("&", (sc, in) -> in[0].getFraction(sc).and(in[1].getFraction(sc)));
+        registerFunction("|", (sc, in) -> in[0].getFraction(sc).or(in[1].getFraction(sc)));
+        registerFunction("^", (sc, in) -> in[0].getFraction(sc).xor(in[1].getFraction(sc)));
+        registerFunction("~", (sc, in) -> in[0].getFraction(sc).invertBits());
+        registerFunction("bit.set", (sc, in) -> in[0].getFraction(sc).setBit(in[1].getInt(sc)));
+        registerFunction("bit.unset", (sc, in) -> in[0].getFraction(sc).unsetBit(in[1].getInt(sc)));
+        registerFunction("bit.get", (sc, in) -> in[0].getFraction(sc).getBit(in[1].getInt(sc)));
+        
+        // ---------------------------------------------------------------------    
+        // math
+        // ---------------------------------------------------------------------    
+        registerFunction("%", (sc, in) -> new Fraction(in[0].getInt(sc) % in[1].getInt(sc)));
+        registerAlias("%", "math.mod");
+        registerFunction("math.abs", (sc, in) -> in[0].getFraction(sc).abs());
+        registerFunction("math.pow", (sc, in) -> in[0].getFraction(sc).power(in[1].getFraction(sc)));
+        registerFunction("math.root", (sc, in) -> in[0].getFraction(sc).power(in[1].getFraction(sc).invert()));
+        registerFunction("math.sin", (sc, in) -> in[0].getFraction(sc).sin());
+        registerFunction("math.cos", (sc, in) -> in[0].getFraction(sc).cos());
+        registerFunction("math.tan", (sc, in) -> in[0].getFraction(sc).tan());
+        registerFunction("math.sin", (sc, in) -> in[0].getFraction(sc).sin());
+        registerFunction("math.acos", (sc, in) -> in[0].getFraction(sc).acos());
+        registerFunction("math.atan", (sc, in) -> in[0].getFraction(sc).atan());
+        registerFunction("math.asin", (sc, in) -> in[0].getFraction(sc).asin());
+        registerFunction("math.e", (sc, in) -> Fraction.E);
+        registerFunction("math.pi", (sc, in) -> Fraction.PI);
+        registerFunction("math.ln", (sc, in) -> in[0].getFraction(sc).log());
+        registerFunction("math.log", (sc, in) -> in[0].getFraction(sc).log10());
+        registerFunction("math.random", (sc, in) -> new Fraction(Utils.randomInt(in[0].getInt(sc), in[1].getInt(sc))));
+        registerFunction("math.round", (sc, in) -> in[0].getFraction(sc).round());
+        registerFunction("math.rounddown", (sc, in) -> in[0].getFraction(sc).floor());
+        registerFunction("math.roundup", (sc, in) -> in[0].getFraction(sc).ceil());
+        registerFunction("math.roundcomma", (sc, in) -> in[0].getFraction(sc).round(in[1].getInt(sc)));
+        
+        // ---------------------------------------------------------------------  
+        // lists
+        // ---------------------------------------------------------------------    
+        registerFunction("list.new", (sc, in) ->     
         {
-            return in[0].getFraction(sc).sub(in[1].getFraction(sc));
-        }));
-        registerFunction("*", new BasicFunction("MUL", (sc, in) -> 
+            in[0].set(sc, new ArrayList<>());
+            return Void.TYPE;
+        });
+        registerFunction("list.exists", (sc, in) -> in[0].get(sc) instanceof List);
+        registerFunction("list.add", (sc, in) -> ((List) in[0].get(sc)).add(in[1].get(sc)));
+        registerFunction("list.remove", (sc, in) -> ((List) in[0].get(sc)).remove(in[1].get(sc)));
+        registerFunction("list.removeindex", (sc, in) -> ((List) in[0].get(sc)).remove(in[1].getInt(sc)));
+        registerFunction("list.contains", (sc, in) -> ((List) in[0].get(sc)).contains(in[1].get(sc)));
+        registerFunction("list.getsize", (sc, in) -> new Fraction(((List) in[0].get(sc)).size()));
+        registerFunction("list.getindex", (sc, in) -> ((List) in[0].get(sc)).get(in[1].getInt(sc)));
+        registerAlias("list.getindex", "list.get");
+        registerFunction("list.setindex", (sc, in) -> ((List) in[0].get(sc)).set(in[1].getInt(sc), in[2].get(sc)));
+        registerFunction("list.clear", (sc, in) ->     
+        {
+            ((List) in[0].get(sc)).clear();
+            return Void.TYPE;
+        });
+        registerFunction("list.getindexof", (sc, in) -> new Fraction(((List) in[0].get(sc)).indexOf(in[1].get(sc))));
+        registerFunction("list.sort", (sc, in) ->     
         {
-            return in[0].getFraction(sc).mul(in[1].getFraction(sc));
-        }));
-        registerFunction("/", new BasicFunction("DIV", (sc, in) -> 
+            Collections.sort(((List<Object>) in[0].get(sc)), (Object o1, Object o2) -> ((Comparable) o1).compareTo(o2));
+            return Void.TYPE;
+        });
+        registerFunction("list.reverse", (sc, in) ->     
         {
-            return in[0].getFraction(sc).div(in[1].getFraction(sc));
-        }));
-        // ---------------------------------------------------------------------
-        // comparing
-        // ---------------------------------------------------------------------
-        registerFunction("==", new BasicFunction("EQUAL", (sc, in) -> 
+            Collections.reverse((List<Object>) in[0].get(sc)); 
+            return Void.TYPE;
+        });
+        registerFunction("list.shuffle", (sc, in) ->     
         {
-            Object a = in[0].get(sc);
-            Object b = in[1].get(sc);
-            if(a == null || b == null)
-            {
-                return a == b ? 1 : 0;
-            }
-            else if(a instanceof String || b instanceof String)
-            {
-                return a.equals(b) ? 1 : 0;
-            }
-            return ((Number) a).doubleValue() == ((Number) b).doubleValue() ? 1 : 0;
-        }));
-        registerFunction("!=", new BasicFunction("NOTEQUAL", (sc, in) -> 
+            Collections.shuffle((List<Object>) in[0].get(sc)); 
+            return Void.TYPE;
+        });
+
+        // ---------------------------------------------------------------------  
+        // arrays
+        // ---------------------------------------------------------------------   
+        registerFunction("array.new", (sc, in) -> 
         {
-            Object a = in[0].get(sc);
-            Object b = in[1].get(sc);
-            if(a == null || b == null)
-            {
-                return a != b ? 1 : 0;
-            }
-            else if(a instanceof String || b instanceof String)
+            for(InputProvider input : in)
             {
-                return a.equals(b) ? 1 : 0;
+                ((DynamicArray) input).init(sc);
             }
-            return ((Number) a).doubleValue() != ((Number) b).doubleValue() ? 1 : 0;
-        }));
-        registerFunction(">", new BasicFunction("GREATER", (sc, in) -> 
+            return Void.TYPE;
+        });
+        registerFunction("array.getsize", (sc, in) -> new Fraction(Array.getLength(in[0].getArray(sc))));
+        
+        /*
+        registerFunction("array.swap", (sc, in) ->                                           
+                {
+                    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;
+                });
+        registerFunction("array.sort", (sc, in) ->  
+                {
+                    if(args.length <= 1)
+                    {
+                        Arrays.sort((Object[]) args[0]);
+                    }
+                    else
+                    {
+                        Arrays.sort((Object[]) args[0], ScriptUtils.getInt(args[1]), ScriptUtils.getInt(args[2]));
+                    }
+                });
+        registerFunction("array.copy", (sc, in) ->  
+                {
+                    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);
+                });
+        registerFunction("array.rsort", (sc, in) ->    
+                {
+                    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)); 
+                    }
+                });
+        registerFunction("array.fill", (sc, in) ->     
+                {
+                    if(args.length <= 2)
+                    {
+                        Arrays.fill((Object[]) args[0], args[1]);
+                    }
+                    else
+                    {
+                        Arrays.fill((Object[]) args[0], ScriptUtils.getInt(args[2]), ScriptUtils.getInt(args[3]), args[1]); 
+                    }
+                });*/  
+
+        // --------------------------------------------------------------------- 
+        // maps
+        // --------------------------------------------------------------------- 
+        registerFunction("map.new", (sc, in) ->     
         {
-            return in[0].getDouble(sc) > in[1].getDouble(sc) ? 1 : 0;
-        }));
-        registerFunction(">=", new BasicFunction("GREATEREQUAL", (sc, in) -> 
+            in[0].set(sc, new HashMap<>());
+            return Void.TYPE;
+        });
+        registerFunction("map.exists", (sc, in) -> in[0].get(sc) instanceof Map);
+        registerFunction("map.add", (sc, in) -> ((Map) in[0].get(sc)).put(in[1].get(sc), in[2].get(sc)));
+        registerFunction("map.remove", (sc, in) -> ((Map) in[0].get(sc)).remove(in[1].get(sc)));
+        registerFunction("map.contains", (sc, in) -> ((Map) in[0].get(sc)).containsKey(in[1].get(sc)));
+        registerFunction("map.getsize", (sc, in) -> new Fraction(((Map) in[0].get(sc)).size()));
+        registerFunction("map.get", (sc, in) -> ((Map) in[0].get(sc)).get(in[1].get(sc)));
+        registerFunction("map.getordefault", (sc, in) -> ((Map) in[0].get(sc)).getOrDefault(in[1].get(sc), in[2].get(sc)));
+        registerFunction("map.clear", (sc, in) ->     
+        {
+            ((Map) in[0].get(sc)).clear();
+            return Void.TYPE;
+        });
+        registerFunction("map.keys", (sc, in) ->     
         {
-            return in[0].getDouble(sc) >= in[1].getDouble(sc) ? 1 : 0;
-        }));
-        registerFunction("<", new BasicFunction("SMALLER", (sc, in) -> 
+            in[0].set(sc, ((Map) in[1].get(sc)).keySet().stream().collect(Collectors.toList()));
+            return Void.TYPE;
+        });
+        registerFunction("map.values", (sc, in) ->     
         {
-            return in[0].getDouble(sc) < in[1].getDouble(sc) ? 1 : 0;
-        }));
-        registerFunction("<=", new BasicFunction("SMALLEREQUAL", (sc, in) -> 
+            in[0].set(sc, ((Map) in[1].get(sc)).values().stream().collect(Collectors.toList()));
+            return Void.TYPE;
+        });
+        
+        // ---------------------------------------------------------------------  
+        // sets
+        // --------------------------------------------------------------------- 
+        registerFunction("set.new", (sc, in) ->     
         {
-            return in[0].getDouble(sc) <= in[1].getDouble(sc) ? 1 : 0;
-        }));
-        // ---------------------------------------------------------------------
-        // logical operators
+            in[0].set(sc, new HashSet<>());
+            return Void.TYPE;
+        });
+        registerFunction("set.exists", (sc, in) -> in[0].get(sc) instanceof Set);
+        registerFunction("set.add", (sc, in) -> ((Set) in[0].get(sc)).add(in[1].get(sc)));
+        registerFunction("set.remove", (sc, in) -> ((Set) in[0].get(sc)).remove(in[1].get(sc)));
+        registerFunction("set.contains", (sc, in) -> ((Set) in[0].get(sc)).contains(in[1].get(sc)));
+        registerFunction("set.getsize", (sc, in) -> new Fraction(((Set) in[0].get(sc)).size()));
+        registerFunction("set.tolist", (sc, in) ->     
+        {
+            in[0].set(sc, ((Set) in[1].get(sc)).stream().collect(Collectors.toList()));
+            return Void.TYPE;
+        });
+
+        // --------------------------------------------------------------------- 
+        // time
         // ---------------------------------------------------------------------
-        registerFunction("&&", new BasicFunction("AND", (sc, in) -> 
+        registerFunction("time.new", (sc, in) ->       
         {
-            return (in[0].getDouble(sc) != 0 && in[1].getDouble(sc) != 0) ? 1 : 0;
-        }));
-        registerFunction("||", new BasicFunction("OR", (sc, in) -> 
+            GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
+            cal.setTimeInMillis(in[1].getFraction(sc).longValue());
+            in[0].set(sc, cal);
+            return Void.TYPE;
+        });
+        registerFunction("time.getmillis", (sc, in) -> new Fraction(System.currentTimeMillis()));
+        registerFunction("time.from", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).getTimeInMillis()));
+        registerFunction("time.nextday", (sc, in) ->         
+        {
+            GregorianCalendar cal = (GregorianCalendar) in[0].get(sc);
+            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 Void.TYPE;
+        });   
+        registerFunction("time.getyear", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.YEAR)));
+        registerFunction("time.getmonth", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.MONTH) + 1));
+        registerFunction("time.getday", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.DAY_OF_MONTH)));
+        registerFunction("time.gethour", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.HOUR_OF_DAY)));
+        registerFunction("time.getminute", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.MINUTE)));
+        registerFunction("time.getsecond", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.SECOND)));
+              
+        // ---------------------------------------------------------------------    
+        // text
+        // ---------------------------------------------------------------------   
+        registerFunction("text.matches", (sc, in) -> in[0].getString(sc).matches(in[1].getString(sc)));      
+        registerFunction("text.number", (sc, in) -> 
+        {
+            Fraction f = in[0].getFraction(sc);
+            if(f.doubleValue() == f.longValue())
+            {
+                return String.valueOf(f.longValue()); 
+            }
+            return String.valueOf(f.doubleValue()); 
+        });
+        registerFunction("text.class", (sc, in) -> in[0].get(sc).getClass().getSimpleName());      
+        registerFunction("text.tolowercase", (sc, in) -> Utils.connect(sc, in, 0).toLowerCase());
+        registerAlias("tolowercase", "text.tolowercase");
+        registerFunction("text.touppercase", (sc, in) -> Utils.connect(sc, in, 0).toUpperCase());
+        registerAlias("touppercase", "text.touppercase");
+        registerFunction("text.split", (sc, in) ->      
+        {
+            in[0].set(sc, Arrays.stream(Utils.connect(sc, in, 2).split(in[1].getString(sc))).map(s -> Compiler.convert(s)).collect(Collectors.toList()));
+            return Void.TYPE;
+        });  
+        registerAlias("split", "text.split");
+        registerFunction("text.concatlist", (sc, in) -> ((List<Object>) in[0].get(sc)).stream().limit(in[3].getInt(sc) + 1).skip(in[2].getInt(sc)).map(o -> String.valueOf(o)).collect(Collectors.joining(in[1].getString(sc))));       
+        registerAlias("concatlist", "text.concatlist");
+        registerFunction("text.concat", (sc, in) -> Utils.connect(sc, in, 0)); 
+        registerAlias("concat", "text.concat");
+        registerFunction("text", (sc, in) -> String.valueOf(in[0].get(sc)));       
+        registerFunction("text.substring", (sc, in) -> in[0].getString(sc).substring(in[1].getInt(sc), in[2].getInt(sc))); 
+        registerFunction("text.length", (sc, in) ->  in[0].getString(sc).length()); 
+        registerFunction("text.startswith", (sc, in) -> in[0].getString(sc).startsWith(in[1].getString(sc), in[2].getInt(sc))); 
+        registerFunction("text.endswith", (sc, in) -> in[0].getString(sc).endsWith(in[1].getString(sc))); 
+        registerFunction("text.contains", (sc, in) ->  in[0].getString(sc).contains(in[1].getString(sc))); 
+        registerFunction("text.indexof", (sc, in) -> in[0].getString(sc).indexOf(in[1].getString(sc), in[2].getInt(sc))); 
+        registerFunction("text.lastindexof", (sc, in) -> in[0].getString(sc).lastIndexOf(in[1].getString(sc), in[2].getInt(sc)));
+        registerFunction("text.replace", (sc, in) -> in[0].getString(sc).replace(in[1].getString(sc), in[2].getString(sc)));
+        registerFunction("text.trim", (sc, in) -> in[0].getString(sc).trim());
+        registerFunction("text.charat", (sc, in) -> String.valueOf(in[0].getString(sc).charAt(in[1].getInt(sc))));
+        registerFunction("text.charcode", (sc, in) -> new Fraction(in[0].getString(sc).charAt(in[1].getInt(sc))));
+        registerFunction("text.fromcode", (sc, in) -> String.valueOf((char) in[0].getInt(sc)));
+        
+        // -------------------------------------------------------------------------------    
+        // files
+        // ------------------------------------------------------------------------------- 
+        
+        registerFunction("file.new", (sc, in) ->    
         {
-            return (in[0].getDouble(sc) != 0 || in[1].getDouble(sc) != 0) ? 1 : 0;
-        }));
-        // ---------------------------------------------------------------------
-        // bit stuff
+            in[0].set(sc, new File(in[1].getString(sc)));
+            return Void.TYPE;
+        });
+        registerFunction("file.exists", (sc, in) -> ((File) in[0].get(sc)).exists());
+        registerFunction("file.delete", (sc, in) ->  ((File) in[0].get(sc)).delete());
+        registerFunction("file.getname", (sc, in) -> ((File) in[0].get(sc)).getName());
+        registerFunction("file.getlist", (sc, in) ->       
+        {
+            in[0].set(sc, Arrays.asList(((File) in[0].get(sc)).listFiles()));
+            return Void.TYPE;
+        });
+        registerFunction("file.read", (sc, in) ->         
+        {
+            try
+            {
+                in[0].set(sc, Files.readAllLines(((File) in[1].get(sc)).toPath()));
+            }
+            catch(IOException ex)
+            {
+                throw new FileIOException(ex.getMessage());
+            }
+            return Void.TYPE;
+        });
+        registerFunction("file.write", (sc, in) ->         
+        {
+            try
+            {
+                File f = (File) in[0].get(sc);
+                if(f.getParentFile() != null)
+                {
+                    f.getParentFile().mkdirs();
+                }
+                if(!f.exists())
+                {
+                    try
+                    {
+                        f.createNewFile();
+                    }
+                    catch(IOException ex)
+                    {
+                        throw new FileIOException(ex.getMessage());
+                    }
+                }
+                Files.write(Paths.get(f.toURI()), ((List<Object>) in[1].get(sc))
+                        .stream().map(o -> String.valueOf(o)).collect(Collectors.toList()), StandardCharsets.UTF_8);
+            }
+            catch(UnsupportedOperationException | SecurityException | IOException ex)
+            {
+                throw new FileIOException(ex.getMessage());
+            }
+            return Void.TYPE;
+        });
+        
+        // ---------------------------------------------------------------------  
+        // config
         // ---------------------------------------------------------------------
-        registerFunction(new BasicFunction("MOD", (sc, in) -> 
+        
+        registerFunction("config.new", (sc, in) ->        
         {
-            return in[0].getInt(sc) % in[1].getInt(sc);
-        }));
-        registerFunction("&", new BasicFunction("AND", (sc, in) -> 
+            in[0].set(sc, new SnuviConfig(sc, in[1].getString(sc), in[2].getString(sc)));
+            return Void.TYPE;
+        });      
+        registerFunction("config.exists", (sc, in) -> ((SnuviConfig) in[0].get(sc)).exists());
+        registerFunction("config.save", (sc, in) -> ((SnuviConfig) in[0].get(sc)).save());
+        registerFunction("config.delete", (sc, in) -> ((SnuviConfig) in[0].get(sc)).delete());
+        registerFunction("config.set", (sc, in) ->      
         {
-            return in[0].getInt(sc) & in[1].getInt(sc);
-        }));
-        registerFunction("|", new BasicFunction("OR", (sc, in) -> 
+            ((SnuviConfig) in[0].get(sc)).set(in[1].getString(sc), in[2].get(sc));
+            return Void.TYPE;
+        });
+        registerFunction("config.getbool", (sc, in) -> ((SnuviConfig) in[0].get(sc)).getBoolean(in[1].getString(sc), in[2].getBoolean(sc)));
+        registerFunction("config.getfraction", (sc, in) -> ((SnuviConfig) in[0].get(sc)).getFraction(in[1].getString(sc), in[2].getFraction(sc)));
+        registerFunction("config.getstring", (sc, in) -> ((SnuviConfig) in[0].get(sc)).getString(in[1].getString(sc), in[2].getString(sc)));
+        
+        // ---------------------------------------------------------------------    
+        // commands without library
+        // ---------------------------------------------------------------------   
+        // elementary calculating
+        registerFunction("+", (sc, in) -> 
         {
-            return in[0].getInt(sc) | in[1].getInt(sc);
-        }));
-        registerFunction("^", new BasicFunction("XOR", (sc, in) -> 
+            return in[0].getFraction(sc).add(in[1].getFraction(sc));
+        });
+        registerAlias("+", "add");
+        registerFunction("-", (sc, in) -> 
         {
-            return in[0].getInt(sc) ^ in[1].getInt(sc);
-        }));
-        registerFunction("<<", new BasicFunction("SHIFTL", (sc, in) -> 
+            return in[0].getFraction(sc).sub(in[1].getFraction(sc));
+        });
+        registerAlias("-", "sub");
+        registerFunction("*", (sc, in) -> 
         {
-            return in[0].getInt(sc) << in[1].getInt(sc);
-        }));
-        registerFunction(">>", new BasicFunction("SHIFTR", (sc, in) -> 
+            return in[0].getFraction(sc).mul(in[1].getFraction(sc));
+        });
+        registerAlias("*", "mul");
+        registerFunction("/", (sc, in) -> 
         {
-            return in[0].getInt(sc) >> in[1].getInt(sc);
-        }));
-        // ---------------------------------------------------------------------
-        // basic instructions (variables and arrays)
-        // ---------------------------------------------------------------------
-        registerFunction("=", new BasicFunction("SET", (sc, in) -> 
+            return in[0].getFraction(sc).div(in[1].getFraction(sc));
+        });
+        registerAlias("/", "div");
+
+        // var setter
+        registerFunction("=", (sc, in) -> 
         {
             in[0].set(sc, in[1].get(sc));
             return Void.TYPE;
-        }));
-        registerFunction("+=", new BasicFunction("ADD_SET", (sc, in) -> 
+        });
+        registerAlias("=", "setvar");
+        registerFunction("+=", (sc, in) -> 
         {
             in[0].set(sc, in[0].getFraction(sc).add(in[1].getFraction(sc)));
             return Void.TYPE;
-        }));
-        registerFunction("-=", new BasicFunction("SUB_SET", (sc, in) -> 
+        });
+        registerFunction("++", (sc, in) -> 
+        {
+            Fraction f = in[0].getFraction(sc);
+            in[0].set(sc, f.add(new Fraction(1)));
+            return f;
+        });
+        registerAlias("++", "inc");
+        registerFunction("p+", (sc, in) -> 
+        {
+            Fraction f = in[0].getFraction(sc).add(new Fraction(1));
+            in[0].set(sc, f);
+            return f;
+        });
+        registerFunction("-=", (sc, in) -> 
         {
             in[0].set(sc, in[0].getFraction(sc).sub(in[1].getFraction(sc)));
             return Void.TYPE;
-        }));
-        registerFunction("*=", new BasicFunction("MUL_SET", (sc, in) -> 
+        });
+        registerFunction("--", (sc, in) -> 
+        {
+            Fraction f = in[0].getFraction(sc);
+            in[0].set(sc, f.sub(new Fraction(1)));
+            return f;
+        });
+        registerAlias("--", "dec");
+        registerFunction("p-", (sc, in) -> 
+        {
+            Fraction f = in[0].getFraction(sc).sub(new Fraction(1));
+            in[0].set(sc, f);
+            return f;
+        });
+        registerFunction("*=", (sc, in) -> 
         {
             in[0].set(sc, in[0].getFraction(sc).mul(in[1].getFraction(sc)));
             return Void.TYPE;
-        }));
-        registerFunction("/=", new BasicFunction("DIV_SET", (sc, in) -> 
+        });
+        registerFunction("/=", (sc, in) -> 
         {
             in[0].set(sc, in[0].getFraction(sc).div(in[1].getFraction(sc)));
             return Void.TYPE;
-        }));
-        registerFunction("%=", new BasicFunction("MOD_SET", (sc, in) -> 
+        });
+        registerFunction("%=", (sc, in) -> 
         {
             in[0].set(sc, new Fraction(in[0].getInt(sc) % in[1].getInt(sc)));
             return Void.TYPE;
-        }));
-        registerFunction("<<=", new BasicFunction("LEFT_SHIFT_SET", (sc, in) -> 
+        });
+        registerFunction("<<=", (sc, in) -> 
         {
             in[0].set(sc, in[0].getFraction(sc).leftShift(in[1].getInt(sc)));
             return Void.TYPE;
-        }));
-        registerFunction(">>=", new BasicFunction("RIGHT_SHIFT_SET", (sc, in) -> 
+        });
+        registerFunction(">>=", (sc, in) -> 
         {
             in[0].set(sc, in[0].getFraction(sc).rightShift(in[1].getInt(sc)));
             return Void.TYPE;
-        }));
-        registerFunction("&=", new BasicFunction("BIT_AND_SET", (sc, in) -> 
+        });
+        registerFunction("&=", (sc, in) -> 
         {
             in[0].set(sc, in[0].getFraction(sc).and(in[1].getFraction(sc)));
             return Void.TYPE;
-        }));
-        registerFunction("^=", new BasicFunction("BIT_XOR_SET", (sc, in) -> 
+        });
+        registerFunction("^=", (sc, in) -> 
         {
             in[0].set(sc, in[0].getFraction(sc).xor(in[1].getFraction(sc)));
             return Void.TYPE;
-        }));
-        registerFunction("|=", new BasicFunction("BIT_OR_SET", (sc, in) -> 
+        });
+        registerFunction("|=", (sc, in) -> 
         {
             in[0].set(sc, in[0].getFraction(sc).or(in[1].getFraction(sc)));
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("DIM", (sc, in) -> 
+        });
+        
+        // var stuff
+        registerFunction("getvar", (sc, in) -> sc.getVar(in[0].getString(sc)).get(sc));      
+        registerFunction("wait", (sc, in) -> 
         {
-            for(InputProvider input : in)
-            {
-                ((DynamicArray) input).init(sc);
-            }
+            sc.setWaiting(true);
             return Void.TYPE;
-        }));
-        registerAlias("DIM", "VAR");
-        registerFunction(new BasicFunction("SWAP", (sc, in) -> 
+        });
+        
+        // try - catch
+        registerFunction("try", (sc, in) -> 
         {
-            Object o = in[0].get(sc);
-            in[0].set(sc, in[1].get(sc));
-            in[1].set(sc, o);
+            // TODO
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("INC", (sc, in) -> 
+        });              
+        registerFunction("catch", (sc, in) -> 
         {
-            in[0].set(sc, in[0].getInt(sc) + (in.length > 1 ? in[1].getInt(sc) : 1));
+            // TODO
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("DEC", (sc, in) -> 
+        });  
+        
+        // branching
+        registerFunction("goto", (sc, in) -> 
         {
-            in[0].set(sc, in[0].getInt(sc) - (in.length > 1 ? in[1].getInt(sc) : 1));
+            sc.currentLine = sc.labels.get(in[0].getString(sc));
             return Void.TYPE;
-        }));
-        // ---------------------------------------------------------------------
-        // basic instructions (control and branching)
-        // ---------------------------------------------------------------------
-        registerFunction(new BasicFunction("goto", (sc, in) -> 
+        });
+        registerFunction("sgoto", (sc, in) -> 
         {
-            sc.currentLine = sc.labels.get(in[0].getString(sc));
+            // TODO
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("GOSUB", (sc, in) -> 
+        });
+        registerFunction("gosub", (sc, in) -> 
         {
             sc.returnStack.push(sc.currentLine);
             sc.currentLine = sc.labels.get(in[0].getString(sc));
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("return", (sc, in) -> 
+        });
+        registerFunction("return", (sc, in) -> 
         {
             if(sc.returnStack.isEmpty())
             {
@@ -307,8 +626,8 @@ public class FunctionLoader
                 sc.currentLine = sc.returnStack.pop();
             }
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("if", (sc, in) -> 
+        });
+        registerFunction("if", (sc, in) -> 
         {
             int p = in[0].getInt(sc);
             if(p == 0)
@@ -316,12 +635,26 @@ public class FunctionLoader
                 sc.currentLine += in[1].getInt(sc);
             }
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("endif", (sc, in) -> 
+        });
+        registerFunction("else", (sc, in) -> 
         {
+            // TODO
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("for", (sc, in) -> 
+        });  
+        registerFunction("while", (sc, in) -> 
+        {
+            if(in[0].getInt(sc) == 0)
+            {
+                sc.currentLine += in[1].getInt(sc);
+            }
+            return Void.TYPE;
+        });
+        registerFunction("wend", (sc, in) -> 
+        {
+            sc.currentLine += in[0].getInt(sc);
+            return Void.TYPE;
+        });
+        registerFunction("for", (sc, in) -> 
         {
             // for(var, start, end, step)
             Fraction start = in[1].getFraction(sc);
@@ -331,8 +664,8 @@ public class FunctionLoader
                 sc.currentLine += in[4].getInt(sc);
             }
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("next", (sc, in) -> 
+        });
+        registerFunction("next", (sc, in) -> 
         {
             int line = sc.currentLine + in[0].getInt(sc);
             InputProvider[] f = sc.code[line].getParameters();
@@ -344,240 +677,83 @@ public class FunctionLoader
                 sc.currentLine = line;
             }
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("while", (sc, in) -> 
-        {
-            if(in[0].getInt(sc) == 0)
-            {
-                sc.currentLine += in[1].getInt(sc);
-            }
-            return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("wend", (sc, in) -> 
+        });
+        registerFunction("continue", (sc, in) -> 
         {
             sc.currentLine += in[0].getInt(sc);
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("continue", (sc, in) -> 
+        });
+        registerFunction("break", (sc, in) -> 
         {
             sc.currentLine += in[0].getInt(sc);
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("break", (sc, in) -> 
+        });
+        
+        // comparing
+        registerFunction("==", (sc, in) -> Objects.equals(in[0].get(sc), in[1].get(sc)));
+        registerAlias("==", "equal");
+        registerAlias("==", "equals");
+        registerFunction("!=", (sc, in) -> !Objects.equals(in[0].get(sc), in[1].get(sc)));
+        registerAlias("!=", "notequal");
+        registerFunction("<", (sc, in) -> in[0].getFraction(sc).compareTo(in[1].getFraction(sc)) < 0);
+        registerAlias("<", "less");
+        registerFunction(">", (sc, in) -> in[0].getFraction(sc).compareTo(in[1].getFraction(sc)) > 0);
+        registerAlias(">", "greater");
+        registerFunction("<=", (sc, in) -> in[0].getFraction(sc).compareTo(in[1].getFraction(sc)) <= 0);
+        registerAlias("<=", "lessequal");
+        registerFunction(">=", (sc, in) -> in[0].getFraction(sc).compareTo(in[1].getFraction(sc)) >= 0);
+        registerAlias(">=", "greaterequal");
+        registerFunction("!", (sc, in) -> !in[0].getBoolean(sc));
+        registerAlias("!", "invert");
+        
+        // logical stuff
+        registerFunction("&&", (sc, in) -> Arrays.stream(in).map(i -> i.getBoolean(sc)).allMatch(s -> s));
+        registerAlias("&&", "and");
+        registerFunction("||", (sc, in) -> Arrays.stream(in).map(i -> i.getBoolean(sc)).anyMatch(s -> s));
+        registerAlias( "||", "or");
+        
+        // non grouped stuff
+        registerFunction("swap", (sc, in) -> 
         {
-            sc.currentLine += in[0].getInt(sc);
+            Object o = in[0].get(sc);
+            in[0].set(sc, in[1].get(sc));
+            in[1].set(sc, o);
             return Void.TYPE;
-        }));
-        // ---------------------------------------------------------------------
-        // mathematics
-        // ---------------------------------------------------------------------
-        registerFunction(new BasicFunction("FLOOR", (sc, in) -> 
-        {
-            return (int) Math.floor(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("ROUND", (sc, in) -> 
-        {
-            return (int) Math.round(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("CEIL", (sc, in) -> 
-        {
-            return (int) Math.ceil(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("ABS", (sc, in) -> 
-        {
-            return in[0].getFraction(sc).abs();
-        }));
-        registerFunction(new BasicFunction("SGN", (sc, in) -> 
-        {
-            double d = in[0].getDouble(sc);
-            return d < 0 ? -1 : (d > 0 ? 1 : 0);
-        }));
-        /*registerFunction(new BasicFunction("MIN", (sc, in) -> 
-        {
-            if(in.length == 1)
-            {
-                return ((IMathOperation) in[0]).min(sc);
-            }
-            double min = Arrays.stream(in).mapToDouble(i -> i.getDouble(sc)).min().getAsDouble();
-            if(min == (int) min)
-            {
-                return (int) min;
-            }
-            return min;
-        }));
-        registerFunction(new BasicFunction("MAX", (sc, in) -> 
-        {
-            if(in.length == 1)
-            {
-                return ((IMathOperation) in[0]).max(sc);
-            }
-            double max = Arrays.stream(in).mapToDouble(i -> i.getDouble(sc)).max().getAsDouble();
-            if(max == (int) max)
-            {
-                return (int) max;
-            }
-            return max;
-        }));*/
-        registerFunction(new BasicFunction("RND", (sc, in) -> 
-        {
-            int seedId;
-            int max;
-            switch (in.length) 
-            {
-                case 1:
-                    seedId = 0;
-                    max = in[0].getInt(sc);
-                    break;
-                case 2:
-                    seedId = in[0].getInt(sc);
-                    max = in[1].getInt(sc);
-                    break;
-                default:
-                    throw new IllegalArgumentException("invalid number of arguments");
-            }
-            if(seedId < 0 || seedId > 7)
-            {
-                throw new IllegalArgumentException("seed id must be from 0 to 7");
-            }
-            return RND[seedId].nextInt(max);
-        }));
-        registerFunction(new BasicFunction("RNDF", (sc, in) -> 
+        });
+        registerFunction("print", (sc, in) -> 
         {
-            int seedId = 0;
-            if(in.length > 0)
-            {
-                seedId = in[0].getInt(sc);
-            }
-            if(seedId < 0 || seedId > 7)
-            {
-                throw new IllegalArgumentException("seed id must be from 0 to 7");
-            }
-            return RND[seedId].nextDouble();
-        }));
-        registerFunction(new BasicFunction("RANDOMIZE", (sc, in) -> 
-        {
-            int seedId = in[0].getInt(sc);
-            if(seedId < 0 || seedId > 7)
-            {
-                throw new IllegalArgumentException("seed id must be from 0 to 7");
-            }
-            switch (in.length) 
-            {
-                case 1:
-                    RND[seedId] = new Random();
-                    break;
-                case 2:
-                    RND[seedId] = new Random(in[1].getInt(sc));
-                    break;
-                default:
-                    throw new IllegalArgumentException("invalid number of arguments");
-            }
+            System.out.println(Utils.connect(sc, in, 0));
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("SQR", (sc, in) -> 
-        {
-            return Math.sqrt(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("EXP", (sc, in) -> 
-        {
-            if(in.length == 0)
-            {
-                return Math.E;
-            }
-            return Math.exp(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("LOG", (sc, in) -> 
-        {
-            if(in.length >= 2)
-            {
-                return Math.log(in[0].getDouble(sc)) / Math.log(in[1].getDouble(sc));
-            }
-            return Math.log(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("POW", (sc, in) -> 
-        {
-            return Math.pow(in[0].getDouble(sc), in[1].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("PI", (sc, in) -> 
-        {
-            return Math.PI;
-        }));
-        registerFunction(new BasicFunction("RAD", (sc, in) -> 
-        {
-            return Math.toRadians(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("DEG", (sc, in) -> 
-        {
-            return Math.toDegrees(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("SIN", (sc, in) -> 
-        {
-            return Math.sin(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("COS", (sc, in) -> 
-        {
-            return Math.cos(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("TAN", (sc, in) -> 
-        {
-            return Math.tan(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("ASIN", (sc, in) -> 
+        });
+        
+        registerFunction("waitfor", (sc, in) ->    
         {
-            return Math.asin(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("ACOS", (sc, in) -> 
+            // TODO
+            return Void.TYPE;
+        });
+        registerFunction("term", (sc, in) -> 
         {
-            return Math.acos(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("ATAN", (sc, in) -> 
+            // TODO
+            // { termSafe(sc); throw new HoldCodeException(); }); 
+            return Void.TYPE;
+        });
+                
+        registerFunction("islong", (sc, in) ->                                           
         {
-            if(in.length >= 2)
+            Object o = in[0].get(sc);
+            if(o instanceof Fraction)
             {
-                return Math.atan2(in[0].getDouble(sc), in[1].getDouble(sc));
+                return ((Fraction) o).isLong();
             }
-            return Math.atan(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("SINH", (sc, in) -> 
-        {
-            return Math.sinh(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("COSH", (sc, in) -> 
+            return false;
+        });
+        registerFunction("assert", (sc, in) ->                                           
         {
-            return Math.cosh(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("TANH", (sc, in) -> 
-        {
-            return Math.tanh(in[0].getDouble(sc));
-        }));
-        registerFunction(new BasicFunction("CLASSIFY", (sc, in) -> 
-        {
-            double d = in[0].getDouble(sc);
-            if(Double.isNaN(d))
+            if(!in[0].getBoolean(sc))
             {
-                return 2;
+                throw new AssertionException("assertion failed");
             }
-            else if(Double.isInfinite(d))
-            {
-                return 1;
-            }
-            return 0;
-        }));
-        
-        
-        registerFunction(new BasicFunction("print", (sc, in) -> 
-        {
-            printMessage(Arrays.stream(in).map(s -> s.getString(sc)).collect(Collectors.joining()));
             return Void.TYPE;
-        }));
-        registerFunction(new BasicFunction("TEST", (sc, in) -> 
-        {
-            return 1;
-        }));
-    }
-    
-    private static void printMessage(String message)
-    {
-        System.out.println(message);
+        });
     }
 }

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

@@ -0,0 +1,16 @@
+package me.hammerle.snuviscript.code;
+
+public interface ISnuviLogger 
+{
+    /** Prints messages depending on the implementation.
+     *
+     * @param message a message, can be null
+     * @param ex an involved exception, can be null
+     * @param function an involved snuvi script function, can be null
+     * @param scriptname the name of an involved script, mainly used for 
+     * prescript exceptions, can be null, but will never be null if sc != null
+     * @param sc an involved script, can be null
+     * @param line an involved script line, -1 if no line is involved
+     */
+    public void print(String message, Exception ex, String function, String scriptname, Script sc, int line);
+}

+ 7 - 0
src/me/hammerle/snuviscript/code/ISnuviScheduler.java

@@ -0,0 +1,7 @@
+package me.hammerle.snuviscript.code;
+
+public interface ISnuviScheduler 
+{
+    public int scheduleTask(Runnable r);  
+    public int scheduleTask(Runnable r, long delay);
+}

+ 81 - 17
src/me/hammerle/snuviscript/code/Script.java

@@ -1,60 +1,68 @@
 package me.hammerle.snuviscript.code;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Stack;
 import me.hammerle.snuviscript.variable.Variable;
 
-public class Script 
+public final class Script 
 {
+    protected ISnuviLogger logger;
+    
     protected int currentLine;
     protected Instruction[] code;
+    protected boolean isWaiting;
     
     protected final HashMap<String, Integer> labels;
     protected final Stack<Integer> returnStack;
+    protected HashMap<String, Variable> vars;
     protected final Stack<HashMap<String, Variable>> localVars;
+    private final HashSet<String> events;
     
     protected Object returnValue;
     protected final boolean subScript;
     protected final String[] subScriptInput;
     protected final HashMap<String, Script> subScripts;
     
-    public Script(List<String> code)
+    protected boolean printStackTrace;
+    
+    protected final String name;
+    
+    public Script(ISnuviLogger logger, List<String> code, String name)
     {
+        this.logger = logger;
         this.subScriptInput = null;
         this.subScripts = new HashMap<>();
         this.labels = new HashMap<>();
         this.returnStack = new Stack<>();
         this.localVars = new Stack<>();
+        this.events = new HashSet<>();
         this.subScript = false;
         this.currentLine = 0;
+        this.isWaiting = false;
+        this.printStackTrace = false;
+        this.name = name;
         
         this.code = Compiler.compile(this, code, labels, subScript, 0);
-        
-        /*System.out.println("__________________________________");
-        subScripts.forEach((k, v) -> 
-        {
-            System.out.println(k);
-            for(Instruction in : v.code)
-            {
-                System.out.println(in);
-            }
-            System.out.println("__________________________________");
-        });*/
     }
     
     public Script(List<String> code, String[] subScriptInput, Script sc, int lineOffset)
     {
+        this.logger = sc.logger;
         this.subScriptInput = subScriptInput;
         this.subScripts = sc.subScripts;
         this.labels = new HashMap<>();
         this.returnStack = new Stack<>();
         this.localVars = sc.localVars;
+        this.events = sc.events;
         this.subScript = true;
-        
-        this.code = Compiler.compile(this, code, labels, subScript, lineOffset);
-
         this.currentLine = 0;
+        this.isWaiting = sc.isWaiting;
+        this.printStackTrace = false;
+        this.name = sc.name;
+        
+        this.code = Compiler.compile(this, code, labels, subScript, lineOffset); 
     }
     
     public HashMap<String, Variable> getLocalVars()
@@ -62,11 +70,15 @@ public class Script
         return localVars.peek();
     }
     
+    // -------------------------------------------------------------------------
+    // flow handling
+    // -------------------------------------------------------------------------
+    
     public Object run()
     {
         int length = code.length;
         returnValue = null;
-        while(currentLine < length)
+        while(currentLine < length && !isWaiting)
         {
             //System.out.println("EXECUTE: " + code[currentLine]);
             code[currentLine].execute(this);
@@ -79,4 +91,56 @@ public class Script
     {
         currentLine = code.length;
     }
+    
+    public void setWaiting(boolean isWaiting)
+    {
+        this.isWaiting = isWaiting;
+    }
+    
+    // -------------------------------------------------------------------------
+    // general stuff
+    // -------------------------------------------------------------------------
+
+    public String getName() 
+    {
+        return name;
+    }
+
+    public ISnuviLogger getLogger()
+    {
+        return logger;
+    }
+    
+    public Variable getVar(String name)
+    {
+        HashMap<String, Variable> map;
+        if(subScript)
+        {
+            map = localVars.peek();
+        }
+        else
+        {
+            map = vars;
+        }
+        return map.get(name);
+    }
+
+    // -------------------------------------------------------------------------
+    // event handling
+    // -------------------------------------------------------------------------
+    
+    public void loadEvent(String s)
+    {
+        events.add(s);
+    }
+    
+    public boolean isEventLoaded(String s)
+    {
+        return events.contains(s);
+    }
+    
+    public void unloadEvent(String s)
+    {
+        events.remove(s);
+    }
 }

+ 16 - 4
src/me/hammerle/snuviscript/code/Syntax.java

@@ -4,6 +4,10 @@ public enum Syntax
 {
     UNKNOWN(" ", 0, 0),
     MAYBE("", 0, 0),
+    INC("++", 2, 1),
+    POST_INC("p+", 2, 1),
+    DEC("--", 2, 1),
+    POST_DEC("p-", 2, 1),
     MUL("*", 3),
     DIV("/", 3),
     MOD("%", 3),
@@ -72,9 +76,13 @@ public enum Syntax
                     {
                         return ADD;
                     }
-                    else if(size == 2 && s.charAt(1) == '=')
+                    else if(size == 2)
                     {
-                        return ADD_SET;
+                        switch(s.charAt(1))
+                        {
+                            case '=':  return ADD_SET;
+                            case '+':  return INC;
+                        }
                     }
                     break;
                 case '-':
@@ -82,9 +90,13 @@ public enum Syntax
                     {
                         return SUB;
                     }
-                    else if(size == 2 && s.charAt(1) == '=')
+                    else if(size == 2)
                     {
-                        return SUB_SET;
+                        switch(s.charAt(1))
+                        {
+                            case '=':  return SUB_SET;
+                            case '-':  return DEC;
+                        }
                     }
                     break;
                 case '^':

+ 72 - 2
src/me/hammerle/snuviscript/code/DataUtils.java → src/me/hammerle/snuviscript/code/Utils.java

@@ -1,13 +1,29 @@
 package me.hammerle.snuviscript.code;
 
+import java.io.File;
+import java.io.IOException;
 import java.lang.reflect.Array;
+import java.nio.charset.MalformedInputException;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 import me.hammerle.snuviscript.exceptions.PreScriptException;
 
-public class DataUtils 
+public class Utils 
 {
+    private static final Random RANDOM = new Random();
+    
+    public static int randomInt(int min, int max)
+    {
+        return RANDOM.nextInt((max - min) + 1) + min;
+    }
+    
     // - in the number is handled somewhere else
     private static final Pattern NUMBER_PATTERN = Pattern.compile("^[0-9]*[.]{0,1}[0-9]*");
     
@@ -16,7 +32,7 @@ public class DataUtils
         return NUMBER_PATTERN.matcher(s).matches();
     }
     
-    private static final Pattern FUNCTION_PATTERN = Pattern.compile("^[a-zA-Z]*\\(.*\\)");
+    private static final Pattern FUNCTION_PATTERN = Pattern.compile("^[a-zA-Z.]*\\(.*\\)");
     
     public static boolean isFunction(String s)
     {
@@ -200,4 +216,58 @@ public class DataUtils
         sb.append("]");
         return sb.toString();
     }
+    
+    // -------------------------------------------------------------------------
+    // connectors
+    // -------------------------------------------------------------------------
+    
+    public static String connect(Script sc, InputProvider[] c, int skip)
+    {
+        return Arrays.stream(c, skip, c.length).map(o -> o.getString(sc)).collect(Collectors.joining());
+    }
+    
+    public static String connect(Collection<Object> c, int skip)
+    {
+        return c.stream().skip(skip).map(o -> o.toString()).collect(Collectors.joining());
+    }
+    
+    public static String connect(Script sc, InputProvider[] c, String s, int skip)
+    {
+        return Arrays.stream(c, skip, c.length).map(o -> o.getString(sc)).collect(Collectors.joining(s));
+    }
+    
+    public static String connect(Collection<Object> c, String s, int skip)
+    {
+        return c.stream().skip(skip).map(o -> String.valueOf(o)).collect(Collectors.joining(s));
+    }
+    
+    // -------------------------------------------------------------------------
+    // file stuff
+    // -------------------------------------------------------------------------
+    
+    public static List<String> readCode(String filename, String ending)
+    {
+        File script = new File("./" + filename + ending);  
+        if(script.exists())
+        {
+            try
+            {
+                return Files.readAllLines(script.toPath());
+            } 
+            catch (MalformedInputException ex) 
+            {
+                throw new PreScriptException("'" + filename + "' contains an illegal character, change file encoding", 0);
+            }
+            catch (IOException ex) 
+            {
+                throw new PreScriptException("file '" + filename + "' cannot be read", 0);
+            }
+        }
+        throw new PreScriptException("file '" + filename + "' does not exist", 0);
+    }
+    
+    public static List<String> readCode(String filename)
+    {
+        return readCode(filename, ".snuvi");
+    }
 }

+ 221 - 0
src/me/hammerle/snuviscript/config/SnuviConfig.java

@@ -0,0 +1,221 @@
+package me.hammerle.snuviscript.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.MalformedInputException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+import me.hammerle.snuviscript.code.ISnuviLogger;
+import me.hammerle.snuviscript.code.Script;
+import me.hammerle.snuviscript.code.Compiler;
+import me.hammerle.snuviscript.math.Fraction;
+
+public class SnuviConfig
+{            
+    protected final ISnuviLogger logger;
+    protected final TreeMap<String, Object> conf;
+    private final File file;
+    private Script sc;
+    
+    private SnuviConfig(Script sc, ISnuviLogger logger, String path, String name)
+    {    
+        this.sc = sc;
+        this.logger = logger;
+        StringBuilder sb = new StringBuilder("./");
+        sb.append(path);
+        sb.append("/");
+        sb.append(name);
+        sb.append(".snuvic");
+        file = new File(sb.toString());
+        conf = new TreeMap<>();
+    }
+    
+    public SnuviConfig(ISnuviLogger logger, String path, String name)
+    {    
+        this(null, logger, path, name);
+    }
+    
+    public SnuviConfig(Script sc, String path, String name)
+    {    
+        this(sc, sc.getLogger(), path, name);
+    }
+    
+    private void print(String message, Exception ex)
+    {
+        logger.print(message, ex, null, sc == null ? null : sc.getName(), sc, -1);
+    }
+    
+    private void print(String message)
+    {
+        print(message, null);
+    }
+    
+    public final void load()
+    {
+        if(!exists())
+        {
+            print("cannot load non existent file '" + file.getPath() + "'");
+            return;
+        }
+        try
+        {
+            String warning = "wrong syntax in '" + file.getPath() + "'";
+            Files.readAllLines(file.toPath()).stream().forEach(s -> 
+            {
+                int b = s.indexOf("=");
+                if(b == -1)
+                {
+                    print(warning);
+                    print(s);
+                }
+                else
+                {
+                    conf.put(s.substring(0, b).trim(), Compiler.convert(s.substring(b + 1)));
+                }
+            });
+        } 
+        catch(MalformedInputException ex) 
+        {
+            print("'" + file.getPath() + "' contains an illegal character, change file encoding", ex);
+        }
+        catch(OutOfMemoryError ex) 
+        {
+            print("'" + file.getPath() + "' is too big");
+        }
+        catch(SecurityException ex) 
+        {
+            print("'" + file.getPath() + "' is not accessable", ex);
+        }
+        catch(IOException ex) 
+        {
+            print("'" + file.getPath() + "' cannot be read", ex);
+        }
+    }   
+    
+    public final boolean exists()
+    {
+        return file.exists();
+    }
+    
+    public final boolean delete()
+    {
+        return file.delete();
+    }
+    
+    public final boolean save()
+    {
+        try
+        {
+            if(file.getParentFile() != null)
+            {
+                file.getParentFile().mkdirs();
+            }
+            if(!file.exists())
+            {
+                try
+                {
+                    file.createNewFile();
+                }
+                catch(IOException ex)
+                {
+                    print("'" + file.getPath() + "' cannot be created", ex);
+                    return false;
+                }
+            }
+            Files.write(Paths.get(file.toURI()), conf.entrySet().stream()
+                            .map(e -> 
+                            {
+                                if(e.getValue().getClass() == String.class)
+                                {
+                                    return e.getKey() + "=\"" + e.getValue() + "\"";
+                                }
+                                return e.getKey() + "=" + String.valueOf(e.getValue());
+                            })
+                            .collect(Collectors.toList()), StandardCharsets.UTF_8);
+            return true;
+        }
+        catch(UnsupportedOperationException ex)
+        {
+            print("an unsupported operation was used", ex);
+            return false;
+        }
+        catch(SecurityException ex)
+        {
+            print("'" + file.getPath() + "' is not accessable", ex);
+            return false;
+        }
+        catch(IOException ex)
+        {
+            print("cannot write to '" + file.getPath() + "'", ex);
+            return false;
+        }
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // getter
+    // -----------------------------------------------------------------------------------
+    
+    public final <T> T get(String key, Class<T> c, T error)
+    {
+        try
+        {
+            Object o = conf.get(key);
+            if(o == null)
+            {
+                return error;
+            }
+            return c.cast(o);
+        }
+        catch(ClassCastException ex)
+        {
+            return error;
+        }
+    }
+    
+    public final String getString(String key, String error)
+    {
+        return get(key, String.class, error);
+    }
+    
+    public final String getString(String key)
+    {
+        return getString(key, null);
+    }
+    
+    public final float getFloat(String key, float error)
+    {
+        return get(key, Fraction.class, Fraction.fromDouble(error)).floatValue();
+    }
+    
+    public final double getDouble(String key, double error)
+    {
+        return get(key, Fraction.class, Fraction.fromDouble(error)).doubleValue();
+    }
+    
+    public final int getInt(String key, int error)
+    {
+        return get(key, Fraction.class, Fraction.fromDouble(error)).intValue();
+    }
+    
+    public final Fraction getFraction(String key, Fraction error)
+    {
+        return get(key, Fraction.class, error);
+    }
+    
+    public final boolean getBoolean(String key, boolean error)
+    {
+        return get(key, Boolean.class, error);
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // set
+    // -----------------------------------------------------------------------------------
+    
+    public final void set(String key, Object o)
+    {
+        conf.put(key, o);
+    }
+}

+ 9 - 0
src/me/hammerle/snuviscript/exceptions/AssertionException.java

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

+ 9 - 0
src/me/hammerle/snuviscript/exceptions/FileIOException.java

@@ -0,0 +1,9 @@
+package me.hammerle.snuviscript.exceptions;
+
+public class FileIOException extends RuntimeException
+{
+    public FileIOException(String message)
+    {
+        super(message);
+    }
+}

+ 2 - 2
src/me/hammerle/snuviscript/variable/ArrayVariable.java

@@ -1,6 +1,6 @@
 package me.hammerle.snuviscript.variable;
 
-import me.hammerle.snuviscript.code.DataUtils;
+import me.hammerle.snuviscript.code.Utils;
 import me.hammerle.snuviscript.code.Script;
 
 public class ArrayVariable extends Variable
@@ -13,7 +13,7 @@ public class ArrayVariable extends Variable
     @Override
     public String getString(Script sc) 
     {
-        return DataUtils.getArrayString(get(sc));
+        return Utils.getArrayString(get(sc));
     }
 
     @Override

+ 2 - 2
src/me/hammerle/snuviscript/variable/LocalArrayVariable.java

@@ -1,7 +1,7 @@
 package me.hammerle.snuviscript.variable;
 
 import java.util.HashMap;
-import me.hammerle.snuviscript.code.DataUtils;
+import me.hammerle.snuviscript.code.Utils;
 import me.hammerle.snuviscript.code.Script;
 
 public class LocalArrayVariable extends LocalVariable
@@ -14,7 +14,7 @@ public class LocalArrayVariable extends LocalVariable
     @Override
     public String getString(Script sc) 
     {
-        return DataUtils.getArrayString(get(sc));
+        return Utils.getArrayString(get(sc));
     }
     
     @Override

+ 13 - 14
test.sbasic

@@ -1,16 +1,15 @@
-function fac(n) 
-{ 
-    if(n == 1)
-    {
-        return 1;
-    }
-    return n * fac(n - 1);
-}
+list.new(a);
+list.add(a, 1);
+list.add(a, 36);
+list.add(a, 34);
+list.add(a, 6);
 
-function test() 
-{ 
-    print("Hallo");
-}
+list.add(getVar("a"), 6);
 
-test();
-print(fac(6));
+print(a);
+print(getVar("a"));
+
+for(i, 0, list.getsize(a) - 1)
+{
+    print(list.get(a, i));
+}