/// <summary> /// selectors : ws selector (s ',' ws selector)* ws ; /// </summary> /// <param name="node"></param> /// <param name="action"></param> /// <returns></returns> private IEnumerable<ElementBlock> Selectors(PegNode node, Func<IEnumerable<ElementBlock>, IEnumerable<ElementBlock>> action) { foreach(var selector in node.AsEnumerable(x => x.id_.ToEnLess() == EnLess.selector)) { var selectors = Selector(selector); foreach(var s in action(selectors)) yield return s; } }
/// <summary> /// primary: (import / declaration / ruleset / comment)* ; /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> private ElementBlock Primary(PegNode node, ElementBlock elementBlock) { foreach (var nextPrimary in node.AsEnumerable()) { switch (nextPrimary.id_.ToEnLess()) { case EnLess.import: Import(nextPrimary.child_, elementBlock); //element.Children.AddRange(import); break; case EnLess.insert: Insert(nextPrimary.child_, elementBlock); //element.Children.AddRange(import); break; case EnLess.standard_ruleset: RuleSet(nextPrimary, elementBlock); break; case EnLess.mixin_ruleset: Mixin(nextPrimary,elementBlock); break; case EnLess.declaration: Declaration(nextPrimary.child_, elementBlock); break; } } return elementBlock; }
/// <summary> /// selector : (s select element s)+ arguments? ; /// </summary> /// <param name="node"></param> /// <returns></returns> private IEnumerable<ElementBlock> Selector(PegNode node) { var enumerator = node.AsEnumerable().GetEnumerator(); while(enumerator.MoveNext()) { ElementBlock block; var selector = enumerator.Current.GetAsString(Src).Trim(); enumerator.MoveNext(); var name = enumerator.Current.GetAsString(Src); var next = enumerator.Current.next_; var isMixinWithArgs = next != null && next.ToEnLess() == EnLess.arguments; if (isMixinWithArgs) block = new PureMixinBlock(name, selector); else block = new ElementBlock(name, selector); if (isMixinWithArgs) { var arguments = GetMixinArguments(next, block); enumerator.MoveNext(); foreach (var argument in arguments) block.Add(argument); } yield return block; } }
private IEnumerable<Variable> GetMixinArguments(PegNode arguments, ElementBlock block) { var enumerator = arguments.AsEnumerable().GetEnumerator(); var variables = new List<Variable>(); var position = 0; while (enumerator.MoveNext()) { var node = enumerator.Current; string name; IEnumerable<INode> value; if (node.child_.ToEnLess() == EnLess.variable) // expect "@variable: expression" { name = node.child_.GetAsString(Src); value = Expressions(node.child_.next_, block); } else // expect "expresion" { // HACK: to make Arguments return as expected. var tmpNode = new PegNode(null, (int) EnLess.arguments); tmpNode.child_ = new PegNode(tmpNode, (int)EnLess.argument); tmpNode.child_.child_ = node.child_; name = position.ToString(); value = Arguments(tmpNode, block).ToList(); } variables.Add(new Variable(name, value)); if(node.next_ == null || node.next_.ToEnLess() != EnLess.argument) break; position++; } return variables; }
/// <summary> /// TODO: Added quick fix for multipule mixins, but need to add mixins with variables which will changes things a bit /// </summary> /// <param name="node"></param> /// <param name="elementBlock"></param> // private void OldMixin(PegNode node, Element element) // { // var root = element.GetRoot(); // foreach (var el in Selectors(node.child_, els => els)) // root = root.Descend(el.Selector, el); // if (root.Children != null) element.Children.AddRange(root.Children); // } private void Mixin(PegNode node, ElementBlock elementBlock) { var root = elementBlock.GetRoot(); var rules = new List<INode>(); foreach (var mixins in node.AsEnumerable()) { var selectors = Selectors(mixins, els => els).ToList(); if (selectors.Count() > 1) { foreach (var el in selectors) root = root.Descend(el.Selector, el); if (root.Children != null) rules.AddRange(root.Children); } else { var el = selectors.First(); foreach (var mixinElement in root.Nearests(el.Name)) { if (mixinElement.Children == null) continue; var children = GetMixinChildren(elementBlock, el.Variables, mixinElement.Children); rules.AddRange(children); el.Parent = elementBlock; } } } elementBlock.Children.AddRange(rules); }
/// <summary> /// fonts : font (s ',' s font)+ ; /// </summary> /// <param name="node"></param> /// <returns></returns> private INode Fonts(PegNode node) { var fonts = from childNode in node.AsEnumerable() select (childNode.child_ ?? childNode).GetAsString(Src); return new FontFamily(fonts.ToArray()); }
/// <summary> /// cursor (s ',' s cursor)+ ; /// </summary> /// <param name="node"></param> /// <returns></returns> private INode Cursors(PegNode node) { var set = from childNode in node.AsEnumerable() select (childNode.child_ ?? childNode).GetAsString(Src); return new CursorSet(set.ToArray()); }
/// <summary> /// arguments : '(' s argument s (',' s argument s)* ')'; /// argument : color / number unit / string / [a-zA-Z]+ '=' dimension / function / expressions / [-a-zA-Z0-9_%$/.&=:;#+?]+ / keyword (S keyword)*; /// </summary> /// <param name="node"></param> /// <param name="element"></param> /// <returns></returns> private IEnumerable<INode> Arguments(PegNode node, ElementBlock element) { foreach (var argument in node.AsEnumerable()) { if (argument.child_ == null) yield return new Anonymous(argument.GetAsString(Src)); else { switch (argument.child_.id_.ToEnLess()) { case EnLess.color: yield return Color(argument.child_); break; case EnLess.number: yield return Number(argument.child_); break; case EnLess.function: yield return Function(argument.child_, element); break; case EnLess.expressions: yield return Expression(argument.child_, element); break; case EnLess.@string: yield return new String(argument.GetAsString(Src)); break; case EnLess.keyword: yield return new Keyword(argument.GetAsString(Src)); break; default: yield return new Anonymous(argument.GetAsString(Src)); break; } } } }
/// <summary> /// selector : (s select element s)+ arguments? ; /// </summary> /// <param name="node"></param> /// <returns></returns> private IEnumerable<Element> Selector(PegNode node) { var enumerator = node.AsEnumerable().GetEnumerator(); while(enumerator.MoveNext()) { var selector = enumerator.Current.GetAsString(Src).Trim(); enumerator.MoveNext(); var name = enumerator.Current.GetAsString(Src); yield return new Element(name, selector); } }
/// <summary> /// arguments : '(' s argument s (',' s argument s)* ')'; /// </summary> /// <param name="node"></param> /// <returns></returns> private IEnumerable<INode> Arguments(PegNode node) { foreach (var argument in node.AsEnumerable().Skip(1)) { if (argument.child_ == null) yield return new Anonymous(argument.GetAsString(Src)); else { switch (argument.child_.id_.ToEnLess()) { case EnLess.color: yield return Color(argument); break; case EnLess.number: yield return Number(argument); break; case EnLess.@string: yield return new String(argument.GetAsString(Src)); break; case EnLess.keyword: yield return new Keyword(argument.GetAsString(Src)); break; default: yield return new Anonymous(argument.GetAsString(Src)); break; } } } }