150 lines
5.0 KiB
Python
150 lines
5.0 KiB
Python
|
# Copyright 2017 The Dawn Authors
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
|
||
|
from collections import namedtuple
|
||
|
|
||
|
class Name:
|
||
|
def __init__(self, name, native=False):
|
||
|
self.native = native
|
||
|
if native:
|
||
|
self.chunks = [name]
|
||
|
else:
|
||
|
self.chunks = name.split(' ')
|
||
|
|
||
|
def CamelChunk(self, chunk):
|
||
|
return chunk[0].upper() + chunk[1:]
|
||
|
|
||
|
def canonical_case(self):
|
||
|
return (' '.join(self.chunks)).lower()
|
||
|
|
||
|
def concatcase(self):
|
||
|
return ''.join(self.chunks)
|
||
|
|
||
|
def camelCase(self):
|
||
|
return self.chunks[0] + ''.join([self.CamelChunk(chunk) for chunk in self.chunks[1:]])
|
||
|
|
||
|
def CamelCase(self):
|
||
|
return ''.join([self.CamelChunk(chunk) for chunk in self.chunks])
|
||
|
|
||
|
def SNAKE_CASE(self):
|
||
|
return '_'.join([chunk.upper() for chunk in self.chunks])
|
||
|
|
||
|
def snake_case(self):
|
||
|
return '_'.join(self.chunks)
|
||
|
|
||
|
class Type:
|
||
|
def __init__(self, name, json_data, native=False):
|
||
|
self.json_data = json_data
|
||
|
self.dict_name = name
|
||
|
self.name = Name(name, native=native)
|
||
|
self.category = json_data['category']
|
||
|
self.is_builder = self.name.canonical_case().endswith(" builder")
|
||
|
|
||
|
EnumValue = namedtuple('EnumValue', ['name', 'value'])
|
||
|
class EnumType(Type):
|
||
|
def __init__(self, name, json_data):
|
||
|
Type.__init__(self, name, json_data)
|
||
|
self.values = [EnumValue(Name(m['name']), m['value']) for m in self.json_data['values']]
|
||
|
|
||
|
BitmaskValue = namedtuple('BitmaskValue', ['name', 'value'])
|
||
|
class BitmaskType(Type):
|
||
|
def __init__(self, name, json_data):
|
||
|
Type.__init__(self, name, json_data)
|
||
|
self.values = [BitmaskValue(Name(m['name']), m['value']) for m in self.json_data['values']]
|
||
|
self.full_mask = 0
|
||
|
for value in self.values:
|
||
|
self.full_mask = self.full_mask | value.value
|
||
|
|
||
|
class NativeType(Type):
|
||
|
def __init__(self, name, json_data):
|
||
|
Type.__init__(self, name, json_data, native=True)
|
||
|
|
||
|
class NativelyDefined(Type):
|
||
|
def __init__(self, name, json_data):
|
||
|
Type.__init__(self, name, json_data)
|
||
|
|
||
|
# Methods and structures are both "records", so record members correspond to
|
||
|
# method arguments or structure members.
|
||
|
class RecordMember:
|
||
|
def __init__(self, name, typ, annotation, optional, is_return_value):
|
||
|
self.name = name
|
||
|
self.type = typ
|
||
|
self.annotation = annotation
|
||
|
self.length = None
|
||
|
self.optional = optional
|
||
|
self.is_return_value = is_return_value
|
||
|
|
||
|
Method = namedtuple('Method', ['name', 'return_type', 'arguments'])
|
||
|
class ObjectType(Type):
|
||
|
def __init__(self, name, json_data):
|
||
|
Type.__init__(self, name, json_data)
|
||
|
self.methods = []
|
||
|
self.native_methods = []
|
||
|
self.built_type = None
|
||
|
|
||
|
class Record:
|
||
|
def __init__(self, name):
|
||
|
self.name = Name(name)
|
||
|
self.members = []
|
||
|
self.has_dawn_object = False
|
||
|
|
||
|
def update_metadata(self):
|
||
|
def has_dawn_object(member):
|
||
|
if isinstance(member.type, ObjectType):
|
||
|
return True
|
||
|
elif isinstance(member.type, StructureType):
|
||
|
return member.type.has_dawn_object
|
||
|
else:
|
||
|
return False
|
||
|
|
||
|
self.has_dawn_object = any(has_dawn_object(member) for member in self.members)
|
||
|
|
||
|
class StructureType(Record, Type):
|
||
|
def __init__(self, name, json_data):
|
||
|
Record.__init__(self, name)
|
||
|
Type.__init__(self, name, json_data)
|
||
|
self.extensible = json_data.get("extensible", False)
|
||
|
|
||
|
class Command(Record):
|
||
|
def __init__(self, name, members=None):
|
||
|
Record.__init__(self, name)
|
||
|
self.members = members or []
|
||
|
self.derived_object = None
|
||
|
self.derived_method = None
|
||
|
|
||
|
def linked_record_members(json_data, types):
|
||
|
members = []
|
||
|
members_by_name = {}
|
||
|
for m in json_data:
|
||
|
member = RecordMember(Name(m['name']), types[m['type']],
|
||
|
m.get('annotation', 'value'), m.get('optional', False),
|
||
|
m.get('is_return_value', False))
|
||
|
members.append(member)
|
||
|
members_by_name[member.name.canonical_case()] = member
|
||
|
|
||
|
for (member, m) in zip(members, json_data):
|
||
|
if member.annotation != 'value':
|
||
|
if not 'length' in m:
|
||
|
if member.type.category == 'structure':
|
||
|
member.length = "constant"
|
||
|
member.constant_length = 1
|
||
|
else:
|
||
|
assert(False)
|
||
|
elif m['length'] == 'strlen':
|
||
|
member.length = 'strlen'
|
||
|
else:
|
||
|
member.length = members_by_name[m['length']]
|
||
|
|
||
|
return members
|