Compiler.java 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. package me.hammerle.snuviscript.code;
  2. import java.util.HashMap;
  3. import java.util.LinkedList;
  4. import java.util.List;
  5. import java.util.Stack;
  6. import me.hammerle.snuviscript.constants.ConstantDouble;
  7. import me.hammerle.snuviscript.constants.ConstantNull;
  8. import me.hammerle.snuviscript.constants.ConstantString;
  9. import me.hammerle.snuviscript.array.DynamicArray;
  10. import me.hammerle.snuviscript.constants.ConstantBoolean;
  11. import me.hammerle.snuviscript.variable.ArrayVariable;
  12. import me.hammerle.snuviscript.variable.LocalArrayVariable;
  13. import me.hammerle.snuviscript.variable.LocalVariable;
  14. import me.hammerle.snuviscript.variable.Variable;
  15. import me.hammerle.snuviscript.exceptions.PreScriptException;
  16. public class Compiler
  17. {
  18. public static Instruction[] compile(
  19. Script sc, List<String> sCode, HashMap<String, Integer> labels,
  20. HashMap<String, Integer> functions, HashMap<String, HashMap<String, Integer>> localLabels)
  21. {
  22. Compiler compiler = new Compiler(sCode, labels, functions, localLabels);
  23. Instruction[] instructions = compiler.compile();
  24. sc.vars = compiler.vars;
  25. return instructions;
  26. }
  27. private final List<String> sCode;
  28. private final HashMap<String, Variable> vars = new HashMap<>();
  29. private final HashMap<String, Integer> labels;
  30. private final HashMap<String, Variable> localVars = new HashMap<>();
  31. private final HashMap<String, Integer> functions;
  32. private final HashMap<String, HashMap<String, Integer>> localLabels;
  33. private String currentFunction = null;
  34. private final LinkedList<Instruction> code = new LinkedList<>();;
  35. private int line = 0;
  36. private int layer = 0;
  37. private JumpData tryState = null;
  38. private class JumpWrapper
  39. {
  40. private final JumpData data;
  41. private final String function;
  42. public JumpWrapper(JumpData data, String function)
  43. {
  44. this.data = data;
  45. this.function = function;
  46. }
  47. }
  48. private final Stack<JumpWrapper> jumps = new Stack<>();
  49. private final Stack<JumpWrapper> loopJumps = new Stack<>();
  50. private final LinkedList<JumpData> breakContinueJumps = new LinkedList<>();
  51. private final HashMap<String, String> strings = new HashMap<>();
  52. private int stringCounter = 0;
  53. private Compiler(List<String> sCode, HashMap<String, Integer> labels,
  54. HashMap<String, Integer> functions, HashMap<String, HashMap<String, Integer>> localLabels)
  55. {
  56. this.sCode = sCode;
  57. this.labels = labels;
  58. this.functions = functions;
  59. this.localLabels = localLabels;
  60. }
  61. private void addCodeInstruction(String function, InputProvider[] input)
  62. {
  63. code.add(new Instruction(line + 1, (byte) layer, new Function(FunctionLoader.getFunction(function), input)));
  64. }
  65. private void addLabel(String name, int line)
  66. {
  67. if(currentFunction != null)
  68. {
  69. HashMap<String, Integer> map = localLabels.get(currentFunction);
  70. if(map.put(name, line) != null)
  71. {
  72. throw new PreScriptException("label duplicate", line);
  73. }
  74. }
  75. else if(labels.put(name, line) != null)
  76. {
  77. throw new PreScriptException("label duplicate", line);
  78. }
  79. }
  80. private Instruction[] compile()
  81. {
  82. int size = sCode.size();
  83. //System.out.println("__________________________________");
  84. StringBuilder sb = new StringBuilder();
  85. String replacement;
  86. String check;
  87. int pos;
  88. int old = 0;
  89. boolean text = false;
  90. boolean comment = false;
  91. int labelIndex;
  92. for(line = 0; line < size; line++)
  93. {
  94. pos = sb.length();
  95. sb.append(sCode.get(line));
  96. while(pos < sb.length())
  97. {
  98. if(comment)
  99. {
  100. if(pos + 1 < sb.length() && sb.charAt(pos) == '*' && sb.charAt(pos + 1) == '/')
  101. {
  102. comment = false;
  103. sb.delete(old, pos + 2);
  104. }
  105. pos++;
  106. continue;
  107. }
  108. else if(text)
  109. {
  110. if(sb.charAt(pos) == '"')
  111. {
  112. replacement = "#" + stringCounter++;
  113. strings.put(replacement, sb.substring(old, pos + 1));
  114. text = false;
  115. sb.replace(old, pos + 1, replacement);
  116. pos = old - 1 + replacement.length();
  117. }
  118. pos++;
  119. continue;
  120. }
  121. switch(sb.charAt(pos))
  122. {
  123. case '/':
  124. if(pos + 1 < sb.length())
  125. {
  126. switch(sb.charAt(pos + 1))
  127. {
  128. case '/':
  129. sb.delete(pos, sb.length());
  130. break;
  131. case '*':
  132. comment = true;
  133. old = pos;
  134. pos++;
  135. break;
  136. }
  137. }
  138. break;
  139. case '}':
  140. sb.delete(0, pos + 1);
  141. pos = -1;
  142. layer--;
  143. if(jumps.isEmpty())
  144. {
  145. throw new PreScriptException("} without a corresponding function and / or {", line);
  146. }
  147. JumpWrapper data = jumps.pop();
  148. switch(data.function)
  149. {
  150. case "function":
  151. {
  152. data.data.setRelativeJump(code.size() + 1);
  153. currentFunction = null;
  154. layer++;
  155. addCodeInstruction("return", new InputProvider[] {});
  156. layer--;
  157. break;
  158. }
  159. case "try":
  160. {
  161. tryState = data.data;
  162. break;
  163. }
  164. case "catch":
  165. {
  166. data.data.setRelativeJump(code.size());
  167. break;
  168. }
  169. case "else":
  170. case "elseif":
  171. case "if":
  172. {
  173. data.data.setRelativeJump(code.size() + 1);
  174. addCodeInstruction("endif", new InputProvider[] {});
  175. break;
  176. }
  177. case "for":
  178. {
  179. loopJumps.pop();
  180. createBreakContinue(code.size());
  181. JumpData jump = data.data;
  182. jump.setRelativeJump(code.size());
  183. addCodeInstruction("next", new InputProvider[] {new JumpData(-jump.getInt(null) - 1)});
  184. break;
  185. }
  186. case "while":
  187. {
  188. loopJumps.pop();
  189. createBreakContinue(code.size());
  190. JumpData jump = data.data;
  191. jump.setRelativeJump(code.size() + 1);
  192. addCodeInstruction("wend", new InputProvider[] {new JumpData(-jump.getInt(null) - 1)});
  193. break;
  194. }
  195. }
  196. break;
  197. case '{':
  198. int currentJumps = jumps.size();
  199. check = sb.toString();
  200. if(check.startsWith("function "))
  201. {
  202. if(currentFunction != null)
  203. {
  204. throw new PreScriptException("function not allowed in another function", line);
  205. }
  206. int index = check.indexOf("(");
  207. if(index == -1)
  208. {
  209. throw new PreScriptException("missing function syntax", line);
  210. }
  211. currentFunction = check.substring(9, index).toLowerCase();
  212. functions.put(currentFunction, code.size());
  213. localLabels.put(currentFunction, new HashMap<>());
  214. int endIndex = check.indexOf(")", index);
  215. if(index == -1)
  216. {
  217. throw new PreScriptException("missing function syntax", line);
  218. }
  219. String[] inputs;
  220. if(index + 1 == endIndex)
  221. {
  222. inputs = new String[0];
  223. }
  224. else
  225. {
  226. inputs = check.substring(index + 1, endIndex).split("[ ]*,[ ]*");
  227. }
  228. InputProvider[] in = new InputProvider[inputs.length + 1];
  229. for(int i = 1; i < in.length; i++)
  230. {
  231. in[i] = new ConstantString(inputs[i - 1]);
  232. }
  233. JumpData jump = new JumpData(code.size());
  234. in[0] = jump;
  235. jumps.add(new JumpWrapper(jump, "function"));
  236. addCodeInstruction("function", in);
  237. pos = endIndex + 1;
  238. boolean b = true;
  239. while(b)
  240. {
  241. switch(sb.charAt(pos))
  242. {
  243. case '{':
  244. b = false;
  245. break;
  246. case '\n':
  247. case ' ':
  248. break;
  249. default:
  250. throw new PreScriptException("invalid character between function and {", line);
  251. }
  252. pos++;
  253. }
  254. layer++;
  255. sb.delete(0, pos);
  256. }
  257. else
  258. {
  259. check = sb.substring(0, pos);
  260. compileLine(check);
  261. sb.delete(0, pos + 1);
  262. layer++;
  263. if(currentJumps == jumps.size())
  264. {
  265. throw new PreScriptException("{ without a corresponding function", line);
  266. }
  267. }
  268. pos = -1;
  269. break;
  270. case ';':
  271. compileLine(sb.substring(0, pos).trim());
  272. sb.delete(0, pos + 1);
  273. pos = -1;
  274. break;
  275. case '"':
  276. text = true;
  277. old = pos;
  278. break;
  279. }
  280. pos++;
  281. }
  282. if(!text && !comment)
  283. {
  284. labelIndex = sb.indexOf("@");
  285. if(labelIndex != -1)
  286. {
  287. String label = sb.toString().trim();
  288. if(label.charAt(0) != '@')
  289. {
  290. throw new PreScriptException("you seriously fucked up the syntax here", line);
  291. }
  292. addLabel(label.substring(1), code.size() - 1);
  293. sb = new StringBuilder();
  294. }
  295. }
  296. }
  297. //System.out.println("__________________________________");
  298. Instruction[] input = code.toArray(new Instruction[code.size()]);
  299. /*for(Instruction in : input)
  300. {
  301. System.out.println(in);
  302. }
  303. System.out.println("__________________________________");*/
  304. /*labels.entrySet().stream().forEach((e) ->
  305. {
  306. System.out.println("LABEL " + e.getKey() + " " + e.getValue());
  307. });*/
  308. //System.out.println("__________________________________");
  309. return input;
  310. }
  311. private void compileLine(String currentCode)
  312. {
  313. //System.out.println(">>>" + currentCode);
  314. String[] parts = SnuviUtils.split(strings, currentCode, line);
  315. //System.out.println(">>> " + String.join("_", parts));
  316. if(tryState != null)
  317. {
  318. switch(parts.length)
  319. {
  320. case 0: return;
  321. case 1:
  322. if(!parts[0].equals("catch"))
  323. {
  324. throw new PreScriptException("no catch after try", line);
  325. }
  326. if(tryState == null)
  327. {
  328. throw new PreScriptException("catch without try", line);
  329. }
  330. tryState.setRelativeJump(code.size());
  331. JumpData jump = new JumpData(code.size());
  332. addCodeInstruction("catch", new InputProvider[] {jump});
  333. jumps.push(new JumpWrapper(jump, "catch"));
  334. tryState = null;
  335. return;
  336. default:
  337. throw new PreScriptException("invalid catch after try", line);
  338. }
  339. }
  340. if(parts.length == 0)
  341. {
  342. return;
  343. }
  344. else if(parts[0].equals("return"))
  345. {
  346. addCodeInstruction("return", compileFunction(parts, true));
  347. return;
  348. }
  349. else if(parts[0].startsWith("@"))
  350. {
  351. if(parts.length > 1)
  352. {
  353. throw new PreScriptException("arguments after label", line);
  354. }
  355. addLabel(parts[0].substring(1), code.size() - 1);
  356. return;
  357. }
  358. String input;
  359. if(parts.length == 1)
  360. {
  361. int bPos = parts[0].indexOf('(');
  362. if(bPos != -1)
  363. {
  364. input = parts[0].substring(0, bPos);
  365. parts = SnuviUtils.split(strings, parts[0].substring(bPos + 1, parts[0].length() - 1), line);
  366. }
  367. else
  368. {
  369. switch(parts[0])
  370. {
  371. case "try":
  372. {
  373. JumpData jump = new JumpData(code.size());
  374. addCodeInstruction("try", new InputProvider[] {jump});
  375. jumps.push(new JumpWrapper(jump, "try"));
  376. return;
  377. }
  378. case "else":
  379. {
  380. JumpData jump = new JumpData(code.size());
  381. addCodeInstruction("else", new InputProvider[] {jump});
  382. jumps.push(new JumpWrapper(jump, "else"));
  383. return;
  384. }
  385. case "while":
  386. throw new PreScriptException("missing syntax at while", line);
  387. case "if":
  388. throw new PreScriptException("missing syntax at if", line);
  389. case "elseif":
  390. throw new PreScriptException("missing syntax at elseif", line);
  391. case "for":
  392. throw new PreScriptException("missing syntax at for", line);
  393. case "break":
  394. {
  395. if(loopJumps.isEmpty())
  396. {
  397. throw new PreScriptException("break without a loop", line);
  398. }
  399. JumpData jump = new JumpData(code.size() - 1);
  400. breakContinueJumps.add(jump);
  401. addCodeInstruction("break", new InputProvider[] {jump});
  402. return;
  403. }
  404. case "continue":
  405. {
  406. if(loopJumps.isEmpty())
  407. {
  408. throw new PreScriptException("continue without a loop", line);
  409. }
  410. JumpData jump = new JumpData(code.size());
  411. breakContinueJumps.add(jump);
  412. addCodeInstruction("continue", new InputProvider[] {jump});
  413. return;
  414. }
  415. }
  416. return;
  417. }
  418. }
  419. else
  420. {
  421. switch(parts[0])
  422. {
  423. case "++":
  424. addCodeInstruction("p+", compileFunction(new String[] {parts[1]}, false));
  425. return;
  426. case "--":
  427. addCodeInstruction("p-", compileFunction(new String[] {parts[1]}, false));
  428. return;
  429. }
  430. switch(parts[1])
  431. {
  432. case "++":
  433. case "--":
  434. input = parts[1];
  435. parts = new String[] {parts[0]};
  436. break;
  437. case "=":
  438. case "+=":
  439. case "-=":
  440. case "*=":
  441. case "/=":
  442. case "%=":
  443. case "<<=":
  444. case ">>=":
  445. case "&=":
  446. case "^=":
  447. case "|=":
  448. {
  449. input = parts[1];
  450. parts[1] = ",";
  451. break;
  452. }
  453. default:
  454. throw new PreScriptException("unknown operation " + parts[1], line);
  455. }
  456. }
  457. switch(input)
  458. {
  459. case "break":
  460. throw new PreScriptException("break does not accept arguments", line);
  461. case "continue":
  462. throw new PreScriptException("continue does not accept arguments", line);
  463. }
  464. //System.out.println(input + " " + String.join("__", parts));
  465. switch(input)
  466. {
  467. case "elseif":
  468. createIf("elseif", parts);
  469. break;
  470. case "if":
  471. createIf("if", parts);
  472. break;
  473. case "for":
  474. createFor(parts);
  475. break;
  476. case "while":
  477. createWhile(parts);
  478. break;
  479. default:
  480. addCodeInstruction(input, compileFunction(parts, false));
  481. }
  482. }
  483. private void addSyntax(LinkedList<InputProvider> list, Syntax sy)
  484. {
  485. int pars = sy.getParameters();
  486. if(pars > list.size())
  487. {
  488. throw new PreScriptException("missing syntax argument", line);
  489. }
  490. if(sy == Syntax.UNARY_SUB)
  491. {
  492. list.add(new SignInverter(list.pollLast()));
  493. return;
  494. }
  495. InputProvider[] input = new InputProvider[pars];
  496. for(int j = input.length - 1; j >= 0; j--)
  497. {
  498. input[j] = list.pollLast();
  499. }
  500. list.add(new Function(FunctionLoader.getFunction(sy.getFunction()), input));
  501. }
  502. private void validateStackCounter(int stackCounter)
  503. {
  504. if(stackCounter < 0)
  505. {
  506. throw new PreScriptException("missing syntax argument", line);
  507. }
  508. }
  509. private InputProvider[] compileFunction(String[] parts, boolean first)
  510. {
  511. LinkedList<InputProvider> list = new LinkedList<>();
  512. int stackCounter = 0;
  513. Stack<Syntax> syntax = new Stack<>();
  514. int bottom = first ? 1 : 0;
  515. Syntax sy;
  516. for(int i = bottom; i < parts.length; i++)
  517. {
  518. if(parts[i].equals(","))
  519. {
  520. // finding a comma means pushing all syntax functions
  521. while(!syntax.isEmpty())
  522. {
  523. addSyntax(list, syntax.pop());
  524. }
  525. stackCounter = 0;
  526. continue;
  527. }
  528. sy = Syntax.getSyntax(parts[i]);
  529. if(sy != Syntax.UNKNOWN)
  530. {
  531. if(stackCounter <= 0)
  532. {
  533. switch(sy)
  534. {
  535. case INVERT:
  536. break;
  537. case BIT_INVERT:
  538. break;
  539. case SUB:
  540. sy = Syntax.UNARY_SUB;
  541. break;
  542. case POST_INC:
  543. sy = Syntax.INC;
  544. break;
  545. case POST_DEC:
  546. sy = Syntax.DEC;
  547. break;
  548. default:
  549. throw new PreScriptException("missing syntax argument", line);
  550. }
  551. }
  552. else
  553. {
  554. switch(sy)
  555. {
  556. case INVERT:
  557. case BIT_INVERT:
  558. throw new PreScriptException("missing syntax argument", line);
  559. }
  560. }
  561. // pushing weaker functions
  562. int weight = sy.getWeight();
  563. while(!syntax.isEmpty() && syntax.peek().getWeight() <= weight)
  564. {
  565. addSyntax(list, syntax.pop());
  566. }
  567. validateStackCounter(stackCounter);
  568. syntax.add(sy);
  569. stackCounter -= sy.getParameters() - 1;
  570. continue;
  571. }
  572. stackCounter++;
  573. list.add(convertString(parts[i]));
  574. }
  575. // pushing left over syntax functions because no comma happened
  576. while(!syntax.isEmpty())
  577. {
  578. addSyntax(list, syntax.pop());
  579. }
  580. validateStackCounter(stackCounter);
  581. return list.toArray(new InputProvider[list.size()]);
  582. }
  583. private InputProvider convertString(String input)
  584. {
  585. if(input.startsWith("@"))
  586. {
  587. return new ConstantString(input.substring(1));
  588. }
  589. else if(input.startsWith("\"") && input.endsWith("\""))
  590. {
  591. return new ConstantString(input.substring(1, input.length() - 1));
  592. }
  593. else if(input.equals("true"))
  594. {
  595. return ConstantBoolean.TRUE;
  596. }
  597. else if(input.equals("false"))
  598. {
  599. return ConstantBoolean.FALSE;
  600. }
  601. else if(input.equals("null"))
  602. {
  603. return ConstantNull.NULL;
  604. }
  605. else if(SnuviUtils.isNumber(input))
  606. {
  607. return new ConstantDouble(Double.parseDouble(input));
  608. }
  609. else if(SnuviUtils.isFunction(input))
  610. {
  611. int bPos = input.indexOf('(');
  612. String[] parts = SnuviUtils.split(strings, input.substring(bPos + 1, input.length() - 1), line);
  613. if(parts.length > 0)
  614. {
  615. return new Function(FunctionLoader.getFunction(input.substring(0, bPos)), compileFunction(parts, false));
  616. }
  617. else
  618. {
  619. return new Function(FunctionLoader.getFunction(input.substring(0, bPos)), new InputProvider[0]);
  620. }
  621. }
  622. else if(SnuviUtils.isArray(input))
  623. {
  624. int bPos = input.indexOf('[');
  625. String[] parts = SnuviUtils.split(strings, input.substring(bPos + 1, input.length() - 1), line);
  626. if(parts.length > 0)
  627. {
  628. return createArray(input.substring(0, bPos), compileFunction(parts, false));
  629. }
  630. else
  631. {
  632. return createArray(input.substring(0, bPos), new InputProvider[0]);
  633. }
  634. }
  635. else
  636. {
  637. return getOrCreateVariable(input);
  638. }
  639. }
  640. public static Object convert(String input)
  641. {
  642. if(input == null)
  643. {
  644. return null;
  645. }
  646. input = input.trim();
  647. if(input.equals("true"))
  648. {
  649. return true;
  650. }
  651. else if(input.equals("false"))
  652. {
  653. return false;
  654. }
  655. else if(input.equals("null"))
  656. {
  657. return null;
  658. }
  659. else if(input.startsWith("\"") && input.endsWith("\""))
  660. {
  661. if(input.length() == 1)
  662. {
  663. return "\"";
  664. }
  665. return input.substring(1, input.length() - 1);
  666. }
  667. try
  668. {
  669. return Double.parseDouble(input);
  670. }
  671. catch(NumberFormatException ex)
  672. {
  673. return input;
  674. }
  675. }
  676. private Variable getOrCreateVariable(String var)
  677. {
  678. if(currentFunction != null && var.charAt(0) != '$')
  679. {
  680. Variable oldVar = localVars.get(var);
  681. if(oldVar == null)
  682. {
  683. oldVar = new LocalVariable(var);
  684. localVars.put(var, oldVar);
  685. }
  686. return oldVar;
  687. }
  688. else
  689. {
  690. if(var.charAt(0) == '$')
  691. {
  692. var = var.substring(1);
  693. }
  694. Variable oldVar = vars.get(var);
  695. if(oldVar == null)
  696. {
  697. oldVar = new Variable(var);
  698. vars.put(var, oldVar);
  699. }
  700. return oldVar;
  701. }
  702. }
  703. private DynamicArray createArray(String var, InputProvider[] in)
  704. {
  705. if(currentFunction != null)
  706. {
  707. Variable oldVar = localVars.get(var);
  708. if(oldVar == null)
  709. {
  710. oldVar = new LocalArrayVariable(var);
  711. localVars.put(var, oldVar);
  712. }
  713. return new DynamicArray(oldVar, in);
  714. }
  715. else
  716. {
  717. Variable oldVar = vars.get(var);
  718. if(oldVar == null)
  719. {
  720. oldVar = new ArrayVariable(var);
  721. vars.put(var, oldVar);
  722. }
  723. return new DynamicArray(oldVar, in);
  724. }
  725. }
  726. private void createIf(String name, String[] parts)
  727. {
  728. InputProvider[] input = compileFunction(parts, false);
  729. InputProvider[] realInput = new InputProvider[input.length + 1];
  730. System.arraycopy(input, 0, realInput, 0, input.length);
  731. JumpData jump = new JumpData(code.size());
  732. realInput[input.length] = jump;
  733. jumps.push(new JumpWrapper(jump, name));
  734. addCodeInstruction(name, realInput);
  735. }
  736. private void createFor(String[] parts)
  737. {
  738. // expected syntax
  739. // for(var, start, end, step)
  740. // for(var, start, end)
  741. InputProvider[] input = compileFunction(parts, false);
  742. if(input.length != 3 && input.length != 4)
  743. {
  744. throw new PreScriptException("missing 'for' syntax at", line);
  745. }
  746. InputProvider[] realInput = new InputProvider[5];
  747. System.arraycopy(input, 0, realInput, 0, input.length);
  748. if(input.length == 3)
  749. {
  750. realInput[3] = new ConstantDouble(1.0);
  751. }
  752. JumpData jump = new JumpData(code.size());
  753. realInput[4] = jump;
  754. JumpWrapper wrapper = new JumpWrapper(jump, "for");
  755. jumps.push(wrapper);
  756. loopJumps.push(wrapper);
  757. addCodeInstruction("for", realInput);
  758. }
  759. private void createWhile(String[] parts)
  760. {
  761. // expected syntax
  762. // while(condition)
  763. InputProvider[] input = compileFunction(parts, false);
  764. if(input.length != 1)
  765. {
  766. throw new PreScriptException("invalid conditions at 'while'", line);
  767. }
  768. InputProvider[] realInput = new InputProvider[2];
  769. realInput[0] = input[0];
  770. JumpData jump = new JumpData(code.size());
  771. realInput[1] = jump;
  772. JumpWrapper wrapper = new JumpWrapper(jump, "while");
  773. jumps.push(wrapper);
  774. loopJumps.push(wrapper);
  775. addCodeInstruction("while", realInput);
  776. }
  777. private void createBreakContinue(int current)
  778. {
  779. breakContinueJumps.forEach(jump -> jump.setRelativeJump(current));
  780. breakContinueJumps.clear();
  781. }
  782. }