mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
stylo: Allow regenerating atoms as part of the normal generation of bindings.
This configures the regeneration of atoms as part of the normal generation of bindings, so it stops being a whole different process. This also adds a generated file to components/style/generated with a convenience macro invocation for pseudo-elements, which comes handy in order to avoid duplication.
This commit is contained in:
parent
54b92015cb
commit
12fcb7a2e7
3 changed files with 226 additions and 79 deletions
|
@ -13,6 +13,8 @@ import copy
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
import regen_atoms
|
||||||
|
|
||||||
DESCRIPTION = 'Regenerate the rust version of the structs or the bindings file.'
|
DESCRIPTION = 'Regenerate the rust version of the structs or the bindings file.'
|
||||||
TOOLS_DIR = os.path.dirname(os.path.abspath(__file__))
|
TOOLS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
COMMON_BUILD_KEY = "__common__"
|
COMMON_BUILD_KEY = "__common__"
|
||||||
|
@ -38,6 +40,7 @@ COMPILATION_TARGETS = {
|
||||||
},
|
},
|
||||||
# Generation of style structs.
|
# Generation of style structs.
|
||||||
"structs": {
|
"structs": {
|
||||||
|
"target_dir": "../gecko_bindings",
|
||||||
"test": True,
|
"test": True,
|
||||||
"flags": [
|
"flags": [
|
||||||
"-ignore-functions",
|
"-ignore-functions",
|
||||||
|
@ -108,6 +111,7 @@ COMPILATION_TARGETS = {
|
||||||
},
|
},
|
||||||
# Generation of the ffi bindings.
|
# Generation of the ffi bindings.
|
||||||
"bindings": {
|
"bindings": {
|
||||||
|
"target_dir": "../gecko_bindings",
|
||||||
"raw_lines": [
|
"raw_lines": [
|
||||||
"use heapsize::HeapSizeOf;",
|
"use heapsize::HeapSizeOf;",
|
||||||
],
|
],
|
||||||
|
@ -140,6 +144,10 @@ COMPILATION_TARGETS = {
|
||||||
"void_types": [
|
"void_types": [
|
||||||
"nsINode", "nsIDocument", "nsIPrincipal", "nsIURI",
|
"nsINode", "nsIDocument", "nsIPrincipal", "nsIURI",
|
||||||
],
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
"atoms": {
|
||||||
|
"custom_build": regen_atoms.build,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,6 +220,17 @@ def build(objdir, target_name, kind_name=None,
|
||||||
assert ((kind_name is None and "build_kinds" not in current_target) or
|
assert ((kind_name is None and "build_kinds" not in current_target) or
|
||||||
(kind_name in current_target["build_kinds"]))
|
(kind_name in current_target["build_kinds"]))
|
||||||
|
|
||||||
|
if "custom_build" in current_target:
|
||||||
|
print("[CUSTOM] {}::{} in \"{}\"... ".format(target_name, kind_name, objdir), end='')
|
||||||
|
sys.stdout.flush()
|
||||||
|
ret = current_target["custom_build"](objdir, verbose=True)
|
||||||
|
if ret != 0:
|
||||||
|
print("FAIL")
|
||||||
|
else:
|
||||||
|
print("OK")
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
if bindgen is None:
|
if bindgen is None:
|
||||||
bindgen = os.path.join(TOOLS_DIR, "rust-bindgen")
|
bindgen = os.path.join(TOOLS_DIR, "rust-bindgen")
|
||||||
|
|
||||||
|
@ -221,18 +240,23 @@ def build(objdir, target_name, kind_name=None,
|
||||||
else:
|
else:
|
||||||
bindgen = [bindgen]
|
bindgen = [bindgen]
|
||||||
|
|
||||||
if output_filename is None:
|
|
||||||
filename = "{}.rs".format(target_name)
|
|
||||||
|
|
||||||
if kind_name is not None:
|
|
||||||
filename = "{}_{}.rs".format(target_name, kind_name)
|
|
||||||
|
|
||||||
output_filename = "{}/../{}".format(TOOLS_DIR, filename)
|
|
||||||
|
|
||||||
if kind_name is not None:
|
if kind_name is not None:
|
||||||
current_target = copy.deepcopy(current_target)
|
current_target = copy.deepcopy(current_target)
|
||||||
extend_object(current_target, current_target["build_kinds"][kind_name])
|
extend_object(current_target, current_target["build_kinds"][kind_name])
|
||||||
|
|
||||||
|
target_dir = None
|
||||||
|
if output_filename is None and "target_dir" in current_target:
|
||||||
|
target_dir = current_target["target_dir"]
|
||||||
|
|
||||||
|
if output_filename is None:
|
||||||
|
output_filename = "{}.rs".format(target_name)
|
||||||
|
|
||||||
|
if kind_name is not None:
|
||||||
|
output_filename = "{}_{}.rs".format(target_name, kind_name)
|
||||||
|
|
||||||
|
if target_dir:
|
||||||
|
output_filename = "{}/{}".format(target_dir, output_filename)
|
||||||
|
|
||||||
print("[BINDGEN] {}::{} in \"{}\"... ".format(target_name, kind_name, objdir), end='')
|
print("[BINDGEN] {}::{} in \"{}\"... ".format(target_name, kind_name, objdir), end='')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
194
ports/geckolib/binding_tools/regen_atoms.py
Executable file
194
ports/geckolib/binding_tools/regen_atoms.py
Executable file
|
@ -0,0 +1,194 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def gnu_symbolify(source, ident):
|
||||||
|
return "_ZN" + str(len(source.CLASS)) + source.CLASS + str(len(ident)) + ident + "E"
|
||||||
|
|
||||||
|
|
||||||
|
def msvc64_symbolify(source, ident):
|
||||||
|
return "?" + ident + "@" + source.CLASS + "@@2PEAV" + source.TYPE + "@@EA"
|
||||||
|
|
||||||
|
|
||||||
|
def msvc32_symbolify(source, ident):
|
||||||
|
return "?" + ident + "@" + source.CLASS + "@@2PAV" + source.TYPE + "@@A"
|
||||||
|
|
||||||
|
|
||||||
|
class GkAtomSource:
|
||||||
|
PATTERN = re.compile('^GK_ATOM\((.+),\s*"(.*)"\)')
|
||||||
|
FILE = "dist/include/nsGkAtomList.h"
|
||||||
|
CLASS = "nsGkAtoms"
|
||||||
|
TYPE = "nsIAtom"
|
||||||
|
|
||||||
|
|
||||||
|
class CSSPseudoElementsAtomSource:
|
||||||
|
PATTERN = re.compile('^CSS_PSEUDO_ELEMENT\((.+),\s*"(.*)",')
|
||||||
|
FILE = "dist/include/nsCSSPseudoElementList.h"
|
||||||
|
CLASS = "nsCSSPseudoElements"
|
||||||
|
# NB: nsICSSPseudoElement is effectively the same as a nsIAtom, but we need
|
||||||
|
# this for MSVC name mangling.
|
||||||
|
TYPE = "nsICSSPseudoElement"
|
||||||
|
|
||||||
|
|
||||||
|
class CSSAnonBoxesAtomSource:
|
||||||
|
PATTERN = re.compile('^CSS_ANON_BOX\((.+),\s*"(.*)"\)')
|
||||||
|
FILE = "dist/include/nsCSSAnonBoxList.h"
|
||||||
|
CLASS = "nsCSSAnonBoxes"
|
||||||
|
TYPE = "nsICSSAnonBoxPseudo"
|
||||||
|
|
||||||
|
|
||||||
|
SOURCES = [
|
||||||
|
GkAtomSource,
|
||||||
|
CSSPseudoElementsAtomSource,
|
||||||
|
CSSAnonBoxesAtomSource,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def map_atom(ident):
|
||||||
|
if ident in {"box", "loop", "match", "mod", "ref",
|
||||||
|
"self", "type", "use", "where", "in"}:
|
||||||
|
return ident + "_"
|
||||||
|
return ident
|
||||||
|
|
||||||
|
|
||||||
|
class Atom:
|
||||||
|
def __init__(self, source, ident, value):
|
||||||
|
self.ident = "{}_{}".format(source.CLASS, ident)
|
||||||
|
self._original_ident = ident
|
||||||
|
self.value = value
|
||||||
|
self.source = source
|
||||||
|
|
||||||
|
def cpp_class(self):
|
||||||
|
return self.source.CLASS
|
||||||
|
|
||||||
|
def gnu_symbol(self):
|
||||||
|
return gnu_symbolify(self.source, self._original_ident)
|
||||||
|
|
||||||
|
def msvc32_symbol(self):
|
||||||
|
return msvc32_symbolify(self.source, self._original_ident)
|
||||||
|
|
||||||
|
def msvc64_symbol(self):
|
||||||
|
return msvc64_symbolify(self.source, self._original_ident)
|
||||||
|
|
||||||
|
def type(self):
|
||||||
|
return self.source.TYPE
|
||||||
|
|
||||||
|
|
||||||
|
def collect_atoms(objdir):
|
||||||
|
atoms = []
|
||||||
|
for source in SOURCES:
|
||||||
|
with open(os.path.join(objdir, source.FILE)) as f:
|
||||||
|
for line in f.readlines():
|
||||||
|
result = re.match(source.PATTERN, line)
|
||||||
|
if result:
|
||||||
|
atoms.append(Atom(source, result.group(1), result.group(2)))
|
||||||
|
return atoms
|
||||||
|
|
||||||
|
PRELUDE = """
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/* Autogenerated file, DO NOT EDIT DIRECTLY */
|
||||||
|
"""[1:]
|
||||||
|
|
||||||
|
|
||||||
|
def write_atom_macro(atoms, file_name):
|
||||||
|
ATOM_TEMPLATE = """
|
||||||
|
#[link_name = "{link_name}"]
|
||||||
|
pub static {name}: *mut {type};
|
||||||
|
"""[1:]
|
||||||
|
|
||||||
|
def write_items(f, func):
|
||||||
|
f.write(" extern {\n")
|
||||||
|
for atom in atoms:
|
||||||
|
f.write(ATOM_TEMPLATE.format(name=atom.ident,
|
||||||
|
link_name=func(atom),
|
||||||
|
type=atom.type()))
|
||||||
|
f.write(" }\n")
|
||||||
|
|
||||||
|
with open(file_name, "wb") as f:
|
||||||
|
f.write(PRELUDE)
|
||||||
|
f.write("use gecko_bindings::structs::nsIAtom;\n\n")
|
||||||
|
f.write("use Atom;\n\n")
|
||||||
|
for source in SOURCES:
|
||||||
|
if source.TYPE != "nsIAtom":
|
||||||
|
f.write("pub enum {} {{}}\n\n".format(source.TYPE))
|
||||||
|
f.write("""
|
||||||
|
#[inline(always)] pub fn unsafe_atom_from_static(ptr: *mut nsIAtom) -> Atom {
|
||||||
|
unsafe { Atom::from_static(ptr) }
|
||||||
|
}\n\n
|
||||||
|
""")
|
||||||
|
f.write("cfg_if! {\n")
|
||||||
|
f.write(" if #[cfg(not(target_env = \"msvc\"))] {\n")
|
||||||
|
write_items(f, Atom.gnu_symbol)
|
||||||
|
f.write(" } else if #[cfg(target_pointer_width = \"64\")] {\n")
|
||||||
|
write_items(f, Atom.msvc64_symbol)
|
||||||
|
f.write(" } else {\n")
|
||||||
|
write_items(f, Atom.msvc32_symbol)
|
||||||
|
f.write(" }\n")
|
||||||
|
f.write("}\n\n")
|
||||||
|
f.write("#[macro_export]\n")
|
||||||
|
f.write("macro_rules! atom {\n")
|
||||||
|
f.writelines(['("%s") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::%s as *mut _) };\n'
|
||||||
|
% (atom.value, atom.ident) for atom in atoms])
|
||||||
|
f.write("}\n")
|
||||||
|
|
||||||
|
|
||||||
|
PSEUDO_ELEMENT_HEADER = """
|
||||||
|
/*
|
||||||
|
* This file contains a helper macro invocation to aid Gecko's style system
|
||||||
|
* pseudo-element integration.
|
||||||
|
*
|
||||||
|
* This file is NOT INTENDED to be compiled as a standalone module.
|
||||||
|
*
|
||||||
|
* Also, it guarantees the property that normal pseudo-elements are processed
|
||||||
|
* before anonymous boxes.
|
||||||
|
*
|
||||||
|
* Expected usage is as follows:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* fn have_to_use_pseudo_elements() {
|
||||||
|
* macro_rules pseudo_element! {
|
||||||
|
* ($pseudo_str_with_colon:expr, $pseudo_atom:expr, $is_anon_box:true) => {{
|
||||||
|
* // Stuff stuff stuff.
|
||||||
|
* }}
|
||||||
|
* }
|
||||||
|
* include!("path/to/helper.rs")
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
"""
|
||||||
|
|
||||||
|
PSEUDO_ELEMENT_MACRO_INVOCATION = """
|
||||||
|
pseudo_element!(\"{}\",
|
||||||
|
atom!(\"{}\"),
|
||||||
|
{});
|
||||||
|
"""[1:]
|
||||||
|
|
||||||
|
|
||||||
|
def write_pseudo_element_helper(atoms, target_filename):
|
||||||
|
with open(target_filename, "wb") as f:
|
||||||
|
f.write(PRELUDE)
|
||||||
|
f.write(PSEUDO_ELEMENT_HEADER)
|
||||||
|
f.write("{\n")
|
||||||
|
for atom in atoms:
|
||||||
|
if atom.type() == "nsICSSPseudoElement":
|
||||||
|
f.write(PSEUDO_ELEMENT_MACRO_INVOCATION.format(atom.value, atom.value, "false"))
|
||||||
|
elif atom.type() == "nsICSSAnonBoxPseudo":
|
||||||
|
f.write(PSEUDO_ELEMENT_MACRO_INVOCATION.format(atom.value, atom.value, "true"))
|
||||||
|
f.write("}\n")
|
||||||
|
|
||||||
|
|
||||||
|
def build(objdir, verbose=False):
|
||||||
|
atoms = collect_atoms(objdir)
|
||||||
|
write_atom_macro(atoms, "../string_cache/atom_macro.rs")
|
||||||
|
write_pseudo_element_helper(atoms, "../../../components/style/generated/gecko_pseudo_element_helper.rs")
|
||||||
|
return 0
|
|
@ -1,71 +0,0 @@
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
|
||||||
print "usage: ./%s PATH/TO/OBJDIR" % sys.argv[0]
|
|
||||||
objdir_path = sys.argv[1]
|
|
||||||
|
|
||||||
|
|
||||||
def line_to_atom(line):
|
|
||||||
result = re.match('^GK_ATOM\((.+),\s*"(.*)"\)', line)
|
|
||||||
return (result.group(1), result.group(2))
|
|
||||||
|
|
||||||
|
|
||||||
def map_atom(ident):
|
|
||||||
if ident in {"box", "loop", "match", "mod", "ref",
|
|
||||||
"self", "type", "use", "where", "in"}:
|
|
||||||
return ident + "_"
|
|
||||||
return ident
|
|
||||||
|
|
||||||
|
|
||||||
def gnu_symbolify(ident):
|
|
||||||
return "_ZN9nsGkAtoms" + str(len(ident)) + ident + "E"
|
|
||||||
|
|
||||||
|
|
||||||
def msvc64_symbolify(ident):
|
|
||||||
return "?" + ident + "@nsGkAtoms@@2PEAVnsIAtom@@EA"
|
|
||||||
|
|
||||||
|
|
||||||
def msvc32_symbolify(ident):
|
|
||||||
return "?" + ident + "@nsGkAtoms@@2PAVnsIAtom@@A"
|
|
||||||
|
|
||||||
|
|
||||||
def write_items(f, func):
|
|
||||||
f.write(" extern {\n")
|
|
||||||
for atom in atoms:
|
|
||||||
f.write(TEMPLATE.format(name=map_atom(atom[0]),
|
|
||||||
link_name=func(atom[0])))
|
|
||||||
f.write(" }\n")
|
|
||||||
|
|
||||||
|
|
||||||
with open(objdir_path + "/dist/include/nsGkAtomList.h") as f:
|
|
||||||
lines = [line for line in f.readlines() if line.startswith("GK_ATOM")]
|
|
||||||
atoms = [line_to_atom(line) for line in lines]
|
|
||||||
|
|
||||||
TEMPLATE = """
|
|
||||||
#[link_name = "{link_name}"]
|
|
||||||
pub static {name}: *mut nsIAtom;
|
|
||||||
"""[1:]
|
|
||||||
|
|
||||||
with open("atom_macro.rs", "wb") as f:
|
|
||||||
f.write("use gecko_bindings::structs::nsIAtom;\n\n")
|
|
||||||
f.write("use Atom;\n\n")
|
|
||||||
f.write("pub fn unsafe_atom_from_static(ptr: *mut nsIAtom) -> Atom { unsafe { Atom::from_static(ptr) } }\n\n")
|
|
||||||
f.write("cfg_if! {\n")
|
|
||||||
f.write(" if #[cfg(not(target_env = \"msvc\"))] {\n")
|
|
||||||
write_items(f, gnu_symbolify)
|
|
||||||
f.write(" } else if #[cfg(target_pointer_width = \"64\")] {\n")
|
|
||||||
write_items(f, msvc64_symbolify)
|
|
||||||
f.write(" } else {\n")
|
|
||||||
write_items(f, msvc32_symbolify)
|
|
||||||
f.write(" }\n")
|
|
||||||
f.write("}\n\n")
|
|
||||||
f.write("#[macro_export]\n")
|
|
||||||
f.write("macro_rules! atom {\n")
|
|
||||||
f.writelines(['("%s") => { $crate::atom_macro::unsafe_atom_from_static($crate::atom_macro::%s) };\n'
|
|
||||||
% (atom[1], map_atom(atom[0])) for atom in atoms])
|
|
||||||
f.write("}\n")
|
|
Loading…
Add table
Add a link
Reference in a new issue