private ParseItem CreateBang(ComplexItem parent, ITextProvider text, ITokenStream stream) { var modifier = stream.Peek(1); if (BangModifier.IsValidModifier(text, modifier, "default")) { return(new DefaultModifier()); } if (BangModifier.IsValidModifier(text, modifier, "important")) { return(new ImportanceModifier()); } if (BangModifier.IsValidModifier(text, modifier, "optional")) { return(new OptionalModifier()); } if (VariableName.IsVariable(text, stream)) { return(CreateVariableDefinitionOrReference(parent, text, stream)); } return(new TokenItem()); }
protected virtual bool ParseCombinator(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { SelectorCombinator combinator = null; switch (stream.Current.Type) { case TokenType.GreaterThan: combinator = new ChildCombinator(); break; case TokenType.Plus: combinator = new AdjacentSiblingCombinator(); break; case TokenType.Tilde: combinator = new GeneralSiblingCombinator(); break; } if (combinator != null) { if (combinator.Parse(itemFactory, text, stream)) { Children.Add(combinator); Combinator = combinator; } } else if (stream.Current.Type != TokenType.OpenCurlyBrace) { // whitespace only combinator means no adding to children or parsing // we just want to know that there was a combinator if (stream.Current.Start >= (stream.Peek(-1).End + 1)) Combinator = new DescendantCombinator(); } return Combinator != null; }
static ParseItem CreateSimpleSelector(ComplexItem parent, IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { switch (stream.Current.Type) { case TokenType.Ampersand: return(new ParentReferenceSelector()); case TokenType.Asterisk: return(new UniversalSelector()); case TokenType.Period: return(new ClassSelector()); case TokenType.Hash: return(new IdSelector()); case TokenType.Identifier: return(new TypeSelector()); case TokenType.OpenBrace: return(new AttributeSelector()); case TokenType.DoubleColon: return(new PseudoElementSelector()); case TokenType.PercentSign: return(new ExtendOnlySelector()); } if (stream.Current.Type == TokenType.Colon) { var next = stream.Peek(1); switch (next.Type) { case TokenType.Identifier: return(new PseudoClassSelector()); case TokenType.Function: return(new PseudoFunctionSelector()); } } return(null); }
private static CommandBinding ParseCommandBinding(ITokenStream stream, ILogger logger) { var tokens = stream.Peek(); if (tokens == null) { return(null); } if (tokens.Length > 3 && tokens[2].Value == "=") { var command = tokens[1].Value; var action = ParseAction(tokens, 3, out var end); if (action != null) { if (end != tokens.Length) { logger?.WriteLine( $"Warning: Ignored unknown symbols at {stream.Path}:{stream.Line}."); } return(new CommandBinding(command, action)); } action = new NoOpAction(); logger?.WriteLine($"Error: Could not parse action at {stream.Path}:{stream.Line}."); return(new CommandBinding(command, action)); } logger?.WriteLine($"Error: Malformed binding at {stream.Path}:{stream.Line}."); return(null); }
public static Token PeekOnly(this ITokenStream stream, Func <Token, bool> predicate, int index) { if (index < 0) { throw new ArgumentOutOfRangeException(nameof(index)); } var i = 0; while (true) { var current = stream.Peek(i++); if (current == null) { return(null); } if (predicate(current)) { index--; if (index < 0) { return(current); } } } }
public static AndSelector ParseAndSelector(ITokenStream tokens) { var selectors = new List <ElementSelector> { ParseNotSelector(tokens) }; while (true) { var zero = tokens.Peek(); switch (zero) { case CaretToken _: tokens.Consume(); selectors.Add(ParseNotSelector(tokens)); break; case NotToken _: case AsteriskToken _: case AmpersandToken _: case StringToken _: case IdentifierToken _: case ScriptToken _: selectors.Add(ParseNotSelector(tokens)); break; default: return(new AndSelector(selectors)); } } }
public static bool IsValidName(ITokenStream stream) { if (stream.Current.Type == TokenType.Period) return stream.Peek(1).Type == TokenType.Identifier; return false; }
private ParseItem CreateVariableDefinitionOrReference(ComplexItem parent, ITextProvider text, ITokenStream stream) { var name = stream.Peek(1); if (name.Type == TokenType.Identifier && stream.Current.End == name.Start) { var assignment = stream.Peek(2); if (assignment.Type == TokenType.Colon || assignment.Type == TokenType.Equal) { return(new VariableDefinition()); } return(new VariableReference()); } return(new TokenItem()); }
static ParseItem CreateFunctionArgument(ComplexItem parent, IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (parent is MixinReference || parent is SystemFunctionReference || parent is UserFunctionReference) if (VariableName.IsVariable(text, stream) && stream.Peek(2).Type == TokenType.Colon) return new NamedFunctionArgument(); return null; }
public static bool IsValidName(ITokenStream stream) { if (stream.Current.Type == TokenType.Period) { return(stream.Peek(1).Type == TokenType.Identifier); } return(false); }
private ParseItem CreatePeriod(ComplexItem parent, ITextProvider text, ITokenStream stream) { if (stream.Peek(1).Type == TokenType.Identifier) { return(new ClassName()); } return(new TokenItem()); }
public override bool Parse(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.Bang && IsValidModifier(text, stream.Peek(1), FlagName)) { Bang = Children.AddCurrentAndAdvance(stream); Flag = Children.AddCurrentAndAdvance(stream); } return Children.Count > 0; }
public override bool Parse(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.At && IsValidTokenType(stream.Peek(1).Type)) { At = Children.AddCurrentAndAdvance(stream); Name = Children.AddCurrentAndAdvance(stream); } return(Children.Count > 0); }
public override bool Parse(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.At && IsValidTokenType(stream.Peek(1).Type)) { At = Children.AddCurrentAndAdvance(stream); Name = Children.AddCurrentAndAdvance(stream); } return Children.Count > 0; }
protected override bool ParseSelectorToken(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.DoubleColon && stream.Peek(1).Type == TokenType.Identifier) { Prefix = Children.AddCurrentAndAdvance(stream, SassClassifierType.PseudoElement); Name = Children.AddCurrentAndAdvance(stream, SassClassifierType.PseudoElement); } return Children.Count > 0; }
public override bool Parse(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.PercentSign && stream.Peek(1).Type == TokenType.Identifier) { Prefix = Children.AddCurrentAndAdvance(stream); Name = Children.AddCurrentAndAdvance(stream); } return(Children.Count > 0); }
public override bool Parse(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.PercentSign && stream.Peek(1).Type == TokenType.Identifier) { Prefix = Children.AddCurrentAndAdvance(stream); Name = Children.AddCurrentAndAdvance(stream); } return Children.Count > 0; }
protected override bool ParseSelectorToken(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.Colon && stream.Peek(1).Type == TokenType.Identifier) { Prefix = Children.AddCurrentAndAdvance(stream, SassClassifierType.PseudoClass); ClassName = Children.AddCurrentAndAdvance(stream, SassClassifierType.PseudoClass); } return(Children.Count > 0); }
public override bool Parse(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.Bang && IsValidModifier(text, stream.Peek(1), FlagName)) { Bang = Children.AddCurrentAndAdvance(stream); Flag = Children.AddCurrentAndAdvance(stream); } return(Children.Count > 0); }
public static bool IsRule(ITextProvider text, ITokenStream stream, string name) { if (stream.Current.Type == TokenType.At) { var nameToken = stream.Peek(1); if (nameToken.Type == TokenType.Identifier) return text.GetText(nameToken.Start, name.Length) == name; } return false; }
private ParseItem CreateHash(ComplexItem parent, ITextProvider text, ITokenStream stream) { var value = stream.Peek(1); if (value.Type == TokenType.Identifier && (value.Length == 3 || value.Length == 6) && IsHex(text, value)) { return(new HexColorValue()); } return(new TokenItem()); }
public static bool IsConditionalContinuationDirective(ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.At) { var name = stream.Peek(1); if (name.Type == TokenType.Identifier) return text.StartsWithOrdinal(name.Start, "else"); } return false; }
public static bool IsConditionalDirective(ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.At) { var name = stream.Peek(1); if (name.Type == TokenType.Identifier || name.Type == TokenType.Function) return text.CompareOrdinal(name.Start, "if"); } return false; }
protected override void ParseDirective(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.Semicolon && stream.Peek(1).Type == TokenType.Identifier) { var selector = itemFactory.CreateSpecific<PseudoClassSelector>(this, text, stream); if (selector.Parse(itemFactory, text, stream)) { Selector = selector; Children.Add(selector); } } }
protected override void ParseDirective(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.Semicolon && stream.Peek(1).Type == TokenType.Identifier) { var selector = itemFactory.CreateSpecific <PseudoClassSelector>(this, text, stream); if (selector.Parse(itemFactory, text, stream)) { Selector = selector; Children.Add(selector); } } }
static ParseItem CreateFunctionArgument(ComplexItem parent, IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (parent is MixinReference || parent is SystemFunctionReference || parent is UserFunctionReference) { if (VariableName.IsVariable(text, stream) && stream.Peek(2).Type == TokenType.Colon) { return(new NamedFunctionArgument()); } } return(null); }
public static bool IsConditionalDirective(ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.At) { var name = stream.Peek(1); if (name.Type == TokenType.Identifier || name.Type == TokenType.Function) { return(text.CompareOrdinal(name.Start, "if")); } } return(false); }
public static bool IsConditionalContinuationDirective(ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.At) { var name = stream.Peek(1); if (name.Type == TokenType.Identifier) { return(text.StartsWithOrdinal(name.Start, "else")); } } return(false); }
public static bool IsVariable(ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.Dollar || stream.Current.Type == TokenType.Bang) { var name = stream.Peek(1); if (name.Type == TokenType.Identifier) { return(true); } } return(false); }
public static bool IsRule(ITextProvider text, ITokenStream stream, string name) { if (stream.Current.Type == TokenType.At) { var nameToken = stream.Peek(1); if (nameToken.Type == TokenType.Identifier) { return(text.GetText(nameToken.Start, name.Length) == name); } } return(false); }
public static ElementSelector ParseNotSelector(ITokenStream tokens) { var zero = tokens.Peek(); var inverse = false; if (zero is NotToken) { inverse = true; tokens.Consume(); } var atom = ParseAtomSelector(tokens); return(inverse ? new NotSelector(atom) : atom); }
private ParseItem CreateImport(ComplexItem parent, ITextProvider text, ITokenStream stream) { var filename = stream.Peek(2); // if doing @import url() then we use standard css import if (UrlItem.IsUrl(text, filename)) { return(new CssImportDirective()); } if ((filename.Type == TokenType.String || filename.Type == TokenType.BadString)) { // check to see if import starts with http(s):// var preamble = text.GetText(filename.Start, 9).Trim('"', '\''); if (preamble.StartsWith("//") || preamble.StartsWith("http://") || preamble.StartsWith("https://")) { return(new CssImportDirective()); } // check for media query var next = stream.Peek(3); if (next.Type == TokenType.Identifier) { return(new CssImportDirective()); } // check if we are importing actual css file if (text.GetText(filename.Start, filename.Length).Trim('"', '\'').EndsWith(".css")) { return(new CssImportDirective()); } } // since we didn't detect that it's a css import, use the sass import return(new SassImportDirective()); }
protected override bool ParseSelectorToken(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.Colon && stream.Peek(1).Type == TokenType.Function) { Prefix = Children.AddCurrentAndAdvance(stream); var function = itemFactory.CreateSpecific <PseduoFunction>(this, text, stream); if (function.Parse(itemFactory, text, stream)) { Function = function; Children.Add(function); } } return(Children.Count > 0); }
protected override bool ParseSelectorToken(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.Colon && stream.Peek(1).Type == TokenType.Function) { Prefix = Children.AddCurrentAndAdvance(stream); var function = itemFactory.CreateSpecific<PseduoFunction>(this, text, stream); if (function.Parse(itemFactory, text, stream)) { Function = function; Children.Add(function); } } return Children.Count > 0; }
private ParseItem CreateAtRule(ComplexItem parent, ITextProvider text, ITokenStream stream) { var nameToken = stream.Peek(1); if (nameToken.Type == TokenType.Identifier || nameToken.Type == TokenType.Function) { var ruleName = text.GetText(nameToken.Start, nameToken.Length); switch (ruleName) { case "mixin": return(new MixinDefinition()); case "content": return(new ContentDirective()); case "include": return(new MixinReference()); case "function": return(new UserFunctionDefinition()); case "import": return(CreateImport(parent, text, stream)); case "extend": return(new ExtendDirective()); case "for": return(new ForLoopDirective()); case "while": return(new WhileLoopDirective()); case "each": return(new EachLoopDirective()); case "if": case "else": case "else if": return(new ConditionalControlDirective()); case "media": return(new MediaQueryDirective()); case "font-face": return(new FontFaceDirective()); case "page": return(new PageDirective()); case "charset": return(new CharsetDirective()); case "keyframes": return(new KeyframesDirective()); default: return(new AtRule()); } } return(new TokenItem()); }
public static ContainmentSelector ParseContainmentSelector(ITokenStream tokens, bool isNested) { var selectors = new List <AndSelector> { ParseAndSelector(tokens) }; while (true) { var zero = tokens.Peek(); if (!(zero is WhitespaceToken)) { break; } var one = tokens.DrainPeek(); switch (one) { case CommaToken _: case LCurlyToken _: goto exit; default: selectors.Add(ParseAndSelector(tokens)); continue; } } exit: for (var i = 1; i < selectors.Count; i++) { if (selectors[i].HasContextSelector) { throw new FormatException("Unexpected context selector in rule."); } } if (isNested && !selectors[0].HasContextSelector) { selectors.Insert(0, new AndSelector(new[] { new ContextSelector() })); } return(new ContainmentSelector(selectors)); }
public static Token[] PeekNonEmpty(this ITokenStream stream) { while (true) { var tokens = stream.Peek(); if (tokens == null) { return(null); } if (tokens.Length > 0) { return(tokens); } stream.Move(); } }
static ParseItem CreateDocumentationTag(ComplexItem parent, IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (!(parent is XmlDocumentationComment)) return null; if (stream.Current.Type == TokenType.LessThan) { var next = stream.Peek(1); if (next.Type != TokenType.Identifier) return null; switch (text.GetText(next.Start, next.Length)) { case "reference": return new FileReferenceTag(); } } return null; }
internal static Token DrainPeek(this ITokenStream tokens) { Token current; while (true) { current = tokens.Peek(); if (current is WhitespaceToken) { tokens.Consume(); } else { break; } } return(current); }
private ParseItem CreateSelectorComponent(ComplexItem parent, ITextProvider text, ITokenStream stream) { switch (stream.Current.Type) { case TokenType.Asterisk: return(new UniversalSelector()); case TokenType.Period: return(new ClassSelector()); case TokenType.Hash: return(new IdSelector()); case TokenType.Identifier: return(new TypeSelector()); case TokenType.OpenBrace: return(new AttributeSelector()); case TokenType.DoubleColon: return(new PseudoElementSelector()); case TokenType.GreaterThan: return(new ChildCombinator()); case TokenType.Plus: return(new AdjacentSiblingCombinator()); case TokenType.Tilde: return(new GeneralSiblingCombinator()); case TokenType.Ampersand: return(new ParentReferenceSelector()); case TokenType.OpenInterpolation: return(new StringInterpolationSelector()); case TokenType.PercentSign: return(new ExtendOnlySelector()); } if (stream.Current.Type == TokenType.Colon) { var next = stream.Peek(1); switch (next.Type) { case TokenType.Identifier: return(new PseudoClassSelector()); case TokenType.Function: return(new PseudoFunctionSelector()); } } return(null); }
public static bool IsDeclaration(ITextProvider text, ITokenStream stream) { int position = stream.Position; bool validPropertyName = false; while (true) { var last = stream.Current; var next = stream.Advance(); if (next.Start > last.End || IsDeclarationTerminator(last.Type)) { break; } if (next.Type == TokenType.Colon) { var value = stream.Peek(1); switch (value.Type) { case TokenType.Ampersand: validPropertyName = false; break; case TokenType.Identifier: case TokenType.Function: validPropertyName = value.Start > next.End || !IsPseudoSelector(text, value); break; default: validPropertyName = true; break; } break; } } stream.SeekTo(position); return(validPropertyName); }
public override bool Parse(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.Identifier && IsValidNamedRange(text.GetText(stream.Current.Start, stream.Current.Length))) { AnimationBegin = Children.AddCurrentAndAdvance(stream, SassClassifierType.Keyword); } else if (stream.Current.Type == TokenType.Number && stream.Peek(1).Type == TokenType.PercentSign) { ParseItem begin = itemFactory.Create <PercentageUnit>(this, text, stream); if (begin.Parse(itemFactory, text, stream)) { AnimationBegin = begin; Children.Add(begin); if (stream.Current.Type == TokenType.Comma) { Comma = Children.AddCurrentAndAdvance(stream, SassClassifierType.Punctuation); } ParseItem end = itemFactory.Create <PercentageUnit>(this, text, stream); if (end.Parse(itemFactory, text, stream)) { AnimationEnd = end; Children.Add(end); } } } if (AnimationBegin != null) { var block = itemFactory.CreateSpecific <RuleBlock>(this, text, stream); if (block.Parse(itemFactory, text, stream)) { Body = block; Children.Add(block); } } return(Children.Count > 0); }
protected virtual bool ParseCombinator(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { SelectorCombinator combinator = null; switch (stream.Current.Type) { case TokenType.GreaterThan: combinator = new ChildCombinator(); break; case TokenType.Plus: combinator = new AdjacentSiblingCombinator(); break; case TokenType.Tilde: combinator = new GeneralSiblingCombinator(); break; } if (combinator != null) { if (combinator.Parse(itemFactory, text, stream)) { Children.Add(combinator); Combinator = combinator; } } else if (stream.Current.Type != TokenType.OpenCurlyBrace) { // whitespace only combinator means no adding to children or parsing // we just want to know that there was a combinator if (stream.Current.Start >= (stream.Peek(-1).End + 1)) { Combinator = new DescendantCombinator(); } } return(Combinator != null); }
public override bool Parse(IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { if (stream.Current.Type == TokenType.Identifier && IsValidNamedRange(text.GetText(stream.Current.Start, stream.Current.Length))) { AnimationBegin = Children.AddCurrentAndAdvance(stream, SassClassifierType.Keyword); } else if (stream.Current.Type == TokenType.Number && stream.Peek(1).Type == TokenType.PercentSign) { ParseItem begin = itemFactory.Create<PercentageUnit>(this, text, stream); if (begin.Parse(itemFactory, text, stream)) { AnimationBegin = begin; Children.Add(begin); if (stream.Current.Type == TokenType.Comma) Comma = Children.AddCurrentAndAdvance(stream, SassClassifierType.Punctuation); ParseItem end = itemFactory.Create<PercentageUnit>(this, text, stream); if (end.Parse(itemFactory, text, stream)) { AnimationEnd = end; Children.Add(end); } } } if (AnimationBegin != null) { var block = itemFactory.CreateSpecific<RuleBlock>(this, text, stream); if (block.Parse(itemFactory, text, stream)) { Body = block; Children.Add(block); } } return Children.Count > 0; }
public static bool IsDeclaration(ITextProvider text, ITokenStream stream) { int position = stream.Position; bool validPropertyName = false; while (true) { var last = stream.Current; var next = stream.Advance(); if (next.Start > last.End || IsDeclarationTerminator(last.Type)) break; if (next.Type == TokenType.Colon) { var value = stream.Peek(1); switch (value.Type) { case TokenType.Ampersand: validPropertyName = false; break; case TokenType.Identifier: case TokenType.Function: validPropertyName = value.Start > next.End || !IsPseudoSelector(text, value); break; default: validPropertyName = true; break; } break; } } stream.SeekTo(position); return validPropertyName; }
static ParseItem CreateSimpleSelector(ComplexItem parent, IItemFactory itemFactory, ITextProvider text, ITokenStream stream) { switch (stream.Current.Type) { case TokenType.Ampersand: return new ParentReferenceSelector(); case TokenType.Asterisk: return new UniversalSelector(); case TokenType.Period: return new ClassSelector(); case TokenType.Hash: return new IdSelector(); case TokenType.Identifier: return new TypeSelector(); case TokenType.OpenBrace: return new AttributeSelector(); case TokenType.DoubleColon: return new PseudoElementSelector(); case TokenType.PercentSign: return new ExtendOnlySelector(); } if (stream.Current.Type == TokenType.Colon) { var next = stream.Peek(1); switch (next.Type) { case TokenType.Identifier: return new PseudoClassSelector(); case TokenType.Function: return new PseudoFunctionSelector(); } } return null; }
static bool IsFunctionCall(ITokenStream stream) { return stream.Current.Type == TokenType.Function || (stream.Current.Type == TokenType.Identifier && stream.Peek(1).Type == TokenType.OpenFunctionBrace); }
public static bool IsNamedArgument(ITextProvider text, ITokenStream stream) { return VariableName.IsVariable(text, stream) && stream.Peek(2).Type == TokenType.Colon; }