public MediaCondition(EMediaCombinator op, IEnumerable <IMediaCondition> conditions) { Conditions = new LinkedList <IMediaCondition>(conditions); Op = op; }
/// <summary> /// Consumes a new <see cref="MediaCondition"/> or <see cref="MediaFeature"/> /// </summary> /// <param name="Stream"></param> /// <returns></returns> static IMediaCondition Consume_Media_Condition(DataConsumer <CssToken> Stream) {/* Docs: https://www.w3.org/TR/mediaqueries-4/#media-condition */ if (Stream is null) { throw new CssParserException(CssErrors.STREAM_IS_NULL); } Consume_All_Whitespace(Stream); if (ParserCommon.Starts_Media_Feature(Stream.AsSpan())) { /* Consume opening parentheses */ Stream.Consume(); var feature = Consume_Media_Feature(Stream); /* Consume closing parentheses */ if (Stream.Next.Type == ECssTokenType.Parenth_Close) { Stream.Consume(); } return(feature); } else if (ParserCommon.Starts_Media_Condition(Stream.AsSpan())) { EMediaCombinator Combinator = EMediaCombinator.None; var conditionList = new LinkedList <IMediaCondition>(); if (Stream.Next.Type == ECssTokenType.Parenth_Close) { /* Empty media condition block */ Stream.Consume(); return(new MediaCondition(EMediaCombinator.None, Array.Empty <MediaFeature>())); } else if (Stream.Next.Type == ECssTokenType.Parenth_Open) { Stream.Consume(); } Consume_All_Whitespace(Stream); /* Repeatedly consume sub-media-conditions until we hit a closing parentheses */ do { Consume_All_Whitespace(Stream); if (Stream.Next.Type == ECssTokenType.Parenth_Close) { /* End of this media condition block */ break; } /* Anything other than the first condition *MUST* specify a combinator */ if (conditionList.Count > 0) { if (!ParserCommon.Is_Combinator(Stream.Next)) { throw new CssSyntaxErrorException(CssErrors.EXPECTING_COMBINATOR, Stream); } } /* Otherwise we just COULD have a combinator */ if (ParserCommon.Is_Combinator(Stream.Next)) { /* Consume combinator */ IdentToken combinatorToken = Stream.Consume() as IdentToken; if (!Lookup.TryEnum(combinatorToken.Value, out EMediaCombinator combLookup)) { throw new CssSyntaxErrorException(String.Format(CultureInfo.InvariantCulture, CssErrors.INVALID_COMBINATOR, combinatorToken.Value), Stream); } else if (Combinator == EMediaCombinator.None) {/* This is the first combinator specified */ Combinator = combLookup; } else if (Combinator != EMediaCombinator.None && combLookup != Combinator) {/* Ensure this new combinator matches the combinator for this method group */ throw new CssSyntaxErrorException(CssErrors.INVALID_MULTIPLE_COMBINATORS_ON_MEDIARULE, Stream); } } Consume_All_Whitespace(Stream); if (Stream.Next.Type != ECssTokenType.Parenth_Open) { throw new CssSyntaxErrorException(CssErrors.EXPECTING_OPENING_PARENTHESES, Stream); } /* Oh look a yummy little sub-condition for us to gobble up! */ var feature = Consume_Media_Condition(Stream); conditionList.AddLast(feature); }while (Stream.Next.Type != ECssTokenType.EOF); /* Consume closing parentheses */ if (Stream.Next.Type == ECssTokenType.Parenth_Close) { Stream.Consume(); } return(new MediaCondition(Combinator, conditionList)); } throw new CssSyntaxErrorException(CssErrors.EXPECTING_MEDIA_CONDITION_START, Stream); }