package me.hammerle.code; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Stack; import me.hammerle.exceptions.CodeTooLongException; import me.hammerle.exceptions.GotoLabelNotFoundException; import me.hammerle.exceptions.HoldCodeException; import me.hammerle.exceptions.SnuviException; public class Script { private final SnuviParser parser; protected final boolean receiveEventBroadcast; protected final ArrayList eventVars; private final int id; private final String name; private final HashMap variables; private final HashMap gotos; private final HashSet events; private final Stack valueStack; private final Stack returnStack; private Code[] code; private int position; private int loopCounter; private boolean halt; private boolean valid; private int tryJumpLine; public Script(SnuviParser parser, int id, String name, String code, boolean receiveEventBroadcast) { this.eventVars = new ArrayList<>(); this.receiveEventBroadcast = receiveEventBroadcast; this.parser = parser; this.id = id; this.name = name; variables = new HashMap<>(); gotos = new HashMap<>(); events = new HashSet<>(); valueStack = new Stack<>(); returnStack = new Stack<>(); this.code = Code.generate(parser, name, code, gotos); /*for(Code c : this.code) { System.out.println(c); }*/ position = 0; loopCounter = 0; halt = false; valid = true; tryJumpLine = -1; } public Script(SnuviParser parser, int id, String name, String code) { this(parser, id, name, code, true); } protected void initExpansion(Object... o) { } public void overload(String code) { gotos.clear(); valueStack.clear(); returnStack.clear(); this.code = Code.generate(parser, name, code, gotos); position = 0; halt = false; valid = true; tryJumpLine = -1; } public Code[] getCode(int line) { int start = 0; int end = code.length; int helper; while(end - start > 1) { helper = (start + end) >> 1; if(code[helper].line > line) { end = helper; } else if(code[helper].line <= line) { start = helper; } } int realEnd = start; start = 0; end = code.length; while(end - start > 1) { helper = (start + end) >> 1; if(code[helper].line >= line) { end = helper; } else if(code[helper].line < line) { start = helper; } } return Arrays.copyOfRange(code, end, realEnd + 1); } // ----------------------------------------------------------------------------------- // Script-Daten // ----------------------------------------------------------------------------------- public int getId() { return id; } public String getName() { return name; } public boolean isHalt() { return halt; } public void setHalt(boolean b) { halt = b; } public boolean isValid() { return valid; } public void setInvalid() { valid = false; } public int getActiveCodeLine() { return code[position].line; } // ----------------------------------------------------------------------------------- // Event-Handling // ----------------------------------------------------------------------------------- public void loadEvent(String s) { events.add(s); } public boolean isLoadedEvent(String s) { return events.contains(s); } public void unloadEvent(String s) { events.remove(s); } // ----------------------------------------------------------------------------------- // Script-Flow // ----------------------------------------------------------------------------------- public void onTerm() { } public void runCode() { if(this.isValid()) { try { while(position < code.length) { code[position].executeFunction(parser, this, valueStack); position++; if(isHalt()) { return; } } parser.termSafe(this); } catch(Exception ex) { if(ex.getClass() != HoldCodeException.class) { parser.logger.printException(new SnuviException(ex, this)); } position++; } } } // ----------------------------------------------------------------------------------- // Variablen // ----------------------------------------------------------------------------------- public void setEventVar(String var, Object value) { variables.put(var, value); eventVars.add(var); } public void setVar(String var, Object value) { variables.put(var, value); } public Object getVar(String var) { return variables.get(var); } public HashMap getVars() { return variables; } public boolean getBooleanVar(String var) { try { return (boolean) getVar(var); } catch(ClassCastException | NullPointerException ex) { return false; } } public void removeVar(String var) { variables.remove(var); } // ----------------------------------------------------------------------------------- // Goto, Return // ----------------------------------------------------------------------------------- public void incLoopCounter() { loopCounter++; if(loopCounter > 50) { resetLoopCounter(); throw new CodeTooLongException(this); } } public void gotoLabel(String label) { try { int i = gotos.get(label); incLoopCounter(); position = i - 1; } catch(NullPointerException ex) { throw new GotoLabelNotFoundException(this, label); } } public void resetLoopCounter() { loopCounter = 0; } public void gotoLabelWithReturn(String label) { returnStack.push(position); gotoLabel(label); } public void doReturn() { position = returnStack.pop(); } public void gotoSpecialJumpLine(int i) { position += code[position].getJumpLine() + i; } public void gotoSpecialJumpLine() { gotoSpecialJumpLine(-1); } public void jumpNextIfElse() { if(code.length <= position + 1) { return; } String s = code[position + 1].getFunction(); if(s == null || !s.equals("else")) { return; } position++; } // ----------------------------------------------------------------------------------- // try // ----------------------------------------------------------------------------------- public void gotoTryJumpLine() { position = tryJumpLine; } public void saveTryJumpLine() { tryJumpLine = position + code[position].getJumpLine(); } public void resetTryJumpLine() { tryJumpLine = -1; } public int getTryJumpLine() { return tryJumpLine; } }