FunctionRegistry.java 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. package me.hammerle.snuviscript.code;
  2. import me.hammerle.snuviscript.inputprovider.InputProvider;
  3. import java.io.File;
  4. import java.nio.charset.StandardCharsets;
  5. import java.lang.reflect.Array;
  6. import java.nio.file.Files;
  7. import java.nio.file.Paths;
  8. import java.time.ZonedDateTime;
  9. import java.util.List;
  10. import java.util.ArrayList;
  11. import java.util.Arrays;
  12. import java.util.Collections;
  13. import java.util.Calendar;
  14. import java.util.GregorianCalendar;
  15. import java.util.HashMap;
  16. import java.util.Map;
  17. import java.util.HashSet;
  18. import java.util.Iterator;
  19. import java.util.Objects;
  20. import java.util.Set;
  21. import java.util.stream.Collectors;
  22. import me.hammerle.snuviscript.config.SnuviConfig;
  23. public class FunctionRegistry {
  24. private static final HashMap<String, Object> GLOBAL_VARS = new HashMap<>();
  25. private static final HashMap<String, NamedFunction> FUNCTIONS = new HashMap<>();
  26. protected static void registerFunction(String name, ExceptionBiFunction<Script, InputProvider[], Object> f) {
  27. FUNCTIONS.put(name, new NamedFunction(name, f));
  28. }
  29. protected static void registerConsumer(String name, ExceptionBiConsumer<Script, InputProvider[]> f) {
  30. FUNCTIONS.put(name, new NamedFunction(name, (sc, in) -> {
  31. f.apply(sc, in);
  32. return Void.TYPE;
  33. }));
  34. }
  35. protected static void registerAlias(String original, String alias) {
  36. FUNCTIONS.put(alias, FUNCTIONS.get(original));
  37. }
  38. public static NamedFunction getFunction(String f) {
  39. final String function = f.toLowerCase();
  40. return FUNCTIONS.getOrDefault(function, new NamedFunction(function, (sc, in) -> {
  41. sc.handleFunction(function, in);
  42. return Void.TYPE;
  43. }));
  44. }
  45. static {
  46. registerFunction("nothing", (sc, in) -> Void.TYPE);
  47. registerConsumer("error", (sc, in) -> sc.setStackTrace(in[0].getBoolean(sc)));
  48. registerConsumer("event.load", (sc, in) -> {
  49. String event = in[0].getString(sc);
  50. sc.loadEvent(event);
  51. sc.getScriptManager().loadEventSafe(event, sc);
  52. });
  53. registerConsumer("event.unload", (sc, in) -> {
  54. String event = in[0].getString(sc);
  55. sc.unloadEvent(in[0].getString(sc));
  56. sc.getScriptManager().unloadEventSafe(event, sc);
  57. });
  58. registerFunction("event.isloaded", (sc, in) -> sc.isEventLoaded(in[0].getString(sc)));
  59. registerFunction("script.get", (sc, in) -> {
  60. String name = in[0].getString(sc);
  61. for(Script script : sc.getScriptManager().getScripts()) {
  62. if(script.getName().equals(name)) {
  63. return script;
  64. }
  65. }
  66. return null;
  67. });
  68. registerFunction("script.getall", (sc, in) -> {
  69. String name = in[0].getString(sc);
  70. return sc.getScriptManager().getScripts().stream()
  71. .filter(script -> script.getName().equals(name))
  72. .collect(Collectors.toList());
  73. });
  74. registerConsumer("script.term", (sc, in) -> {
  75. Script other = (Script) in[0].get(sc);
  76. other.term();
  77. sc.getScriptManager().removeScriptSafe(other);
  78. });
  79. registerFunction(">>", (sc, in) -> (double) (in[0].getInt(sc) >> in[1].getInt(sc)));
  80. registerFunction("<<", (sc, in) -> (double) (in[0].getInt(sc) << in[1].getInt(sc)));
  81. registerFunction("&", (sc, in) -> (double) (in[0].getInt(sc) & in[1].getInt(sc)));
  82. registerFunction("|", (sc, in) -> (double) (in[0].getInt(sc) | in[1].getInt(sc)));
  83. registerFunction("^", (sc, in) -> (double) (in[0].getInt(sc) ^ in[1].getInt(sc)));
  84. registerFunction("~", (sc, in) -> (double) (~in[0].getInt(sc)));
  85. registerFunction("bit.set", (sc, in) -> (double) (in[0].getInt(sc) | (1 << (in[1].getInt(sc)))));
  86. registerFunction("bit.unset", (sc, in) -> (double) (in[0].getInt(sc) & (~(1 << (in[1].getInt(sc))))));
  87. registerFunction("bit.get", (sc, in) -> (in[0].getInt(sc) & (1 << (in[1].getInt(sc)))) != 0);
  88. registerFunction("%", (sc, in) -> (double) (in[0].getInt(sc) % in[1].getInt(sc)));
  89. registerAlias("%", "math.mod");
  90. registerFunction("math.abs", (sc, in) -> Math.abs(in[0].getDouble(sc)));
  91. registerFunction("math.pow", (sc, in) -> Math.pow(in[0].getDouble(sc), in[1].getDouble(sc)));
  92. registerFunction("math.root", (sc, in) -> Math.pow(in[0].getDouble(sc), 1.0 / in[1].getDouble(sc)));
  93. registerFunction("math.sqrt", (sc, in) -> Math.sqrt(in[0].getDouble(sc)));
  94. registerFunction("math.hypot", (sc, in) -> Math.hypot(in[0].getDouble(sc), in[1].getDouble(sc)));
  95. registerFunction("math.sin", (sc, in) -> Math.sin(in[0].getDouble(sc)));
  96. registerFunction("math.cos", (sc, in) -> Math.cos(in[0].getDouble(sc)));
  97. registerFunction("math.tan", (sc, in) -> Math.tan(in[0].getDouble(sc)));
  98. registerFunction("math.asin", (sc, in) -> Math.asin(in[0].getDouble(sc)));
  99. registerFunction("math.acos", (sc, in) -> Math.acos(in[0].getDouble(sc)));
  100. registerFunction("math.atan", (sc, in) -> Math.atan(in[0].getDouble(sc)));
  101. registerFunction("math.e", (sc, in) -> Math.E);
  102. registerFunction("math.pi", (sc, in) -> Math.PI);
  103. registerFunction("math.ln", (sc, in) -> Math.log(in[0].getDouble(sc)));
  104. registerFunction("math.log", (sc, in) -> Math.log10(in[0].getDouble(sc)));
  105. registerFunction("math.random", (sc, in) -> (double) SnuviUtils.randomInt(in[0].getInt(sc), in[1].getInt(sc)));
  106. registerFunction("math.round", (sc, in) -> (double) Math.round(in[0].getDouble(sc)));
  107. registerFunction("math.rounddown", (sc, in) -> Math.floor(in[0].getDouble(sc)));
  108. registerFunction("math.roundup", (sc, in) -> Math.ceil(in[0].getDouble(sc)));
  109. registerFunction("math.roundcomma", (sc, in) -> {
  110. double d = in[0].getDouble(sc);
  111. int factor = (int) Math.pow(10, in[1].getInt(sc));
  112. return (double) (((double) Math.round(d * factor)) / factor);
  113. });
  114. registerFunction("list.new", (sc, in) -> {
  115. if(in.length == 0) {
  116. return new ArrayList<>();
  117. }
  118. in[0].set(sc, new ArrayList<>());
  119. return Void.TYPE;
  120. });
  121. registerFunction("list.exists", (sc, in) -> in[0].get(sc) instanceof List);
  122. registerFunction("list.add", (sc, in) -> ((List) in[0].get(sc)).add(in[1].get(sc)));
  123. registerConsumer("list.addall", (sc, in) -> {
  124. List list = ((List) in[0].get(sc));
  125. for(int i = 1; i < in.length; i++) {
  126. list.add(in[i].get(sc));
  127. }
  128. });
  129. registerFunction("list.remove", (sc, in) -> ((List) in[0].get(sc)).remove(in[1].get(sc)));
  130. registerFunction("list.removeindex", (sc, in) -> ((List) in[0].get(sc)).remove(in[1].getInt(sc)));
  131. registerFunction("list.contains", (sc, in) -> ((List) in[0].get(sc)).contains(in[1].get(sc)));
  132. registerFunction("list.getsize", (sc, in) -> (double) ((List) in[0].get(sc)).size());
  133. registerFunction("list.getindex", (sc, in) -> ((List) in[0].get(sc)).get(in[1].getInt(sc)));
  134. registerAlias("list.getindex", "list.get");
  135. registerFunction("list.setindex", (sc, in) -> ((List) in[0].get(sc)).set(in[1].getInt(sc), in[2].get(sc)));
  136. registerConsumer("list.clear", (sc, in) -> ((List) in[0].get(sc)).clear());
  137. registerFunction("list.getindexof", (sc, in) -> (double) ((List) in[0].get(sc)).indexOf(in[1].get(sc)));
  138. registerConsumer("list.sort", (sc, in) -> {
  139. Collections.sort(((List<Object>) in[0].get(sc)), (o1, o2) -> ((Comparable) o1).compareTo(o2));
  140. });
  141. registerConsumer("list.reverse", (sc, in) -> Collections.reverse((List<Object>) in[0].get(sc)));
  142. registerConsumer("list.shuffle", (sc, in) -> Collections.shuffle((List<Object>) in[0].get(sc)));
  143. registerFunction("list.iterator", (sc, in) -> ((List) in[0].get(sc)).iterator());
  144. registerFunction("array.new", (sc, in) -> {
  145. if(in.length == 0) {
  146. throw new ArrayIndexOutOfBoundsException("missing array dimension");
  147. }
  148. int[] dim = new int[in.length];
  149. for(int i = 0; i < in.length; i++) {
  150. dim[i] = in[i].getInt(sc);
  151. }
  152. return Array.newInstance(Object.class, dim);
  153. });
  154. registerFunction("array.getsize", (sc, in) -> (double) Array.getLength(in[0].get(sc)));
  155. registerAlias("array.getsize", "array.length");
  156. registerFunction("map.new", (sc, in) -> {
  157. if(in.length == 0) {
  158. return new HashMap<>();
  159. }
  160. in[0].set(sc, new HashMap<>());
  161. return Void.TYPE;
  162. });
  163. registerFunction("map.exists", (sc, in) -> in[0].get(sc) instanceof Map);
  164. registerFunction("map.add", (sc, in) -> ((Map) in[0].get(sc)).put(in[1].get(sc), in[2].get(sc)));
  165. registerFunction("map.remove", (sc, in) -> ((Map) in[0].get(sc)).remove(in[1].get(sc)));
  166. registerFunction("map.contains", (sc, in) -> ((Map) in[0].get(sc)).containsKey(in[1].get(sc)));
  167. registerFunction("map.getsize", (sc, in) -> (double) ((Map) in[0].get(sc)).size());
  168. registerFunction("map.get", (sc, in) -> ((Map) in[0].get(sc)).get(in[1].get(sc)));
  169. registerFunction("map.getordefault", (sc, in) -> ((Map) in[0].get(sc)).getOrDefault(in[1].get(sc), in[2].get(sc)));
  170. registerConsumer("map.clear", (sc, in) -> ((Map) in[0].get(sc)).clear());
  171. registerFunction("map.iterator", (sc, in) -> ((Map) in[0].get(sc)).entrySet().iterator());
  172. registerFunction("map.getkey", (sc, in) -> ((Map.Entry) in[0].get(sc)).getKey());
  173. registerFunction("map.getvalue", (sc, in) -> ((Map.Entry) in[0].get(sc)).getValue());
  174. registerFunction("map.setvalue", (sc, in) -> ((Map.Entry) in[0].get(sc)).setValue(in[1].get(sc)));
  175. registerFunction("set.new", (sc, in) -> {
  176. if(in.length == 0) {
  177. return new HashSet<>();
  178. }
  179. in[0].set(sc, new HashSet<>());
  180. return Void.TYPE;
  181. });
  182. registerFunction("set.exists", (sc, in) -> in[0].get(sc) instanceof Set);
  183. registerFunction("set.add", (sc, in) -> ((Set) in[0].get(sc)).add(in[1].get(sc)));
  184. registerConsumer("set.addall", (sc, in) -> {
  185. Set set = ((Set) in[0].get(sc));
  186. for(int i = 1; i < in.length; i++) {
  187. set.add(in[i].get(sc));
  188. }
  189. });
  190. registerFunction("set.remove", (sc, in) -> ((Set) in[0].get(sc)).remove(in[1].get(sc)));
  191. registerFunction("set.contains", (sc, in) -> ((Set) in[0].get(sc)).contains(in[1].get(sc)));
  192. registerFunction("set.getsize", (sc, in) -> (double) ((Set) in[0].get(sc)).size());
  193. registerConsumer("set.clear", (sc, in) -> ((Set) in[0].get(sc)).clear());
  194. registerFunction("set.iterator", (sc, in) -> ((Set) in[0].get(sc)).iterator());
  195. registerFunction("time.new", (sc, in) -> {
  196. if(in.length <= 1) {
  197. GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
  198. cal.setTimeInMillis(in[0].getLong(sc));
  199. return cal;
  200. } else {
  201. GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
  202. cal.setTimeInMillis(in[1].getLong(sc));
  203. in[0].set(sc, cal);
  204. return Void.TYPE;
  205. }
  206. });
  207. registerFunction("time.getmillis", (sc, in) -> (double) System.currentTimeMillis());
  208. registerFunction("time.getnanos", (sc, in) -> (double) System.nanoTime());
  209. registerFunction("time.from", (sc, in) -> (double) ((GregorianCalendar) in[0].get(sc)).getTimeInMillis());
  210. registerConsumer("time.nextday", (sc, in) -> {
  211. GregorianCalendar cal = (GregorianCalendar) in[0].get(sc);
  212. cal.add(Calendar.DAY_OF_YEAR, 1);
  213. cal.set(Calendar.HOUR_OF_DAY, 0);
  214. cal.set(Calendar.SECOND, 0);
  215. cal.set(Calendar.MINUTE, 0);
  216. cal.set(Calendar.MILLISECOND, 0);
  217. });
  218. registerFunction("time.getyear", (sc, in) -> (double) ((GregorianCalendar) in[0].get(sc)).get(Calendar.YEAR));
  219. registerFunction("time.getmonth", (sc, in) -> (double) (((GregorianCalendar) in[0].get(sc)).get(Calendar.MONTH) + 1));
  220. registerFunction("time.getday", (sc, in) -> (double) (((GregorianCalendar) in[0].get(sc)).get(Calendar.DAY_OF_MONTH)));
  221. registerFunction("time.gethour", (sc, in) -> (double) ((GregorianCalendar) in[0].get(sc)).get(Calendar.HOUR_OF_DAY));
  222. registerFunction("time.getminute", (sc, in) -> (double) ((GregorianCalendar) in[0].get(sc)).get(Calendar.MINUTE));
  223. registerFunction("time.getsecond", (sc, in) -> (double) ((GregorianCalendar) in[0].get(sc)).get(Calendar.SECOND));
  224. registerFunction("text.matches", (sc, in) -> in[0].getString(sc).matches(in[1].getString(sc)));
  225. registerFunction("text.number", (sc, in) -> SnuviUtils.toString(in[0].getDouble(sc)));
  226. registerFunction("text.class", (sc, in) -> in[0].get(sc).getClass().getSimpleName());
  227. registerFunction("text.tolowercase", (sc, in) -> SnuviUtils.connect(sc, in, 0).toLowerCase());
  228. registerAlias("text.tolowercase", "tolowercase");
  229. registerFunction("text.touppercase", (sc, in) -> SnuviUtils.connect(sc, in, 0).toUpperCase());
  230. registerAlias("text.touppercase", "touppercase");
  231. registerFunction("text.split", (sc, in) -> {
  232. if(in.length <= 2) {
  233. String[] parts = in[1].getString(sc).split(in[0].getString(sc));
  234. ArrayList<Object> list = new ArrayList<>();
  235. for(String part : parts) {
  236. list.add(SnuviUtils.convert(part));
  237. }
  238. return list;
  239. }
  240. String[] parts = in[2].getString(sc).split(in[1].getString(sc));
  241. ArrayList<Object> list = new ArrayList<>();
  242. for(String part : parts) {
  243. list.add(SnuviUtils.convert(part));
  244. }
  245. in[0].set(sc, list);
  246. return Void.TYPE;
  247. });
  248. registerAlias("text.split", "split");
  249. registerFunction("text.concatlist", (sc, in) -> {
  250. StringBuilder sb = new StringBuilder();
  251. List<Object> list = (List<Object>) in[0].get(sc);
  252. String splitter = in[1].getString(sc);
  253. Iterator<Object> iter = list.iterator();
  254. int from = in[2].getInt(sc);
  255. int to = Math.min(in[3].getInt(sc), list.size() - 1);
  256. to -= from;
  257. while(iter.hasNext() && from > 0) {
  258. iter.next();
  259. from--;
  260. }
  261. while(iter.hasNext() && to > 0) {
  262. sb.append(iter.next());
  263. sb.append(splitter);
  264. to--;
  265. }
  266. if(iter.hasNext() && to == 0) {
  267. sb.append(iter.next());
  268. }
  269. return sb.toString();
  270. });
  271. registerAlias("text.concatlist", "concatlist");
  272. registerFunction("text.concat", (sc, in) -> SnuviUtils.connect(sc, in, 0));
  273. registerAlias("text.concat", "concat");
  274. registerFunction("text.concatspace", (sc, in) -> SnuviUtils.connect(sc, in, " ", 0));
  275. registerFunction("text", (sc, in) -> String.valueOf(in[0].get(sc)));
  276. registerFunction("text.substring", (sc, in) -> in[0].getString(sc).substring(in[1].getInt(sc), in[2].getInt(sc)));
  277. registerFunction("text.length", (sc, in) -> (double) in[0].getString(sc).length());
  278. registerFunction("text.startswith", (sc, in) -> in[0].getString(sc).startsWith(in[1].getString(sc), in[2].getInt(sc)));
  279. registerFunction("text.endswith", (sc, in) -> in[0].getString(sc).endsWith(in[1].getString(sc)));
  280. registerFunction("text.contains", (sc, in) -> in[0].getString(sc).contains(in[1].getString(sc)));
  281. registerFunction("text.indexof", (sc, in) -> (double) in[0].getString(sc).indexOf(in[1].getString(sc), in[2].getInt(sc)));
  282. registerFunction("text.lastindexof", (sc, in) -> (double) in[0].getString(sc).lastIndexOf(in[1].getString(sc), in[2].getInt(sc)));
  283. registerFunction("text.replace", (sc, in) -> in[0].getString(sc).replace(in[1].getString(sc), in[2].getString(sc)));
  284. registerFunction("text.trim", (sc, in) -> in[0].getString(sc).trim());
  285. registerFunction("text.charat", (sc, in) -> String.valueOf(in[0].getString(sc).charAt(in[1].getInt(sc))));
  286. registerFunction("text.charcode", (sc, in) -> (double) in[0].getString(sc).charAt(in[1].getInt(sc)));
  287. registerFunction("text.fromcode", (sc, in) -> String.valueOf((char) in[0].getInt(sc)));
  288. registerFunction("text.onlyletters", (sc, in) -> {
  289. for(char c : in[0].getString(sc).toCharArray()) {
  290. if(!Character.isLetter(c)) {
  291. return false;
  292. }
  293. }
  294. return true;
  295. });
  296. registerFunction("file.new", (sc, in) -> new File(in[0].getString(sc)));
  297. registerFunction("file.exists", (sc, in) -> ((File) in[0].get(sc)).exists());
  298. registerFunction("file.isfile", (sc, in) -> ((File) in[0].get(sc)).isFile());
  299. registerFunction("file.isdirectory", (sc, in) -> ((File) in[0].get(sc)).isDirectory());
  300. registerFunction("file.delete", (sc, in) -> ((File) in[0].get(sc)).delete());
  301. registerFunction("file.getname", (sc, in) -> ((File) in[0].get(sc)).getName());
  302. registerFunction("file.getlist", (sc, in) -> Arrays.asList(((File) in[0].get(sc)).listFiles()));
  303. registerFunction("file.read", (sc, in) -> Files.readAllLines(((File) in[0].get(sc)).toPath()));
  304. registerConsumer("file.write", (sc, in) -> {
  305. File f = (File) in[0].get(sc);
  306. if(f.getParentFile() != null) {
  307. f.getParentFile().mkdirs();
  308. }
  309. if(!f.exists()) {
  310. f.createNewFile();
  311. }
  312. Files.write(Paths.get(f.toURI()), ((List<Object>) in[1].get(sc))
  313. .stream().map(o -> String.valueOf(o)).collect(Collectors.toList()), StandardCharsets.UTF_8);
  314. });
  315. registerFunction("config.new", (sc, in) -> new SnuviConfig(sc, in[0].getString(sc), in[1].getString(sc)));
  316. registerFunction("config.exists", (sc, in) -> ((SnuviConfig) in[0].get(sc)).exists());
  317. registerFunction("config.save", (sc, in) -> ((SnuviConfig) in[0].get(sc)).save());
  318. registerConsumer("config.load", (sc, in) -> ((SnuviConfig) in[0].get(sc)).load());
  319. registerFunction("config.delete", (sc, in) -> ((SnuviConfig) in[0].get(sc)).delete());
  320. registerConsumer("config.set", (sc, in) -> ((SnuviConfig) in[0].get(sc)).set(in[1].getString(sc), in[2].get(sc)));
  321. registerFunction("config.getbool", (sc, in) -> ((SnuviConfig) in[0].get(sc)).getBoolean(in[1].getString(sc), in[2].getBoolean(sc)));
  322. registerFunction("config.getdouble", (sc, in) -> ((SnuviConfig) in[0].get(sc)).getDouble(in[1].getString(sc), in[2].getDouble(sc)));
  323. registerFunction("config.getstring", (sc, in) -> ((SnuviConfig) in[0].get(sc)).getString(in[1].getString(sc), in[2].getString(sc)));
  324. registerFunction("read.number", (sc, in) -> Double.parseDouble(in[0].getString(sc)));
  325. registerFunction("+", (sc, in) -> in[0].getDouble(sc) + in[1].getDouble(sc));
  326. registerAlias("+", "add");
  327. registerFunction("-", (sc, in) -> in.length == 1 ? -in[0].getDouble(sc) : in[0].getDouble(sc) - in[1].getDouble(sc));
  328. registerAlias("-", "sub");
  329. registerFunction("*", (sc, in) -> in[0].getDouble(sc) * in[1].getDouble(sc));
  330. registerAlias("*", "mul");
  331. registerFunction("/", (sc, in) -> in[0].getDouble(sc) / in[1].getDouble(sc));
  332. registerAlias("/", "div");
  333. registerFunction("=", (sc, in) -> {
  334. Object o = in[1].get(sc);
  335. in[0].set(sc, o);
  336. return o;
  337. });
  338. registerFunction("+=", (sc, in) -> {
  339. Object o = in[0].getDouble(sc) + in[1].getDouble(sc);
  340. in[0].set(sc, o);
  341. return o;
  342. });
  343. registerFunction("p++", (sc, in) -> {
  344. double d = in[0].getDouble(sc);
  345. in[0].set(sc, d + 1.0);
  346. return d;
  347. });
  348. registerAlias("p++", "inc");
  349. registerFunction("++", (sc, in) -> {
  350. double d = in[0].getDouble(sc) + 1.0;
  351. in[0].set(sc, d);
  352. return d;
  353. });
  354. registerFunction("-=", (sc, in) -> {
  355. Object o = in[0].getDouble(sc) - in[1].getDouble(sc);
  356. in[0].set(sc, o);
  357. return o;
  358. });
  359. registerFunction("p--", (sc, in) -> {
  360. double d = in[0].getDouble(sc);
  361. in[0].set(sc, d - 1.0);
  362. return d;
  363. });
  364. registerAlias("p--", "dec");
  365. registerFunction("--", (sc, in) -> {
  366. double d = in[0].getDouble(sc) - 1.0;
  367. in[0].set(sc, d);
  368. return d;
  369. });
  370. registerFunction("*=", (sc, in) -> {
  371. Object o = in[0].getDouble(sc) * in[1].getDouble(sc);
  372. in[0].set(sc, o);
  373. return o;
  374. });
  375. registerFunction("/=", (sc, in) -> {
  376. Object o = in[0].getDouble(sc) / in[1].getDouble(sc);
  377. in[0].set(sc, o);
  378. return o;
  379. });
  380. registerFunction("%=", (sc, in) -> {
  381. Object o = (double) (in[0].getInt(sc) % in[1].getInt(sc));
  382. in[0].set(sc, o);
  383. return o;
  384. });
  385. registerFunction("<<=", (sc, in) -> {
  386. Object o = (double) (in[0].getInt(sc) << in[1].getInt(sc));
  387. in[0].set(sc, o);
  388. return o;
  389. });
  390. registerFunction(">>=", (sc, in) -> {
  391. Object o = (double) (in[0].getInt(sc) >> in[1].getInt(sc));
  392. in[0].set(sc, o);
  393. return o;
  394. });
  395. registerFunction("&=", (sc, in) -> {
  396. Object o = (double) (in[0].getInt(sc) & in[1].getInt(sc));
  397. in[0].set(sc, o);
  398. return o;
  399. });
  400. registerFunction("^=", (sc, in) -> {
  401. Object o = (double) (in[0].getInt(sc) ^ in[1].getInt(sc));
  402. in[0].set(sc, o);
  403. return o;
  404. });
  405. registerFunction("|=", (sc, in) -> {
  406. Object o = (double) (in[0].getInt(sc) | in[1].getInt(sc));
  407. in[0].set(sc, o);
  408. return o;
  409. });
  410. registerFunction("getvar", (sc, in) -> sc.getVar(in[0].getString(sc)).get(sc));
  411. registerConsumer("setvar", (sc, in) -> sc.getVar(in[0].getString(sc)).set(sc, in[1].get(sc)));
  412. registerConsumer("removevar", (sc, in) -> sc.getVar(in[0].getString(sc)).set(sc, null));
  413. registerConsumer("wait", (sc, in) -> sc.setWaiting());
  414. registerConsumer("goto", (sc, in) -> sc.gotoLabel(in[0].getString(sc), true));
  415. registerConsumer("ignoregoto", (sc, in) -> sc.gotoLabel(in[0].getString(sc), false));
  416. registerAlias("ignoregoto", "igoto");
  417. registerConsumer("sgoto", (sc, in) -> {
  418. int time = in[0].getInt(sc);
  419. if(time < 0) {
  420. throw new IllegalArgumentException("time units can't be negative");
  421. }
  422. String label = in[1].getString(sc);
  423. sc.getScriptManager().getScheduler().scheduleTask(() -> {
  424. if(sc.shouldTerm() || sc.isHolded()) {
  425. return;
  426. }
  427. sc.gotoLabel(label, true, 1);
  428. sc.run();
  429. if(sc.shouldTerm()) {
  430. sc.getScriptManager().removeScriptSafe(sc);
  431. }
  432. }, time);
  433. });
  434. registerConsumer("gosub", (sc, in) -> sc.goSub(in[0].getString(sc)));
  435. registerFunction("==", (sc, in) -> Objects.equals(in[0].get(sc), in[1].get(sc)));
  436. registerAlias("==", "equal");
  437. registerAlias("==", "equals");
  438. registerFunction("!=", (sc, in) -> !Objects.equals(in[0].get(sc), in[1].get(sc)));
  439. registerAlias("!=", "notequal");
  440. registerFunction("<", (sc, in) -> ((Comparable) in[0].get(sc)).compareTo(in[1].get(sc)) < 0);
  441. registerAlias("<", "less");
  442. registerFunction(">", (sc, in) -> ((Comparable) in[0].get(sc)).compareTo(in[1].get(sc)) > 0);
  443. registerAlias(">", "greater");
  444. registerFunction("<=", (sc, in) -> ((Comparable) in[0].get(sc)).compareTo(in[1].get(sc)) <= 0);
  445. registerAlias("<=", "lessequal");
  446. registerFunction(">=", (sc, in) -> ((Comparable) in[0].get(sc)).compareTo(in[1].get(sc)) >= 0);
  447. registerAlias(">=", "greaterequal");
  448. registerFunction("!", (sc, in) -> !in[0].getBoolean(sc));
  449. registerAlias("!", "invert");
  450. registerFunction("&&", (sc, in) -> {
  451. for(InputProvider i : in) {
  452. if(!i.getBoolean(sc)) {
  453. return false;
  454. }
  455. }
  456. return true;
  457. });
  458. registerAlias("&&", "and");
  459. registerFunction("||", (sc, in) -> {
  460. for(InputProvider i : in) {
  461. if(i.getBoolean(sc)) {
  462. return true;
  463. }
  464. }
  465. return false;
  466. });
  467. registerAlias("||", "or");
  468. registerFunction("getscriptvar", (sc, in) -> GLOBAL_VARS.get(in[0].getString(sc)));
  469. registerFunction("setscriptvar", (sc, in) -> GLOBAL_VARS.put(in[0].getString(sc), in[1].get(sc)));
  470. registerFunction("delscriptvar", (sc, in) -> GLOBAL_VARS.remove(in[0].getString(sc)));
  471. registerConsumer("clearscriptvars", (sc, in) -> GLOBAL_VARS.clear());
  472. registerFunction("hasnext", (sc, in) -> ((Iterator) in[0].get(sc)).hasNext());
  473. registerFunction("next", (sc, in) -> ((Iterator) in[0].get(sc)).next());
  474. registerConsumer("swap", (sc, in) -> {
  475. Object o = in[0].get(sc);
  476. in[0].set(sc, in[1].get(sc));
  477. in[1].set(sc, o);
  478. });
  479. registerConsumer("print", (sc, in) -> {
  480. sc.getScriptManager().getLogger().print(SnuviUtils.connect(sc, in, 0), null, "print", sc.getName(), sc, sc.getActiveSourceLine());
  481. });
  482. registerConsumer("rprint", (sc, in) -> System.out.println(SnuviUtils.connect(sc, in, 0)));
  483. registerConsumer("waitfor", (sc, in) -> {
  484. long l = in[0].getInt(sc);
  485. if(l < 0) {
  486. throw new IllegalArgumentException("time units can't be negative");
  487. }
  488. sc.setHolded(true);
  489. sc.setWaiting();
  490. sc.getScriptManager().getScheduler().scheduleTask(() -> {
  491. if(sc.shouldTerm()) {
  492. return;
  493. }
  494. sc.setHolded(false);
  495. sc.run();
  496. if(sc.shouldTerm()) {
  497. sc.getScriptManager().removeScriptSafe(sc);
  498. }
  499. }, l);
  500. });
  501. registerConsumer("term", (sc, in) -> {
  502. sc.term();
  503. sc.getScriptManager().removeScriptSafe(sc);
  504. });
  505. registerFunction("isdouble", (sc, in) -> (in[0].get(sc) instanceof Double));
  506. registerFunction("islong", (sc, in) -> {
  507. Object o = in[0].get(sc);
  508. if(o instanceof Double) {
  509. double d = (Double) o;
  510. return d == (long) d;
  511. }
  512. return false;
  513. });
  514. registerConsumer("assert", (sc, in) -> {
  515. if(!in[0].getBoolean(sc)) {
  516. throw new IllegalArgumentException("assertion failed");
  517. }
  518. });
  519. registerFunction("class", (sc, in) -> in[0].get(sc).getClass());
  520. registerFunction("usedmemory", (sc, in) -> {
  521. Runtime runtime = Runtime.getRuntime();
  522. double usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / 1048576;
  523. return usedMemory;
  524. });
  525. registerFunction("allocatedmemory", (sc, in) -> Runtime.getRuntime().totalMemory() / 1048576.0);
  526. }
  527. }