diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Revision history for stylist
 
+## 2.4.0 -- 2020-12-31
+* Add `@document regexp()` support via TDFA.
+* Allow callers to define psuedoclasses via callbacks on attribute value.
+
 ## 0.0.1  -- YYYY-mm-dd
 
 * First version. Released on an unsuspecting world.
diff --git a/src/Data/CSS/Preprocessor/Conditions.hs b/src/Data/CSS/Preprocessor/Conditions.hs
--- a/src/Data/CSS/Preprocessor/Conditions.hs
+++ b/src/Data/CSS/Preprocessor/Conditions.hs
@@ -21,6 +21,7 @@
 import Data.Text (unpack)
 import Network.URI (URI(..), URIAuth(..), parseURI)
 import Control.Concurrent.Async (forConcurrently)
+import Text.Regex.TDFA ((=~))
 
 import Data.List
 
@@ -85,6 +86,9 @@
         | isUnstyled self = parseAtBlock self toks
         | otherwise = addAtRule self "document" toks
     -- TODO Support regexp() conditions, requires new dependency
+    addAtRule self "document" (Function "regexp":String pattern:RightParen:toks)
+        | hostUrlS self =~ unpack pattern = parseAtBlock self toks
+        | otherwise = addAtRule self "document" toks
     addAtRule self "document" tokens = (self, skipAtRule tokens)
 
     addAtRule self "media" toks
diff --git a/src/Data/CSS/Preprocessor/Conditions/Expr.hs b/src/Data/CSS/Preprocessor/Conditions/Expr.hs
--- a/src/Data/CSS/Preprocessor/Conditions/Expr.hs
+++ b/src/Data/CSS/Preprocessor/Conditions/Expr.hs
@@ -86,7 +86,7 @@
 -- Have tokens lower to variables, to make things easier for the callee.
 eval' stack v t (Tok tok:ops) | t tok /= B False = eval' (t tok:stack) v t ops
 eval' stack v t (Tok (Ident name):ops) = eval' (v name:stack) v t ops
--- TODO: How should I handle ratios?
+-- Ratios should be compared as floating point...
 eval' (N y:N x:stack) v t (MkRatio:ops) = eval' (N (x / y):stack) v t ops
 eval' (N y:N x:stack) v t (Less:ops) = eval' (B (x < y):stack) v t ops
 eval' (R _ y:N x:stack) v t (Less:ops) = eval' (B (x < y):stack) v t ops
