mirror of
https://github.com/servo/servo.git
synced 2025-07-19 05:13:55 +01:00
196 lines
6 KiB
Python
Executable file
196 lines
6 KiB
Python
Executable file
#!/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):
|
|
# Prepend "\x01" to avoid LLVM prefixing the mangled name with "_".
|
|
# See https://github.com/rust-lang/rust/issues/36097
|
|
return "\\x01?" + 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
|