123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897 |
- package me.hammerle.code;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.LinkedList;
- import java.util.Stack;
- import me.hammerle.exceptions.PreScriptException;
- import me.hammerle.exceptions.NoSuchMethodException;
- import me.hammerle.math.Fraction;
- public class Code
- {
- protected final int realLine;
- protected final String function;
- protected final int pars;
- protected Object value;
-
- private Code(String function, int pars, Object value, int realLine)
- {
- this.function = function;
- this.pars = pars;
- this.value = value;
- this.realLine = realLine;
- }
-
- public Code(String function, int pars, int realLine)
- {
- this(function, pars, null, realLine);
- }
-
- public Code(Object value, int realLine)
- {
- this(null, 0, value, realLine);
- }
-
- public void executeFunction(SnuviParser parser, Script sc, Stack<Object> stack)
- {
- if(function == null)
- {
- if(value != null)
- {
- if(value.getClass() == Variable.class)
- {
- stack.push(sc.getVar(((Variable) value).getName()));
- return;
- }
- stack.push(value);
- return;
- }
- stack.push(value);
- return;
- }
- Object[] input;
- if(pars > 0)
- {
- input = new Object[pars];
- for(int i = 0; i < pars; i++)
- {
- input[i] = stack.pop();
- }
- }
- else
- {
- input = new Object[0];
- }
- Object output = parser.parseFunction(sc, function, input);
- if(output != Void.TYPE)
- {
- stack.push(output);
- }
- }
- @Override
- public String toString()
- {
- StringBuilder sb = new StringBuilder("(");
- sb.append(realLine);
- sb.append(") ");
-
- if(function != null)
- {
- sb.append("function '");
- sb.append(function);
- sb.append("' ");
- for(int i = 0; i < pars; i++)
- {
- sb.append("X,");
- }
- if(pars > 0)
- {
- sb.deleteCharAt(sb.length() - 1);
- }
- if(value != null)
- {
- sb.append("(");
- sb.append(value);
- sb.append(")");
- }
- }
- else
- {
- sb.append("push '");
- sb.append(value);
- sb.append("' ");
- if(value != null)
- {
- sb.append(value.getClass().getSimpleName());
- }
- return sb.toString();
- }
- return sb.toString();
- }
-
-
-
-
-
- private static String scriptName = null;
-
- private static int findFirstNonLetterOrDigit(StringBuilder code, int pos)
- {
- int length = code.length();
- while(pos < length)
- {
- if(!Character.isLetterOrDigit(code.charAt(pos)))
- {
- return pos;
- }
- pos++;
- }
- return -1;
- }
-
- private static int findStartOfSyntax(StringBuilder code, int pos)
- {
- int bracketCounter = 0;
- while(pos >= 0 && code.charAt(pos) == ' ')
- {
- pos--;
- }
- while(pos >= 0)
- {
- switch(code.charAt(pos))
- {
- case ';':
- case '{':
- case '}':
- if(bracketCounter != 0)
- {
- throw new PreScriptException(scriptName, countChar('\n', pos, code), "unbalanced ()");
- }
- return pos + 1;
- case ' ':
- case '+':
- case '-':
- case '*':
- case '/':
- case '^':
- case '@':
- case '=':
- case '>':
- case '<':
- case '!':
- case '%':
- case ',':
- case '&':
- case '|':
- if(bracketCounter != 0)
- {
- break;
- }
- return pos + 1;
- case ')':
- bracketCounter++;
- break;
- case '(':
- if(bracketCounter == 0)
- {
- return pos + 1;
- }
- bracketCounter--;
- break;
- }
- pos--;
- }
- return 0;
- }
-
- private static int findEndOfSyntax(StringBuilder code, int pos)
- {
- return findEndOfSyntax(code, pos, false);
- }
-
- private static int findEndOfSyntax(StringBuilder code, int pos, boolean b)
- {
- int bracketCounter = 0;
- char c;
- while(pos < code.length() && code.charAt(pos) == ' ')
- {
- pos++;
- }
- while(pos < code.length())
- {
- c = code.charAt(pos);
- if(b && c == '\n')
- {
- if(bracketCounter != 0)
- {
- pos++;
- continue;
- }
- return pos;
- }
- switch(c)
- {
- case ';':
- case '{':
- case '}':
- if(bracketCounter != 0)
- {
- throw new PreScriptException(scriptName, countChar('\n', pos, code), "unbalanced ()");
- }
- return pos;
- case ' ':
- case '+':
- case '-':
- case '*':
- case '/':
- case '^':
- case '@':
- case '=':
- case '>':
- case '<':
- case '!':
- case '%':
- case ',':
- case '&':
- case '|':
- if(bracketCounter != 0)
- {
- break;
- }
- return pos;
- case '(':
- bracketCounter++;
- break;
- case ')':
- if(bracketCounter == 0)
- {
- return pos;
- }
- bracketCounter--;
- break;
- }
- pos++;
- }
- return code.length();
- }
-
- private static int findChar(char c, StringBuilder code, int pos)
- {
- int length = code.length();
- while(pos < length)
- {
- if(code.charAt(pos) == c)
- {
- return pos;
- }
- pos++;
- }
- return -1;
- }
-
- private static int findSyntax(String find, StringBuilder code, int pos)
- {
- int length = code.length();
- String s = code.toString();
- while(pos < length)
- {
-
- if(s.startsWith(find, pos) && !s.startsWith(find + "=", pos) && (pos == 0 || code.charAt(pos - 1) != '='))
- {
- return pos;
- }
- pos++;
- }
- return -1;
- }
-
- private static int findSyntaxIgnoreString(String find, StringBuilder code, int pos)
- {
- int length = code.length();
- int add = find.length();
- char c;
- boolean text = false;
- while(pos < length)
- {
- c = code.charAt(pos);
- if(text && c != '"')
- {
- pos++;
- continue;
- }
- else if(c == '"')
- {
- text = !text;
- pos++;
- continue;
- }
- else if(code.substring(pos, Math.min(pos + add, length)).equals(find))
- {
- return pos;
- }
- pos++;
- }
- return -1;
- }
-
- private static void changeBiSyntax(String syntax, String f, StringBuilder sb, boolean b)
- {
- int pos = -1;
- int end;
- int start;
- int slength = syntax.length();
- StringBuilder newSyntax;
- while(pos < sb.length())
- {
- pos = findSyntax(syntax, sb, pos + 1);
- if(pos == -1)
- {
- break;
- }
- start = findStartOfSyntax(sb, pos - 1);
- end = findEndOfSyntax(sb, pos + slength);
- newSyntax = new StringBuilder(f);
- newSyntax.append("(");
- if(b)
- {
- newSyntax.append("\"");
- }
- newSyntax.append(sb.substring(start, pos).trim());
- if(b)
- {
- newSyntax.append("\"");
- }
- if(end > pos)
- {
- newSyntax.append(",");
- newSyntax.append(sb.substring(pos + slength, end).trim());
- }
- newSyntax.append(")");
- pos -= end - start - newSyntax.length();
-
- sb.replace(start, end, newSyntax.toString());
- }
- }
-
- private static void changeUnSyntax(String syntax, String f, StringBuilder sb)
- {
- int pos = -1;
- int end;
- int start;
- int slength = syntax.length();
- String first;
- StringBuilder newSyntax;
- while(pos < sb.length())
- {
- pos = findSyntax(syntax, sb, pos + 1);
- if(pos == -1)
- {
- break;
- }
- start = findStartOfSyntax(sb, pos - 1);
- end = findEndOfSyntax(sb, pos + slength);
- newSyntax = new StringBuilder("setvar(\"");
- first = sb.substring(start, pos).trim();
- newSyntax.append(first);
- newSyntax.append("\",");
- newSyntax.append(f);
- newSyntax.append("(");
- newSyntax.append(first);
- newSyntax.append(",");
- newSyntax.append(sb.substring(pos + slength, end).trim());
- newSyntax.append("))");
- pos -= end - start - newSyntax.length();
- sb.replace(start, end, newSyntax.toString());
- }
- }
- public static int countChar(char find, int end, StringBuilder code)
- {
- int counter = 0;
- int pos = 0;
- end = Math.min(end, code.length());
- while(pos < end)
- {
- if(code.charAt(pos) == find)
- {
- counter++;
- }
- pos++;
- }
- return counter;
- }
-
- private static void addKeyWordBrackets(String keyWord, StringBuilder sb)
- {
- String with = keyWord + "()";
- int length = keyWord.length();
- int pos = 0;
- while(true)
- {
- pos = sb.indexOf(keyWord, pos);
- if(pos + length >= sb.length())
- {
- throw new PreScriptException(scriptName, countChar('\n', pos, sb), "unexpected keyword");
- }
- else if(pos == -1 ||
- (pos >= 1 && Character.isLetterOrDigit(sb.charAt(pos - 1))) ||
- (Character.isLetterOrDigit(sb.charAt(pos + length))))
- {
- break;
- }
- else if(sb.charAt(pos + length) != '(')
- {
- sb.replace(pos, pos + length, with);
- }
- pos += length;
- }
- }
-
- private static String removeNonSyntax(String s)
- {
- StringBuilder sb = new StringBuilder(s);
- int pos = 0;
- while(pos < sb.length())
- {
- switch(sb.charAt(pos))
- {
- case ' ':
- case '\t':
- case '\n':
- sb.deleteCharAt(pos);
- continue;
- }
- pos++;
- }
- return sb.toString();
- }
-
- public static Code[] generate(SnuviParser parser, String scriptName, String code, HashMap<String, Integer> gotos)
- {
- System.out.println("START GENERATE");
- long startTime = System.currentTimeMillis();
-
- Code.scriptName = scriptName;
-
- int old = 0;
- int pos;
- StringBuilder sb = new StringBuilder(code);
-
-
-
-
-
- while(true)
- {
- old = findSyntaxIgnoreString("/*", sb, old);
- if(old == -1)
- {
- break;
- }
- pos = findSyntaxIgnoreString("*/", sb, old);
- if(pos == -1)
- {
- throw new PreScriptException(scriptName, countChar('\n', old, sb), "/* without */");
- }
- sb.delete(old, pos + 2);
- }
- old = 0;
- while(true)
- {
- old = findSyntaxIgnoreString("//", sb, old);
- if(old == -1)
- {
- break;
- }
- pos = findSyntaxIgnoreString("\n", sb, old);
- if(pos == -1)
- {
- sb.delete(old, sb.length());
- break;
- }
- sb.delete(old, pos + 1);
- }
-
-
-
-
-
- pos = 0;
- String replacement;
- String text;
- int stringIndex = 0;
- HashMap<String, String> strings = new HashMap<>();
- while(pos < sb.length())
- {
- if(sb.charAt(pos) == '"')
- {
- old = pos;
- pos++;
- while(sb.charAt(pos) != '"')
- {
- pos++;
- if(pos >= sb.length())
- {
- throw new PreScriptException(scriptName, countChar('\n', old, sb), "\" without another");
- }
- }
- pos++;
- text = sb.substring(old, pos);
- replacement = "#" + stringIndex;
- sb.replace(old, pos, replacement);
- strings.put(replacement, text);
- stringIndex++;
- pos -= (pos - old) - replacement.length();
- }
- pos++;
- }
-
-
-
-
-
- old = 0;
- while(true)
- {
- pos = findChar('@', sb, old);
- if(pos == -1)
- {
- break;
- }
- pos++;
- old = pos;
- pos = findFirstNonLetterOrDigit(sb, pos);
- if(pos == -1)
- {
- break;
- }
- if(sb.charAt(pos) != ';')
- {
- sb.insert(pos, ';');
- }
- }
-
-
-
-
- addKeyWordBrackets("else", sb);
- addKeyWordBrackets("try", sb);
- addKeyWordBrackets("catch", sb);
-
-
-
-
-
- changeBiSyntax("^", "math.pow", sb, false);
- changeBiSyntax("/", "div", sb, false);
- changeBiSyntax("%", "math.mod", sb, false);
- changeBiSyntax("*", "mul", sb, false);
- changeBiSyntax("-", "sub", sb, false);
- changeBiSyntax("+", "add", sb, false);
- changeBiSyntax("==", "equal", sb, false);
- changeBiSyntax("!=", "notequal", sb, false);
- changeBiSyntax("<", "less", sb, false);
- changeBiSyntax(">", "greater", sb, false);
- changeBiSyntax(">=", "greaterequal", sb, false);
- changeBiSyntax("<=", "lessequal", sb, false);
- changeBiSyntax("||", "or", sb, false);
- changeBiSyntax("&&", "and", sb, false);
- changeUnSyntax("+=", "add", sb);
- changeUnSyntax("-=", "sub", sb);
- changeUnSyntax("/=", "div", sb);
- changeUnSyntax("*=", "mul", sb);
- changeBiSyntax("=", "setvar", sb, true);
-
-
-
-
-
- pos = 0;
- while(true)
- {
- pos = findSyntax("sub(,", sb, pos);
- if(pos == -1)
- {
- break;
- }
- sb.insert(pos + 4, '0');
- pos++;
- }
-
- code = sb.toString();
-
-
-
-
- ArrayList<String> lines = new ArrayList<>();
- int lineCounter = 1;
- ArrayList<Integer> realCodeLine = new ArrayList<>();
- old = 0;
- pos = 0;
- int length = code.length();
- int counter = 0;
- int bracketCounter = 0;
- boolean closed = true;
- Stack<Integer> brackets = new Stack<>();
- while(pos < length)
- {
- switch(code.charAt(pos))
- {
- case '(':
- closed = false;
- bracketCounter++;
- break;
- case ')':
- bracketCounter--;
- break;
- case ';':
- if(bracketCounter != 0)
- {
- throw new PreScriptException(scriptName, lineCounter, "unbalanced ()");
- }
- lines.add(removeNonSyntax(code.substring(old, pos)));
- realCodeLine.add(lineCounter);
- old = pos + 1;
- closed = true;
- break;
- case '{':
- if(bracketCounter != 0)
- {
- throw new PreScriptException(scriptName, lineCounter, "unbalanced ()");
- }
- brackets.push(lineCounter);
- counter++;
- lines.add(removeNonSyntax(code.substring(old, pos)));
- realCodeLine.add(lineCounter);
- old = pos + 1;
- lines.add("{");
- realCodeLine.add(lineCounter);
- break;
- case '}':
- if(!closed)
- {
- throw new PreScriptException(scriptName, lineCounter, "missing ;");
- }
- else if(bracketCounter != 0)
- {
- throw new PreScriptException(scriptName, lineCounter, "unbalanced ()");
- }
- counter--;
- if(counter < 0)
- {
- throw new PreScriptException(scriptName, lineCounter, "unexpected }");
- }
- old = pos + 1;
- lines.add("}");
- realCodeLine.add(lineCounter);
- brackets.pop();
- break;
- case '\n':
- lineCounter++;
- break;
- }
- pos++;
- }
-
- if(counter != 0 && !brackets.isEmpty())
- {
- throw new PreScriptException(scriptName, brackets.pop(), "unbalanced {}");
- }
-
-
-
-
-
- ArrayList<Code> co = new ArrayList<>();
- Stack<Integer> parCounter = new Stack<>();
- char current;
- char previous;
- int layer = 0;
- int line;
- boolean noFunction;
- LinkedList<Integer> whileStart = new LinkedList<>();
- String s;
- for(int i = 0; i < lines.size(); i++)
- {
- s = lines.get(i);
- if(s.isEmpty())
- {
- continue;
- }
- else if(s.startsWith("while"))
- {
- whileStart.push(co.size());
- }
- else if(s.charAt(0) == '@')
- {
- gotos.put(s.substring(1), co.size());
- continue;
- }
- line = realCodeLine.get(i);
- previous = ',';
- noFunction = true;
- pos = s.length() - 1;
- while(pos >= 0)
- {
- current = s.charAt(pos);
- switch(current)
- {
- case ')':
- parCounter.add(0);
- if(previous != ',' && previous != ')')
- {
- throw new PreScriptException(scriptName, line, "unexpected )");
- }
- old = pos;
- break;
- case '(':
- if(previous != ')')
- {
- parCounter.set(parCounter.size() - 1, parCounter.lastElement() + 1);
- if(noFunction)
- {
- co.add(new Code(Code.convertInput(strings, s.substring(pos + 1, old), true), line));
- }
- }
- old = pos;
- pos--;
- while(pos >= 0 && (Character.isLetterOrDigit(s.charAt(pos))
- || s.charAt(pos) == '_' || s.charAt(pos) == '.'))
- {
- pos--;
- }
- pos++;
- String functionName = s.substring(pos, old).toLowerCase();
- if(!parser.isRegisteredFunction(functionName))
- {
- throw new NoSuchMethodException(scriptName, line, functionName);
- }
- co.add(new Code(functionName, parCounter.pop(), line));
- noFunction = false;
- break;
- case ',':
- parCounter.set(parCounter.size() - 1, parCounter.lastElement() + 1);
- if(noFunction)
- {
- co.add(new Code(Code.convertInput(strings, s.substring(pos + 1, old), true), line));
- }
- old = pos;
- noFunction = true;
- break;
- case '{':
- layer++;
- co.add(new Code("goto", 0, layer, line));
- break;
- case '}':
- co.add(new Code("goto", 0, layer, line));
- layer--;
- break;
- }
- pos--;
- previous = current;
- }
- }
-
-
-
-
-
- Code[] c = co.toArray(new Code[co.size()]);
- for(int i = 0; i < c.length; i++)
- {
- if("goto".equals(c[i].function) && c[i].value != null)
- {
- Object value = c[i].value;
- if((int) value <= 0)
- {
- continue;
- }
- for(int j = i + 1; j < c.length; j++)
- {
- if(value.equals(c[j].value))
- {
- c[i].value = j - i;
- switch(c[i-1].function)
- {
- case "while":
- c[j].value = whileStart.pollLast() - j - 1;
- break;
-
- default:
- c[j].value = 0;
- break;
- }
- break;
- }
- }
- }
- }
-
- System.out.println("END GENERATE - " + (System.currentTimeMillis() - startTime));
-
-
-
- return c;
- }
-
- public static Object convertInput(HashMap<String, String> map, String s, boolean variable)
- {
- if(s == null)
- {
- return null;
- }
- s = s.trim();
- if(s.length() == 0)
- {
- return "";
- }
- if(s.charAt(0) == '"' && s.charAt(s.length() - 1) == '"')
- {
- if(s.length() == 1)
- {
- System.out.println("Convert-Input - this should never happen");
- return "";
- }
- return s.substring(1, s.length() - 1);
- }
- else if(variable && s.startsWith("#"))
- {
- return convertInput(null, map.get(s), false);
- }
- else if(s.equals("true"))
- {
- return true;
- }
- else if(s.equals("false"))
- {
- return false;
- }
- else if(s.equals("null"))
- {
- return null;
- }
- try
- {
- if(s.contains("/"))
- {
- String[] parts = s.split("/");
- return new Fraction(Long.parseLong(parts[0].trim()), Long.parseLong(parts[1].trim()));
- }
- return new Fraction(Long.parseLong(s));
- }
- catch(NumberFormatException ex)
- {
- try
- {
- return Fraction.fromDouble(Double.parseDouble(s));
- }
- catch(NumberFormatException ex2)
- {
- if(variable)
- {
- return new Variable(s);
- }
- return s;
- }
- }
- }
-
- public static Object convertInput(String s)
- {
- return convertInput(null, s, false);
- }
- }
|