FunctionRegistry.java 30 KB

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