Modules |
Files |
Inheritance Tree |
Inheritance Graph |
Name Index |
Config
File: Synopsis/Parser/Python/python.py
1| # Python Parser
2| # Copyright(c) 2000 by Stephen Davies
3| #
4| # This file is under the GPL.
5| """Main module for the Python parser.
6| Parsing python is achieved by using the code in the Python distribution that
7| is an example for parsing python by using the built-in parser. This parser
8| returns a parse tree which we can traverse and translate into Synopsis' AST.
9| The exparse module contains the enhanced example code (it has many more
10| features than the simple example did), and this module translates the
11| resulting intermediate AST objects into Synopsis.Core.AST objects.
12| """
13|
14| import parser, sys, os, string, getopt
15| from Synopsis.Core import AST, Type
16| import exparse
17|
18| verbose = 0
19|
20| def addDeclaration(decl):
21| """Adds the given declaration to the current top scope and to the
22| SourceFile for this file."""
23| global scopes, sourcefile
24| scopes[-1].declarations().append(decl)
25| sourcefile.declarations().append(decl)
26|
27| def push(scope):
28| """Pushes the given scope onto the top of the stack"""
29| scopes.append(scope)
30|
31| def pop():
32| """Pops the scope stack by one level"""
33| del scopes[-1]
34|
35| def scopeName(name):
36| """Scopes the given name. If the given name is a list then it is returned
37| verbatim, else it is concatenated with the (scoped) name of the current
38| scope"""
39| if type(name) == type([]): return tuple(name)
40| return tuple(list(scopes[-1].name()) + [name])
41|
42| def process_ModuleInfo(mi):
43| """Processes a ModuleInfo object. The comments are extracted, and any
44| functions and comments recursively processed."""
45| comm = AST.Comment(mi.get_docstring(), sourcefile, -1)
46| scopes[-1].comments().append(comm)
47| for name in mi.get_function_names():
48| process_FunctionInfo(mi.get_function_info(name))
49| for name in mi.get_class_names():
50| process_ClassInfo(mi.get_class_info(name))
51|
52| def add_params(func, fi):
53| """Adds the parameters of 'fi' to the AST.Function 'func'."""
54| for name, value in map(None, fi.get_params(), fi.get_param_defaults()):
55| func.parameters().append(AST.Parameter('', returnType,'',name,value))
56|
57| def process_FunctionInfo(fi):
58| """Process a FunctionInfo object. An AST.Function object is created and
59| inserted into the current scope."""
60| name = scopeName(fi.get_name())
61| func = AST.Function(sourcefile, -1, 'Python', 'function', '', returnType, name, name[-1])
62| comm = AST.Comment(fi.get_docstring(), '', -1)
63| func.comments().append(comm)
64| add_params(func, fi)
65| addDeclaration(func)
66|
67| def process_MethodInfo(fi):
68| """Process a MethodInfo object. An AST.Operation object is created and
69| inserted into the current scope."""
70| name = scopeName(fi.get_name())
71| func = AST.Operation(sourcefile,-1, 'Python', 'operation', '', returnType, name, name[-1])
72| comm = AST.Comment(fi.get_docstring(), '', -1)
73| func.comments().append(comm)
74| add_params(func, fi)
75| addDeclaration(func)
76|
77|
78| def process_ClassInfo(ci):
79| """Process a ClassInfo object. An AST.Class object is created and
80| inserted into the current scope. The inheritance of the class is also
81| parsed, and nested classes and methods recursively processed."""
82| name = scopeName(ci.get_name())
83| clas = AST.Class(sourcefile,-1, 'Python', 'class', name)
84| comm = AST.Comment(ci.get_docstring(), '', -1)
85| clas.comments().append(comm)
86| # Figure out bases:
87| for base in ci.get_base_names():
88| try:
89| t = types[scopeName(base)]
90| except KeyError:
91| #print "Adding Unknown type for",scopeName(base)
92| t = Type.Unknown("Python", scopeName(base))
93| clas.parents().append(AST.Inheritance('', t, ''))
94| # Add the new class
95| addDeclaration(clas)
96| types[clas.name()] = Type.Declared("Python", clas.name(), clas)
97| push(clas)
98| for name in ci.get_class_names():
99| process_ClassInfo(ci.get_class_info(name))
100| for name in ci.get_method_names():
101| process_MethodInfo(ci.get_method_info(name))
102| pop()
103|
104| def usage():
105| """Prints a usage message"""
106| print \
107| """
108| -b <basename> Specify basename"""
109|
110| def __parseArgs(args, config_obj):
111| """Parses the command line arguments and the config object"""
112| global basename, verbose
113| # Set defaults
114| basename = ''
115|
116| # Parse config object
117| if hasattr(config_obj, 'verbose') and config_obj.verbose:
118| verbose = 1
119| if hasattr(config_obj, 'basename') and config_obj.basename:
120| basename = config_obj.basename
121|
122| # Parse command line arguments
123| try:
124| opts,remainder = getopt.getopt(args, "b:v")
125| except getopt.error, e:
126| sys.stderr.write("Error in arguments: " + str(e) + "\n")
127| sys.exit(1)
128|
129| for opt in opts:
130| o,a = opt
131| if o == "-b": basename = a
132| elif o == "-v": verbose = 1
133|
134| def get_synopsis(file):
135| """Returns the docstring from the top of an open file"""
136| mi = exparse.get_docs(file)
137| return mi.get_docstring()
138|
139| def parse(file, extra_files, parser_args, config_obj):
140| """Entry point for the Python parser"""
141| __parseArgs(parser_args, config_obj)
142| global scopes, filename, types, basename, returnType, sourcefile
143|
144| ast = AST.AST()
145| filename = file
146| types = ast.types()
147|
148| # Split the filename into a scoped tuple name
149| name = file
150| if file[:len(basename)] == basename:
151| name = filename = file[len(basename):]
152| name = string.split(os.path.splitext(name)[0], os.sep)
153| exparse.packagepath = string.join(string.split(file, os.sep)[:-1], os.sep)
154| exparse.packagename = name[:-1]
155| #print "package path, name:",exparse.packagepath, exparse.packagename
156| sourcefile = AST.SourceFile(filename, file, 'Python')
157| sourcefile.set_is_main(1)
158|
159| # Create the enclosing module scopes
160| scopes = [AST.Scope(sourcefile, -1, 'Python', 'file scope', name)]
161| for depth in range(len(name) - 1):
162| module = AST.Module(sourcefile, -1, 'Python', 'package', name[:depth+1])
163| addDeclaration(module)
164| types[module.name()] = Type.Declared("Python", module.name(), module)
165| push(module)
166| # Add final name as Module -- unless module is __init__
167| if name[-1] != '__init__':
168| module = AST.Module(sourcefile, -1, 'Python', 'module', name)
169| addDeclaration(module)
170| types[module.name()] = Type.Declared("Python", module.name(), module)
171| push(module)
172|
173| # Parse the file
174| mi = exparse.get_docs(file)
175|
176| # Create return type for Python functions:
177| returnType = Type.Base('Python',('',))
178|
179| # Process the parsed file
180| process_ModuleInfo(mi)
181|
182| # Store the declarations
183| ast.files()[filename] = sourcefile
184| ast.declarations().extend(scopes[0].declarations())
185|
186| # Return new AST object
187| return ast
188|