diff --git a/src/components/macros/macros.rs b/src/components/macros/macros.rs index fabfc8bb7c0..ecd8915dbc4 100644 --- a/src/components/macros/macros.rs +++ b/src/components/macros/macros.rs @@ -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) + -> Box { + 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, 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> + } + + impl MacResult for MacItems { + fn make_items(&self) -> Option>> { + Some(SmallVector::many(self.items.clone())) + } + } + + box MacItems { items: vec![struct_def, impl_def] } as Box +} + #[macro_export] macro_rules! bitfield( diff --git a/src/components/style/properties/mod.rs.mako b/src/components/style/properties/mod.rs.mako index e699c392a77..975bdd3c9ce 100644 --- a/src/components/style/properties/mod.rs.mako +++ b/src/components/style/properties/mod.rs.mako @@ -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); }