private static Selector ApplyEscapeMap(Selector sel, Dictionary<char, string> map)
{
// shortcircuit the typical case
if (map.Count == 0) return sel;
var multi = sel as MultiSelector;
if (multi != null)
{
var ret = multi.Selectors.Select(s => ApplyEscapeMap(s, map)).ToList();
return new MultiSelector(ret, multi.Start, multi.Stop, multi.FilePath);
}
var childSel = sel as ChildSelector;
if (childSel != null)
{
var parent = ApplyEscapeMap(childSel.Parent, map);
var child = ApplyEscapeMap(childSel.Child, map);
return new ChildSelector(parent, child, childSel.Start, childSel.Stop, childSel.FilePath);
}
var sibling = sel as AdjacentSiblingSelector;
if(sibling != null)
{
var older = ApplyEscapeMap(sibling.Older, map);
var younger = ApplyEscapeMap(sibling.Younger, map);
return new AdjacentSiblingSelector(older, younger, sibling.Start, sibling.Stop, sibling.FilePath);
}
var compound = sel as CompoundSelector;
if (compound != null)
{
var inner = ApplyEscapeMap(compound.Inner, map);
var outer = ApplyEscapeMap(compound.Outer, map);
return new CompoundSelector(inner, outer, compound.Start, compound.Stop, compound.FilePath);
}
var concat = sel as ConcatWithParentSelector;
if (concat != null)
{
var subSel = ApplyEscapeMap(concat.Selector, map);
return new ConcatWithParentSelector(subSel, concat.Start, concat.Stop, concat.FilePath);
}
var attrOp = sel as AttributeOperatorSelector;
if (attrOp != null)
{
var attr = ApplyEscapeMap(attrOp.Attribute, map);
var value = ApplyEscapeMap(attrOp.Value, map);
return new AttributeOperatorSelector(attr, attrOp.Operator, value, attrOp.Start, attrOp.Stop, attrOp.FilePath);
}
var attrSet = sel as AttributeSetSelector;
if (attrSet != null)
{
var attr = ApplyEscapeMap(attrSet.Attribute, map);
return new AttributeSetSelector(attr, attrSet.Start, attrSet.Stop, attrSet.FilePath);
}
var @class = sel as ClassSelector;
if (@class != null)
{
var className = ApplyEscapeMap(@class.Name, map);
return new ClassSelector(className, @class.Start, @class.Stop, @class.FilePath);
}
var concatSel = sel as ConcatSelector;
if (concatSel != null)
{
var sels = concatSel.Selectors.Select(s => ApplyEscapeMap(s, map)).ToList();
return new ConcatSelector(sels, concatSel.Start, concatSel.Stop, concatSel.FilePath);
}
var elem = sel as ElementSelector;
if (elem != null)
{
var name = ApplyEscapeMap(elem.Name, map);
return new ElementSelector(name, elem.Start, elem.Stop, elem.FilePath);
}
var id = sel as IdSelector;
if (id != null)
{
var name = ApplyEscapeMap(id.Name, map);
return new IdSelector(name, id.Start, id.Stop, id.FilePath);
}
var langSel = sel as LangPseudoClassSelector;
if (langSel != null)
{
var lang = ApplyEscapeMap(langSel.Language, map);
return new LangPseudoClassSelector(lang, langSel.Start, langSel.Stop, langSel.FilePath);
}
var not = sel as NotPseudoClassSelector;
if (not != null)
{
var innerSel = ApplyEscapeMap(not.Selector, map);
return new NotPseudoClassSelector(innerSel, not.Start, not.Stop, not.FilePath);
}
// You can't really escape and have valid versions of these selectors
if (sel is NthChildPsuedoClassSelector || sel is NthLastChildPseudoClassSelector) return sel;
// Likewise
if (sel is NthOfTypePseudoClassSelector || sel is NthLastOfTypePseudoClassSelector) return sel;
// Ditto
if (sel is PseudoClassSelector) return sel;
// And lucky #4
if (sel is WildcardSelector) return sel;
throw new InvalidOperationException(sel + " should have been handled but wasn't");
}