ScriptData.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. package me.hammerle.scriptsystem;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.nio.file.Files;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. import java.util.HashMap;
  8. import java.util.HashSet;
  9. import me.hammerle.exceptions.CodeTooLongException;
  10. import me.hammerle.exceptions.GoHigherAtRootTreeException;
  11. import me.hammerle.exceptions.GotoLabelNotFoundException;
  12. import me.hammerle.exceptions.NoChildTreeException;
  13. public class ScriptData
  14. {
  15. private final int id;
  16. private final Tree<String> code;
  17. private String currentCode;
  18. private int position;
  19. private final HashMap<String, Object> variables;
  20. private final HashMap<String, Integer[]> gotos;
  21. private final HashSet<String> events;
  22. private final String scriptName;
  23. private boolean isWaiting;
  24. //private boolean isValid;
  25. private int overflowProtection;
  26. public ScriptData(int id, String filename)
  27. {
  28. this.id = id;
  29. code = new Tree<>();
  30. position = 0;
  31. variables = new HashMap<>();
  32. gotos = new HashMap<>();
  33. events = new HashSet<>();
  34. scriptName = filename;
  35. readCode(filename);
  36. isWaiting = false;
  37. //isValid = true;
  38. overflowProtection = 0;
  39. }
  40. public void goDeeper() throws NoChildTreeException
  41. {
  42. code.goDeeper();
  43. }
  44. private void readCode(String filename)
  45. {
  46. File script = new File(filename + ".txt");
  47. List<String> lines;
  48. if(script.exists())
  49. {
  50. try
  51. {
  52. lines = Files.readAllLines(script.toPath());
  53. }
  54. catch (IOException ex)
  55. {
  56. ScriptUtils.printError("Datei '" + filename + "' kann nicht gelesen werden.");
  57. return;
  58. }
  59. }
  60. else
  61. {
  62. ScriptUtils.printError("Datei '" + filename + "' wurde nicht gefunden.");
  63. return;
  64. }
  65. int line = 0;
  66. int i = 0;
  67. int old = 0;
  68. int bracket = 0;
  69. boolean bracketEnd = false;
  70. int bracketEndPos = 0;
  71. boolean oneLineChild = false;
  72. boolean comment = false;
  73. int commentPos = 0;
  74. StringBuilder codeLine = new StringBuilder();
  75. while(line < lines.size())
  76. {
  77. if(old == codeLine.length() && !comment)
  78. {
  79. codeLine = new StringBuilder(lines.get(line).trim());
  80. i = 0;
  81. old = 0;
  82. }
  83. else
  84. {
  85. codeLine.append(lines.get(line).trim());
  86. }
  87. //System.out.println(codeLine);
  88. while(i < codeLine.length())
  89. {
  90. switch(codeLine.charAt(i))
  91. {
  92. case '@':
  93. if(comment)
  94. {
  95. break;
  96. }
  97. old = i;
  98. while(i < codeLine.length() && codeLine.charAt(i) != ' ')
  99. {
  100. i++;
  101. }
  102. try
  103. {
  104. code.selectLastChild(); // Nur für richtige Position
  105. }
  106. catch(NoChildTreeException ex)
  107. {
  108. }
  109. gotos.put(codeLine.substring(old + 1, i), code.getCurrentPosition());
  110. codeLine.delete(old, i + 1);
  111. i = old - 1;
  112. break;
  113. case '/':
  114. if(!comment && i + 1 < codeLine.length() && codeLine.charAt(i + 1) == '*')
  115. {
  116. comment = true;
  117. commentPos = i;
  118. }
  119. if(!comment && i + 1 < codeLine.length() && codeLine.charAt(i + 1) == '/')
  120. {
  121. codeLine.delete(commentPos, codeLine.length());
  122. }
  123. break;
  124. case '*':
  125. if(comment && i + 1 < codeLine.length() && codeLine.charAt(i + 1) == '/')
  126. {
  127. comment = false;
  128. codeLine.delete(commentPos, i + 2);
  129. i = commentPos;
  130. }
  131. break;
  132. case ';':
  133. if(comment)
  134. {
  135. break;
  136. }
  137. bracketEnd = false;
  138. code.addChild(codeLine.substring(old, i));
  139. old = i + 1;
  140. if(oneLineChild)
  141. {
  142. oneLineChild = false;
  143. try
  144. {
  145. code.goHigher();
  146. }
  147. catch(GoHigherAtRootTreeException ex)
  148. {
  149. System.out.println("Das sollte nicht passieren");
  150. return;
  151. }
  152. }
  153. break;
  154. case '(':
  155. if(!comment && !oneLineChild)
  156. {
  157. bracket++;
  158. if(bracketEnd)
  159. {
  160. bracketEnd = false;
  161. oneLineChild = true;
  162. code.addChild(codeLine.substring(old, bracketEndPos));
  163. old = bracketEndPos;
  164. try
  165. {
  166. code.selectLastChild();
  167. code.goDeeper();
  168. }
  169. catch(NoChildTreeException ex)
  170. {
  171. System.out.println("Das sollte nicht passieren");
  172. }
  173. }
  174. }
  175. break;
  176. case ')':
  177. if(comment || oneLineChild)
  178. {
  179. break;
  180. }
  181. bracket--;
  182. if(bracket < 0)
  183. {
  184. ScriptUtils.printError(") ohne ( in Zeile " + (line + 1));
  185. return;
  186. }
  187. if(bracket == 0)
  188. {
  189. bracketEnd = true;
  190. bracketEndPos = i + 1;
  191. }
  192. break;
  193. case '{':
  194. if(comment)
  195. {
  196. break;
  197. }
  198. bracketEnd = false;
  199. code.addChild(codeLine.substring(old, i));
  200. old = i + 1;
  201. try
  202. {
  203. code.selectLastChild();
  204. code.goDeeper();
  205. }
  206. catch(NoChildTreeException ex)
  207. {
  208. System.out.println("Das sollte nicht passieren");
  209. }
  210. break;
  211. case '}':
  212. if(comment)
  213. {
  214. break;
  215. }
  216. old = i + 1;
  217. try
  218. {
  219. code.goHigher();
  220. }
  221. catch(GoHigherAtRootTreeException ex)
  222. {
  223. ScriptUtils.printError("} ohne { in Zeile " + (line + 1));
  224. return;
  225. }
  226. break;
  227. }
  228. i++;
  229. }
  230. line++;
  231. }
  232. code.goToRoot();
  233. }
  234. public void runCode()
  235. {
  236. try
  237. {
  238. while(!isWaiting)
  239. {
  240. try
  241. {
  242. code.selectNextChild();
  243. }
  244. catch(NoChildTreeException ex)
  245. {
  246. //System.out.println("NACH OBEN!");
  247. code.goHigher();
  248. continue;
  249. }
  250. currentCode = code.getCurrentChildData();
  251. findFunction(0, currentCode.length() - 1);
  252. }
  253. }
  254. catch(NoChildTreeException | GoHigherAtRootTreeException ex)
  255. {
  256. System.out.println("END PROGRAM");
  257. }
  258. }
  259. private Object findFunction(int from, int to)
  260. {
  261. if(to <= from) // Springt in { } ohne Kopf
  262. {
  263. try
  264. {
  265. code.goDeeper();
  266. }
  267. catch(NoChildTreeException ex)
  268. {
  269. System.out.println("SOLLTE NICHT SEIN");
  270. }
  271. return null;
  272. }
  273. int old = from;
  274. int bracket;
  275. ArrayList<Object> list = new ArrayList<>();
  276. while(currentCode.charAt(from) != '(')
  277. {
  278. from++;
  279. }
  280. bracket = from;
  281. from++;
  282. int last = from;
  283. int counter = 0;
  284. boolean string = false;
  285. while(from <= to)
  286. {
  287. if(string)
  288. {
  289. if(currentCode.charAt(from) == '"')
  290. {
  291. string = !string;
  292. }
  293. from++;
  294. continue;
  295. }
  296. switch(currentCode.charAt(from))
  297. {
  298. case '"':
  299. string = !string;
  300. break;
  301. case ',':
  302. if(last != from)
  303. {
  304. list.add(currentCode.substring(last, from).trim());
  305. }
  306. last = from + 1;
  307. break;
  308. case ')':
  309. if(counter > 0)
  310. {
  311. last = from + 1;
  312. counter--;
  313. break;
  314. }
  315. position = from;
  316. if(last != from)
  317. {
  318. list.add(currentCode.substring(last, from).trim());
  319. }
  320. return doFunction(currentCode.substring(old, bracket).trim(), list);
  321. case '(':
  322. list.add(findFunction(last, to));
  323. from = position - 1;
  324. last = from;
  325. counter++;
  326. break;
  327. }
  328. from++;
  329. }
  330. return null;
  331. }
  332. private Object doFunction(String function, List<Object> args)
  333. {
  334. for(int i = 0; i < args.size(); i++)
  335. {
  336. args.set(i, readParameter(args.get(i)));
  337. }
  338. Object o = CodeParser.parseFunction(this, function, args);
  339. if(o == null)
  340. {
  341. isWaiting = true;
  342. }
  343. return o;
  344. }
  345. private Object readParameter(Object o)
  346. {
  347. if(!(o instanceof String))
  348. {
  349. return o;
  350. }
  351. String s = o.toString();
  352. if(s.startsWith("\"") && s.endsWith("\""))
  353. {
  354. return s.substring(1, s.length() - 1);
  355. }
  356. else if(s.startsWith("$"))
  357. {
  358. return getVar(s);
  359. }
  360. try
  361. {
  362. return ScriptUtils.getNumber(s);
  363. }
  364. catch(NumberFormatException ex)
  365. {
  366. return s;
  367. }
  368. }
  369. public int getId()
  370. {
  371. return id;
  372. }
  373. public String getName()
  374. {
  375. return scriptName;
  376. }
  377. /*public boolean isWaiting()
  378. {
  379. return isWaiting;
  380. }
  381. public void setWaiting(Boolean bool)
  382. {
  383. isWaiting = bool;
  384. }
  385. public boolean isValid()
  386. {
  387. return isValid;
  388. }
  389. public void setValid(Boolean bool)
  390. {
  391. isValid = bool;
  392. }*/
  393. public Object getVar(String var)
  394. {
  395. if(var.startsWith("$"))
  396. {
  397. return variables.get(var);
  398. }
  399. return variables.get("$" + var);
  400. }
  401. public Object getVar(Object var)
  402. {
  403. return getVar(var.toString());
  404. }
  405. public HashMap<String, Object> getVars()
  406. {
  407. return variables;
  408. }
  409. public void removeVar(String var)
  410. {
  411. if(var.startsWith("$"))
  412. {
  413. variables.remove(var);
  414. }
  415. variables.remove("$" + var);
  416. }
  417. public void removeVar(Object var)
  418. {
  419. removeVar(var.toString());
  420. }
  421. public void setVar(String var, Object value)
  422. {
  423. if(!var.startsWith("$"))
  424. {
  425. var = "$" + var;
  426. }
  427. variables.put(var, value);
  428. }
  429. public void setVar(Object var, Object value)
  430. {
  431. setVar(var.toString(), value);
  432. }
  433. public void gotoLabel(String label) throws NoChildTreeException, CodeTooLongException
  434. {
  435. Integer[] i = gotos.get(label);
  436. if(i == null)
  437. {
  438. throw new GotoLabelNotFoundException(label);
  439. }
  440. overflowProtection++;
  441. if(overflowProtection > 50)
  442. {
  443. overflowProtection = 0;
  444. throw new CodeTooLongException();
  445. }
  446. code.goToPosition(i);
  447. }
  448. public void resetOverflowProtection()
  449. {
  450. overflowProtection = 0;
  451. }
  452. public void loadEvent(Object event)
  453. {
  454. events.add(event.toString());
  455. }
  456. public void unloadEvent(Object event)
  457. {
  458. events.remove(event.toString());
  459. }
  460. public boolean isEventLoaded(Object event)
  461. {
  462. return events.contains(event.toString());
  463. }
  464. }