Skip to content

Commit

Permalink
adding java parser, updating base_parser to support more language dif…
Browse files Browse the repository at this point in the history
…ferences
  • Loading branch information
njlg committed Apr 6, 2012
1 parent 1a1dfce commit e4f0c19
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 27 deletions.
52 changes: 25 additions & 27 deletions base_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

class BaseParser(object):

NO_RETURN_TYPE = 1
UNKNOWN_RETURN_TYPE = 2

def __init__(self, preferences={}):
self.preferences = preferences
self.setupSettings()
Expand All @@ -21,11 +24,11 @@ def isExistingComment(self, line):

def parse(self, line):
out = self.parseClass(line) # (name, extends)
if (out):
if out:
return self.formatClass(*out)

out = self.parseFunction(line) # (name, args)
if (out):
if out:
return self.formatFunction(*out)

out = self.parseVar(line)
Expand All @@ -46,8 +49,9 @@ def parseVar(self, line):
def escape(self, str):
return string.replace(str, '$', '\$')

def formatClass(self, name, base=None):
def formatClass(self, name, base=None, interface=None):
out = []

classname = 'Class'
if 'classname' in self.settings:
classname = self.settings['classname']
Expand All @@ -58,6 +62,9 @@ def formatClass(self, name, base=None):
if base:
out.append("Extends: %s" % base)

if interface:
out.append("Implements: %s" % interface)

return out

def formatVar(self, name, val):
Expand All @@ -69,16 +76,20 @@ def formatVar(self, name, val):

return out

def formatFunction(self, name, args):
def formatFunction(self, name, args, return_type=None):
out = []

out.append("Function: %s" % (name))
function_name = 'Function'
if 'function_name' in self.settings:
function_name = self.settings['function_name']

out.append("%s: %s" % (function_name, name))
out.append("${1:description}")

self.addExtraTags(out)

# if there are arguments, add a Parameter section for each
if (args):
if args:
# remove comments inside the argument list.
args = re.sub("/\*.*?\*/", '', args)
out.append("Parameters:")
Expand All @@ -96,16 +107,16 @@ def formatFunction(self, name, args):
if self.preferences.get("natural_docs_spacer_between_sections"):
out.append("")

retType = self.getFunctionReturnType(name)
if retType is not None:
if return_type is None:
return_type = self.getFunctionReturnType(name)

if return_type is not None and return_type is not self.NO_RETURN_TYPE:
out.append("Returns:")

if retType:
retType = "<" + retType + ">"
if return_type is not self.UNKNOWN_RETURN_TYPE:
out.append(" %s - ${1:return description}" % (return_type))
else:
retType = ""

out.append(" %s ${1:return description}" % (retType))
out.append(" ${1:return description}")

return out

Expand All @@ -129,20 +140,7 @@ def alignParameters(self, params):

def getFunctionReturnType(self, name):
""" returns None for no return type. False meaning unknown, or a string """
name = re.sub("^[$_]", "", name)

if re.match("[A-Z]", name):
# no return, but should add a class
return None

if re.match('(?:set|add)[A-Z_]', name):
# setter/mutator, no return
return None

if re.match('(?:is|has)[A-Z_]', name): # functions starting with 'is' or 'has'
return self.settings['bool']

return False
return self.UNKNOWN_RETURN_TYPE

def parseArgs(self, args):
""" an array of tuples, the first being the best guess at the type, the second being the name """
Expand Down
104 changes: 104 additions & 0 deletions parsers/java.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@

import re
from base_parser import BaseParser


class Parser(BaseParser):
def setupSettings(self):
self.settings = {
# curly brackets around the type information
'curlyTypes': True,
'typeTag': 'type',
# technically, they can contain all sorts of unicode, but whatever
'varIdentifier': '[a-zA-Z][a-zA-Z_0-9]*',
'fnIdentifier': '[a-zA-Z][a-zA-Z_0-9]*',
'classIdentifier': '[a-zA-Z][a-zA-Z_0-9]*',
'function_name': 'Method',
'block_start': '/**',
'block_middle': ' * ',
'block_end': '*/',
}

def parseClass(self, line):
# public class ArticlesDAO extends TableDAO {
res = re.search(
# Declaration
'class'
# Identifier
+ '\\s+(?P<name>' + self.settings['classIdentifier'] + ')'
# Extends (optional)
+ '(\\s+extends\\s+)?(?P<extends>' + self.settings['classIdentifier'] + ')?'
# Implements (optional)
+ '(\\s+implements\\s+)?(?P<implements>(' + self.settings['classIdentifier'] + ',?\s*)+)?',
line
)

if res:
return (res.group('name'), res.group('extends'), res.group('implements'))

return None

def parseFunction(self, line):
res = re.search(
# Modifier
'(public|private|protected|static|final|native|synchronized|abstract|threadsafe|transient)+'
# Type. Constructor has no type.
+ '\s+(?P<return>' + self.settings['fnIdentifier'] + ')?'
# Identifier
+ '(?:\s+(?P<name>' + self.settings['fnIdentifier'] + '))?'
# Parameter list
+ '\s*\((?P<args>.*)\)',
line
)

if not res:
return None

# grab the name out of "name1 = function name2(foo)" preferring name1
return_type = res.group('return')
name = res.group('name')
args = res.group('args')

if return_type is not None and name is None:
# Constructors do not have types, we need to flip these results
name = return_type
return_type = None

if return_type == 'void':
return_type = self.NO_RETURN_TYPE

return (name, args, return_type)

def parseVar(self, line):
res = re.search(
# <Type> foo = blah;
# baz.foo = blah;

'(?P<name>' + self.settings['varIdentifier'] + ')\s*[=]\s*(?P<val>.*?)(?:[;,]|$)',
line
)
if not res:
return None

return (res.group('name'), res.group('val').strip())

def parseArgs(self, args):
""" an array of tuples, the first being the best guess at the type, the second being the name """
out = []
for arg in re.split('\s*,\s*', args):
arg = arg.strip()
out.append(re.split('\s+', arg))
return out

def formatFunction(self, name, args, return_type=None):
"""
Override BaseParser to change Method to Construtor where applicable
"""
out = super(Parser, self).formatFunction(name, args, return_type)

# all methods must have a return type specified, therefore if there
# BaseParser did not find a return type this must be a constructor
if out[-2] != 'Returns:':
out[0] = out[0].replace('Method: ', 'Constructor: ')

return out

0 comments on commit e4f0c19

Please sign in to comment.