blob: 3de896da09d766d7b19b48f22c485a64d8e25bf3 [file] [log] [blame]
import json
import os
import sys
import typing as t
class DeclState(object):
def __init__(self, indent: str = '', parents: t.Set[str] = frozenset()):
self.indent = indent
self.parents = parents
def nest(self, indent: str = '',
identifier: t.Optional[str] = None) -> 'DeclState':
indent = self.indent + indent
parents = self.parents
if identifier:
parents = parents.union({identifier})
return DeclState(indent, parents)
class Declaration(dict):
def __init__(self, library: 'Library', value: dict):
dict.__init__(self, value)
self.library = library
@property
def name(self) -> str:
return self['name']
@property
def attributes(self):
return dict(
(a['name'], a['value']) for a in self.get('maybe_attributes', []))
class Type(dict):
def __init__(self, library, value):
self.library = library
dict.__init__(self, value)
@property
def kind(self):
return self['kind']
def is_primitive(self) -> bool:
return self.kind == 'primitive'
def is_nullable(self) -> bool:
return self.get('nullable', False)
@property
def element_type(self):
if 'element_type' in self:
return Type(self.library, self['element_type'])
def decl(self, state) -> str:
if self.is_primitive():
return self['subtype']
nullable = ''
if self.is_nullable():
nullable = '?'
if self.kind == 'identifier':
if self['identifier'] in state.parents:
# a cycle
return self['identifier'] + nullable
value = self.library.libraries.find(self['identifier'])
if isinstance(value, Interface):
return self['identifier'] + nullable
else:
return value.decl(
state.nest(identifier=self['identifier'])) + nullable
element_count = self.get('element_count',
self.get('maybe_element_count'))
size = ''
if element_count is not None:
size = ':%d' % element_count
if self.kind == 'string':
return 'string' + size + nullable
if self.kind in ('vector', 'array'):
return '%s<%s>%s%s' % (
self.kind,
Type(self.library, self['element_type']).decl(state), size,
nullable)
if self.kind == 'handle':
if self['subtype'] == 'handle':
return 'handle'
else:
return 'handle<%s>' % self['subtype']
if self.kind == 'request':
return 'request<%s>' % self['subtype']
raise Exception('unknown type %r' % self)
class Const(Declaration):
@property
def type(self) -> Type:
return Type(self.library, self['type'])
class EnumMember(Declaration):
def __init__(self, enum: 'Enum', value: dict):
Declaration.__init__(self, enum.library, value)
self.enum = enum
def decl(self, state: DeclState) -> str:
return '%s = %s' % (self.name, self['value']['literal']['value'])
class Enum(Declaration):
@property
def type(self) -> Type:
return Type(self.library, {
'kind': 'primitive',
'subtype': self['type']
})
@property
def members(self) -> t.List[EnumMember]:
return [EnumMember(self, m) for m in self['members']]
def decl(self, state: DeclState) -> str:
state = state.nest(identifier=self.name)
return ('enum %s : %s {' %
(self.name, self.type.decl(state))) + '\n ' + state.indent + (
',\n ' + state.indent).join(
m.decl(state)
for m in self.members) + '\n' + state.indent + '}'
class Argument(Declaration):
def __init__(self, method: 'Method', value: dict):
Declaration.__init__(self, method.library, value)
self.method = method
@property
def type(self) -> Type:
return Type(self.library, self['type'])
def decl(self, state: DeclState) -> str:
return '%s %s' % (self.type.decl(state), self['name'])
class Method(Declaration):
def __init__(self, interface: 'Interface', value: dict):
Declaration.__init__(self, interface.library, value)
self.interface = interface
@property
def name(self) -> str:
return '%s.%s' % (self.interface.name, self['name'])
def is_event(self) -> bool:
return 'maybe_request' not in self
def is_one_way(self) -> bool:
return 'maybe_response' not in self
def request(self) -> t.Optional[t.List[Argument]]:
if self['has_request']:
return [Argument(self, a) for a in self['maybe_request']]
else:
return None
def response(self) -> t.Optional[t.List[Argument]]:
if self['has_response']:
return [Argument(self, a) for a in self['maybe_response']]
else:
return None
def decl(self, state: DeclState) -> str:
if self.is_event():
preamble = '%d: -> %s(' % (self['ordinal'], self['name'])
state = state.nest(indent=' ' * len(preamble))
return preamble + ', '.join(
arg.decl(state) for arg in self.response()) + ');'
if self.is_one_way():
# TODO
return 'adsf'
preamble = '%d: %s(' % (self['ordinal'], self['name'])
state = state.nest(indent=' ' * len(preamble))
return (preamble + ', '.join(
arg.decl(state)
for arg in self.request()) + ')\n' + state.indent[:-4] + '-> (' +
', '.join(arg.decl(state) for arg in self.response()) + ');')
class Interface(Declaration):
@property
def methods(self) -> t.List[Method]:
return [Method(self, m) for m in self.get('methods', [])]
class StructMember(Declaration):
def __init__(self, struct: 'Struct', value: dict):
Declaration.__init__(self, struct.library, value)
self.struct = struct
@property
def type(self) -> Type:
return Type(self.library, self['type'])
def decl(self, state: DeclState) -> str:
# TODO: defaults?
return self.type.decl(state) + ' ' + self.name
class Struct(Declaration):
@property
def members(self) -> t.List[StructMember]:
return [StructMember(self, m) for m in self['members']]
def decl(self, state: DeclState) -> str:
sub_state = state.nest(indent=' ', identifier=self.name)
return ('struct %s {' % self.name) + '\n' + sub_state.indent + (
';\n' + sub_state.indent).join(
m.decl(sub_state)
for m in self.members) + ';\n' + state.indent + '}'
class TableMember(Declaration):
def __init__(self, table: 'Table', value: dict):
Declaration.__init__(self, table.library, value)
self.table = table
@property
def name(self) -> t.Optional[str]:
return self.get('name')
@property
def reserved(self) -> bool:
return self['reserved']
@property
def type(self) -> Type:
return Type(self.library, self['type'])
def decl(self, state: DeclState) -> str:
ordinal = '%d: ' % self['ordinal']
if self.reserved:
return ordinal + 'reserved'
else:
sub_state = state.nest(indent=' ' * len(ordinal))
return ordinal + self.type.decl(sub_state) + ' ' + self.name
class Table(Declaration):
@property
def members(self) -> t.List[TableMember]:
return [TableMember(self, m) for m in self['members']]
def decl(self, state: DeclState) -> str:
sub_state = state.nest(indent=' ', identifier=self.name)
return ('table %s {' % self.name) + '\n' + sub_state.indent + (
';\n' + sub_state.indent).join(
m.decl(sub_state)
for m in self.members) + ';\n' + state.indent + '}'
class UnionMember(Declaration):
def __init__(self, union: 'Union', value):
Declaration.__init__(self, union.library, value)
self.union = union
@property
def type(self) -> Type:
return Type(self.library, self['type'])
def decl(self, state: DeclState) -> str:
return self.type.decl(state) + ' ' + self.name
class Union(Declaration):
@property
def members(self) -> t.List[UnionMember]:
return [UnionMember(self, m) for m in self['members']]
def decl(self, state: DeclState) -> str:
sub_state = state.nest(indent=' ', identifier=self.name)
return 'union %s {\n' % self.name + sub_state.indent + (
';\n' + sub_state.indent).join(
m.decl(sub_state)
for m in self.members) + ';\n' + state.indent + '}'
DECLARATION_TYPES = {
'const': ('const_declarations', Const),
'enum': ('enum_declarations', Enum),
'interface': ('interface_declarations', Interface),
'struct': ('struct_declarations', Struct),
'table': ('table_declarations', Table),
'union': ('union_declarations', Union),
}
class Library(dict):
def __init__(self, libraries: 'FidlLibraries', path: str):
self.libraries = libraries
self._path = path
dict.__init__(self, json.load(open(path)))
self.name = self['name']
def __repr__(self):
return 'Library<%s>' % self.name
@property
def consts(self) -> t.List[Const]:
return [Const(self, value) for value in self['const_declarations']]
@property
def enums(self) -> t.List[Enum]:
return [Enum(self, value) for value in self['enum_declarations']]
@property
def interfaces(self) -> t.List[Interface]:
return [Interface(self, v) for v in self['interface_declarations']]
@property
def structs(self) -> t.List[Struct]:
return [Struct(self, value) for value in self['struct_declarations']]
@property
def tables(self) -> t.List[Table]:
return [Table(self, value) for value in self['table_declarations']]
@property
def unions(self) -> t.List[Union]:
return [Union(self, value) for value in self['union_declarations']]
@property
def methods(self) -> t.List[Method]:
return [
method for interface in self.interfaces
for method in interface.methods
]
def find(self, identifier: str) -> t.Union[None, Const, Enum, Interface, Struct, Table, Union]:
if identifier not in self['declarations']:
return None
declaration_type = self['declarations'][identifier]
declarations_key, constructor = DECLARATION_TYPES[declaration_type]
return self._lookup_declaration(identifier, declarations_key,
constructor)
def _lookup_declaration(self, identifier, declarations_key, constructor):
value = next(
s for s in self[declarations_key] if s['name'] == identifier)
return constructor(self, value)
class Libraries(list):
def __init__(self):
build_dir = os.environ.get('FUCHSIA_BUILD_DIR')
if build_dir is None:
print('FUCHSIA_BUILD_DIR is not set.')
print('Run: fx exec %s' % ' '.join(sys.argv))
sys.exit(1)
# find all the .fidl.json files
ENDING = '.fidl.json'
for root, _, files in os.walk(build_dir):
self.extend(
Library(self, os.path.join(root, f)) for f in files
if f.endswith(ENDING))
self.by_name = dict((l.name, l) for l in self)
@property
def consts(self) -> t.List[Const]:
return [const for library in self for const in library.consts]
@property
def enums(self) -> t.List[Enum]:
return [enum for library in self for enum in library.enums]
@property
def interfaces(self) -> t.List[Interface]:
return [
interface for library in self for interface in library.interfaces
]
@property
def structs(self) -> t.List[Struct]:
return [struct for library in self for struct in library.structs]
@property
def tables(self) -> t.List[Table]:
return [table for library in self for table in library.tables]
@property
def unions(self) -> t.List[Union]:
return [union for library in self for union in library.unions]
@property
def methods(self) -> t.List[Method]:
return [method for library in self for method in library.methods]
def find(self, identifier: str
) -> t.Union[None, Const, Enum, Interface, Struct, Table, Union]:
library_name, _ = identifier.split('/')
if library_name not in self.by_name:
return None
library = self.by_name[library_name]
return library.find(identifier)