summaryrefslogtreecommitdiff
path: root/scipy/base/code_generators/genapi.py
diff options
context:
space:
mode:
authorcookedm <cookedm@localhost>2005-12-06 11:10:13 +0000
committercookedm <cookedm@localhost>2005-12-06 11:10:13 +0000
commitc6e97c7886750ffd6d6623ec6a1510c566cb3b50 (patch)
tree60e9c8e96ed9fdfbc5798a603758ba9c540c79b7 /scipy/base/code_generators/genapi.py
parentaeccfe653e5429fc1debe38af415ec9a1ce4cfc1 (diff)
downloadnumpy-c6e97c7886750ffd6d6623ec6a1510c566cb3b50.tar.gz
The declarations for API functions are now read directly from the source files, using the /*OBJECT_API*/ (and similiar) tags.
The order of the API functions is determined by the *_api_order.txt files in code_generators/. Also, the code_generators/generate_*.py files are imported instead of using execfile() in setup.py, with common routines held in genapi.py.
Diffstat (limited to 'scipy/base/code_generators/genapi.py')
-rw-r--r--scipy/base/code_generators/genapi.py224
1 files changed, 224 insertions, 0 deletions
diff --git a/scipy/base/code_generators/genapi.py b/scipy/base/code_generators/genapi.py
new file mode 100644
index 000000000..f185cd9bc
--- /dev/null
+++ b/scipy/base/code_generators/genapi.py
@@ -0,0 +1,224 @@
+import sys, os, re
+import md5
+
+API_FILES = ['arraymethods.c',
+ 'arrayobject.c',
+ 'arraytypes.inc.src',
+ 'multiarraymodule.c',
+ 'scalartypes.inc.src',
+ 'ufuncobject.c',
+ ]
+THIS_DIR = os.path.dirname(__file__)
+API_FILES = [os.path.join(THIS_DIR, '..', 'src', a) for a in API_FILES]
+
+def remove_whitespace(s):
+ return ''.join(s.split())
+
+class Function(object):
+ def __init__(self, name, return_type, args, doc=''):
+ self.name = name
+ self.return_type = return_type
+ self.args = args
+ self.doc = doc
+
+ def _format_arg(self, (typename, name)):
+ if typename.endswith('*'):
+ return typename + name
+ else:
+ return typename + ' ' + name
+
+ def argtypes_string(self):
+ if not self.args:
+ return 'void'
+ argstr = ', '.join(a[0] for a in self.args)
+ return argstr
+
+ def __str__(self):
+ argstr = ', '.join(self._format_arg(a) for a in self.args)
+ if self.doc:
+ doccomment = '/* %s */\n' % self.doc
+ else:
+ doccomment = ''
+ return '%s%s %s(%s)' % (doccomment, self.return_type, self.name, argstr)
+
+ def api_hash(self):
+ m = md5.new()
+ m.update(remove_whitespace(self.return_type))
+ m.update('\000')
+ m.update(self.name)
+ m.update('\000')
+ for typename, name in self.args:
+ m.update(remove_whitespace(typename))
+ m.update('\000')
+ return m.hexdigest()[:8]
+
+class ParseError(Exception):
+ def __init__(self, filename, lineno, msg):
+ self.filename = filename
+ self.lineno = lineno
+ self.msg = msg
+
+ def __str__(self):
+ return '%s:%s:%s' % (self.filename, self.lineno, self.msg)
+
+def skip_brackets(s, lbrac, rbrac):
+ count = 0
+ for i, c in enumerate(s):
+ if c == lbrac:
+ count += 1
+ elif c == rbrac:
+ count -= 1
+ if count == 0:
+ return i
+ raise ValueError("no match '%s' for '%s' (%r)" % (lbrac, rbrac, s))
+
+def split_arguments(argstr):
+ arguments = []
+ bracket_counts = {'(': 0, '[': 0}
+ current_argument = []
+ state = 0
+ i = 0
+ def finish_arg():
+ if current_argument:
+ argstr = ''.join(current_argument).strip()
+ m = re.match(r'(.*(\s+|[*]))(\w+)$', argstr)
+ if m:
+ typename = m.group(1).strip()
+ name = m.group(3)
+ else:
+ typename = argstr
+ name = ''
+ arguments.append((typename, name))
+ del current_argument[:]
+ while i < len(argstr):
+ c = argstr[i]
+ if c == ',':
+ finish_arg()
+ elif c == '(':
+ p = skip_brackets(argstr[i:], '(', ')')
+ current_argument += argstr[i:i+p]
+ i += p-1
+ else:
+ current_argument += c
+ i += 1
+ finish_arg()
+ return arguments
+
+
+def find_functions(filename, tag='API'):
+ fo = open(filename, 'r')
+ functions = []
+ return_type = None
+ function_name = None
+ function_args = []
+ doclist = []
+ SCANNING, STATE_DOC, STATE_RETTYPE, STATE_NAME, STATE_ARGS = range(5)
+ state = SCANNING
+ tagcomment = '/*' + tag
+ for lineno, line in enumerate(fo):
+ try:
+ line = line.strip()
+ if state == SCANNING:
+ if line.startswith(tagcomment):
+ if line.endswith('*/'):
+ state = STATE_RETTYPE
+ else:
+ state = STATE_DOC
+ elif state == STATE_DOC:
+ if line.startswith('*/'):
+ state = STATE_RETTYPE
+ else:
+ line = line.lstrip(' *')
+ doclist.append(line)
+ elif state == STATE_RETTYPE: #first line of declaration with return type
+ m = re.match(r'static\s+(.*)$', line)
+ if m:
+ line = m.group(1)
+ return_type = line
+ state = STATE_NAME
+ elif state == STATE_NAME: # second line, with function name
+ m = re.match(r'(\w+)\s*\(', line)
+ if m:
+ function_name = m.group(1)
+ else:
+ raise ParseError(filename, lineno+1, 'could not find function name')
+ function_args.append(line[m.end():])
+ state = STATE_ARGS
+ elif state == STATE_ARGS:
+ if line.startswith('{'): # finished
+ fargs_str = ' '.join(function_args).rstrip(' )')
+ fargs = split_arguments(fargs_str)
+ f = Function(function_name, return_type, fargs,
+ ' '.join(doclist))
+ functions.append(f)
+ return_type = None
+ function_name = None
+ function_args = []
+ doclist = []
+ state = 0
+ else:
+ function_args.append(line)
+ except:
+ print filename, lineno+1
+ raise
+ fo.close()
+ return functions
+
+def read_order(order_file):
+ fo = open(order_file, 'r')
+ order = {}
+ i = 0
+ for line in fo:
+ line = line.strip()
+ if not line.startswith('#'):
+ order[line] = i
+ i += 1
+ fo.close()
+ return order
+
+def get_api_functions(tagname, order_file):
+ if not os.path.exists(order_file):
+ order_file = os.path.join(THIS_DIR, order_file)
+ order = read_order(order_file)
+ functions = []
+ for f in API_FILES:
+ functions.extend(find_functions(f, tagname))
+ dfunctions = []
+ for func in functions:
+ o = order[func.name]
+ dfunctions.append( (o, func) )
+ dfunctions.sort()
+ return [a[1] for a in dfunctions]
+
+def add_api_list(offset, APIname, api_list,
+ module_list, extension_list, init_list):
+ """Add the API function declerations to the appropiate lists for use in
+ the headers.
+ """
+ for k, func in enumerate(api_list):
+ num = offset + k
+ astr = "static %s %s \\\n (%s);" % \
+ (func.return_type, func.name, func.argtypes_string())
+ module_list.append(astr)
+ astr = "#define %s \\\n (*(%s (*)(%s)) \\\n"\
+ " %s[%d])" % (func.name,func.return_type,
+ func.argtypes_string(), APIname, num)
+ extension_list.append(astr)
+ astr = " (void *) %s," % func.name
+ init_list.append(astr)
+
+
+def main():
+ tagname = sys.argv[1]
+ order_file = sys.argv[2]
+ functions = get_api_functions(tagname, order_file)
+ m = md5.new(tagname)
+ for func in functions:
+ print func
+ ah = func.api_hash()
+ m.update(ah)
+ print hex(int(ah,16))
+ print hex(int(m.hexdigest()[:8],16))
+
+if __name__ == '__main__':
+ main()