mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Move PropertyBitField to a syntax extension.
This is a first step towards moving away the Mako template in the style crate.
This commit is contained in:
parent
0ba9c9e3ed
commit
d6002a0a50
2 changed files with 141 additions and 65 deletions
|
@ -4,14 +4,133 @@
|
|||
|
||||
#![crate_name = "macros"]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
|
||||
#![feature(macro_rules)]
|
||||
#![feature(macro_rules, plugin_registrar, quote)]
|
||||
|
||||
//! Exports macros for use in other Servo crates.
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate sync;
|
||||
|
||||
extern crate rustc;
|
||||
extern crate syntax;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ext::base;
|
||||
use syntax::ext::base::{ExtCtxt, MacResult};
|
||||
use syntax::parse::token;
|
||||
use syntax::util::small_vector::SmallVector;
|
||||
use rustc::plugin::Registry;
|
||||
use std::gc::{Gc, GC};
|
||||
|
||||
|
||||
#[plugin_registrar]
|
||||
pub fn plugin_registrar(reg: &mut Registry) {
|
||||
reg.register_syntax_extension(
|
||||
token::intern("bit_struct"),
|
||||
base::IdentTT(box base::BasicIdentMacroExpander {
|
||||
expander: expand_bit_struct,
|
||||
span: None,
|
||||
}, None));
|
||||
}
|
||||
|
||||
fn expand_bit_struct(cx: &mut ExtCtxt, sp: Span, name: ast::Ident, tts: Vec<ast::TokenTree>)
|
||||
-> Box<base::MacResult> {
|
||||
let mut fields = Vec::new();
|
||||
for (i, e) in tts.iter().enumerate() {
|
||||
if i & 1 == 1 {
|
||||
match *e {
|
||||
ast::TTTok(_, token::COMMA) => (),
|
||||
_ => {
|
||||
cx.span_err(sp, "bit_struct! expecting comma.");
|
||||
return base::DummyResult::any(sp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match *e {
|
||||
ast::TTTok(_, token::IDENT(ident, _)) => {
|
||||
fields.push(ident)
|
||||
}
|
||||
_ => {
|
||||
cx.span_err(sp, "bit_struct! requires ident args.");
|
||||
return base::DummyResult::any(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let bits_per_word =
|
||||
if cfg!(target_word_size = "64") { 64 }
|
||||
else if cfg!(target_word_size = "32") { 32 }
|
||||
else { fail!("Unexpected target word size") };
|
||||
let nb_words = (fields.len() - 1 + bits_per_word) / bits_per_word;
|
||||
|
||||
let struct_def = quote_item!(&*cx,
|
||||
pub struct $name {
|
||||
storage: [uint, ..$nb_words]
|
||||
}
|
||||
).unwrap();
|
||||
let impl_def = quote_item!(&*cx,
|
||||
impl $name {
|
||||
#[inline]
|
||||
pub fn new() -> $name {
|
||||
$name { storage: [0, ..$nb_words] }
|
||||
}
|
||||
}
|
||||
).unwrap();
|
||||
|
||||
// Unwrap from Gc<T>, which does not implement DerefMut
|
||||
let mut impl_def = (*impl_def).clone();
|
||||
match impl_def.node {
|
||||
ast::ItemImpl(_, _, _, ref mut methods) => {
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
let setter_name = "set_".to_string() + field.as_str();
|
||||
let setter = token::str_to_ident(setter_name.as_slice());
|
||||
let word = i / bits_per_word;
|
||||
let bit = i % bits_per_word;
|
||||
let additional_impl = quote_item!(&*cx,
|
||||
impl $name {
|
||||
#[allow(non_snake_case_functions)]
|
||||
pub fn $field(&self) -> bool {
|
||||
(self.storage[$word] & (1 << $bit)) != 0
|
||||
}
|
||||
#[allow(non_snake_case_functions)]
|
||||
pub fn $setter(&mut self, new_value: bool) {
|
||||
if new_value {
|
||||
self.storage[$word] |= 1 << $bit
|
||||
} else {
|
||||
self.storage[$word] &= !(1 << $bit)
|
||||
}
|
||||
}
|
||||
}
|
||||
).unwrap();
|
||||
match additional_impl.node {
|
||||
ast::ItemImpl(_, _, _, ref additional_methods) => {
|
||||
methods.push_all(additional_methods.as_slice());
|
||||
}
|
||||
_ => fail!()
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => fail!()
|
||||
}
|
||||
// Re-wrap.
|
||||
let impl_def = box(GC) impl_def;
|
||||
|
||||
struct MacItems {
|
||||
items: Vec<Gc<ast::Item>>
|
||||
}
|
||||
|
||||
impl MacResult for MacItems {
|
||||
fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
|
||||
Some(SmallVector::many(self.items.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
box MacItems { items: vec![struct_def, impl_def] } as Box<MacResult>
|
||||
}
|
||||
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! bitfield(
|
||||
|
|
|
@ -21,7 +21,6 @@ pub use self::common_types::*;
|
|||
use selector_matching::DeclarationBlock;
|
||||
|
||||
|
||||
pub use self::property_bit_field::PropertyBitField;
|
||||
pub mod common_types;
|
||||
|
||||
|
||||
|
@ -1339,53 +1338,11 @@ pub mod shorthands {
|
|||
}
|
||||
|
||||
|
||||
// TODO(SimonSapin): Convert this to a syntax extension rather than a Mako template.
|
||||
// Maybe submit for inclusion in libstd?
|
||||
mod property_bit_field {
|
||||
use std::uint;
|
||||
use std::mem;
|
||||
|
||||
pub struct PropertyBitField {
|
||||
storage: [uint, ..(${len(LONGHANDS)} - 1 + uint::BITS) / uint::BITS]
|
||||
}
|
||||
|
||||
impl PropertyBitField {
|
||||
#[inline]
|
||||
pub fn new() -> PropertyBitField {
|
||||
PropertyBitField { storage: unsafe { mem::zeroed() } }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get(&self, bit: uint) -> bool {
|
||||
(self.storage[bit / uint::BITS] & (1 << (bit % uint::BITS))) != 0
|
||||
}
|
||||
#[inline]
|
||||
fn set(&mut self, bit: uint) {
|
||||
self.storage[bit / uint::BITS] |= 1 << (bit % uint::BITS)
|
||||
}
|
||||
#[inline]
|
||||
fn clear(&mut self, bit: uint) {
|
||||
self.storage[bit / uint::BITS] &= !(1 << (bit % uint::BITS))
|
||||
}
|
||||
% for i, property in enumerate(LONGHANDS):
|
||||
#[allow(non_snake_case_functions)]
|
||||
#[inline]
|
||||
pub fn get_${property.ident}(&self) -> bool {
|
||||
self.get(${i})
|
||||
}
|
||||
#[allow(non_snake_case_functions)]
|
||||
#[inline]
|
||||
pub fn set_${property.ident}(&mut self) {
|
||||
self.set(${i})
|
||||
}
|
||||
#[allow(non_snake_case_functions)]
|
||||
#[inline]
|
||||
pub fn clear_${property.ident}(&mut self) {
|
||||
self.clear(${i})
|
||||
}
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
bit_struct! PropertyBitField [
|
||||
% for property in LONGHANDS:
|
||||
${property.ident},
|
||||
% endfor
|
||||
]
|
||||
|
||||
|
||||
/// Declarations are stored in reverse order.
|
||||
|
@ -1508,12 +1465,12 @@ impl PropertyDeclaration {
|
|||
return ExperimentalProperty
|
||||
}
|
||||
% endif
|
||||
if seen.get_${property.ident}() {
|
||||
if seen.${property.ident}() {
|
||||
return ValidOrIgnoredDeclaration
|
||||
}
|
||||
match longhands::${property.ident}::parse_declared(value, base_url) {
|
||||
Ok(value) => {
|
||||
seen.set_${property.ident}();
|
||||
seen.set_${property.ident}(true);
|
||||
result_list.push(${property.camel_case}Declaration(value));
|
||||
ValidOrIgnoredDeclaration
|
||||
},
|
||||
|
@ -1526,15 +1483,15 @@ impl PropertyDeclaration {
|
|||
% endfor
|
||||
% for shorthand in SHORTHANDS:
|
||||
"${shorthand.name}" => {
|
||||
if ${" && ".join("seen.get_%s()" % sub_property.ident
|
||||
if ${" && ".join("seen.%s()" % sub_property.ident
|
||||
for sub_property in shorthand.sub_properties)} {
|
||||
return ValidOrIgnoredDeclaration
|
||||
}
|
||||
match CSSWideKeyword::parse(value) {
|
||||
Ok(InheritKeyword) => {
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
if !seen.get_${sub_property.ident}() {
|
||||
seen.set_${sub_property.ident}();
|
||||
if !seen.${sub_property.ident}() {
|
||||
seen.set_${sub_property.ident}(true);
|
||||
result_list.push(
|
||||
${sub_property.camel_case}Declaration(Inherit));
|
||||
}
|
||||
|
@ -1543,8 +1500,8 @@ impl PropertyDeclaration {
|
|||
},
|
||||
Ok(InitialKeyword) => {
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
if !seen.get_${sub_property.ident}() {
|
||||
seen.set_${sub_property.ident}();
|
||||
if !seen.${sub_property.ident}() {
|
||||
seen.set_${sub_property.ident}(true);
|
||||
result_list.push(
|
||||
${sub_property.camel_case}Declaration(Initial));
|
||||
}
|
||||
|
@ -1553,8 +1510,8 @@ impl PropertyDeclaration {
|
|||
},
|
||||
Ok(UnsetKeyword) => {
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
if !seen.get_${sub_property.ident}() {
|
||||
seen.set_${sub_property.ident}();
|
||||
if !seen.${sub_property.ident}() {
|
||||
seen.set_${sub_property.ident}(true);
|
||||
result_list.push(${sub_property.camel_case}Declaration(
|
||||
${"Inherit" if sub_property.style_struct.inherited else "Initial"}
|
||||
));
|
||||
|
@ -1565,8 +1522,8 @@ impl PropertyDeclaration {
|
|||
Err(()) => match shorthands::${shorthand.ident}::parse(value, base_url) {
|
||||
Ok(result) => {
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
if !seen.get_${sub_property.ident}() {
|
||||
seen.set_${sub_property.ident}();
|
||||
if !seen.${sub_property.ident}() {
|
||||
seen.set_${sub_property.ident}(true);
|
||||
result_list.push(${sub_property.camel_case}Declaration(
|
||||
match result.${sub_property.ident} {
|
||||
Some(value) => SpecifiedValue(value),
|
||||
|
@ -1813,10 +1770,10 @@ fn cascade_with_cached_declarations(applicable_declarations: &[DeclarationBlock]
|
|||
% if property.derived_from is None:
|
||||
${property.camel_case}Declaration(ref ${'_' if not style_struct.inherited else ''}declared_value) => {
|
||||
% if style_struct.inherited:
|
||||
if seen.get_${property.ident}() {
|
||||
if seen.${property.ident}() {
|
||||
continue
|
||||
}
|
||||
seen.set_${property.ident}();
|
||||
seen.set_${property.ident}(true);
|
||||
let computed_value = match *declared_value {
|
||||
SpecifiedValue(ref specified_value)
|
||||
=> longhands::${property.ident}::to_computed_value(
|
||||
|
@ -2020,10 +1977,10 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock],
|
|||
% for property in style_struct.longhands:
|
||||
% if property.derived_from is None:
|
||||
${property.camel_case}Declaration(ref declared_value) => {
|
||||
if seen.get_${property.ident}() {
|
||||
if seen.${property.ident}() {
|
||||
continue
|
||||
}
|
||||
seen.set_${property.ident}();
|
||||
seen.set_${property.ident}(true);
|
||||
let computed_value = match *declared_value {
|
||||
SpecifiedValue(ref specified_value)
|
||||
=> longhands::${property.ident}::to_computed_value(
|
||||
|
@ -2081,7 +2038,7 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock],
|
|||
}
|
||||
|
||||
// The initial value of display may be changed at computed value time.
|
||||
if !seen.get_display() {
|
||||
if !seen.display() {
|
||||
let box_ = style_box_.make_unique_experimental();
|
||||
box_.display = longhands::display::to_computed_value(box_.display, &context);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue