FunctionLoader.java 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. package me.hammerle.snuviscript.code;
  2. import java.io.File;
  3. import java.io.IOException;
  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.Objects;
  19. import java.util.Set;
  20. import java.util.function.BiFunction;
  21. import java.util.stream.Collectors;
  22. import me.hammerle.snuviscript.array.DynamicArray;
  23. import me.hammerle.snuviscript.config.SnuviConfig;
  24. import me.hammerle.snuviscript.exceptions.AssertionException;
  25. import me.hammerle.snuviscript.exceptions.FileIOException;
  26. import me.hammerle.snuviscript.variable.ArrayVariable;
  27. import me.hammerle.snuviscript.variable.Variable;
  28. import me.hammerle.snuviscript.math.Fraction;
  29. public class FunctionLoader
  30. {
  31. private static final HashMap<String, BasicFunction> FUNCTIONS = new HashMap<>();
  32. protected static void registerFunction(String name, String fname, BiFunction<Script, InputProvider[], Object> f)
  33. {
  34. FUNCTIONS.put(name, new BasicFunction(fname, f));
  35. }
  36. protected static void registerFunction(String name, BiFunction<Script, InputProvider[], Object> f)
  37. {
  38. registerFunction(name, name, f);
  39. }
  40. protected static void registerAlias(String original, String alias)
  41. {
  42. FUNCTIONS.put(alias, FUNCTIONS.get(original));
  43. }
  44. protected static BasicFunction getFunction(String f)
  45. {
  46. final String function = f.toLowerCase();
  47. return FUNCTIONS.getOrDefault(function, new BasicFunction(function, (sc, in) ->
  48. {
  49. Script sub = sc.subScripts.get(function);
  50. if(sub == null)
  51. {
  52. throw new NullPointerException("function " + function + " does not exist");
  53. }
  54. // push storage for local vars
  55. HashMap<String, Variable> vars = new HashMap<>();
  56. if(in.length != sub.subScriptInput.length)
  57. {
  58. throw new NullPointerException("invalid number of parameters at function '" + function + "'");
  59. }
  60. // generate local vars
  61. String s;
  62. Variable v;
  63. for(int i = 0; i < in.length; i++)
  64. {
  65. s = sub.subScriptInput[i];
  66. if(in[i].isArray(sc))
  67. {
  68. v = new ArrayVariable(s);
  69. v.set(sc, in[i].getArray(sc));
  70. }
  71. else
  72. {
  73. v = new Variable(s);
  74. v.set(sc, in[i].get(sc));
  75. }
  76. vars.put(s, v);
  77. }
  78. sub.localVars.push(vars);
  79. // saving line for return
  80. int line = sub.currentLine;
  81. // set starting line for current run
  82. sub.currentLine = 0;
  83. // run subscript and save return value
  84. Object r = sub.run();
  85. // return back to previous line
  86. sub.currentLine = line;
  87. // pop storage for local vars
  88. sub.localVars.pop();
  89. return r;
  90. }));
  91. }
  92. static
  93. {
  94. // ---------------------------------------------------------------------
  95. // system stuff
  96. // ---------------------------------------------------------------------
  97. registerFunction("nothing", (sc, in) -> Void.TYPE);
  98. registerFunction("error", (sc, in) ->
  99. {
  100. sc.printStackTrace = !sc.printStackTrace;
  101. return Void.TYPE;
  102. });
  103. registerFunction("", (sc, in) -> in[0].get(sc));
  104. // ---------------------------------------------------------------------
  105. // event
  106. // ---------------------------------------------------------------------
  107. registerFunction("event.load", (sc, in) ->
  108. {
  109. sc.events.add(in[0].getString(sc));
  110. return Void.TYPE;
  111. });
  112. registerFunction("event.unload", (sc, in) ->
  113. {
  114. sc.events.remove(in[0].getString(sc));
  115. return Void.TYPE;
  116. });
  117. registerFunction("event.isloaded", (sc, in) -> sc.isEventLoaded(in[0].getString(sc)));
  118. // ---------------------------------------------------------------------
  119. // bit
  120. // ---------------------------------------------------------------------
  121. registerFunction(">>", (sc, in) -> in[0].getFraction(sc).rightShift(in[1].getInt(sc)));
  122. registerFunction("<<", (sc, in) -> in[0].getFraction(sc).leftShift(in[1].getInt(sc)));
  123. registerFunction("&", (sc, in) -> in[0].getFraction(sc).and(in[1].getFraction(sc)));
  124. registerFunction("|", (sc, in) -> in[0].getFraction(sc).or(in[1].getFraction(sc)));
  125. registerFunction("^", (sc, in) -> in[0].getFraction(sc).xor(in[1].getFraction(sc)));
  126. registerFunction("~", (sc, in) -> in[0].getFraction(sc).invertBits());
  127. registerFunction("bit.set", (sc, in) -> in[0].getFraction(sc).setBit(in[1].getInt(sc)));
  128. registerFunction("bit.unset", (sc, in) -> in[0].getFraction(sc).unsetBit(in[1].getInt(sc)));
  129. registerFunction("bit.get", (sc, in) -> in[0].getFraction(sc).getBit(in[1].getInt(sc)));
  130. // ---------------------------------------------------------------------
  131. // math
  132. // ---------------------------------------------------------------------
  133. registerFunction("%", (sc, in) -> new Fraction(in[0].getInt(sc) % in[1].getInt(sc)));
  134. registerAlias("%", "math.mod");
  135. registerFunction("math.abs", (sc, in) -> in[0].getFraction(sc).abs());
  136. registerFunction("math.pow", (sc, in) -> in[0].getFraction(sc).power(in[1].getFraction(sc)));
  137. registerFunction("math.root", (sc, in) -> in[0].getFraction(sc).power(in[1].getFraction(sc).invert()));
  138. registerFunction("math.sin", (sc, in) -> in[0].getFraction(sc).sin());
  139. registerFunction("math.cos", (sc, in) -> in[0].getFraction(sc).cos());
  140. registerFunction("math.tan", (sc, in) -> in[0].getFraction(sc).tan());
  141. registerFunction("math.sin", (sc, in) -> in[0].getFraction(sc).sin());
  142. registerFunction("math.acos", (sc, in) -> in[0].getFraction(sc).acos());
  143. registerFunction("math.atan", (sc, in) -> in[0].getFraction(sc).atan());
  144. registerFunction("math.asin", (sc, in) -> in[0].getFraction(sc).asin());
  145. registerFunction("math.e", (sc, in) -> Fraction.E);
  146. registerFunction("math.pi", (sc, in) -> Fraction.PI);
  147. registerFunction("math.ln", (sc, in) -> in[0].getFraction(sc).log());
  148. registerFunction("math.log", (sc, in) -> in[0].getFraction(sc).log10());
  149. registerFunction("math.random", (sc, in) -> new Fraction(Utils.randomInt(in[0].getInt(sc), in[1].getInt(sc))));
  150. registerFunction("math.round", (sc, in) -> in[0].getFraction(sc).round());
  151. registerFunction("math.rounddown", (sc, in) -> in[0].getFraction(sc).floor());
  152. registerFunction("math.roundup", (sc, in) -> in[0].getFraction(sc).ceil());
  153. registerFunction("math.roundcomma", (sc, in) -> in[0].getFraction(sc).round(in[1].getInt(sc)));
  154. // ---------------------------------------------------------------------
  155. // lists
  156. // ---------------------------------------------------------------------
  157. registerFunction("list.new", (sc, in) ->
  158. {
  159. in[0].set(sc, new ArrayList<>());
  160. return Void.TYPE;
  161. });
  162. registerFunction("list.exists", (sc, in) -> in[0].get(sc) instanceof List);
  163. registerFunction("list.add", (sc, in) -> ((List) in[0].get(sc)).add(in[1].get(sc)));
  164. registerFunction("list.remove", (sc, in) -> ((List) in[0].get(sc)).remove(in[1].get(sc)));
  165. registerFunction("list.removeindex", (sc, in) -> ((List) in[0].get(sc)).remove(in[1].getInt(sc)));
  166. registerFunction("list.contains", (sc, in) -> ((List) in[0].get(sc)).contains(in[1].get(sc)));
  167. registerFunction("list.getsize", (sc, in) -> new Fraction(((List) in[0].get(sc)).size()));
  168. registerFunction("list.getindex", (sc, in) -> ((List) in[0].get(sc)).get(in[1].getInt(sc)));
  169. registerAlias("list.getindex", "list.get");
  170. registerFunction("list.setindex", (sc, in) -> ((List) in[0].get(sc)).set(in[1].getInt(sc), in[2].get(sc)));
  171. registerFunction("list.clear", (sc, in) ->
  172. {
  173. ((List) in[0].get(sc)).clear();
  174. return Void.TYPE;
  175. });
  176. registerFunction("list.getindexof", (sc, in) -> new Fraction(((List) in[0].get(sc)).indexOf(in[1].get(sc))));
  177. registerFunction("list.sort", (sc, in) ->
  178. {
  179. Collections.sort(((List<Object>) in[0].get(sc)), (Object o1, Object o2) -> ((Comparable) o1).compareTo(o2));
  180. return Void.TYPE;
  181. });
  182. registerFunction("list.reverse", (sc, in) ->
  183. {
  184. Collections.reverse((List<Object>) in[0].get(sc));
  185. return Void.TYPE;
  186. });
  187. registerFunction("list.shuffle", (sc, in) ->
  188. {
  189. Collections.shuffle((List<Object>) in[0].get(sc));
  190. return Void.TYPE;
  191. });
  192. // ---------------------------------------------------------------------
  193. // arrays
  194. // ---------------------------------------------------------------------
  195. registerFunction("array.new", (sc, in) ->
  196. {
  197. for(InputProvider input : in)
  198. {
  199. ((DynamicArray) input).init(sc);
  200. }
  201. return Void.TYPE;
  202. });
  203. registerFunction("array.getsize", (sc, in) -> new Fraction(Array.getLength(in[0].getArray(sc))));
  204. /*
  205. registerFunction("array.swap", (sc, in) ->
  206. {
  207. Object[] o = (Object[]) args[0];
  208. int first = ScriptUtils.getInt(args[1]);
  209. int sec = ScriptUtils.getInt(args[2]);
  210. Object helper = o[first];
  211. o[first] = o[sec];
  212. o[sec] = helper;
  213. });
  214. registerFunction("array.sort", (sc, in) ->
  215. {
  216. if(args.length <= 1)
  217. {
  218. Arrays.sort((Object[]) args[0]);
  219. }
  220. else
  221. {
  222. Arrays.sort((Object[]) args[0], ScriptUtils.getInt(args[1]), ScriptUtils.getInt(args[2]));
  223. }
  224. });
  225. registerFunction("array.copy", (sc, in) ->
  226. {
  227. int first = ScriptUtils.getInt(args[2]);
  228. System.arraycopy((Object[]) args[0], first, (Object[]) args[1],
  229. ScriptUtils.getInt(args[4]), ScriptUtils.getInt(args[3]) - first + 1);
  230. });
  231. registerFunction("array.rsort", (sc, in) ->
  232. {
  233. if(args.length <= 1)
  234. {
  235. Arrays.sort((Object[]) args[0], (Object o, Object o1) -> -((Comparable) o).compareTo(o));
  236. }
  237. else
  238. {
  239. Arrays.sort((Object[]) args[0], ScriptUtils.getInt(args[1]),
  240. ScriptUtils.getInt(args[2]), (Object o, Object o1) -> -((Comparable) o).compareTo(o));
  241. }
  242. });
  243. registerFunction("array.fill", (sc, in) ->
  244. {
  245. if(args.length <= 2)
  246. {
  247. Arrays.fill((Object[]) args[0], args[1]);
  248. }
  249. else
  250. {
  251. Arrays.fill((Object[]) args[0], ScriptUtils.getInt(args[2]), ScriptUtils.getInt(args[3]), args[1]);
  252. }
  253. });*/
  254. // ---------------------------------------------------------------------
  255. // maps
  256. // ---------------------------------------------------------------------
  257. registerFunction("map.new", (sc, in) ->
  258. {
  259. in[0].set(sc, new HashMap<>());
  260. return Void.TYPE;
  261. });
  262. registerFunction("map.exists", (sc, in) -> in[0].get(sc) instanceof Map);
  263. registerFunction("map.add", (sc, in) -> ((Map) in[0].get(sc)).put(in[1].get(sc), in[2].get(sc)));
  264. registerFunction("map.remove", (sc, in) -> ((Map) in[0].get(sc)).remove(in[1].get(sc)));
  265. registerFunction("map.contains", (sc, in) -> ((Map) in[0].get(sc)).containsKey(in[1].get(sc)));
  266. registerFunction("map.getsize", (sc, in) -> new Fraction(((Map) in[0].get(sc)).size()));
  267. registerFunction("map.get", (sc, in) -> ((Map) in[0].get(sc)).get(in[1].get(sc)));
  268. registerFunction("map.getordefault", (sc, in) -> ((Map) in[0].get(sc)).getOrDefault(in[1].get(sc), in[2].get(sc)));
  269. registerFunction("map.clear", (sc, in) ->
  270. {
  271. ((Map) in[0].get(sc)).clear();
  272. return Void.TYPE;
  273. });
  274. registerFunction("map.keys", (sc, in) ->
  275. {
  276. in[0].set(sc, ((Map) in[1].get(sc)).keySet().stream().collect(Collectors.toList()));
  277. return Void.TYPE;
  278. });
  279. registerFunction("map.values", (sc, in) ->
  280. {
  281. in[0].set(sc, ((Map) in[1].get(sc)).values().stream().collect(Collectors.toList()));
  282. return Void.TYPE;
  283. });
  284. // ---------------------------------------------------------------------
  285. // sets
  286. // ---------------------------------------------------------------------
  287. registerFunction("set.new", (sc, in) ->
  288. {
  289. in[0].set(sc, new HashSet<>());
  290. return Void.TYPE;
  291. });
  292. registerFunction("set.exists", (sc, in) -> in[0].get(sc) instanceof Set);
  293. registerFunction("set.add", (sc, in) -> ((Set) in[0].get(sc)).add(in[1].get(sc)));
  294. registerFunction("set.remove", (sc, in) -> ((Set) in[0].get(sc)).remove(in[1].get(sc)));
  295. registerFunction("set.contains", (sc, in) -> ((Set) in[0].get(sc)).contains(in[1].get(sc)));
  296. registerFunction("set.getsize", (sc, in) -> new Fraction(((Set) in[0].get(sc)).size()));
  297. registerFunction("set.tolist", (sc, in) ->
  298. {
  299. in[0].set(sc, ((Set) in[1].get(sc)).stream().collect(Collectors.toList()));
  300. return Void.TYPE;
  301. });
  302. // ---------------------------------------------------------------------
  303. // time
  304. // ---------------------------------------------------------------------
  305. registerFunction("time.new", (sc, in) ->
  306. {
  307. GregorianCalendar cal = GregorianCalendar.from(ZonedDateTime.now());
  308. cal.setTimeInMillis(in[1].getFraction(sc).longValue());
  309. in[0].set(sc, cal);
  310. return Void.TYPE;
  311. });
  312. registerFunction("time.getmillis", (sc, in) -> new Fraction(System.currentTimeMillis()));
  313. registerFunction("time.from", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).getTimeInMillis()));
  314. registerFunction("time.nextday", (sc, in) ->
  315. {
  316. GregorianCalendar cal = (GregorianCalendar) in[0].get(sc);
  317. cal.add(Calendar.DAY_OF_YEAR, 1);
  318. cal.set(Calendar.HOUR, 0);
  319. cal.set(Calendar.SECOND, 0);
  320. cal.set(Calendar.MINUTE, 0);
  321. cal.set(Calendar.MILLISECOND, 0);
  322. return Void.TYPE;
  323. });
  324. registerFunction("time.getyear", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.YEAR)));
  325. registerFunction("time.getmonth", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.MONTH) + 1));
  326. registerFunction("time.getday", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.DAY_OF_MONTH)));
  327. registerFunction("time.gethour", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.HOUR_OF_DAY)));
  328. registerFunction("time.getminute", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.MINUTE)));
  329. registerFunction("time.getsecond", (sc, in) -> new Fraction(((GregorianCalendar) in[0].get(sc)).get(Calendar.SECOND)));
  330. // ---------------------------------------------------------------------
  331. // text
  332. // ---------------------------------------------------------------------
  333. registerFunction("text.matches", (sc, in) -> in[0].getString(sc).matches(in[1].getString(sc)));
  334. registerFunction("text.number", (sc, in) ->
  335. {
  336. Fraction f = in[0].getFraction(sc);
  337. if(f.doubleValue() == f.longValue())
  338. {
  339. return String.valueOf(f.longValue());
  340. }
  341. return String.valueOf(f.doubleValue());
  342. });
  343. registerFunction("text.class", (sc, in) -> in[0].get(sc).getClass().getSimpleName());
  344. registerFunction("text.tolowercase", (sc, in) -> Utils.connect(sc, in, 0).toLowerCase());
  345. registerAlias("tolowercase", "text.tolowercase");
  346. registerFunction("text.touppercase", (sc, in) -> Utils.connect(sc, in, 0).toUpperCase());
  347. registerAlias("touppercase", "text.touppercase");
  348. registerFunction("text.split", (sc, in) ->
  349. {
  350. in[0].set(sc, Arrays.stream(Utils.connect(sc, in, 2).split(in[1].getString(sc))).map(s -> Compiler.convert(s)).collect(Collectors.toList()));
  351. return Void.TYPE;
  352. });
  353. registerAlias("split", "text.split");
  354. registerFunction("text.concatlist", (sc, in) -> ((List<Object>) in[0].get(sc)).stream().limit(in[3].getInt(sc) + 1).skip(in[2].getInt(sc)).map(o -> String.valueOf(o)).collect(Collectors.joining(in[1].getString(sc))));
  355. registerAlias("concatlist", "text.concatlist");
  356. registerFunction("text.concat", (sc, in) -> Utils.connect(sc, in, 0));
  357. registerAlias("concat", "text.concat");
  358. registerFunction("text", (sc, in) -> String.valueOf(in[0].get(sc)));
  359. registerFunction("text.substring", (sc, in) -> in[0].getString(sc).substring(in[1].getInt(sc), in[2].getInt(sc)));
  360. registerFunction("text.length", (sc, in) -> in[0].getString(sc).length());
  361. registerFunction("text.startswith", (sc, in) -> in[0].getString(sc).startsWith(in[1].getString(sc), in[2].getInt(sc)));
  362. registerFunction("text.endswith", (sc, in) -> in[0].getString(sc).endsWith(in[1].getString(sc)));
  363. registerFunction("text.contains", (sc, in) -> in[0].getString(sc).contains(in[1].getString(sc)));
  364. registerFunction("text.indexof", (sc, in) -> in[0].getString(sc).indexOf(in[1].getString(sc), in[2].getInt(sc)));
  365. registerFunction("text.lastindexof", (sc, in) -> in[0].getString(sc).lastIndexOf(in[1].getString(sc), in[2].getInt(sc)));
  366. registerFunction("text.replace", (sc, in) -> in[0].getString(sc).replace(in[1].getString(sc), in[2].getString(sc)));
  367. registerFunction("text.trim", (sc, in) -> in[0].getString(sc).trim());
  368. registerFunction("text.charat", (sc, in) -> String.valueOf(in[0].getString(sc).charAt(in[1].getInt(sc))));
  369. registerFunction("text.charcode", (sc, in) -> new Fraction(in[0].getString(sc).charAt(in[1].getInt(sc))));
  370. registerFunction("text.fromcode", (sc, in) -> String.valueOf((char) in[0].getInt(sc)));
  371. // -------------------------------------------------------------------------------
  372. // files
  373. // -------------------------------------------------------------------------------
  374. registerFunction("file.new", (sc, in) ->
  375. {
  376. in[0].set(sc, new File(in[1].getString(sc)));
  377. return Void.TYPE;
  378. });
  379. registerFunction("file.exists", (sc, in) -> ((File) in[0].get(sc)).exists());
  380. registerFunction("file.delete", (sc, in) -> ((File) in[0].get(sc)).delete());
  381. registerFunction("file.getname", (sc, in) -> ((File) in[0].get(sc)).getName());
  382. registerFunction("file.getlist", (sc, in) ->
  383. {
  384. in[0].set(sc, Arrays.asList(((File) in[0].get(sc)).listFiles()));
  385. return Void.TYPE;
  386. });
  387. registerFunction("file.read", (sc, in) ->
  388. {
  389. try
  390. {
  391. in[0].set(sc, Files.readAllLines(((File) in[1].get(sc)).toPath()));
  392. }
  393. catch(IOException ex)
  394. {
  395. throw new FileIOException(ex.getMessage());
  396. }
  397. return Void.TYPE;
  398. });
  399. registerFunction("file.write", (sc, in) ->
  400. {
  401. try
  402. {
  403. File f = (File) in[0].get(sc);
  404. if(f.getParentFile() != null)
  405. {
  406. f.getParentFile().mkdirs();
  407. }
  408. if(!f.exists())
  409. {
  410. try
  411. {
  412. f.createNewFile();
  413. }
  414. catch(IOException ex)
  415. {
  416. throw new FileIOException(ex.getMessage());
  417. }
  418. }
  419. Files.write(Paths.get(f.toURI()), ((List<Object>) in[1].get(sc))
  420. .stream().map(o -> String.valueOf(o)).collect(Collectors.toList()), StandardCharsets.UTF_8);
  421. }
  422. catch(UnsupportedOperationException | SecurityException | IOException ex)
  423. {
  424. throw new FileIOException(ex.getMessage());
  425. }
  426. return Void.TYPE;
  427. });
  428. // ---------------------------------------------------------------------
  429. // config
  430. // ---------------------------------------------------------------------
  431. registerFunction("config.new", (sc, in) ->
  432. {
  433. in[0].set(sc, new SnuviConfig(sc, in[1].getString(sc), in[2].getString(sc)));
  434. return Void.TYPE;
  435. });
  436. registerFunction("config.exists", (sc, in) -> ((SnuviConfig) in[0].get(sc)).exists());
  437. registerFunction("config.save", (sc, in) -> ((SnuviConfig) in[0].get(sc)).save());
  438. registerFunction("config.delete", (sc, in) -> ((SnuviConfig) in[0].get(sc)).delete());
  439. registerFunction("config.set", (sc, in) ->
  440. {
  441. ((SnuviConfig) in[0].get(sc)).set(in[1].getString(sc), in[2].get(sc));
  442. return Void.TYPE;
  443. });
  444. registerFunction("config.getbool", (sc, in) -> ((SnuviConfig) in[0].get(sc)).getBoolean(in[1].getString(sc), in[2].getBoolean(sc)));
  445. registerFunction("config.getfraction", (sc, in) -> ((SnuviConfig) in[0].get(sc)).getFraction(in[1].getString(sc), in[2].getFraction(sc)));
  446. registerFunction("config.getstring", (sc, in) -> ((SnuviConfig) in[0].get(sc)).getString(in[1].getString(sc), in[2].getString(sc)));
  447. // ---------------------------------------------------------------------
  448. // commands without library
  449. // ---------------------------------------------------------------------
  450. // elementary calculating
  451. registerFunction("+", (sc, in) ->
  452. {
  453. return in[0].getFraction(sc).add(in[1].getFraction(sc));
  454. });
  455. registerAlias("+", "add");
  456. registerFunction("-", (sc, in) ->
  457. {
  458. return in[0].getFraction(sc).sub(in[1].getFraction(sc));
  459. });
  460. registerAlias("-", "sub");
  461. registerFunction("*", (sc, in) ->
  462. {
  463. return in[0].getFraction(sc).mul(in[1].getFraction(sc));
  464. });
  465. registerAlias("*", "mul");
  466. registerFunction("/", (sc, in) ->
  467. {
  468. return in[0].getFraction(sc).div(in[1].getFraction(sc));
  469. });
  470. registerAlias("/", "div");
  471. // var setter
  472. registerFunction("=", (sc, in) ->
  473. {
  474. in[0].set(sc, in[1].get(sc));
  475. return Void.TYPE;
  476. });
  477. registerAlias("=", "setvar");
  478. registerFunction("+=", (sc, in) ->
  479. {
  480. in[0].set(sc, in[0].getFraction(sc).add(in[1].getFraction(sc)));
  481. return Void.TYPE;
  482. });
  483. registerFunction("++", (sc, in) ->
  484. {
  485. Fraction f = in[0].getFraction(sc);
  486. in[0].set(sc, f.add(new Fraction(1)));
  487. return f;
  488. });
  489. registerAlias("++", "inc");
  490. registerFunction("p+", (sc, in) ->
  491. {
  492. Fraction f = in[0].getFraction(sc).add(new Fraction(1));
  493. in[0].set(sc, f);
  494. return f;
  495. });
  496. registerFunction("-=", (sc, in) ->
  497. {
  498. in[0].set(sc, in[0].getFraction(sc).sub(in[1].getFraction(sc)));
  499. return Void.TYPE;
  500. });
  501. registerFunction("--", (sc, in) ->
  502. {
  503. Fraction f = in[0].getFraction(sc);
  504. in[0].set(sc, f.sub(new Fraction(1)));
  505. return f;
  506. });
  507. registerAlias("--", "dec");
  508. registerFunction("p-", (sc, in) ->
  509. {
  510. Fraction f = in[0].getFraction(sc).sub(new Fraction(1));
  511. in[0].set(sc, f);
  512. return f;
  513. });
  514. registerFunction("*=", (sc, in) ->
  515. {
  516. in[0].set(sc, in[0].getFraction(sc).mul(in[1].getFraction(sc)));
  517. return Void.TYPE;
  518. });
  519. registerFunction("/=", (sc, in) ->
  520. {
  521. in[0].set(sc, in[0].getFraction(sc).div(in[1].getFraction(sc)));
  522. return Void.TYPE;
  523. });
  524. registerFunction("%=", (sc, in) ->
  525. {
  526. in[0].set(sc, new Fraction(in[0].getInt(sc) % in[1].getInt(sc)));
  527. return Void.TYPE;
  528. });
  529. registerFunction("<<=", (sc, in) ->
  530. {
  531. in[0].set(sc, in[0].getFraction(sc).leftShift(in[1].getInt(sc)));
  532. return Void.TYPE;
  533. });
  534. registerFunction(">>=", (sc, in) ->
  535. {
  536. in[0].set(sc, in[0].getFraction(sc).rightShift(in[1].getInt(sc)));
  537. return Void.TYPE;
  538. });
  539. registerFunction("&=", (sc, in) ->
  540. {
  541. in[0].set(sc, in[0].getFraction(sc).and(in[1].getFraction(sc)));
  542. return Void.TYPE;
  543. });
  544. registerFunction("^=", (sc, in) ->
  545. {
  546. in[0].set(sc, in[0].getFraction(sc).xor(in[1].getFraction(sc)));
  547. return Void.TYPE;
  548. });
  549. registerFunction("|=", (sc, in) ->
  550. {
  551. in[0].set(sc, in[0].getFraction(sc).or(in[1].getFraction(sc)));
  552. return Void.TYPE;
  553. });
  554. // var stuff
  555. registerFunction("getvar", (sc, in) -> sc.getVar(in[0].getString(sc)).get(sc));
  556. registerFunction("wait", (sc, in) ->
  557. {
  558. sc.isWaiting = true;
  559. return Void.TYPE;
  560. });
  561. // try - catch
  562. registerFunction("try", (sc, in) ->
  563. {
  564. sc.catchLine = sc.currentLine + in[0].getInt(sc);
  565. return Void.TYPE;
  566. });
  567. registerFunction("catch", (sc, in) ->
  568. {
  569. if(sc.catchLine != -1)
  570. {
  571. sc.currentLine += in[0].getInt(sc);
  572. }
  573. return Void.TYPE;
  574. });
  575. // branching
  576. registerFunction("goto", (sc, in) ->
  577. {
  578. sc.currentLine = sc.labels.get(in[0].getString(sc));
  579. return Void.TYPE;
  580. });
  581. registerFunction("sgoto", (sc, in) ->
  582. {
  583. if(sc.subScript)
  584. {
  585. throw new IllegalStateException("sgoto is not allowed in functions");
  586. }
  587. int time = in[0].getInt(sc);
  588. if(time < 0)
  589. {
  590. throw new IllegalArgumentException("time units can't be negative");
  591. }
  592. int label = sc.labels.get(in[1].getString(sc));
  593. sc.scheduler.scheduleTask(() ->
  594. {
  595. if(!sc.isValid || sc.isHolded)
  596. {
  597. return;
  598. }
  599. sc.currentLine = label + 1;
  600. sc.run();
  601. }, time);
  602. return Void.TYPE;
  603. });
  604. registerFunction("gosub", (sc, in) ->
  605. {
  606. sc.returnStack.push(sc.currentLine);
  607. sc.currentLine = sc.labels.get(in[0].getString(sc));
  608. return Void.TYPE;
  609. });
  610. registerFunction("return", (sc, in) ->
  611. {
  612. if(sc.returnStack.isEmpty())
  613. {
  614. sc.end();
  615. sc.returnValue = in.length > 0 ? in[0].get(sc) : null;
  616. }
  617. else
  618. {
  619. sc.currentLine = sc.returnStack.pop();
  620. }
  621. return Void.TYPE;
  622. });
  623. registerFunction("if", (sc, in) ->
  624. {
  625. sc.ifState = in[0].getBoolean(sc);
  626. if(!sc.ifState)
  627. {
  628. sc.currentLine += in[1].getInt(sc);
  629. }
  630. return Void.TYPE;
  631. });
  632. registerFunction("elseif", (sc, in) ->
  633. {
  634. if(sc.ifState)
  635. {
  636. sc.currentLine += in[1].getInt(sc);
  637. }
  638. else
  639. {
  640. sc.ifState = in[0].getBoolean(sc);
  641. if(!sc.ifState)
  642. {
  643. sc.currentLine += in[1].getInt(sc);
  644. }
  645. }
  646. return Void.TYPE;
  647. });
  648. registerFunction("else", (sc, in) ->
  649. {
  650. if(sc.ifState)
  651. {
  652. sc.currentLine += in[0].getInt(sc);
  653. }
  654. sc.ifState = true;
  655. return Void.TYPE;
  656. });
  657. registerFunction("while", (sc, in) ->
  658. {
  659. if(!in[0].getBoolean(sc))
  660. {
  661. sc.currentLine += in[1].getInt(sc);
  662. }
  663. return Void.TYPE;
  664. });
  665. registerFunction("wend", (sc, in) ->
  666. {
  667. sc.currentLine += in[0].getInt(sc);
  668. return Void.TYPE;
  669. });
  670. registerFunction("for", (sc, in) ->
  671. {
  672. // for(var, start, end, step)
  673. Fraction start = in[1].getFraction(sc);
  674. in[0].set(sc, start);
  675. if(start.compareTo(in[2].getFraction(sc)) > 0)
  676. {
  677. sc.currentLine += in[4].getInt(sc);
  678. }
  679. return Void.TYPE;
  680. });
  681. registerFunction("next", (sc, in) ->
  682. {
  683. int line = sc.currentLine + in[0].getInt(sc);
  684. InputProvider[] f = sc.code[line].getParameters();
  685. // for(var, start, end, step)
  686. Fraction current = f[0].getFraction(sc).add(f[3].getFraction(sc));
  687. f[0].set(sc, current);
  688. if(current.compareTo(f[2].getFraction(sc)) <= 0)
  689. {
  690. sc.currentLine = line;
  691. }
  692. return Void.TYPE;
  693. });
  694. registerFunction("continue", (sc, in) ->
  695. {
  696. sc.currentLine += in[0].getInt(sc);
  697. return Void.TYPE;
  698. });
  699. registerFunction("break", (sc, in) ->
  700. {
  701. sc.currentLine += in[0].getInt(sc);
  702. return Void.TYPE;
  703. });
  704. // comparing
  705. registerFunction("==", (sc, in) -> Objects.equals(in[0].get(sc), in[1].get(sc)));
  706. registerAlias("==", "equal");
  707. registerAlias("==", "equals");
  708. registerFunction("!=", (sc, in) -> !Objects.equals(in[0].get(sc), in[1].get(sc)));
  709. registerAlias("!=", "notequal");
  710. registerFunction("<", (sc, in) -> in[0].getFraction(sc).compareTo(in[1].getFraction(sc)) < 0);
  711. registerAlias("<", "less");
  712. registerFunction(">", (sc, in) -> in[0].getFraction(sc).compareTo(in[1].getFraction(sc)) > 0);
  713. registerAlias(">", "greater");
  714. registerFunction("<=", (sc, in) -> in[0].getFraction(sc).compareTo(in[1].getFraction(sc)) <= 0);
  715. registerAlias("<=", "lessequal");
  716. registerFunction(">=", (sc, in) -> in[0].getFraction(sc).compareTo(in[1].getFraction(sc)) >= 0);
  717. registerAlias(">=", "greaterequal");
  718. registerFunction("!", (sc, in) -> !in[0].getBoolean(sc));
  719. registerAlias("!", "invert");
  720. // logical stuff
  721. registerFunction("&&", (sc, in) -> Arrays.stream(in).map(i -> i.getBoolean(sc)).allMatch(s -> s));
  722. registerAlias("&&", "and");
  723. registerFunction("||", (sc, in) -> Arrays.stream(in).map(i -> i.getBoolean(sc)).anyMatch(s -> s));
  724. registerAlias( "||", "or");
  725. // non grouped stuff
  726. registerFunction("swap", (sc, in) ->
  727. {
  728. Object o = in[0].get(sc);
  729. in[0].set(sc, in[1].get(sc));
  730. in[1].set(sc, o);
  731. return Void.TYPE;
  732. });
  733. registerFunction("print", (sc, in) ->
  734. {
  735. System.out.println(Utils.connect(sc, in, 0));
  736. return Void.TYPE;
  737. });
  738. registerFunction("waitfor", (sc, in) ->
  739. {
  740. if(sc.subScript)
  741. {
  742. throw new IllegalStateException("waitfor is not allowed in functions");
  743. }
  744. long l = in[0].getInt(sc);
  745. if(l < 0)
  746. {
  747. throw new IllegalArgumentException("time units can't be negative");
  748. }
  749. sc.isHolded = true;
  750. sc.scheduler.scheduleTask(() ->
  751. {
  752. // activate this again on NullPointerException
  753. // if(sc == null || !sc.isValid)
  754. if(sc.isValid)
  755. {
  756. sc.isHolded = false;
  757. sc.run();
  758. }
  759. }, l);
  760. sc.isWaiting = true;
  761. return Void.TYPE;
  762. });
  763. registerFunction("term", (sc, in) ->
  764. {
  765. // TODO
  766. // { termSafe(sc); throw new HoldCodeException(); });
  767. return Void.TYPE;
  768. });
  769. registerFunction("islong", (sc, in) ->
  770. {
  771. Object o = in[0].get(sc);
  772. if(o instanceof Fraction)
  773. {
  774. return ((Fraction) o).isLong();
  775. }
  776. return false;
  777. });
  778. registerFunction("assert", (sc, in) ->
  779. {
  780. if(!in[0].getBoolean(sc))
  781. {
  782. throw new AssertionException("assertion failed");
  783. }
  784. return Void.TYPE;
  785. });
  786. }
  787. }