Code.java 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. package me.hammerle.code;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.Map.Entry;
  5. import java.util.Stack;
  6. import java.util.TreeSet;
  7. import me.hammerle.exceptions.PreScriptException;
  8. import me.hammerle.exceptions.NoSuchMethodException;
  9. public class Code implements Comparable<Code>
  10. {
  11. protected final int realLine;
  12. protected final int line;
  13. private int subline;
  14. private final String function;
  15. private final int level;
  16. private final int pars;
  17. private final Object value;
  18. private int jump;
  19. private Code(String function, int level, int pars, int line, int subline, Object value, int jump, int realLine)
  20. {
  21. this.function = function;
  22. this.level = level;
  23. this.pars = pars;
  24. this.line = line;
  25. this.subline = subline;
  26. this.value = value;
  27. this.jump = jump;
  28. this.realLine = realLine;
  29. }
  30. public Code(String function, int level, int pars, int line, int subline, int realLine)
  31. {
  32. this(function.trim(), level, pars, line, subline, null, 0, realLine);
  33. }
  34. public Code(int level, int pars, int line, int subline, Object value, int realLine)
  35. {
  36. this(null, level, pars, line, subline, value, 0, realLine);
  37. }
  38. public void executeFunction(SnuviParser parser, Script sc, Stack<Object> stack)
  39. {
  40. //System.out.println("Executing: " + this.toString());
  41. if(value != null)
  42. {
  43. if(value.getClass() == Variable.class)
  44. {
  45. stack.push(sc.getVar(((Variable) value).getName()));
  46. return;
  47. }
  48. stack.push(value);
  49. return;
  50. }
  51. else if(value == null && function == null)
  52. {
  53. stack.push(value);
  54. return;
  55. }
  56. Object[] input;
  57. if(pars > 0)
  58. {
  59. input = new Object[pars];
  60. for(int i = 0; i < pars; i++)
  61. {
  62. input[i] = stack.pop();
  63. }
  64. }
  65. else
  66. {
  67. input = new Object[0];
  68. }
  69. Object output = parser.parseFunction(sc, function, input);
  70. if(output != Void.TYPE)
  71. {
  72. stack.push(output);
  73. }
  74. }
  75. public String getFunction()
  76. {
  77. return function;
  78. }
  79. @Override
  80. public String toString()
  81. {
  82. StringBuilder sb = new StringBuilder(">");
  83. for(int i = 1; i < level; i++)
  84. {
  85. sb.append(">");
  86. }
  87. sb.append(" (");
  88. sb.append(line);
  89. sb.append(",");
  90. sb.append(subline);
  91. sb.append(") ");
  92. if(value != null)
  93. {
  94. sb.append("push ");
  95. sb.append(value.getClass().getSimpleName());
  96. sb.append(" '");
  97. sb.append(value);
  98. sb.append("'");
  99. return sb.toString();
  100. }
  101. else if(value == null && function == null)
  102. {
  103. sb.append("push Null '");
  104. sb.append(value);
  105. sb.append("'");
  106. return sb.toString();
  107. }
  108. sb.append("function ");
  109. sb.append(function);
  110. sb.append(" (");
  111. for(int i = 0; i < pars; i++)
  112. {
  113. sb.append("X,");
  114. }
  115. if(pars > 0)
  116. {
  117. sb.deleteCharAt(sb.length() - 1);
  118. }
  119. sb.append(")");
  120. if(jump != 0)
  121. {
  122. sb.append(" (");
  123. sb.append(jump);
  124. sb.append(")");
  125. }
  126. return sb.toString();
  127. }
  128. @Override
  129. public int compareTo(Code o)
  130. {
  131. int i = Integer.compare(line, o.line);
  132. if(i == 0)
  133. {
  134. return Integer.compare(o.subline, subline);
  135. }
  136. return i;
  137. }
  138. public int getJumpLine()
  139. {
  140. return jump;
  141. }
  142. // -----------------------------------------------------------------------------------
  143. // code builder
  144. // -----------------------------------------------------------------------------------
  145. private static SnuviParser parser = null;
  146. private static String scriptName = null;
  147. private static int sublines = 0;
  148. private static int realLines = 0;
  149. private static HashMap<String, String> strings;
  150. private static int findEndOfLine(String code, int pos)
  151. {
  152. int start = pos;
  153. int length = code.length();
  154. while(pos < length)
  155. {
  156. switch(code.charAt(pos))
  157. {
  158. case ';':
  159. case '{':
  160. case '}':
  161. return pos;
  162. }
  163. pos++;
  164. }
  165. return start;
  166. }
  167. private static int findStartOfSyntax(StringBuilder code, int pos)
  168. {
  169. int bracketCounter = 0;
  170. while(pos >= 0 && code.charAt(pos) == ' ')
  171. {
  172. pos--;
  173. }
  174. while(pos >= 0)
  175. {
  176. switch(code.charAt(pos))
  177. {
  178. case ';':
  179. case '{':
  180. case '}':
  181. if(bracketCounter != 0)
  182. {
  183. throw new PreScriptException(scriptName, code.substring(pos - 1, Math.min(code.length(), pos + 20)), "unbalanced ()");
  184. }
  185. return pos + 1;
  186. case ' ':
  187. case '+':
  188. case '-':
  189. case '*':
  190. case '/':
  191. case '^':
  192. case '@':
  193. case '=':
  194. case '>':
  195. case '<':
  196. case '!':
  197. case '%':
  198. case ',':
  199. case '&':
  200. case '|':
  201. if(bracketCounter != 0)
  202. {
  203. break;
  204. }
  205. return pos + 1;
  206. case ')':
  207. bracketCounter++;
  208. break;
  209. case '(':
  210. if(bracketCounter == 0)
  211. {
  212. return pos + 1;
  213. }
  214. bracketCounter--;
  215. break;
  216. }
  217. pos--;
  218. }
  219. return 0;
  220. }
  221. private static int findEndOfSyntax(StringBuilder code, int pos)
  222. {
  223. return findEndOfSyntax(code, pos, false);
  224. }
  225. private static int findEndOfSyntax(StringBuilder code, int pos, boolean b)
  226. {
  227. int bracketCounter = 0;
  228. char c;
  229. while(pos < code.length() && code.charAt(pos) == ' ')
  230. {
  231. pos++;
  232. }
  233. while(pos < code.length())
  234. {
  235. c = code.charAt(pos);
  236. if(b && c == '\n')
  237. {
  238. if(bracketCounter != 0)
  239. {
  240. pos++;
  241. continue;
  242. }
  243. return pos;
  244. }
  245. switch(c)
  246. {
  247. case ';':
  248. case '{':
  249. case '}':
  250. if(bracketCounter != 0)
  251. {
  252. throw new PreScriptException(scriptName, code.substring(pos - 1, Math.min(code.length(), pos + 20)), "unbalanced ()");
  253. }
  254. return pos;
  255. case ' ':
  256. case '+':
  257. case '-':
  258. case '*':
  259. case '/':
  260. case '^':
  261. case '@':
  262. case '=':
  263. case '>':
  264. case '<':
  265. case '!':
  266. case '%':
  267. case ',':
  268. case '&':
  269. case '|':
  270. if(bracketCounter != 0)
  271. {
  272. break;
  273. }
  274. return pos;
  275. case '(':
  276. bracketCounter++;
  277. break;
  278. case ')':
  279. if(bracketCounter == 0)
  280. {
  281. return pos;
  282. }
  283. bracketCounter--;
  284. break;
  285. }
  286. pos++;
  287. }
  288. return code.length();
  289. }
  290. private static int findChar(char c, StringBuilder code, int pos)
  291. {
  292. int length = code.length();
  293. while(pos < length)
  294. {
  295. if(code.charAt(pos) == c)
  296. {
  297. return pos;
  298. }
  299. pos++;
  300. }
  301. return -1;
  302. }
  303. private static int findSyntax(String find, StringBuilder code, int pos)
  304. {
  305. int length = code.length();
  306. int add = find.length() + 1;
  307. String s;
  308. while(pos < length)
  309. {
  310. s = code.substring(pos, Math.min(pos + add, length));
  311. // additionel check for e.g. difference between + and +=
  312. if(s.startsWith(find) && !s.startsWith(find + "=") && code.charAt(pos - 1) != '=')
  313. {
  314. return pos;
  315. }
  316. pos++;
  317. }
  318. return -1;
  319. }
  320. private static int findSyntaxIgnoreString(String find, StringBuilder code, int pos)
  321. {
  322. int length = code.length();
  323. int add = find.length() + 1;
  324. char c;
  325. boolean text = false;
  326. String s;
  327. while(pos < length)
  328. {
  329. c = code.charAt(pos);
  330. if(text && c != '"')
  331. {
  332. pos++;
  333. continue;
  334. }
  335. if(c == '"')
  336. {
  337. text = !text;
  338. pos++;
  339. continue;
  340. }
  341. s = code.substring(pos, Math.min(pos + add, length));
  342. // additionel check for e.g. difference between + and +=
  343. if(s.startsWith(find) && !s.startsWith(find + "=") && code.charAt(pos - 1) != '=')
  344. {
  345. return pos;
  346. }
  347. pos++;
  348. }
  349. return -1;
  350. }
  351. private static void changeBiSyntax(String syntax, String f, StringBuilder sb, boolean b)
  352. {
  353. int pos = -1;
  354. int end;
  355. int start;
  356. int slength = syntax.length();
  357. StringBuilder newSyntax;
  358. while(pos < sb.length())
  359. {
  360. pos = findSyntax(syntax, sb, pos + 1);
  361. if(pos == -1)
  362. {
  363. break;
  364. }
  365. start = findStartOfSyntax(sb, pos - 1);
  366. end = findEndOfSyntax(sb, pos + slength);
  367. newSyntax = new StringBuilder(f);
  368. newSyntax.append("(");
  369. if(b)
  370. {
  371. newSyntax.append("\"");
  372. }
  373. newSyntax.append(sb.substring(start, pos).trim());
  374. if(b)
  375. {
  376. newSyntax.append("\"");
  377. }
  378. if(end > pos)
  379. {
  380. newSyntax.append(",");
  381. newSyntax.append(sb.substring(pos + slength, end).trim());
  382. }
  383. newSyntax.append(")");
  384. pos -= end - start - newSyntax.length();
  385. //System.out.println(sb.substring(start, end) + " ===> " + newSyntax);
  386. sb.replace(start, end, newSyntax.toString());
  387. }
  388. }
  389. private static void changeUnSyntax(String syntax, String f, StringBuilder sb)
  390. {
  391. int pos = -1;
  392. int end;
  393. int start;
  394. int slength = syntax.length();
  395. String first;
  396. StringBuilder newSyntax;
  397. while(pos < sb.length())
  398. {
  399. pos = findSyntax(syntax, sb, pos + 1);
  400. if(pos == -1)
  401. {
  402. break;
  403. }
  404. start = findStartOfSyntax(sb, pos - 1);
  405. end = findEndOfSyntax(sb, pos + slength);
  406. newSyntax = new StringBuilder("setvar(\"");
  407. first = sb.substring(start, pos).trim();
  408. newSyntax.append(first);
  409. newSyntax.append("\",");
  410. newSyntax.append(f);
  411. newSyntax.append("(");
  412. newSyntax.append(first);
  413. newSyntax.append(",");
  414. newSyntax.append(sb.substring(pos + slength, end).trim());
  415. newSyntax.append("))");
  416. pos -= end - start - newSyntax.length();
  417. sb.replace(start, end, newSyntax.toString());
  418. }
  419. }
  420. private static String replaceChar(char find, char replacement, String code)
  421. {
  422. return code.replace(find, replacement);
  423. }
  424. private static int countChar(char find, String code)
  425. {
  426. int counter = 0;
  427. int pos = 0;
  428. while(pos < code.length())
  429. {
  430. if(code.charAt(pos) == find)
  431. {
  432. counter++;
  433. }
  434. pos++;
  435. }
  436. return counter;
  437. }
  438. private static void addKeyWordBrackets(String keyWord, StringBuilder sb)
  439. {
  440. String with = keyWord + "()";
  441. int length = keyWord.length();
  442. int pos = 0;
  443. while(true)
  444. {
  445. pos = findSyntax(keyWord, sb, pos);
  446. if(pos == -1)
  447. {
  448. break;
  449. }
  450. if(pos >= 1 && Character.isLetter(sb.charAt(pos - 1)))
  451. {
  452. pos += length;
  453. continue;
  454. }
  455. if(pos + length < sb.length() && Character.isLetter(sb.charAt(pos + length)))
  456. {
  457. pos += length;
  458. continue;
  459. }
  460. if(!sb.substring(pos).startsWith(with))
  461. {
  462. sb.replace(pos, pos + length, with);
  463. }
  464. pos += length;
  465. }
  466. }
  467. public static Code[] generate(SnuviParser parser, String scriptName, String code, HashMap<String, Integer> gotos)
  468. {
  469. System.out.println("START GENERATE");
  470. long startTime = System.currentTimeMillis();
  471. Code.scriptName = scriptName;
  472. Code.parser = parser;
  473. // comments
  474. int old = 0;
  475. int pos;
  476. StringBuilder sb = new StringBuilder(code);
  477. while(true)
  478. {
  479. old = findSyntaxIgnoreString("/*", sb, old);
  480. if(old == -1)
  481. {
  482. break;
  483. }
  484. pos = findSyntaxIgnoreString("*/", sb, old);
  485. if(pos == -1)
  486. {
  487. throw new PreScriptException(scriptName, sb.substring(old, Math.min(old + 20, sb.length())), "/* without */");
  488. }
  489. sb.delete(old, pos + 2);
  490. }
  491. old = 0;
  492. while(true)
  493. {
  494. old = findSyntaxIgnoreString("//", sb, old);
  495. if(old == -1)
  496. {
  497. break;
  498. }
  499. pos = findSyntaxIgnoreString("\n", sb, old);
  500. if(pos == -1)
  501. {
  502. sb.delete(old, sb.length());
  503. break;
  504. }
  505. sb.delete(old, pos + 1);
  506. }
  507. // end comments
  508. // replacing Strings with #... to get rid of "
  509. pos = 0;
  510. String text;
  511. String replacement;
  512. int stringIndex = 0;
  513. strings = new HashMap<>();
  514. while(pos < sb.length())
  515. {
  516. if(sb.charAt(pos) == '"')
  517. {
  518. old = pos;
  519. pos++;
  520. while(sb.charAt(pos) != '"')
  521. {
  522. if(pos >= sb.length())
  523. {
  524. throw new PreScriptException(scriptName, sb.substring(old, Math.min(old + 20, sb.length())), "\" without another");
  525. }
  526. pos++;
  527. }
  528. pos++;
  529. text = sb.substring(old, pos);
  530. //System.out.println("Found String: " + text);
  531. replacement = "#" + stringIndex;
  532. sb.replace(old, pos, replacement);
  533. strings.put(replacement, text);
  534. stringIndex++;
  535. pos -= (pos - old) - replacement.length();
  536. }
  537. pos++;
  538. }
  539. // end of string replacing
  540. // allowing labels without ;
  541. old = 0;
  542. while(true)
  543. {
  544. pos = findChar('@', sb, old);
  545. if(pos == -1)
  546. {
  547. break;
  548. }
  549. pos++;
  550. old = pos;
  551. pos = findEndOfSyntax(sb, pos, true);
  552. if(pos == -1)
  553. {
  554. break;
  555. }
  556. if(sb.charAt(pos) != ';')
  557. {
  558. sb.insert(pos, ';');
  559. }
  560. }
  561. // key words without ()
  562. addKeyWordBrackets("else", sb);
  563. addKeyWordBrackets("try", sb);
  564. addKeyWordBrackets("catch", sb);
  565. //System.out.println(sb);
  566. // end key words
  567. // replacing of function syntax
  568. changeBiSyntax("^", "math.pow", sb, false);
  569. changeBiSyntax("/", "div", sb, false);
  570. changeBiSyntax("%", "math.mod", sb, false);
  571. changeBiSyntax("*", "mul", sb, false);
  572. changeBiSyntax("-", "sub", sb, false);
  573. changeBiSyntax("+", "add", sb, false);
  574. changeBiSyntax("==", "equal", sb, false);
  575. changeBiSyntax("!=", "notequal", sb, false);
  576. changeBiSyntax("<", "less", sb, false);
  577. changeBiSyntax(">", "greater", sb, false);
  578. changeBiSyntax(">=", "greaterequal", sb, false);
  579. changeBiSyntax("<=", "lessequal", sb, false);
  580. changeBiSyntax("||", "or", sb, false);
  581. changeBiSyntax("&&", "and", sb, false);
  582. changeUnSyntax("+=", "add", sb);
  583. changeUnSyntax("-=", "sub", sb);
  584. changeUnSyntax("/=", "div", sb);
  585. changeUnSyntax("*=", "mul", sb);
  586. changeBiSyntax("=", "setvar", sb, true);
  587. // numbers like -5 turn to sub(,5) --> fixing
  588. pos = 0;
  589. while(true)
  590. {
  591. pos = findSyntax("sub(,", sb, pos);
  592. if(pos == -1)
  593. {
  594. break;
  595. }
  596. sb.insert(pos + 4, '0');
  597. pos++;
  598. }
  599. code = sb.toString();
  600. //System.out.println(code);
  601. // end of substitution
  602. // split code into lines
  603. // tree for sorting and inserting of code
  604. TreeSet<Code> tree = new TreeSet();
  605. sublines = 0;
  606. realLines = 1;
  607. String actual;
  608. int length = code.length();
  609. int level = 1;
  610. pos = 0;
  611. int line = 0;
  612. while(pos < length)
  613. {
  614. old = pos;
  615. pos = findEndOfLine(code, pos);
  616. actual = code.substring(old, pos);
  617. //System.out.println(actual);
  618. realLines += countChar('\n', actual);
  619. actual = actual.trim();
  620. if(actual.startsWith("@"))
  621. {
  622. // sets the right layer of the goto, the exact position is set later
  623. if(gotos.put(actual.substring(1), line) != null)
  624. {
  625. throw new PreScriptException(scriptName, realLines, code.substring(old, Math.min(code.length(), pos + 20)), "double goto");
  626. }
  627. pos++;
  628. continue;
  629. }
  630. switch(code.charAt(pos))
  631. {
  632. case '{':
  633. line++;
  634. splitFunctions(tree, actual, level, line);
  635. level++;
  636. break;
  637. case '}':
  638. level--;
  639. line++;
  640. sublines++;
  641. tree.add(new Code("gotoline", level, 0, line, sublines, realLines));
  642. break;
  643. case ';':
  644. line++;
  645. splitFunctions(tree, actual, level, line);
  646. break;
  647. }
  648. pos++;
  649. }
  650. // end of code splitting
  651. Code[] c = tree.toArray(new Code[tree.size()]);
  652. // generating gotos of key words
  653. String function;
  654. int baseLevel;
  655. boolean gotoLine = false;
  656. int lastLineChange = 0;
  657. line = 0;
  658. for(int i = 0; i < c.length; i++)
  659. {
  660. function = c[i].function;
  661. if(c[i].line != line)
  662. {
  663. line = c[i].line;
  664. lastLineChange = i;
  665. }
  666. if(function == null)
  667. {
  668. continue;
  669. }
  670. switch(function)
  671. {
  672. case "if":
  673. case "else":
  674. case "try":
  675. case "catch":
  676. break;
  677. case "while":
  678. gotoLine = true;
  679. break;
  680. default:
  681. continue;
  682. }
  683. baseLevel = c[i].level;
  684. for(int j = i + 1; j < c.length; j++)
  685. {
  686. if(c[j].level <= baseLevel)
  687. {
  688. c[i].jump = j - i; // key word pos - end pos = jump
  689. if(gotoLine)
  690. {
  691. // setting right jump for gotoline of loops
  692. gotoLine = false;
  693. c[j].jump = lastLineChange - j - 1;
  694. }
  695. break;
  696. }
  697. }
  698. }
  699. // end of key word jumps
  700. // end
  701. //java.util.Arrays.stream(c).forEach(co -> System.out.println(co.toString()));
  702. //gotos.forEach((k, v) -> System.out.println(k + " " + v));
  703. System.out.println("END GENERATE - " + (System.currentTimeMillis() - startTime));
  704. //System.exit(0);
  705. return c;
  706. }
  707. private static int findOpenBracket(String code, int pos)
  708. {
  709. int length = code.length();
  710. char c;
  711. boolean text = false;
  712. while(pos < length)
  713. {
  714. c = code.charAt(pos);
  715. if(text && c != '"')
  716. {
  717. pos++;
  718. continue;
  719. }
  720. switch(c)
  721. {
  722. case '(':
  723. return pos;
  724. case '"':
  725. text = !text;
  726. break;
  727. }
  728. pos++;
  729. }
  730. return -1;
  731. }
  732. private static int findClosingBracket(String code, int pos)
  733. {
  734. if(pos == -1)
  735. {
  736. pos++;
  737. }
  738. int length = code.length();
  739. char c;
  740. boolean text = false;
  741. int brackets = 0;
  742. while(pos < length)
  743. {
  744. c = code.charAt(pos);
  745. if(text && c != '"')
  746. {
  747. pos++;
  748. continue;
  749. }
  750. switch(c)
  751. {
  752. case '(':
  753. brackets++;
  754. break;
  755. case ')':
  756. brackets--;
  757. if(brackets == 0)
  758. {
  759. return pos;
  760. }
  761. break;
  762. case '"':
  763. text = !text;
  764. break;
  765. }
  766. pos++;
  767. }
  768. return -1;
  769. }
  770. private static ArrayList<String> splitComma(String code)
  771. {
  772. ArrayList<String> list = new ArrayList<>();
  773. int length = code.length();
  774. int pos = 0;
  775. int old = 0;
  776. int brackets = 0;
  777. char c;
  778. boolean text = false;
  779. while(pos < length)
  780. {
  781. c = code.charAt(pos);
  782. if(text && c != '"')
  783. {
  784. pos++;
  785. continue;
  786. }
  787. switch(c)
  788. {
  789. case '"':
  790. text = !text;
  791. break;
  792. case '(':
  793. brackets++;
  794. break;
  795. case ')':
  796. brackets--;
  797. break;
  798. case ',':
  799. if(brackets == 0)
  800. {
  801. list.add(code.substring(old, pos));
  802. old = pos + 1;
  803. }
  804. break;
  805. }
  806. pos++;
  807. }
  808. if(old < pos)
  809. {
  810. list.add(code.substring(old, pos));
  811. }
  812. return list;
  813. }
  814. private static void splitFunctions(TreeSet<Code> tree, String f, int level, int line)
  815. {
  816. f = f.trim();
  817. sublines++;
  818. int start = findOpenBracket(f, 0);
  819. int end = findClosingBracket(f, start);
  820. if((start != -1 || end != -1) &&
  821. (((start == -1 || end == -1) && start != end) || end != f.length() - 1))
  822. {
  823. throw new PreScriptException(scriptName, realLines, f, "unbalanced ()");
  824. }
  825. if(start == -1)
  826. {
  827. tree.add(new Code(level, 0, line, sublines, convertInput(f, true), realLines));
  828. return;
  829. }
  830. else if(start >= end - 1)
  831. {
  832. String functionName = f.substring(0, start).trim().toLowerCase();
  833. if(!parser.isRegisteredFunction(functionName))
  834. {
  835. throw new NoSuchMethodException(scriptName, realLines, f, functionName);
  836. }
  837. tree.add(new Code(functionName, level, 0, line, sublines, realLines));
  838. return;
  839. }
  840. ArrayList<String> splitted = splitComma(f.substring(start + 1, end));
  841. String functionName = f.substring(0, start).trim().toLowerCase();
  842. if(!parser.isRegisteredFunction(functionName))
  843. {
  844. throw new NoSuchMethodException(scriptName, realLines, f, functionName);
  845. }
  846. tree.add(new Code(functionName, level, splitted.size(), line, sublines, realLines));
  847. splitted.forEach(s -> splitFunctions(tree, s, level, line));
  848. }
  849. public static Object convertInput(String s, boolean variable)
  850. {
  851. if(s == null)
  852. {
  853. return null;
  854. }
  855. s = s.trim();
  856. if(s.length() == 0)
  857. {
  858. return "";
  859. }
  860. if(s.charAt(0) == '"' && s.charAt(s.length() - 1) == '"')
  861. {
  862. if(s.length() == 1)
  863. {
  864. return "\"";
  865. }
  866. else if(s.charAt(1) == '$')
  867. {
  868. return s.substring(2, s.length() - 1);
  869. }
  870. return s.substring(1, s.length() - 1);
  871. }
  872. else if(s.startsWith("#"))
  873. {
  874. return convertInput(strings.get(s), variable);
  875. }
  876. else if(s.equals("true"))
  877. {
  878. return true;
  879. }
  880. else if(s.equals("false"))
  881. {
  882. return false;
  883. }
  884. else if(s.equals("null"))
  885. {
  886. return null;
  887. }
  888. try
  889. {
  890. return Double.parseDouble(s);
  891. }
  892. catch(NumberFormatException ex)
  893. {
  894. if(variable)
  895. {
  896. return new Variable(s);
  897. }
  898. return s;
  899. }
  900. }
  901. }