Compiler.java 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  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());
  168. break;
  169. }
  170. case "for":
  171. {
  172. loopJumps.pop();
  173. createBreakContinue(code.size());
  174. JumpData jump = data.data;
  175. jump.setRelativeJump(code.size());
  176. addCodeInstruction("next", new InputProvider[] {new JumpData(-jump.getInt(null) - 1)});
  177. break;
  178. }
  179. case "while":
  180. {
  181. loopJumps.pop();
  182. createBreakContinue(code.size());
  183. JumpData jump = data.data;
  184. jump.setRelativeJump(code.size() + 1);
  185. addCodeInstruction("wend", new InputProvider[] {new JumpData(-jump.getInt(null) - 1)});
  186. break;
  187. }
  188. }
  189. break;
  190. case '{':
  191. int currentJumps = jumps.size();
  192. check = sb.toString();
  193. if(check.startsWith("function "))
  194. {
  195. if(parentScript.subScript)
  196. {
  197. throw new PreScriptException("function not allowed in another function", line);
  198. }
  199. int index = check.indexOf("(");
  200. if(index == -1)
  201. {
  202. throw new PreScriptException("missing function syntax", line);
  203. }
  204. String function = check.substring(9, index);
  205. int endIndex = check.indexOf(")", index);
  206. if(index == -1)
  207. {
  208. throw new PreScriptException("missing function syntax", line);
  209. }
  210. String[] inputs;
  211. if(index + 1 == endIndex)
  212. {
  213. inputs = new String[0];
  214. }
  215. else
  216. {
  217. inputs = check.substring(index + 1, endIndex).split("[ ]*,[ ]*");
  218. }
  219. ArrayList<String> subList = new ArrayList<>();
  220. int bCounter = 1;
  221. String subLine = check;
  222. pos++;
  223. int oldLine = line;
  224. out: while(true)
  225. {
  226. old = pos;
  227. while(pos < subLine.length())
  228. {
  229. switch(subLine.charAt(pos))
  230. {
  231. case '"':
  232. text = !text;
  233. break;
  234. case '{':
  235. if(!text)
  236. {
  237. bCounter++;
  238. }
  239. break;
  240. case '}':
  241. if(!text)
  242. {
  243. bCounter--;
  244. if(bCounter == 0)
  245. {
  246. subList.add(subLine.substring(old, pos).trim());
  247. sb = new StringBuilder();
  248. sCode.set(line, subLine.substring(pos + 1));
  249. line--;
  250. break out;
  251. }
  252. }
  253. break;
  254. }
  255. pos++;
  256. }
  257. subList.add(subLine.substring(old, pos).trim());
  258. line++;
  259. if(line >= sCode.size())
  260. {
  261. throw new PreScriptException("{ without }", line);
  262. }
  263. pos = 0;
  264. subLine = sCode.get(line);
  265. }
  266. Script sub = new Script(subList, inputs, parentScript, oldLine);
  267. parentScript.subScripts.put(function, sub);
  268. }
  269. else
  270. {
  271. check = sb.substring(0, pos);
  272. compileLine(check);
  273. sb.delete(0, pos + 1);
  274. layer++;
  275. if(currentJumps == jumps.size())
  276. {
  277. throw new PreScriptException("{ without a corresponding function", line);
  278. }
  279. }
  280. pos = -1;
  281. break;
  282. case ';':
  283. compileLine(sb.substring(0, pos).trim());
  284. sb.delete(0, pos + 1);
  285. pos = -1;
  286. break;
  287. case '"':
  288. text = true;
  289. old = pos;
  290. break;
  291. }
  292. pos++;
  293. }
  294. if(!text && !comment)
  295. {
  296. labelIndex = sb.indexOf("@");
  297. if(labelIndex != -1)
  298. {
  299. String label = sb.toString().trim();
  300. if(label.charAt(0) != '@')
  301. {
  302. throw new PreScriptException("you seriously fucked up the syntax here", line);
  303. }
  304. addLabel(label.substring(1), code.size() - 1);
  305. sb = new StringBuilder();
  306. }
  307. }
  308. }
  309. //System.out.println("__________________________________");
  310. Instruction[] input = code.toArray(new Instruction[code.size()]);
  311. /*
  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 && sy != Syntax.MAYBE)
  543. {
  544. if(stackCounter <= 0)
  545. {
  546. switch(sy)
  547. {
  548. case SUB:
  549. sy = Syntax.UNARY_SUB;
  550. break;
  551. case INC:
  552. sy = Syntax.POST_INC;
  553. break;
  554. case DEC:
  555. sy = Syntax.POST_DEC;
  556. break;
  557. default:
  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 ConstantFraction(Fraction.fromDouble(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.equals("true"))
  643. {
  644. return true;
  645. }
  646. else if(input.equals("false"))
  647. {
  648. return false;
  649. }
  650. else if(input.equals("null"))
  651. {
  652. return null;
  653. }
  654. else if(SnuviUtils.isNumber(input))
  655. {
  656. return Fraction.fromDouble(Double.parseDouble(input));
  657. }
  658. return input;
  659. }
  660. private Variable getOrCreateVariable(String var)
  661. {
  662. if(locale)
  663. {
  664. Variable oldVar = localVars.get(var);
  665. if(oldVar == null)
  666. {
  667. oldVar = new LocalVariable(var);
  668. localVars.put(var, oldVar);
  669. }
  670. return oldVar;
  671. }
  672. else
  673. {
  674. Variable oldVar = vars.get(var);
  675. if(oldVar == null)
  676. {
  677. oldVar = new Variable(var);
  678. vars.put(var, oldVar);
  679. }
  680. return oldVar;
  681. }
  682. }
  683. private DynamicArray createArray(String var, InputProvider[] in)
  684. {
  685. if(locale)
  686. {
  687. Variable oldVar = localVars.get(var);
  688. if(oldVar == null)
  689. {
  690. oldVar = new LocalArrayVariable(var);
  691. localVars.put(var, oldVar);
  692. }
  693. return new DynamicArray(oldVar, in);
  694. }
  695. else
  696. {
  697. Variable oldVar = vars.get(var);
  698. if(oldVar == null)
  699. {
  700. oldVar = new ArrayVariable(var);
  701. vars.put(var, oldVar);
  702. }
  703. return new DynamicArray(oldVar, in);
  704. }
  705. }
  706. private void createIf(String name, String[] parts)
  707. {
  708. InputProvider[] input = compileFunction(parts, false);
  709. InputProvider[] realInput = new InputProvider[input.length + 1];
  710. System.arraycopy(input, 0, realInput, 0, input.length);
  711. JumpData jump = new JumpData(code.size());
  712. realInput[input.length] = jump;
  713. jumps.push(new JumpWrapper(jump, name));
  714. addCodeInstruction(name, realInput);
  715. }
  716. private void createFor(String[] parts)
  717. {
  718. // expected syntax
  719. // for(var, start, end, step)
  720. // for(var, start, end)
  721. InputProvider[] input = compileFunction(parts, false);
  722. if(input.length != 3 && input.length != 4)
  723. {
  724. throw new PreScriptException("missing 'for' syntax at", line);
  725. }
  726. InputProvider[] realInput = new InputProvider[5];
  727. System.arraycopy(input, 0, realInput, 0, input.length);
  728. if(input.length == 3)
  729. {
  730. realInput[3] = new ConstantFraction(new Fraction(1));
  731. }
  732. JumpData jump = new JumpData(code.size());
  733. realInput[4] = jump;
  734. JumpWrapper wrapper = new JumpWrapper(jump, "for");
  735. jumps.push(wrapper);
  736. loopJumps.push(wrapper);
  737. addCodeInstruction("for", realInput);
  738. }
  739. private void createWhile(String[] parts)
  740. {
  741. // expected syntax
  742. // while(condition)
  743. InputProvider[] input = compileFunction(parts, false);
  744. if(input.length != 1)
  745. {
  746. throw new PreScriptException("invalid conditions at 'while'", line);
  747. }
  748. InputProvider[] realInput = new InputProvider[2];
  749. realInput[0] = input[0];
  750. JumpData jump = new JumpData(code.size());
  751. realInput[1] = jump;
  752. JumpWrapper wrapper = new JumpWrapper(jump, "while");
  753. jumps.push(wrapper);
  754. loopJumps.push(wrapper);
  755. addCodeInstruction("while", realInput);
  756. }
  757. private void createBreakContinue(int current)
  758. {
  759. breakContinueJumps.forEach(jump -> jump.setRelativeJump(current));
  760. breakContinueJumps.clear();
  761. }
  762. }