diff --git a/css/ast/src/lib.rs b/css/ast/src/lib.rs index e3571bb7f265f..f88dfb35f4c15 100644 --- a/css/ast/src/lib.rs +++ b/css/ast/src/lib.rs @@ -10,18 +10,29 @@ pub struct Text { #[ast_node] pub struct Stylesheet { pub span: Span, - pub rules: Vec, + pub rules: Vec, } #[ast_node] -pub struct Rule { +pub struct StyleRule { pub span: Span, pub selectors: Vec, pub properties: Vec, } #[ast_node] -pub enum Selector {} +pub struct Selector { + pub span: Span, + pub base: BaseSelector, + pub pseudo_class: Option, + pub pseudo_element: Option, +} + +#[ast_node] +pub enum BaseSelector { + #[tag("Id")] + Id(Text), +} #[ast_node] pub struct Property { diff --git a/css/parser/Cargo.toml b/css/parser/Cargo.toml index e32d1f3f4c1bb..a19279f723fee 100644 --- a/css/parser/Cargo.toml +++ b/css/parser/Cargo.toml @@ -7,3 +7,8 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +swc_atoms = { version = "0.2", path = "../../atoms" } +swc_common = { version = "0.9.0", path = "../../common" } +swc_css_ast = { version = "0.1.0", path = "../ast" } +nom = "5.1.2" +serde = { version = "1", features = ["derive"] } \ No newline at end of file diff --git a/css/parser/src/input.rs b/css/parser/src/input.rs new file mode 100644 index 0000000000000..2e532771d9edf --- /dev/null +++ b/css/parser/src/input.rs @@ -0,0 +1,115 @@ +use nom::{Compare, CompareResult, InputIter, InputLength, InputTake, Slice, UnspecializedInput}; +use std::{ + ops::{Deref, Range, RangeFrom, RangeTo}, + str::{CharIndices, Chars}, +}; +use swc_common::{BytePos, Span}; +use swc_css_ast::Text; + +#[derive(Debug, Clone, Copy)] +pub struct Input<'i> { + start: BytePos, + end: BytePos, + src: &'i str, +} + +impl<'i> Input<'i> { + pub const fn empty() -> Self { + Self::new(BytePos(0), BytePos(0), "") + } + + pub const fn new(start: BytePos, end: BytePos, src: &'i str) -> Self { + Self { start, end, src } + } + + #[inline(always)] + pub fn span(self) -> Span { + Span::new(self.start, self.end, Default::default()) + } +} + +macro_rules! impl_slice { + ($T:ident) => { + impl Slice<$T> for Input<'_> { + fn slice(&self, range: $T) -> Self { + let s = self.src.slice(range); + + Self::new(self.start, self.start + BytePos(s.as_bytes().len() as _), s) + } + } + }; +} + +impl_slice!(Range); +impl_slice!(RangeFrom); +impl_slice!(RangeTo); + +impl<'i> From> for Text { + fn from(i: Input) -> Self { + Self { + span: Span::new(i.start, i.end, Default::default()), + sym: i.src.into(), + } + } +} + +impl InputTake for Input<'_> { + fn take(&self, count: usize) -> Self { + self.slice(..count) + } + + fn take_split(&self, count: usize) -> (Self, Self) { + (self.slice(..count), self.slice(count..)) + } +} + +impl<'a> Compare<&'a str> for Input<'_> { + fn compare(&self, t: &'a str) -> CompareResult { + self.src.compare(t) + } + + fn compare_no_case(&self, t: &'a str) -> CompareResult { + self.src.compare_no_case(t) + } +} + +impl InputLength for Input<'_> { + fn input_len(&self) -> usize { + self.src.as_bytes().len() + } +} + +impl UnspecializedInput for Input<'_> {} + +impl<'a> InputIter for Input<'a> { + type Item = char; + type Iter = CharIndices<'a>; + type IterElem = Chars<'a>; + + fn iter_indices(&self) -> Self::Iter { + self.src.iter_indices() + } + + fn iter_elements(&self) -> Self::IterElem { + self.src.iter_elements() + } + + fn position

(&self, predicate: P) -> Option + where + P: Fn(Self::Item) -> bool, + { + self.src.position(predicate) + } + + fn slice_index(&self, count: usize) -> Option { + self.src.slice_index(count) + } +} + +impl Deref for Input<'_> { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.src + } +} diff --git a/css/parser/src/lib.rs b/css/parser/src/lib.rs index 8b137891791fe..8623b82ad265e 100644 --- a/css/parser/src/lib.rs +++ b/css/parser/src/lib.rs @@ -1 +1,9 @@ +pub use self::input::Input; +use nom::IResult; +use swc_css_ast::Stylesheet; +pub type PResult<'a, T> = IResult>; + +mod input; + +pub fn parse(s: Input) -> PResult {}