• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/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 three keys:
22#  - header: an instance of Header
23#  - enums: a dictionary of EnumDecl objects by name
24#  - structs: a dictionary of StructDecl objects by name
25
26# It requires 'ply' (Python Lex/Yacc).
27
28from __future__ import print_function
29
30import ply
31
32tokens = ('package', 'import', 'enum', 'struct', 'typedef',
33    'COLON', 'IDENTIFIER', 'COMMENT', 'NUMBER', 'HEX', 'OR', 'EQUALS',
34    'LPAREN', 'RPAREN', 'LBRACE', 'RBRACE', 'DOT', 'SEMICOLON', 'VERSION',
35    'COMMA', 'SHIFT', 'LESSTHAN', 'GREATERTHAN')
36
37t_COLON = r':'
38t_NUMBER = r'[0-9]+'
39t_HEX = r'0[x|X][0-9A-Fa-f]+'
40t_OR = r'\|'
41t_EQUALS = r'='
42t_LPAREN = r'\('
43t_RPAREN = r'\)'
44t_SHIFT = r'<<'
45t_LESSTHAN = r'<'
46t_GREATERTHAN = r'>'
47
48def t_COMMENT(t):
49    r'(/\*(.|\n)*?\*/)|(//.*)'
50    pass
51
52t_LBRACE = r'{'
53t_RBRACE = r'}'
54t_DOT = r'\.'
55t_SEMICOLON = r';'
56t_VERSION = r'@[0-9].[0-9]'
57t_COMMA = r','
58t_ignore = ' \n\t'
59
60def t_IDENTIFIER(t):
61    r'[a-zA-Z_][a-zA-Z_0-9]*'
62    if t.value == 'package':
63        t.type = 'package'
64    elif t.value == 'import':
65        t.type = 'import'
66    elif t.value == 'enum':
67        t.type = 'enum'
68    elif t.value == 'struct':
69        t.type = 'struct'
70    elif t.value == 'typedef':
71        t.type = 'typedef'
72    return t
73
74def t_error(t):
75    t.type = t.value[0]
76    t.value = t.value[0]
77    t.lexer.skip(1)
78    return t
79
80import ply.lex as lex
81lexer = lex.lex()
82
83class Typename(object):
84    pass
85
86class SimpleTypename(Typename):
87    def __init__(self, name):
88        self.name = name
89
90    def __str__(self):
91        return self.name
92
93class GenericTypename(Typename):
94    def __init__(self, name, arg):
95        self.name = name
96        self.arg = arg
97
98    def __str__(self):
99        return '%s<%s>' % (self.name, self.arg)
100
101class EnumHeader(object):
102    def __init__(self, name, base):
103        self.name = name
104        self.base = base
105
106    def __str__(self):
107        return '%s%s' % (self.name, ' %s' % self.base if self.base else '')
108
109class StructHeader(object):
110    def __init__(self, name):
111        self.name = name
112
113    def __str__(self):
114        return 'struct %s' % self.name
115
116class TypedefHeader(object):
117    def __init__(self, name):
118        self.name = name
119
120    def __str__(self):
121        return 'typedef %s' % self.name
122
123class EnumDecl(object):
124    def __init__(self, header, cases):
125        self.header = header
126        self.cases = cases
127        self.fillInValues()
128
129    def fillInValues(self):
130        # if no cases, we're done
131        if len(self.cases) < 1: return
132        # then, if case 0 has no value, set it to 0
133        if self.cases[0].value is None:
134            self.cases[0].value = EnumValueConstant("0")
135        # then for all other cases...
136        for i in range(1,len(self.cases)):
137            # ...if there's no value
138            if self.cases[i].value is None:
139                # set to previous case + 1
140                self.cases[i].value = EnumValueSuccessor(
141                    EnumValueLocalRef(self.cases[i-1].name))
142
143    def __str__(self):
144        return '%s {\n%s\n}' % (self.header,
145            '\n'.join(str(x) for x in self.cases))
146
147    def __repr__(self):
148        return self.__str__()
149
150class StructDecl(object):
151    def __init__(self, header, items):
152        self.header = header
153        self.items = items
154
155    def __str__(self):
156        return '%s {\n%s\n}' % (self.header,
157            '\n'.join(str(x) for x in self.items))
158
159    def __repr__(self):
160        return self.__str__()
161
162class TypedefDecl(object):
163    def __init__(self, header, name):
164        self.header = header
165        self.name = name
166
167    def __str__(self):
168        return '%s {\n%s\n}' % (self.header,
169            self.name)
170
171    def __repr__(self):
172        return self.__str__()
173
174class StructElement(object):
175    pass
176
177class StructElementIVar(StructElement):
178    def __init__(self, typename, name):
179        self.typename = typename
180        self.name = name
181
182    def __str__(self):
183        return '%s %s' % (self.typename, self.name)
184
185class StructElementStruct(StructElement):
186    def __init__(self, struct):
187        self.name = struct.header.name
188        self.struct = struct
189
190    def __str__(self):
191        return self.struct.__str__()
192
193class EnumCase(object):
194    def __init__(self, name, value):
195        self.name = name
196        self.value = value
197
198    def __str__(self):
199        return '%s = %s' % (self.name, self.value)
200
201class PackageID(object):
202    def __init__(self, name, version):
203        self.name = name
204        self.version = version
205
206    def __str__(self):
207        return '%s%s' % (self.name, self.version)
208
209class Package(object):
210    def __init__(self, package):
211        self.package = package
212
213    def __str__(self):
214        return 'package %s' % self.package
215
216class Import(object):
217    def __init__(self, package):
218        self.package = package
219
220    def __str__(self):
221        return 'import %s' % self.package
222
223class Header(object):
224    def __init__(self, package, imports):
225        self.package = package
226        self.imports = imports
227
228    def __str__(self):
229        return str(self.package) + "\n" + \
230            '\n'.join(str(x) for x in self.imports)
231
232class EnumValue(object):
233    def resolve(self, enum, document):
234        pass
235
236class EnumValueConstant(EnumValue):
237    def __init__(self, value):
238        self.value = value
239
240    def __str__(self):
241        return self.value
242
243    def resolve(self, enum, document):
244        if self.value.lower().startswith("0x"):
245            return int(self.value, 16)
246        else:
247            return int(self.value, 10)
248
249class EnumValueSuccessor(EnumValue):
250    def __init__(self, value):
251        self.value = value
252
253    def __str__(self):
254        return '%s + 1' % self.value
255
256    def resolve(self, enum, document):
257        return self.value.resolve(enum, document) + 1
258
259class EnumValueLocalRef(EnumValue):
260    def __init__(self, ref):
261        self.ref = ref
262
263    def __str__(self):
264        return self.ref
265
266    def resolve(self, enum, document):
267        for case in enum.cases:
268            if case.name == self.ref: return case.value.resolve(enum, document)
269
270class EnumValueLShift(EnumValue):
271    def __init__(self, base, offset):
272        self.base = base
273        self.offset = offset
274
275    def __str__(self):
276        return '%s << %s' % (self.base, self.offset)
277
278    def resolve(self, enum, document):
279        base = self.base.resolve(enum, document)
280        offset = self.offset.resolve(enum, document)
281        return base << offset
282
283class EnumValueOr(EnumValue):
284    def __init__(self, param1, param2):
285        self.param1 = param1
286        self.param2 = param2
287
288    def __str__(self):
289        return '%s | %s' % (self.param1, self.param2)
290
291    def resolve(self, enum, document):
292        param1 = self.param1.resolve(enum, document)
293        param2 = self.param2.resolve(enum, document)
294        return param1 | param2
295
296class EnumValueExternRef(EnumValue):
297    def __init__(self, where, ref):
298        self.where = where
299        self.ref = ref
300
301    def __str__(self):
302        return '%s:%s' % (self.where, self.ref)
303
304    def resolve(self, enum, document):
305        enum = document['enums'][self.where]
306        return EnumValueLocalRef(self.ref).resolve(enum, document)
307
308class Typedef(object):
309    def __init__(self, header, name):
310        self.header = header
311        self.name = name
312
313    def __str__(self):
314        return 'typedef %s %s' % (self.typename, self.name)
315
316# Error rule for syntax errors
317def p_error(p):
318    print("Syntax error in input: %s" % p)
319    try:
320        while True:
321            print(p.lexer.next().value, end=' ')
322    except:
323        pass
324
325def p_document(t):
326    'document : header type_decls'
327    enums = {}
328    structs = {}
329    typedefs = {}
330    for enum in t[2]:
331        if not isinstance(enum, EnumDecl): continue
332        enums[enum.header.name] = enum
333    for struct in t[2]:
334        if not isinstance(struct, StructDecl): continue
335        structs[struct.header.name] = struct
336    for typedef in t[2]:
337        if not isinstance(typedef, TypedefDecl): continue
338        typedefs[typedef.header.name] = typedef
339
340    t[0] = {'header' : t[1], 'enums' : enums, 'structs' : structs, 'typedefs' : typedef}
341
342def p_type_decls_1(t):
343    'type_decls : type_decl'
344    t[0] = [t[1]]
345def p_type_decls_2(t):
346    'type_decls : type_decls type_decl'
347    t[0] = t[1] + [t[2]]
348
349def p_type_decl_e(t):
350    'type_decl : enum_decl'
351    t[0] = t[1]
352def p_type_decl_s(t):
353    'type_decl : struct_decl'
354    t[0] = t[1]
355def p_type_decl_t(t):
356    'type_decl : typedef_decl'
357    t[0] = t[1]
358
359def p_enum_cases_1(t):
360    'enum_cases : enum_case'
361    t[0] = [t[1]]
362def p_enum_cases_2(t):
363    'enum_cases : enum_cases COMMA enum_case'
364    t[0] = t[1] + [t[3]]
365
366def p_struct_elements_1(t):
367    'struct_elements : struct_element'
368    t[0] = [t[1]]
369def p_struct_elements_2(t):
370    'struct_elements : struct_elements struct_element'
371    t[0] = t[1] + [t[2]]
372
373def p_enum_base_1(t):
374    'enum_base : VERSION COLON COLON IDENTIFIER'
375    t[0] = '%s::%s' % (t[1], t[4])
376def p_enum_base_2(t):
377    'enum_base : IDENTIFIER'
378    t[0] = t[1]
379
380def p_typedef_name(t):
381    'typedef_name : IDENTIFIER'
382    t[0] = t[1]
383
384def p_struct_header(t):
385    'struct_header : struct IDENTIFIER'
386    t[0] = StructHeader(t[2])
387
388def p_enum_header_1(t):
389    'enum_header : enum IDENTIFIER'
390    t[0] = EnumHeader(t[2], None)
391def p_enum_header_2(t):
392    'enum_header : enum IDENTIFIER COLON enum_base'
393    t[0] = EnumHeader(t[2], t[4])
394
395def p_typedef_header(t):
396    'typedef_header : typedef IDENTIFIER'
397    t[0] = TypedefHeader(t[2])
398
399def p_struct_decl(t):
400    'struct_decl : struct_header LBRACE struct_elements RBRACE SEMICOLON'
401    t[0] = StructDecl(t[1], t[3])
402
403def p_enum_decl_1(t):
404    'enum_decl : enum_header LBRACE enum_cases RBRACE SEMICOLON'
405    t[0] = EnumDecl(t[1], t[3])
406def p_enum_decl_2(t):
407    'enum_decl : enum_header LBRACE enum_cases COMMA RBRACE SEMICOLON'
408    t[0] = EnumDecl(t[1], t[3])
409
410def p_typedef_decl(t):
411    'typedef_decl : typedef_header typedef_name SEMICOLON'
412    t[0] = TypedefDecl(t[1], t[2])
413
414def p_enum_value_1(t):
415    '''enum_value : NUMBER
416                  | HEX'''
417    t[0] = EnumValueConstant(t[1])
418def p_enum_value_2(t):
419    'enum_value : enum_value SHIFT NUMBER'
420    t[0] = EnumValueLShift(t[1], EnumValueConstant(t[3]))
421def p_enum_value_3(t):
422    'enum_value : enum_value OR enum_value'
423    t[0] = EnumValueOr(t[1], t[3])
424def p_enum_value_4(t):
425    'enum_value : LPAREN enum_value RPAREN'
426    t[0] = t[2]
427def p_enum_value_5(t):
428    'enum_value : IDENTIFIER COLON IDENTIFIER'
429    t[0] = EnumValueExternRef(t[1],t[3])
430def p_enum_value_6(t):
431    'enum_value : IDENTIFIER'
432    t[0] = EnumValueLocalRef(t[1])
433
434def p_typename_v(t):
435    'typename : IDENTIFIER'
436    t[0] = SimpleTypename(t[1])
437def p_typename_g(t):
438    'typename : IDENTIFIER LESSTHAN IDENTIFIER GREATERTHAN'
439    t[0] = GenericTypename(t[1], t[3])
440
441def p_struct_element_ivar(t):
442    'struct_element : typename IDENTIFIER SEMICOLON'
443    t[0] = StructElementIVar(t[1], t[2])
444
445def p_struct_element_struct(t):
446    'struct_element : struct_decl'
447    t[0] = StructElementStruct(t[1])
448
449def p_enum_case_v(t):
450    'enum_case : IDENTIFIER EQUALS enum_value'
451    t[0] = EnumCase(t[1], t[3])
452def p_enum_case_b(t):
453    'enum_case : IDENTIFIER'
454    t[0] = EnumCase(t[1], None)
455
456def p_header_1(t):
457    'header : package_decl'
458    t[0] = Header(t[1], [])
459
460def p_header_2(t):
461    'header : package_decl import_decls'
462    t[0] = Header(t[1], t[2])
463
464def p_import_decls_1(t):
465    'import_decls : import_decl'
466    t[0] = [t[1]]
467
468def p_import_decls_2(t):
469    'import_decls : import_decls import_decl'
470    t[0] = t[1] + [t[2]]
471
472def p_package_decl(t):
473    'package_decl : package package_ID SEMICOLON'
474    t[0] = Package(t[2])
475
476def p_import_decl(t):
477    'import_decl : import package_ID SEMICOLON'
478    t[0] = Import(t[2])
479
480def p_package_ID(t):
481    'package_ID : dotted_identifier VERSION'
482    t[0] = PackageID(t[1], t[2])
483
484def p_dotted_identifier_1(t):
485    'dotted_identifier : IDENTIFIER'
486    t[0] = t[1]
487def p_dotted_identifier_2(t):
488    'dotted_identifier : dotted_identifier DOT IDENTIFIER'
489    t[0] = t[1] + '.' + t[3]
490
491class SilentLogger(object):
492    def warning(*args):
493        pass
494    def error(*args):
495        print(args)
496
497import ply.yacc as yacc
498parser = yacc.yacc(debug=False, write_tables=False, errorlog=SilentLogger())
499import sys
500
501def parse(filename):
502    return parser.parse(open(filename, 'r').read())
503