Compiler.java 29 KB

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