FunctionLoader.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. package me.hammerle.snuviscript.code;
  2. import java.util.Arrays;
  3. import java.util.HashMap;
  4. import java.util.Random;
  5. import java.util.stream.Collectors;
  6. import me.hammerle.snuviscript.array.DynamicArray;
  7. import me.hammerle.snuviscript.variable.ArrayVariable;
  8. import me.hammerle.snuviscript.variable.Variable;
  9. import me.hammerle.snuviscript.math.Fraction;
  10. public class FunctionLoader
  11. {
  12. private static final HashMap<String, BasicFunction> FUNCTIONS = new HashMap<>();
  13. public static void registerFunction(String name, BasicFunction function)
  14. {
  15. FUNCTIONS.put(name, function);
  16. }
  17. public static void registerFunction(BasicFunction function)
  18. {
  19. registerFunction(function.getName(), function);
  20. }
  21. public static void registerAlias(String original, String alias)
  22. {
  23. FUNCTIONS.put(alias, FUNCTIONS.get(original));
  24. }
  25. public static BasicFunction getFunction(String function)
  26. {
  27. return FUNCTIONS.getOrDefault(function, new BasicFunction(function, (sc, in) ->
  28. {
  29. Script sub = sc.subScripts.get(function);
  30. if(sub == null)
  31. {
  32. throw new NullPointerException("function " + function + " does not exist");
  33. }
  34. // push storage for local vars
  35. HashMap<String, Variable> vars = new HashMap<>();
  36. if(in.length != sub.subScriptInput.length)
  37. {
  38. throw new NullPointerException("invalid number of input for function " + function);
  39. }
  40. // generate local vars
  41. String s;
  42. Variable v;
  43. for(int i = 0; i < in.length; i++)
  44. {
  45. s = sub.subScriptInput[i];
  46. if(in[i].isArray(sc))
  47. {
  48. v = new ArrayVariable(s);
  49. v.set(sc, in[i].getArray(sc));
  50. }
  51. else
  52. {
  53. v = new Variable(s);
  54. v.set(sc, in[i].get(sc));
  55. }
  56. vars.put(s, v);
  57. }
  58. sub.localVars.push(vars);
  59. // saving line for return
  60. int line = sub.currentLine;
  61. // set starting line for current run
  62. sub.currentLine = 0;
  63. // run subscript and save return value
  64. Object r = sub.run();
  65. // return back to previous line
  66. sub.currentLine = line;
  67. // pop storage for local vars
  68. sub.localVars.pop();
  69. return r;
  70. }));
  71. }
  72. private static final Random[] RND;
  73. static
  74. {
  75. RND = new Random[8];
  76. for(int i = 0; i < 8; i++)
  77. {
  78. RND[i] = new Random();
  79. }
  80. // ---------------------------------------------------------------------
  81. // brackets
  82. // ---------------------------------------------------------------------
  83. registerFunction("", new BasicFunction("", (sc, in) ->
  84. {
  85. return in[0].get(sc);
  86. }));
  87. // ---------------------------------------------------------------------
  88. // elementary arithmetic
  89. // ---------------------------------------------------------------------
  90. registerFunction("+", new BasicFunction("ADD", (sc, in) ->
  91. {
  92. return in[0].getFraction(sc).add(in[1].getFraction(sc));
  93. }));
  94. registerFunction("-", new BasicFunction("SUB", (sc, in) ->
  95. {
  96. return in[0].getFraction(sc).sub(in[1].getFraction(sc));
  97. }));
  98. registerFunction("*", new BasicFunction("MUL", (sc, in) ->
  99. {
  100. return in[0].getFraction(sc).mul(in[1].getFraction(sc));
  101. }));
  102. registerFunction("/", new BasicFunction("DIV", (sc, in) ->
  103. {
  104. return in[0].getFraction(sc).div(in[1].getFraction(sc));
  105. }));
  106. // ---------------------------------------------------------------------
  107. // comparing
  108. // ---------------------------------------------------------------------
  109. registerFunction("==", new BasicFunction("EQUAL", (sc, in) ->
  110. {
  111. Object a = in[0].get(sc);
  112. Object b = in[1].get(sc);
  113. if(a == null || b == null)
  114. {
  115. return a == b ? 1 : 0;
  116. }
  117. else if(a instanceof String || b instanceof String)
  118. {
  119. return a.equals(b) ? 1 : 0;
  120. }
  121. return ((Number) a).doubleValue() == ((Number) b).doubleValue() ? 1 : 0;
  122. }));
  123. registerFunction("!=", new BasicFunction("NOTEQUAL", (sc, in) ->
  124. {
  125. Object a = in[0].get(sc);
  126. Object b = in[1].get(sc);
  127. if(a == null || b == null)
  128. {
  129. return a != b ? 1 : 0;
  130. }
  131. else if(a instanceof String || b instanceof String)
  132. {
  133. return a.equals(b) ? 1 : 0;
  134. }
  135. return ((Number) a).doubleValue() != ((Number) b).doubleValue() ? 1 : 0;
  136. }));
  137. registerFunction(">", new BasicFunction("GREATER", (sc, in) ->
  138. {
  139. return in[0].getDouble(sc) > in[1].getDouble(sc) ? 1 : 0;
  140. }));
  141. registerFunction(">=", new BasicFunction("GREATEREQUAL", (sc, in) ->
  142. {
  143. return in[0].getDouble(sc) >= in[1].getDouble(sc) ? 1 : 0;
  144. }));
  145. registerFunction("<", new BasicFunction("SMALLER", (sc, in) ->
  146. {
  147. return in[0].getDouble(sc) < in[1].getDouble(sc) ? 1 : 0;
  148. }));
  149. registerFunction("<=", new BasicFunction("SMALLEREQUAL", (sc, in) ->
  150. {
  151. return in[0].getDouble(sc) <= in[1].getDouble(sc) ? 1 : 0;
  152. }));
  153. // ---------------------------------------------------------------------
  154. // logical operators
  155. // ---------------------------------------------------------------------
  156. registerFunction("&&", new BasicFunction("AND", (sc, in) ->
  157. {
  158. return (in[0].getDouble(sc) != 0 && in[1].getDouble(sc) != 0) ? 1 : 0;
  159. }));
  160. registerFunction("||", new BasicFunction("OR", (sc, in) ->
  161. {
  162. return (in[0].getDouble(sc) != 0 || in[1].getDouble(sc) != 0) ? 1 : 0;
  163. }));
  164. // ---------------------------------------------------------------------
  165. // bit stuff
  166. // ---------------------------------------------------------------------
  167. registerFunction(new BasicFunction("MOD", (sc, in) ->
  168. {
  169. return in[0].getInt(sc) % in[1].getInt(sc);
  170. }));
  171. registerFunction("&", new BasicFunction("AND", (sc, in) ->
  172. {
  173. return in[0].getInt(sc) & in[1].getInt(sc);
  174. }));
  175. registerFunction("|", new BasicFunction("OR", (sc, in) ->
  176. {
  177. return in[0].getInt(sc) | in[1].getInt(sc);
  178. }));
  179. registerFunction("^", new BasicFunction("XOR", (sc, in) ->
  180. {
  181. return in[0].getInt(sc) ^ in[1].getInt(sc);
  182. }));
  183. registerFunction("<<", new BasicFunction("SHIFTL", (sc, in) ->
  184. {
  185. return in[0].getInt(sc) << in[1].getInt(sc);
  186. }));
  187. registerFunction(">>", new BasicFunction("SHIFTR", (sc, in) ->
  188. {
  189. return in[0].getInt(sc) >> in[1].getInt(sc);
  190. }));
  191. // ---------------------------------------------------------------------
  192. // basic instructions (variables and arrays)
  193. // ---------------------------------------------------------------------
  194. registerFunction("=", new BasicFunction("SET", (sc, in) ->
  195. {
  196. in[0].set(sc, in[1].get(sc));
  197. return Void.TYPE;
  198. }));
  199. registerFunction("+=", new BasicFunction("ADD_SET", (sc, in) ->
  200. {
  201. in[0].set(sc, in[0].getFraction(sc).add(in[1].getFraction(sc)));
  202. return Void.TYPE;
  203. }));
  204. registerFunction("-=", new BasicFunction("SUB_SET", (sc, in) ->
  205. {
  206. in[0].set(sc, in[0].getFraction(sc).sub(in[1].getFraction(sc)));
  207. return Void.TYPE;
  208. }));
  209. registerFunction("*=", new BasicFunction("MUL_SET", (sc, in) ->
  210. {
  211. in[0].set(sc, in[0].getFraction(sc).mul(in[1].getFraction(sc)));
  212. return Void.TYPE;
  213. }));
  214. registerFunction("/=", new BasicFunction("DIV_SET", (sc, in) ->
  215. {
  216. in[0].set(sc, in[0].getFraction(sc).div(in[1].getFraction(sc)));
  217. return Void.TYPE;
  218. }));
  219. registerFunction("%=", new BasicFunction("MOD_SET", (sc, in) ->
  220. {
  221. in[0].set(sc, new Fraction(in[0].getInt(sc) % in[1].getInt(sc)));
  222. return Void.TYPE;
  223. }));
  224. registerFunction("<<=", new BasicFunction("LEFT_SHIFT_SET", (sc, in) ->
  225. {
  226. in[0].set(sc, in[0].getFraction(sc).leftShift(in[1].getInt(sc)));
  227. return Void.TYPE;
  228. }));
  229. registerFunction(">>=", new BasicFunction("RIGHT_SHIFT_SET", (sc, in) ->
  230. {
  231. in[0].set(sc, in[0].getFraction(sc).rightShift(in[1].getInt(sc)));
  232. return Void.TYPE;
  233. }));
  234. registerFunction("&=", new BasicFunction("BIT_AND_SET", (sc, in) ->
  235. {
  236. in[0].set(sc, in[0].getFraction(sc).and(in[1].getFraction(sc)));
  237. return Void.TYPE;
  238. }));
  239. registerFunction("^=", new BasicFunction("BIT_XOR_SET", (sc, in) ->
  240. {
  241. in[0].set(sc, in[0].getFraction(sc).xor(in[1].getFraction(sc)));
  242. return Void.TYPE;
  243. }));
  244. registerFunction("|=", new BasicFunction("BIT_OR_SET", (sc, in) ->
  245. {
  246. in[0].set(sc, in[0].getFraction(sc).or(in[1].getFraction(sc)));
  247. return Void.TYPE;
  248. }));
  249. registerFunction(new BasicFunction("DIM", (sc, in) ->
  250. {
  251. for(InputProvider input : in)
  252. {
  253. ((DynamicArray) input).init(sc);
  254. }
  255. return Void.TYPE;
  256. }));
  257. registerAlias("DIM", "VAR");
  258. registerFunction(new BasicFunction("SWAP", (sc, in) ->
  259. {
  260. Object o = in[0].get(sc);
  261. in[0].set(sc, in[1].get(sc));
  262. in[1].set(sc, o);
  263. return Void.TYPE;
  264. }));
  265. registerFunction(new BasicFunction("INC", (sc, in) ->
  266. {
  267. in[0].set(sc, in[0].getInt(sc) + (in.length > 1 ? in[1].getInt(sc) : 1));
  268. return Void.TYPE;
  269. }));
  270. registerFunction(new BasicFunction("DEC", (sc, in) ->
  271. {
  272. in[0].set(sc, in[0].getInt(sc) - (in.length > 1 ? in[1].getInt(sc) : 1));
  273. return Void.TYPE;
  274. }));
  275. // ---------------------------------------------------------------------
  276. // basic instructions (control and branching)
  277. // ---------------------------------------------------------------------
  278. registerFunction(new BasicFunction("goto", (sc, in) ->
  279. {
  280. sc.currentLine = sc.labels.get(in[0].getString(sc));
  281. return Void.TYPE;
  282. }));
  283. registerFunction(new BasicFunction("GOSUB", (sc, in) ->
  284. {
  285. sc.returnStack.push(sc.currentLine);
  286. sc.currentLine = sc.labels.get(in[0].getString(sc));
  287. return Void.TYPE;
  288. }));
  289. registerFunction(new BasicFunction("return", (sc, in) ->
  290. {
  291. if(sc.returnStack.isEmpty())
  292. {
  293. sc.end();
  294. sc.returnValue = in.length > 0 ? in[0].get(sc) : null;
  295. }
  296. else
  297. {
  298. sc.currentLine = sc.returnStack.pop();
  299. }
  300. return Void.TYPE;
  301. }));
  302. registerFunction(new BasicFunction("if", (sc, in) ->
  303. {
  304. int p = in[0].getInt(sc);
  305. if(p == 0)
  306. {
  307. sc.currentLine += in[1].getInt(sc);
  308. }
  309. return Void.TYPE;
  310. }));
  311. registerFunction(new BasicFunction("endif", (sc, in) ->
  312. {
  313. return Void.TYPE;
  314. }));
  315. registerFunction(new BasicFunction("for", (sc, in) ->
  316. {
  317. // for(var, start, end, step)
  318. Fraction start = in[1].getFraction(sc);
  319. in[0].set(sc, start);
  320. if(start.compareTo(in[2].getFraction(sc)) > 0)
  321. {
  322. sc.currentLine += in[4].getInt(sc);
  323. }
  324. return Void.TYPE;
  325. }));
  326. registerFunction(new BasicFunction("next", (sc, in) ->
  327. {
  328. int line = sc.currentLine + in[0].getInt(sc);
  329. InputProvider[] f = sc.code[line].getParameters();
  330. // for(var, start, end, step)
  331. Fraction current = f[0].getFraction(sc).add(f[3].getFraction(sc));
  332. f[0].set(sc, current);
  333. if(current.compareTo(f[2].getFraction(sc)) <= 0)
  334. {
  335. sc.currentLine = line;
  336. }
  337. return Void.TYPE;
  338. }));
  339. registerFunction(new BasicFunction("while", (sc, in) ->
  340. {
  341. if(in[0].getInt(sc) == 0)
  342. {
  343. sc.currentLine += in[1].getInt(sc);
  344. }
  345. return Void.TYPE;
  346. }));
  347. registerFunction(new BasicFunction("wend", (sc, in) ->
  348. {
  349. sc.currentLine += in[0].getInt(sc);
  350. return Void.TYPE;
  351. }));
  352. registerFunction(new BasicFunction("continue", (sc, in) ->
  353. {
  354. sc.currentLine += in[0].getInt(sc);
  355. return Void.TYPE;
  356. }));
  357. registerFunction(new BasicFunction("break", (sc, in) ->
  358. {
  359. sc.currentLine += in[0].getInt(sc);
  360. return Void.TYPE;
  361. }));
  362. // ---------------------------------------------------------------------
  363. // mathematics
  364. // ---------------------------------------------------------------------
  365. registerFunction(new BasicFunction("FLOOR", (sc, in) ->
  366. {
  367. return (int) Math.floor(in[0].getDouble(sc));
  368. }));
  369. registerFunction(new BasicFunction("ROUND", (sc, in) ->
  370. {
  371. return (int) Math.round(in[0].getDouble(sc));
  372. }));
  373. registerFunction(new BasicFunction("CEIL", (sc, in) ->
  374. {
  375. return (int) Math.ceil(in[0].getDouble(sc));
  376. }));
  377. registerFunction(new BasicFunction("ABS", (sc, in) ->
  378. {
  379. return in[0].getFraction(sc).abs();
  380. }));
  381. registerFunction(new BasicFunction("SGN", (sc, in) ->
  382. {
  383. double d = in[0].getDouble(sc);
  384. return d < 0 ? -1 : (d > 0 ? 1 : 0);
  385. }));
  386. /*registerFunction(new BasicFunction("MIN", (sc, in) ->
  387. {
  388. if(in.length == 1)
  389. {
  390. return ((IMathOperation) in[0]).min(sc);
  391. }
  392. double min = Arrays.stream(in).mapToDouble(i -> i.getDouble(sc)).min().getAsDouble();
  393. if(min == (int) min)
  394. {
  395. return (int) min;
  396. }
  397. return min;
  398. }));
  399. registerFunction(new BasicFunction("MAX", (sc, in) ->
  400. {
  401. if(in.length == 1)
  402. {
  403. return ((IMathOperation) in[0]).max(sc);
  404. }
  405. double max = Arrays.stream(in).mapToDouble(i -> i.getDouble(sc)).max().getAsDouble();
  406. if(max == (int) max)
  407. {
  408. return (int) max;
  409. }
  410. return max;
  411. }));*/
  412. registerFunction(new BasicFunction("RND", (sc, in) ->
  413. {
  414. int seedId;
  415. int max;
  416. switch (in.length)
  417. {
  418. case 1:
  419. seedId = 0;
  420. max = in[0].getInt(sc);
  421. break;
  422. case 2:
  423. seedId = in[0].getInt(sc);
  424. max = in[1].getInt(sc);
  425. break;
  426. default:
  427. throw new IllegalArgumentException("invalid number of arguments");
  428. }
  429. if(seedId < 0 || seedId > 7)
  430. {
  431. throw new IllegalArgumentException("seed id must be from 0 to 7");
  432. }
  433. return RND[seedId].nextInt(max);
  434. }));
  435. registerFunction(new BasicFunction("RNDF", (sc, in) ->
  436. {
  437. int seedId = 0;
  438. if(in.length > 0)
  439. {
  440. seedId = in[0].getInt(sc);
  441. }
  442. if(seedId < 0 || seedId > 7)
  443. {
  444. throw new IllegalArgumentException("seed id must be from 0 to 7");
  445. }
  446. return RND[seedId].nextDouble();
  447. }));
  448. registerFunction(new BasicFunction("RANDOMIZE", (sc, in) ->
  449. {
  450. int seedId = in[0].getInt(sc);
  451. if(seedId < 0 || seedId > 7)
  452. {
  453. throw new IllegalArgumentException("seed id must be from 0 to 7");
  454. }
  455. switch (in.length)
  456. {
  457. case 1:
  458. RND[seedId] = new Random();
  459. break;
  460. case 2:
  461. RND[seedId] = new Random(in[1].getInt(sc));
  462. break;
  463. default:
  464. throw new IllegalArgumentException("invalid number of arguments");
  465. }
  466. return Void.TYPE;
  467. }));
  468. registerFunction(new BasicFunction("SQR", (sc, in) ->
  469. {
  470. return Math.sqrt(in[0].getDouble(sc));
  471. }));
  472. registerFunction(new BasicFunction("EXP", (sc, in) ->
  473. {
  474. if(in.length == 0)
  475. {
  476. return Math.E;
  477. }
  478. return Math.exp(in[0].getDouble(sc));
  479. }));
  480. registerFunction(new BasicFunction("LOG", (sc, in) ->
  481. {
  482. if(in.length >= 2)
  483. {
  484. return Math.log(in[0].getDouble(sc)) / Math.log(in[1].getDouble(sc));
  485. }
  486. return Math.log(in[0].getDouble(sc));
  487. }));
  488. registerFunction(new BasicFunction("POW", (sc, in) ->
  489. {
  490. return Math.pow(in[0].getDouble(sc), in[1].getDouble(sc));
  491. }));
  492. registerFunction(new BasicFunction("PI", (sc, in) ->
  493. {
  494. return Math.PI;
  495. }));
  496. registerFunction(new BasicFunction("RAD", (sc, in) ->
  497. {
  498. return Math.toRadians(in[0].getDouble(sc));
  499. }));
  500. registerFunction(new BasicFunction("DEG", (sc, in) ->
  501. {
  502. return Math.toDegrees(in[0].getDouble(sc));
  503. }));
  504. registerFunction(new BasicFunction("SIN", (sc, in) ->
  505. {
  506. return Math.sin(in[0].getDouble(sc));
  507. }));
  508. registerFunction(new BasicFunction("COS", (sc, in) ->
  509. {
  510. return Math.cos(in[0].getDouble(sc));
  511. }));
  512. registerFunction(new BasicFunction("TAN", (sc, in) ->
  513. {
  514. return Math.tan(in[0].getDouble(sc));
  515. }));
  516. registerFunction(new BasicFunction("ASIN", (sc, in) ->
  517. {
  518. return Math.asin(in[0].getDouble(sc));
  519. }));
  520. registerFunction(new BasicFunction("ACOS", (sc, in) ->
  521. {
  522. return Math.acos(in[0].getDouble(sc));
  523. }));
  524. registerFunction(new BasicFunction("ATAN", (sc, in) ->
  525. {
  526. if(in.length >= 2)
  527. {
  528. return Math.atan2(in[0].getDouble(sc), in[1].getDouble(sc));
  529. }
  530. return Math.atan(in[0].getDouble(sc));
  531. }));
  532. registerFunction(new BasicFunction("SINH", (sc, in) ->
  533. {
  534. return Math.sinh(in[0].getDouble(sc));
  535. }));
  536. registerFunction(new BasicFunction("COSH", (sc, in) ->
  537. {
  538. return Math.cosh(in[0].getDouble(sc));
  539. }));
  540. registerFunction(new BasicFunction("TANH", (sc, in) ->
  541. {
  542. return Math.tanh(in[0].getDouble(sc));
  543. }));
  544. registerFunction(new BasicFunction("CLASSIFY", (sc, in) ->
  545. {
  546. double d = in[0].getDouble(sc);
  547. if(Double.isNaN(d))
  548. {
  549. return 2;
  550. }
  551. else if(Double.isInfinite(d))
  552. {
  553. return 1;
  554. }
  555. return 0;
  556. }));
  557. registerFunction(new BasicFunction("print", (sc, in) ->
  558. {
  559. printMessage(Arrays.stream(in).map(s -> s.getString(sc)).collect(Collectors.joining()));
  560. return Void.TYPE;
  561. }));
  562. registerFunction(new BasicFunction("TEST", (sc, in) ->
  563. {
  564. return 1;
  565. }));
  566. }
  567. private static void printMessage(String message)
  568. {
  569. System.out.println(message);
  570. }
  571. }