blob: 29554459240f06334dcd9154602e3d4d3b84d811 [file] [log] [blame]
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import web_idl
from . import name_style
from .code_node import Likeliness
from .code_node import SymbolDefinitionNode
from .code_node import SymbolNode
from .code_node import TextNode
from .code_node_cxx import CxxIfElseNode
from .code_node_cxx import CxxLikelyIfNode
from .code_node_cxx import CxxUnlikelyIfNode
from .codegen_format import format_template as _format
def blink_class_name(idl_definition):
"""
Returns the class name of Blink implementation.
"""
class_name = idl_definition.code_generator_info.receiver_implemented_as
if class_name:
return class_name
if isinstance(idl_definition,
(web_idl.CallbackFunction, web_idl.CallbackInterface)):
return name_style.class_("v8", idl_definition.identifier)
else:
return name_style.class_(idl_definition.identifier)
def v8_bridge_class_name(idl_definition):
"""
Returns the name of V8-from/to-Blink bridge class.
"""
assert isinstance(idl_definition, (web_idl.Namespace, web_idl.Interface))
return name_style.class_("v8", idl_definition.identifier)
def blink_type_info(idl_type):
"""
Returns the types of Blink implementation corresponding to the given IDL
type. The returned object has the following attributes.
member_t: The type of a member variable. E.g. T => Member<T>
ref_t: The type of a local variable that references to an already-existing
value. E.g. String => String&
const_ref_t: A const-qualified reference type.
value_t: The type of a variable that behaves as a value. E.g. String =>
String
is_nullable: True if the Blink implementation type can represent IDL null
value by itself.
"""
assert isinstance(idl_type, web_idl.IdlType)
class TypeInfo(object):
def __init__(self,
typename,
member_fmt="{}",
ref_fmt="{}",
const_ref_fmt="{}",
value_fmt="{}",
is_nullable=False):
self.member_t = member_fmt.format(typename)
self.ref_t = ref_fmt.format(typename)
self.value_t = value_fmt.format(typename)
# Whether Blink impl type can represent IDL null or not.
self.is_nullable = is_nullable
real_type = idl_type.unwrap(typedef=True)
if real_type.is_boolean or real_type.is_numeric:
cxx_type = {
"boolean": "bool",
"byte": "int8_t",
"octet": "uint8_t",
"short": "int16_t",
"unsigned short": "uint16_t",
"long": "int32_t",
"unsigned long": "uint32_t",
"long long": "int64_t",
"unsigned long long": "uint64_t",
"float": "float",
"unrestricted float": "float",
"double": "double",
"unrestricted double": "double",
}
return TypeInfo(cxx_type[real_type.keyword_typename])
if real_type.is_string or real_type.is_enumeration:
return TypeInfo(
"String",
ref_fmt="{}&",
const_ref_fmt="const {}&",
is_nullable=True)
if real_type.is_buffer_source_type:
return TypeInfo(
'DOM{}'.format(real_type.keyword_typename),
member_fmt="Member<{}>",
ref_fmt="{}*",
const_ref_fmt="const {}*",
value_fmt="{}*",
is_nullable=True)
if real_type.is_symbol:
assert False, "Blink does not support/accept IDL symbol type."
if real_type.is_any or real_type.is_object:
return TypeInfo(
"ScriptValue",
ref_fmt="{}&",
const_ref_fmt="const {}&",
is_nullable=True)
if real_type.is_void:
assert False, "Blink does not support/accept IDL void type."
if real_type.type_definition_object is not None:
blink_impl_type = blink_class_name(real_type.type_definition_object)
return TypeInfo(
blink_impl_type,
member_fmt="Member<{}>",
ref_fmt="{}*",
const_ref_fmt="const {}*",
value_fmt="{}*",
is_nullable=True)
if (real_type.is_sequence or real_type.is_frozen_array
or real_type.is_variadic):
element_type = blink_type_info(real_type.element_type)
return TypeInfo(
"VectorOf<{}>".format(element_type.value_t),
ref_fmt="{}&",
const_ref_fmt="const {}&")
if real_type.is_record:
key_type = blink_type_info(real_type.key_type)
value_type = blink_type_info(real_type.value_type)
return TypeInfo(
"VectorOfPairs<{}, {}>".format(key_type.value_t,
value_type.value_t),
ref_fmt="{}&",
const_ref_fmt="const {}&")
if real_type.is_promise:
return TypeInfo(
"ScriptPromise", ref_fmt="{}&", const_ref_fmt="const {}&")
if real_type.is_union:
def_obj = real_type.union_definition_object
blink_impl_type = blink_class_name(def_obj)
return TypeInfo(
blink_impl_type,
ref_fmt="{}&",
const_ref_fmt="const {}&",
is_nullable=def_obj.does_include_nullable_type)
if real_type.is_nullable:
inner_type = blink_type_info(real_type.inner_type)
if inner_type.is_nullable:
return inner_type
return TypeInfo(
"base::Optional<{}>".format(inner_type.value_t),
ref_fmt="{}&",
const_ref_fmt="const {}&")
assert False, "Unknown type: {}".format(idl_type.syntactic_form)
def native_value_tag(idl_type):
"""Returns the tag type of NativeValueTraits."""
assert isinstance(idl_type, web_idl.IdlType)
real_type = idl_type.unwrap(typedef=True)
if (real_type.is_boolean or real_type.is_numeric or real_type.is_string
or real_type.is_any or real_type.is_object):
return "IDL{}".format(real_type.type_name)
if real_type.is_symbol:
assert False, "Blink does not support/accept IDL symbol type."
if real_type.is_void:
assert False, "Blink does not support/accept IDL void type."
if real_type.type_definition_object is not None:
return blink_type_info(real_type).value_t
if real_type.is_sequence:
return "IDLSequence<{}>".format(
native_value_tag(real_type.element_type))
if real_type.is_record:
return "IDLRecord<{}, {}>".format(
native_value_tag(real_type.key_type),
native_value_tag(real_type.value_type))
if real_type.is_promise:
return "IDLPromise"
if real_type.is_union:
return blink_type_info(real_type).value_t
if real_type.is_nullable:
return "IDLNullable<{}>".format(native_value_tag(real_type.inner_type))
def make_default_value_expr(idl_type, default_value):
"""
Returns a set of C++ expressions to be used for initialization with default
values. The returned object has the following attributes.
initializer: Used as "Type var(|initializer|);". This is None if
"Type var;" sets an appropriate default value.
assignment_value: Used as "var = |assignment_value|;".
"""
assert default_value.is_type_compatible_with(idl_type)
if idl_type.is_union:
for member_type in idl_type.flattened_member_types:
if default_value.is_type_compatible_with(member_type):
idl_type = member_type
break
assert default_value.is_type_compatible_with(idl_type)
type_info = blink_type_info(idl_type)
is_initializer_lightweight = False
if default_value.idl_type.is_nullable:
if idl_type.unwrap().type_definition_object is not None:
initializer = "nullptr"
is_initializer_lightweight = True
assignment_value = "nullptr"
elif idl_type.unwrap().is_string:
initializer = None # String::IsNull() by default
assignment_value = "String()"
elif type_info.value_t == "ScriptValue":
initializer = None # ScriptValue::IsEmpty() by default
assignment_value = "ScriptValue()"
else:
assert not type_info.is_nullable
initializer = None # !base::Optional::has_value() by default
assignment_value = "base::nullopt"
elif default_value.idl_type.is_sequence:
initializer = None # VectorOf<T>::size() == 0 by default
assignment_value = "{}()".format(type_info.value_t)
elif default_value.idl_type.is_object:
dict_name = blink_class_name(idl_type.unwrap().type_definition_object)
value = _format("{}::Create()", dict_name)
initializer = value
assignment_value = value
elif default_value.idl_type.is_boolean:
value = "true" if default_value.value else "false"
initializer = value
is_initializer_lightweight = True
assignment_value = value
elif default_value.idl_type.is_integer:
initializer = default_value.literal
is_initializer_lightweight = True
assignment_value = default_value.literal
elif default_value.idl_type.is_floating_point_numeric:
if default_value.value == float("NaN"):
value_fmt = "std::numeric_limits<{type}>::quiet_NaN()"
elif default_value.value == float("Infinity"):
value_fmt = "std::numeric_limits<{type}>::infinity()"
elif default_value.value == float("-Infinity"):
value_fmt = "-std::numeric_limits<{type}>::infinity()"
else:
value_fmt = "{value}"
value = value_fmt.format(
type=type_info.value_t, value=default_value.literal)
initializer = value
is_initializer_lightweight = True
assignment_value = value
elif default_value.idl_type.is_string:
value = "\"{}\"".format(default_value.value)
initializer = value
assignment_value = value
else:
assert False
class DefaultValueExpr:
def __init__(self, initializer, is_initializer_lightweight,
assignment_value):
assert initializer is None or isinstance(initializer, str)
assert isinstance(is_initializer_lightweight, bool)
assert isinstance(assignment_value, str)
self.initializer = initializer
self.is_initializer_lightweight = is_initializer_lightweight
self.assignment_value = assignment_value
return DefaultValueExpr(
initializer=initializer,
is_initializer_lightweight=is_initializer_lightweight,
assignment_value=assignment_value)
def make_v8_to_blink_value(blink_var_name,
v8_value_expr,
idl_type,
default_value=None):
"""
Returns a SymbolNode whose definition converts a v8::Value to a Blink value.
"""
assert isinstance(blink_var_name, str)
assert isinstance(v8_value_expr, str)
assert isinstance(idl_type, web_idl.IdlType)
assert (default_value is None
or isinstance(default_value, web_idl.LiteralConstant))
T = TextNode
F = lambda *args, **kwargs: T(_format(*args, **kwargs))
def create_definition(symbol_node):
blink_value_expr = _format(
"NativeValueTraits<{_1}>::NativeValue({_2})",
_1=native_value_tag(idl_type),
_2=", ".join(["${isolate}", v8_value_expr, "${exception_state}"]))
if default_value is None:
return SymbolDefinitionNode(symbol_node, [
F("const auto& ${{{}}} = {};", blink_var_name,
blink_value_expr),
CxxUnlikelyIfNode(
cond="${exception_state}.HadException()",
body=T("return;")),
])
nodes = []
type_info = blink_type_info(idl_type)
default_expr = make_default_value_expr(idl_type, default_value)
if default_expr.initializer is None:
nodes.append(F("{} ${{{}}};", type_info.value_t, blink_var_name))
elif default_expr.is_initializer_lightweight:
nodes.append(
F("{} ${{{}}} = {};", type_info.value_t, blink_var_name,
default_expr.initializer))
assignment = [
F("${{{}}} = {};", blink_var_name, blink_value_expr),
CxxUnlikelyIfNode(
cond="${exception_state}.HadException()", body=T("return;")),
]
if (default_expr.initializer is None
or default_expr.is_initializer_lightweight):
nodes.append(
CxxLikelyIfNode(
cond="!{}->IsUndefined()".format(v8_value_expr),
body=assignment))
else:
nodes.append(
CxxIfElseNode(
cond="{}->IsUndefined()".format(v8_value_expr),
then=F("${{{}}} = {};", blink_var_name,
default_expr.assignment_value),
then_likeliness=Likeliness.LIKELY,
else_=assignment,
else_likeliness=Likeliness.LIKELY))
return SymbolDefinitionNode(symbol_node, nodes)
return SymbolNode(blink_var_name, definition_constructor=create_definition)
def make_v8_to_blink_value_variadic(blink_var_name, v8_array,
v8_array_start_index, idl_type):
"""
Returns a SymbolNode whose definition converts an array of v8::Value
(variadic arguments) to a Blink value.
"""
assert isinstance(blink_var_name, str)
assert isinstance(v8_array, str)
assert isinstance(v8_array_start_index, (int, long))
assert isinstance(idl_type, web_idl.IdlType)
pattern = "const auto& ${{{_1}}} = ToImplArguments<{_2}>({_3});"
_1 = blink_var_name
_2 = native_value_tag(idl_type.element_type)
_3 = [v8_array, str(v8_array_start_index), "${exception_state}"]
text = _format(pattern, _1=_1, _2=_2, _3=", ".join(_3))
def create_definition(symbol_node):
return SymbolDefinitionNode(symbol_node, [
TextNode(text),
CxxUnlikelyIfNode(
cond="${exception_state}.HadException()",
body=TextNode("return;")),
])
return SymbolNode(blink_var_name, definition_constructor=create_definition)