diff --git a/crates/hdx_parser/src/css/properties.rs b/crates/hdx_parser/src/css/properties.rs deleted file mode 100644 index 6b0cc157..00000000 --- a/crates/hdx_parser/src/css/properties.rs +++ /dev/null @@ -1,1257 +0,0 @@ -/// Properties -use hdx_ast::css::{ - component_values::ComponentValue, properties::*, unknown::UnknownDeclaration, values::*, -}; -use miette::Result; - -use crate::{atom, diagnostics, Atomizable, Kind, Parse, Parser, Spanned, Token}; - -impl<'a> Parse<'a> for Custom<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let mut important = false; - let name = parser.expect_ident_cased()?; - parser.expect(Kind::Colon)?; - let checkpoint = parser.checkpoint(); - let value_span = parser.span(); - let value_like = ValueLike::parse(parser) - .unwrap_or(ValueLike::Unknown.spanned(value_span.end(parser.pos()))); - parser.rewind(checkpoint); - let mut value = parser.parse_component_values(Kind::Semicolon, true)?; - if parser.at(Kind::Semicolon) { - parser.advance(); - } - if let Some(Spanned { node: ComponentValue::Token(tok), .. }) = value.last() { - if tok.kind == Kind::Ident && tok.as_atom_lower().unwrap() == atom!("important") { - let len = value.len(); - if let Some(Spanned { node: ComponentValue::Token(tok), .. }) = value.get(len - 2) { - if tok.kind == Kind::Delim && tok.value.as_char().unwrap() == '!' { - value.truncate(len - 2); - important = true - } - } - } - } - Ok(Self { name, value_like, value: parser.boxup(value), important } - .spanned(span.end(parser.pos()))) - } -} - -impl<'a> Parse<'a> for ValueLike<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let checkpoint = parser.checkpoint(); - let span = parser.span(); - let token = parser.cur().clone(); - let parsed = MathExpr::::parse(parser); - if let Ok(value) = parsed { - return Ok(Self::Length(parser.boxup(value)).spanned(span.end(parser.pos()))); - } - parser.rewind(checkpoint); - let checkpoint = parser.checkpoint(); - let parsed = MathExpr::::parse(parser); - if let Ok(value) = parsed { - return Ok(Self::LengthPercentage(parser.boxup(value)).spanned(span.end(parser.pos()))); - } - parser.rewind(checkpoint); - let checkpoint = parser.checkpoint(); - let parsed = Expr::::parse(parser); - if let Ok(value) = parsed { - return Ok(Self::Color(parser.boxup(value)).spanned(span.end(parser.pos()))); - } - parser.rewind(checkpoint); - let parsed = ExprList::::parse(parser); - if let Ok(value) = parsed { - return Ok(Self::FontFamily(parser.boxup(value)).spanned(span.end(parser.pos()))); - } - Err(diagnostics::Unexpected(token.kind, token.span).into()) - } -} - -macro_rules! parse_properties { - {$( $prop: ident, )+} => { - $( - impl<'a> Parse<'a> for $prop<'a> { - fn parse(parser: &mut Parser<'a>) -> Result>> { - let span = parser.span(); - parser.parse_declaration( - Some($prop::name_as_atom()), - |parser: &mut Parser<'a>, _name: &Token, value: Spanned<<$prop as Declaration>::Value>, important: bool| { - Ok($prop { value: parser.boxup(value), important }.spanned(span.end(parser.pos()))) - }, - ) - } - } - )+ - - impl<'a> Parse<'a> for Property<'a> { - fn parse(parser: &mut Parser<'a>) -> Result>> { - let span = parser.span(); - if parser.cur().is_dashed_ident() { - let custom = Custom::parse(parser)?; - return Ok(Property::Custom(parser.boxup(custom)).spanned(span.end(parser.pos()))); - } - let checkpoint = parser.checkpoint(); - let property = match PropertyId::from_atom(parser.cur().as_atom_lower().unwrap_or(atom!(""))) { - $( - Some(PropertyId::$prop) => { - $prop::parse(parser).map(|p| Property::$prop(parser.boxup(p))) - } - )+ - _ => { - Err(diagnostics::UnexpectedIdent(parser.cur().as_atom().unwrap(), parser.span()))? - } - } - .or_else(|e| { - parser.rewind(checkpoint); - let parsed = - UnknownDeclaration::parse(parser).map(|p| Property::Unknown(parser.boxup(p))); - parser.warnings.push(e); - parser.warnings.push(diagnostics::UnknownDeclaration(span.end(parser.pos())).into()); - parsed - })?; - Ok(property.spanned(span.end(parser.pos()))) - } - } - } -} - -parse_properties! { - // https://drafts.csswg.org/css-align-3/#property-index - AlignContent, - AlignItems, - AlignSelf, - ColumnGap, - Gap, - JustifyContent, - JustifyItems, - JustifySelf, - PlaceContent, - PlaceItems, - PlaceSelf, - RowGap, - - // https://drafts.csswg.org/css-anchor-position-1/#property-index - AnchorDefault, - AnchorPosition, - PositionFallback, - PositionFallbackBounds, - - // https://drafts.csswg.org/css-animations-1/#property-index - Animation, - AnimationDelay, - AnimationDirection, - // ! animation-duration redefined in css-animations-2 - AnimationFillMode, - AnimationIterationCount, - AnimationName, - AnimationPlayState, - AnimationTimingFunction, - - // https://drafts.csswg.org/css-animations-2/#property-index - AnimationDuration, - AnimationComposition, - AnimationTimeline, - - // https://drafts.csswg.org/css-backgrounds-3/#property-index - Background, - BackgroundAttachment, - // ! background-clip redefined in css-backgrounds-4 - BackgroundColor, - BackgroundImage, - BackgroundOrigin, - // ! background-position redefined in css-backgrounds-4 - BackgroundRepeat, - BackgroundSize, - Border, - BorderBottom, - BorderBottomColor, - BorderBottomLeftRadius, - BorderBottomRightRadius, - BorderBottomStyle, - BorderBottomWidth, - BorderColor, - BorderImage, - BorderImageOutset, - BorderImageRepeat, - BorderImageSlice, - BorderImageSource, - BorderImageWidth, - BorderLeft, - BorderLeftColor, - BorderLeftStyle, - BorderLeftWidth, - BorderRadius, - BorderRight, - BorderRightColor, - BorderRightStyle, - BorderRightWidth, - BorderStyle, - BorderTop, - BorderTopColor, - BorderTopLeftRadius, - BorderTopRightRadius, - BorderTopStyle, - BorderTopWidth, - BorderWidth, - BoxShadow, - - // https://drafts.csswg.org/css-backgrounds-4/#property-index - BackgroundClip, - BackgroundPosition, - BackgroundPositionBlock, - BackgroundPositionInline, - BackgroundPositionX, - BackgroundPositionY, - - - // https://drafts.csswg.org/css-box-3/#property-index - // ! margin redefined in css-box-4 - // ! margin-bottom redefined in css-box-4 - // ! margin-left redefined in css-box-4 - // ! margin-right redefined in css-box-4 - // ! margin-top redefined in css-box-4 - // ! padding redefined in css-box-4 - // ! padding-bottom redefined in css-box-4 - // ! padding-left redefined in css-box-4 - // ! padding-right redefined in css-box-4 - // ! padding-top redefined in css-box-4 - - // https://drafts.csswg.org/css-box-4/#property-index - Margin, - MarginBottom, - MarginLeft, - MarginRight, - MarginTop, - MarginTrim, - Padding, - PaddingBottom, - PaddingLeft, - PaddingRight, - PaddingTop, - - // https://drafts.csswg.org/css-break-3/#property-index - // ! box-decoration-break redefined in css-break-4 - // ! break-after redefined in css-break-4 - // ! break-before redefined in css-break-4 - // ! break-inside redefined in css-break-4 - // ! orphans redefined in css-break-4 - // ! widows redefined in css-break-4 - - // https://drafts.csswg.org/css-break-4/#property-index - BoxDecorationBreak, - BreakAfter, - BreakBefore, - BreakInside, - BreakMargin, - PageBreakAfter, - PageBreakBefore, - PageBreakInside, - Orphans, - Widows, - - // https://drafts.csswg.org/css-cascade-3/#property-index - // ! all redefined in css-cascade-4 - - // https://drafts.csswg.org/css-cascade-4/#property-index - // ! all redefined in css-cascade-5 - - // https://drafts.csswg.org/css-cascade-5/#property-index - All, - - // https://drafts.csswg.org/css-cascade-6/#property-index - // - - // https://drafts.csswg.org/css-color-3/#property-index - // ! color redefined in css-color-4 - // ! opacity redefined in css-color-4 - - // https://drafts.csswg.org/css-color-4/#property-index - Color, - Opacity, - - // https://drafts.csswg.org/css-color-5/#property-index - // - - // https://drafts.csswg.org/css-color-6/#property-index - // - - // https://drafts.csswg.org/css-color-adjust-1/#property-index - ColorAdjust, - ColorScheme, - ForcedColorAdjust, - PrintColorAdjust, - - // https://drafts.csswg.org/css-color-hdr/#property-index - // - - // https://drafts.csswg.org/css-conditional-3/#property-index - // https://drafts.csswg.org/css-conditional-4/#property-index - // https://drafts.csswg.org/css-conditional-5/#property-index - // - - // https://drafts.csswg.org/css-conditional-values-1/#property-index - // - - // https://drafts.csswg.org/css-contain-1/#property-index - // ! contain redefined in css-contain-2 - // ! content-visibility redefined in css-contain-3 - - // https://drafts.csswg.org/css-contain-2/#property-index - Contain, - // ! content-visibility redefined in css-contain-3 - - - // https://drafts.csswg.org/css-contain-3/#property-index - Container, - ContainerName, - ContainerType, - ContentVisibility, - - // https://drafts.csswg.org/css-content-3/#property-index - BookmarkLabel, - BookmarkLevel, - BookmarkState, - Content, - Quotes, - StringSet, - - // https://drafts.csswg.org/css-counter-styles-3/#property-index - // - - // https://drafts.csswg.org/css-display-3/#property-index - // ! display redefined in css-display-4 - // ! order redefined in css-display-4 - // ! visibility redefined in css-display-4 - - // https://drafts.csswg.org/css-display-4/#property-index - Display, - LayoutOrder, - Order, - ReadingOrder, - Visibility, - - // https://drafts.csswg.org/css-easing-1/#property-index - // - - // https://drafts.csswg.org/css-easing-2/#property-index - // - - // https://drafts.csswg.org/css-egg-1/#property-index - // - - // https://drafts.csswg.org/css-env-1/#property-index - // - - // https://drafts.csswg.org/css-exclusions-1/#property-index - WrapFlow, - WrapThrough, - - // https://drafts.csswg.org/css-extensions-1/#property-index - // - - // https://drafts.csswg.org/css-flexbox-1/#property-index - // ! align-content redefined in css-align-3 - // ! align-items redefined in css-align-3 - // ! align-self redefined in css-align-3 - Flex, - FlexBasis, - FlexDirection, - FlexFlow, - FlexGrow, - FlexShrink, - FlexWrap, - // ! justify-content redefined in css-align-3 - - // https://drafts.csswg.org/css-font-loading-3/#property-index - // - - // https://drafts.csswg.org/css-fonts-3/#property-index - // ! font redefined in css-fonts-4 - // ! font-family redefined in css-fonts-4 - // ! font-feature-settings redefined in css-fonts-4 - // ! font-kerning redefined in css-fonts-4 - // ! font-size redefined in css-fonts-4 - // ! font-size-adjust redefined in css-fonts-4 - // ! font-stretch redefined in css-fonts-4 - // ! font-style redefined in css-fonts-4 - // ! font-synthesis redefined in css-fonts-4 - // ! font-variant redefined in css-fonts-4 - // ! font-variant-caps redefined in css-fonts-4 - // ! font-variant-east-asian redefined in css-fonts-4 - // ! font-variant-ligatures redefined in css-fonts-4 - // ! font-variant-numeric redefined in css-fonts-4 - // ! font-variant-position redefined in css-fonts-4 - // ! font-weight redefined in css-fonts-4 - - // https://drafts.csswg.org/css-fonts-4/#property-index - Font, - FontFamily, - FontFeatureSettings, - FontKerning, - FontLanguageOverride, - FontOpticalSizing, - FontPalette, - FontSize, - // ! font-size-adjust redefined in css-fonts-5 - FontStretch, - FontStyle, - FontSynthesis, - FontSynthesisSmallCaps, - FontSynthesisStyle, - FontSynthesisWeight, - FontVariant, - FontVariantAlternates, - FontVariantCaps, - FontVariantEastAsian, - FontVariantEmoji, - FontVariantLigatures, - FontVariantNumeric, - FontVariantPosition, - FontVariationSettings, - FontWeight, - - // https://drafts.csswg.org/css-fonts-5/#property-index - FontSizeAdjust, - - // https://drafts.csswg.org/css-forms-1/#property-index - // - - // https://drafts.csswg.org/css-gcpm-3/#property-index - FootnoteDisplay, - FootnotePolicy, - Running, - // ! string-set redefined in css-content-3 - - // https://drafts.csswg.org/css-gcpm-4/#property-index - CopyInto, - - // https://drafts.csswg.org/css-grid-1/#property-index - // ! grid redefined in css-grid-2 - // ! grid-area redefined in css-grid-2 - // ! grid-auto-columns redefined in css-grid-2 - // ! grid-auto-flow redefined in css-grid-2 - // ! grid-auto-rows redefined in css-grid-2 - // ! grid-column redefined in css-grid-2 - // ! grid-column-end redefined in css-grid-2 - // ! grid-column-start redefined in css-grid-2 - // ! grid-row redefined in css-grid-2 - // ! grid-row-end redefined in css-grid-2 - // ! grid-row-start redefined in css-grid-2 - // ! grid-template redefined in css-grid-2 - // ! grid-template-areas redefined in css-grid-2 - // ! grid-template-columns redefined in css-grid-2 - // ! grid-template-rows redefined in css-grid-2 - - // https://drafts.csswg.org/css-grid-2/#property-index - Grid, - GridArea, - GridAutoColumns, - GridAutoFlow, - GridAutoRows, - GridColumn, - GridColumnEnd, - GridColumnStart, - GridRow, - GridRowEnd, - GridRowStart, - GridTemplate, - GridTemplateAreas, - GridTemplateColumns, - GridTemplateRows, - - // https://drafts.csswg.org/css-grid-3/#property-index - AlignTracks, - JustifyTracks, - MasonryAutoFlow, - - // https://drafts.csswg.org/css-images-3/#property-index - ImageOrientation, - ImageRendering, - // ! object-fit redefined in css-images-4 - ObjectPosition, - - // https://drafts.csswg.org/css-images-4/#property-index - ImageResolution, - ObjectFit, - - // https://drafts.csswg.org/css-images-5/#property-index - ObjectViewBox, - - // https://drafts.csswg.org/css-inline-3/#property-index - AlignmentBaseline, - BaselineSource, - BaselineShift, - DominantBaseline, - InitialLetter, - InitialLetterAlign, - InitialLetterWrap, - InlineSizing, - LineHeight, - TextBoxEdge, - TextBoxTrim, - VerticalAlign, - - // https://drafts.csswg.org/css-line-grid-1/#property-index - BoxSnap, - LineGrid, - LineSnap, - - // https://drafts.csswg.org/css-link-params-1/#property-index - LinkParameters, - - // https://drafts.csswg.org/css-lists-3/#property-index - CounterIncrement, - CounterReset, - CounterSet, - ListStyle, - ListStyleImage, - ListStylePosition, - ListStyleType, - MarkerSide, - - // https://drafts.csswg.org/css-logical-1/#property-index - BlockSize, - BorderBlock, - BorderBlockColor, - BorderBlockEnd, - BorderBlockEndColor, - BorderBlockEndStyle, - BorderBlockEndWidth, - BorderBlockStart, - BorderBlockStartColor, - BorderBlockStartStyle, - BorderBlockStartWidth, - BorderBlockStyle, - BorderBlockWidth, - BorderEndEndRadius, - BorderEndStartRadius, - BorderInline, - BorderInlineColor, - BorderInlineEnd, - BorderInlineEndColor, - BorderInlineEndStyle, - BorderInlineEndWidth, - BorderInlineStart, - BorderInlineStartColor, - BorderInlineStartStyle, - BorderInlineStartWidth, - BorderInlineStyle, - BorderInlineWidth, - BorderStartEndRadius, - BorderStartStartRadius, - InlineSize, - // ! inset redefined in css-position-3 - // ! inset-block redefined in css-position-3 - // ! inset-inline redefined in css-position-3 - // ! inset-block-end redefined in css-position-3 - // ! inset-inline redefined in css-position-3 - // ! inset-inline-end redefined in css-position-3 - // ! inset-inline-start redefined in css-position-3 - MarginBlock, - MarginBlockEnd, - MarginBlockStart, - MarginInline, - MarginInlineEnd, - MarginInlineStart, - MaxBlockSize, - MaxInlineSize, - MinBlockSize, - MinInlineSize, - PaddingBlock, - PaddingBlockEnd, - PaddingBlockStart, - PaddingInline, - PaddingInlineEnd, - PaddingInlineStart, - - // https://drafts.csswg.org/css-mobile/#property-index - // - - // https://drafts.csswg.org/css-multicol-1/#property-index - ColumnCount, - ColumnFill, - ColumnRule, - ColumnRuleColor, - ColumnRuleStyle, - ColumnRuleWidth, - // ! column-span redined in css-multicol-2 - ColumnWidth, - Columns, - - // https://drafts.csswg.org/css-multicol-2/#property-index - ColumnSpan, - - // https://drafts.csswg.org/css-namespaces-3/#property-index - // - - // https://drafts.csswg.org/css-nav-1/#property-index - SpatialNavigationAction, - SpatialNavigationContain, - SpatialNavigationFunction, - - // https://drafts.csswg.org/css-nesting-1/#property-index - // - - // https://drafts.csswg.org/css-overflow-3/#property-index - Overflow, - OverflowBlock, - // ! overflow-clip-margin redined in css-overflow-4 - OverflowInline, - OverflowX, - OverflowY, - ScrollBehavior, - ScrollbarGutter, - // ! text-overflow redined in css-overflow-4 - - // https://drafts.csswg.org/css-overflow-4/#property-index - // (Yes this is really in the spec as -webkit-line-clamp) - WebkitLineClamp, - BlockEllipsis, - Continue, - LineClamp, - MaxLines, - OverflowClipMargin, - OverflowClipMarginBlock, - OverflowClipMarginBlockEnd, - OverflowClipMarginBlockStart, - OverflowClipMarginBottom, - OverflowClipMarginInline, - OverflowClipMarginInlineEnd, - OverflowClipMarginInlineStart, - OverflowClipMarginLeft, - OverflowClipMarginRight, - OverflowClipMarginTop, - TextOverflow, - - // https://drafts.csswg.org/css-overscroll-1/#property-index - OverscrollBehavior, - OverscrollBehaviorBlock, - OverscrollBehaviorInline, - OverscrollBehaviorX, - OverscrollBehaviorY, - - // https://drafts.csswg.org/css-page-3/#property-index - Page, - - // https://drafts.csswg.org/css-page-4/#property-index - // - - // https://drafts.csswg.org/css-page-floats-3/#property-index - Clear, - Float, - FloatDefer, - FloatOffset, - FloatReference, - - // https://drafts.csswg.org/css-page-template-1/#property-index - // - - // https://drafts.csswg.org/css-position-3/#property-index - Bottom, - Inset, - InsetBlock, - InsetBlockEnd, - InsetBlockStart, - InsetInline, - InsetInlineEnd, - InsetInlineStart, - Left, - Position, - Right, - Top, - - // https://drafts.csswg.org/css-preslev-1/#property-index - // - - // https://drafts.csswg.org/css-print/#property-index - // - - // https://drafts.csswg.org/css-pseudo-4/#property-index - // - - // https://drafts.csswg.org/css-regions-1/#property-index - FlowFrom, - FlowInto, - RegionFragment, - - // https://drafts.csswg.org/css-rhythm-1/#property-index - BlockStep, - BlockStepAlign, - BlockStepInsert, - BlockStepRound, - BlockStepSize, - LineHeightStep, - - // https://drafts.csswg.org/css-round-display-1/#property-index - BorderBoundary, - ShapeInside, - - // https://drafts.csswg.org/css-ruby-1/#property-index - RubyAlign, - RubyMerge, - RubyOverhang, - RubyPosition, - - // https://drafts.csswg.org/css-scoping-1/#property-index - // - - // https://drafts.csswg.org/css-scroll-anchoring-1/#property-index - OverflowAnchor, - - // https://drafts.csswg.org/css-scroll-snap-1/#property-index - ScrollMargin, - ScrollMarginBlock, - ScrollMarginBlockEnd, - ScrollMarginBlockStart, - ScrollMarginBottom, - ScrollMarginInline, - ScrollMarginInlineEnd, - ScrollMarginInlineStart, - ScrollMarginLeft, - ScrollMarginRight, - ScrollMarginTop, - ScrollPadding, - ScrollPaddingBlock, - ScrollPaddingBlockEnd, - ScrollPaddingBlockStart, - ScrollPaddingBottom, - ScrollPaddingInline, - ScrollPaddingInlineEnd, - ScrollPaddingInlineStart, - ScrollPaddingLeft, - ScrollPaddingRight, - ScrollPaddingTop, - ScrollSnapAlign, - ScrollSnapStop, - ScrollSnapType, - - // https://drafts.csswg.org/css-scroll-snap-2/#property-index - ScrollStart, - ScrollStartBlock, - ScrollStartInline, - ScrollStartTarget, - ScrollStartTargetBlock, - ScrollStartTargetInline, - ScrollStartTargetX, - ScrollStartTargetY, - ScrollStartX, - ScrollStartY, - - // https://drafts.csswg.org/css-scrollbars-1/#property-index - ScrollbarColor, - ScrollbarWidth, - - // https://drafts.csswg.org/css-shadow-parts-1/#property-index - // - - // https://drafts.csswg.org/css-shapes-1/#property-index - ShapeImageThreshold, - ShapeMargin, - ShapeOutside, - - // https://drafts.csswg.org/css-size-adjust-1/#property-index - TextSizeAdjust, - - // https://drafts.csswg.org/css-shapes-2/#property-index - // ! shape-inside is redefined in css-round-display-1 - ShapePadding, - - // https://drafts.csswg.org/css-sizing-3/#property-index - BoxSizing, - Height, - MaxHeight, - MaxWidth, - MinHeight, - MinWidth, - Width, - - // https://drafts.csswg.org/css-sizing-4/#property-index - AspecRatio, - ContainIntrinsicBlockSize, - ContainIntrinsicHeight, - ContainIntrinsicInlineSize, - ContainIntrinsicSize, - ContainIntrinsicWidth, - MinIntrinsicSizing, - - // https://drafts.csswg.org/css-speech-1/#property-index - Cue, - CueAfter, - CueBefore, - Pause, - PauseAfter, - PauseBefore, - Rest, - RestAfter, - RestBefore, - Speak, - SpeakAs, - VoiceBalance, - VoiceDuration, - VoiceFamily, - VoicePitch, - VoiceRange, - VoiceRate, - VoiceStress, - VoiceVolume, - - // https://drafts.csswg.org/css-style-attr-1/#property-index - // - - // https://drafts.csswg.org/css-syntax-3/#property-index - // - - // https://drafts.csswg.org/css-tables-3/#property-index - BorderCollapse, - BorderSpacing, - CaptionSide, - EmptyCells, - TableLayout, - - // https://drafts.csswg.org/css-template-1/#property-index - // TODO: Is this even a thing? - - - // https://drafts.csswg.org/css-text-3/#property-index - // ! hanging-punctuation redefined in css-text-4 - // ! hypens redefined in css-text-4 - // ! letter-spacing redefined in css-text-4 - // ! line-break redefined in css-text-4 - // ! overflow-wrap redefined in css-text-4 - // ! tab-size redefined in css-text-4 - // ! text-align redefined in css-text-4 - // ! text-align-all redefined in css-text-4 - // ! text-align-last redefined in css-text-4 - // ! text-indent redefined in css-text-4 - // ! text-justify redefined in css-text-4 - // ! text-transform redefined in css-text-4 - // ! white-space redefined in css-text-4 - // ! word-break redefined in css-text-4 - // ! word-spacing redefined in css-text-4 - // ! word-wrap redefined in css-text-4 - - // https://drafts.csswg.org/css-text-4/#property-index - HangingPunctuation, - HyphenateCharacter, - HyphenateLimitChars, - HyphenateLimitLast, - HyphenateLimitLines, - HyphenateLimitZone, - Hyphens, - LetterSpacing, - LineBreak, - LinePadding, - OverflowWrap, - TabSize, - TextAlign, - TextAlignAll, - TextAlignLast, - TextAutospace, - TextGroupAlign, - TextIndent, - TextJustify, - TextSpacing, - TextSpacingTrim, - TextTransform, - TextWrap, - WhiteSpace, - WhiteSpaceCollapse, - WhiteSpaceTrim, - WordBoundaryDetection, - WordBoundaryExpansion, - WordBreak, - WordSpacing, - WordWrap, - WrapAfter, - WrapBefore, - WrapInside, - - // https://drafts.csswg.org/css-text-decor-3/#property-index - // ! text-decoration redefined in css-text-decor-4 - // ! text-decoration-color redefined in css-text-decor-4 - // ! text-decoration-line redefined in css-text-decor-4 - // ! text-emphasis redefined in css-text-decor-4 - // ! text-emphasis-color redefined in css-text-decor-4 - // ! text-emphasis-position redefined in css-text-decor-4 - // ! text-emphasis-style redefined in css-text-decor-4 - // ! tex-tshadow redefined in css-text-decor-4 - // ! text-underline-position redefined in css-text-decor-4 - - // https://drafts.csswg.org/css-text-decor-4/#property-index - TextDecoration, - TextDecorationColor, - TextDecorationLine, - TextDecorationSkip, - TextDecorationSkipInk, - TextDecorationSkipSelf, - TextDecorationSkipSpaces, - TextDecorationStyle, - TextDecorationThickness, - TextDecorationTrim, - TextEmphasis, - TextEmphasisColor, - TextEmphasisPosition, - TextEmphasisSkip, - TextEmphasisStyle, - TextShadow, - TextUnderlineOffset, - TextUnderlinePosition, - - // https://drafts.csswg.org/css-transitions-1/#property-index - Transition, - TransitionDelay, - TransitionDuration, - TransitionProperty, - TransitionTimingFunction, - - // https://drafts.csswg.org/css-transitions-2/#property-index - // - - // https://drafts.csswg.org/css-tv/#property-index - // - - // https://drafts.csswg.org/css-ui-3/#property-index - // ! box-sizing refined in css-sizing-3 - // ! caret-color redefined in css-ui-4 - // ! outline redefined in css-ui-4 - // ! outline redefined in css-ui-4 - // ! outline-color redefined in css-ui-4 - // ! outline-offset redefined in css-ui-4 - // ! outline-style redefined in css-ui-4 - // ! outline-width redefined in css-ui-4 - // ! resize redefined in css-ui-4 - // ! text-overflow redefined in css-overflow-4 - - // https://drafts.csswg.org/css-ui-4/#property-index - AccentColor, - Appearance, - Caret, - CaretColor, - CaretShape, - Cursor, - InputSecurity, - NavDown, - NavLeft, - NavRight, - NavUp, - Outline, - OutlineColor, - OutlineOffset, - OutlineStyle, - OutlineWidth, - PointerEvents, - Resize, - UserSelect, - - // https://drafts.csswg.org/css-values-3/#property-index - // - - // https://drafts.csswg.org/css-values-4/#property-index - // - - // https://drafts.csswg.org/css-values-5/#property-index - // - - // https://drafts.csswg.org/css-variables-1/#property-index - // This spec defines the properties. - - // https://drafts.csswg.org/css-variables-2/#property-index - // This spec defines the properties. - - // https://drafts.csswg.org/css-view-transitions-1/#property-index - ViewTransitionName, - - // https://drafts.csswg.org/css-viewport/#property-index - // - - // https://drafts.csswg.org/css-will-change-1/#property-index - WillChange, - - // https://drafts.csswg.org/css-writing-modes-3/#property-index - // ! direction is redefined in css-text-decor-4 - // ! glyph-orientation-horizontal is redefined in css-text-decor-4 - // ! text-combine-upright is redefined in css-text-decor-4 - // ! text-orientation is redefined in css-text-decor-4 - // ! unicode-bidi is redefined in css-text-decor-4 - // ! writing-mode is redefined in css-text-decor-4 - - // https://drafts.csswg.org/css-writing-modes-4/#property-index - Direction, - GlyphOrientationHorizontal, - TextCombineUpright, - TextOrientation, - UnicodeBidi, - WritingMode, - - // https://drafts.csswg.org/css2/#property-index - // ! background is redefined in css-backgrounds-3 - // ! background-attachment is redefined in css-backgrounds-3 - // ! background-color is redefined in css-backgrounds-3 - // ! background-image is redefined in css-backgrounds-3 - // ! background-position is redefined in css-backgrounds-3 - // ! background-repeat is redefined in css-backgrounds-3 - // ! border is redefined in css-backgrounds-3 - // ! border-bottom is redefined in css-backgrounds-3 - // ! border-bottom-color is redefined in css-backgrounds-3 - // ! border-bottom-style is redefined in css-backgrounds-3 - // ! border-bottom-width is redefined in css-backgrounds-3 - // ! border-collapse is redefined in css-tables-3 - // ! border-color is redefined in css-backgrounds-3 - // ! border-left is redefined in css-backgrounds-3 - // ! border-left-color is redefined in css-backgrounds-3 - // ! border-left-style is redefined in css-backgrounds-3 - // ! border-left-width is redefined in css-backgrounds-3 - // ! border-right is redefined in css-backgrounds-3 - // ! border-right-color is redefined in css-backgrounds-3 - // ! border-right-style is redefined in css-backgrounds-3 - // ! border-right-width is redefined in css-backgrounds-3 - // ! border-spacing is redefined in css-tables-3 - // ! border-style is redefined in css-backgrounds-3 - // ! border-top is redefined in css-backgrounds-3 - // ! border-top-color is redefined in css-backgrounds-3 - // ! border-top-style is redefined in css-backgrounds-3 - // ! border-top-width is redefined in css-backgrounds-3 - // ! border-width is redefined in css-backgrounds-3 - // ! bottom is redefined in css-position-3 - // ! caption-side is redefined in css-tables-3 - // ! clear is redefined in css-page-floats-3 - // ! clip is redefined in css-masking-3 - // ! color is redefined in css-color-3 - // ! content is redefined in css-content-3 - // ! counter-increment is redefined in css-lists-3 - // ! counter-reset is redefined in css-lists-3 - // ! cursor is redefined in css-ui-4 - // ! direction is redefined in css-writing-modes-4 - // ! display is redefined in css-display-3 - // ! empty-cells is redefined in css-tables-3 - // ! float is redefined in css-page-floats-3 - // ! font is redefined in css-fonts-3 - // ! font-family is redefined in css-fonts-3 - // ! font-size is redefined in css-fonts-3 - // ! font-style is redefined in css-fonts-3 - // ! font-variant is redefined in css-fonts-3 - // ! font-weight is redefined in css-fonts-3 - // ! height is redefined in css-sizing-3 - // ! left is redefined in css-position-3 - // ! letter-spacing is redefined in css-text-decor-4 - // ! line-height is redefined in css-line-grid-1 - // ! list-style is redefined in css-lists-3 - // ! list-style-image is redefined in css-lists-3 - // ! list-style-position is redefined in css-lists-3 - // ! list-style-type is redefined in css-lists-3 - // ! margin is redefined in css-box-3 - // ! margin-bottom is redefined in css-box-3 - // ! margin-left is redefined in css-box-3 - // ! margin-right is redefined in css-box-3 - // ! margin-top is redefined in css-box-3 - // ! max-height is redefined in css-sizing-3 - // ! max-width is redefined in css-sizing-3 - // ! min-height is redefined in css-sizing-3 - // ! min-width is redefined in css-sizing-3 - // ! orphans is redefined in css-page-3 - // ! outline is redefined in css-ui-4 - // ! outline-color is redefined in css-ui-4 - // ! outline-style is redefined in css-ui-4 - // ! outline-width is redefined in css-ui-4 - // ! overflow is redefined in css-overflow-3 - // ! padding is redefined in css-box-3 - // ! padding-bottom is redefined in css-box-3 - // ! padding-left is redefined in css-box-3 - // ! padding-right is redefined in css-box-3 - // ! padding-top is redefined in css-box-3 - // ! page-break-after is redefined in css-page-3 - // ! page-break-before is redefined in css-page-3 - // ! page-break-inside is redefined in css-page-3 - // ! position is redefined in css-position-3 - // ! quotes is redefined in css-content-3 - // ! right is redefined in css-position-3 - // ! table-layout is redefined in css-tables-3 - // ! text-align is redefined in css-text-3 - // ! text-decoration is redefined in css-text-decor-4 - // ! text-indent is redefined in css-text-3 - // ! text-transform is redefined in css-text-decor-4 - // ! top is redefined in css-position-3 - // ! unicode-bidi is redefined in css-writing-modes-4 - // ! vertical-align is redefined in css-inline-3 - // ! visibility is redefined in css-ui-4 - // ! white-space is redefined in css-text-3 - // ! widows is redefined in css-page-3 - // ! word-spacing is redefined in css-text-decor-4 - ZIndex, - - // https://drafts.csswg.org/cssom-1/#property-index - // - - // https://drafts.csswg.org/cssom-view-1/#property-index - // - - // https://drafts.csswg.org/mediaqueries-3/#property-index - // - - // https://drafts.csswg.org/mediaqueries-4/#property-index - // - - // https://drafts.csswg.org/mediaqueries-5/#property-index - // - - // https://drafts.csswg.org/resize-observer-1/#property-index - // - - // https://drafts.csswg.org/scroll-animations-1/#property-index - AnimationRange, - AnimationRangeEnd, - AnimationRangeStart, - ScrollTimeline, - ScrollTimelineAxis, - ScrollTimelineName, - TimelineScope, - ViewTimeline, - ViewTimelineAxis, - ViewTimelineInset, - ViewTimelineName, - - // https://drafts.csswg.org/selectors-3/#property-index - // - - // https://drafts.csswg.org/selectors-4/#property-index - // - - // https://drafts.csswg.org/selectors-nonelement-1/#property-index - // - - // https://drafts.csswg.org/web-animations-1/#property-index - // - - // https://drafts.csswg.org/web-animations-2/#property-index - - // Non Standard - NonStandardZoom, - NonStandardClip, - - // Webkit Non Standard - WebkitTextSizeAdjust, - WebkitTextDecoration, - WebkitTapHighlightColor, -} - -#[cfg(test)] -mod test { - - use hdx_ast::css::{ - component_values::ComponentValue, - values::{ColorValue, Expr, NamedColor}, - }; - use hdx_lexer::TokenValue; - - use super::*; - use crate::{Allocator, Atom, ParserOptions, Span, Spanned}; - - #[test] - fn parses_display_block() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "display:block", ParserOptions::default()); - let boxed_property = parser.boxup(Spanned { - span: Span::new(0, 13), - node: Display { - value: parser.boxup(Spanned { - span: Span::new(8, 13), - node: DisplayValue::Pair(DisplayOutside::Block, DisplayInside::Implicit), - }), - important: false, - }, - }); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - if !parser_return.warnings.is_empty() { - panic!("{:?}", parser_return.warnings[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { span: Span::new(0, 13), node: Property::Display(boxed_property) } - ); - } - - #[test] - fn parses_overflow_hidden() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "overflow :/**/ hidden;", ParserOptions::default()); - let boxed_property = parser.boxup(Spanned { - span: Span::new(0, 25), - node: Overflow { - value: parser.boxup(Spanned { - span: Span::new(18, 24), - node: XYShorthand { - x: Shorthand::Explicit(parser.boxup(Spanned { - span: Span::new(18, 24), - node: Expr::Literal(Spanned { - span: Span::new(18, 24), - node: OverflowKeyword::Hidden, - }), - })), - y: Shorthand::Implicit, - }, - }), - important: false, - }, - }); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - if !parser_return.warnings.is_empty() { - panic!("{:?}", parser_return.warnings[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { span: Span::new(0, 25), node: Property::Overflow(boxed_property) } - ); - } - - #[test] - fn parses_custom_property() { - let allocator = Allocator::default(); - let parser = - Parser::new(&allocator, "--some-thing :/**/ red;", ParserOptions::default()); - let mut component_values = parser.new_vec(); - component_values.push(Spanned { - span: Span::new(22, 25), - node: ComponentValue::Token(Token { - kind: Kind::Ident, - span: Span::new(22, 25), - escaped: false, - value: TokenValue::String(Atom::from("red")), - }), - }); - let boxed_property = parser.boxup(Spanned { - span: Span::new(0, 26), - node: Custom { - name: Atom::from("--some-thing"), - value: parser.boxup(component_values), - value_like: Spanned { - span: Span::new(22, 25), - node: ValueLike::Color(parser.boxup(Spanned { - span: Span::new(22, 25), - node: Expr::Literal(Spanned { - span: Span::new(22, 25), - node: ColorValue::Named(NamedColor::Red), - }), - })), - }, - important: false, - }, - }); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - if !parser_return.warnings.is_empty() { - panic!("{:?}", parser_return.warnings[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 26), node: Property::Custom(boxed_property) }); - } -} diff --git a/crates/hdx_parser/src/css/rules/charset.rs b/crates/hdx_parser/src/css/rules/charset.rs deleted file mode 100644 index f8faf404..00000000 --- a/crates/hdx_parser/src/css/rules/charset.rs +++ /dev/null @@ -1,13 +0,0 @@ -use hdx_ast::css::rules::charset::CSSCharsetRule; - -use crate::{atom, Kind, Parse, Parser, Result, Spanned}; - -impl<'a> Parse<'a> for CSSCharsetRule { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - parser.expect_at_keyword_of(atom!("charset"))?; - let encoding = parser.expect_string()?; - parser.expect(Kind::Semicolon)?; - Ok(Self { encoding }.spanned(span.end(parser.pos()))) - } -} diff --git a/crates/hdx_parser/src/css/rules/mod.rs b/crates/hdx_parser/src/css/rules/mod.rs deleted file mode 100644 index f959b1da..00000000 --- a/crates/hdx_parser/src/css/rules/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub mod charset; -pub mod page; - -use crate::{Kind, Parse, Parser, Result, Spanned}; - -pub struct NoPreludeAllowed; -impl<'a> Parse<'a> for NoPreludeAllowed { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - parser.expect_without_advance(Kind::LeftCurly)?; - Ok(Self {}.spanned(span.end(parser.pos()))) - } -} diff --git a/crates/hdx_parser/src/css/rules/page.rs b/crates/hdx_parser/src/css/rules/page.rs deleted file mode 100644 index 268b2825..00000000 --- a/crates/hdx_parser/src/css/rules/page.rs +++ /dev/null @@ -1,181 +0,0 @@ -use hdx_ast::css::{ - properties::Property, - rules::page::{ - CSSMarginRule, CSSPageRule, PageMarginBox, PagePseudoClass, PageSelector, PageSelectorList, - }, -}; -use oxc_allocator::Vec; - -use super::NoPreludeAllowed; -use crate::{atom, diagnostics, Atom, Atomizable, Kind, Parse, Parser, Result, Spanned}; - -impl<'a> Parse<'a> for CSSPageRule<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - parser.parse_at_rule( - Some(atom!("page")), - |parser: &mut Parser<'a>, - _name: Atom, - selectors: Option>>, - rules: Vec<'a, Spanned>>, - declarations: Vec<'a, Spanned>>| { - Ok(Self { - selectors: parser.boxup(selectors.unwrap_or_else(|| { - Spanned::dummy(PageSelectorList { children: parser.new_vec() }) - })), - declarations: parser.boxup(declarations), - rules: parser.boxup(rules), - } - .spanned(span.end(parser.pos()))) - }, - ) - } -} - -impl<'a> Parse<'a> for PageSelectorList<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let ok = Ok(Self { children: parser.parse_comma_list_of::()? } - .spanned(span.end(parser.pos()))); - ok - } -} - -impl<'a> Parse<'a> for PageSelector<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let mut page_type = None; - let mut pseudos = parser.new_vec(); - if parser.at(Kind::Ident) { - page_type = Some(parser.expect_ident()?); - } else { - parser.expect_without_advance(Kind::Colon)?; - } - if parser.at(Kind::Colon) { - loop { - pseudos.push(PagePseudoClass::parse(parser)?); - if !parser.at(Kind::Colon) { - break; - } - } - } - Ok(Self { page_type, pseudos }.spanned(span.end(parser.pos()))) - } -} - -impl<'a> Parse<'a> for PagePseudoClass { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - parser.expect(Kind::Colon)?; - let name = parser.expect_ident()?; - match Self::from_atom(name.clone()) { - Some(v) => Ok(v.spanned(span.end(parser.pos()))), - _ => Err(diagnostics::UnexpectedPseudo(name, span).into()), - } - } -} - -impl<'a> Parse<'a> for CSSMarginRule<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - parser.parse_at_rule( - None, - |parser: &mut Parser<'a>, - _name: Atom, - _prelude: Option>, - _rules: Vec<'a, Spanned>>, - declarations: Vec<'a, Spanned>>| { - Ok(Self { name: PageMarginBox::TopLeft, declarations } - .spanned(span.end(parser.pos()))) - }, - ) - } -} - -#[cfg(test)] -mod test { - use hdx_ast::{ - css::{ - properties::{Background, Property}, - rules::{CSSPageRule, PagePseudoClass, PageSelector, PageSelectorList}, - values::{ColorValue, NamedColor}, - }, - Spanned, - }; - use oxc_allocator::Allocator; - - use crate::{Atom, Parser, ParserOptions, Span, Vec}; - - #[test] - fn parses_toc_left_selector() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "toc:left", ParserOptions::default()); - let parser_return = parser.parse_with::(); - let ast = parser_return.output.unwrap(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - if !parser_return.warnings.is_empty() { - panic!("{:?}", parser_return.warnings[0]); - } - let mut children = Vec::new_in(&allocator); - let mut pseudos = Vec::new_in(&allocator); - pseudos.push(Spanned { span: Span::new(3, 8), node: PagePseudoClass::Left }); - children.push(Spanned { - span: Span::new(0, 8), - node: PageSelector { page_type: Some(Atom::from("toc")), pseudos }, - }); - assert_eq!(ast, Spanned { span: Span::new(0, 8), node: PageSelectorList { children } }); - } - - #[test] - fn parses_toc_left_page_rule_with_bakcground_black() { - let allocator = Allocator::default(); - let parser = Parser::new( - &allocator, - "@page toc:left { background: black; }", - ParserOptions::default(), - ); - let mut children = Vec::new_in(&allocator); - let mut pseudos = Vec::new_in(&allocator); - pseudos.push(Spanned { span: Span::new(9, 15), node: PagePseudoClass::Left }); - children.push(Spanned { - span: Span::new(6, 15), - node: PageSelector { page_type: Some(Atom::from("toc")), pseudos }, - }); - let mut declarations = Vec::new_in(&allocator); - declarations.push(Spanned { - span: Span::new(17, 36), - node: Property::Background({ - parser.boxup(Spanned { - span: Span::new(17, 36), - node: Background { - value: parser.boxup(Spanned { - span: Span::new(29, 34), - node: ColorValue::Named(NamedColor::Black), - }), - important: false, - }, - }) - }), - }); - let expected = Spanned { - span: Span::new(0, 37), - node: CSSPageRule { - selectors: parser - .boxup(Spanned { span: Span::new(6, 15), node: PageSelectorList { children } }), - declarations: parser.boxup(declarations), - rules: parser.boxup(Vec::new_in(&allocator)), - }, - }; - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - if !parser_return.warnings.is_empty() { - panic!("{:?}", parser_return.warnings[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, expected); - } -} diff --git a/crates/hdx_parser/src/css/selector/mod.rs b/crates/hdx_parser/src/css/selector/mod.rs deleted file mode 100644 index 9393d696..00000000 --- a/crates/hdx_parser/src/css/selector/mod.rs +++ /dev/null @@ -1,533 +0,0 @@ -use hdx_ast::css::selector::{ - Attribute, AttributeMatch, AttributeModifier, Combinator, Component, LegacyPseudoElement, - NSPrefix, PseudoClass, PseudoElement, Selector, -}; -use miette::Result; - -use crate::{atom, diagnostics, Atom, Atomizable, Kind, Parse, Parser, Span, Spanned, Vec}; - -fn parse_wq_name(parser: &mut Parser) -> Result<(NSPrefix, Atom)> { - let peeked = parser.peek(); - let mut nsprefix = NSPrefix::None; - if peeked.kind == Kind::Delim && peeked.value.as_char().unwrap() == '|' { - match parser.cur() { - Kind::Delim => { - let span = parser.span(); - let ch = parser.expect_delim()?; - if ch == '*' { - nsprefix = NSPrefix::Wildcard; - } else { - Err(diagnostics::UnexpectedDelim(ch, span))? - } - } - Kind::Ident => { - let ident = parser.expect_ident()?; - nsprefix = NSPrefix::Named(ident); - } - k => Err(diagnostics::Unexpected(k, parser.span()))?, - } - let span = parser.span(); - let ch = parser.expect_delim()?; - if ch != '|' { - Err(diagnostics::UnexpectedDelim(ch, span))? - } - Ok((nsprefix, parser.expect_ident()?)) - } else { - if parser.at(Kind::Delim) && parser.cur_char().unwrap() == '|' { - parser.advance(); - } - Ok((nsprefix, parser.expect_ident()?)) - } -} - -impl<'a> Parse<'a> for Selector<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let mut components: Vec<'a, Spanned> = parser.new_vec(); - loop { - match parser.cur() { - Kind::Eof | Kind::Semicolon | Kind::Comma | Kind::LeftCurly => { - break; - } - Kind::Whitespace => { - if matches!( - parser.peek().kind, - Kind::Eof | Kind::Semicolon | Kind::Comma | Kind::LeftCurly - ) { - break; - } - } - _ => {} - } - let component = Component::parse(parser)?; - if let Some(Spanned { node, span: component_span }) = components.last() { - match (node, &component.node) { - // A selector like `a /**/ b` would parse as // , , - // , . The CSS selector grammar implicitly swallows adjacent - // descendant combinators as whitespace, but due to simplifying AST nodes in our - // parser, it means we must explicitly check for, and elide adjacent descendant - // combinators. Adjacent Descendant Combinator Elision is the name of my metal - // band, btw. - (Component::Combinator(_), Component::Combinator(Combinator::Descendant)) - | (Component::Combinator(Combinator::Descendant), Component::Combinator(_)) => { - continue; - } - // Combinators cannot be next to eachother. - (Component::Combinator(_), Component::Combinator(_)) => { - Err(diagnostics::AdjacentSelectorCombinators( - *component_span, - Span::new(span.start, component_span.start), - ))? - } - // Types cannot be next to eachother. - (Component::Type(_), Component::Type(_)) => { - Err(diagnostics::AdjacentSelectorTypes( - *component_span, - Span::new(span.start, component_span.start), - ))? - } - _ => {} - } - } - components.push(component); - } - Ok(Self { components: parser.boxup(components) }.spanned(span.end(parser.pos()))) - } -} - -impl<'a> Parse<'a> for Component<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Kind::Whitespace => { - parser.advance(); - Ok(Self::Combinator(Combinator::Descendant).spanned(span.end(parser.pos()))) - } - Kind::Ident => { - let name = parser.cur().as_atom_lower().unwrap(); - parser.advance(); - Ok(Self::Type(name).spanned(span)) - } - Kind::Colon => { - parser.advance(); - match parser.cur() { - Kind::Colon => { - parser.advance(); - parser.expect_without_advance(Kind::Ident)?; - let ident = parser.cur().as_atom().unwrap(); - if let Some(selector) = PseudoElement::from_atom(ident) { - parser.advance(); - Ok(Self::PseudoElement(selector).spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::Unimplemented(parser.span()))? - } - } - Kind::Ident => { - parser.expect_without_advance(Kind::Ident)?; - let ident = parser.cur().as_atom().unwrap(); - if let Some(selector) = PseudoClass::from_atom(ident.clone()) { - parser.advance(); - Ok(Self::PseudoClass(selector).spanned(span.end(parser.pos()))) - } else if let Some(e) = LegacyPseudoElement::from_atom(ident.clone()) { - parser.advance(); - Ok(Self::LegacyPseudoElement(e).spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedIdent(ident, parser.span()))? - } - } - _ => Err(diagnostics::Unimplemented(parser.span()))?, - } - } - Kind::Hash => { - let name = parser.cur().as_atom().unwrap(); - parser.advance(); - Ok(Self::Id(name).spanned(span.end(parser.pos()))) - } - Kind::Delim => match parser.cur().value.as_char() { - Some('.') => { - let next_token = parser.peek_including_trivia(); - match next_token.kind { - Kind::Ident => { - parser.advance(); - let ident = parser.cur().as_atom().unwrap(); - parser.advance(); - Ok(Self::Class(ident).spanned(span.end(parser.pos()))) - } - _ => Err(diagnostics::Unimplemented(parser.span()))?, - } - } - Some('*') => { - let next_token = parser.peek_including_trivia(); - match next_token.kind { - Kind::Delim if next_token.value.as_char().unwrap() == '|' => { - let (prefix, atom) = parse_wq_name(parser)?; - Ok(Self::NSPrefixedType(parser.boxup((prefix, atom))) - .spanned(span.end(parser.pos()))) - } - _ => { - parser.advance(); - Ok(Self::Wildcard.spanned(span.end(parser.pos()))) - } - } - } - _ => Err(diagnostics::Unimplemented(parser.span()))?, - }, - Kind::LeftSquare => { - let attr = Attribute::parse(parser)?; - Ok(Component::Attribute(parser.boxup(attr)).spanned(span.end(parser.pos()))) - } - _ => Err(diagnostics::Unimplemented(parser.span()))?, - } - } -} - -impl<'a> Parse<'a> for Attribute { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - parser.expect(Kind::LeftSquare)?; - let (ns_prefix, name) = parse_wq_name(parser)?; - let mut matcher = AttributeMatch::Any; - let mut modifier = AttributeModifier::None; - let mut value = atom!(""); - match parser.cur() { - Kind::RightSquare => { - parser.advance(); - return Ok(Self { ns_prefix, name, value, modifier, matcher } - .spanned(span.end(parser.pos()))); - } - Kind::Delim => { - let delim_span = parser.span(); - let ch = parser.cur().value.as_char().unwrap(); - parser.advance(); - if matcher != AttributeMatch::Any { - Err(diagnostics::UnexpectedDelim(ch, delim_span))?; - } - matcher = match ch { - '=' => AttributeMatch::Exact, - '~' => AttributeMatch::SpaceList, - '|' => AttributeMatch::LangPrefix, - '^' => AttributeMatch::Prefix, - '$' => AttributeMatch::Suffix, - '*' => AttributeMatch::Contains, - _ => Err(diagnostics::UnexpectedDelim(ch, delim_span))?, - }; - if ch != '=' { - let ch = parser.expect_delim()?; - if ch != '=' { - Err(diagnostics::UnexpectedDelim(ch, delim_span))?; - } - } - } - k => Err(diagnostics::Unexpected(k, parser.span()))?, - } - match parser.cur() { - Kind::Ident | Kind::String => { - value = parser.cur().as_atom().unwrap(); - parser.advance(); - } - k => Err(diagnostics::Unexpected(k, parser.span()))?, - } - match parser.cur() { - Kind::RightSquare => { - parser.advance(); - Ok(Self { ns_prefix, name, value, modifier, matcher } - .spanned(span.end(parser.pos()))) - } - Kind::Ident => { - let ident_span = parser.span(); - modifier = match parser.expect_ident()? { - atom!("i") => AttributeModifier::Insensitive, - atom!("s") => AttributeModifier::Sensitive, - a => Err(diagnostics::UnexpectedIdent(a, ident_span))?, - }; - parser.expect(Kind::RightSquare)?; - Ok(Self { ns_prefix, name, value, modifier, matcher } - .spanned(span.end(parser.pos()))) - } - k => Err(diagnostics::Unexpected(k, parser.span()))?, - } - } -} - -#[cfg(test)] -mod test { - use hdx_ast::css::selector::{ - Attribute, AttributeMatch, AttributeModifier, Combinator, Component, NSPrefix, Selector, - }; - use oxc_allocator::{Box, Vec}; - - use crate::{atom, Allocator, Atom, Parser, ParserOptions, Span, Spanned}; - - #[test] - fn test_descendant_combinator() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "a b c .d\n#f", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - let mut components = Vec::new_in(&allocator); - components.push(Spanned { span: Span::new(0, 1), node: Component::Type(Atom::from("a")) }); - components.push(Spanned { - span: Span::new(1, 2), - node: Component::Combinator(Combinator::Descendant), - }); - components.push(Spanned { span: Span::new(2, 3), node: Component::Type(Atom::from("b")) }); - components.push(Spanned { - span: Span::new(3, 5), - node: Component::Combinator(Combinator::Descendant), - }); - components.push(Spanned { span: Span::new(5, 6), node: Component::Type(Atom::from("c")) }); - components.push(Spanned { - span: Span::new(6, 9), - node: Component::Combinator(Combinator::Descendant), - }); - components - .push(Spanned { span: Span::new(9, 11), node: Component::Class(Atom::from("d")) }); - components.push(Spanned { - span: Span::new(11, 12), - node: Component::Combinator(Combinator::Descendant), - }); - components.push(Spanned { span: Span::new(12, 14), node: Component::Id(Atom::from("f")) }); - assert_eq!( - ast, - Spanned { - span: Span::new(0, 14), - node: Selector { components: Box(allocator.alloc(components)) } - } - ); - } - - #[test] - fn test_class_auto() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, ".auto", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - let mut components = Vec::new_in(&allocator); - components.push(Spanned { span: Span::new(0, 5), node: Component::Class(atom!("auto")) }); - assert_eq!( - ast, - Spanned { - span: Span::new(0, 5), - node: Selector { components: Box(allocator.alloc(components)) } - } - ); - } - - #[test] - fn test_body_leading_trailing_space() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, " body ", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - let mut components = Vec::new_in(&allocator); - components.push(Spanned { span: Span::new(3, 7), node: Component::Type(atom!("body")) }); - assert_eq!( - ast, - Spanned { - span: Span::new(3, 7), - node: Selector { components: Box(allocator.alloc(components)) } - } - ); - } - - #[test] - fn test_attribute_selector() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "a[b='c']", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - let mut components = Vec::new_in(&allocator); - components.push(Spanned { span: Span::new(0, 1), node: Component::Type(atom!("a")) }); - components.push(Spanned { - span: Span::new(1, 8), - node: Component::Attribute(Box(allocator.alloc(Spanned { - span: Span::new(1, 8), - node: Attribute { - ns_prefix: NSPrefix::None, - name: atom!("b"), - matcher: AttributeMatch::Exact, - value: Atom::from("c"), - modifier: AttributeModifier::None, - }, - }))), - }); - assert_eq!( - ast, - Spanned { - span: Span::new(0, 8), - node: Selector { components: Box(allocator.alloc(components)) } - } - ); - } - - #[test] - fn test_attribute_with_ns_prefix() { - let allocator = Allocator::default(); - let parser = Parser::new( - &allocator, - "a/**/[ */**/|/**/b ~/*=*/= c/* */ /**/ s]", - ParserOptions::default(), - ); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - let mut components = Vec::new_in(&allocator); - components.push(Spanned { span: Span::new(0, 1), node: Component::Type(atom!("a")) }); - components.push(Spanned { - span: Span::new(5, 48), - node: Component::Attribute(Box(allocator.alloc(Spanned { - span: Span::new(5, 48), - node: Attribute { - ns_prefix: NSPrefix::Wildcard, - name: atom!("b"), - value: Atom::from("c"), - matcher: AttributeMatch::SpaceList, - modifier: AttributeModifier::Sensitive, - }, - }))), - }); - assert_eq!( - ast, - Spanned { - span: Span::new(0, 48), - node: Selector { components: Box(allocator.alloc(components)) } - } - ); - } - - #[test] - fn test_various_attribute_patterns() { - let allocator = Allocator::default(); - let parser = Parser::new( - &allocator, - "a[b|a][b][*|b~=i i][|i|=i i][s^=s s][i|i$=\"i\"][*|i*='foo' s]", - ParserOptions::default(), - ); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - let mut components = Vec::new_in(&allocator); - components.push(Spanned { span: Span::new(0, 1), node: Component::Type(atom!("a")) }); - // [b|a] - components.push(Spanned { - span: Span::new(1, 6), - node: Component::Attribute(Box(allocator.alloc(Spanned { - span: Span::new(1, 6), - node: Attribute { - ns_prefix: NSPrefix::Named(atom!("b")), - name: atom!("a"), - matcher: AttributeMatch::Any, - value: atom!(""), - modifier: AttributeModifier::None, - }, - }))), - }); - // [b] - components.push(Spanned { - span: Span::new(6, 9), - node: Component::Attribute(Box(allocator.alloc(Spanned { - span: Span::new(6, 9), - node: Attribute { - ns_prefix: NSPrefix::None, - name: atom!("b"), - matcher: AttributeMatch::Any, - value: atom!(""), - modifier: AttributeModifier::None, - }, - }))), - }); - // [*|b~=i i] - components.push(Spanned { - span: Span::new(9, 19), - node: Component::Attribute(Box(allocator.alloc(Spanned { - span: Span::new(9, 19), - node: Attribute { - ns_prefix: NSPrefix::Wildcard, - name: atom!("b"), - matcher: AttributeMatch::SpaceList, - value: atom!("i"), - modifier: AttributeModifier::Insensitive, - }, - }))), - }); - // [|i|=i i] - components.push(Spanned { - span: Span::new(19, 28), - node: Component::Attribute(Box(allocator.alloc(Spanned { - span: Span::new(19, 28), - node: Attribute { - ns_prefix: NSPrefix::None, - name: atom!("i"), - matcher: AttributeMatch::LangPrefix, - value: atom!("i"), - modifier: AttributeModifier::Insensitive, - }, - }))), - }); - // [s^=s s] - components.push(Spanned { - span: Span::new(28, 36), - node: Component::Attribute(Box(allocator.alloc(Spanned { - span: Span::new(28, 36), - node: Attribute { - ns_prefix: NSPrefix::None, - name: atom!("s"), - matcher: AttributeMatch::Prefix, - value: atom!("s"), - modifier: AttributeModifier::Sensitive, - }, - }))), - }); - // [i|i$="i"] - components.push(Spanned { - span: Span::new(36, 46), - node: Component::Attribute(Box(allocator.alloc(Spanned { - span: Span::new(36, 46), - node: Attribute { - ns_prefix: NSPrefix::Named(atom!("i")), - name: atom!("i"), - matcher: AttributeMatch::Suffix, - value: atom!("i"), - modifier: AttributeModifier::None, - }, - }))), - }); - // [*|i*='foo' s] - components.push(Spanned { - span: Span::new(46, 60), - node: Component::Attribute(Box(allocator.alloc(Spanned { - span: Span::new(46, 60), - node: Attribute { - ns_prefix: NSPrefix::Wildcard, - name: atom!("i"), - matcher: AttributeMatch::Contains, - value: Atom::from("foo"), - modifier: AttributeModifier::Sensitive, - }, - }))), - }); - assert_eq!( - ast, - Spanned { - span: Span::new(0, 60), - node: Selector { components: Box(allocator.alloc(components)) } - } - ); - } -} diff --git a/crates/hdx_parser/src/css/stylerule.rs b/crates/hdx_parser/src/css/stylerule.rs deleted file mode 100644 index 05c52374..00000000 --- a/crates/hdx_parser/src/css/stylerule.rs +++ /dev/null @@ -1,30 +0,0 @@ -use hdx_ast::css::{ - properties::Property, - stylesheet::{CSSStyleRule, SelectorSet}, -}; - -use crate::{diagnostics, Parse, Parser, Result, Spanned, Vec}; - -impl<'a> Parse<'a> for CSSStyleRule<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - parser.parse_qualified_rule( - None, - false, - |parser: &mut Parser<'a>, - selectors: Option>>, - rules: Vec<'a, Spanned>>, - declarations: Vec<'a, Spanned>>| { - if selectors.is_none() { - Err(diagnostics::NoSelector(span, span.end(parser.pos())))? - } - Ok(Self { - selectors: parser.boxup(selectors.unwrap()), - declarations: parser.boxup(declarations), - rules: parser.boxup(rules), - } - .spanned(span.end(parser.pos()))) - }, - ) - } -} diff --git a/crates/hdx_parser/src/css/unknown.rs b/crates/hdx_parser/src/css/unknown.rs deleted file mode 100644 index b6678ab1..00000000 --- a/crates/hdx_parser/src/css/unknown.rs +++ /dev/null @@ -1,143 +0,0 @@ -use hdx_ast::css::{ - unknown::{UnknownAtRule, UnknownDeclaration, UnknownPrelude, UnknownRule}, - values::ValueLike, -}; -use hdx_lexer::Kind; -use miette::Result; - -use crate::{atom, Atom, Parse, Parser, Spanned}; - -impl<'a> Parse<'a> for UnknownAtRule<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - parser.parse_at_rule( - None, - |parser: &mut Parser<'a>, name: Atom, prelude, rules, properties| { - Ok(Self { - name, - prelude: parser.boxup(prelude), - rules: parser.boxup(rules), - properties: parser.boxup(properties), - } - .spanned(span.end(parser.pos()))) - }, - ) - } -} - -impl<'a> Parse<'a> for UnknownRule<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - parser.parse_qualified_rule( - Some(Kind::Semicolon), - true, - |parser: &mut Parser<'a>, prelude, rules, properties| { - Ok(Self { - prelude: parser.boxup(prelude), - rules: parser.boxup(rules), - properties: parser.boxup(properties), - } - .spanned(span.end(parser.pos()))) - }, - ) - } -} - -impl<'a> Parse<'a> for UnknownPrelude<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let value = parser.parse_component_values(Kind::Semicolon, false)?; - Ok(Self { value: parser.boxup(value) }.spanned(span.end(parser.pos()))) - } -} - -// https://drafts.csswg.org/css-syntax-3/#consume-the-remnants-of-a-bad-declaration -impl<'a> Parse<'a> for UnknownDeclaration<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let mut name = atom!(""); - let mut value_like = Spanned::dummy(ValueLike::Unknown); - let value; - // While consume-the-remnants-of-a-bad-declaration just returns token soup, we can at least - // try to discover a useful property name, so try to do that first but if that fails then - // shove it all in component values - if parser.at(Kind::Ident) { - let ident = parser.cur().as_atom().unwrap(); - if parser.peek().kind == Kind::Colon { - parser.advance(); // ident - parser.advance(); // colon - name = ident; - let checkpoint = parser.checkpoint(); - value_like = ValueLike::parse(parser).unwrap_or(value_like); - parser.rewind(checkpoint); - value = parser.parse_component_values(Kind::Semicolon, true)?; - } else { - value = parser.parse_component_values(Kind::Semicolon, true)?; - } - } else { - value = parser.parse_component_values(Kind::Semicolon, true)?; - } - if parser.cur() == Kind::Semicolon { - parser.advance(); - } - Ok(Self { name, value_like, value: parser.boxup(value), important: false } - .spanned(span.end(parser.pos()))) - } -} - -#[cfg(test)] -mod test { - - use hdx_ast::css::{ - component_values::ComponentValue, - unknown::UnknownDeclaration, - values::{ColorValue, Expr, NamedColor}, - }; - use hdx_lexer::{Token, TokenValue}; - - use super::*; - use crate::{Allocator, Atom, ParserOptions, Span, Spanned}; - - #[test] - fn parses_unknown_property() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "colour :/**/ red;", ParserOptions::default()); - let mut component_values = parser.new_vec(); - component_values.push(Spanned { - span: Span::new(16, 19), - node: ComponentValue::Token(Token { - kind: Kind::Ident, - span: Span::new(16, 19), - escaped: false, - value: TokenValue::String(Atom::from("red")), - }), - }); - let expected = Spanned { - span: Span::new(0, 20), - node: UnknownDeclaration { - name: Atom::from("colour"), - value: parser.boxup(component_values), - value_like: Spanned { - span: Span::new(16, 19), - node: ValueLike::Color(parser.boxup(Spanned { - span: Span::new(16, 19), - node: Expr::Literal(Spanned { - span: Span::new(16, 19), - node: ColorValue::Named(NamedColor::Red), - }), - })), - }, - important: false, - }, - }; - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - if !parser_return.warnings.is_empty() { - panic!("{:?}", parser_return.warnings[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, expected); - } -} diff --git a/crates/hdx_parser/src/css/values/backgrounds.rs b/crates/hdx_parser/src/css/values/backgrounds.rs deleted file mode 100644 index 9d0c99ca..00000000 --- a/crates/hdx_parser/src/css/values/backgrounds.rs +++ /dev/null @@ -1,157 +0,0 @@ -use hdx_ast::css::values::{ - BorderShorthand, ColorValue, Expr, Length, LineStyle, LineWidth, MathExpr, Shorthand, -}; - -use crate::{atom, diagnostics, Kind, Parse, Parser, Result, Spanned}; - -impl<'a> Parse<'a> for BorderShorthand<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let mut line_width = Shorthand::Implicit; - let mut line_style = Shorthand::Implicit; - let mut color = Shorthand::Implicit; - loop { - match parser.cur() { - Kind::Ident => { - let ident = parser.cur_atom().unwrap(); - if line_style.is_implicit() - && matches!( - ident, - atom!("none") - | atom!("hidden") | atom!("dotted") - | atom!("dashed") | atom!("solid") - | atom!("double") | atom!("groove") - | atom!("ridge") | atom!("inset") - | atom!("outset") - ) { - let node = Expr::::parse(parser)?; - line_style = Shorthand::Explicit(parser.boxup(node)); - } else if line_width.is_implicit() - && matches!(ident, atom!("thin") | atom!("medium") | atom!("thick")) - { - let node = MathExpr::::parse(parser)?; - line_width = Shorthand::Explicit(parser.boxup(node)); - } else if color.is_implicit() { - let node = MathExpr::::parse(parser)?; - color = Shorthand::Explicit(parser.boxup(node)); - } else { - Err(diagnostics::UnexpectedIdent(ident.clone(), parser.span()))? - } - } - Kind::Semicolon | Kind::Comma | Kind::Eof => { - break; - } - Kind::Dimension => { - if line_width.is_implicit() { - let node = MathExpr::::parse(parser)?; - line_width = Shorthand::Explicit(parser.boxup(node)); - } else { - Err(diagnostics::Unexpected(Kind::Dimension, parser.span()))? - } - } - k => { - let checkpoint = parser.checkpoint(); - if line_width.is_implicit() { - let node = MathExpr::::parse(parser); - match node { - Ok(node) => { - line_width = Shorthand::Explicit(parser.boxup(node)); - continue; - } - Err(_) => parser.rewind(checkpoint), - } - } - let checkpoint = parser.checkpoint(); - if color.is_implicit() { - let node = MathExpr::::parse(parser); - match node { - Ok(node) => { - color = Shorthand::Explicit(parser.boxup(node)); - continue; - } - Err(_) => parser.rewind(checkpoint), - } - } - Err(diagnostics::Unexpected(k, parser.span()))? - } - } - if color.is_explicit() && line_style.is_explicit() && line_width.is_explicit() { - break; - } - } - Ok(Self { color, line_style, line_width }.spanned(span.end(parser.pos()))) - } -} - -impl<'a> Parse<'a> for LineWidth { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Kind::Number | Kind::Dimension => { - Ok(Self::Length(Length::parse(parser)?).spanned(span.end(parser.pos()))) - } - Kind::Ident => { - let ident = parser.cur_atom().unwrap(); - match ident { - atom!("thin") => Ok(Self::Thin.spanned(span)), - atom!("medium") => Ok(Self::Medium.spanned(span)), - atom!("thick") => Ok(Self::Thick.spanned(span)), - _ => Err(diagnostics::UnexpectedIdent(ident, span))?, - } - } - k => Err(diagnostics::Unexpected(k, span))?, - } - } -} - -#[cfg(test)] -mod test { - - use hdx_ast::css::values::{ - BorderShorthand, ColorValue, Expr, Length, LineStyle, LineWidth, MathExpr, NamedColor, Px, - Shorthand, - }; - - use crate::{Allocator, Parser, ParserOptions, Span, Spanned}; - - #[test] - fn parses_border_1px_solid_red() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "1px solid red", ParserOptions::default()); - let expected = Spanned { - span: Span::new(0, 13), - node: BorderShorthand { - line_width: Shorthand::Explicit(parser.boxup(Spanned { - span: Span::new(0, 4), - node: MathExpr::Literal(Spanned { - span: Span::new(0, 4), - node: LineWidth::Length(Spanned { - span: Span::new(0, 4), - node: Length::Px(Px(1.0)), - }), - }), - })), - line_style: Shorthand::Explicit(parser.boxup(Spanned { - span: Span::new(4, 10), - node: Expr::Literal(Spanned { span: Span::new(4, 10), node: LineStyle::Solid }), - })), - color: Shorthand::Explicit(parser.boxup(Spanned { - span: Span::new(10, 13), - node: MathExpr::Literal(Spanned { - span: Span::new(10, 13), - node: ColorValue::Named(NamedColor::Red), - }), - })), - }, - }; - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - if !parser_return.warnings.is_empty() { - panic!("{:?}", parser_return.warnings[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, expected); - } -} diff --git a/crates/hdx_parser/src/css/values/box.rs b/crates/hdx_parser/src/css/values/box.rs deleted file mode 100644 index 44c66da1..00000000 --- a/crates/hdx_parser/src/css/values/box.rs +++ /dev/null @@ -1,67 +0,0 @@ -use hdx_ast::css::values::MarginTrimValue; - -use crate::{atom, diagnostics, Kind, Parse, Parser, Result, Spanned}; - -impl<'a> Parse<'a> for MarginTrimValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let ident = parser.expect_ident()?; - if ident == atom!("none") { - Ok(Self { - block_start: false, - block_end: false, - inline_start: false, - inline_end: false, - } - .spanned(span.end(parser.pos()))) - } else if ident == atom!("block") { - Ok(Self { block_start: true, block_end: true, inline_start: false, inline_end: false } - .spanned(span.end(parser.pos()))) - } else if ident == atom!("inline") { - Ok(Self { block_start: false, block_end: false, inline_start: true, inline_end: true } - .spanned(span.end(parser.pos()))) - } else { - let mut value = Self { - block_start: ident == atom!("block-start"), - block_end: ident == atom!("block-end"), - inline_start: ident == atom!("inline-start"), - inline_end: ident == atom!("inline-end"), - }; - loop { - if !parser.at(Kind::Ident) { - break; - } - let span = parser.span(); - let ident = parser.expect_ident()?; - match ident { - atom!("block-start") => { - if value.block_start { - Err(diagnostics::UnexpectedDuplicateIdent(ident, span))?; - } - value.block_start = true - } - atom!("block-end") => { - if value.block_end { - Err(diagnostics::UnexpectedDuplicateIdent(ident, span))?; - } - value.block_end = true - } - atom!("inline-start") => { - if value.inline_start { - Err(diagnostics::UnexpectedDuplicateIdent(ident, span))?; - } - value.inline_start = true - } - atom!("inline-end") => { - if value.inline_end { - Err(diagnostics::UnexpectedDuplicateIdent(ident, span))?; - } - value.inline_end = true - } - _ => break, - } - } - Ok(value.spanned(span.end(parser.pos()))) - } - } -} diff --git a/crates/hdx_parser/src/css/values/color.rs b/crates/hdx_parser/src/css/values/color.rs deleted file mode 100644 index d074aa89..00000000 --- a/crates/hdx_parser/src/css/values/color.rs +++ /dev/null @@ -1,192 +0,0 @@ -use hdx_ast::css::values::{ - color::{ColorValue, NamedColor, NumberPercentageOrNone, RGB}, - MathExpr, -}; - -use crate::{atom, diagnostics, Atomizable, Kind, Parse, Parser, Result, Spanned}; - -impl<'a> Parse<'a> for ColorValue<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - // https://drafts.csswg.org/css-color/#hex-notation - Kind::Hash => { - let hash = parser.expect_hash()?; - if let Some(hex) = ColorValue::from_hex(hash.as_ref()) { - Ok(hex.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::BadHexColor(hash.clone(), span))? - } - } - Kind::Ident => { - let name = parser.expect_ident()?; - match name { - atom!("transparent") => { - Ok(ColorValue::Transparent.spanned(span.end(parser.pos()))) - } - _ => match NamedColor::from_atom(name.clone()) { - Some(n) => Ok(ColorValue::Named(n).spanned(span.end(parser.pos()))), - None => Err(diagnostics::UnknownColor(name, span))?, - }, - } - } - Kind::Function => { - let name = parser.cur().as_atom_lower().unwrap(); - match name { - atom!("rgb") | atom!("rgba") => { - let node = RGB::parse(parser)?; - Ok(ColorValue::RGB(parser.boxup(node)).spanned(span.end(parser.pos()))) - } - _ => Err(diagnostics::Unimplemented(span))?, - } - } - _ => Err(diagnostics::Unimplemented(span))?, - } - } -} - -impl<'a> Parse<'a> for RGB<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let ident = parser.expect_function()?; - let mut legacy = false; - let r = MathExpr::::parse(parser)?; - if parser.at(Kind::Comma) { - legacy = true; - parser.advance(); - } - let g = MathExpr::::parse(parser)?; - if legacy { - parser.expect(Kind::Comma)? - } - let b = MathExpr::::parse(parser)?; - let mut alpha = - Spanned::dummy(MathExpr::Literal(Spanned::dummy(NumberPercentageOrNone::Number(1.0)))); - if ident == atom!("rgba") { - if legacy { - parser.expect(Kind::Comma)? - } else { - parser.expect_delim_of('/')? - } - alpha = MathExpr::::parse(parser)?; - } - parser.expect(Kind::RightParen)?; - Ok(Self { r, g, b, alpha }.spanned(span.end(parser.pos()))) - } -} - -impl<'a> Parse<'a> for NumberPercentageOrNone { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Kind::Number => { - Ok(Self::Number(parser.expect_number()?).spanned(span.end(parser.pos()))) - } - Kind::Percentage => { - Ok(Self::Percentage(parser.expect_percentage()?).spanned(span.end(parser.pos()))) - } - Kind::Ident => match parser.expect_ident()? { - atom!("none") => { - parser.advance(); - Ok(Self::None.spanned(span.end(parser.pos()))) - } - _ => Err(diagnostics::Unimplemented(span))?, - }, - _ => Err(diagnostics::Unimplemented(span))?, - } - } -} - -#[cfg(test)] -mod test { - use hdx_ast::css::values::{ - color::{ColorValue, NamedColor, NumberPercentageOrNone, RGB}, - MathExpr, - }; - use oxc_allocator::Allocator; - - use crate::{Parser, ParserOptions, Span, Spanned}; - - #[test] - fn parses_named_black() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "black", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { span: Span::new(0, 5), node: ColorValue::Named(NamedColor::Black) } - ); - } - - #[test] - fn parses_named_rebeccapurple() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "rebeccapurple", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { span: Span::new(0, 13), node: ColorValue::Named(NamedColor::Rebeccapurple) } - ); - } - - #[test] - fn parses_hex() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "#abc", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 4), node: ColorValue::Hex(2864434431) }); - } - - #[test] - fn parses_rgb() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "rgb(0, 128, 255)", ParserOptions::default()); - let color = parser.boxup(Spanned { - span: Span::new(0, 16), - node: RGB { - r: Spanned { - span: Span::new(4, 5), - node: MathExpr::Literal(Spanned { - span: Span::new(4, 5), - node: NumberPercentageOrNone::Number(0.0), - }), - }, - g: Spanned { - span: Span::new(7, 10), - node: MathExpr::Literal(Spanned { - span: Span::new(7, 10), - node: NumberPercentageOrNone::Number(128.0), - }), - }, - b: Spanned { - span: Span::new(12, 15), - node: MathExpr::Literal(Spanned { - span: Span::new(12, 15), - node: NumberPercentageOrNone::Number(255.0), - }), - }, - alpha: Spanned::dummy(MathExpr::Literal(Spanned::dummy( - NumberPercentageOrNone::Number(1.0), - ))), - }, - }); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 16), node: ColorValue::RGB(color) }) - } -} diff --git a/crates/hdx_parser/src/css/values/content.rs b/crates/hdx_parser/src/css/values/content.rs deleted file mode 100644 index 48f687a9..00000000 --- a/crates/hdx_parser/src/css/values/content.rs +++ /dev/null @@ -1,87 +0,0 @@ -use hdx_ast::css::values::content::{ContentElement, ContentList, ContentsValue, QuotesValue}; - -use crate::{atom, diagnostics, Kind, Parse, Parser, Result, Spanned}; - -impl<'a> Parse<'a> for ContentsValue<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - if parser.at(Kind::Ident) { - match parser.cur_atom_lower().unwrap() { - atom!("normal") => { - parser.advance(); - return Ok(Self::Normal.spanned(span.end(parser.pos()))); - } - atom!("none") => { - parser.advance(); - return Ok(Self::None.spanned(span.end(parser.pos()))); - } - _ => {} - } - } - let list = ContentList::parse(parser)?; - // TODO: Replacement?? - // if list.values.len() == 1 { - // let element = list.values[0]; - // if let ContentElement::Image(image) = element { - // return Ok(Self::Replacement(ContentReplacement { image, alt: list.alt })); - // } - // } - Ok(Self::List(list).spanned(span.end(parser.pos()))) - } -} - -impl<'a> Parse<'a> for ContentList<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let mut values = parser.new_vec(); - let alt = parser.new_vec(); - loop { - match parser.cur() { - Kind::String => { - values.push(ContentElement::String(parser.cur_atom().unwrap())); - parser.advance(); - } - Kind::Semicolon | Kind::Eof | Kind::RightCurly => { - break; - } - _ => Err(diagnostics::Unimplemented(parser.span()))?, - } - } - Ok(Self { values, alt }.spanned(span.end(parser.pos()))) - } -} - -impl<'a> Parse<'a> for QuotesValue<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Kind::Ident => { - let ident = parser.expect_ident()?; - match ident { - atom!("none") => { - parser.advance(); - return Ok(Self::None.spanned(span.end(parser.pos()))); - } - atom!("auto") => { - parser.advance(); - return Ok(Self::Auto.spanned(span.end(parser.pos()))); - } - _ => Err(diagnostics::UnexpectedIdent(ident, parser.span()))?, - } - } - Kind::String => { - let mut custom = parser.new_vec(); - loop { - let open = parser.expect_string()?; - let close = parser.expect_string()?; - custom.push((open, close)); - if !parser.at(Kind::String) { - break; - } - } - Ok(Self::Custom(custom).spanned(span.end(parser.pos()))) - } - k => Err(diagnostics::Unexpected(k, parser.span()))?, - } - } -} diff --git a/crates/hdx_parser/src/css/values/counter_styles.rs b/crates/hdx_parser/src/css/values/counter_styles.rs deleted file mode 100644 index 3bb20042..00000000 --- a/crates/hdx_parser/src/css/values/counter_styles.rs +++ /dev/null @@ -1,35 +0,0 @@ -use hdx_ast::css::values::{CounterStyle, PredefinedCounterStyle, Symbols}; - -use crate::{atom, diagnostics, Atomizable, Kind, Parse, Parser, Result, Spanned}; - -impl<'a> Parse<'a> for CounterStyle<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Kind::Ident => { - let ident = parser.expect_ident()?; - if let Some(node) = PredefinedCounterStyle::from_atom(ident.clone()) { - Ok(Self::Predefined(node).spanned(span)) - } else { - Ok(Self::Named(ident).spanned(span)) - } - } - Kind::Function => { - let ident = parser.expect_ident()?; - if ident == atom!("symbols") { - let node = Symbols::parse(parser)?; - Ok(Self::Symbols(node).spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::ExpectedFunction(atom!("symbols"), ident, parser.span()))? - } - } - k => Err(diagnostics::Unexpected(k, parser.span()))?, - } - } -} - -impl<'a> Parse<'a> for Symbols<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - Err(diagnostics::Unimplemented(parser.span()))? - } -} diff --git a/crates/hdx_parser/src/css/values/expr.rs b/crates/hdx_parser/src/css/values/expr.rs deleted file mode 100644 index 0102c2ce..00000000 --- a/crates/hdx_parser/src/css/values/expr.rs +++ /dev/null @@ -1,312 +0,0 @@ -use hdx_ast::css::values::{ - Expr, ExprList, ExprListItem, GlobalValue, MathExpr, MathExprList, MathExprListItem, MathFunc, - Reference, -}; - -use crate::{atom, diagnostics, Atomizable, Kind, Parse, Parser, Result, Spanned}; - -impl<'a, T> Parse<'a> for Expr<'a, T> -where - T: Parse<'a>, -{ - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - Ok(match parser.cur() { - Kind::Ident => { - if let Some(val) = GlobalValue::from_atom(parser.cur().as_atom().unwrap()) { - parser.advance(); - Self::GlobalValue(val).spanned(span.end(parser.pos())) - } else { - Self::Literal(T::parse(parser)?).spanned(span.end(parser.pos())) - } - } - Kind::Function => match parser.cur().as_atom().unwrap() { - atom!("var") | atom!("env") => { - let node = Reference::parse(parser)?; - Self::Reference(node).spanned(span.end(parser.pos())) - } - atom!("calc") /*TODO! ...*/ => { - Err(diagnostics::DisallowedMathFunction(parser.cur().as_atom().unwrap(), parser.span()))? - }, - _ => { - let node = T::parse(parser)?; - Self::Literal(node).spanned(span.end(parser.pos())) - } - }, - _ => { - let node = T::parse(parser)?; - Self::Literal(node).spanned(span.end(parser.pos())) - } - }) - } -} - -impl<'a, T> Parse<'a> for MathExpr<'a, T> -where - T: Parse<'a>, -{ - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - Ok(match parser.cur() { - Kind::Ident => { - if let Some(val) = GlobalValue::from_atom(parser.cur().as_atom().unwrap()) { - parser.advance(); - Self::GlobalValue(val).spanned(span.end(parser.pos())) - } else { - let node = T::parse(parser)?; - Self::Literal(node).spanned(span.end(parser.pos())) - } - } - Kind::Function => { - match parser.cur().value.as_atom().unwrap() { - atom!("var") | atom!("env") => { - let node = Reference::parse(parser)?; - Self::Reference(node).spanned(span.end(parser.pos())) - }, - atom!("calc") /*TODO! ...*/ => { - let node = MathFunc::parse(parser)?; - Self::Math(node).spanned(span.end(parser.pos())) - }, - _ => Self::Literal(T::parse(parser)?).spanned(span.end(parser.pos())) - } - } - _ => Self::Literal(T::parse(parser)?).spanned(span.end(parser.pos())), - }) - } -} - -impl<'a, T> Parse<'a> for ExprList<'a, T> -where - T: Parse<'a>, -{ - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - Ok(match parser.cur() { - Kind::Ident => { - if let Some(val) = GlobalValue::from_atom(parser.cur().as_atom().unwrap()) { - parser.advance(); - Self::GlobalValue(val).spanned(span.end(parser.pos())) - } else { - Self::Values(parser.parse_comma_list_of::>()?) - .spanned(span.end(parser.pos())) - } - } - _ => Self::Values(parser.parse_comma_list_of::>()?) - .spanned(span.end(parser.pos())), - }) - } -} - -impl<'a, T> Parse<'a> for MathExprList<'a, T> -where - T: Parse<'a>, -{ - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - Ok(match parser.cur() { - Kind::Ident => { - if let Some(val) = GlobalValue::from_atom(parser.cur().as_atom().unwrap()) { - parser.advance(); - Self::GlobalValue(val).spanned(span.end(parser.pos())) - } else { - Self::Values(parser.parse_comma_list_of::>()?) - .spanned(span.end(parser.pos())) - } - } - _ => Self::Values(parser.parse_comma_list_of::>()?) - .spanned(span.end(parser.pos())), - }) - } -} - -impl<'a, T> Parse<'a> for ExprListItem<'a, T> -where - T: Parse<'a>, -{ - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - Ok(match parser.cur() { - Kind::Ident => Self::Literal(T::parse(parser)?).spanned(span.end(parser.pos())), - Kind::Function => match parser.cur().as_atom().unwrap() { - atom!("var") | atom!("env") => Self::Reference(Reference::parse(parser)?).spanned(span.end(parser.pos())), - atom!("calc") /*TODO! ...*/ => { - Err(diagnostics::DisallowedMathFunction(parser.cur().as_atom().unwrap(), parser.span()))? - }, - _ => Self::Literal(T::parse(parser)?).spanned(span.end(parser.pos())), - }, - _ => Self::Literal(T::parse(parser)?).spanned(span.end(parser.pos())), - }) - } -} - -impl<'a, T> Parse<'a> for MathExprListItem<'a, T> -where - T: Parse<'a>, -{ - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - Ok(match parser.cur() { - Kind::Ident => Self::Literal(T::parse(parser)?).spanned(span.end(parser.pos())), - Kind::Function => { - match parser.cur().as_atom().unwrap() { - atom!("var") | atom!("env") => { - Self::Reference(Reference::parse(parser)?).spanned(span.end(parser.pos())) - }, - atom!("calc") /*TODO! ...*/ => { - Self::Math(MathFunc::parse(parser)?).spanned(span.end(parser.pos())) - }, - _ => Self::Literal(T::parse(parser)?).spanned(span.end(parser.pos())) - } - } - _ => Self::Literal(T::parse(parser)?).spanned(span.end(parser.pos())), - }) - } -} - -impl<'a> Parse<'a> for MathFunc<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - parser.expect(Kind::Function)?; - todo!() - } -} - -impl<'a, T> Parse<'a> for Reference<'a, T> -where - T: Parse<'a>, -{ - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let ident = parser.expect_function()?; - Ok(match ident { - atom!("var") => { - let name = parser.expect_ident()?; - let mut inner = None; - if parser.at(Kind::Comma) { - parser.advance(); - inner = Some(T::parse(parser)?) - } - parser.expect(Kind::RightParen)?; - Self::Var(name, parser.boxup(inner)).spanned(span.end(parser.pos())) - } - atom!("env") => { - let name = parser.expect_ident()?; - let mut inner = None; - if parser.at(Kind::Comma) { - parser.advance(); - inner = Some(T::parse(parser)?) - } - parser.expect(Kind::RightParen)?; - Self::Env(name, parser.boxup(inner)).spanned(span.end(parser.pos())) - } - _ => Err(diagnostics::UnexpectedFunction(ident, parser.span()))?, - }) - } -} - -#[cfg(test)] -mod test { - use hdx_ast::css::values::{ColorValue, Expr, GlobalValue, Length, NamedColor, Px, Reference}; - - use crate::{Allocator, Atom, Parser, ParserOptions, Span, Spanned}; - - #[test] - fn test_expr_basic_inherit() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "inherit", ParserOptions::default()); - let node = Expr::::GlobalValue(GlobalValue::Inherit); - let parser_return = parser.parse_entirely_with::>(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 7), node }); - } - - #[test] - fn test_expr_basic_var() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "var(--foo)", ParserOptions::default()); - let fallback = None; - let node = Expr::::Reference(Spanned { - span: Span::new(0, 10), - node: Reference::Var(Atom::from("--foo"), parser.boxup(fallback)), - }); - let parser_return = parser.parse_entirely_with::>(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 10), node }); - } - - #[test] - fn test_expr_var_colorvalue_with_fallback() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "var(--foo, blue)", ParserOptions::default()); - let fallback = Some(Spanned { - span: Span::new(11, 15), - node: Expr::Literal(Spanned { - span: Span::new(11, 15), - node: ColorValue::Named(NamedColor::Blue), - }), - }); - let node = Expr::::Reference(Spanned { - span: Span::new(0, 16), - node: Reference::Var(Atom::from("--foo"), parser.boxup(fallback)), - }); - let parser_return = parser.parse_entirely_with::>(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 16), node }); - } - - #[test] - fn test_expr_var_with_fallback() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "var(--foo, 8px)", ParserOptions::default()); - let fallback = Some(Spanned { - span: Span::new(11, 14), - node: Expr::Literal(Spanned { span: Span::new(11, 14), node: Length::Px(Px(8.0)) }), - }); - let node = Expr::::Reference(Spanned { - span: Span::new(0, 15), - node: Reference::Var(Atom::from("--foo"), parser.boxup(fallback)), - }); - let parser_return = parser.parse_entirely_with::>(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 15), node }); - } - - #[test] - fn test_expr_env_with_var_with_fallback() { - let allocator = Allocator::default(); - let parser = - Parser::new(&allocator, "env(--bar, var(--foo, 8px))", ParserOptions::default()); - let var_fallback = Some(Spanned { - span: Span::new(22, 25), - node: Expr::Literal(Spanned { span: Span::new(22, 25), node: Length::Px(Px(8.0)) }), - }); - let env_fallback = Some(Spanned { - span: Span::new(11, 26), - node: Expr::Reference(Spanned { - span: Span::new(11, 26), - node: Reference::Var(Atom::from("--foo"), parser.boxup(var_fallback)), - }), - }); - let node = Expr::::Reference(Spanned { - span: Span::new(0, 27), - node: Reference::Env(Atom::from("--bar"), parser.boxup(env_fallback)), - }); - let parser_return = parser.parse_entirely_with::>(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 27), node }); - } -} diff --git a/crates/hdx_parser/src/css/values/fonts.rs b/crates/hdx_parser/src/css/values/fonts.rs deleted file mode 100644 index fa88efe9..00000000 --- a/crates/hdx_parser/src/css/values/fonts.rs +++ /dev/null @@ -1,230 +0,0 @@ -use hdx_ast::css::values::{ - AbsoluteSize, Angle, FontFamilyValue, FontSizeValue, FontStyleValue, FontWeightValue, MathExpr, - PositiveLengthPercentage, RelativeSize, -}; - -use crate::{atom, diagnostics, Atom, Atomizable, Kind, Parse, Parser, Result, Spanned}; - -impl<'a> Parse<'a> for FontWeightValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Kind::Ident => { - let ident = parser.expect_ident()?; - if ident == atom!("normal") { - Ok(Self::Normal.spanned(span.end(parser.pos()))) - } else if ident == atom!("bold") { - Ok(Self::Bold.spanned(span.end(parser.pos()))) - } else if ident == atom!("bolder") { - Ok(Self::Bolder.spanned(span.end(parser.pos()))) - } else if ident == atom!("lighter") { - Ok(Self::Lighter.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedIdent(ident, parser.span()))? - } - } - Kind::Number => { - let num = parser.cur().value.as_f32().unwrap(); - parser.advance(); - if (1.0..=1000.0).contains(&num) { - Ok(Self::Number(num as u16).spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::NumberOutOfBounds(1.0, 1000.0, parser.span()))? - } - } - k => Err(diagnostics::Unexpected(k, parser.span()))?, - } - } -} - -impl<'a> Parse<'a> for FontSizeValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Kind::Ident => { - let ident = parser.expect_ident()?; - if ident == atom!("math") { - Ok(Self::Math.spanned(span.end(parser.pos()))) - } else if let Some(val) = AbsoluteSize::from_atom(ident.clone()) { - parser.advance(); - Ok(Self::Absolute(val).spanned(span.end(parser.pos()))) - } else if let Some(val) = RelativeSize::from_atom(ident.clone()) { - parser.advance(); - Ok(Self::Relative(val).spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedIdent(ident, parser.span()))? - } - } - _ => { - let node = PositiveLengthPercentage::parse(parser)?; - Ok(Self::LengthPercentage(node).spanned(span.end(parser.pos()))) - } - } - } -} - -impl<'a> Parse<'a> for FontFamilyValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Kind::Ident => { - let mut ident = parser.expect_ident_cased()?; - match ident.to_ascii_lowercase() { - atom!("serif") => Ok(Self::Serif.spanned(span.end(parser.pos()))), - atom!("sans-serif") => Ok(Self::SansSerif.spanned(span.end(parser.pos()))), - atom!("cursive") => Ok(Self::Cursive.spanned(span.end(parser.pos()))), - atom!("fantasy") => Ok(Self::Fantasy.spanned(span.end(parser.pos()))), - atom!("monospace") => Ok(Self::Monospace.spanned(span.end(parser.pos()))), - atom!("system-ui") => Ok(Self::SystemUi.spanned(span.end(parser.pos()))), - atom!("emoji") => Ok(Self::Emoji.spanned(span.end(parser.pos()))), - atom!("math") => Ok(Self::Math.spanned(span.end(parser.pos()))), - atom!("fangsong") => Ok(Self::Fangsong.spanned(span.end(parser.pos()))), - atom!("ui-serif") => Ok(Self::UiSerif.spanned(span.end(parser.pos()))), - atom!("ui-sans-serif") => Ok(Self::UiSansSerif.spanned(span.end(parser.pos()))), - atom!("ui-monospace") => Ok(Self::UiMonospace.spanned(span.end(parser.pos()))), - atom!("ui-rounded") => Ok(Self::UiRounded.spanned(span.end(parser.pos()))), - _ => { - let mut name = String::new(); - loop { - name.push_str(ident.as_ref()); - if !parser.at(Kind::Ident) { - break; - } - name.push(' '); - ident = parser.expect_ident_cased()?; - } - Ok(Self::Named(Atom::from(name)).spanned(span.end(parser.pos()))) - } - } - } - Kind::String => { - let string = parser.cur_atom().unwrap(); - parser.advance(); - Ok(Self::Named(string).spanned(span.end(parser.pos()))) - } - _ => Err(diagnostics::Unexpected(parser.cur(), parser.span()))?, - } - } -} - -impl<'a> Parse<'a> for FontStyleValue<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Kind::Ident => { - let ident = parser.expect_ident()?; - match ident { - atom!("normal") => Ok(Self::Normal.spanned(span.end(parser.pos()))), - atom!("italic") => Ok(Self::Italic.spanned(span.end(parser.pos()))), - atom!("oblique") => { - if matches!(parser.cur(), Kind::Dimension | Kind::Number) { - let degrees = MathExpr::::parse(parser)?; - Ok(Self::Oblique(degrees).spanned(span.end(parser.pos()))) - } else { - Ok(Self::Oblique(Spanned::dummy(MathExpr::Literal(Spanned::dummy( - Angle::Deg(14.0), - )))) - .spanned(span.end(parser.pos()))) - } - } - _ => Err(diagnostics::UnexpectedIdent(ident, parser.span()))?, - } - } - k => Err(diagnostics::Unexpected(k, parser.span()))?, - } - } -} - -#[cfg(test)] -mod test { - use hdx_ast::css::values::{Angle, FontFamilyValue, FontStyleValue, FontWeightValue, MathExpr}; - - use crate::{Allocator, Atom, Parser, ParserOptions, Span, Spanned}; - - #[test] - fn test_font_weight_numeric() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "326", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 3), node: FontWeightValue::Number(326) }); - } - - #[test] - fn test_basic_named() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "Roboto", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { span: Span::new(0, 6), node: FontFamilyValue::Named(Atom::from("Roboto")) } - ); - } - - #[test] - fn test_multi_ident_named() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "Gill Sans Semibold", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { - span: Span::new(0, 18), - node: FontFamilyValue::Named(Atom::from("Gill Sans Semibold")) - } - ); - } - - #[test] - fn test_multi_string_named() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "'Gill Sans Semibold'", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { - span: Span::new(0, 20), - node: FontFamilyValue::Named(Atom::from("Gill Sans Semibold")) - } - ); - } - - #[test] - fn test_font_style_oblique_deg() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "oblique 30deg", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { - span: Span::new(0, 13), - node: FontStyleValue::Oblique(Spanned { - span: Span::new(8, 13), - node: (MathExpr::Literal(Spanned { - span: Span::new(8, 13), - node: Angle::Deg(30.0) - })) - }) - } - ); - } -} diff --git a/crates/hdx_parser/src/css/values/inline.rs b/crates/hdx_parser/src/css/values/inline.rs deleted file mode 100644 index 8612f353..00000000 --- a/crates/hdx_parser/src/css/values/inline.rs +++ /dev/null @@ -1,112 +0,0 @@ -use hdx_ast::css::values::{ - AlignmentBaselineValue, BaselineShiftValue, BaselineSourceValue, Expr, LengthPercentage, - LineHeightValue, MathExpr, Shorthand, VerticalAlignShorthand, -}; - -use crate::{atom, diagnostics, Parse, Parser, Result, Spanned, Token}; - -impl<'a> Parse<'a> for LineHeightValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - match parser.cur() { - Token::Ident(ident) => { - if ident.eq_ignore_ascii_case(&atom!("normal")) { - Ok(Self::Normal.spanned(parser.advance())) - } else { - Err(diagnostics::UnexpectedIdentSuggest( - *ident, - atom!("normal"), - parser.span(), - ))? - } - } - Token::Number(_, value) => Ok(Self::Number(*value).spanned(parser.advance())), - _ => { - let span = parser.span(); - let node = LengthPercentage::parse(parser)?; - Ok(Self::LengthPercentage(node).spanned(span.end(parser.pos()))) - } - } - } -} - -impl<'a> Parse<'a> for BaselineShiftValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - match parser.cur() { - Token::Ident(ident) => match ident.as_ascii_lower() { - atom!("sub") => Ok(Self::Sub.spanned(parser.advance())), - atom!("super") => Ok(Self::Super.spanned(parser.advance())), - atom!("top") => Ok(Self::Top.spanned(parser.advance())), - atom!("center") => Ok(Self::Center.spanned(parser.advance())), - atom!("bottom") => Ok(Self::Bottom.spanned(parser.advance())), - _ => Err(diagnostics::UnexpectedIdent(*ident, parser.span()))?, - }, - _ => { - let span = parser.span(); - let node = LengthPercentage::parse(parser)?; - Ok(Self::LengthPercentage(node).spanned(span.end(parser.pos()))) - } - } - } -} - -impl<'a> Parse<'a> for VerticalAlignShorthand<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let mut alignment_baseline = Shorthand::Implicit; - let mut baseline_shift = Shorthand::Implicit; - let mut baseline_source = match parser.cur() { - Token::Ident(ident) => match ident.to_ascii_lower() { - atom!("first") => Shorthand::Explicit( - parser.boxup( - Expr::Literal(BaselineSourceValue::First.spanned(parser.span())) - .spanned(parser.advance()), - ), - ), - atom!("last") => Shorthand::Explicit( - parser.boxup( - Expr::Literal(BaselineSourceValue::Last.spanned(parser.span())) - .spanned(parser.advance()), - ), - ), - }, - _ => Shorthand::Implicit, - }; - loop { - if !matches!( - parser.cur(), - Token::Ident(_) | Token::Number(_, _) | Token::Dimension(_, _, _) - ) { - break; - } - if alignment_baseline.is_explicit() && baseline_shift.is_explicit() { - break; - } - if alignment_baseline.is_implicit() { - let checkpoint = parser.checkpoint(); - if let Ok(expr) = Expr::::parse(parser) { - alignment_baseline = Shorthand::Explicit(parser.boxup(expr)); - } else { - parser.rewind(checkpoint); - } - } - if baseline_shift.is_implicit() { - let checkpoint = parser.checkpoint(); - if let Ok(expr) = MathExpr::::parse(parser) { - baseline_shift = Shorthand::Explicit(parser.boxup(expr)); - } else { - parser.rewind(checkpoint); - } - } - if baseline_source.is_implicit() { - let checkpoint = parser.checkpoint(); - if let Ok(expr) = Expr::::parse(parser) { - baseline_source = Shorthand::Explicit(parser.boxup(expr)); - } else { - parser.rewind(checkpoint); - } - } - } - Ok(Self { baseline_source, alignment_baseline, baseline_shift } - .spanned(span.end(parser.pos()))) - } -} diff --git a/crates/hdx_parser/src/css/values/length.rs b/crates/hdx_parser/src/css/values/length.rs deleted file mode 100644 index 5cea5007..00000000 --- a/crates/hdx_parser/src/css/values/length.rs +++ /dev/null @@ -1,280 +0,0 @@ -use hdx_ast::css::values::{lengths::*, Percentage}; - -use crate::{atom, diagnostics, Parse, Parser, Result, Spanned, Token}; - -// https://drafts.csswg.org/css-values-4/#lengths -impl<'a> Parse<'a> for Length { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Token::Dimension(_, value, atom) => { - if let Some(unit) = Self::from_f32_and_atom(value, *atom) { - Ok(unit.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedDimension(atom, span))? - } - } - Token::Number(_, value) => { - if *value != 0.0 { - Err(diagnostics::DisallowedValueWithoutDimension(atom!("px"), parser.span()))? - } - Ok(Self::Zero.spanned(span.end(parser.pos()))) - } - k => Err(diagnostics::Unexpected(k, span))?, - } - } -} - -// https://drafts.csswg.org/css-values-4/#lengths -impl<'a> Parse<'a> for PositiveLength { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Token::Dimension(_, value, atom) => { - let (value, atom) = parser.expect_dimension_gte(0.0)?; - if let Some(unit) = Self::from_f32_and_atom(value, atom.clone()) { - Ok(unit.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedDimension(atom, span))? - } - } - Token::Number(_, value) => { - if value != 0.0 { - Err(diagnostics::DisallowedValueWithoutDimension(atom!("px"), span))? - } - Ok(Self::Zero.spanned(span.end(parser.pos()))) - } - k => Err(diagnostics::Unexpected(k, span))?, - } - } -} - -// https://drafts.csswg.org/css-values-4/#lengths -impl<'a> Parse<'a> for PositiveLengthPercentageOrNormal { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Token::Ident => { - parser.expect_ident_of(atom!("normal"))?; - Ok(Self::Normal.spanned(span.end(parser.pos()))) - } - Token::Dimension => { - let (value, atom) = parser.expect_dimension_gte(0.0)?; - if let Some(unit) = Self::from_f32_and_atom(value, atom.clone()) { - Ok(unit.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedDimension(atom, span))? - } - } - Token::Percentage => { - let value = parser.expect_percentage_gte(0.0)?; - Ok(Self::Percentage(Percentage(value)).spanned(span.end(parser.pos()))) - } - Token::Number => { - let value = parser.expect_number()?; - if value != 0.0 { - Err(diagnostics::DisallowedValueWithoutDimension(atom!("px"), span))? - } - Ok(Self::Zero.spanned(span.end(parser.pos()))) - } - k => Err(diagnostics::Unexpected(k, span))?, - } - } -} - -// https://drafts.csswg.org/css-values-4/#typedef-length-percentage -impl<'a> Parse<'a> for LengthPercentage { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Token::Dimension => { - let value = parser.cur().value.as_f32().unwrap(); - let atom = parser.cur().value.as_atom().unwrap(); - if let Some(unit) = Self::from_f32_and_atom(value, atom.clone()) { - parser.advance(); - Ok(unit.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedDimension(atom, parser.span()))? - } - } - Token::Number => { - let value = parser.cur().value.as_f32().unwrap(); - if value != 0.0 { - Err(diagnostics::DisallowedValueWithoutDimension(atom!("px"), parser.span()))? - } - parser.advance(); - Ok(Self::Zero.spanned(span.end(parser.pos()))) - } - Token::Percentage => { - let value = parser.cur().value.as_f32().unwrap(); - parser.advance(); - Ok(Self::Percentage(Percentage(value)).spanned(span.end(parser.pos()))) - } - _ => Err(diagnostics::Unexpected(parser.cur(), parser.span()))?, - } - } -} - -// https://drafts.csswg.org/css-values-4/#typedef-length-percentage -impl<'a> Parse<'a> for LengthPercentageOrNormal { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Token::Ident => { - if parser.cur_atom_lower().unwrap() == atom!("normal") { - parser.advance(); - Ok(Self::Normal.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedIdent( - parser.cur_atom_lower().unwrap(), - parser.span(), - ))? - } - } - Token::Dimension => { - let value = parser.cur().value.as_f32().unwrap(); - let atom = parser.cur().value.as_atom().unwrap(); - if let Some(unit) = Self::from_f32_and_atom(value, atom.clone()) { - parser.advance(); - Ok(unit.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedDimension(atom, parser.span()))? - } - } - Token::Number => { - let value = parser.cur().value.as_f32().unwrap(); - if value != 0.0 { - Err(diagnostics::DisallowedValueWithoutDimension(atom!("px"), parser.span()))? - } - parser.advance(); - Ok(Self::Zero.spanned(span.end(parser.pos()))) - } - Token::Percentage => { - let value = parser.cur().value.as_f32().unwrap(); - parser.advance(); - Ok(Self::Percentage(Percentage(value)).spanned(span.end(parser.pos()))) - } - _ => Err(diagnostics::Unexpected(parser.cur(), parser.span()))?, - } - } -} - -// https://drafts.csswg.org/css-values-4/#typedef-length-percentage -impl<'a> Parse<'a> for PositiveLengthPercentage { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Token::Dimension => { - let value = parser.cur().value.as_f32().unwrap(); - if value < 0.0 { - Err(diagnostics::NumberOutOfBounds(value, 0.0, parser.span()))?; - } - let atom = parser.cur().value.as_atom().unwrap(); - if let Some(unit) = Self::from_f32_and_atom(value, atom.clone()) { - parser.advance(); - Ok(unit.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedDimension(atom, parser.span()))? - } - } - Token::Number => { - let value = parser.cur().value.as_f32().unwrap(); - if value != 0.0 { - Err(diagnostics::DisallowedValueWithoutDimension(atom!("px"), parser.span()))? - } - parser.advance(); - Ok(Self::Zero.spanned(span.end(parser.pos()))) - } - Token::Percentage => { - let value = parser.cur().value.as_f32().unwrap(); - if value < 0.0 { - Err(diagnostics::NumberOutOfBounds(value, 0.0, parser.span()))?; - } - parser.advance(); - Ok(Self::Percentage(Percentage(value)).spanned(span.end(parser.pos()))) - } - _ => Err(diagnostics::Unexpected(parser.cur(), parser.span()))?, - } - } -} - -impl<'a> Parse<'a> for LengthPercentageOrAuto { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Token::Ident => { - if parser.cur_atom_lower().unwrap() == atom!("auto") { - parser.advance(); - Ok(Self::Auto.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedIdent( - parser.cur_atom_lower().unwrap(), - parser.span(), - ))? - } - } - Token::Dimension => { - let value = parser.cur().value.as_f32().unwrap(); - let atom = parser.cur().value.as_atom().unwrap(); - if let Some(unit) = Self::from_f32_and_atom(value, atom.clone()) { - parser.advance(); - Ok(unit.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedDimension(atom, parser.span()))? - } - } - Token::Number => { - let value = parser.cur().value.as_f32().unwrap(); - if value != 0.0 { - Err(diagnostics::DisallowedValueWithoutDimension(atom!("px"), parser.span()))? - } - parser.advance(); - Ok(Self::Zero.spanned(span.end(parser.pos()))) - } - Token::Percentage => { - let value = parser.cur().value.as_f32().unwrap(); - parser.advance(); - Ok(Self::Percentage(Percentage(value)).spanned(span.end(parser.pos()))) - } - _ => Err(diagnostics::Unexpected(parser.cur(), parser.span()))?, - } - } -} - -#[cfg(test)] -mod test { - use hdx_ast::css::values::{LengthPercentage, Percentage, Px}; - use oxc_allocator::Allocator; - - use crate::{Parser, ParserOptions, Span, Spanned}; - - #[test] - fn parses_0() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "0", ParserOptions::default()); - let parser_return = parser.parse_with::(); - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 1), node: LengthPercentage::Zero }); - } - - #[test] - fn parses_3pc() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "3%", ParserOptions::default()); - let parser_return = parser.parse_with::(); - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { span: Span::new(0, 2), node: LengthPercentage::Percentage(Percentage(3.0)) } - ); - } - - #[test] - fn parses_10dot4px() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "10.4px", ParserOptions::default()); - let parser_return = parser.parse_with::(); - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 6), node: LengthPercentage::Px(Px(10.4)) }); - } -} diff --git a/crates/hdx_parser/src/css/values/lists.rs b/crates/hdx_parser/src/css/values/lists.rs deleted file mode 100644 index cfeee4f0..00000000 --- a/crates/hdx_parser/src/css/values/lists.rs +++ /dev/null @@ -1,112 +0,0 @@ -use hdx_ast::css::values::{ - CounterStyle, Expr, Image, ListStyleImageValue, ListStylePositionValue, ListStyleShorthand, - ListStyleTypeValue, Shorthand, -}; - -use crate::{atom, diagnostics, Parse, Parser, Result, Spanned, Token}; - -impl<'a> Parse<'a> for ListStyleShorthand<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let mut position = Shorthand::Implicit; - let mut image = Shorthand::Implicit; - let mut marker = Shorthand::Implicit; - loop { - match parser.cur() { - Token::Semicolon | Token::Comma | Token::Eof => { - break; - } - Token::Ident(ident) => { - if position.is_implicit() - && matches!(ident.to_ascii_lowercase(), atom!("inside") | atom!("outside")) - { - let node = Expr::::parse(parser)?; - position = Shorthand::Explicit(parser.boxup(node)); - } else if image.is_implicit() - && matches!(ident.to_ascii_lowercase(), atom!("none")) - { - let node = Expr::::parse(parser)?; - image = Shorthand::Explicit(parser.boxup(node)); - } else if marker.is_implicit() { - let node = Expr::::parse(parser)?; - marker = Shorthand::Explicit(parser.boxup(node)); - } else { - Err(diagnostics::UnexpectedIdent(*ident, parser.span()))? - } - } - k => { - let checkpoint = parser.checkpoint(); - if image.is_implicit() { - let node = Expr::::parse(parser); - match node { - Ok(node) => { - image = Shorthand::Explicit(parser.boxup(node)); - continue; - } - Err(_) => parser.rewind(checkpoint), - } - } - let checkpoint = parser.checkpoint(); - if marker.is_implicit() { - let node = Expr::::parse(parser); - match node { - Ok(node) => { - marker = Shorthand::Explicit(parser.boxup(node)); - continue; - } - Err(_) => parser.rewind(checkpoint), - } - } - Err(diagnostics::Unexpected(*k, parser.span()))? - } - } - if position.is_explicit() && image.is_explicit() && marker.is_explicit() { - break; - } - } - Ok(Self { position, image, marker }.spanned(span.end(parser.pos()))) - } -} - -impl<'a> Parse<'a> for ListStyleTypeValue<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - match parser.cur() { - Token::Ident(ident) => { - if ident.to_ascii_lowercase() == atom!("none") { - Ok(Self::None.spanned(parser.advance())) - } else { - let span = parser.span(); - let node = CounterStyle::parse(parser)?; - Ok(Self::CounterStyle(node).spanned(span.end(parser.pos()))) - } - } - Token::String(value) => Ok(Self::String(*value).spanned(parser.advance())), - _ => { - let span = parser.span(); - let node = CounterStyle::parse(parser)?; - Ok(Self::CounterStyle(node).spanned(span.end(parser.pos()))) - } - } - } -} - -impl<'a> Parse<'a> for ListStyleImageValue<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - match parser.cur() { - Token::Ident(ident) => { - if ident.to_ascii_lowercase() == atom!("none") { - Ok(Self::None.spanned(parser.advance())) - } else { - let span = parser.span(); - let node = Image::parse(parser)?; - Ok(Self::Image(node).spanned(span.end(parser.pos()))) - } - } - _ => { - let span = parser.span(); - let node = Image::parse(parser)?; - Ok(Self::Image(node).spanned(span.end(parser.pos()))) - } - } - } -} diff --git a/crates/hdx_parser/src/css/values/mod.rs b/crates/hdx_parser/src/css/values/mod.rs deleted file mode 100644 index b1e5f783..00000000 --- a/crates/hdx_parser/src/css/values/mod.rs +++ /dev/null @@ -1,112 +0,0 @@ -pub mod angle; -pub mod backgrounds; -pub mod r#box; -pub mod color; -pub mod content; -pub mod counter_styles; -pub mod display; -pub mod expr; -pub mod fonts; -pub mod inline; -pub mod length; -pub mod lists; -pub mod non_standard; -pub mod page_floats; -pub mod shorthand; -pub mod size_adjust; -pub mod sizing; -pub mod text; -pub mod text_decor; -pub mod ui; - -use hdx_ast::css::{properties::Todo, values::*}; - -use crate::{diagnostics, Atomizable, Parse, Parser, Result, Spanned, Token}; - -macro_rules! parse_for_enums { - {$( $prop: ident, )+} => { - $( - impl<'a> Parse<'a> for $prop { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Token::Ident(ident) => { - if let Some(val) = $prop::from_atom(*ident) { - Ok(val.spanned(span)) - } else { - Err(diagnostics::UnexpectedIdent(*ident, span))? - } - } - token => Err(diagnostics::ExpectedIdent(*token, span))?, - } - } - } - )+ - } -} - -parse_for_enums! { - AlignmentBaselineValue, - AutoOrNone, - BaselineSourceValue, - BorderCollapseValue, - BoxDecorationBreakValue, - BoxSizingValue, - BreakValue, - BreakInsideValue, - CaptionSideValue, - ClearValue, - DominantBaselineValue, - EmptyCellsValue, - FloatReferenceValue, - InlineSizingValue, - LineStyle, - ListStylePositionValue, - MarginBreakValue, - MinIntrinsicSizingValue, - OverflowKeyword, - PositionValue, - TableLayoutValue, - TextAlignAllValue, - TextAlignLastValue, - TextAlignValue, - TextDecorationSkipInkValue, - TextDecorationStyleValue, - TextWrapValue, - VisibilityValue, - WhiteSpaceCollapseValue, -} - -// TODO: -impl<'a> Parse<'a> for Image<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - Err(diagnostics::Unimplemented(parser.span()))? - } -} - -// TODO: -impl<'a> Parse<'a> for RatioOrAuto { - fn parse(parser: &mut Parser<'a>) -> Result> { - Err(diagnostics::Unimplemented(parser.span()))? - } -} - -// TODO: -impl<'a> Parse<'a> for TimeOrAuto { - fn parse(parser: &mut Parser<'a>) -> Result> { - Err(diagnostics::Unimplemented(parser.span()))? - } -} - -impl<'a> Parse<'a> for NoNonGlobalValuesAllowed { - fn parse(parser: &mut Parser<'a>) -> Result> { - unexpected!(parser); - } -} - -// TODO: -impl<'a> Parse<'a> for Todo { - fn parse(parser: &mut Parser<'a>) -> Result> { - Err(diagnostics::Unimplemented(parser.span()))? - } -} diff --git a/crates/hdx_parser/src/css/values/non_standard.rs b/crates/hdx_parser/src/css/values/non_standard.rs deleted file mode 100644 index cfdb3ddd..00000000 --- a/crates/hdx_parser/src/css/values/non_standard.rs +++ /dev/null @@ -1,20 +0,0 @@ -use hdx_ast::css::values::non_standard::ZoomValue; - -use crate::{atom, diagnostics, Parse, Parser, Result, Spanned, Token}; - -impl<'a> Parse<'a> for ZoomValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - match parser.cur() { - Token::Ident(ident) => match ident.to_ascii_lowercase() { - atom!("normal") => Ok(Self::Normal.spanned(parser.advance())), - atom!("reset") => Ok(Self::Reset.spanned(parser.advance())), - _ => Err(diagnostics::UnexpectedIdent(*ident, parser.span()))?, - }, - Token::Dimension(_, value, atom!("%")) => { - Ok(Self::Percentage(*value).spanned(parser.advance())) - } - Token::Number(_, value) => Ok(Self::Number(*value).spanned(parser.advance())), - token => Err(diagnostics::Unexpected(*token, parser.span()))?, - } - } -} diff --git a/crates/hdx_parser/src/css/values/page_floats.rs b/crates/hdx_parser/src/css/values/page_floats.rs deleted file mode 100644 index 8fbd128c..00000000 --- a/crates/hdx_parser/src/css/values/page_floats.rs +++ /dev/null @@ -1,78 +0,0 @@ -use hdx_ast::css::values::{ - page_floats::{FloatDeferValue, FloatValue, SnapBlockFloat, SnapInlineFloat}, - Length, -}; - -use crate::{atom, diagnostics, Atomizable, Kind, Parse, Parser, Result, Spanned}; - -impl<'a> Parse<'a> for FloatDeferValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Kind::Ident => { - if let Some(val) = Self::from_atom(parser.expect_ident()?) { - Ok(val.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedIdent(parser.cur_atom().unwrap(), parser.span()))? - } - } - Kind::Number => { - let node = parser.expect_int()?; - Ok(Self::Integer(node).spanned(span.end(parser.pos()))) - } - _ => Err(diagnostics::Unexpected(parser.cur(), parser.span()))?, - } - } -} - -impl<'a> Parse<'a> for FloatValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Kind::Ident => { - if let Some(val) = Self::from_atom(parser.expect_ident()?) { - Ok(val.spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedIdent(parser.cur_atom().unwrap(), parser.span()))? - } - } - Kind::Function => { - let name = parser.expect_function()?; - let length = Length::parse(parser)?; - parser.expect(Kind::Comma)?; - let floated_atom = parser.expect_ident()?; - match name { - atom!("snap-block") => { - if let Some(floated) = SnapBlockFloat::from_atom(floated_atom) { - Ok(Self::SnapBlockFunction(length, floated) - .spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedIdent( - parser.cur_atom().unwrap(), - parser.span(), - ) - .into()) - } - } - atom!("snap-inline") => { - if let Some(floated) = SnapInlineFloat::from_atom(floated_atom) { - Ok(Self::SnapInlineFunction(length, floated) - .spanned(span.end(parser.pos()))) - } else { - Err(diagnostics::UnexpectedIdent( - parser.cur_atom().unwrap(), - parser.span(), - ) - .into()) - } - } - _ => { - Err(diagnostics::UnexpectedIdent(parser.cur_atom().unwrap(), parser.span()) - .into()) - } - } - } - _ => Err(diagnostics::Unexpected(parser.cur(), parser.span()))?, - } - } -} diff --git a/crates/hdx_parser/src/css/values/shorthand.rs b/crates/hdx_parser/src/css/values/shorthand.rs deleted file mode 100644 index 84cb71f6..00000000 --- a/crates/hdx_parser/src/css/values/shorthand.rs +++ /dev/null @@ -1,62 +0,0 @@ -use hdx_ast::css::values::{shorthand::*, Shorthand}; - -use crate::{Parse, Parser, Result, Spanned, Token}; - -impl<'a, T: Parse<'a>> Parse<'a> for BoxShorthand<'a, T> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let mut top = Shorthand::Implicit; - let mut right = Shorthand::Implicit; - let mut bottom = Shorthand::Implicit; - let mut left = Shorthand::Implicit; - while matches!( - parser.cur(), - Token::Dimension(_, _, _) | Token::Number(_, _) | Token::Ident(_) | Token::Function(_) - ) { - let parsed = T::parse(parser)?; - if top.is_implicit() { - top = Shorthand::Explicit(parser.boxup(parsed)); - } else if right.is_implicit() { - right = Shorthand::Explicit(parser.boxup(parsed)); - } else if bottom.is_implicit() { - bottom = Shorthand::Explicit(parser.boxup(parsed)); - } else if left.is_implicit() { - left = Shorthand::Explicit(parser.boxup(parsed)); - break; - } - } - Ok(Self { top, right, bottom, left }.spanned(span.end(parser.pos()))) - } -} - -impl<'a, T: Parse<'a>> Parse<'a> for XYShorthand<'a, T> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let node = T::parse(parser)?; - let x = Shorthand::Explicit(parser.boxup(node)); - match parser.cur() { - Token::Ident(_) | Token::Function(_) => { - let node = T::parse(parser)?; - Ok(Self { x, y: Shorthand::Explicit(parser.boxup(node)) } - .spanned(span.end(parser.pos()))) - } - _ => Ok(Self { x, y: Shorthand::Implicit }.spanned(span.end(parser.pos()))), - } - } -} - -impl<'a, T: Parse<'a>> Parse<'a> for DoubleShorthand<'a, T> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let node = T::parse(parser)?; - let first = Shorthand::Explicit(parser.boxup(node)); - match parser.cur() { - Token::Ident(_) | Token::Function(_) => { - let node = T::parse(parser)?; - Ok(Self(first, Shorthand::Explicit(parser.boxup(node))) - .spanned(span.end(parser.pos()))) - } - _ => Ok(Self(first, Shorthand::Implicit).spanned(span.end(parser.pos()))), - } - } -} diff --git a/crates/hdx_parser/src/css/values/size_adjust.rs b/crates/hdx_parser/src/css/values/size_adjust.rs deleted file mode 100644 index 68c33103..00000000 --- a/crates/hdx_parser/src/css/values/size_adjust.rs +++ /dev/null @@ -1,19 +0,0 @@ -use hdx_ast::css::values::TextSizeAdjustValue; - -use crate::{atom, diagnostics, Parse, Parser, Result, Spanned, Token}; - -impl<'a> Parse<'a> for TextSizeAdjustValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - match parser.cur() { - Token::Ident(ident) => match ident.to_ascii_lowercase() { - atom!("none") => Ok(TextSizeAdjustValue::None.spanned(parser.advance())), - atom!("auto") => Ok(TextSizeAdjustValue::Auto.spanned(parser.advance())), - _ => Err(diagnostics::UnexpectedIdent(*ident, parser.span()))?, - }, - Token::Dimension(_, value, atom!("%")) => { - Ok(TextSizeAdjustValue::Percentage(*value).spanned(parser.advance())) - } - token => Err(diagnostics::Unexpected(*token, parser.span()))?, - } - } -} diff --git a/crates/hdx_parser/src/css/values/sizing.rs b/crates/hdx_parser/src/css/values/sizing.rs deleted file mode 100644 index 77eb6131..00000000 --- a/crates/hdx_parser/src/css/values/sizing.rs +++ /dev/null @@ -1,111 +0,0 @@ -use hdx_ast::css::values::{LengthPercentage, MaxSizing, Sizing}; - -use crate::{atom, diagnostics, expect, Parse, Parser, Result, Spanned, Token}; - -impl<'a> Parse<'a> for Sizing { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let sizing = match parser.cur() { - Token::Ident(name) => match name.to_ascii_lowercase() { - atom!("auto") => Sizing::Auto, - atom!("max-content") => Sizing::MaxContent, - atom!("min-content") => Sizing::MinContent, - atom!("stretch") => Sizing::Stretch, - atom!("fit-content") => Sizing::FitContent, - _ => Err(diagnostics::UnexpectedIdent(*name, parser.span()))?, - }, - Token::Dimension(_, _, _) | Token::Number(_, _) => { - Sizing::LengthPercentage(LengthPercentage::parse(parser)?) - } - Token::Function(_) => { - parser.expect_function_of(&atom!("fit-content"))?; - let result = LengthPercentage::parse(parser)?; - expect!(Token::RightParen); - Sizing::FitContentFunction(result) - } - _ => Err(diagnostics::Unimplemented(parser.span()))?, - }; - Ok(sizing.spanned(span.end(parser.pos()))) - } -} - -impl<'a> Parse<'a> for MaxSizing { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let sizing = match parser.cur() { - Token::Ident(name) => match name.to_ascii_lowercase() { - atom!("none") => MaxSizing::None, - atom!("max-content") => MaxSizing::MaxContent, - atom!("min-content") => MaxSizing::MinContent, - atom!("stretch") => MaxSizing::Stretch, - atom!("fit-content") => MaxSizing::FitContent, - _ => Err(diagnostics::UnexpectedIdent(*name, parser.span()))?, - }, - Token::Dimension(_, _, _) | Token::Number(_, _) => { - MaxSizing::LengthPercentage(LengthPercentage::parse(parser)?) - } - Token::Function(_) => { - let name = parser.expect_function_of(&atom!("fit-content"))?; - let result = LengthPercentage::parse(parser)?; - expect!(Token::RightParen); - MaxSizing::FitContentFunction(result) - } - _ => Err(diagnostics::Unimplemented(parser.span()))?, - }; - Ok(sizing.spanned(span.end(parser.pos()))) - } -} - -#[cfg(test)] -mod test { - - use hdx_ast::css::values::{LengthPercentage, Px}; - - use super::*; - use crate::{Allocator, Parser, ParserOptions, Span, Spanned}; - - #[test] - fn parse_10px() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "10px", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { - span: Span::new(0, 4), - node: Sizing::LengthPercentage(Spanned { - span: Span::new(0, 4), - node: LengthPercentage::Px(Px(10.0)) - }) - } - ); - } - - #[test] - fn parse_0() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "0", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { - span: Span::new(0, 1), - node: Sizing::LengthPercentage(Spanned { - span: Span::new(0, 1), - node: LengthPercentage::Zero - }) - } - ); - } - - #[test] - fn parse_auto() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "auto", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 4), node: Sizing::Auto }); - } -} diff --git a/crates/hdx_parser/src/css/values/text.rs b/crates/hdx_parser/src/css/values/text.rs deleted file mode 100644 index a048673d..00000000 --- a/crates/hdx_parser/src/css/values/text.rs +++ /dev/null @@ -1,144 +0,0 @@ -use hdx_ast::css::values::{ - Expr, Shorthand, TextWrapValue, WhiteSpaceCollapseValue, WhiteSpaceShorthand, - WhiteSpaceTrimValue, -}; - -use crate::{atom, diagnostics, Atomizable, Parse, Parser, Result, Spanned, Token}; - -impl<'a> Parse<'a> for WhiteSpaceTrimValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let mut inner = false; - let mut after = false; - let mut before = false; - loop { - match parser.cur() { - Token::Ident(ident) => match ident.to_ascii_lowercase() { - atom!("none") => { - return Ok(Self::None.spanned(parser.advance())); - } - atom!("discard-inner") => { - parser.advance(); - inner = true; - } - atom!("discard-after") => { - parser.advance(); - after = true; - } - atom!("discard-before") => { - parser.advance(); - before = true; - } - _ => break, - }, - _ => break, - } - if inner && after && before { - break; - } - } - Ok(Self::Discard { inner, after, before }.spanned(span.end(parser.pos()))) - } -} - -impl<'a> Parse<'a> for WhiteSpaceShorthand<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Token::Ident(ident) => match ident.to_ascii_lowercase() { - //normal | pre | nowrap | pre-wrap | pre-line - atom!("normal") => { - return Ok(Self::Normal.spanned(parser.advance())); - } - atom!("pre") => { - return Ok(Self::Pre.spanned(parser.advance())); - } - atom!("nowrap") => { - return Ok(Self::Nowrap.spanned(parser.advance())); - } - atom!("pre-wrap") => { - return Ok(Self::PreWrap.spanned(parser.advance())); - } - atom!("pre-line") => { - return Ok(Self::PreLine.spanned(parser.advance())); - } - _ => {} - }, - _ => {} - } - let mut collapse = Shorthand::Implicit; - let mut wrap = Shorthand::Implicit; - let mut trim = Shorthand::Implicit; - loop { - match parser.cur() { - Token::Semicolon | Token::Comma | Token::Eof => { - break; - } - Token::Ident(ident) => { - if collapse.is_implicit() - && WhiteSpaceCollapseValue::from_atom(ident.to_ascii_lowercase()).is_some() - { - let node = Expr::::parse(parser)?; - collapse = Shorthand::Explicit(parser.boxup(node)); - } else if wrap.is_implicit() - && TextWrapValue::from_atom(ident.clone()).is_some() - { - let node = Expr::::parse(parser)?; - wrap = Shorthand::Explicit(parser.boxup(node)); - } else if trim.is_implicit() - && matches!( - ident.to_ascii_lowercase(), - atom!("none") - | atom!("discard-inner") | atom!("discard-after") - | atom!("discard-before") - ) { - let node = Expr::::parse(parser)?; - trim = Shorthand::Explicit(parser.boxup(node)); - } else { - Err(diagnostics::UnexpectedIdent(ident.clone(), parser.span()))? - } - } - k => { - let checkpoint = parser.checkpoint(); - if collapse.is_implicit() { - let node = Expr::::parse(parser); - match node { - Ok(node) => { - collapse = Shorthand::Explicit(parser.boxup(node)); - continue; - } - Err(_) => parser.rewind(checkpoint), - } - } - let checkpoint = parser.checkpoint(); - if wrap.is_implicit() { - let node = Expr::::parse(parser); - match node { - Ok(node) => { - wrap = Shorthand::Explicit(parser.boxup(node)); - continue; - } - Err(_) => parser.rewind(checkpoint), - } - } - let checkpoint = parser.checkpoint(); - if trim.is_implicit() { - let node = Expr::::parse(parser); - match node { - Ok(node) => { - trim = Shorthand::Explicit(parser.boxup(node)); - continue; - } - Err(_) => parser.rewind(checkpoint), - } - } - Err(diagnostics::Unexpected(*k, parser.span()))? - } - } - if collapse.is_explicit() && wrap.is_explicit() && trim.is_explicit() { - break; - } - } - Ok(Self::Expanded { collapse, wrap, trim }.spanned(span.end(parser.pos()))) - } -} diff --git a/crates/hdx_parser/src/css/values/text_decor.rs b/crates/hdx_parser/src/css/values/text_decor.rs deleted file mode 100644 index dcd513a8..00000000 --- a/crates/hdx_parser/src/css/values/text_decor.rs +++ /dev/null @@ -1,181 +0,0 @@ -use hdx_ast::css::values::{ - ColorValue, Expr, MathExpr, Shorthand, TextDecorationLineValue, TextDecorationShorthand, - TextDecorationStyleValue, -}; - -use crate::{atom, diagnostics, Parse, Parser, Result, Spanned, Token}; - -impl<'a> Parse<'a> for TextDecorationShorthand<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - let mut color = Shorthand::Implicit; - let mut style = Shorthand::Implicit; - let mut line = Shorthand::Implicit; - loop { - match parser.cur() { - Token::Ident(ident) => { - if style.is_implicit() - && matches!( - ident.to_ascii_lowercase(), - atom!("solid") - | atom!("double") | atom!("dotted") - | atom!("dashed") | atom!("wavy") - ) { - let node = Expr::::parse(parser)?; - style = Shorthand::Explicit(parser.boxup(node)); - } else if line.is_implicit() - && matches!( - *ident, - atom!("none") - | atom!("underline") | atom!("overline") - | atom!("line-through") | atom!("blink") - ) { - let node = Expr::::parse(parser)?; - line = Shorthand::Explicit(parser.boxup(node)); - } else if color.is_implicit() { - let node = MathExpr::::parse(parser)?; - color = Shorthand::Explicit(parser.boxup(node)); - } else { - Err(diagnostics::UnexpectedIdent(ident.clone(), parser.span()))? - } - } - Token::Semicolon | Token::Comma | Token::Eof => { - break; - } - token => { - if color.is_implicit() { - let node = MathExpr::::parse(parser)?; - color = Shorthand::Explicit(parser.boxup(node)); - } else { - Err(diagnostics::Unexpected(*token, parser.span()))? - } - } - } - if color.is_explicit() && style.is_explicit() && line.is_explicit() { - break; - } - } - Ok(Self { color, style, line }.spanned(span.end(parser.pos()))) - } -} - -impl<'a> Parse<'a> for TextDecorationLineValue { - fn parse(parser: &mut Parser<'a>) -> Result> { - let span = parser.span(); - match parser.cur() { - Token::Ident(ident) => match ident.to_ascii_lowercase() { - atom!("none") => { - return Ok(Self::None.spanned(parser.advance())); - } - _ => {} - }, - _ => {} - } - let mut underline = false; - let mut overline = false; - let mut line_through = false; - let mut blink = false; - loop { - match parser.cur() { - Token::Ident(ident) => { - match ident.to_ascii_lowercase() { - atom!("underline") => { - if underline { - break; - } - underline = true - } - atom!("overline") => { - if overline { - break; - } - overline = true - } - atom!("line-through") => { - if overline { - break; - } - line_through = true - } - atom!("blink") => { - if overline { - break; - } - blink = true - } - _ => break, - }; - parser.advance(); - } - _ => break, - } - } - Ok(Self::Style { underline, overline, line_through, blink }.spanned(span.end(parser.pos()))) - } -} - -#[cfg(test)] -mod test { - use hdx_ast::css::values::{ - Expr, Shorthand, TextDecorationLineValue, TextDecorationShorthand, TextDecorationStyleValue, - }; - - use crate::{Allocator, Parser, ParserOptions, Span, Spanned}; - - #[test] - fn test_line_parses_underline() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "underline", ParserOptions::default()); - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!( - ast, - Spanned { - span: Span::new(0, 9), - node: TextDecorationLineValue::Style { - underline: true, - overline: false, - line_through: false, - blink: false - } - } - ); - } - - #[test] - fn test_shorthand_parses_underline_dotted() { - let allocator = Allocator::default(); - let parser = Parser::new(&allocator, "underline dotted", ParserOptions::default()); - let node = TextDecorationShorthand { - color: Shorthand::Implicit, - line: Shorthand::Explicit(parser.boxup(Spanned { - span: Span::new(0, 10), - node: Expr::Literal(Spanned { - span: Span::new(0, 10), - node: TextDecorationLineValue::Style { - underline: true, - overline: false, - line_through: false, - blink: false, - }, - }), - })), - style: Shorthand::Explicit(parser.boxup(Spanned { - span: Span::new(10, 16), - node: Expr::Literal(Spanned { - span: Span::new(10, 16), - node: TextDecorationStyleValue::Dotted, - }), - })), - }; - let parser_return = parser.parse_entirely_with::(); - if !parser_return.errors.is_empty() { - panic!("{:?}", parser_return.errors[0]); - } - let ast = parser_return.output.unwrap(); - assert_eq!(ast, Spanned { span: Span::new(0, 16), node }); - } -} diff --git a/crates/hdx_parser/src/css/values/ui.rs b/crates/hdx_parser/src/css/values/ui.rs deleted file mode 100644 index de7faa8f..00000000 --- a/crates/hdx_parser/src/css/values/ui.rs +++ /dev/null @@ -1,18 +0,0 @@ -use hdx_ast::css::values::CursorValue; - -use crate::{diagnostics, Atomizable, Parse, Parser, Result, Spanned, Token}; - -impl<'a> Parse<'a> for CursorValue<'a> { - fn parse(parser: &mut Parser<'a>) -> Result> { - match parser.cur() { - Token::Ident(ident) => { - if let Some(val) = CursorValue::from_atom(*ident) { - Ok(val.spanned(parser.advance())) - } else { - Err(diagnostics::UnexpectedIdent(*ident, parser.span()))? - } - } - token => Err(diagnostics::Unexpected(*token, parser.span()))?, - } - } -}