diff --git a/.gitignore b/.gitignore
index 7e00121..319057d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+*.swp
.sass-cache
.DS_Store
.my.cnf
@@ -39,3 +40,13 @@ nosetests.xml
.mr.developer.cfg
.project
.pydevproject
+
+# Maven
+target
+
+# Ruby
+!parsers/ruby/lib
+
+# Ctags
+*/tags
+log
diff --git a/README.md b/README.md
index 8ca31d7..96a93bc 100644
--- a/README.md
+++ b/README.md
@@ -32,3 +32,9 @@ root. Note that this will revert any custom changes made to the files in
`docs/source/api`, so you might want to update them by hand instead.
[SASS]: http://sass-lang.com/guide
+
+Releasing
+---------
+
+- Update `__version__` in `bitshift/__init__.py`, `version` in `setup.py`, and
+ `version` and `release` in `docs/conf.py`.
diff --git a/bitshift/__init__.py b/bitshift/__init__.py
index 78ca5e9..0bd031c 100644
--- a/bitshift/__init__.py
+++ b/bitshift/__init__.py
@@ -1 +1,8 @@
-from . import assets, codelet, config, database, parser, query, crawler
+# -*- coding: utf-8 -*-
+
+__author__ = "Benjamin Attal, Ben Kurtovic, Severyn Kozak"
+__copyright__ = "Copyright (c) 2014 Benjamin Attal, Ben Kurtovic, Severyn Kozak"
+__license__ = "MIT License"
+__version__ = "0.1.dev"
+
+from . import assets, codelet, config, crawler, database, parser, query
diff --git a/bitshift/codelet.py b/bitshift/codelet.py
index 453ace0..acaa52b 100644
--- a/bitshift/codelet.py
+++ b/bitshift/codelet.py
@@ -18,6 +18,8 @@ class Codelet(object):
code was last modified.
:ivar rank: (float) A quanitification of the source code's quality, as
per available ratings (stars, forks, upvotes, etc.).
+ :ivar symbols: (dict) Dictionary containing dictionaries of functions, classes,
+ variable definitions, etc.
"""
def __init__(self, name, code, filename, language, authors, code_url,
diff --git a/bitshift/languages.py b/bitshift/languages.py
new file mode 100644
index 0000000..b04c094
--- /dev/null
+++ b/bitshift/languages.py
@@ -0,0 +1,2 @@
+
+LANGS = ["Python", "C", "Java", "Ruby"]
diff --git a/bitshift/parser/__init__.py b/bitshift/parser/__init__.py
index e69de29..55c76e1 100644
--- a/bitshift/parser/__init__.py
+++ b/bitshift/parser/__init__.py
@@ -0,0 +1,93 @@
+import json, pygments.lexers as pgl, sys, socket, struct
+from ..languages import LANGS
+from .python import parse_py
+
+_all__ = ["parse"]
+
+class UnsupportedFileError(Exception):
+ pass
+
+def _lang(codelet):
+ """
+ Private function to identify the language of a codelet.
+
+ :param codelet: The codelet object to identified.
+
+ :type code: Codelet
+
+ .. todo::
+ Modify function to incorporate tags from stackoverflow.
+ """
+
+ if codelet.filename is not None:
+ try:
+ return pgl.guess_lexer_for_filename(codelet.filename, '').name
+ except:
+ raise UnsupportedFileError('Could not find a lexer for the codelet\'s filename')
+
+ return LANGS.index(pgl.guess_lexer(codelet.code))
+
+def _recv_data(server_socket):
+ """
+ Private function to read string response from a server. It reads a certain
+ amount of data based on the size it is sent from the server.
+
+ :param server_socket: The server that the client is connected to, and will,
+ read from.
+
+ :type code: socket.ServerSocket
+ """
+
+ recv_size = 8192
+ total_data = []; size_data = cur_data = ''
+ total_size = 0; size = sys.maxint
+
+ while total_size < size:
+ cur_data = server_socket.recv(recv_size)
+
+ if not total_data:
+ if len(size_data) > 4:
+ size_data += cur_data
+ size = struct.unpack('>i', size_data[:4])[0]
+ recv_size = size
+ if recv_size > sys.maxint: recv_size = sys.maxint
+ total_data.append(size_data[4:])
+ else:
+ size_data += cur_data
+
+ else:
+ total_data.append(cur_data)
+
+ total_size = sum([len(s) for s in total_data])
+
+ server_socket.close()
+ return ''.join(total_data);
+
+
+def parse(codelet):
+ """
+ Dispatches the codelet to the correct parser based on its language.
+ It is the job of the respective parsers to accumulate data about the
+ code and to convert it into a string representing a python dict.
+ The codelet is then given dict as its 'symbols' field.
+
+ :param codelet: The codelet object to parsed.
+
+ :type code: Codelet
+ """
+
+ lang = _lang(codelet); source = codelet.code
+ codelet.language = lang
+ server_socket_number = 5000 + lang
+
+ if lang == LANGS.index('Python'):
+ parse_py(codelet)
+
+ else:
+ server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ server_socket.connect(("localhost", server_socket_number))
+ server_socket.send("%d\n%s" % (len(source), source));
+
+ symbols = json.loads(_recv_data(server_socket))
+ codelet.symbols = symbols
+
diff --git a/bitshift/parser/c.py b/bitshift/parser/c.py
new file mode 100644
index 0000000..50ee6eb
--- /dev/null
+++ b/bitshift/parser/c.py
@@ -0,0 +1,106 @@
+from pycparser import c_parser, c_ast
+
+class _TreeCutter(c_ast.NodeVisitor):
+ """
+ Local node visitor for c abstract syntax trees.
+
+ :ivar accum: (dict) Information on variables, functions, and structs
+ accumulated from an abstract syntax tree.
+
+ :ivar cache: (dict or None) Information stored about parent nodes. Added
+ to accum when node reaches the lowest possible level.
+
+ .. todo::
+ Add visit function for c_ast.ID to record all uses of a variable.
+
+ Use self.cache to store extra information about variables.
+ """
+
+ def __init__(self):
+ """
+ Create a _TreeCutter instance.
+ """
+
+ self.accum = {'vars': {}, 'functions': {}, 'structs': {}}
+ self.cache = None
+
+ def start_n_end(self, node):
+ pass
+
+ def visit_FuncDecl(self, node):
+ """
+ Visits FuncDecl nodes in a tree. Adds relevant data about them to accum
+ after visiting all of its children as well.
+
+ :param node: The current node.
+
+ :type node: c_ast.FuncDecl
+
+ .. todo::
+ Add other relevant information about functions like parameters and
+ return type.
+ """
+
+ self.cache['group'] = 'functions'
+ self.cache['meta']['end_ln'] = node.coord.line
+ self.cache['meta']['end_col'] = node.coord.column
+
+ self.generic_visit(node)
+
+ def visit_Struct(self, node):
+ """
+ Visits Struct nodes in a tree. Adds relevant data about them to accum
+ after visiting all of its children as well.
+
+ :param node: The current node.
+
+ :type node: c_ast.Struct
+
+ .. todo::
+ Find other relevant information to add about structs.
+ """
+
+ self.cache['group'] = 'structs'
+ self.cache['meta']['end_ln'] = node.coord.line
+ self.cache['meta']['end_col'] = node.coord.column
+
+ self.generic_visit(node)
+
+ def visit_Decl(self, node):
+ """
+ Visits Decl nodes in a tree. Adds relevant data about them to accum
+ after visiting all of its children as well.
+
+ :param node: The current node.
+
+ :type node: c_ast.Decl
+ """
+
+ self.cache = {'group': 'vars', 'meta': {}}
+
+ self.cache['meta']['start_ln'] = node.coord.line
+ self.cache['meta']['start_col'] = node.coord.column
+ self.cache['meta']['end_ln'] = node.coord.line
+ self.cache['meta']['end_col'] = node.coord.column
+
+ self.generic_visit(node)
+
+ self.accum[self.cache['group']][node.name] = self.cache['meta']
+ self.cache = None
+
+def parse_c(codelet):
+ """
+ Adds 'symbols' field to the codelet after parsing the c code.
+
+ :param codelet: The codelet object to parsed.
+
+ :type code: Codelet
+
+ .. todo::
+ Preprocess c code so that no ParseErrors are thrown.
+ """
+
+ tree = c_parser.CParser().parse(codelet.code)
+ cutter = _TreeCutter()
+ cutter.visit(tree)
+ codelet.symbols = cutter.accum
diff --git a/bitshift/parser/python.py b/bitshift/parser/python.py
new file mode 100644
index 0000000..d0cd7d3
--- /dev/null
+++ b/bitshift/parser/python.py
@@ -0,0 +1,160 @@
+import ast
+
+class _CachedWalker(ast.NodeVisitor):
+ """
+ Local node visitor for python abstract syntax trees.
+
+ :ivar accum: (dict) Information on variables, functions, and classes
+ accumulated from an abstract syntax tree.
+
+ :ivar cache: (dict or None) Information stored about parent nodes. Added
+ to accum when node reaches the lowest possible level.
+
+ .. todo::
+ Add visit funciton for ast.Name to record all uses of a variable.
+
+ Use self.cache to store extra information about nodes.
+ """
+
+ def __init__(self):
+ """
+ Create a _TreeCutter instance.
+ """
+
+ self.accum = {'vars': {}, 'functions': {}, 'classes': {}}
+ self.cache = []
+
+ def block_position(self, node):
+ """
+ Helper function to get the start and end lines of an AST node.
+
+ :param node: The node.
+
+ :type node: ast.FunctionDef or ast.ClassDef or ast.Module
+ """
+
+ start_line, start_col = node.lineno, node.col_offset
+
+ temp_node = node
+ while 'body' in temp_node.__dict__:
+ temp_node = temp_node.body[-1]
+
+ end_line, end_col = temp_node.lineno, temp_node.col_offset
+ return (start_line, start_col, end_line, end_col)
+
+ def visit_Assign(self, node):
+ """
+ Visits Assign nodes in a tree. Adds relevant data about them to accum.
+
+ :param node: The current node.
+
+ :type node: ast.Assign
+
+ .. todo::
+ Add value and type metadata to accum.
+ """
+
+ line, col = node.lineno, node.col_offset
+ pos = (line, col, -1, -1)
+
+ self.cache.append({'nodes': []})
+ self.generic_visit(node)
+ last = self.cache.pop()
+
+ for name in last['nodes']:
+ if not self.accum['vars'].has_key(name):
+ self.accum['vars'][name] = {'assignments': [], 'uses': []}
+
+ self.accum['vars'][name]['assignments'].append(pos)
+
+
+ def visit_FunctionDef(self, node):
+ """
+ Visits FunctionDef nodes in a tree. Adds relevant data about them to accum.
+
+ :param node: The current node.
+
+ :type node: ast.FunctionDef
+
+ .. todo::
+ Add arguments and decorators metadata to accum.
+ """
+
+ start_line, start_col, end_line, end_col = self.block_position(node)
+
+ if not self.accum['functions'].has_key(node.name):
+ self.accum['functions'][node.name] = {'assignments': [], 'uses': []}
+
+ pos = (start_line, start_col, end_line, end_col)
+ self.accum['functions'][node.name]['assignments'].append(pos)
+
+ self.generic_visit(node)
+
+ def visit_Call(self, node):
+ """
+ Visits Function Call nodes in a tree. Adds relevant data about them
+ in the functions section for accum.
+
+ :param node: The current node.
+
+ :type node: ast.Call
+
+ .. todo::
+ Add arguments and decorators metadata to accum.
+ """
+
+ line, col = node.lineno, node.col_offset
+ pos = (line, col, -1, -1)
+
+ if isinstance(node.func, ast.Name):
+ name = node.func.id
+ else:
+ name = node.func.attr
+
+ if not self.accum['functions'].has_key(name):
+ self.accum['functions'][name] = {'assignments': [], 'uses': []}
+
+ self.accum['functions'][name]['uses'].append(pos)
+
+ def visit_ClassDef(self, node):
+ """
+ Visits ClassDef nodes in a tree. Adds relevant data about them to accum.
+
+ :param node: The current node.
+
+ :type node: ast.ClassDef
+
+ .. todo::
+ Add arguments, inherits, and decorators metadata to accum.
+ """
+
+ start_line, start_col, end_line, end_col = self.block_position(node)
+
+ pos = (start_line, start_col, end_line, end_col)
+ self.accum['classes'][node.name] = pos
+
+ self.generic_visit(node)
+
+ def visit_Name(self, node):
+ if self.cache:
+ last = self.cache[-1]
+ last['nodes'].append(node.id)
+
+ def visit_Attribute(self, node):
+ if self.cache:
+ last = self.cache[-1]
+ last['nodes'].append(node.attr)
+
+def parse_py(codelet):
+ """
+ Adds 'symbols' field to the codelet after parsing the python code.
+
+ :param codelet: The codelet object to parsed.
+
+ :type code: Codelet
+ """
+
+ tree = ast.parse(codelet.code)
+ cutter = _CachedWalker()
+ cutter.visit(tree)
+ codelet.symbols = cutter.accum
diff --git a/docs/source/api/bitshift.crawler.rst b/docs/source/api/bitshift.crawler.rst
new file mode 100644
index 0000000..2add004
--- /dev/null
+++ b/docs/source/api/bitshift.crawler.rst
@@ -0,0 +1,27 @@
+crawler Package
+===============
+
+:mod:`crawler` Package
+----------------------
+
+.. automodule:: bitshift.crawler
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`crawler` Module
+---------------------
+
+.. automodule:: bitshift.crawler.crawler
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`indexer` Module
+---------------------
+
+.. automodule:: bitshift.crawler.indexer
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
diff --git a/docs/source/api/bitshift.database.rst b/docs/source/api/bitshift.database.rst
new file mode 100644
index 0000000..38e20b6
--- /dev/null
+++ b/docs/source/api/bitshift.database.rst
@@ -0,0 +1,19 @@
+database Package
+================
+
+:mod:`database` Package
+-----------------------
+
+.. automodule:: bitshift.database
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`migration` Module
+-----------------------
+
+.. automodule:: bitshift.database.migration
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
diff --git a/docs/source/api/bitshift.rst b/docs/source/api/bitshift.rst
index 1b1c703..388ac71 100644
--- a/docs/source/api/bitshift.rst
+++ b/docs/source/api/bitshift.rst
@@ -33,19 +33,13 @@ bitshift Package
:undoc-members:
:show-inheritance:
-:mod:`database` Module
-----------------------
-
-.. automodule:: bitshift.database
- :members:
- :undoc-members:
- :show-inheritance:
-
Subpackages
-----------
.. toctree::
+ bitshift.crawler
+ bitshift.database
bitshift.parser
bitshift.query
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 5aee357..1f9d1be 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -59,7 +59,7 @@ copyright = u'2014, Benjamin Attal, Ben Kurtovic, Severyn Kozak'
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
-release = '0.1'
+release = '0.1.dev'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/parsers/java/pom.xml b/parsers/java/pom.xml
new file mode 100644
index 0000000..c2191b0
--- /dev/null
+++ b/parsers/java/pom.xml
@@ -0,0 +1,40 @@
+
+ 4.0.0
+
+ com.bitshift.parsing
+ parsing
+ jar
+ 1.0-SNAPSHOT
+ parsing
+ http://maven.apache.org
+
+
+
+ junit
+ junit
+ 4.11
+
+
+ org.eclipse.jdt
+ org.eclipse.jdt.core
+ 3.7.1
+
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.2.1
+
+ com.bitshift.parsing.Parse
+
+
+
+
+
+
+
+
diff --git a/parsers/java/src/main/java/com/bitshift/parsing/Parse.java b/parsers/java/src/main/java/com/bitshift/parsing/Parse.java
new file mode 100644
index 0000000..fc1d36f
--- /dev/null
+++ b/parsers/java/src/main/java/com/bitshift/parsing/Parse.java
@@ -0,0 +1,33 @@
+package com.bitshift.parsing;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.IOException;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import com.bitshift.parsing.parsers.JavaParser;
+
+public class Parse {
+
+ public static void main(String[] args) {
+ String fromClient;
+ String toClient;
+
+ try {
+ ServerSocket server = new ServerSocket(5002);
+
+ while(true) {
+ Socket clientSocket = server.accept();
+
+ JavaParser parser = new JavaParser(clientSocket);
+ Thread parserTask = new Thread(parser);
+ parserTask.start();
+ }
+ } catch (IOException ex) {
+ }
+ }
+
+}
diff --git a/parsers/java/src/main/java/com/bitshift/parsing/parsers/CParser.java b/parsers/java/src/main/java/com/bitshift/parsing/parsers/CParser.java
new file mode 100644
index 0000000..dbe93fb
--- /dev/null
+++ b/parsers/java/src/main/java/com/bitshift/parsing/parsers/CParser.java
@@ -0,0 +1,3 @@
+package com.bitshift.parsing.parsers;
+
+import com.bitshift.parsing.parsers.Parser;
diff --git a/parsers/java/src/main/java/com/bitshift/parsing/parsers/JavaParser.java b/parsers/java/src/main/java/com/bitshift/parsing/parsers/JavaParser.java
new file mode 100644
index 0000000..4ba3623
--- /dev/null
+++ b/parsers/java/src/main/java/com/bitshift/parsing/parsers/JavaParser.java
@@ -0,0 +1,221 @@
+package com.bitshift.parsing.parsers;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import java.net.Socket;
+
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTParser;
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.ClassInstanceCreation;
+import org.eclipse.jdt.core.dom.FieldDeclaration;
+import org.eclipse.jdt.core.dom.MethodDeclaration;
+import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.Name;
+import org.eclipse.jdt.core.dom.PackageDeclaration;
+import org.eclipse.jdt.core.dom.QualifiedName;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.Statement;
+import org.eclipse.jdt.core.dom.TypeDeclaration;
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+
+import com.bitshift.parsing.parsers.Parser;
+import com.bitshift.parsing.symbols.Symbols;
+import com.bitshift.parsing.symbols.JavaSymbols;
+
+/*TODO: Work on parsing partial java code.*/
+public class JavaParser extends Parser {
+
+ public JavaParser(Socket clientSocket) {
+ super(clientSocket);
+ }
+
+ @Override
+ protected Symbols genSymbols() {
+ char[] source = this.readFromClient().toCharArray();
+
+ ASTParser parser = ASTParser.newParser(AST.JLS3);
+ parser.setSource(source);
+
+ Map options = JavaCore.getOptions();
+ parser.setCompilerOptions(options);
+
+ CompilationUnit root = (CompilationUnit) parser.createAST(null);
+
+ NodeVisitor visitor = new NodeVisitor(root);
+ root.accept(visitor);
+
+ return visitor.symbols;
+ }
+
+ @Override
+ public void run() {
+ JavaSymbols symbols = (JavaSymbols) this.genSymbols();
+ writeToClient(symbols.toString());
+ }
+
+ class NodeVisitor extends ASTVisitor {
+
+ protected CompilationUnit root;
+ protected JavaSymbols symbols;
+ private Stack> _cache;
+
+ public NodeVisitor(CompilationUnit root) {
+ this.root = root;
+ this.symbols = new JavaSymbols();
+ this._cache = new Stack>();
+ }
+
+ public boolean visit(FieldDeclaration node) {
+ HashMap data = new HashMap();
+ int sl = this.root.getLineNumber(node.getStartPosition());
+ int sc = this.root.getColumnNumber(node.getStartPosition());
+
+ data.put("coord", Symbols.createCoord(sl, sc, -1, -1));
+ this._cache.push(data);
+ return true;
+ }
+
+ public void endVisit(FieldDeclaration node) {
+ HashMap data = this._cache.pop();
+ String name = (String)data.remove("name");
+ this.symbols.insertFieldDeclaration(name, data);
+ }
+
+ public boolean visit(MethodDeclaration node) {
+ HashMap data = new HashMap();
+ Name nameObj = node.getName();
+ String name = nameObj.isQualifiedName() ?
+ ((QualifiedName) nameObj).getFullyQualifiedName() :
+ ((SimpleName) nameObj).getIdentifier();
+ List statements = node.getBody().statements();
+
+ int sl = this.root.getLineNumber(node.getStartPosition());
+ int sc = this.root.getColumnNumber(node.getStartPosition());
+ Integer el = -1;
+ Integer ec = -1;
+
+ if (statements.size() > 0) {
+ Statement last = statements.get(statements.size() - 1);
+ el = this.root.getLineNumber(last.getStartPosition());
+ ec = this.root.getColumnNumber(last.getStartPosition());
+ }
+
+ data.put("coord", Symbols.createCoord(sl, sc, el, ec));
+ data.put("name", name);
+ this._cache.push(data);
+ return true;
+ }
+
+ public void endVisit(MethodDeclaration node) {
+ HashMap data = this._cache.pop();
+ String name = (String)data.remove("name");
+ this.symbols.insertMethodDeclaration(name, data);
+ }
+
+ public boolean visit(MethodInvocation node) {
+ HashMap data = new HashMap();
+ Name nameObj = node.getName();
+ String name = nameObj.isQualifiedName() ?
+ ((QualifiedName) nameObj).getFullyQualifiedName() :
+ ((SimpleName) nameObj).getIdentifier();
+ int sl = this.root.getLineNumber(node.getStartPosition());
+ int sc = this.root.getColumnNumber(node.getStartPosition());
+
+ data.put("coord", Symbols.createCoord(sl, sc, -1, -1));
+ data.put("name", name);
+ this._cache.push(data);
+ return true;
+ }
+
+ public void endVisit(MethodInvocation node) {
+ HashMap data = this._cache.pop();
+ String name = (String)data.remove("name");
+ this.symbols.insertMethodInvocation(name, data);
+ }
+
+ public boolean visit(PackageDeclaration node) {
+ HashMap data = new HashMap();
+ this._cache.push(data);
+ return true;
+ }
+
+ public void endVisit(PackageDeclaration node) {
+ HashMap data = this._cache.pop();
+ String name = (String)data.remove("name");
+ this.symbols.setPackage(name);
+ }
+
+ public boolean visit(TypeDeclaration node) {
+ HashMap data = new HashMap();
+
+ int sl = this.root.getLineNumber(node.getStartPosition());
+ int sc = this.root.getColumnNumber(node.getStartPosition());
+
+ data.put("coord", Symbols.createCoord(sl, sc, -1, -1));
+ this._cache.push(data);
+ return true;
+ }
+
+ public void endVisit(TypeDeclaration node) {
+ HashMap data = this._cache.pop();
+ String name = (String)data.remove("name");
+
+ if (node.isInterface()) {
+ this.symbols.insertInterfaceDeclaration(name, data);
+ } else {
+ this.symbols.insertClassDeclaration(name, data);
+ }
+ }
+
+ public boolean visit(VariableDeclarationFragment node) {
+ HashMap data = new HashMap();
+ int sl = this.root.getLineNumber(node.getStartPosition());
+ int sc = this.root.getColumnNumber(node.getStartPosition());
+
+ data.put("coord", Symbols.createCoord(sl, sc, -1, -1));
+ this._cache.push(data);
+ return true;
+ }
+
+ public void endVisit(VariableDeclarationFragment node) {
+ HashMap data = this._cache.pop();
+ String name = (String)data.remove("name");
+ this.symbols.insertVariableDeclaration(name, data);
+ }
+
+ public boolean visit(QualifiedName node) {
+ if (!this._cache.empty()) {
+ HashMap data = this._cache.pop();
+
+ if(!data.containsKey("name")) {
+ String name = node.getFullyQualifiedName();
+ data.put("name", name);
+ }
+
+ this._cache.push(data);
+ }
+ return true;
+ }
+
+ public boolean visit(SimpleName node) {
+ if (!this._cache.empty()) {
+ HashMap data = this._cache.pop();
+
+ if(!data.containsKey("name")) {
+ String name = node.getIdentifier();
+ data.put("name", name);
+ }
+
+ this._cache.push(data);
+ }
+ return true;
+ }
+
+ }
+}
diff --git a/parsers/java/src/main/java/com/bitshift/parsing/parsers/Parser.java b/parsers/java/src/main/java/com/bitshift/parsing/parsers/Parser.java
new file mode 100644
index 0000000..9d00954
--- /dev/null
+++ b/parsers/java/src/main/java/com/bitshift/parsing/parsers/Parser.java
@@ -0,0 +1,64 @@
+package com.bitshift.parsing.parsers;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.IOException;
+
+import java.net.Socket;
+
+import com.bitshift.parsing.symbols.Symbols;
+import com.bitshift.parsing.utils.PackableMemory;
+
+public abstract class Parser implements Runnable {
+
+ protected Socket clientSocket;
+
+ public Parser(Socket clientSocket) {
+ this.clientSocket = clientSocket;
+ }
+
+ protected String readFromClient() {
+ String fromClient = "";
+
+ try {
+ BufferedReader clientReader = new BufferedReader(
+ new InputStreamReader(this.clientSocket.getInputStream()));
+
+ int bytes = Integer.parseInt(clientReader.readLine());
+
+ StringBuilder builder = new StringBuilder();
+ int i = 0;
+
+ while(i < bytes) {
+ char aux = (char)clientReader.read();
+ builder.append(aux);
+ i++;
+ }
+
+ fromClient = builder.toString();
+
+ } catch (IOException ex) {
+ }
+
+ return fromClient;
+ }
+
+ protected void writeToClient(String toClient) {
+ try {
+ PrintWriter clientWriter = new PrintWriter(
+ this.clientSocket.getOutputStream(), true);
+
+ PackableMemory mem = new PackableMemory(toClient.length());
+ String dataSize = new String(mem.mem);
+ clientWriter.println(dataSize + toClient);
+ } catch (IOException ex) {
+ }
+ }
+
+ protected abstract Symbols genSymbols();
+
+ public abstract void run();
+
+}
+
diff --git a/parsers/java/src/main/java/com/bitshift/parsing/symbols/CSymbols.java b/parsers/java/src/main/java/com/bitshift/parsing/symbols/CSymbols.java
new file mode 100644
index 0000000..9abd60d
--- /dev/null
+++ b/parsers/java/src/main/java/com/bitshift/parsing/symbols/CSymbols.java
@@ -0,0 +1 @@
+package com.bitshift.parsing.symbols;
diff --git a/parsers/java/src/main/java/com/bitshift/parsing/symbols/JavaSymbols.java b/parsers/java/src/main/java/com/bitshift/parsing/symbols/JavaSymbols.java
new file mode 100644
index 0000000..5419d5a
--- /dev/null
+++ b/parsers/java/src/main/java/com/bitshift/parsing/symbols/JavaSymbols.java
@@ -0,0 +1,147 @@
+package com.bitshift.parsing.symbols;
+
+import java.util.HashMap;
+import java.util.ArrayList;
+import com.bitshift.parsing.symbols.Symbols;
+
+/*TODO: Overwrite toString.*/
+public class JavaSymbols extends Symbols {
+
+ private String _packageName;
+ private HashMap> _classes;
+ private HashMap> _interfaces;
+ private HashMap> _methods;
+ private HashMap> _fields;
+ private HashMap> _vars;
+
+ public JavaSymbols() {
+ _packageName = null;
+ _classes = new HashMap>();
+ _interfaces = new HashMap>();
+ _methods = new HashMap>();
+ _fields = new HashMap>();
+ _vars = new HashMap>();
+ }
+
+ public boolean setPackage(String name) {
+ _packageName = name;
+ return true;
+ }
+
+ public boolean insertClassDeclaration(String name, HashMap data) {
+ ArrayList