java syntax parser
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 7 Jul 2013 20:01:07 +0000 (23:01 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 7 Jul 2013 20:01:07 +0000 (23:01 +0300)
src/main/java/eu/svjatoslav/inspector/java/methods/ClassReference.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/inspector/java/methods/Clazz.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/inspector/java/methods/EnumerationBuffer.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/inspector/java/methods/JavaFile.java
src/main/java/eu/svjatoslav/inspector/java/methods/Modifiers.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/inspector/java/methods/Package.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/inspector/java/methods/Project.java
src/main/java/eu/svjatoslav/inspector/java/methods/ProjectScanner.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/inspector/tokenizer/InvalidSyntaxException.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/inspector/tokenizer/Tokenizer.java

diff --git a/src/main/java/eu/svjatoslav/inspector/java/methods/ClassReference.java b/src/main/java/eu/svjatoslav/inspector/java/methods/ClassReference.java
new file mode 100644 (file)
index 0000000..43d7625
--- /dev/null
@@ -0,0 +1,48 @@
+package eu.svjatoslav.inspector.java.methods;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import eu.svjatoslav.inspector.tokenizer.InvalidSyntaxException;
+import eu.svjatoslav.inspector.tokenizer.Tokenizer;
+
+public class ClassReference {
+
+       public String name;
+
+       List<ClassReference> typeParameters = new ArrayList<ClassReference>();
+
+       public ClassReference(final Tokenizer tokenizer)
+                       throws InvalidSyntaxException {
+               name = tokenizer.getToken().token;
+
+               if (!tokenizer.isNextToken("<"))
+                       return;
+
+               while (true) {
+                       final ClassReference parameterType = new ClassReference(tokenizer);
+                       typeParameters.add(parameterType);
+
+                       if (!tokenizer.isNextToken(","))
+                               break;
+               }
+
+               tokenizer.expectToken(">");
+       }
+
+       @Override
+       public String toString() {
+               final EnumerationBuffer result = new EnumerationBuffer();
+
+               result.append(name);
+
+               if (typeParameters.size() > 0) {
+                       result.append("<");
+                       for (final ClassReference classReference : typeParameters)
+                               result.appendEnumeration(classReference.toString());
+                       result.append(">");
+               }
+
+               return result.toString();
+       }
+}
diff --git a/src/main/java/eu/svjatoslav/inspector/java/methods/Clazz.java b/src/main/java/eu/svjatoslav/inspector/java/methods/Clazz.java
new file mode 100644 (file)
index 0000000..fda73d1
--- /dev/null
@@ -0,0 +1,73 @@
+package eu.svjatoslav.inspector.java.methods;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import eu.svjatoslav.inspector.tokenizer.InvalidSyntaxException;
+import eu.svjatoslav.inspector.tokenizer.Tokenizer;
+import eu.svjatoslav.inspector.tokenizer.TokenizerMatch;
+
+public class Clazz {
+
+       private final String packageName;
+       private final String className;
+
+       public ClassReference superClass;
+       public List<ClassReference> implementedInterfaces = new ArrayList<ClassReference>();
+
+       public Clazz(final String packageName, final String className,
+                       final Tokenizer tokenizer) throws InvalidSyntaxException {
+               this.packageName = packageName;
+               this.className = className;
+
+               while (true) {
+                       final TokenizerMatch match = tokenizer.getToken();
+
+                       if ("extends".equals(match.token)) {
+                               superClass = new ClassReference(tokenizer);
+                               continue;
+                       }
+
+                       if ("implements".equals(match.token)) {
+                               while (true) {
+                                       implementedInterfaces.add(new ClassReference(tokenizer));
+
+                                       if (tokenizer.isNextToken(","))
+                                               continue;
+
+                                       break;
+                               }
+                               continue;
+                       }
+
+                       if ("{".equals(match.token)) {
+                               parseClassBody(tokenizer);
+                               break;
+                       }
+
+               }
+       }
+
+       public void parseClassBody(final Tokenizer tokenizer) {
+               tokenizer.skipUtilEnd();
+       }
+
+       @Override
+       public String toString() {
+               final EnumerationBuffer result = new EnumerationBuffer();
+
+               result.append(packageName + " -> " + className + "\n");
+               if (superClass != null)
+                       result.append("    super: " + superClass.toString() + "\n");
+
+               if (implementedInterfaces.size() > 0) {
+                       result.append("    implements: ");
+                       for (final ClassReference classReference : implementedInterfaces)
+                               result.appendEnumeration(classReference.toString());
+                       result.append("\n");
+               }
+
+               return result.toString();
+       }
+
+}
diff --git a/src/main/java/eu/svjatoslav/inspector/java/methods/EnumerationBuffer.java b/src/main/java/eu/svjatoslav/inspector/java/methods/EnumerationBuffer.java
new file mode 100644 (file)
index 0000000..0dcf853
--- /dev/null
@@ -0,0 +1,40 @@
+package eu.svjatoslav.inspector.java.methods;
+
+public class EnumerationBuffer {
+
+       private final String enumerationDelimiter;
+
+       private final StringBuffer buffer = new StringBuffer();
+
+       public int enumeratedEntitiesCount = 0;
+
+       public EnumerationBuffer() {
+               this(", ");
+       }
+
+       public EnumerationBuffer(final String enumerationDelimiter) {
+               this.enumerationDelimiter = enumerationDelimiter;
+       }
+
+       public void append(final String value) {
+               buffer.append(value);
+       }
+
+       public void appendEnumeration(final String value) {
+               if (enumeratedEntitiesCount > 0)
+                       buffer.append(enumerationDelimiter);
+
+               buffer.append(value);
+               enumeratedEntitiesCount++;
+       }
+
+       public void resetEnumeration() {
+               enumeratedEntitiesCount = 0;
+       }
+
+       @Override
+       public String toString() {
+               return buffer.toString();
+       }
+
+}
index 5b636d6..400ff87 100644 (file)
@@ -8,6 +8,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
+import eu.svjatoslav.inspector.tokenizer.InvalidSyntaxException;
 import eu.svjatoslav.inspector.tokenizer.Tokenizer;
 import eu.svjatoslav.inspector.tokenizer.TokenizerMatch;
 
@@ -15,16 +16,18 @@ public class JavaFile {
 
        private final List<Import> imports = new ArrayList<Import>();
 
+       private String packageName;
+
        private final File file;
 
        StringBuffer contents = new StringBuffer();
 
-       public JavaFile(final File file) throws IOException {
+       public JavaFile(final File file) throws IOException, InvalidSyntaxException {
                this.file = file;
                parse();
        }
 
-       public void parse() throws IOException {
+       public void parse() throws IOException, InvalidSyntaxException {
                System.out.println("java file: " + file);
 
                readFile();
@@ -41,26 +44,59 @@ public class JavaFile {
                tokenizer.addTerminator(")", false);
                tokenizer.addTerminator("[", false);
                tokenizer.addTerminator("]", false);
+               tokenizer.addTerminator("<", false);
+               tokenizer.addTerminator(">", false);
+               tokenizer.addTerminator(",", false);
+
+               final Modifiers modifiers = new Modifiers();
 
                while (true) {
                        final TokenizerMatch match = tokenizer.getToken();
                        if (match == null)
                                break;
 
-                       if (match.token.equals("import"))
-                               parseImport(tokenizer);
-
-                       if (match.token.equals("package"))
+                       if (match.token.equals("package")) {
                                parsePackage(tokenizer);
+                               continue;
+                       }
 
+                       if (match.token.equals("import")) {
+                               parseImport(tokenizer);
+                               continue;
+                       }
+
+                       final boolean wasModifier = modifiers.parseModifier(match.token);
+                       if (wasModifier)
+                               continue;
+
+                       if ("class".equals(match.token)) {
+                               parseClass(tokenizer);
+                               continue;
+                       }
+
+                       System.out.println("    " + modifiers.toString() + " "
+                                       + match.token);
+                       modifiers.reset();
+                       skipUntilSemicolon(tokenizer);
                }
 
        }
 
-       private void parseImport(final Tokenizer tokenizer) {
+       private void parseClass(final Tokenizer tokenizer)
+                       throws InvalidSyntaxException {
+
+               final TokenizerMatch match = tokenizer.getToken();
+               final Clazz clazz = new Clazz(packageName, match.token, tokenizer);
+               System.out.println(clazz.toString());
+
+       }
+
+       private void parseImport(final Tokenizer tokenizer)
+                       throws InvalidSyntaxException {
+
                final Import imp = new Import();
 
-               TokenizerMatch match = tokenizer.getToken();
+               final TokenizerMatch match = tokenizer.getToken();
 
                if (match.token.equals("static")) {
                        imp.isStatic = true;
@@ -70,18 +106,17 @@ public class JavaFile {
 
                imports.add(imp);
 
-               // ;
-               match = tokenizer.getToken();
+               tokenizer.expectToken(";");
        }
 
-       private void parsePackage(final Tokenizer tokenizer) {
+       private void parsePackage(final Tokenizer tokenizer)
+                       throws InvalidSyntaxException {
 
-               TokenizerMatch match = tokenizer.getToken();
+               final TokenizerMatch match = tokenizer.getToken();
 
-               System.out.println(match.token);
+               packageName = match.token;
 
-               // ;
-               match = tokenizer.getToken();
+               tokenizer.expectToken(";");
        }
 
        private void readFile() throws FileNotFoundException, IOException {
@@ -103,4 +138,12 @@ public class JavaFile {
                fileReader.close();
        }
 
+       public void skipUntilSemicolon(final Tokenizer tokenizer) {
+               while (true) {
+                       final TokenizerMatch token = tokenizer.getToken();
+                       if (token.token.equals(";"))
+                               return;
+               }
+       }
+
 }
diff --git a/src/main/java/eu/svjatoslav/inspector/java/methods/Modifiers.java b/src/main/java/eu/svjatoslav/inspector/java/methods/Modifiers.java
new file mode 100644 (file)
index 0000000..747d7db
--- /dev/null
@@ -0,0 +1,68 @@
+package eu.svjatoslav.inspector.java.methods;
+
+public class Modifiers {
+
+       public enum Access {
+               PUBLIC("public"), PROTECTED("protected"), DEFAULT(""), PRIVATE(
+                               "private");
+
+               public final String name;
+
+               Access(final String name) {
+                       this.name = name;
+               };
+       }
+
+       Access access = Access.DEFAULT;
+
+       boolean isStatic = false;;
+
+       boolean isFinal = false;
+
+       public boolean parseModifier(final String string) {
+               for (final Access access : Access.values())
+                       if (access.name.equals(string)) {
+                               this.access = access;
+                               return true;
+                       }
+
+               if ("static".equals(string)) {
+                       isStatic = true;
+                       return true;
+               }
+
+               if ("final".equals(string)) {
+                       isFinal = true;
+                       return true;
+               }
+
+               return false;
+       }
+
+       public void reset() {
+               isStatic = false;
+               isFinal = false;
+               access = Access.DEFAULT;
+       }
+
+       @Override
+       public String toString() {
+               final StringBuffer result = new StringBuffer();
+
+               result.append(access.name);
+
+               if (isStatic) {
+                       if (result.length() > 0)
+                               result.append(" ");
+                       result.append("static");
+               }
+
+               if (isFinal) {
+                       if (result.length() > 0)
+                               result.append(" ");
+                       result.append("final");
+               }
+
+               return result.toString();
+       }
+}
diff --git a/src/main/java/eu/svjatoslav/inspector/java/methods/Package.java b/src/main/java/eu/svjatoslav/inspector/java/methods/Package.java
new file mode 100644 (file)
index 0000000..9a98a7d
--- /dev/null
@@ -0,0 +1,10 @@
+package eu.svjatoslav.inspector.java.methods;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Package {
+
+       Map<String, Clazz> classes = new HashMap<String, Clazz>();
+
+}
index 2688e78..b3a87cc 100644 (file)
@@ -1,55 +1,10 @@
 package eu.svjatoslav.inspector.java.methods;
 
-import java.io.File;
-import java.io.IOException;
-
-import eu.svjatoslav.commons.file.FilePathParser;
+import java.util.HashMap;
+import java.util.Map;
 
 public class Project {
 
-       private final File projectPath;
-
-       public Project(final File projectPath) {
-               this.projectPath = projectPath;
-               parse();
-       }
-
-       public void parse() {
-
-               if (!projectPath.exists())
-                       System.out.println("Project not found on path: " + projectPath);
-
-               if (!projectPath.canRead())
-                       System.out.println("Cannot read project path: " + projectPath);
-
-               if (projectPath.isDirectory())
-                       parseDirectory(projectPath);
-
-               if (projectPath.isFile())
-                       parseFile(projectPath);
-       }
-
-       public void parseDirectory(final File file) {
-
-               for (final File subFile : file.listFiles()) {
-
-                       if (subFile.isFile())
-                               parseFile(subFile);
-
-                       if (subFile.isDirectory())
-                               parseDirectory(subFile);
-               }
-       }
-
-       public void parseFile(final File file) {
-               final String fileExtension = FilePathParser.getFileExtension(file);
-               if ("java".equalsIgnoreCase(fileExtension))
-                       try {
-                               final JavaFile javaFile = new JavaFile(file);
-                       } catch (final IOException e) {
-                               System.out.println("Error parsing file: " + file.toString()
-                                               + ", " + e.toString());
-                       }
-       }
+       Map<String, Package> packages = new HashMap<String, Package>();
 
 }
diff --git a/src/main/java/eu/svjatoslav/inspector/java/methods/ProjectScanner.java b/src/main/java/eu/svjatoslav/inspector/java/methods/ProjectScanner.java
new file mode 100644 (file)
index 0000000..3ed5a31
--- /dev/null
@@ -0,0 +1,63 @@
+package eu.svjatoslav.inspector.java.methods;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import eu.svjatoslav.commons.file.FilePathParser;
+import eu.svjatoslav.inspector.tokenizer.InvalidSyntaxException;
+
+public class ProjectScanner {
+
+       private final File scanPath;
+
+       Map<File, Project> projects = new HashMap<File, Project>();
+
+       public ProjectScanner(final File projectPath) {
+               scanPath = projectPath;
+               parse();
+       }
+
+       public void parse() {
+
+               if (!scanPath.exists())
+                       System.out.println("Path not found: " + scanPath);
+
+               if (!scanPath.canRead())
+                       System.out.println("Cannot read path: " + scanPath);
+
+               if (scanPath.isDirectory())
+                       parseDirectory(scanPath);
+
+               if (scanPath.isFile())
+                       parseFile(scanPath);
+       }
+
+       public void parseDirectory(final File file) {
+
+               for (final File subFile : file.listFiles()) {
+
+                       if (subFile.isFile())
+                               parseFile(subFile);
+
+                       if (subFile.isDirectory())
+                               parseDirectory(subFile);
+               }
+       }
+
+       public void parseFile(final File file) {
+               final String fileExtension = FilePathParser.getFileExtension(file);
+               if ("java".equalsIgnoreCase(fileExtension))
+                       try {
+                               final JavaFile javaFile = new JavaFile(file);
+                       } catch (final IOException e) {
+                               System.out.println("Error parsing file: " + file.toString()
+                                               + ": " + e.toString());
+                       } catch (final InvalidSyntaxException e) {
+                               System.out.println("Syntax error occured while parsing file: "
+                                               + file.toString() + ": " + e.toString());
+                       }
+       }
+
+}
diff --git a/src/main/java/eu/svjatoslav/inspector/tokenizer/InvalidSyntaxException.java b/src/main/java/eu/svjatoslav/inspector/tokenizer/InvalidSyntaxException.java
new file mode 100644 (file)
index 0000000..1d47f4c
--- /dev/null
@@ -0,0 +1,11 @@
+package eu.svjatoslav.inspector.tokenizer;
+
+public class InvalidSyntaxException extends Exception {
+
+       private static final long serialVersionUID = 88294980027680555L;
+
+       public InvalidSyntaxException(final String cause) {
+               super(cause);
+       }
+
+}
index 97f1224..8a42776 100644 (file)
@@ -2,12 +2,15 @@ package eu.svjatoslav.inspector.tokenizer;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Stack;
 
 public class Tokenizer {
 
        private final List<Terminator> terminators = new ArrayList<Terminator>();
        private final String source;
 
+       Stack<Integer> tokenIndexes = new Stack<Integer>();
+
        private int currentIndex = 0;
 
        public Tokenizer(final String source) {
@@ -19,7 +22,15 @@ public class Tokenizer {
                terminators.add(new Terminator(terminator, empty));
        }
 
+       public void expectToken(final String value) throws InvalidSyntaxException {
+               final TokenizerMatch match = getToken();
+               if (!value.equals(match.token))
+                       throw new InvalidSyntaxException("Expected \"" + value
+                                       + "\" but got \"" + match.token + "\" instead.");
+       }
+
        public TokenizerMatch getToken() {
+               tokenIndexes.push(currentIndex);
                final StringBuffer result = new StringBuffer();
 
                while (true) {
@@ -55,6 +66,23 @@ public class Tokenizer {
 
        }
 
+       public boolean isNextToken(final String token) {
+               if (token.equals(getToken().token))
+                       return true;
+
+               rollbackToken();
+               return false;
+       }
+
+       public void rollbackToken() {
+               currentIndex = tokenIndexes.pop();
+       }
+
+       public void skipUtilEnd() {
+               tokenIndexes.push(currentIndex);
+               currentIndex = source.length();
+       }
+
        public boolean terminatorMatches(final Terminator terminator) {
                if ((currentIndex + terminator.value.length()) > source.length())
                        return false;