FunctionLoader.java 39 KB

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