FunctionLoader.java 39 KB

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