diff --git a/SanityCheck.jar b/SanityCheck.jar new file mode 100644 index 0000000000000000000000000000000000000000..42a086d8c043eb99010faa0dfcca5dc778ad0e1d Binary files /dev/null and b/SanityCheck.jar differ diff --git a/devTools/javaSanityCheck/excluded b/devTools/javaSanityCheck/excluded new file mode 100644 index 0000000000000000000000000000000000000000..1b1e091323a74b93ccf8bfc7861906b967c6439e --- /dev/null +++ b/devTools/javaSanityCheck/excluded @@ -0,0 +1,16 @@ +#Add files or folders to be excluded. +#empty lines will match on ALL paths, so if you need one do it like this: +# +src/art/ +src/gui/svgFilters.tw +# +#excluded to reduce false positives until better solution: +src/pregmod/basenationalitiesControls.tw +src/pregmod/editGenetics.tw +src/pregmod/widgets/bodySwapReaction.tw +src/uncategorized/costsBudget.tw +src/uncategorized/initRules.tw +src/uncategorized/slaveAssignmentsReport.tw +src/uncategorized/storyCaption.tw +# +#reincluded later: diff --git a/devTools/javaSanityCheck/htmlTags b/devTools/javaSanityCheck/htmlTags new file mode 100644 index 0000000000000000000000000000000000000000..c306acc52dd6141ea7b38abdf51725ce483645b0 --- /dev/null +++ b/devTools/javaSanityCheck/htmlTags @@ -0,0 +1,44 @@ +#Allowed HTML tags +#Effectively everything that is allowed in one of these statements like this: +#<tag>, <tag ???> or </tag> +#Do not add Twine Tags here. +#Characters outside of ASCII scope are not supported. +# +#included to reduce false positives until better solution +!-- +http://www.gnu.org/licenses/ +#html tags +a +b +blockquote +body +br +button +caption +center +dd +div +dl +dt +h1 +h2 +h3 +h4 +hr +html +i +img +input +li +option +script +select +span +strong +style +table +td +th +tr +tt +ul diff --git a/devTools/javaSanityCheck/src/Main.java b/devTools/javaSanityCheck/src/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..e1f7909624c79b630cd8c1c6784821c97fff9fe4 --- /dev/null +++ b/devTools/javaSanityCheck/src/Main.java @@ -0,0 +1,150 @@ +package org.arkerthan.sanityCheck; + +import org.arkerthan.sanityCheck.element.AngleBracketElement; +import org.arkerthan.sanityCheck.element.AngleBracketElement2; +import org.arkerthan.sanityCheck.element.AtElement; +import org.arkerthan.sanityCheck.element.Element; + +import java.io.*; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + +public class Main { + + public static StringSearchTree htmlTags; + private static String currentFile; + private static int currentLine, currentPosition; + private static Stack<Element> stack; + private static List<SyntaxError> errors = new LinkedList<>(); + private static String[] excluded; + + public static void main(String[] args) { + setupExclude(); + setupHtmlTags(); + + // replace this with a known encoding if possible + Charset encoding = Charset.defaultCharset(); + for (String filename : args) { + if (!excluded(filename)) { + currentFile = filename; + currentLine = 1; + stack = new Stack<>(); + File file = new File(filename); + try { + handleFile(file, encoding); + } catch (IOException e) { + System.err.println("Couldn't read " + filename); + } + } + } + + //handle errors + for (SyntaxError e : + errors) { + System.out.println(e.getError()); + } + } + + private static void setupHtmlTags() { + //preparing excluding folders + List<String> htmlTagsList = new ArrayList<>(); + try { + + Files.lines(new File("devTools/javaSanityCheck/htmlTags").toPath()).map(String::trim) + .filter(s -> !s.startsWith("#")) + .forEach(htmlTagsList::add); + } catch (IOException e) { + System.err.println("Couldn't read devTools/javaSanityCheck/htmlTags"); + } + + try { + htmlTags = StringSearchTree.generateTree(htmlTagsList); + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("Illegal Character in devTools/javaSanityCheck/htmlTags"); + System.exit(-1); + } + } + + private static void setupExclude() { + //preparing excluding folders + List<String> excludedList = new ArrayList<>(); + try { + + Files.lines(new File("devTools/javaSanityCheck/excluded").toPath()).map(String::trim) + .filter(s -> !s.startsWith("#")) + .forEach(excludedList::add); + } catch (IOException e) { + System.err.println("Couldn't read devTools/javaSanityCheck/excluded"); + } + + excluded = excludedList.toArray(new String[0]); + } + + private static boolean excluded(String s) { + for (String ex : + excluded) { + if (s.startsWith(ex)) return true; + } + return false; + } + + + private static void handleFile(File file, Charset encoding) throws IOException { + try (InputStream in = new FileInputStream(file); + Reader reader = new InputStreamReader(in, encoding); + // buffer for efficiency + Reader buffer = new BufferedReader(reader)) { + handleCharacters(buffer); + } + } + + private static void handleCharacters(Reader reader) throws IOException { + int r; + while ((r = reader.read()) != -1) { + char c = (char) r; + handleCharacter(c); + } + } + + private static void handleCharacter(char c) { + currentPosition++; + if (c == '\n') { + currentLine++; + currentPosition = 1; + } + + //try applying to the innermost element + if (!stack.empty()) { + int change; + try { + change = stack.peek().handleChar(c); + } catch (SyntaxError e) { + e.setFile(currentFile); + e.setLine(currentLine); + e.setPosition(currentPosition); + change = e.getChange(); + errors.add(e); + } + if (change > 0) { + if (change == 2) { + stack.pop(); + } + return; + } + } + + //innermost element was uninterested, trying to find matching element + switch (c) { + case '@': + stack.push(new AtElement()); + break; + case '<': + stack.push(new AngleBracketElement2()); + break; + } + } +} diff --git a/devTools/javaSanityCheck/src/StringSearchTree.java b/devTools/javaSanityCheck/src/StringSearchTree.java new file mode 100644 index 0000000000000000000000000000000000000000..b1458b397bfc48525c47a9010964ae4165b46c15 --- /dev/null +++ b/devTools/javaSanityCheck/src/StringSearchTree.java @@ -0,0 +1,47 @@ +package org.arkerthan.sanityCheck; + +import java.util.List; + +public class StringSearchTree { + private static final int SIZE = 128; + private String element = null; + private StringSearchTree[] branches; + + private StringSearchTree() { + branches = new StringSearchTree[SIZE]; + } + + + public static StringSearchTree generateTree(List<String> list) { + StringSearchTree tree = new StringSearchTree(); + + for (String s : + list) { + tree.add(s, 0); + } + + return tree; + } + + private void add(String s, int index) { + if (s.length() == index) { + element = s; + } else { + char c = s.charAt(index); + if (branches[c] == null) { + branches[c] = new StringSearchTree(); + } + branches[c].add(s, index + 1); + } + } + + public StringSearchTree getBranch(char c) { + if (c >= SIZE) return null; + return branches[c]; + } + + public String getElement() { + return element; + } + +} diff --git a/devTools/javaSanityCheck/src/SyntaxError.java b/devTools/javaSanityCheck/src/SyntaxError.java new file mode 100644 index 0000000000000000000000000000000000000000..ed2f1f3da76aa4195050c6f20014e3dc8bfb6259 --- /dev/null +++ b/devTools/javaSanityCheck/src/SyntaxError.java @@ -0,0 +1,40 @@ +package org.arkerthan.sanityCheck; + +public class SyntaxError extends Exception { + private String file; + private int line, position; + private String description; + private int change; + private boolean warning = false; + + public SyntaxError(String description, int change) { + this.description = description; + this.change = change; + } + + public SyntaxError(String description, int change, boolean warning) { + this(description, change); + this.warning = warning; + } + + public void setFile(String file) { + this.file = file; + } + + public void setLine(int line) { + this.line = line; + } + + public void setPosition(int position) { + this.position = position; + } + + public String getError() { + String s = warning ? "Warning: " : "Error: "; + return s + file + ": " + line + ":" + position + " : "+ description; + } + + public int getChange() { + return change; + } +} diff --git a/devTools/javaSanityCheck/src/UnknownState.java b/devTools/javaSanityCheck/src/UnknownState.java new file mode 100644 index 0000000000000000000000000000000000000000..3344f09d8f08bd838c127276321c02a774cd8106 --- /dev/null +++ b/devTools/javaSanityCheck/src/UnknownState.java @@ -0,0 +1,8 @@ +package org.arkerthan.sanityCheck; + +public class UnknownState extends RuntimeException { + + public UnknownState(int state) { + super(String.valueOf(state)); + } +} diff --git a/devTools/javaSanityCheck/src/element/AngleBracketElement.java b/devTools/javaSanityCheck/src/element/AngleBracketElement.java new file mode 100644 index 0000000000000000000000000000000000000000..ed669e8c1cb7f6726e69364fae2e63c991097e75 --- /dev/null +++ b/devTools/javaSanityCheck/src/element/AngleBracketElement.java @@ -0,0 +1,515 @@ +package org.arkerthan.sanityCheck.element; + +import org.arkerthan.sanityCheck.SyntaxError; +import org.arkerthan.sanityCheck.UnknownState; + +public class AngleBracketElement extends Element { + private int state = 0; + + /* + -1 - </ + 0 - < + 1 - << + 2 - <<abc + 3 - <<abc> + + 5 - waiting for > + -5 - expecting > + + 10 - <b + br: wait in 5 + + 15 - <d + 16 - <di + 17 - <div + 18 - <div abc + -15 - </d + -16 - </di + -17 - </div + + works for any number + 20 - <h + 21 - <h1 || hr:wait in 5 + -20 - </h + -21 - </h1 + + 25 - <c + 26 - <ce + 27 - <cen + 28 - <cent + 29 - <cente + center: wait in 5 + -25 - </c + -26 - </ce + -27 - </cen + -28 - </cent + -29 - </cente + -30 - </center + + 35 - <s + 36 - <sp + 37 - <spa + span: wait in 5 + 39 - <st + 40 - <str + 41 - <stro + 42 - <stron + strong: wait in 5 + -35 - </s + -36 - </sp + -37 - </spa + span: expecting in -5 + -39 - </st + -40 - </str + -41 - </stro + -42 - </stron + strong: expecting in -5 + */ + @Override + public int handleChar(char c) throws SyntaxError { + switch (state) { + case 0: + return singleAngleBracket(c); + case -1: + return closingTag(c); + case 1: + if (c == '<') { + throw new SyntaxError("Too many \"<\".", 1); + } else if (c == '>') { + state = 3; + throw new SyntaxError("Empty Statement?", 1); + } else { + state = 2; + return 1; + } + case 2: + //TODO finding special statements: IF, ELSE... + if (c == '>') { + state = 3; + return 1; + } + break; + case 3: + if (c == '>') { + return 2; + } else if (c == ' ' || c == '=') { // assuming comparison + state = 2; + } else { + throw new SyntaxError("Closing \">\" missing [1]", 2); + } + break; + case 5: + if (c == '>') + return 2; + if (c == '@') + return 1; + break; + case -5: + if (c == '>') + return 2; + throw new SyntaxError("Closing \">\" missing [2]", 2); + //10 - <b + //br: wait in 5 + case 10: + if (c == 'r') { + state = 5; + return 1; + } else { + state = 1; + throw new SyntaxError("Opening \"<\" missing [1]", 1); + } + //15 - <d + //16 - <di + //17 - <div + //18 - <div abc + case 15: + if (c == 'i') { + state = 16; + return 1; + } else { + state = 1; + throw new SyntaxError("Opening \"<\" missing.", 1); + } + case 16: + if (c == 'v') { + state = 17; + return 1; + } else { + state = 1; + throw new SyntaxError("Opening \"<\" missing.", 1); + } + case 17: + if (c == ' ') { + state = 5; + return 1; + } else { + state = 5; + throw new SyntaxError("Missing Space?", 1, true); + } + //-15 - </d + //-16 - </di + //-17 - </div + case -15: + if (c == 'i') { + state = -16; + return 1; + } else { + state = 5; + throw new SyntaxError("Unknown Statement:</d" + c, 1, true); + } + case -16: + if (c == 'v') { + state = -17; + return 1; + } else { + state = 5; + throw new SyntaxError("Unknown Statement:</di" + c, 1, true); + } + case -17: + if (c == '>') { + return 2; + } else { + state = 5; + throw new SyntaxError("Unknown Statement:</div" + c, 1, true); + } + // works for any number + // 20 - <h + // 21 - <h1 || hr:wait in 5 + //-20 - </h + //-21 - </h1 + case 20: + if (Character.isDigit(c)) { + state = 21; + return 1; + } else if (c == 'r') { + state = 5; + return 1; + } else { + state = 1; + throw new SyntaxError("Opening \"<\" missing.", 1); + } + case 21: + if (c == '>') { + return 2; + } else { + throw new SyntaxError("Closing \">\" missing", 2); + } + case -20: + if (Character.isDigit(c)) { + state = -21; + return 1; + } else { + state = 5; + throw new SyntaxError("Unknown Statement:</h" + c, 1, true); + } + case -21: + if (c == '>') { + return 2; + } else { + state = 5; + throw new SyntaxError("Unknown Statement:</h?" + c, 1, true); + } + //25 - <c + //26 - <ce + //27 - <cen + //28 - <cent + //29 - <cente + //wait in 5 + case 25: + if (c == 'e') { + state = 26; + return 1; + } else { + state = 1; + throw new SyntaxError("Opening \"<\" missing.", 1); + } + case 26: + if (c == 'n') { + state = 27; + return 1; + } else { + state = 1; + throw new SyntaxError("Opening \"<\" missing.", 1); + } + case 27: + if (c == 't') { + state = 28; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"center\"?", 1); + } + case 28: + if (c == 'e') { + state = 29; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"center\"?", 1); + } + case 29: + if (c == 'r') { + state = 5; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"center\"?", 1); + } + //-25 - </c + //-26 - </ce + //-27 - </cen + //-28 - </cent + //-29 - </cente + //-30 - </center + case -25: + if (c == 'e') { + state = -26; + return 1; + } else { + state = 1; + throw new SyntaxError("Unknown Statement:</c" + c, 1, true); + } + case -26: + if (c == 'n') { + state = -27; + return 1; + } else { + state = 1; + throw new SyntaxError("Unknown Statement:</h?" + c, 1, true); + } + case -27: + if (c == 't') { + state = -28; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"center\"?", 1); + } + case -28: + if (c == 'e') { + state = -29; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"center\"?", 1); + } + case -29: + if (c == 'r') { + state = -30; + return 1; + } else { + state = -30; + throw new SyntaxError("Misspelled \"center\"?", 1); + } + case -30: + if (c == '>') { + return 2; + } else { + throw new SyntaxError("Closing \">\" missing", 2); + } + //35 - <s + //36 - <sp + //37 - <spa + //span: wait in 5 + //39 - <st + //40 - <str + //41 - <stro + //42 - <stron + //strong: wait in 5 + case 35: + if (c == 'p') { + state = 36; + return 1; + } else if (c == 't') { + state = 39; + return 1; + } else { + state = 1; + throw new SyntaxError("Opening \"<\" missing.", 1); + } + case 36: + if (c == 'a') { + state = 37; + return 1; + } else { + state = 1; + throw new SyntaxError("Opening \"<\" missing.", 1); + } + case 37: + if (c == 'n') { + state = 5; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"span\"?", 1); + } + case 39: + if (c == 'r') { + state = 40; + return 1; + } else { + state = 1; + throw new SyntaxError("Opening \"<\" missing.", 1); + } + case 40: + if (c == 'o') { + state = 41; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"strong\"?", 1); + } + case 41: + if (c == 'n') { + state = 42; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"strong\"?", 1); + } + case 42: + if (c == 'g') { + state = 5; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"strong\"?", 1); + } + //-35 - </s + //-36 - </sp + //-37 - </spa + //span: expecting in -5 + //-39 - </st + //-40 - </str + //-41 - </stro + //-42 - </stron + //strong: expecting in -5 + case -35: + if (c == 'p') { + state = -36; + return 1; + } else if (c == 't') { + state = -39; + return 1; + } else { + state = 1; + throw new SyntaxError("Unknown Statement:</s" + c, 1, true); + } + case -36: + if (c == 'a') { + state = -37; + return 1; + } else { + state = 1; + throw new SyntaxError("Unknown Statement:</sp" + c, 1, true); + } + case -37: + if (c == 'n') { + state = -5; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"span\"?", 1); + } + case -39: + if (c == 'r') { + state = -40; + return 1; + } else { + state = 1; + throw new SyntaxError("Unknown Statement:</sp" + c, 1, true); + } + case -40: + if (c == 'o') { + state = -41; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"strong\"?", 1); + } + case -41: + if (c == 'n') { + state = -42; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"strong\"?", 1); + } + case -42: + if (c == 'g') { + state = -5; + return 1; + } else { + state = 5; + throw new SyntaxError("Misspelled \"strong\"?", 1); + } + + default: + throw new UnknownState(state); + } + return 0; + } + + private int singleAngleBracket(char c) throws SyntaxError { + switch (c) { + case '<': + state = 1; + return 1; + case '/': + state = -1; + return 1; + case ' ':// assume comparison + case '=':// " + return 2; + case '3'://a heart: <3 + return 2; + case 'a': + state = 5; + return 1; + case 'b': + state = 10; + return 1; + case 'd': + state = 15; + return 1; + case 'h': + state = 20; + return 1; + case 'c': + state = 25; + return 1; + case 's': + state = 35; + return 1; + default: + state = 1; + throw new SyntaxError("Opening \"<\" missing, found " + c + " [debug:initialCase]", 1); + } + } + + private int closingTag(char c) throws SyntaxError { + switch (c) { + case '>': + throw new SyntaxError("Empty Statement?", 1, true); + case 'a': + state = -5; + return 1; + case 'd': + state = -15; + return 1; + case 'h': + state = -20; + return 1; + case 'c': + state = -25; + return 1; + case 's': + state = 35; + return 1; + default: + state = 5; + throw new SyntaxError("Unknown Statement", 1, true); + } + } +} + diff --git a/devTools/javaSanityCheck/src/element/AngleBracketElement2.java b/devTools/javaSanityCheck/src/element/AngleBracketElement2.java new file mode 100644 index 0000000000000000000000000000000000000000..018cb5e75e90f1f2e97c4465c6a463d91a9a98ac --- /dev/null +++ b/devTools/javaSanityCheck/src/element/AngleBracketElement2.java @@ -0,0 +1,147 @@ +package org.arkerthan.sanityCheck.element; + +import org.arkerthan.sanityCheck.Main; +import org.arkerthan.sanityCheck.StringSearchTree; +import org.arkerthan.sanityCheck.SyntaxError; +import org.arkerthan.sanityCheck.UnknownState; + +public class AngleBracketElement2 extends Element { + private int state = 0; + private StringSearchTree tree; + + /* + -1 - </ + 0 - initial: < + 1 - << + 2 - <<abc + 3 - <<abc> + + 4 - trying to complete HTML tag: <tag ???> + -4 - trying to complete HTML tag: </tag> + 5 - waiting for > + -5 - expecting > + */ + + @Override + public int handleChar(char c) throws SyntaxError { + switch (state) { + case 0: + switch (c) { + case '<': + state = 1; + return 1; + case '>': + throw new SyntaxError("Empty Statement?", 2); + case '/': + state = -1; + return 1; + case ' ':// assume comparison + case '=':// " + return 2; + case '3'://a heart: <3 + return 2; + default: + try { + state = 4; + tree = Main.htmlTags; + return handleOpeningHTML(c); + } catch (SyntaxError e) { + state = 1; + throw new SyntaxError("Opening \"<\" missing, found " + c + " [debug:initialCase]", 1); + } + } + case -1: + if (c == '>') { + throw new SyntaxError("Empty Statement?", 2, true); + } + state = -4; + tree = Main.htmlTags; + return handleClosingHTML(c); + case 1: + if (c == '<') { + throw new SyntaxError("Too many \"<\".", 1); + } else if (c == '>') { + state = 3; + throw new SyntaxError("Empty Statement?", 1); + } else { + state = 2; + return 1; + } + case 2: + //TODO finding special Twine statements: IF, ELSE... + if (c == '>') { + state = 3; + return 1; + } + break; + case 3: + if (c == '>') { + return 2; + } else if (c == ' ' || c == '=') { // assuming comparison + state = 2; + } else { + throw new SyntaxError("Closing \">\" missing [1]", 2); + } + break; + + case 4: + return handleOpeningHTML(c); + case -4: + return handleClosingHTML(c); + case 5: + if (c == '>') + return 2; + if (c == '@') //@ inside HTML tags is allowed + return 1; + break; + case -5: + if (c == '>') + return 2; + throw new SyntaxError("Closing \">\" missing [2]", 2); + default: + throw new UnknownState(state); + } + return 0; + } + + private int handleOpeningHTML(char c) throws SyntaxError { + if (c == ' ') { + state = 5; + if (tree.getElement() == null) { + throw new SyntaxError("Unknown HTML tag", 1); + } + return 1; + } + if (c == '>') { + if (tree.getElement() == null) { + throw new SyntaxError("Unknown HTML tag", 2); + } + return 2; + } + + tree = tree.getBranch(c); + if (tree == null) { + state = 5; + throw new SyntaxError("Unknown HTML tag or closing \">\" missing, found "+c, 1); + } + + return 1; + } + + private int handleClosingHTML(char c) throws SyntaxError { + if (c == '>') { + if (tree.getElement() == null) { + throw new SyntaxError("Unknown HTML tag", 2); + } + return 2; + } + + tree = tree.getBranch(c); + if (tree == null) { + state = -5; + throw new SyntaxError("Unknown HTML tag or closing \">\" missing, found "+c, 1); + } + + return 1; + } +} diff --git a/devTools/javaSanityCheck/src/element/AtElement.java b/devTools/javaSanityCheck/src/element/AtElement.java new file mode 100644 index 0000000000000000000000000000000000000000..cedf439542f43b2bed0459508f4836ad0a7e0bde --- /dev/null +++ b/devTools/javaSanityCheck/src/element/AtElement.java @@ -0,0 +1,72 @@ +package org.arkerthan.sanityCheck.element; + +import org.arkerthan.sanityCheck.SyntaxError; +import org.arkerthan.sanityCheck.UnknownState; + +public class AtElement extends Element { + private int state = 0; + // 0 = @ + // 1 = @@ + // 2 = @@. + // 3 = @@.a -- @@.ab -- @@.abc + // 4 = @@.abc;abc + // 5 = @@.abc;abc@ + + // example: @@.red;some text@@ + + @Override + public int handleChar(char c) throws SyntaxError { + switch (state) { + case 0: + state = 1; + if (c == '@') { + return 1; + } else { + if (c == '.') { + state = 2; + } + throw new SyntaxError("Opening \"@\" missing.", 1); + } + case 1: + if (c == '.') { + state = 2; + return 1; + } else { + state = 4; + throw new SyntaxError("\".\" missing, found \"" + c + "\". This might also indicate a " + + "missing closure in the previous color code.", 0, true); + } + case 2: + state = 3; + if (Character.isAlphabetic(c)) { + return 1; + } else { + throw new SyntaxError("Identifier might be wrong.", 1, true); + } + case 3: + if (c == ';') { + state = 4; + return 1; + } else if (c == ' ') { + state = 4; + throw new SyntaxError("\";\" missing or wrong space.", 1); + } + break; + case 4: + if (c == '@') { + state = 5; + return 1; + } + break; + case 5: + if (c == '@') { + return 2; + } else { + throw new SyntaxError("Closing \"@\" missing.", 2); + } + default: + throw new UnknownState(state); + } + return 0; + } +} diff --git a/devTools/javaSanityCheck/src/element/Element.java b/devTools/javaSanityCheck/src/element/Element.java new file mode 100644 index 0000000000000000000000000000000000000000..ed289d2decf21a6e461b1cbafadf061a7706a4d8 --- /dev/null +++ b/devTools/javaSanityCheck/src/element/Element.java @@ -0,0 +1,17 @@ +package org.arkerthan.sanityCheck.element; + +import org.arkerthan.sanityCheck.SyntaxError; + +public abstract class Element { + + /** + * Parses a Char and returns an int depending on the state of the element + * 0 - the Element did nothing + * 1 - the Element changed state + * 2 - the Element is finished + * @param c + * @return + * @throws Error + */ + public abstract int handleChar(char c) throws SyntaxError; +} diff --git a/devTools/javaSanityCheck/src/element/KnownElement.java b/devTools/javaSanityCheck/src/element/KnownElement.java new file mode 100644 index 0000000000000000000000000000000000000000..34390b7ef3efb04d784a1ccbdfaf86b5edf10e55 --- /dev/null +++ b/devTools/javaSanityCheck/src/element/KnownElement.java @@ -0,0 +1,44 @@ +package org.arkerthan.sanityCheck.element; + +import org.arkerthan.sanityCheck.SyntaxError; + +public class KnownElement extends Element { + + private boolean opening; + private String statement; + + public KnownElement(boolean opening, String statement) { + this.opening = opening; + this.statement = statement; + } + + @Override + public int handleChar(char c) throws SyntaxError { + return 0; + } + + /** + * @return true, if it needs another Known Element to close it. + */ + public boolean isOpening() { + return opening; + } + + /** + * @param k Element to be checked + * @return true if given Element closes Element + */ + public boolean isClosingElement(KnownElement k) { + return k.statement.equals(this.statement); + } + + /** + * Returns, if isOpening is true, the needed statement for closing, + * otherwise the statement that generated it. + * + * @return statement + */ + public String getStatement() { + return statement; + } +} diff --git a/sanityCheck-java b/sanityCheck-java new file mode 100755 index 0000000000000000000000000000000000000000..c564d01dfc659224509727bfa9098774f886dea2 --- /dev/null +++ b/sanityCheck-java @@ -0,0 +1 @@ +git ls-files "src/*.tw" | xargs java -jar SanityCheck.jar