blob: 79a860808fadcce2011e8c8a622bbeaecdd944b4 [file] [log] [blame]
Enrico Granata4c43add2017-03-15 18:01:34 -07001#!/usr/bin/env python3
2#
3# Copyright (C) 2017 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18# A parser for enum types defined in HIDL.
19# This script can parse HIDL files and generate a parse tree.
20# To use, import and call parse("path/to/file.hal")
21# It will return a Python dictionary with two keys:
22# - header: an instance of Header
23# - enums: a dictionary of EnumDecl objects by name
24# This script cannot parse structs for now, but that would be easy to add.
25
26# It requires 'ply' (Python Lex/Yacc).
27
28import ply
29
Enrico Granataa109ed62017-03-28 17:01:32 -070030tokens = ('package', 'import', 'enum', 'struct',
Enrico Granata4c43add2017-03-15 18:01:34 -070031 'COLON', 'IDENTIFIER', 'COMMENT', 'NUMBER', 'HEX', 'OR', 'EQUALS',
32 'LPAREN', 'RPAREN', 'LBRACE', 'RBRACE', 'DOT', 'SEMICOLON', 'VERSION',
Enrico Granataa109ed62017-03-28 17:01:32 -070033 'COMMA', 'SHIFT', 'LESSTHAN', 'GREATERTHAN')
Enrico Granata4c43add2017-03-15 18:01:34 -070034
35t_COLON = r':'
36t_NUMBER = r'[0-9]+'
37t_HEX = r'0x[0-9A-Fa-f]+'
38t_OR = r'\|'
39t_EQUALS = r'='
40t_LPAREN = r'\('
41t_RPAREN = r'\)'
42t_SHIFT = r'<<'
Enrico Granataa109ed62017-03-28 17:01:32 -070043t_LESSTHAN = r'<'
44t_GREATERTHAN = r'>'
Enrico Granata4c43add2017-03-15 18:01:34 -070045
46def t_COMMENT(t):
47 r'(/\*(.|\n)*?\*/)|(//.*)'
48 pass
49
50t_LBRACE = r'{'
51t_RBRACE = r'}'
52t_DOT = r'\.'
53t_SEMICOLON = r';'
54t_VERSION = r'@[0-9].[0-9]'
55t_COMMA = r','
56t_ignore = ' \n\t'
57
58def t_IDENTIFIER(t):
59 r'[a-zA-Z_][a-zA-Z_0-9]*'
60 if t.value == 'package':
61 t.type = 'package'
62 elif t.value == 'import':
63 t.type = 'import'
64 elif t.value == 'enum':
65 t.type = 'enum'
Enrico Granataa109ed62017-03-28 17:01:32 -070066 elif t.value == 'struct':
67 t.type = 'struct'
Enrico Granata4c43add2017-03-15 18:01:34 -070068 return t
69
70def t_error(t):
71 t.type = t.value[0]
72 t.value = t.value[0]
73 t.lexer.skip(1)
74 return t
75
76import ply.lex as lex
77lexer = lex.lex()
78
Enrico Granataa109ed62017-03-28 17:01:32 -070079class Typename(object):
80 pass
81
82class SimpleTypename(Typename):
83 def __init__(self, name):
84 self.name = name
85
86 def __str__(self):
87 return self.name
88
89class GenericTypename(Typename):
90 def __init__(self, name, arg):
91 self.name = name
92 self.arg = arg
93
94 def __str__(self):
95 return '%s<%s>' % (self.name, self.arg)
96
Enrico Granata4c43add2017-03-15 18:01:34 -070097class EnumHeader(object):
98 def __init__(self, name, base):
99 self.name = name
100 self.base = base
101
102 def __str__(self):
103 return '%s%s' % (self.name, ' %s' % self.base if self.base else '')
104
Enrico Granataa109ed62017-03-28 17:01:32 -0700105class StructHeader(object):
106 def __init__(self, name):
107 self.name = name
108
109 def __str__(self):
110 return 'struct %s' % self.name
111
Enrico Granata4c43add2017-03-15 18:01:34 -0700112class EnumDecl(object):
113 def __init__(self, header, cases):
114 self.header = header
115 self.cases = cases
Enrico Granataa109ed62017-03-28 17:01:32 -0700116 self.fillInValues()
117
118 def fillInValues(self):
119 # if no cases, we're done
120 if len(self.cases) < 1: return
121 # then, if case 0 has no value, set it to 0
122 if self.cases[0].value is None:
123 self.cases[0].value = EnumValueConstant("0")
124 # then for all other cases...
125 for i in range(1,len(self.cases)):
126 # ...if there's no value
127 if self.cases[i].value is None:
128 # set to previous case + 1
129 self.cases[i].value = EnumValueSuccessor(
130 EnumValueLocalRef(self.cases[i-1].name))
Enrico Granata4c43add2017-03-15 18:01:34 -0700131
132 def __str__(self):
133 return '%s {\n%s\n}' % (self.header,
134 '\n'.join(str(x) for x in self.cases))
135
136 def __repr__(self):
137 return self.__str__()
138
Enrico Granataa109ed62017-03-28 17:01:32 -0700139class StructDecl(object):
140 def __init__(self, header, items):
141 self.header = header
142 self.items = items
143
144 def __str__(self):
145 return '%s {\n%s\n}' % (self.header,
146 '\n'.join(str(x) for x in self.items))
147
148 def __repr__(self):
149 return self.__str__()
150
151class StructElement(object):
152 pass
153
154class StructElementIVar(StructElement):
155 def __init__(self, typename, name):
156 self.typename = typename
157 self.name = name
158
159 def __str__(self):
160 return '%s %s' % (self.typename, self.name)
161
162class StructElementStruct(StructElement):
163 def __init__(self, struct):
164 self.name = struct.header.name
165 self.struct = struct
166
167 def __str__(self):
168 return self.struct.__str__()
169
Enrico Granata4c43add2017-03-15 18:01:34 -0700170class EnumCase(object):
171 def __init__(self, name, value):
172 self.name = name
173 self.value = value
174
175 def __str__(self):
176 return '%s = %s' % (self.name, self.value)
177
178class PackageID(object):
179 def __init__(self, name, version):
180 self.name = name
181 self.version = version
182
183 def __str__(self):
184 return '%s%s' % (self.name, self.version)
185
186class Package(object):
187 def __init__(self, package):
188 self.package = package
189
190 def __str__(self):
191 return 'package %s' % self.package
192
193class Import(object):
194 def __init__(self, package):
195 self.package = package
196
197 def __str__(self):
198 return 'import %s' % self.package
199
200class Header(object):
201 def __init__(self, package, imports):
202 self.package = package
203 self.imports = imports
204
205 def __str__(self):
206 return str(self.package) + "\n" + \
207 '\n'.join(str(x) for x in self.imports)
208
Enrico Granataa109ed62017-03-28 17:01:32 -0700209class EnumValue(object):
210 def resolve(self, enum, document):
211 pass
212
213class EnumValueConstant(EnumValue):
214 def __init__(self, value):
215 self.value = value
216
217 def __str__(self):
218 return self.value
219
220 def resolve(self, enum, document):
221 if self.value.startswith("0x"):
222 return int(self.value, 16)
223 else:
224 return int(self.value, 10)
225
226class EnumValueSuccessor(EnumValue):
227 def __init__(self, value):
228 self.value = value
229
230 def __str__(self):
231 return '%s + 1' % self.value
232
233 def resolve(self, enum, document):
234 return self.value.resolve(enum, document) + 1
235
236class EnumValueLocalRef(EnumValue):
237 def __init__(self, ref):
238 self.ref = ref
239
240 def __str__(self):
241 return self.ref
242
243 def resolve(self, enum, document):
244 for case in enum.cases:
245 if case.name == self.ref: return case.value.resolve(enum, document)
246
247class EnumValueRShift(EnumValue):
248 def __init__(self, base, offset):
249 self.base = base
250 self.offset = offset
251
252 def __str__(self):
253 return '%s << %s' % (self.base, self.offset)
254
255 def resolve(self, enum, document):
256 base = self.base.resolve(enum, document)
257 offset = self.offset.resolve(enum, document)
258 return base << offset
259
260class EnumValueOr(EnumValue):
261 def __init__(self, param1, param2):
262 self.param1 = param1
263 self.param2 = param2
264
265 def __str__(self):
266 return '%s | %s' % (self.param1, self.param2)
267
268 def resolve(self, enum, document):
269 param1 = self.param1.resolve(enum, document)
270 param2 = self.param2.resolve(enum, document)
271 return param1 | param2
272
273class EnumValueExternRef(EnumValue):
274 def __init__(self, where, ref):
275 self.where = where
276 self.ref = ref
277
278 def __str__(self):
279 return '%s:%s' % (self.where, self.ref)
280
281 def resolve(self, enum, document):
282 enum = document['enums'][self.where]
283 return EnumValueLocalRef(self.ref).resolve(enum, document)
284
Enrico Granata4c43add2017-03-15 18:01:34 -0700285# Error rule for syntax errors
286def p_error(p):
287 print("Syntax error in input: %s" % p)
Enrico Granataa109ed62017-03-28 17:01:32 -0700288 try:
289 while True:
290 print(p.lexer.next().value, end=' ')
291 except:
292 pass
Enrico Granata4c43add2017-03-15 18:01:34 -0700293
294def p_document(t):
Enrico Granataa109ed62017-03-28 17:01:32 -0700295 'document : header type_decls'
Enrico Granata4c43add2017-03-15 18:01:34 -0700296 enums = {}
Enrico Granataa109ed62017-03-28 17:01:32 -0700297 structs = {}
Enrico Granata4c43add2017-03-15 18:01:34 -0700298 for enum in t[2]:
Enrico Granataa109ed62017-03-28 17:01:32 -0700299 if not isinstance(enum, EnumDecl): continue
Enrico Granata4c43add2017-03-15 18:01:34 -0700300 enums[enum.header.name] = enum
Enrico Granataa109ed62017-03-28 17:01:32 -0700301 for struct in t[2]:
302 if not isinstance(struct, StructDecl): continue
303 structs[struct.header.name] = struct
304 t[0] = {'header' : t[1], 'enums' : enums, 'structs' : structs}
Enrico Granata4c43add2017-03-15 18:01:34 -0700305
Enrico Granataa109ed62017-03-28 17:01:32 -0700306def p_type_decls_1(t):
307 'type_decls : type_decl'
Enrico Granata4c43add2017-03-15 18:01:34 -0700308 t[0] = [t[1]]
Enrico Granataa109ed62017-03-28 17:01:32 -0700309def p_type_decls_2(t):
310 'type_decls : type_decls type_decl'
Enrico Granata4c43add2017-03-15 18:01:34 -0700311 t[0] = t[1] + [t[2]]
312
Enrico Granataa109ed62017-03-28 17:01:32 -0700313def p_type_decl_e(t):
314 'type_decl : enum_decl'
315 t[0] = t[1]
316def p_type_decl_s(t):
317 'type_decl : struct_decl'
318 t[0] = t[1]
319
Enrico Granata4c43add2017-03-15 18:01:34 -0700320def p_enum_cases_1(t):
321 'enum_cases : enum_case'
322 t[0] = [t[1]]
323def p_enum_cases_2(t):
324 'enum_cases : enum_cases COMMA enum_case'
325 t[0] = t[1] + [t[3]]
326
Enrico Granataa109ed62017-03-28 17:01:32 -0700327def p_struct_elements_1(t):
328 'struct_elements : struct_element'
329 t[0] = [t[1]]
330def p_struct_elements_2(t):
331 'struct_elements : struct_elements struct_element'
332 t[0] = t[1] + [t[2]]
333
Enrico Granata4c43add2017-03-15 18:01:34 -0700334def p_enum_base_1(t):
335 'enum_base : VERSION COLON COLON IDENTIFIER'
336 t[0] = '%s::%s' % (t[1], t[4])
337def p_enum_base_2(t):
338 'enum_base : IDENTIFIER'
339 t[0] = t[1]
340
Enrico Granataa109ed62017-03-28 17:01:32 -0700341def p_struct_header(t):
342 'struct_header : struct IDENTIFIER'
343 t[0] = StructHeader(t[2])
344
Enrico Granata4c43add2017-03-15 18:01:34 -0700345def p_enum_header_1(t):
346 'enum_header : enum IDENTIFIER'
347 t[0] = EnumHeader(t[2], None)
348def p_enum_header_2(t):
349 'enum_header : enum IDENTIFIER COLON enum_base'
350 t[0] = EnumHeader(t[2], t[4])
351
Enrico Granataa109ed62017-03-28 17:01:32 -0700352def p_struct_decl(t):
353 'struct_decl : struct_header LBRACE struct_elements RBRACE SEMICOLON'
354 t[0] = StructDecl(t[1], t[3])
355
Enrico Granata4c43add2017-03-15 18:01:34 -0700356def p_enum_decl_1(t):
357 'enum_decl : enum_header LBRACE enum_cases RBRACE SEMICOLON'
358 t[0] = EnumDecl(t[1], t[3])
359def p_enum_decl_2(t):
360 'enum_decl : enum_header LBRACE enum_cases COMMA RBRACE SEMICOLON'
361 t[0] = EnumDecl(t[1], t[3])
362
363def p_enum_value_1(t):
364 '''enum_value : NUMBER
Enrico Granataa109ed62017-03-28 17:01:32 -0700365 | HEX'''
366 t[0] = EnumValueConstant(t[1])
Enrico Granata4c43add2017-03-15 18:01:34 -0700367def p_enum_value_2(t):
368 'enum_value : enum_value SHIFT NUMBER'
Enrico Granataa109ed62017-03-28 17:01:32 -0700369 t[0] = EnumValueRShift(t[1], t[3])
Enrico Granata4c43add2017-03-15 18:01:34 -0700370def p_enum_value_3(t):
371 'enum_value : enum_value OR enum_value'
Enrico Granataa109ed62017-03-28 17:01:32 -0700372 t[0] = EnumValueOr(t[1], t[3])
Enrico Granata4c43add2017-03-15 18:01:34 -0700373def p_enum_value_4(t):
374 'enum_value : LPAREN enum_value RPAREN'
375 t[0] = t[2]
376def p_enum_value_5(t):
377 'enum_value : IDENTIFIER COLON IDENTIFIER'
Enrico Granataa109ed62017-03-28 17:01:32 -0700378 t[0] = EnumValueExternRef(t[1],t[3])
379def p_enum_value_6(t):
380 'enum_value : IDENTIFIER'
381 t[0] = EnumValueLocalRef(t[1])
Enrico Granata4c43add2017-03-15 18:01:34 -0700382
Enrico Granataa109ed62017-03-28 17:01:32 -0700383def p_typename_v(t):
384 'typename : IDENTIFIER'
385 t[0] = SimpleTypename(t[1])
386def p_typename_g(t):
387 'typename : IDENTIFIER LESSTHAN IDENTIFIER GREATERTHAN'
388 t[0] = GenericTypename(t[1], t[3])
389
390def p_struct_element_ivar(t):
391 'struct_element : typename IDENTIFIER SEMICOLON'
392 t[0] = StructElementIVar(t[1], t[2])
393
394def p_struct_element_struct(t):
395 'struct_element : struct_decl'
396 t[0] = StructElementStruct(t[1])
397
398def p_enum_case_v(t):
Enrico Granata4c43add2017-03-15 18:01:34 -0700399 'enum_case : IDENTIFIER EQUALS enum_value'
400 t[0] = EnumCase(t[1], t[3])
Enrico Granataa109ed62017-03-28 17:01:32 -0700401def p_enum_case_b(t):
402 'enum_case : IDENTIFIER'
403 t[0] = EnumCase(t[1], None)
Enrico Granata4c43add2017-03-15 18:01:34 -0700404
405def p_header_1(t):
406 'header : package_decl'
407 t[0] = Header(t[1], [])
408
409def p_header_2(t):
410 'header : package_decl import_decls'
411 t[0] = Header(t[1], t[2])
412
413def p_import_decls_1(t):
414 'import_decls : import_decl'
415 t[0] = [t[1]]
416
417def p_import_decls_2(t):
418 'import_decls : import_decls import_decl'
419 t[0] = t[1] + [t[2]]
420
421def p_package_decl(t):
422 'package_decl : package package_ID SEMICOLON'
423 t[0] = Package(t[2])
424
425def p_import_decl(t):
426 'import_decl : import package_ID SEMICOLON'
427 t[0] = Import(t[2])
428
429def p_package_ID(t):
430 'package_ID : dotted_identifier VERSION'
431 t[0] = PackageID(t[1], t[2])
432
433def p_dotted_identifier_1(t):
434 'dotted_identifier : IDENTIFIER'
435 t[0] = t[1]
436def p_dotted_identifier_2(t):
437 'dotted_identifier : dotted_identifier DOT IDENTIFIER'
438 t[0] = t[1] + '.' + t[3]
439
440class SilentLogger(object):
441 def warning(*args):
442 pass
443
444import ply.yacc as yacc
445parser = yacc.yacc(debug=False, write_tables=False, errorlog=SilentLogger())
446import sys
447
448def parse(filename):
449 return parser.parse(open(filename, 'r').read())