blob: 52b72f615541258cb994e486112c9fbf7537f9f1 [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 .blink_v8_bridge import blink_class_name
from .blink_v8_bridge import blink_type_info
from .blink_v8_bridge import make_blink_to_v8_value
from .blink_v8_bridge import make_default_value_expr
from .blink_v8_bridge import make_v8_to_blink_value
from .blink_v8_bridge import native_value_tag
from .code_node import Likeliness
from .code_node import ListNode
from .code_node import SequenceNode
from .code_node import SymbolNode
from .code_node import SymbolScopeNode
from .code_node import TextNode
from .code_node_cxx import CxxClassDefNode
from .code_node_cxx import CxxFuncDeclNode
from .code_node_cxx import CxxFuncDefNode
from .code_node_cxx import CxxIfElseNode
from .code_node_cxx import CxxLikelyIfNode
from .code_node_cxx import CxxNamespaceNode
from .codegen_accumulator import CodeGenAccumulator
from .codegen_context import CodeGenContext
from .codegen_expr import expr_from_exposure
from .codegen_format import format_template as _format
from .codegen_utils import collect_forward_decls_and_include_headers
from .codegen_utils import component_export
from .codegen_utils import component_export_header
from .codegen_utils import enclose_with_header_guard
from .codegen_utils import make_copyright_header
from .codegen_utils import make_forward_declarations
from .codegen_utils import make_header_include_directives
from .codegen_utils import write_code_node_to_file
from .mako_renderer import MakoRenderer
from .package_initializer import package_initializer
from .path_manager import PathManager
from .task_queue import TaskQueue
_DICT_MEMBER_PRESENCE_PREDICATES = {
"ScriptValue": "!{}.IsEmpty()",
"ScriptPromise": "!{}.IsEmpty()",
}
def _blink_member_name(member):
assert isinstance(member, web_idl.DictionaryMember)
class BlinkMemberName(object):
def __init__(self, member):
blink_name = (member.code_generator_info.property_implemented_as
or member.identifier)
self.get_api = name_style.api_func(blink_name)
self.get_or_api = name_style.api_func(blink_name, "or")
self.set_api = name_style.api_func("set", blink_name)
self.has_api = name_style.api_func("has", blink_name)
# C++ data member that shows the presence of the IDL member.
self.presence_var = name_style.member_var("has", blink_name)
# C++ data member that holds the value of the IDL member.
self.value_var = name_style.member_var_f("member_{}", blink_name)
# Migration Adapters
self.get_non_null_api = name_style.api_func(blink_name, "non_null")
self.has_non_null_api = name_style.api_func(
"has", blink_name, "non_null")
return BlinkMemberName(member)
def _is_member_always_present(member):
assert isinstance(member, web_idl.DictionaryMember)
return member.is_required or member.default_value is not None
def _does_use_presence_flag(member):
assert isinstance(member, web_idl.DictionaryMember)
return (not _is_member_always_present(member) and blink_type_info(
member.idl_type).member_t not in _DICT_MEMBER_PRESENCE_PREDICATES)
def _member_presence_expr(member):
assert isinstance(member, web_idl.DictionaryMember)
if _is_member_always_present(member):
return "true"
if _does_use_presence_flag(member):
return _blink_member_name(member).presence_var
blink_type = blink_type_info(member.idl_type).member_t
assert blink_type in _DICT_MEMBER_PRESENCE_PREDICATES
_1 = _blink_member_name(member).value_var
return _format(_DICT_MEMBER_PRESENCE_PREDICATES[blink_type], _1)
def bind_member_iteration_local_vars(code_node):
local_vars = [
SymbolNode(
"current_context", "v8::Local<v8::Context> ${current_context} = "
"${isolate}->GetCurrentContext();"),
SymbolNode(
"v8_member_names", "const auto* ${v8_member_names} = "
"GetV8MemberNames(${isolate}).data();"),
SymbolNode(
"is_in_secure_context", "const bool ${is_in_secure_context} = "
"${execution_context}->IsSecureContext();"),
]
# Execution context
node = SymbolNode(
"execution_context", "ExecutionContext* ${execution_context} = "
"ToExecutionContext(${current_context});")
node.accumulate(
CodeGenAccumulator.require_include_headers([
"third_party/blink/renderer/core/execution_context/execution_context.h"
]))
local_vars.append(node)
code_node.register_code_symbols(local_vars)
def _is_default_ctor_available(dictionary):
for member in dictionary.members:
if member.default_value is None:
continue
default_expr = make_default_value_expr(member.idl_type,
member.default_value)
if default_expr.initializer_deps:
return False
return True
def make_create_dict_funcs(cg_context):
assert isinstance(cg_context, CodeGenContext)
dictionary = cg_context.dictionary
name = "Create"
return_type = "${class_name}*"
decls = ListNode()
defs = ListNode()
if _is_default_ctor_available(dictionary):
func_def = CxxFuncDefNode(name=name,
arg_decls=[],
return_type=return_type,
static=True)
decls.append(func_def)
func_def.set_base_template_vars(cg_context.template_bindings())
func_def.body.append(
TextNode("return MakeGarbageCollected<${class_name}>();"))
func_def = CxxFuncDefNode(name=name,
arg_decls=["v8::Isolate* isolate"],
return_type=return_type,
static=True)
decls.append(func_def)
func_def.set_base_template_vars(cg_context.template_bindings())
func_def.body.append(
TextNode("return MakeGarbageCollected<${class_name}>(isolate);"))
arg_decls = [
"v8::Isolate* isolate",
"v8::Local<v8::Value> v8_value",
"ExceptionState& exception_state",
]
func_decl = CxxFuncDeclNode(name=name,
arg_decls=arg_decls,
return_type=return_type,
static=True)
decls.append(func_decl)
func_def = CxxFuncDefNode(name=name,
class_name=cg_context.class_name,
arg_decls=arg_decls,
return_type=return_type)
defs.append(func_def)
func_def.set_base_template_vars(cg_context.template_bindings())
func_def.body.append(
TextNode("""\
DCHECK(!v8_value.IsEmpty());
${class_name}* dictionary = Create(isolate);
dictionary->FillMembers(isolate, v8_value, exception_state);
if (exception_state.HadException()) {
return nullptr;
}
return dictionary;"""))
return decls, defs
def make_dict_constructors(cg_context):
decls = ListNode()
defs = ListNode()
dictionary = cg_context.dictionary
class_name = blink_class_name(dictionary)
member_initializer_list = []
should_construct_in_source = False
for member in dictionary.own_members:
if member.default_value is None:
continue
# In order to avoid cyclic header inclusion of IDL dictionaries, do not
# put dictionary member's initialization in the class definition.
does_initialize_with_dict = member.default_value.idl_type.is_object
if does_initialize_with_dict:
should_construct_in_source = True
default_expr = make_default_value_expr(member.idl_type,
member.default_value)
if (default_expr.initializer_deps == ["isolate"]
or does_initialize_with_dict):
_1 = _blink_member_name(member).value_var
_2 = default_expr.initializer_expr
member_initializer_list.append(_format("{_1}({_2})", _1=_1, _2=_2))
if _is_default_ctor_available(dictionary):
name = class_name
arg_decls = []
return_type = ""
# In order to avoid cyclic header inclusion of IDL dictionaries, do not
# put dictionary member's initialization in the class definition.
if should_construct_in_source:
ctor_decl = CxxFuncDeclNode(name=name,
arg_decls=arg_decls,
return_type=return_type)
decls.append(ctor_decl)
ctor_def = CxxFuncDefNode(
name=name,
class_name=class_name,
arg_decls=arg_decls,
return_type=return_type,
member_initializer_list=member_initializer_list)
defs.append(ctor_def)
else:
ctor_decl = CxxFuncDeclNode(name=name,
arg_decls=arg_decls,
return_type=return_type,
default=True)
decls.append(ctor_decl)
ctor_decl = CxxFuncDeclNode(name=class_name,
arg_decls=["v8::Isolate* isolate"],
return_type="",
explicit=True)
decls.append(ctor_decl)
ctor_decl.set_base_template_vars(cg_context.template_bindings())
member_initializer_list.insert(0, "BaseClass(${isolate})")
ctor_def = CxxFuncDefNode(name=class_name,
class_name=class_name,
arg_decls=["v8::Isolate* isolate"],
return_type="",
member_initializer_list=member_initializer_list)
defs.append(ctor_def)
ctor_def.set_base_template_vars(cg_context.template_bindings())
ctor_def.add_template_var("isolate", "isolate")
return decls, defs
def make_dict_member_get(cg_context):
assert isinstance(cg_context, CodeGenContext)
member = cg_context.dict_member
blink_member_name = _blink_member_name(member)
name = blink_member_name.get_api
idl_type = member.idl_type.unwrap(typedef=True)
blink_type = blink_type_info(idl_type)
const_ref_t = blink_type.const_ref_t
ref_t = blink_type.ref_t
# Since Blink conventionally prefers non-const references to const
# references for the certain types, makes const member's getters return a
# non-const reference. For example, "Node* foo() const;" is preferable to
# "const Node* foo() const;".
if (idl_type.unwrap().is_interface
or idl_type.unwrap().is_callback_interface
or idl_type.unwrap().is_callback_function
or idl_type.unwrap().is_buffer_source_type):
const_ref_t = ref_t
decls = ListNode()
defs = ListNode()
func_def = CxxFuncDefNode(name=name,
arg_decls=[],
return_type=const_ref_t,
const=True)
decls.append(func_def)
func_def.set_base_template_vars(cg_context.template_bindings())
func_def.body.extend([
TextNode(_format("DCHECK({}());", blink_member_name.has_api)),
TextNode(_format("return {};", blink_member_name.value_var)),
])
if ref_t != const_ref_t:
func_def = CxxFuncDefNode(name=name, arg_decls=[], return_type=ref_t)
decls.append(func_def)
func_def.set_base_template_vars(cg_context.template_bindings())
func_def.body.extend([
TextNode(_format("DCHECK({}());", blink_member_name.has_api)),
TextNode(_format("return {};", blink_member_name.value_var)),
])
if idl_type.is_numeric or idl_type.unwrap().is_string:
arg_type = blink_type.const_ref_t
return_type = blink_type.value_t
elif idl_type.unwrap().is_enumeration:
arg_type = ("base::nullopt_t"
if idl_type.is_nullable else blink_type.value_t)
return_type = blink_type.value_t
elif idl_type.unwrap().is_dictionary:
arg_type = "nullptr_t"
return_type = blink_type.const_ref_t
elif idl_type.unwrap().type_definition_object:
arg_type = "nullptr_t"
return_type = blink_type.ref_t
elif idl_type.is_nullable and (idl_type.unwrap().is_sequence
or idl_type.unwrap().is_frozen_array
or idl_type.unwrap().is_record):
arg_type = "base::nullopt_t"
return_type = blink_type.value_t
else:
arg_type = None
return_type = None
if arg_type is not None or return_type is not None:
assert arg_type is not None and return_type is not None
name = blink_member_name.get_or_api
arg_decls = [_format("{} fallback_value", arg_type)]
def should_be_defined_in_source(member):
# sequence<Dictionary> and record<String, Dictionary> are
# implemented with HeapVector and Dictionary's definition is
# required while promise<Dictionary> doesn't require it.
def element_or_value_of(idl_type):
return (idl_type.unwrap().element_type
or idl_type.unwrap().value_type)
idl_type = element_or_value_of(member.idl_type)
while idl_type and element_or_value_of(idl_type):
idl_type = element_or_value_of(idl_type)
return idl_type and idl_type.unwrap().is_dictionary
# In order to avoid cyclic header inclusion of IDL dictionaries,
# whenever the function needs a dictionary's definition, do not put the
# function definition in the header file.
if should_be_defined_in_source(member):
func_decl = CxxFuncDeclNode(name=name,
arg_decls=arg_decls,
return_type=return_type,
const=True)
decls.append(func_decl)
func_def = CxxFuncDefNode(name=name,
class_name=cg_context.class_name,
arg_decls=arg_decls,
return_type=return_type,
const=True)
defs.append(func_def)
func_def.set_base_template_vars(cg_context.template_bindings())
else:
func_def = CxxFuncDefNode(name=name,
arg_decls=arg_decls,
return_type=return_type,
const=True)
decls.append(func_def)
func_def.set_base_template_vars(cg_context.template_bindings())
body_node = TextNode(
_format("""\
if ({has}()) {{
return {get}();
}}
return fallback_value;""",
has=blink_member_name.has_api,
get=blink_member_name.get_api))
func_def.body.append(body_node)
return decls, defs
def make_dict_member_has(cg_context):
assert isinstance(cg_context, CodeGenContext)
member = cg_context.dict_member
decls = ListNode()
defs = ListNode()
func_def = CxxFuncDefNode(
name=_blink_member_name(member).has_api,
arg_decls=[],
return_type="bool",
const=True)
decls.append(func_def)
func_def.set_base_template_vars(cg_context.template_bindings())
body = func_def.body
_1 = _member_presence_expr(member)
body.append(TextNode(_format("return {_1};", _1=_1)))
return decls, defs
def make_dict_member_set(cg_context):
assert isinstance(cg_context, CodeGenContext)
T = TextNode
member = cg_context.dict_member
blink_member_name = _blink_member_name(member)
real_type = member.idl_type.unwrap(typedef=True)
type_info = blink_type_info(real_type)
decls = ListNode()
defs = ListNode()
template_func_def = CxxFuncDefNode(
name=blink_member_name.set_api,
arg_decls=["T&& value"],
return_type="void",
template_params=["typename T"])
decls.append(template_func_def)
# This setter with the explicit type declaration makes it possible to set
# the dictionary member with uniform initialization (especially aggregate
# initialization), e.g. setIntVector({3, 1, 4, 1, 5}).
move_func_decl = CxxFuncDeclNode(
name=blink_member_name.set_api,
arg_decls=[_format("{}&&", type_info.member_t)],
return_type="void")
decls.append(move_func_decl)
move_func_def = CxxFuncDefNode(
name=blink_member_name.set_api,
arg_decls=[_format("{}&& value", type_info.member_t)],
return_type="void",
class_name=cg_context.class_name)
defs.append(move_func_def)
_1 = blink_member_name.value_var
template_func_def.body.append(
T(_format("{_1} = std::forward<T>(value);", _1=_1)))
move_func_def.body.append(T(_format("{_1} = value;", _1=_1)))
if _does_use_presence_flag(member):
set_presense_expr = _format("{} = true;",
blink_member_name.presence_var)
template_func_def.body.append(T(set_presense_expr))
move_func_def.body.append(T(set_presense_expr))
# Migration Adapter
if (real_type.is_nullable and
blink_type_info(real_type).typename.startswith("base::Optional")):
to_null_func_def = CxxFuncDefNode(
name=_format("{}ToNull", blink_member_name.set_api),
arg_decls=[],
return_type="void")
decls.append(to_null_func_def)
to_null_func_def.set_base_template_vars(cg_context.template_bindings())
to_null_func_def.body.append(
T(_format("{}(base::nullopt);", blink_member_name.set_api)))
return decls, defs
def make_dict_member_vars(cg_context):
assert isinstance(cg_context, CodeGenContext)
member = cg_context.dict_member
default_value_initializer = ""
if member.default_value:
default_expr = make_default_value_expr(member.idl_type,
member.default_value)
# In order to avoid cyclic header inclusion of IDL dictionaries, do not
# put dictionary member's initialization in the class definition.
if (default_expr.initializer_expr is not None
and not default_expr.initializer_deps
and not member.default_value.idl_type.is_object):
default_value_initializer = _format("{{{}}}",
default_expr.initializer_expr)
_1 = blink_type_info(member.idl_type).member_t
_2 = _blink_member_name(member).value_var
_3 = default_value_initializer
value_var_def = TextNode(_format("{_1} {_2}{_3};", _1=_1, _2=_2, _3=_3))
if _does_use_presence_flag(member):
_1 = _blink_member_name(member).presence_var
presense_var_def = TextNode(_format("bool {_1} = false;", _1=_1))
else:
presense_var_def = None
return value_var_def, presense_var_def
def make_dict_member_migration_adapters(cg_context):
assert isinstance(cg_context, CodeGenContext)
member = cg_context.dict_member
blink_member_name = _blink_member_name(member)
idl_type = member.idl_type
blink_type = blink_type_info(idl_type)
real_type = idl_type.unwrap(typedef=True)
if (not real_type.is_nullable
or blink_type_info(real_type.inner_type).has_null_value):
return None, None
decls = ListNode([TextNode("// Migration Adapters")])
defs = ListNode()
# Accessors for non-null values, if the usual getter returns
# base::Optional<T>.
blink_inner_type = blink_type_info(real_type.inner_type)
get_api = blink_member_name.get_api
has_api = blink_member_name.has_api
get_non_null_api = blink_member_name.get_non_null_api
has_non_null_api = blink_member_name.has_non_null_api
func_def = CxxFuncDefNode(name=get_non_null_api,
arg_decls=[],
return_type=blink_inner_type.const_ref_t,
const=True)
decls.extend([
TextNode(
_format(
"""\
// Returns the value if this member has a non-null value. Call
// |{}| in advance to check the condition.""", has_non_null_api)),
func_def,
])
func_def.set_base_template_vars(cg_context.template_bindings())
func_def.body.extend([
TextNode(_format("DCHECK({}());", has_non_null_api)),
TextNode(_format("return {}().value();", get_api)),
])
if blink_inner_type.ref_t != blink_inner_type.const_ref_t:
func_def = CxxFuncDefNode(name=get_non_null_api,
arg_decls=[],
return_type=blink_inner_type.ref_t)
decls.append(func_def)
func_def.set_base_template_vars(cg_context.template_bindings())
func_def.body.extend([
TextNode(_format("DCHECK({}());", has_non_null_api)),
TextNode(_format("return {}().value();", get_api)),
])
func_def = CxxFuncDefNode(name=has_non_null_api,
arg_decls=[],
return_type="bool",
const=True)
decls.extend([
TextNode("""\
// Returns true iff this member has a non-null value. Returns false if the
// value is missing or the null value."""),
func_def,
])
func_def.set_base_template_vars(cg_context.template_bindings())
func_def.body.append(
TextNode(_format("return {}() && {}().has_value();", has_api,
get_api)))
return decls, defs
def make_get_v8_dict_member_names_func(cg_context):
assert isinstance(cg_context, CodeGenContext)
dictionary = cg_context.dictionary
name = "GetV8MemberNames"
arg_decls = ["v8::Isolate* isolate"]
return_type = "const base::span<const v8::Eternal<v8::Name>>"
func_decl = CxxFuncDeclNode(
name=name, arg_decls=arg_decls, return_type=return_type, static=True)
func_def = CxxFuncDefNode(
name=name,
class_name=cg_context.class_name,
arg_decls=arg_decls,
return_type=return_type)
func_def.set_base_template_vars(cg_context.template_bindings())
body = func_def.body
if dictionary.own_members:
pattern = "static const char* const kKeyStrings[] = {{{_1}}};"
_1 = ", ".join(
_format("\"{}\"", member.identifier)
for member in dictionary.own_members)
body.extend([
TextNode(_format(pattern, _1=_1)),
TextNode("return V8PerIsolateData::From(isolate)"
"->FindOrCreateEternalNameCache(kKeyStrings, "
"kKeyStrings);"),
])
else:
body.append(TextNode("return {};"))
return func_decl, func_def
def make_fill_with_dict_members_func(cg_context):
assert isinstance(cg_context, CodeGenContext)
dictionary = cg_context.dictionary
name = "FillWithMembers"
arg_decls = [
"v8::Isolate* isolate",
"v8::Local<v8::Object> creation_context",
"v8::Local<v8::Object> v8_dictionary",
]
return_type = "bool"
func_decl = CxxFuncDeclNode(
name=name,
arg_decls=arg_decls,
return_type=return_type,
const=True,
override=True)
func_def = CxxFuncDefNode(
name=name,
class_name=cg_context.class_name,
arg_decls=arg_decls,
return_type=return_type,
const=True)
func_def.set_base_template_vars(cg_context.template_bindings())
body = func_def.body
if dictionary.inherited:
text = """\
if (!BaseClass::FillWithMembers(isolate, creation_context, v8_dictionary)) {
return false;
}"""
body.append(TextNode(text))
body.append(
TextNode("return FillWithOwnMembers("
"isolate, creation_context, v8_dictionary);"))
return func_decl, func_def
def make_fill_with_own_dict_members_func(cg_context):
assert isinstance(cg_context, CodeGenContext)
dictionary = cg_context.dictionary
own_members = dictionary.own_members
name = "FillWithOwnMembers"
arg_decls = [
"v8::Isolate* isolate",
"v8::Local<v8::Object> creation_context",
"v8::Local<v8::Object> v8_dictionary",
]
return_type = "bool"
func_decl = CxxFuncDeclNode(
name=name, arg_decls=arg_decls, return_type=return_type, const=True)
func_def = CxxFuncDefNode(
name=name,
class_name=cg_context.class_name,
arg_decls=arg_decls,
return_type=return_type,
const=True)
func_def.set_base_template_vars(cg_context.template_bindings())
body = func_def.body
body.add_template_var("isolate", "isolate")
body.add_template_var("creation_context", "creation_context")
body.add_template_var("v8_dictionary", "v8_dictionary")
bind_member_iteration_local_vars(body)
for index, member in enumerate(own_members):
member_name = _blink_member_name(member)
v8_member_name = name_style.local_var_f("v8_member_{}",
member.identifier)
body.register_code_symbol(
make_blink_to_v8_value(v8_member_name,
"{}()".format(member_name.get_api),
member.idl_type, "${creation_context}"))
node = CxxLikelyIfNode(
cond="{}()".format(member_name.has_api),
body=TextNode(
_format(
"${v8_dictionary}->CreateDataProperty("
"${current_context}, "
"${v8_member_names}[{index}].Get(${isolate}), "
"${{{v8_member_name}}}"
").ToChecked();",
index=index,
v8_member_name=v8_member_name)))
conditional = expr_from_exposure(member.exposure)
if not conditional.is_always_true:
node = CxxLikelyIfNode(cond=conditional, body=node)
body.append(node)
body.append(TextNode("return true;"))
return func_decl, func_def
def make_fill_dict_members_func(cg_context):
assert isinstance(cg_context, CodeGenContext)
T = TextNode
dictionary = cg_context.dictionary
own_members = dictionary.own_members
required_own_members = list(
member for member in own_members if member.is_required)
name = "FillMembers"
arg_decls = [
"v8::Isolate* isolate",
"v8::Local<v8::Value> v8_value",
"ExceptionState& exception_state",
]
return_type = "void"
func_decl = CxxFuncDeclNode(
name=name, arg_decls=arg_decls, return_type=return_type)
func_def = CxxFuncDefNode(
name=name,
class_name=cg_context.class_name,
arg_decls=arg_decls,
return_type=return_type)
func_def.set_base_template_vars(cg_context.template_bindings())
if required_own_members:
check_required_members_node = T("""\
if (v8_value->IsNullOrUndefined()) {
exception_state.ThrowTypeError(ExceptionMessages::FailedToConstruct(
"${dictionary.identifier}",
"has required members, but null/undefined was passed."));
return;
}""")
else:
check_required_members_node = T("""\
if (v8_value->IsNullOrUndefined()) {
return;
}""")
# [PermissiveDictionaryConversion]
if "PermissiveDictionaryConversion" in dictionary.extended_attributes:
permissive_conversion_node = T("""\
if (!v8_value->IsObject()) {
// [PermissiveDictionaryConversion]
return;
}""")
else:
permissive_conversion_node = T("""\
if (!v8_value->IsObject()) {
exception_state.ThrowTypeError(
ExceptionMessages::FailedToConstruct(
"${dictionary.identifier}", "The value is not of type Object"));
return;
}""")
call_internal_func_node = T("""\
FillMembersInternal(isolate, v8_value.As<v8::Object>(), exception_state);""")
func_def.body.extend([
check_required_members_node,
permissive_conversion_node,
call_internal_func_node,
])
return func_decl, func_def
def make_fill_dict_members_internal_func(cg_context):
assert isinstance(cg_context, CodeGenContext)
T = TextNode
dictionary = cg_context.dictionary
own_members = dictionary.own_members
name = "FillMembersInternal"
arg_decls = [
"v8::Isolate* isolate",
"v8::Local<v8::Object> v8_dictionary",
"ExceptionState& exception_state",
]
return_type = "void"
func_decl = CxxFuncDeclNode(
name=name, arg_decls=arg_decls, return_type=return_type)
func_def = CxxFuncDefNode(
name=name,
class_name=cg_context.class_name,
arg_decls=arg_decls,
return_type=return_type)
func_def.set_base_template_vars(cg_context.template_bindings())
body = func_def.body
body.add_template_var("isolate", "isolate")
body.add_template_var("exception_state", "exception_state")
bind_member_iteration_local_vars(body)
body.register_code_symbols([
SymbolNode("try_block", "v8::TryCatch ${try_block}(${isolate});"),
SymbolNode("v8_value", "v8::Local<v8::Value> ${v8_value};"),
SymbolNode("unused_presence_var", "bool ${unused_presence_var};"),
])
if dictionary.inherited:
text = """\
BaseClass::FillMembersInternal(${isolate}, v8_dictionary, ${exception_state});
if (${exception_state}.HadException()) {
return;
}
"""
body.append(T(text))
for key_index, member in enumerate(own_members):
body.append(make_fill_own_dict_member(key_index, member))
return func_decl, func_def
def make_fill_own_dict_member(key_index, member):
assert isinstance(key_index, int)
assert isinstance(member, web_idl.DictionaryMember)
pattern = """\
if (!bindings::ConvertDictionaryMember<{nvt_tag}, {is_required}>(
${isolate},
${current_context},
v8_dictionary,
${v8_member_names}[{key_index}].Get(${isolate}),
"${{dictionary.identifier}}",
"{member_name}",
{value_var},
{presence_var},
${try_block},
${exception_state})) {{
return;
}}"""
if _does_use_presence_flag(member):
presence_var = _blink_member_name(member).presence_var
else:
presence_var = "${unused_presence_var}"
node = TextNode(
_format(pattern,
nvt_tag=native_value_tag(member.idl_type),
is_required="true" if member.is_required else "false",
key_index=key_index,
member_name=member.identifier,
value_var=_blink_member_name(member).value_var,
presence_var=presence_var))
conditional = expr_from_exposure(member.exposure)
if not conditional.is_always_true:
node = CxxLikelyIfNode(cond=conditional, body=node)
return node
def make_dict_trace_func(cg_context):
assert isinstance(cg_context, CodeGenContext)
T = TextNode
dictionary = cg_context.dictionary
own_members = dictionary.own_members
name = "Trace"
arg_decls = ["Visitor* visitor"]
return_type = "void"
func_decl = CxxFuncDeclNode(name=name,
arg_decls=arg_decls,
return_type=return_type,
const=True,
override=True)
func_def = CxxFuncDefNode(name=name,
class_name=cg_context.class_name,
arg_decls=arg_decls,
return_type=return_type,
const=True)
func_def.set_base_template_vars(cg_context.template_bindings())
body = func_def.body
def make_trace_member_node(member):
pattern = "TraceIfNeeded<{_1}>::Trace(visitor, {_2});"
_1 = blink_type_info(member.idl_type).member_t
_2 = _blink_member_name(member).value_var
return TextNode(_format(pattern, _1=_1, _2=_2))
body.extend(list(map(make_trace_member_node, own_members)))
body.append(TextNode("BaseClass::Trace(visitor);"))
return func_decl, func_def
def generate_dictionary(dictionary_identifier):
assert isinstance(dictionary_identifier, web_idl.Identifier)
web_idl_database = package_initializer().web_idl_database()
dictionary = web_idl_database.find(dictionary_identifier)
path_manager = PathManager(dictionary)
assert path_manager.api_component == path_manager.impl_component, (
"We don't support partial dictionaries across components yet.")
api_component = path_manager.api_component
for_testing = dictionary.code_generator_info.for_testing
path_manager = PathManager(dictionary)
class_name = name_style.class_(blink_class_name(dictionary))
if dictionary.inherited:
base_class_name = blink_class_name(dictionary.inherited)
else:
base_class_name = "bindings::DictionaryBase"
cg_context = CodeGenContext(
dictionary=dictionary,
class_name=class_name,
base_class_name=base_class_name)
# Filepaths
header_path = path_manager.api_path(ext="h")
source_path = path_manager.api_path(ext="cc")
# Root nodes
header_node = ListNode(tail="\n")
header_node.set_accumulator(CodeGenAccumulator())
header_node.set_renderer(MakoRenderer())
source_node = ListNode(tail="\n")
source_node.set_accumulator(CodeGenAccumulator())
source_node.set_renderer(MakoRenderer())
# Namespaces
header_blink_ns = CxxNamespaceNode(name_style.namespace("blink"))
source_blink_ns = CxxNamespaceNode(name_style.namespace("blink"))
# Class definitions
class_def = CxxClassDefNode(cg_context.class_name,
base_class_names=[cg_context.base_class_name],
export=component_export(
api_component, for_testing))
class_def.set_base_template_vars(cg_context.template_bindings())
class_def.top_section.append(
TextNode("using BaseClass = ${base_class_name};"))
# Create functions
create_decl, create_def = make_create_dict_funcs(cg_context)
# Constructor and destructor
constructor_decls, constructor_defs = make_dict_constructors(cg_context)
destructor_decl = CxxFuncDeclNode(
name="~${class_name}", arg_decls=[], return_type="", default=True)
# Fill with members (Blink -> V8 conversion)
(fill_with_members_decl,
fill_with_members_def) = make_fill_with_dict_members_func(cg_context)
(fill_with_own_members_decl, fill_with_own_members_def
) = make_fill_with_own_dict_members_func(cg_context)
# Fill members (V8 -> Blink conversion)
(fill_members_decl,
fill_members_def) = make_fill_dict_members_func(cg_context)
(fill_members_internal_decl, fill_members_internal_def
) = make_fill_dict_members_internal_func(cg_context)
# Misc. functions
(get_v8_member_names_decl,
get_v8_member_names_def) = make_get_v8_dict_member_names_func(cg_context)
trace_decl, trace_def = make_dict_trace_func(cg_context)
member_accessor_decls = ListNode()
member_accessor_defs = ListNode()
member_value_var_defs = ListNode()
member_presense_var_defs = ListNode()
for member in cg_context.dictionary.own_members:
member_context = cg_context.make_copy(dict_member=member)
get_decls, get_defs = make_dict_member_get(member_context)
has_decls, has_defs = make_dict_member_has(member_context)
set_decls, set_defs = make_dict_member_set(member_context)
value_var_def, presense_var_def = make_dict_member_vars(member_context)
(migration_adapter_decls, migration_adapter_defs
) = make_dict_member_migration_adapters(member_context)
member_accessor_decls.extend([
TextNode(""),
get_decls,
has_decls,
set_decls,
migration_adapter_decls,
])
member_accessor_defs.extend([
TextNode(""),
get_defs,
has_defs,
set_defs,
migration_adapter_defs,
])
member_value_var_defs.append(value_var_def)
member_presense_var_defs.append(presense_var_def)
# Header part (copyright, include directives, and forward declarations)
header_node.extend([
make_copyright_header(),
TextNode(""),
enclose_with_header_guard(
ListNode([
make_header_include_directives(header_node.accumulator),
TextNode(""),
header_blink_ns,
]), name_style.header_guard(header_path)),
])
header_blink_ns.body.extend([
make_forward_declarations(header_node.accumulator),
TextNode(""),
])
source_node.extend([
make_copyright_header(),
TextNode(""),
TextNode("#include \"{}\"".format(header_path)),
TextNode(""),
make_header_include_directives(source_node.accumulator),
TextNode(""),
source_blink_ns,
])
source_blink_ns.body.extend([
make_forward_declarations(source_node.accumulator),
TextNode(""),
])
# Assemble the parts.
header_node.accumulator.add_class_decls(["ExceptionState"])
header_node.accumulator.add_include_headers([
(PathManager(dictionary.inherited).api_path(ext="h")
if dictionary.inherited else
"third_party/blink/renderer/platform/bindings/dictionary_base.h"),
component_export_header(api_component, for_testing),
"v8/include/v8.h",
])
source_node.accumulator.add_include_headers([
"third_party/blink/renderer/bindings/core/v8/generated_code_helper.h",
"third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h",
"third_party/blink/renderer/platform/bindings/exception_messages.h",
"third_party/blink/renderer/platform/bindings/exception_state.h",
"third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h",
])
(header_forward_decls, header_include_headers, source_forward_decls,
source_include_headers) = collect_forward_decls_and_include_headers(
map(lambda member: member.idl_type, dictionary.own_members))
header_node.accumulator.add_class_decls(header_forward_decls)
header_node.accumulator.add_include_headers(header_include_headers)
source_node.accumulator.add_class_decls(source_forward_decls)
source_node.accumulator.add_include_headers(source_include_headers)
header_blink_ns.body.append(class_def)
class_def.public_section.extend([
create_decl,
constructor_decls,
destructor_decl,
TextNode(""),
trace_decl,
TextNode(""),
member_accessor_decls,
])
class_def.protected_section.extend([
fill_with_members_decl,
TextNode(""),
fill_members_internal_decl,
])
class_def.private_section.extend([
get_v8_member_names_decl,
TextNode(""),
fill_with_own_members_decl,
TextNode(""),
fill_members_decl,
TextNode(""),
member_value_var_defs,
TextNode(""),
member_presense_var_defs,
])
source_blink_ns.body.extend([
constructor_defs,
TextNode(""),
get_v8_member_names_def,
TextNode(""),
create_def,
TextNode(""),
fill_with_members_def,
TextNode(""),
fill_with_own_members_def,
TextNode(""),
fill_members_def,
TextNode(""),
fill_members_internal_def,
TextNode(""),
member_accessor_defs,
TextNode(""),
trace_def,
])
# Write down to the files.
write_code_node_to_file(header_node, path_manager.gen_path_to(header_path))
write_code_node_to_file(source_node, path_manager.gen_path_to(source_path))
def generate_dictionaries(task_queue):
assert isinstance(task_queue, TaskQueue)
web_idl_database = package_initializer().web_idl_database()
for dictionary in web_idl_database.dictionaries:
task_queue.post_task(generate_dictionary, dictionary.identifier)