CodeGeneratorReplayInputs.py [plain text]
import os.path
import re
import sys
import string
from string import Template
import optparse
import logging
from CodeGeneratorReplayInputsTemplates import Templates
try:
import json
except ImportError:
import simplejson as json
GLOBAL_CONFIG = {
"baseFilename": "ReplayInputs",
"guardCondition": "ENABLE(WEB_REPLAY)",
"traitsFrameworkName": "JavaScriptCore",
"headerIncludes": [
(["WebCore"],
("WebCore", "replay/EventLoopInput.h")
),
(["JavaScriptCore", "WebCore"],
("JavaScriptCore", "replay/EncodedValue.h")
),
(["JavaScriptCore"],
("JavaScriptCore", "replay/NondeterministicInput.h")
),
(["WebCore"],
("WTF", "wtf/text/WTFString.h")
),
(["Test"],
("WebCore", "platform/ExternalNamespaceHeaderIncludeDummy.h")
),
(["Test"],
("Test", "platform/InternalNamespaceHeaderIncludeDummy.h")
)
],
"implIncludes": [
(["WebCore"],
("WebCore", "replay/ReplayInputTypes.h")
),
(["WebCore"],
("WebCore", "replay/SerializationMethods.h")
),
(["WebCore", "JavaScriptCore"],
("JavaScriptCore", "inspector/InspectorValues.h")
),
(["JavaScriptCore"],
("WTF", "wtf/NeverDestroyed.h")
),
(["JavaScriptCore"],
("WTF", "wtf/text/AtomicString.h")
),
(["Test"],
("WebCore", "platform/ExternalNamespaceImplIncludeDummy.h")
),
(["Test"],
("Test", "platform/InternalNamespaceImplIncludeDummy.h")
)
],
}
FRAMEWORK_CONFIG_MAP = {
"Global": {
"prefix": "",
"namespace": ""
},
"WTF": {
"prefix": "WTF",
"namespace": "WTF",
},
"JavaScriptCore": {
"prefix": "JS",
"namespace": "JSC",
"exportMacro": "JS_EXPORT_PRIVATE",
"inputTypeTemplate": Templates.InputTypeFromStaticLocal,
},
"WebCore": {
"prefix": "Web",
"namespace": "WebCore",
"inputTypeTemplate": Templates.InputTypeFromThreadLocal,
},
"Test": {
"prefix": "Test",
"namespace": "Test",
"inputTypeTemplate": Templates.InputTypeFromStaticLocal,
}
}
QUEUE_CONFIG_MAP = {
"SCRIPT_MEMOIZED": {
"enumValue": "ScriptMemoizedData",
"baseClass": "NondeterministicInput<%s>",
},
"LOADER_MEMOIZED": {
"enumValue": "LoaderMemoizedData",
"baseClass": "NondeterministicInput<%s>",
},
"EVENT_LOOP": {
"enumValue": "EventLoopInput",
"baseClass": "EventLoopInput<%s>",
},
}
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.ERROR)
log = logging.getLogger('global')
class ParseException(Exception):
pass
class TypecheckException(Exception):
pass
class Framework:
def __init__(self, name):
self._settings = FRAMEWORK_CONFIG_MAP[name]
self.name = name
def setting(self, key, default=''):
return self._settings.get(key, default)
@staticmethod
def fromString(frameworkString):
if frameworkString == "Global":
return Frameworks.Global
if frameworkString == "WTF":
return Frameworks.WTF
if frameworkString == "JavaScriptCore":
return Frameworks.JavaScriptCore
if frameworkString == "WebCore":
return Frameworks.WebCore
if frameworkString == "Test":
return Frameworks.Test
raise ParseException("Unknown framework: " + frameworkString)
class Frameworks:
Global = Framework("Global")
WTF = Framework("WTF")
JavaScriptCore = Framework("JavaScriptCore")
WebCore = Framework("WebCore")
Test = Framework("Test")
class InputQueue:
def __init__(self, settings):
self._settings = settings
def setting(self, key, default=''):
return self._settings.get(key, default)
@staticmethod
def fromString(queueString):
if queueString == "SCRIPT_MEMOIZED":
return InputQueues.SCRIPT_MEMOIZED
if queueString == "LOADER_MEMOIZED":
return InputQueues.LOADER_MEMOIZED
if queueString == "EVENT_LOOP":
return InputQueues.EVENT_LOOP
raise ParseException("Unknown input queue: " + queueString)
class InputQueues:
SCRIPT_MEMOIZED = InputQueue(QUEUE_CONFIG_MAP["SCRIPT_MEMOIZED"])
LOADER_MEMOIZED = InputQueue(QUEUE_CONFIG_MAP["LOADER_MEMOIZED"])
EVENT_LOOP = InputQueue(QUEUE_CONFIG_MAP["EVENT_LOOP"])
class Input:
def __init__(self, name, description, queueString, flags, guard=None):
self.name = name
self.description = description
self.queue = InputQueue.fromString(queueString)
self._flags = flags
self.guard = guard
self.members = []
def setting(self, key, default=''):
if key in self._flags:
return True
return self.queue.setting(key, default)
class InputMember:
def __init__(self, memberName, typeName, flags=[]):
self.memberName = memberName
self.typeName = typeName
self._flags = flags
def has_flag(self, key, default=''):
return key in self._flags
class TypeMode:
def __init__(self, name):
self._name = name
@staticmethod
def fromString(modeString):
modeString = modeString.upper()
if modeString == 'SCALAR':
return TypeModes.SCALAR
if modeString == 'HEAVY_SCALAR':
return TypeModes.HEAVY_SCALAR
if modeString == 'OWNED':
return TypeModes.OWNED
if modeString == 'SHARED':
return TypeModes.SHARED
if modeString == 'VECTOR':
return TypeModes.VECTOR
raise ParseException("Unknown type mode: " + modeString)
class TypeModes:
SCALAR = TypeMode("SCALAR")
HEAVY_SCALAR = TypeMode("HEAVY_SCALAR")
OWNED = TypeMode("OWNED")
SHARED = TypeMode("SHARED")
VECTOR = TypeMode("VECTOR")
class Type:
def __init__(self, name, mode, framework, header, enclosing_class, values, guard_values_map, underlying_storage, flags, guard=None):
self._name = name
self.mode = mode
self.framework = framework
self.header = header
self.enclosing_class = enclosing_class
self.values = values
self.guard_values_map = guard_values_map
self.underlying_storage = underlying_storage
self._flags = flags
self.guard = guard
def __eq__(self, other):
return self.type_name() == other.type_name() and self.mode == other.mode
def __hash__(self):
return self._name.__hash__()
def has_flag(self, flagString):
return flagString in self._flags
def is_struct(self):
return self.has_flag("STRUCT")
def is_enum(self):
return self.has_flag("ENUM")
def is_enum_class(self):
return self.has_flag("ENUM_CLASS")
def declaration_kind(self):
if self.is_enum():
return "enum"
elif self.is_enum_class():
return "enum class"
elif self.is_struct():
return "struct"
else:
return "class"
def qualified_prefix(self):
components = []
if self.framework != Frameworks.Global:
components.append(self.framework.setting('namespace'))
if self.enclosing_class is not None:
components.append(self.enclosing_class)
components.append("")
return "::".join(components)
def type_name(self, qualified=False):
if qualified:
return "%s%s" % (self.qualified_prefix(), self._name)
elif self.enclosing_class is not None:
return "%s::%s" % (self.enclosing_class, self._name)
else:
return self._name
def storage_type(self, qualified=False):
if self.mode == TypeModes.OWNED:
return "std::unique_ptr<%s>" % self.type_name(qualified)
elif self.mode == TypeModes.SHARED:
return "RefPtr<%s>" % self.type_name(qualified)
else:
return self.type_name(qualified)
def borrow_type(self, qualified=False):
if self.mode == TypeModes.SCALAR:
return self.type_name(qualified)
elif self.mode == TypeModes.SHARED:
return "PassRefPtr<%s>" % self.type_name(qualified)
else:
return "const %s&" % self.type_name(qualified)
def argument_type(self, qualified=False):
if self.mode == TypeModes.SHARED:
return "PassRefPtr<%s>" % self.type_name(qualified)
else:
return self.storage_type()
def check_for_required_properties(props, obj, what):
for prop in props:
if prop not in obj:
raise ParseException("When parsing %s, required property missing: %s" % (what, prop))
class VectorType(Type):
def __init__(self, element_type):
self._element_type = element_type
self.mode = TypeModes.VECTOR
self.framework = element_type.framework
self.enclosing_class = None
def has_flag(self):
return False
def is_struct(self):
return False
def is_enum(self):
return False
def is_enum_class(self):
return False
def qualified_prefix(self):
return ""
def type_name(self, qualified=False):
return "Vector<%s>" % self._element_type.type_name(qualified=qualified)
def argument_type(self, qualified=False):
return self.type_name(qualified=qualified) + "&"
class InputsModel:
def __init__(self, parsed_json):
self.inputs = []
self.types = []
self.types_by_name = {}
self.inputs_by_name = {}
self.parse_toplevel(parsed_json)
def enum_types(self):
_enums = filter(lambda x: x.is_enum() or x.is_enum_class(), self.types)
return sorted(_enums, key=lambda _enum: _enum.type_name())
def get_type_for_member(self, member):
if member.has_flag("VECTOR"):
return VectorType(self.types_by_name.get(member.typeName))
else:
return self.types_by_name.get(member.typeName)
def parse_toplevel(self, json):
check_for_required_properties(['types', 'inputs'], json, 'toplevel')
if not isinstance(json['types'], dict):
raise ParseException("Malformed specification: types is not a dict of framework->type list")
if not isinstance(json['inputs'], list):
raise ParseException("Malformed specification: inputs is not an array")
for type_framework_name, type_list in json['types'].iteritems():
if not isinstance(type_list, list):
raise ParseException("Malformed specification: type list for framework %s is not a list" % type_framework_name)
for _type in type_list:
self.parse_type_with_framework_name(_type, type_framework_name)
for val in json['inputs']:
self.parse_input(val)
def parse_type_with_framework_name(self, json, framework_name):
check_for_required_properties(['name', 'mode'], json, 'type')
framework = Framework.fromString(framework_name)
if framework is not Frameworks.Global:
check_for_required_properties(['header'], json, 'non-global type')
type_name = json['name']
type_mode = TypeMode.fromString(json['mode'])
header = json.get('header')
enclosing_class = json.get('enclosing_class')
enum_values = json.get('values')
guarded_enum_values = json.get('guarded_values', {})
type_storage = json.get('storage')
type_flags = json.get('flags', [])
guard = json.get('guard', None)
_type = Type(type_name, type_mode, framework, header, enclosing_class, enum_values, guarded_enum_values, type_storage, type_flags, guard)
if _type.is_enum() or _type.is_enum_class():
check_for_required_properties(['values'], json, 'enum')
if not isinstance(json['values'], list) or len(_type.values) == 0:
raise ParseException("Malformed specification: enum %s does not supply a list of values" % type_name)
if _type.is_enum() and "storage" not in json:
raise ParseException("Could not parse enum %s: C-style enums must also specify their storage type so they can be forward declared." % type_name)
self.types.append(_type)
def parse_input(self, json):
check_for_required_properties(['name', 'description', 'queue', 'members'], json, 'input')
_input = Input(json['name'], json['description'], json['queue'], json.get('flags', []), json.get('guard'))
if isinstance(json['members'], list):
for member in json['members']:
check_for_required_properties(['name', 'type'], member, 'member')
_input.members.append(InputMember(member['name'], member['type'], member.get('flags', [])))
self.inputs.append(_input)
def resolve_types(self):
for _type in self.types:
self.typecheck_type(_type)
for _input in self.inputs:
self.typecheck_input(_input)
def typecheck_type(self, _type):
log.debug("typecheck type " + _type.type_name())
if _type.type_name() in self.types_by_name:
raise TypecheckException("Duplicate type with name: " + _type.type_name())
self.types_by_name[_type.type_name()] = _type
def typecheck_input(self, _input):
log.debug("typecheck input " + _input.name)
if _input.name in self.inputs_by_name:
raise TypecheckException("Duplicate input with name: " + _input.name)
seen_members = {}
for member in _input.members:
if member.memberName in seen_members:
raise TypecheckException("Duplicate input member with name: " + member.memberName)
self.typecheck_input_member(member, _input)
seen_members[member.memberName] = member
self.inputs_by_name[_input.name] = _input
def typecheck_input_member(self, input_member, _input):
log.debug("typecheck member '%s' of '%s'" % (input_member.memberName, _input.name))
if not input_member.typeName in self.types_by_name:
raise TypecheckException("Unknown type '%s' referenced by member '%s' of input '%s'" % (input_member.typeName, input_member.memberName, _input.name))
class IncrementalFileWriter:
def __init__(self, filepath, force_output):
self._filepath = filepath
self._output = ""
self.force_output = force_output
def write(self, text):
self._output += text
def close(self):
text_changed = True
self._output = self._output.rstrip() + "\n"
try:
read_file = open(self._filepath, "r")
old_text = read_file.read()
read_file.close()
text_changed = old_text != self._output
except:
pass
if text_changed or self.force_output:
out_file = open(self._filepath, "w")
out_file.write(self._output)
out_file.close()
def wrap_with_guard(contents, condition=None):
if condition is None:
return contents
return "\n".join([
"#if %s" % condition,
contents,
"#endif // %s" % condition
])
class Generator:
def __init__(self, model, target_framework_name, input_filepath, output_prefix):
self._model = model
self.target_framework = Framework.fromString(target_framework_name)
self.traits_framework = Framework.fromString(self.setting('traitsFrameworkName'))
self._input_filepath = input_filepath
self._output_prefix = output_prefix
def setting(self, key, default=''):
return self.target_framework.setting(key, GLOBAL_CONFIG.get(key, default))
def output_filename(self, extension=None):
components = []
if len(self._output_prefix) > 0:
components.extend([self._output_prefix, '-'])
components.extend([self.setting('prefix'), self.setting('baseFilename')])
if extension is not None:
components.extend(['.', extension])
return "".join(components)
def write_output_files(self, _dir, force=False):
header_file = IncrementalFileWriter(os.path.join(_dir, self.output_filename('h')), force)
implementation_file = IncrementalFileWriter(os.path.join(_dir, self.output_filename('cpp')), force)
header_file.write(self.generate_header())
implementation_file.write(self.generate_implementation())
header_file.close()
implementation_file.close()
def generate_header(self):
template_arguments = {
'licenseBlock': self.generate_license(),
'headerGuard': re.sub('[-./]', '_', self.output_filename() + ".h"),
'filename': self.output_filename(),
'guardCondition': self.setting('guardCondition'),
'traitsNamespace': self.traits_framework.setting('namespace'),
'inputsNamespace': self.target_framework.setting('namespace'),
'includes': self.generate_includes(defaults=self.setting('headerIncludes')),
'typeForwardDeclarations': self.generate_type_forward_declarations(),
'inputForwardDeclarations': "\n".join([wrap_with_guard("class %s;", _input.guard) % _input.name for _input in self._model.inputs]),
'inputClassDeclarations': "\n\n".join([self.generate_class_declaration(_input) for _input in self._model.inputs]),
'inputTraitDeclarations': "\n\n".join([self.generate_input_trait_declaration(_input) for _input in self._model.inputs]),
'enumTraitDeclarations': "\n\n".join([wrap_with_guard(self.generate_enum_trait_declaration(_type), _type.guard) for _type in self._model.enum_types()]),
'forEachMacro': self.generate_for_each_macro(),
}
return Template(Templates.HeaderSkeleton).substitute(template_arguments)
def generate_implementation(self):
template_arguments = {
'licenseBlock': self.generate_license(),
'filename': self.output_filename(),
'guardCondition': self.setting('guardCondition'),
'traitsNamespace': self.traits_framework.setting('namespace'),
'inputsNamespace': self.target_framework.setting('namespace'),
'includes': self.generate_includes(defaults=self.setting('implIncludes'), includes_for_types=True),
'inputClassImplementations': "\n\n".join([self.generate_class_implementation(_input) for _input in self._model.inputs]),
'inputTraitImplementations': "\n\n".join([self.generate_input_trait_implementation(_input) for _input in self._model.inputs]),
'enumTraitImplementations': "\n\n".join([wrap_with_guard(self.generate_enum_trait_implementation(_type), _type.guard) for _type in self._model.enum_types()]),
}
return Template(Templates.ImplementationSkeleton).substitute(template_arguments)
def generate_license(self):
return Template(Templates.CopyrightBlock).substitute(None, inputFilename=os.path.basename(self._input_filepath))
def generate_includes(self, defaults=[], includes_for_types=False):
lines = set()
for _type in self._model.types:
if _type.framework is Frameworks.Global:
continue
include_for_destructor = _type.mode is TypeModes.SHARED
include_for_enclosing_class = _type.is_enum() and _type.enclosing_class is not None
include_for_copyable_member = _type.mode is TypeModes.HEAVY_SCALAR
if (not includes_for_types) ^ (include_for_destructor or include_for_enclosing_class or include_for_copyable_member):
continue
if self.target_framework != _type.framework:
lines.add("#include <%s>" % _type.header)
else:
lines.add("#include \"%s\"" % os.path.basename(_type.header))
for entry in defaults:
(allowed_framework_names, data) = entry
(framework_name, header_path) = data
if self.target_framework.name not in allowed_framework_names:
continue
if self.target_framework.name != framework_name:
lines.add("#include <%s>" % header_path)
else:
lines.add("#include \"%s\"" % os.path.basename(header_path))
return "\n".join(sorted(list(lines)))
def generate_type_forward_declarations(self):
lines = []
decls_by_framework = {}
frameworks = [Framework.fromString(s) for s in FRAMEWORK_CONFIG_MAP.keys() if s != Frameworks.Global.name]
for framework in frameworks:
decls_by_framework[framework] = []
for _type in self._model.types:
if _type.framework not in frameworks:
continue
if _type.enclosing_class is not None:
continue
if _type.mode == TypeModes.HEAVY_SCALAR:
continue
if _type.mode == TypeModes.SCALAR and not (_type.is_enum() or _type.is_enum_class()):
continue
if _type.is_enum():
declaration = "enum %s : %s;" % (_type.type_name(), _type.underlying_storage)
else:
declaration = "%s %s;" % (_type.declaration_kind(), _type.type_name())
decls_by_framework[_type.framework].append(declaration)
for framework in frameworks:
if len(decls_by_framework[framework]) == 0:
continue
decls_by_framework[framework].sort()
lines.append("namespace %s {" % framework.setting('namespace'))
lines.extend(decls_by_framework[framework])
lines.append("}")
lines.append("")
return "\n".join(lines)
def generate_class_declaration(self, _input):
extra_declarations = []
if _input.queue == InputQueues.EVENT_LOOP:
extra_declarations.extend([
"",
" // EventLoopInput API",
" virtual void dispatch(ReplayController&) override final;",
])
if _input.setting('CREATE_FROM_PAGE'):
extra_declarations.extend([
" static std::unique_ptr<%s> createFromPage(const Page&);" % _input.name
])
member_getters = [self.generate_input_member_getter(_member) for _member in _input.members]
member_declarations = [self.generate_input_member_declaration(_member) for _member in _input.members]
if len(member_declarations) > 0:
member_declarations.insert(0, "private:")
template_arguments = {
'inputConstructor': self.generate_input_constructor_declaration(_input),
'inputDestructor': self.generate_input_destructor_declaration(_input),
'inputName': _input.name,
'inputQueue': _input.setting('enumValue'),
'baseClass': _input.setting('baseClass') % _input.name,
'extraDeclarations': "\n".join(extra_declarations),
'memberGetters': "\n".join(member_getters),
'memberDeclarations': "\n".join(member_declarations),
}
return wrap_with_guard(Template(Templates.InputClassDeclaration).substitute(template_arguments), _input.guard)
def generate_input_constructor_declaration(self, _input):
formals_list = self.generate_constructor_formals_list(_input)
terms = []
if self.setting('exportMacro'):
terms.append(self.setting('exportMacro'))
terms.append("%s(%s)" % (_input.name, formals_list))
return " %s;" % " ".join(terms)
def generate_input_destructor_declaration(self, _input):
return " virtual ~%s();" % _input.name
def generate_input_member_getter(self, _member):
member_type = self._model.get_type_for_member(_member)
return " %s %s() const { return %s; }" % (member_type.borrow_type(), _member.memberName, self.generate_member_borrow_expression(_member))
def generate_input_member_declaration(self, _member):
member_type = self._model.get_type_for_member(_member)
return " %s m_%s;" % (member_type.storage_type(), _member.memberName)
def generate_input_member_tuples(self, _input):
return [(_member, self._model.get_type_for_member(_member)) for _member in _input.members]
def qualified_input_name(self, _input):
if self.target_framework == self.traits_framework:
return _input.name
else:
return "%s::%s" % (self.target_framework.setting('namespace'), _input.name)
def generate_input_trait_declaration(self, _input):
decl_type = ['struct']
if len(self.setting('exportMacro')) > 0:
decl_type.append(self.setting('exportMacro'))
template_arguments = {
'structOrClass': " ".join(decl_type),
'queueType': _input.queue.setting('enumValue'),
'qualifiedInputName': self.qualified_input_name(_input),
}
return wrap_with_guard(Template(Templates.InputTraitsDeclaration).substitute(template_arguments), _input.guard)
def generate_enum_trait_declaration(self, _type):
should_qualify_type = _type.framework != self.traits_framework
template = Templates.EnumTraitDeclaration if _type.is_enum() else Templates.EnumClassTraitDeclaration
template_arguments = {
'enumName': _type.type_name(qualified=should_qualify_type),
}
return Template(template).substitute(template_arguments)
def generate_for_each_macro(self):
macro_name = "%s_REPLAY_INPUT_NAMES_FOR_EACH" % self.setting('prefix').upper()
lines = []
lines.append("#define %s(macro) \\" % macro_name)
lines.extend([" macro(%s) \\" % _input.name for _input in self._model.inputs])
lines.append(" \\")
lines.append("// end of %s" % macro_name)
return "\n".join(lines)
def generate_class_implementation(self, _input):
template_arguments = {
'inputName': _input.name,
'inputsNamespace': self.target_framework.setting('namespace'),
'initializerList': self.generate_constructor_initializer_list(_input),
'constructorFormalsList': self.generate_constructor_formals_list(_input),
}
return wrap_with_guard(Template(Templates.InputClassImplementation).substitute(template_arguments), _input.guard)
def generate_enum_trait_implementation(self, _type):
should_qualify_type = _type.framework != self.traits_framework
prefix_components = []
if should_qualify_type:
prefix_components.append(_type.framework.setting('namespace'))
if _type.is_enum_class():
prefix_components.append(_type.type_name())
if _type.enclosing_class is not None:
prefix_components.append(_type.enclosing_class)
prefix_components.append("")
enum_prefix = "::".join(prefix_components)
encodeLines = []
if _type.is_enum():
encode_template = Templates.EnumEncodeCase
decode_template = Templates.EnumDecodeCase
enum_trait_template = Templates.EnumTraitImplementation
else:
encode_template = Templates.EnumClassEncodeCase
decode_template = Templates.EnumClassDecodeCase
enum_trait_template = Templates.EnumClassTraitImplementation
for _value in _type.values:
template_arguments = {
'enumStringValue': _value,
'qualifiedEnumValue': "%s%s" % (enum_prefix, _value),
}
encodeLines.append(Template(encode_template).substitute(template_arguments))
for guard, guard_values in _type.guard_values_map.iteritems():
guardedLines = []
for guard_value in guard_values:
template_arguments = {
'enumStringValue': guard_value,
'qualifiedEnumValue': "%s%s" % (enum_prefix, guard_value),
}
guardedLines.append(Template(encode_template).substitute(template_arguments))
encodeLines.append(wrap_with_guard("\n".join(guardedLines), guard))
decodeLines = []
for _value in _type.values:
template_arguments = {
'enumStringValue': _value,
'qualifiedEnumValue': "%s%s" % (enum_prefix, _value),
'qualifiedEnumName': _type.type_name(qualified=should_qualify_type)
}
decodeLines.append(Template(decode_template).substitute(template_arguments))
for guard, guard_values in _type.guard_values_map.iteritems():
guardedLines = []
for guard_value in guard_values:
template_arguments = {
'enumStringValue': guard_value,
'qualifiedEnumValue': "%s%s" % (enum_prefix, guard_value),
'qualifiedEnumName': _type.type_name(qualified=should_qualify_type)
}
guardedLines.append(Template(decode_template).substitute(template_arguments))
decodeLines.append(wrap_with_guard("\n".join(guardedLines), guard))
template_arguments = {
'enumName': _type.type_name(qualified=should_qualify_type),
'encodeCases': "\n".join(encodeLines),
'decodeCases': "\n".join(decodeLines)
}
return Template(enum_trait_template).substitute(template_arguments)
def generate_input_trait_implementation(self, _input):
template_arguments = {
'inputsNamespace': self.target_framework.setting('namespace'),
'inputTypeImplementation': Template(self.setting('inputTypeTemplate')).substitute(None, inputName=_input.name),
'qualifiedInputName': self.qualified_input_name(_input),
'constructorArguments': self.generate_constructor_arguments_list(_input),
'constructorFormalsList': self.generate_constructor_formals_list(_input),
'encodeSteps': self.generate_input_encode_implementation(_input),
'decodeSteps': self.generate_input_decode_implementation(_input),
}
return wrap_with_guard(Template(Templates.InputTraitsImplementation).substitute(template_arguments), _input.guard)
def generate_input_encode_implementation(self, _input):
steps = []
for (_member, _type) in self.generate_input_member_tuples(_input):
should_qualify_type = _type.framework != self.traits_framework
put_method = "put<%s>" % _type.type_name(qualified=should_qualify_type)
steps.extend([
" encodedValue.%s(ASCIILiteral(\"%s\"), input.%s());" % (put_method, _member.memberName, _member.memberName)
])
if len(steps) == 0:
steps.extend([
" UNUSED_PARAM(encodedValue);",
" UNUSED_PARAM(input);",
])
return "\n".join(steps)
def generate_input_decode_implementation(self, _input):
steps = []
for (_member, _type) in self.generate_input_member_tuples(_input):
should_qualify_type = _type.framework != self.traits_framework
get_method = "get<%s>" % _type.type_name(qualified=should_qualify_type)
lines = [
" %s %s;" % (_type.storage_type(qualified=should_qualify_type), _member.memberName),
" if (!encodedValue.%s(ASCIILiteral(\"%s\"), %s))" % (get_method, _member.memberName, _member.memberName),
" return false;",
""
]
steps.append("\n".join(lines))
if len(steps) == 0:
steps.extend([
" UNUSED_PARAM(encodedValue);",
])
return "\n".join(steps)
def generate_constructor_initializer_list(self, _input):
initializers = []
initializers.append(" : %s()" % (_input.setting('baseClass') % _input.name))
for _member in _input.members:
initializers.append(" , m_%s(%s)" % (_member.memberName, self.generate_member_move_expression(_member)))
return "\n".join(initializers)
def generate_constructor_formals_list(self, _input):
member_tuples = self.generate_input_member_tuples(_input)
return ", ".join(["%s %s" % (_type.argument_type(), _member.memberName) for (_member, _type) in member_tuples])
def generate_member_borrow_expression(self, _member):
_type = self._model.get_type_for_member(_member)
expression = "m_%s" % _member.memberName
if _type.mode == TypeModes.OWNED:
expression = "*" + expression
return expression
def generate_member_move_expression(self, _member):
_type = self._model.get_type_for_member(_member)
if _type.mode == TypeModes.OWNED:
return "WTF::move(%s)" % _member.memberName
else:
return _member.memberName
def generate_constructor_arguments_list(self, _input):
return ", ".join([self.generate_member_move_expression(_member) for _member in _input.members])
def generate_from_specification(input_filepath=None, output_prefix="", output_dirpath=None, framework_name=None, force_output=False):
try:
with open(input_filepath, "r") as input_file:
parsed_json = json.load(input_file)
except ValueError as e:
raise Exception("Error parsing valid JSON in file: " + input_filepath)
if not framework_name in FRAMEWORK_CONFIG_MAP:
raise ParseException("Unknown or unsupported framework name supplied: " + framework_name)
model = InputsModel(parsed_json)
model.resolve_types()
generator = Generator(model, framework_name, input_filepath, output_prefix)
generator.write_output_files(output_dirpath, force_output)
if __name__ == '__main__':
allowed_framework_names = FRAMEWORK_CONFIG_MAP.keys()
cli_parser = optparse.OptionParser(usage="usage: %prog [options] <Inputs.json>")
cli_parser.add_option("-o", "--outputDir", help="Directory where generated files should be written.")
cli_parser.add_option("--framework", type="choice", choices=allowed_framework_names, help="The framework these inputs belong to.") cli_parser.add_option("--force", action="store_true", help="Force output of generated scripts, even if nothing changed.")
cli_parser.add_option("-v", "--debug", action="store_true", help="Log extra output for debugging the generator itself.")
cli_parser.add_option("-t", "--test", action="store_true", help="Enable test mode. Use unique output filenames created by prepending the input filename.")
options = None
arg_options, arg_values = cli_parser.parse_args()
if (len(arg_values) < 1):
raise ParseException("At least one plain argument expected")
if not arg_options.outputDir:
raise ParseException("Missing output directory")
if arg_options.debug:
log.setLevel(logging.DEBUG)
options = {
'input_filepath': arg_values[0],
'output_dirpath': arg_options.outputDir,
'output_prefix': os.path.basename(arg_values[0]) if arg_options.test else "",
'framework_name': arg_options.framework,
'force_output': arg_options.force
}
try:
generate_from_specification(**options)
except (ParseException, TypecheckException) as e:
if arg_options.test:
log.error(e.message)
else:
raise e