use crate::{Cursor, CursorSink, Kind, KindSet, Parse, Parser, Peek, Result, Span, ToNumberValue, Token};
macro_rules! cursor_wrapped {
($ident:ident) => {
impl $crate::ToCursors for $ident {
fn to_cursors(&self, s: &mut impl CursorSink) {
s.append((*self).into());
}
}
impl From<$ident> for $crate::Cursor {
fn from(value: $ident) -> Self {
value.0.into()
}
}
impl From<$ident> for $crate::Token {
fn from(value: $ident) -> Self {
value.0.into()
}
}
impl $crate::ToSpan for $ident {
fn to_span(&self) -> Span {
self.0.to_span()
}
}
impl $crate::SemanticEq for $ident {
fn semantic_eq(&self, s: &Self) -> bool {
self.0.semantic_eq(&s.0)
}
}
};
}
macro_rules! define_kinds {
($($(#[$meta:meta])* $ident:ident,)*) => {
$(
$(#[$meta])*
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct $ident($crate::Cursor);
impl $ident {
pub const fn dummy() -> Self {
Self($crate::Cursor::dummy($crate::Token::dummy($crate::Kind::$ident)))
}
pub fn associated_whitespace(&self) -> $crate::AssociatedWhitespaceRules {
self.0.token().associated_whitespace()
}
pub fn with_associated_whitespace(&self, rules: $crate::AssociatedWhitespaceRules) -> Self {
Self(self.0.with_associated_whitespace(rules))
}
}
impl $crate::ToCursors for $ident {
fn to_cursors(&self, s: &mut impl $crate::CursorSink) {
s.append((*self).into());
}
}
impl<'a> $crate::Peek<'a> for $ident {
fn peek<I>(_: &$crate::Parser<'a, I>, c: $crate::Cursor) -> bool
where
I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
{
c == $crate::Kind::$ident
}
}
impl<'a> $crate::Parse<'a> for $ident {
fn parse<I>(p: &mut $crate::Parser<'a, I>) -> $crate::Result<Self>
where
I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
{
let c = p.next();
if Self::peek(p, c) { Ok(Self(c)) } else { Err($crate::Diagnostic::new(c, $crate::Diagnostic::unexpected))? }
}
}
impl From<$ident> for $crate::Cursor {
fn from(value: $ident) -> Self {
value.0.into()
}
}
impl From<$ident> for $crate::Token {
fn from(value: $ident) -> Self {
value.0.into()
}
}
impl $crate::ToSpan for $ident {
fn to_span(&self) -> $crate::Span {
self.0.to_span()
}
}
impl $crate::SemanticEq for $ident {
fn semantic_eq(&self, s: &Self) -> bool {
self.0.semantic_eq(&s.0)
}
}
)*
};
}
macro_rules! define_kind_idents {
($($(#[$meta:meta])* $ident:ident,)*) => {
$(
$(#[$meta])*
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct $ident($crate::Cursor);
impl $crate::ToCursors for $ident {
fn to_cursors(&self, s: &mut impl $crate::CursorSink) {
s.append((*self).into());
}
}
impl<'a> $crate::Peek<'a> for $ident {
fn peek<I>(_: &$crate::Parser<'a, I>, c: $crate::Cursor) -> bool
where
I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
{
c == $crate::Kind::$ident
}
}
impl<'a> $crate::Parse<'a> for $ident {
fn parse<I>(p: &mut $crate::Parser<'a, I>) -> $crate::Result<Self>
where
I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
{
let c = p.next();
if Self::peek(p, c) { Ok(Self(c)) } else { Err($crate::Diagnostic::new(c, $crate::Diagnostic::unexpected))? }
}
}
impl From<$ident> for $crate::Kind {
fn from(value: $ident) -> Self {
value.0.into()
}
}
impl From<$ident> for $crate::Cursor {
fn from(value: $ident) -> Self {
value.0
}
}
impl From<$ident> for $crate::Token {
fn from(value: $ident) -> Self {
value.0.into()
}
}
impl $crate::ToSpan for $ident {
fn to_span(&self) -> $crate::Span {
self.0.to_span()
}
}
impl $crate::SemanticEq for $ident {
fn semantic_eq(&self, s: &Self) -> bool {
self.0.semantic_eq(&s.0)
}
}
impl $ident {
pub fn is_dashed_ident(&self) -> bool {
self.0.token().is_dashed_ident()
}
pub const fn dummy() -> Self {
Self($crate::Cursor::dummy($crate::Token::dummy($crate::Kind::$ident)))
}
}
)*
};
}
#[macro_export]
macro_rules! custom_delim {
($(#[$meta:meta])* $ident:ident, $ch:literal) => {
$(#[$meta])*
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct $ident($crate::T![Delim]);
impl $crate::ToCursors for $ident {
fn to_cursors(&self, s: &mut impl $crate::CursorSink) {
s.append((*self).into());
}
}
impl<'a> $crate::Peek<'a> for $ident {
fn peek<I>(_: &$crate::Parser<'a, I>, c: $crate::Cursor) -> bool
where
I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
{
c == $crate::Kind::Delim && c == $ch
}
}
impl<'a> $crate::Parse<'a> for $ident {
fn parse<I>(p: &mut $crate::Parser<'a, I>) -> $crate::Result<Self>
where
I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
{
use $crate::Peek;
let delim = p.parse::<$crate::T![Delim]>()?;
if Self::peek(p, delim.into()) {
Ok(Self(delim))
} else {
Err($crate::Diagnostic::new(delim.into(), $crate::Diagnostic::unexpected))?
}
}
}
impl From<$ident> for $crate::Cursor {
fn from(value: $ident) -> Self {
value.0.into()
}
}
impl $crate::ToSpan for $ident {
fn to_span(&self) -> $crate::Span {
self.0.to_span()
}
}
impl PartialEq<char> for $ident {
fn eq(&self, other: &char) -> bool {
self.0 == *other
}
}
impl $crate::SemanticEq for $ident {
fn semantic_eq(&self, other: &Self) -> bool {
self.0.semantic_eq(&other.0)
}
}
};
}
#[macro_export]
macro_rules! custom_double_delim {
($(#[$meta:meta])*$ident: ident, $first: literal, $second: literal) => {
$(#[$meta])*
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct $ident($crate::T![Delim], pub $crate::T![Delim]);
impl $ident {
pub const fn dummy() -> Self {
Self(<$crate::T![Delim]>::dummy(), <$crate::T![Delim]>::dummy())
}
}
impl<'a> $crate::Peek<'a> for $ident {
fn peek<I>(p: &$crate::Parser<'a, I>, c: $crate::Cursor) -> bool
where
I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
{
c == $first && p.peek_n(2) == $second
}
}
impl<'a> $crate::Parse<'a> for $ident {
fn parse<I>(p: &mut $crate::Parser<'a, I>) -> $crate::Result<Self>
where
I: ::std::iter::Iterator<Item = $crate::Cursor> + ::std::clone::Clone,
{
let first = p.parse::<$crate::T![Delim]>()?;
if first != $first {
let c: Cursor = first.into();
Err($crate::Diagnostic::new(c, $crate::Diagnostic::expected_delim))?;
}
let skip = p.set_skip($crate::KindSet::NONE);
let second = p.parse::<$crate::T![Delim]>();
p.set_skip(skip);
let second = second?;
if second != $second {
let c:Cursor = second.into();
Err($crate::Diagnostic::new(c, $crate::Diagnostic::expected_delim))?;
}
Ok(Self(first, second))
}
}
impl<'a> $crate::ToCursors for $ident {
fn to_cursors(&self, s: &mut impl $crate::CursorSink) {
s.append(self.0.into());
s.append(self.1.into());
}
}
impl $crate::ToSpan for $ident {
fn to_span(&self) -> $crate::Span {
self.0.to_span() + self.1.to_span()
}
}
impl $crate::SemanticEq for $ident {
fn semantic_eq(&self, other: &Self) -> bool {
self.0.semantic_eq(&other.0) && self.1.semantic_eq(&other.1)
}
}
};
}
define_kinds! {
Eof,
Comment,
CdcOrCdo,
BadString,
BadUrl,
Delim,
Colon,
Semicolon,
Comma,
LeftCurly,
RightCurly,
LeftSquare,
RightSquare,
LeftParen,
RightParen,
}
impl PartialEq<char> for Delim {
fn eq(&self, other: &char) -> bool {
self.0 == *other
}
}
define_kind_idents! {
Ident,
String,
Url,
Function,
AtKeyword,
Hash,
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct Whitespace(Cursor);
cursor_wrapped!(Whitespace);
impl<'a> Peek<'a> for Whitespace {
fn peek<I>(p: &Parser<'a, I>, _: Cursor) -> bool
where
I: Iterator<Item = Cursor> + Clone,
{
let c = p.peek_n_with_skip(1, KindSet::COMMENTS);
c == Kind::Whitespace
}
}
impl<'a> Parse<'a> for Whitespace {
fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
let skip = p.set_skip(KindSet::COMMENTS);
let c = p.next();
p.set_skip(skip);
if c != Kind::Whitespace {
Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))?
}
Ok(Self(c))
}
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct DashedIdent(Ident);
cursor_wrapped!(DashedIdent);
impl<'a> Peek<'a> for DashedIdent {
fn peek<I>(_: &Parser<'a, I>, c: Cursor) -> bool
where
I: Iterator<Item = Cursor> + Clone,
{
c == Kind::Ident && c.token().is_dashed_ident()
}
}
impl<'a> Parse<'a> for DashedIdent {
fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
let c = p.next();
if Self::peek(p, c) {
Ok(Self(Ident(c)))
} else {
Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))?
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct Dimension(Cursor);
cursor_wrapped!(Dimension);
impl PartialEq<f32> for Dimension {
fn eq(&self, other: &f32) -> bool {
self.0.token().value() == *other
}
}
impl<'a> Peek<'a> for Dimension {
fn peek<I>(_: &Parser<'a, I>, c: Cursor) -> bool
where
I: Iterator<Item = Cursor> + Clone,
{
c == Kind::Dimension
}
}
impl<'a> Parse<'a> for Dimension {
fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
let c = p.next();
if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
}
}
impl From<Dimension> for f32 {
fn from(val: Dimension) -> Self {
val.0.token().value()
}
}
impl ToNumberValue for Dimension {
fn to_number_value(&self) -> Option<f32> {
Some(self.0.token().value())
}
}
impl Dimension {
pub fn value(&self) -> f32 {
self.0.token().value()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct Number(Cursor);
cursor_wrapped!(Number);
impl Number {
pub const NUMBER_ZERO: Number = Number(Cursor::dummy(Token::NUMBER_ZERO));
pub const ZERO: Number = Number(Cursor::dummy(Token::NUMBER_ZERO));
pub fn value(&self) -> f32 {
self.0.token().value()
}
pub fn is_int(&self) -> bool {
self.0.token().is_int()
}
pub fn is_float(&self) -> bool {
self.0.token().is_float()
}
pub fn has_sign(&self) -> bool {
self.0.token().has_sign()
}
pub fn preserve_sign(self) -> Self {
if self.has_sign() { Self(self.0.with_sign_required()) } else { self }
}
}
impl<'a> Peek<'a> for Number {
fn peek<I>(_: &Parser<'a, I>, c: Cursor) -> bool
where
I: Iterator<Item = Cursor> + Clone,
{
c == Kind::Number
}
}
impl<'a> Parse<'a> for Number {
fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
let c = p.next();
if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
}
}
impl From<Number> for f32 {
fn from(value: Number) -> Self {
value.value()
}
}
impl From<Number> for i32 {
fn from(value: Number) -> Self {
value.value() as i32
}
}
impl PartialEq<f32> for Number {
fn eq(&self, other: &f32) -> bool {
self.value() == *other
}
}
impl ToNumberValue for Number {
fn to_number_value(&self) -> Option<f32> {
Some(self.value())
}
}
pub mod delim {
custom_delim! {
And, '&'
}
custom_delim! {
At, '@'
}
custom_delim! {
Caret, '^'
}
custom_delim! {
Dash, '-'
}
custom_delim! {
Dollar, '$'
}
custom_delim! {
Dot, '.'
}
custom_delim! {
Eq, '='
}
custom_delim! {
Gt, '>'
}
custom_delim! {
Hash, '#'
}
custom_delim! {
Lt, '<'
}
custom_delim! {
Bang, '!'
}
custom_delim! {
Or, '|'
}
custom_delim! {
Percent, '%'
}
custom_delim! {
Plus, '+'
}
custom_delim! {
Question, '?'
}
custom_delim! {
Slash, '/'
}
custom_delim! {
Star, '*'
}
custom_delim! {
Tilde, '~'
}
custom_delim! {
Underscore, '_'
}
custom_delim! {
Backtick, '`'
}
}
pub mod double {
use crate::{
Cursor, CursorSink, Kind, KindSet, Parse, Parser, Peek, Result, SemanticEq, Span, T, ToCursors, ToSpan,
};
custom_double_delim! {
GreaterThanEqual, '>', '='
}
custom_double_delim! {
LessThanEqual, '<', '='
}
custom_double_delim! {
StarPipe, '*', '|'
}
custom_double_delim! {
PipePipe, '|', '|'
}
custom_double_delim! {
EqualEqual, '=', '='
}
custom_double_delim! {
TildeEqual, '~', '='
}
custom_double_delim! {
PipeEqual, '|', '='
}
custom_double_delim! {
CaretEqual, '^', '='
}
custom_double_delim! {
DollarEqual, '$', '='
}
custom_double_delim! {
StarEqual, '*', '='
}
custom_double_delim! {
BangEqual, '*', '='
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct ColonColon(T![:], T![:]);
impl ColonColon {
pub const fn dummy() -> Self {
Self(<T![:]>::dummy(), <T![:]>::dummy())
}
}
impl<'a> Peek<'a> for ColonColon {
fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
where
I: Iterator<Item = Cursor> + Clone,
{
c == Kind::Colon && p.peek_n(2) == Kind::Colon
}
}
impl<'a> Parse<'a> for ColonColon {
fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
let first = p.parse::<T![:]>()?;
let skip = p.set_skip(KindSet::NONE);
let second = p.parse::<T![:]>();
p.set_skip(skip);
Ok(Self(first, second?))
}
}
impl ToCursors for ColonColon {
fn to_cursors(&self, s: &mut impl CursorSink) {
s.append(self.0.into());
s.append(self.1.into());
}
}
impl ToSpan for ColonColon {
fn to_span(&self) -> Span {
self.0.to_span() + self.1.to_span()
}
}
impl SemanticEq for ColonColon {
fn semantic_eq(&self, other: &Self) -> bool {
self.0.semantic_eq(&other.0) && self.1.semantic_eq(&other.1)
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct Any(Cursor);
cursor_wrapped!(Any);
impl<'a> Peek<'a> for Any {
fn peek<I>(_: &Parser<'a, I>, _: Cursor) -> bool
where
I: Iterator<Item = Cursor> + Clone,
{
true
}
}
impl<'a> Parse<'a> for Any {
fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
let c = p.next();
Ok(Self(c))
}
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct PairWiseStart(Cursor);
cursor_wrapped!(PairWiseStart);
impl PairWiseStart {
pub fn kind(&self) -> Kind {
self.0.token().kind()
}
pub fn end(&self) -> Kind {
match self.kind() {
Kind::LeftCurly => Kind::RightCurly,
Kind::LeftParen => Kind::RightParen,
Kind::LeftSquare => Kind::RightSquare,
k => k,
}
}
}
impl<'a> Peek<'a> for PairWiseStart {
const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::LeftCurly, Kind::LeftSquare, Kind::LeftParen]);
}
impl<'a> Parse<'a> for PairWiseStart {
fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
let c = p.next();
if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
}
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
pub struct PairWiseEnd(Cursor);
cursor_wrapped!(PairWiseEnd);
impl PairWiseEnd {
pub fn kind(&self) -> Kind {
self.0.token().kind()
}
pub fn start(&self) -> Kind {
match self.kind() {
Kind::RightCurly => Kind::LeftCurly,
Kind::RightParen => Kind::LeftParen,
Kind::RightSquare => Kind::LeftSquare,
k => k,
}
}
}
impl<'a> Peek<'a> for PairWiseEnd {
const PEEK_KINDSET: KindSet = KindSet::new(&[Kind::RightCurly, Kind::RightSquare, Kind::RightParen]);
}
impl<'a> Parse<'a> for PairWiseEnd {
fn parse<I>(p: &mut Parser<'a, I>) -> Result<Self>
where
I: Iterator<Item = Cursor> + Clone,
{
let c = p.next();
if Self::peek(p, c) { Ok(Self(c)) } else { Err(crate::Diagnostic::new(c, crate::Diagnostic::unexpected))? }
}
}
#[macro_export]
macro_rules! T {
[:] => { $crate::token_macros::Colon };
[;] => { $crate::token_macros::Semicolon };
[,] => { $crate::token_macros::Comma };
['{'] => { $crate::token_macros::LeftCurly };
['}'] => { $crate::token_macros::RightCurly };
['['] => { $crate::token_macros::LeftSquare };
[']'] => { $crate::token_macros::RightSquare };
['('] => { $crate::token_macros::LeftParen };
[')'] => { $crate::token_macros::RightParen };
[' '] => { $crate::token_macros::Whitespace };
[&] => { $crate::token_macros::delim::And };
[@] => { $crate::token_macros::delim::At };
[^] => { $crate::token_macros::delim::Caret };
[-] => { $crate::token_macros::delim::Dash };
[$] => { $crate::token_macros::delim::Dollar };
[.] => { $crate::token_macros::delim::Dot };
[=] => { $crate::token_macros::delim::Eq };
[>] => { $crate::token_macros::delim::Gt };
[#] => { $crate::token_macros::delim::Hash };
[<] => { $crate::token_macros::delim::Lt };
[!] => { $crate::token_macros::delim::Bang };
[|] => { $crate::token_macros::delim::Or };
[%] => { $crate::token_macros::delim::Percent };
[+] => { $crate::token_macros::delim::Plus };
[?] => { $crate::token_macros::delim::Question };
[/] => { $crate::token_macros::delim::Slash };
[*] => { $crate::token_macros::delim::Star };
[~] => { $crate::token_macros::delim::Tilde };
[_] => { $crate::token_macros::delim::Underscore };
['`'] => { $crate::token_macros::delim::Backtick };
[>=] => { $crate::token_macros::double::GreaterThanEqual };
[<=] => { $crate::token_macros::double::LessThanEqual };
[*|] => { $crate::token_macros::double::StarPipe };
[::] => { $crate::token_macros::double::ColonColon };
[||] => { $crate::token_macros::double::PipePipe };
[==] => { $crate::token_macros::double::EqualEqual };
[~=] => { $crate::token_macros::double::TildeEqual };
[|=] => { $crate::token_macros::double::PipeEqual };
[^=] => { $crate::token_macros::double::CaretEqual };
["$="] => { $crate::token_macros::double::DollarEqual };
[*=] => { $crate::token_macros::double::StarEqual };
[!=] => { $crate::token_macros::double::BangEqual };
[Dimension::$ident: ident] => { $crate::token_macros::dimension::$ident };
[!important] => { $crate::token_macros::double::BangImportant };
[$ident:ident] => { $crate::token_macros::$ident }
}