diff --git a/src/Data/CSS/Preprocessor/PsuedoClasses.hs b/src/Data/CSS/Preprocessor/PsuedoClasses.hs
--- a/src/Data/CSS/Preprocessor/PsuedoClasses.hs
+++ b/src/Data/CSS/Preprocessor/PsuedoClasses.hs
@@ -2,7 +2,7 @@
 -- | Lowers psuedoclasses to rawer syntactic forms.
 module Data.CSS.Preprocessor.PsuedoClasses(LowerPsuedoClasses(..),
     psuedoClassesFilter, htmlPsuedoFilter,
-    addRewrite, addRewrite', addPsuedoEl, addNamespace) where
+    addRewrite, addRewrite', addPsuedoEl, addNamespace, addTest, PropertyTest) where
 
 import Data.CSS.Syntax.StyleSheet
 import Data.CSS.Syntax.Selector
@@ -16,9 +16,10 @@
 --------
 ---- core
 --------
+type RewriteMap = HashMap Text ([Token] -> [SimpleSelector])
 data LowerPsuedoClasses s = LowerPsuedoClasses {
     inner :: s,
-    rewriteRules :: HashMap Text [Token],
+    rewriteRules :: RewriteMap,
     psuedoEls :: [Text],
     namespaces :: HashMap Text Text
 }
@@ -48,7 +49,7 @@
 extractPseudoEl' :: [Text] -> [SimpleSelector] -> Maybe Text
 extractPseudoEl' ps sel = listToMaybe [p | Psuedoclass p [] <- sel, p `elem` ps]
 
-lowerSelector :: HashMap Text Text -> HashMap Text [Token] -> Selector -> Selector
+lowerSelector :: HashMap Text Text -> RewriteMap -> Selector -> Selector
 lowerSelector ns rewrites (Element sel') = Element $ lowerSelector' ns rewrites sel'
 lowerSelector ns rewrites (Child p sel') =
     Child (lowerSelector ns rewrites p) $ lowerSelector' ns rewrites sel'
@@ -59,14 +60,11 @@
 lowerSelector ns rewrites (Sibling sib sel') =
     Sibling (lowerSelector ns rewrites sib) $ lowerSelector' ns rewrites sel'
 
-lowerSelector' :: HashMap Text Text -> HashMap Text [Token] -> [SimpleSelector] -> [SimpleSelector]
+lowerSelector' :: HashMap Text Text -> RewriteMap -> [SimpleSelector] -> [SimpleSelector]
 lowerSelector' namespaces' rewrites (Namespace ns:sels) =
     Namespace (fromMaybe "about:invalid" $ HM.lookup ns namespaces') : lowerSelector' namespaces' rewrites sels
-lowerSelector' ns rewrites (Psuedoclass name []:sels)
-    | Just value <- name `HM.lookup` rewrites = Psuedoclass "where" value : lowerSelector' ns rewrites sels
-lowerSelector' ns rewrites (Psuedoclass name [arg]:sels)
-    | Just value <- name `HM.lookup` rewrites =
-        Psuedoclass "where" [if a == Ident "_" then arg else a | a <- value] : lowerSelector' ns rewrites sels
+lowerSelector' ns rewrites (Psuedoclass name args:sels)
+    | Just value <- name `HM.lookup` rewrites = value args ++ lowerSelector' ns rewrites sels
 lowerSelector' ns rewrites (sel:sels) = sel : lowerSelector' ns rewrites sels
 lowerSelector' _ _ [] = []
 
@@ -82,7 +80,21 @@
 addRewrite :: Text -> Text -> LowerPsuedoClasses s -> LowerPsuedoClasses s
 addRewrite name sel self = addRewrite' name (tokenize sel) self
 addRewrite' :: Text -> [Token] -> LowerPsuedoClasses s -> LowerPsuedoClasses s
-addRewrite' name sel self = self { rewriteRules = insert name sel $ rewriteRules self }
+addRewrite' name sel self =
+    addTest' name (\args -> [Psuedoclass "where" $ spliceArgs sel args]) self
+  where
+    spliceArgs [] [] = []
+    spliceArgs (Ident "_":toks) (arg:args) = arg : spliceArgs toks args
+    spliceArgs (tok:toks) args = tok : spliceArgs toks args
+    spliceArgs _ _ = [Ident "\tfail"]
+
+addTest :: Text -> Maybe Text -> Text -> PropertyFunc -> LowerPsuedoClasses s -> LowerPsuedoClasses s
+addTest name ns attr test self = addTest' name (noArg [Property ns attr $ Callback test]) self
+    where
+        noArg sel [] = sel
+        noArg _ _ = [Psuedoclass " fail" []]
+addTest' :: Text -> ([Token] -> [SimpleSelector]) -> LowerPsuedoClasses s -> LowerPsuedoClasses s
+addTest' name sel self = self {rewriteRules = insert name sel $ rewriteRules self }
 
 addNamespace :: Text -> Text -> LowerPsuedoClasses s -> LowerPsuedoClasses s
 addNamespace ns uri self = self { namespaces = insert ns uri $ namespaces self }
diff --git a/stylist.cabal b/stylist.cabal
--- a/stylist.cabal
+++ b/stylist.cabal
@@ -10,7 +10,7 @@
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             2.3.0.0
+version:             2.4.0.0
 
 -- A short (one-line) description of the package.
 synopsis:            Apply CSS styles to a document tree.
@@ -70,7 +70,8 @@
   -- Other library packages from which modules are imported.
   build-depends:       base >=4.9 && <=4.12, css-syntax >=0.1 && <0.2, text,
                         unordered-containers >= 0.2 && <0.3, hashable,
-                        network-uri >= 2.6 && <2.7, async >= 2.1 && <2.3
+                        network-uri >= 2.6 && <2.7, async >= 2.1 && <2.3,
+                        regex-tdfa >= 1.3
   
   -- Directories containing source files.
   hs-source-dirs:      src
@@ -89,5 +90,5 @@
   build-depends:       base >=4.9 && <=4.12, css-syntax >=0.1 && <0.2, text,
                         unordered-containers >= 0.2 && <0.3, hashable,
                         network-uri >= 2.6 && <2.7, async >= 2.1 && <2.3, hspec, QuickCheck,
-                        scientific >= 0.3 && <1.0
+                        scientific >= 0.3 && <1.0, regex-tdfa >= 1.3
   ghc-options: -Wall
