123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146 |
- package me.hammerle.code;
- import java.io.File;
- import java.io.IOException;
- import java.lang.reflect.InvocationTargetException;
- import java.nio.charset.StandardCharsets;
- import java.nio.file.Files;
- import java.nio.file.Paths;
- import me.hammerle.exceptions.HoldCodeException;
- import java.time.ZonedDateTime;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Calendar;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.GregorianCalendar;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.function.BiFunction;
- import java.util.function.BiConsumer;
- import java.util.function.Consumer;
- import java.util.function.Predicate;
- import java.util.stream.Collectors;
- import me.hammerle.exceptions.FileIOException;
- import me.hammerle.exceptions.GotoLabelNotFoundException;
- import me.hammerle.exceptions.PreScriptException;
- import me.hammerle.math.Fraction;
- public class SnuviParser
- {
- protected final ISnuviLogger logger;
- private final ISnuviScheduler scheduler;
- private final HashMap<String, BiFunction<Object[], Script, Object>> functions;
- public boolean printStack;
-
- private int idCounter;
- private final HashMap<Integer, Script> scripts;
- private final ArrayList<Integer> termQueue;
-
- public SnuviParser(ISnuviLogger logger, ISnuviScheduler scheduler)
- {
- this.logger = logger;
- this.scheduler = scheduler;
- functions = new HashMap<>();
- registerStandardLibraries();
-
- printStack = false;
-
- scripts = new HashMap<>();
- termQueue = new ArrayList<>();
- idCounter = 0;
- }
-
- // -----------------------------------------------------------------------------------
- // function registry
- // -----------------------------------------------------------------------------------
-
- public boolean isRegisteredFunction(String s)
- {
- return functions.containsKey(s);
- }
-
- public void registerFunction(String s, BiFunction<Object[], Script, Object> f)
- {
- functions.put(s, f);
- }
-
- public void registerConsumer(String s, BiConsumer<Object[], Script> f)
- {
- functions.put(s, (BiFunction<Object[], Script, Object>) (args, sc) ->
- {
- f.accept(args, sc);
- return Void.TYPE;
- });
- }
-
- public void registerAlias(String alias, String original)
- {
- BiFunction<Object[], Script, Object> f = functions.get(original);
- if(f == null)
- {
- throw new IllegalArgumentException("registering alias for non existent function");
- }
- registerFunction(alias, functions.get(original));
- }
-
- @SuppressWarnings("unchecked")
- private void registerStandardLibraries()
- {
- registerFunction("nothing", (args, sc) ->
- 0);
- registerFunction("", (args, sc) ->
- args[0]);
- registerConsumer("gotoline", (args, sc) ->
- {
- sc.jump();
- sc.incLoopCounter();
- });
- registerConsumer("error", (args, sc) ->
- printStack = !printStack);
-
- // -------------------------------------------------------------------------------
- // event
- // -------------------------------------------------------------------------------
- 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()));
- // -------------------------------------------------------------------------------
- // bit
- // -------------------------------------------------------------------------------
-
- registerFunction(">>", (args, qd) ->
- ((Fraction) args[0]).rightShift(getInt(args[1])));
- registerFunction("<<", (args, qd) ->
- ((Fraction) args[0]).leftShift(getInt(args[1])));
- registerFunction("&", (args, qd) ->
- ((Fraction) args[0]).and((Fraction) args[1]));
- registerFunction("|", (args, qd) ->
- ((Fraction) args[0]).or((Fraction) args[1]));
- registerFunction("^", (args, qd) ->
- ((Fraction) args[0]).xor((Fraction) args[1]));
- registerFunction("~", (args, qd) ->
- ((Fraction) args[0]).invertBits());
- registerFunction("bit.set", (args, qd) ->
- ((Fraction) args[0]).setBit(getInt(args[1])));
- registerFunction("bit.unset", (args, qd) ->
- ((Fraction) args[0]).unsetBit(getInt(args[1])));
- registerFunction("bit.get", (args, qd) ->
- ((Fraction) args[0]).getBit(getInt(args[1])));
-
- // -------------------------------------------------------------------------------
- // math
- // -------------------------------------------------------------------------------
- registerFunction("%", (args, sc) ->
- new Fraction(getInt(args[0]) % getInt(args[1])));
- registerAlias("math.mod", "%");
- registerFunction("math.abs", (args, sc) ->
- ((Fraction) args[0]).abs());
- registerFunction("math.pow", (args, sc) ->
- ((Fraction) args[0]).power((Fraction) args[1]));
- registerFunction("math.root", (args, sc) ->
- ((Fraction) args[0]).power(((Fraction) args[1]).invert()));
- registerFunction("math.sin", (args, sc) ->
- ((Fraction) args[0]).sin());
- registerFunction("math.cos", (args, sc) ->
- ((Fraction) args[0]).cos());
- registerFunction("math.tan", (args, sc) ->
- ((Fraction) args[0]).tan());
- registerFunction("math.asin", (args, sc) ->
- ((Fraction) args[0]).asin());
- registerFunction("math.acos", (args, sc) ->
- ((Fraction) args[0]).acos());
- registerFunction("math.atan", (args, sc) ->
- ((Fraction) args[0]).atan());
- registerFunction("math.e", (args, sc) ->
- Fraction.E);
- registerFunction("math.pi", (args, sc) ->
- Fraction.PI);
- registerFunction("math.ln", (args, sc) ->
- ((Fraction) args[0]).log());
- registerFunction("math.log", (args, sc) ->
- ((Fraction) args[0]).log());
- registerFunction("math.random", (args, sc) ->
- new Fraction(ScriptUtils.randomInt(getInt(args[0]), getInt(args[1]))));
- registerFunction("math.round", (args, sc) ->
- ((Fraction) args[0]).round());
- registerFunction("math.rounddown", (args, sc) ->
- ((Fraction) args[0]).floor());
- registerFunction("math.roundup", (args, sc) ->
- ((Fraction) args[0]).ceil());
- registerFunction("math.roundcomma", (args, sc) ->
- ((Fraction) args[0]).round(getInt(args[1])));
-
- // -------------------------------------------------------------------------------
- // lists
- // -------------------------------------------------------------------------------
- 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) ->
- new Fraction(((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) ->
- new Fraction(((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]));
-
- // -------------------------------------------------------------------------------
- // arrays
- // -------------------------------------------------------------------------------
- registerConsumer("array.new", (args, sc) ->
- sc.setVar(args[0].toString(), new Object[ScriptUtils.getInt(args[1])]));
- registerConsumer("array.=", (args, sc) ->
- ((Object[]) sc.getVar(args[0].toString()))[ScriptUtils.getInt(args[1])] = args[2]);
- registerAlias("array.set", "array.=");
- registerFunction("array.get", (args, sc) ->
- ((Object[]) sc.getVar(args[0].toString()))[ScriptUtils.getInt(args[1])]);
- registerFunction("array.++", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ((Fraction) o[i]).add(new Fraction(1));
- return o[i];
- });
- registerFunction("array.--", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ((Fraction) o[i]).sub(new Fraction(1));
- return o[i];
- });
- registerFunction("array.p+", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- Fraction f = (Fraction) o[i];
- o[i] = f.add(new Fraction(1));
- return f;
- });
- registerFunction("array.p-", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- Fraction f = (Fraction) o[i];
- o[i] = f.sub(new Fraction(1));
- return f;
- });
- registerConsumer("array.+=", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ((Fraction) o[i]).add((Fraction) args[2]);
- });
- registerConsumer("array.-=", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ((Fraction) o[i]).sub((Fraction) args[2]);
- });
- registerConsumer("array.*=", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ((Fraction) o[i]).mul((Fraction) args[2]);
- });
- registerConsumer("array./=", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ((Fraction) o[i]).div((Fraction) args[2]);
- });
- registerConsumer("array.%=", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ScriptUtils.getInt(o[i]) % ScriptUtils.getInt(args[2]);
- });
- registerConsumer("array.<<=", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ((Fraction) o[i]).leftShift(ScriptUtils.getInt(args[2]));
- });
- registerConsumer("array.>>=", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ((Fraction) o[i]).rightShift(ScriptUtils.getInt(args[2]));
- });
- registerConsumer("array.&=", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ((Fraction) o[i]).and((Fraction) args[2]);
- });
- registerConsumer("array.^=", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ((Fraction) o[i]).xor((Fraction) args[2]);
- });
- registerConsumer("array.|=", (args, sc) ->
- {
- Object[] o = (Object[]) sc.getVar(args[0].toString());
- int i = ScriptUtils.getInt(args[1]);
- o[i] = ((Fraction) o[i]).or((Fraction) args[2]);
- });
- registerFunction("array.getsize", (args, sc) ->
- ((Object[]) args[0]).length);
- registerConsumer("array.swap", (args, sc) ->
- {
- Object[] o = (Object[]) args[0];
- int first = ScriptUtils.getInt(args[1]);
- int sec = ScriptUtils.getInt(args[2]);
- Object helper = o[first];
- o[first] = o[sec];
- o[sec] = helper;
- });
- registerConsumer("array.sort", (args, sc) ->
- {
- if(args.length <= 1)
- {
- Arrays.sort((Object[]) args[0]);
- }
- else
- {
- Arrays.sort((Object[]) args[0], ScriptUtils.getInt(args[1]), ScriptUtils.getInt(args[2]));
- }
- });
- registerConsumer("array.copy", (args, sc) ->
- {
- int first = ScriptUtils.getInt(args[2]);
- System.arraycopy((Object[]) args[0], first, (Object[]) args[1],
- ScriptUtils.getInt(args[4]), ScriptUtils.getInt(args[3]) - first + 1);
- });
- registerConsumer("array.rsort", (args, sc) ->
- {
- if(args.length <= 1)
- {
- Arrays.sort((Object[]) args[0], (Object o, Object o1) -> -((Comparable) o).compareTo(o));
- }
- else
- {
- Arrays.sort((Object[]) args[0], ScriptUtils.getInt(args[1]),
- ScriptUtils.getInt(args[2]), (Object o, Object o1) -> -((Comparable) o).compareTo(o));
- }
- });
- registerConsumer("array.fill", (args, sc) ->
- {
- if(args.length <= 2)
- {
- Arrays.fill((Object[]) args[0], args[1]);
- }
- else
- {
- Arrays.fill((Object[]) args[0], ScriptUtils.getInt(args[2]), ScriptUtils.getInt(args[3]), args[1]);
- }
- });
-
- // -------------------------------------------------------------------------------
- // maps
- // -------------------------------------------------------------------------------
- registerConsumer("map.new", (args, sc) ->
- sc.setVar(args[0].toString(), new HashMap<>()));
- registerFunction("map.exists", (args, sc) ->
- args[0] instanceof Map);
- 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) ->
- new Fraction(((HashMap) args[0]).size()));
- registerFunction("map.get", (args, sc) ->
- ((HashMap) args[0]).get(args[1]));
- registerConsumer("map.clear", (args, sc) ->
- ((HashMap) args[0]).clear());
- registerConsumer("map.keys", (args, sc) ->
- sc.setVar(args[0].toString(), ((HashMap) args[1]).keySet().stream().collect(Collectors.toList())));
- registerConsumer("map.values", (args, sc) ->
- sc.setVar(args[0].toString(), ((HashMap) args[1]).values().stream().collect(Collectors.toList())));
-
- // -------------------------------------------------------------------------------
- // sets
- // -------------------------------------------------------------------------------
- registerConsumer("set.new", (args, sc) ->
- sc.setVar(args[0].toString(), new HashSet<>()));
- registerFunction("set.exists", (args, sc) ->
- args[0] instanceof Set);
- 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) ->
- new Fraction(((HashSet) args[0]).size()));
- registerConsumer("set.tolist", (args, sc) ->
- sc.setVar(args[0].toString(), ((HashSet) args[1]).stream().collect(Collectors.toList())));
- // -------------------------------------------------------------------------------
- // time
- // -------------------------------------------------------------------------------
- registerFunction("time.get", (args, sc) ->
- new Fraction(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));
-
- // -------------------------------------------------------------------------------
- // text
- // -------------------------------------------------------------------------------
- registerFunction("text.number", (args, sc) ->
- fractionToDoubleString((Fraction) args[0]));
- registerFunction("text.class", (args, sc) ->
- args[0].getClass().getSimpleName());
- registerFunction("text.tolowercase", (args, sc) ->
- ScriptUtils.connect(args, 0).toLowerCase());
- registerAlias("tolowercase", "text.tolowercase");
- registerFunction("text.touppercase", (args, sc) ->
- ScriptUtils.connect(args, 0).toUpperCase());
- registerAlias("touppercase", "text.touppercase");
- registerConsumer("text.split", (args, sc) ->
- split(args, sc));
- registerAlias("split", "text.split");
- registerFunction("text.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())));
- registerAlias("concatlist", "text.concatlist");
- registerFunction("text.concat", (args, sc) ->
- ScriptUtils.connect(args, 0));
- registerAlias("concat", "text.concat");
- registerFunction("text", (args, sc) ->
- String.valueOf(args[0]));
- registerFunction("text.substring", (args, sc) ->
- args[0].toString().substring(getInt(args[1]), getInt(args[2])));
- registerFunction("text.length", (args, sc) ->
- args[0].toString().length());
- registerFunction("text.startswith", (args, sc) ->
- args[0].toString().startsWith(args[1].toString(), getInt(args[2])));
- registerFunction("text.endswith", (args, sc) ->
- args[0].toString().endsWith(args[1].toString()));
- registerFunction("text.contains", (args, sc) ->
- args[0].toString().contains(args[1].toString()));
- registerFunction("text.indexof", (args, sc) ->
- args[0].toString().indexOf(args[1].toString(), getInt(args[2])));
- registerFunction("text.lastindexof", (args, sc) ->
- args[0].toString().lastIndexOf(args[1].toString(), getInt(args[2])));
- registerFunction("text.replace", (args, sc) ->
- args[0].toString().replace(args[1].toString(), args[2].toString()));
- registerFunction("text.trim", (args, sc) ->
- args[0].toString().trim());
- registerFunction("text.charat", (args, sc) ->
- String.valueOf(args[0].toString().charAt(getInt(args[1]))));
- registerFunction("text.charcode", (args, sc) ->
- new Fraction(args[0].toString().charAt(getInt(args[1]))));
- registerFunction("text.fromcode", (args, sc) ->
- new String(new char[] {(char) ScriptUtils.getInt(args[0])}));
-
- // -------------------------------------------------------------------------------
- // files
- // -------------------------------------------------------------------------------
-
- registerFunction("file.new", (args, sc) ->
- new File(args[0].toString()));
- registerFunction("file.exists", (args, sc) ->
- ((File) args[0]).exists());
- registerFunction("file.delete", (args, sc) ->
- ((File) args[0]).delete());
- registerFunction("file.getname", (args, sc) ->
- ((File) args[0]).getName());
- registerFunction("file.rename", (args, sc) ->
- ((File) args[0]).renameTo(new File(args[1].toString())));
- registerConsumer("file.getlist", (args, sc) ->
- sc.setVar(args[0].toString(), Arrays.asList(((File) args[0]).listFiles())));
- registerConsumer("file.read", (args, sc) ->
- readFile(args, sc));
- registerConsumer("file.write", (args, sc) ->
- writeFile(args, sc));
-
- // -------------------------------------------------------------------------------
- // commands without library
- // -------------------------------------------------------------------------------
- registerFunction("+", (args, sc) ->
- ((Fraction) args[0]).add((Fraction) args[1]));
- registerAlias("add", "+");
- registerFunction("-", (args, sc) ->
- ((Fraction) args[0]).sub((Fraction) args[1]));
- registerAlias("sub", "-");
- registerConsumer("+=", (args, sc) ->
- {
- String s = args[0].toString();
- sc.setVar(s, ((Fraction) sc.getVar(s)).add((Fraction) args[1]));
- });
- registerConsumer("-=", (args, sc) ->
- {
- String s = args[0].toString();
- sc.setVar(s, ((Fraction) sc.getVar(s)).sub((Fraction) args[1]));
- });
- registerConsumer("*=", (args, sc) ->
- {
- String s = args[0].toString();
- sc.setVar(s, ((Fraction) sc.getVar(s)).mul((Fraction) args[1]));
- });
- registerConsumer("/=", (args, sc) ->
- {
- String s = args[0].toString();
- sc.setVar(s, ((Fraction) sc.getVar(s)).div((Fraction) args[1]));
- });
- registerConsumer("%=", (args, sc) ->
- {
- String s = args[0].toString();
- sc.setVar(s, ScriptUtils.getInt(sc.getVar(s)) % ScriptUtils.getInt(args[1]));
- });
- registerConsumer("<<=", (args, sc) ->
- {
- String s = args[0].toString();
- sc.setVar(s, ((Fraction) sc.getVar(s)).leftShift(ScriptUtils.getInt(args[1])));
- });
- registerConsumer(">>=", (args, sc) ->
- {
- String s = args[0].toString();
- sc.setVar(s, ((Fraction) sc.getVar(s)).rightShift(ScriptUtils.getInt(args[1])));
- });
- registerConsumer("&=", (args, sc) ->
- {
- String s = args[0].toString();
- sc.setVar(s, ((Fraction) sc.getVar(s)).and((Fraction) args[1]));
- });
- registerConsumer("^=", (args, sc) ->
- {
- String s = args[0].toString();
- sc.setVar(s, ((Fraction) sc.getVar(s)).xor((Fraction) args[1]));
- });
- registerConsumer("|=", (args, sc) ->
- {
- String s = args[0].toString();
- sc.setVar(s, ((Fraction) sc.getVar(s)).or((Fraction) args[1]));
- });
- registerFunction("inc", (args, sc) ->
- {
- String s = args[0].toString();
- Fraction n = ((Fraction) sc.getVar(s)).add(new Fraction(1));
- sc.setVar(s, n);
- return n;
- });
- registerAlias("++", "inc");
- registerFunction("dec", (args, sc) ->
- {
- String s = args[0].toString();
- Fraction n = ((Fraction) sc.getVar(s)).add(new Fraction(-1));
- sc.setVar(s, n);
- return n;
- });
- registerAlias("--", "dec");
- registerFunction("p+", (args, sc) ->
- {
- String s = args[0].toString();
- Fraction n = (Fraction) sc.getVar(s);
- sc.setVar(s, n.add(new Fraction(1)));
- return n;
- });
- registerFunction("p-", (args, sc) ->
- {
- String s = args[0].toString();
- Fraction n = (Fraction) sc.getVar(s);
- sc.setVar(s, n.add(new Fraction(-1)));
- return n;
- });
- registerFunction("*", (args, sc) ->
- ((Fraction) args[0]).mul((Fraction) args[1]));
- registerAlias("mul", "*");
- registerFunction("/", (args, sc) ->
- ((Fraction) args[0]).div((Fraction) args[1]));
- registerAlias("div", "/");
- registerFunction("getvar", (args, sc) ->
- sc.getVar(args[0].toString()));
- registerConsumer("setvar", (args, sc) ->
- sc.setVar(args[0].toString(), args[1]));
- registerAlias("=", "setvar");
- registerConsumer("removevar", (args, sc) ->
- sc.removeVar(args[0].toString()));
- registerConsumer("reset", (args, sc) ->
- sc.resetLoopCounter());
- registerConsumer("wait", (args, sc) ->
- { sc.resetLoopCounter(); throw new HoldCodeException(); });
-
- // branching
- registerConsumer("goto", (args, sc) ->
- sc.gotoLabel(args[0].toString(), false, true));
- registerConsumer("sgoto", (args, sc) ->
- scheduleGoto(args, sc));
- registerConsumer("gosub", (args, sc) ->
- sc.gotoLabelWithReturn(args[0].toString()));
- // push / pop values for functions
- registerConsumer("pusharg", (args, sc) ->
- sc.pushFunctionInput(args));
- registerFunction("poparg", (args, sc) ->
- sc.popFunctionInput());
- // push / pop values for saving
- registerConsumer("push", (args, sc) ->
- sc.push(0, args));
- registerConsumer("pop", (args, sc) ->
- sc.pop(args));
-
- registerConsumer("return", (args, sc) ->
- sc.doReturn());
- registerConsumer("try", (args, sc) ->
- sc.saveTryJumpLine());
- registerConsumer("catch", (args, sc) ->
- {
- sc.resetTryJumpLine();
- sc.jump();
- });
- registerConsumer("if", (args, sc) ->
- ifFunction(args, sc));
- registerConsumer("else", (args, sc) ->
- sc.jump());
- registerConsumer("while", (args, sc) ->
- whileFunction(args, sc));
- registerConsumer("for", (args, sc) ->
- {
- Fraction f = sc.nextRepeatData((Fraction) args[1], (Fraction) args[3]);
- sc.setVar(args[0].toString(), f);
- if(sc.repeatFinished(f, (Fraction) args[3], (Fraction) args[2]))
- {
- sc.clearRepeatData();
- sc.jump();
- }
- });
- registerConsumer("break", (args, sc) ->
- sc.jump());
- registerConsumer("breakreset", (args, sc) ->
- {
- sc.jump();
- sc.clearLastRepeatData();
- });
- registerConsumer("continue", (args, sc) ->
- sc.jump());
- registerFunction("==", (args, sc) ->
- isEqual(args));
- registerAlias("equal", "==");
- registerAlias("equals", "==");
- registerFunction("<", (args, sc) ->
- ((Fraction) args[0]).compareTo((Fraction) args[1]) < 0);
- registerAlias("less", "<");
- registerFunction(">", (args, sc) ->
- ((Fraction) args[0]).compareTo((Fraction) args[1]) > 0);
- registerAlias("greater", ">");
- registerFunction("!=", (args, sc) ->
- !isEqual(args));
- registerAlias("notequal", "!=");
- registerFunction("<=", (args, sc) ->
- ((Fraction) args[0]).compareTo((Fraction) args[1]) <= 0);
- registerAlias("lessequal", "<=");
- registerFunction(">=", (args, sc) ->
- ((Fraction) args[0]).compareTo((Fraction) args[1]) >= 0);
- registerAlias("greaterequal", ">=");
- registerFunction("!", (args, sc) ->
- !((boolean) args[0]));
- registerAlias("invert", "!");
- registerFunction("&&", (args, sc) ->
- Arrays.stream(args).allMatch(s -> s.equals(true)));
- registerAlias("and", "&&");
- registerFunction("||", (args, sc) ->
- Arrays.stream(args).anyMatch(s -> s.equals(true)));
- registerAlias("or", "||");
- registerConsumer("waitfor", (args, sc) ->
- waitFor(args, sc));
- registerConsumer("term", (args, sc) ->
- { termSafe(sc); throw new HoldCodeException(); });
- registerConsumer("swap", (args, sc) ->
- {
- String first = args[0].toString();
- String sec = args[1].toString();
- Object helper = sc.getVar(first);
- sc.setVar(first, sc.getVar(sec));
- sc.setVar(sec, helper);
- });
- }
-
- @SuppressWarnings("unchecked")
- protected Object parseFunction(Script sc, String function, Object[] args) throws HoldCodeException
- {
- try
- {
- BiFunction<Object[], Script, Object> bif = functions.get(function);
- if(bif == null)
- {
- try
- {
- sc.gotoLabelWithReturn(function);
- sc.pushFunctionInput(args, new Fraction(args.length));
- return Void.TYPE;
- }
- catch(GotoLabelNotFoundException ex)
- {
- throw new NoSuchMethodException(function);
- }
- }
- return bif.apply(args, sc);
- }
- catch(HoldCodeException ex)
- {
- throw ex;
- }
- catch(Exception ex)
- {
- if(printStack)
- {
- ex.printStackTrace();
- }
- if(sc.getTryJumpLine() != -1)
- {
- sc.setVar("error", ex.getClass().getSimpleName());
- sc.gotoTryJumpLine();
- sc.resetTryJumpLine();
- return Void.TYPE;
- }
- logger.printException(ex, function, sc, sc.getActiveRealCodeLine());
- sc.resetLoopCounter();
- throw new HoldCodeException();
- }
- }
-
- // -----------------------------------------------------------------------------------
- // script controller
- // -----------------------------------------------------------------------------------
-
- public Script getScript(int id)
- {
- return scripts.get(id);
- }
-
- public boolean termUnsafe(Script sc)
- {
- if(sc == null)
- {
- return false;
- }
- sc.setInvalid();
- sc.onTerm();
- return scripts.remove(sc.getId()) != null;
- }
-
- public void termSafe(Script sc)
- {
- if(sc == null)
- {
- return;
- }
- sc.setInvalid();
- termQueue.add(sc.getId());
- }
-
- private void term()
- {
- if(!termQueue.isEmpty())
- {
- termQueue.forEach(i ->
- {
- Script sc = scripts.remove(i);
- if(sc != null)
- {
- sc.onTerm();
- }
- });
- termQueue.clear();
- }
- }
-
- public void termAllUnsafe()
- {
- scripts.values().forEach(sc ->
- {
- sc.onTerm();
- sc.setInvalid();
- });
- scripts.clear();
- }
-
- public Collection<Script> getScripts()
- {
- return scripts.values();
- }
-
- private Script startScript(Script script, Object... o)
- {
- try
- {
- script.initExpansion(o);
- scripts.put(idCounter, script);
- idCounter++;
- script.runCode();
- term();
- return script;
- }
- catch(PreScriptException ex)
- {
- logger.printException(ex, null, script, ex.getLine());
- return null;
- }
- }
-
- public Script startScript(String scriptName, String code)
- {
- try
- {
- return startScript(new Script(this, idCounter, scriptName, code));
- }
- catch(PreScriptException ex)
- {
- logger.printException(ex, null, scriptName, ex.getLine());
- return null;
- }
- }
-
- @SuppressWarnings(value = "unchecked")
- public <T extends Script> T startScript(Class<T> c, String scriptName, String code, boolean b, Object... o)
- {
- try
- {
- return (T) startScript(c.getDeclaredConstructor(
- SnuviParser.class, int.class, String.class, String.class, boolean.class)
- .newInstance(this, idCounter, scriptName, code, b), o);
- }
- catch(IllegalAccessException | IllegalArgumentException | InstantiationException |
- InvocationTargetException | NoSuchMethodException | SecurityException ex)
- {
- if(ex instanceof InvocationTargetException)
- {
- Throwable t = ((InvocationTargetException) ex).getCause();
- if(t != null && t instanceof Exception)
- {
- if(t instanceof PreScriptException)
- {
- logger.printException((Exception) t, null, scriptName, ((PreScriptException) t).getLine());
- return null;
- }
- logger.printException((Exception) t, null, scriptName, -1);
- return null;
- }
- }
- ex.printStackTrace();
- return null;
- }
- }
-
- // -----------------------------------------------------------------------------------
- // event
- // -----------------------------------------------------------------------------------
-
- public void callEvent(String name, Consumer<Script> before, Consumer<Script> after, Predicate<Script> check)
- {
- scripts.values().stream()
- .filter(sc -> sc.receiveEventBroadcast && !sc.isHalt() && !sc.isRunning())
- .filter(sc -> sc.isLoadedEvent(name))
- .filter(check)
- .forEach(sc ->
- {
- sc.setVar("event", name);
- if(before != null)
- {
- before.accept(sc);
- }
- sc.runCode();
- if(after != null)
- {
- after.accept(sc);
- }
- sc.eventVars.forEach(s -> sc.removeVar(s));
- sc.eventVars.clear();
- });
- term();
- }
-
- public void callEvent(String name, Consumer<Script> before, Consumer<Script> after)
- {
- callEvent(name, before, after, sc -> true);
- }
-
- public boolean callEvent(String name, Script sc, Consumer<Script> before, Consumer<Script> after, boolean check)
- {
- if(sc.isLoadedEvent(name) && !sc.isHalt() && !sc.isRunning() && check)
- {
- sc.setVar("event", name);
- if(before != null)
- {
- before.accept(sc);
- }
- sc.runCode();
- if(after != null)
- {
- after.accept(sc);
- }
- sc.eventVars.forEach(s -> sc.removeVar(s));
- sc.eventVars.clear();
- term();
- return true;
- }
- return false;
- }
-
- public boolean callEvent(String name, Script sc, Consumer<Script> before, Consumer<Script> after)
- {
- return callEvent(name, sc, before, after, true);
- }
-
- // -----------------------------------------------------------------------------------
- // functions
- // -----------------------------------------------------------------------------------
-
- private String fractionToDoubleString(Fraction f)
- {
- if(f.doubleValue() == f.longValue())
- {
- return String.valueOf(f.longValue());
- }
- return String.valueOf(f.doubleValue());
- }
-
- private void ifFunction(Object[] args, Script sc)
- {
- if(Arrays.stream(args).anyMatch(s -> !((boolean) s)))
- {
- sc.jumpDoElse();
- }
- }
-
- private void whileFunction(Object[] args, Script sc)
- {
- if(Arrays.stream(args).anyMatch(s -> !((boolean) s)))
- {
- sc.jump();
- }
- }
-
- @SuppressWarnings("unchecked")
- private void sortList(List<Object> args, Script sc)
- {
- Collections.sort(args, (Object o1, Object o2) -> ((Comparable) o1).compareTo(o2));
- }
-
- private void scheduleGoto(Object[] args, Script sc)
- {
- int time = getInt(args[0]);
- if(time < 0)
- {
- throw new IllegalArgumentException("time units can't be negative");
- }
- scheduler.scheduleTask(() ->
- {
- if(!sc.isValid() && !sc.isHalt())
- {
- return;
- }
- try
- {
- sc.gotoLabel(args[1].toString(), true, true);
- sc.runCode();
- }
- catch(Exception ex)
- {
- logger.printException(ex, "sgoto", sc, sc.getActiveRealCodeLine());
- }
- }, time);
- }
-
- @SuppressWarnings("")
- private void waitFor(Object[] args, Script sc) throws UnsupportedOperationException
- {
- sc.resetLoopCounter();
- long l = getLong(args[0]);
- if(l < 0)
- {
- throw new IllegalArgumentException("time units can't be negative");
- }
- sc.setHalt(true);
- scheduler.scheduleTask(() ->
- {
- if(sc == null || !sc.isValid())
- {
- return;
- }
- sc.setHalt(false);
- sc.runCode();
- }, l);
- throw new HoldCodeException();
- }
-
- private static boolean isEqual(Object[] args)
- {
- if(args[0] == null)
- {
- return args[1] == null;
- }
- else if(args[1] == null)
- {
- return false;
- }
- return args[0].equals(args[1]);
- }
-
- private void split(Object[] args, Script sc)
- {
- sc.setVar(args[0].toString(),
- Arrays.stream(ScriptUtils.connect(args, 2).split(args[1].toString()))
- .map(s -> Code.convertInput(null, s, false)).collect(Collectors.toList()));
- }
-
- private void readFile(Object[] args, Script sc)
- {
- try
- {
- sc.setVar(args[0].toString(), Files.readAllLines(((File) args[1]).toPath()));
- }
- catch(IOException ex)
- {
- throw new FileIOException(ex.getMessage());
- }
- }
-
- @SuppressWarnings(value = "unchecked")
- private void writeFile(Object[] args, Script sc)
- {
- try
- {
- File f = (File) args[0];
- if(!f.getParentFile().exists())
- {
- 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>) args[1])
- .stream().map(o -> String.valueOf(o)).collect(Collectors.toList()), StandardCharsets.UTF_8);
- }
- catch(UnsupportedOperationException | SecurityException | IOException ex)
- {
- throw new FileIOException(ex.getMessage());
- }
- }
-
- // -----------------------------------------------------------------------------------
- // number handlers, cause primitive types transform into their classes all the time
- // -----------------------------------------------------------------------------------
-
- public static int getInt(Object o)
- {
- return ScriptUtils.getInt(o);
- }
-
- public static long getLong(Object o)
- {
- return ScriptUtils.getLong(o);
- }
-
- public static double getDouble(Object o)
- {
- return ScriptUtils.getDouble(o);
- }
-
- // -----------------------------------------------------------------------------------
- // time handler
- // -----------------------------------------------------------------------------------
-
- private Fraction getNextDay(Object[] args)
- {
- GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
- cal.setTimeInMillis(getLong(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 new Fraction(cal.getTimeInMillis());
- }
-
- private Fraction getYear(Object[] args)
- {
- GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
- cal.setTimeInMillis(getLong(args[0]));
- return new Fraction(cal.get(Calendar.YEAR));
- }
-
- private Fraction getMonth(Object[] args)
- {
- GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
- cal.setTimeInMillis(getLong(args[0]));
- return new Fraction(cal.get(Calendar.MONTH) + 1);
- }
-
- private Fraction getDay(Object[] args)
- {
- GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
- cal.setTimeInMillis(getLong(args[0]));
- return new Fraction(cal.get(Calendar.DAY_OF_MONTH));
- }
-
- private Fraction getHour(Object[] args)
- {
- GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
- cal.setTimeInMillis(getLong(args[0]));
- return new Fraction(cal.get(Calendar.HOUR_OF_DAY));
- }
-
- private Fraction getMinute(Object[] args)
- {
- GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
- cal.setTimeInMillis(getLong(args[0]));
- return new Fraction(cal.get(Calendar.MINUTE));
- }
-
- private Fraction getSecond(Object[] args)
- {
- GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
- cal.setTimeInMillis(getLong(args[0]));
- return new Fraction(cal.get(Calendar.SECOND));
- }
- }
|