Get rid of string type and replace with a bool type
[fidl.git] / fidl.py
blob8319402a50ac0634c0388c414daaee490e6347ed
1 ##
2 # Flexible IDL framework
4 # Copyright IBM, Corp. 2010
6 # Authors:
7 # Anthony Liguori <aliguori@us.ibm.com>
9 # This work is licensed under the terms of the GNU GPL, version 2. See
10 # the COPYING file in the top-level directory.
13 from spark import GenericScanner, GenericParser
15 # Lexical token representation. It really just lets us associate a tag with
16 # the token value for purposes of classification.
17 class Token(object):
18 def __init__(self, kind, value=None):
19 self.kind = kind
20 if value == None:
21 self.value = kind
22 else:
23 self.value = value
25 def __cmp__(self, rhs):
26 return cmp(self.kind, rhs)
28 def __repr__(self):
29 return '[%s %s]' % (self.kind, self.value)
31 # Lexical scanner. It skips whitespace and C99 and C89 comments. It also
32 # skips cpp directives which is somewhat unusual.
34 class IdlScanner(GenericScanner):
35 keywords = ['const', 'struct', 'typedef', 'void',
36 '__capacity_is__', '__feature__']
38 def __init__(self):
39 GenericScanner.__init__(self)
41 def tokenize(self, input):
42 self.rv = []
43 GenericScanner.tokenize(self, input)
44 return self.rv
46 def t_whitespace(self, s):
47 r' \s+ '
48 pass
50 def t_c89_comment(self, s):
51 r' /\*([^\*]|\n|\*[^\/])*\*/ '
52 pass
54 def t_c99_comment(self, s):
55 r' //.*?\n '
56 pass
58 def t_cpp_directive(self, s):
59 r' \#(.*?\\\n)*.*?\n '
60 pass
62 def t_symbol(self, s):
63 r' [A-Za-z_][A-Za-z0-9_]* '
64 if s in self.keywords:
65 self.rv.append(Token(s))
66 else:
67 self.rv.append(Token('symbol', s))
69 def t_integer(self, s):
70 r' \-?[1-9][0-9]+|0([Xx][0-9a-fA-F]+)? '
71 self.rv.append(Token('integer', s))
73 def t_op(self, s):
74 r' [*,\(\);{}\[\]] '
75 self.rv.append(s)
77 def scan(f):
78 input = f.read()
79 scanner = IdlScanner()
80 return scanner.tokenize(input)
82 # Abstract Syntax Tree node.
83 class AST(object):
84 def __init__(self, kind, **kwds):
85 self.kind = kind
86 self.kwds = kwds
88 def __getattr__(self, key):
89 if self.kwds.has_key(key):
90 return self.kwds[key]
91 return object.__getattr__(self, key)
93 def __repr__(self):
94 return '(%s, %s)' % (self.kind, self.kwds)
96 # Grammar implementation. This is only a subset of C. It does not support
97 # enums or unions. It also only supports single levels of pointers and only
98 # support const at the beginning of a type. It does not support static or the
99 # extern keywords.
101 # It's meant to support the type of C you'd find in a typical header file. It
102 # assumes that a CPP pass has not been performed.
103 class IdlParser(GenericParser):
104 def __init__(self, start='statements'):
105 GenericParser.__init__(self, start)
107 def p_primitive_1(self, args):
109 primitive ::= symbol
111 return AST('type', value=args[0].value)
113 def p_primitive_2(self, args):
114 ' primitive ::= structure '
115 return args[0]
117 def p_structure(self, args):
119 structure ::= struct symbol
120 structure ::= struct symbol { members }
121 structure ::= struct { members }
122 structure ::= struct { members } __feature__ ( symbol )
124 if len(args) == 2:
125 return AST('struct', name=args[1].value)
126 elif len(args) == 4:
127 return AST('struct', name=None, members=args[2])
128 elif len(args) == 5:
129 return AST('struct', name=args[1].value, members=args[3])
130 else:
131 return AST('struct', name=None, members=args[2],
132 feature=args[6].value)
134 def p_type_1(self, args):
135 ' type ::= const primitive * '
136 return AST('input', base=args[1])
138 def p_type_2(self, args):
139 ' type ::= primitive * '
140 return AST('output', base=args[0])
142 def p_type_3(self, args):
143 ' type ::= primitive * * '
144 return AST('output', base=AST('array', base=args[0]))
146 def p_type_4(self, args):
147 ' type ::= primitive '
148 return args[0]
150 def p_type_5(self, args):
151 ' type ::= primitive * __capacity_is__ ( symbol ) '
152 return AST('varray',
153 base=args[0],
154 size=args[4].value)
156 def p_arg_1(self, args):
157 ' arg ::= type symbol'
158 return AST('arg', type=args[0], name=args[1].value)
160 def p_arg_2(self, args):
161 ' arg ::= type symbol [ symbol ] '
162 return AST('arg',
163 type=AST('array', base=args[0]),
164 name=args[1].value,
165 size=args[3].value)
167 def p_arg_3(self, args):
168 ' arg ::= type symbol [ integer ] '
169 return AST('arg',
170 type=AST('array', base=args[0]),
171 name=args[1].value,
172 size=args[3].value)
174 def p_arglist_1(self, args):
175 ' arglist ::= arg '
176 return [args[0]]
178 def p_arglist_2(self, args):
179 ' arglist ::= arglist , arg '
180 return args[0] + [args[2]]
182 def p_argslist_1(self, args):
183 ' argslist ::= arglist '
184 return args[0]
186 def p_argslist_2(self, args):
187 ' argslist ::= void '
188 return []
190 def p_definition_1(self, args):
191 ' definition ::= void symbol ( argslist ) '
192 return AST('def', name=args[1].value, params=args[3])
194 def p_definition_2(self, args):
195 ' definition ::= type symbol ( argslist ) '
196 return AST('def', name=args[1].value, retval=args[0], params=args[3])
198 def p_members_1(self, args):
199 ' members ::= arg ; '
200 return [args[0]]
202 def p_members_2(self, args):
203 ' members ::= members arg ; '
204 return args[0] + [args[1]]
206 def p_type_definition(self, args):
207 ' type_definition ::= typedef type symbol '
208 return AST('typedef', alias=args[2].value, base=args[1])
210 def p_statement_1(self, args):
212 statement ::= type_definition ;
213 statement ::= definition ;
215 return [args[0]]
217 def p_statement_2(self, args):
218 ' statement ::= structure ; '
219 return [AST('struct_decl', struct=args[0])]
221 def p_statements_1(self, args):
222 ' statements ::= statement '
223 return args[0]
225 def p_statements_2(self, args):
226 ' statements ::= statements statement '
227 return args[0] + args[1]
229 def parse(tokens):
230 parser = IdlParser()
231 return parser.parse(tokens)
233 # Walk the AST tree. Each AST node type has a method that only knows enough
234 # to walk its children. This class should be subclassed to transform the
235 # tree.
236 class ASTWalker(object):
237 def __init__(self):
238 pass
240 def default(self, node):
241 kwds = {}
242 for key in node.kwds:
243 value = getattr(node, key)
244 if type(value) in [AST, list]:
245 kwds[key] = self.walk(value)
246 else:
247 kwds[key] = value
248 return AST(node.kind, **kwds)
250 def walk_node(self, node):
251 name = 'n_%s' % node.kind
252 if hasattr(self, name):
253 fn = getattr(self, name)
254 node = fn(node)
255 else:
256 node = self.default(node)
257 return node
259 def walk(self, tree):
260 if type(tree) == AST:
261 return self.walk_node(tree)
262 else:
263 return filter(lambda x: x != None, map(self.walk_node, tree))
265 # Pretty print an AST
266 class PrettyWalker(ASTWalker):
267 def __init__(self):
268 ASTWalker.__init__(self)
270 def print_indent(self, indent):
271 for i in range(indent):
272 print ' ',
274 def default(self, nodes, indent=0):
275 if type(nodes) != list:
276 nodes = [nodes]
278 for node in nodes:
279 self.print_indent(indent)
280 print '%s:' % node.kind
281 for key in node.kwds:
282 value = getattr(node, key)
283 if type(value) == AST or type(value) == list:
284 self.default(value, indent + 1)
285 else:
286 self.print_indent(indent + 1)
287 print '%s = %s' % (key, value)