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