diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,14 @@
+# v0.5.0.3
+
+## Fixes
+
+- Fixed subquery operators requiring whitespace around them: unspaced forms like `a=ANY(b)` used to be a parse error and now parse, matching Postgres (#36).
+
 # v0.5.0.2
 
 ## Non-breaking
 
-- `PostgresqlSyntax.Algebra`'s `LeftRecursion base ext item` class (internal-library-only, not part of the public `PostgresqlSyntax` API) is now a single-method `Extends base ext` — drops the unread `item` type parameter: `extension`/`applyExtension`/`foldExtensions` are gone in favor of one `parseExtensions` method; `nonRecursiveParser` → `parseBase`; `parseLeftRecursive` → `parseMaybeExtended`; `leftRecursionProperties` → `extendedByProperties`. `JoinedTableExtension` is deleted (#33).
+- `PostgresqlSyntax.Algebra`'s `LeftRecursion base ext item` class (internal-library-only, not part of the public `PostgresqlSyntax` API) is now a single-method `Extends base ext` - drops the unread `item` type parameter: `extension`/`applyExtension`/`foldExtensions` are gone in favor of one `parseExtensions` method; `nonRecursiveParser` → `parseBase`; `parseLeftRecursive` → `parseMaybeExtended`; `leftRecursionProperties` → `extendedByProperties`. `JoinedTableExtension` is deleted (#33).
 - `TableRef.hs` and `FuncApplicationParams.hs` now have explicit export lists, exporting only their types and instances (#30).
 
 ## Fixes
diff --git a/hspec-test/Ast/AExprSpec.hs b/hspec-test/Ast/AExprSpec.hs
--- a/hspec-test/Ast/AExprSpec.hs
+++ b/hspec-test/Ast/AExprSpec.hs
@@ -19,8 +19,11 @@
   itSatisfiesRefines @SelectWithParens @AExpr
   itSatisfiesArbitrary @AExpr
   describe "Postgres grammar conformance" $ do
+    describe "accepts subquery operators without surrounding whitespace" $ do
+      itParses @AExpr "a=ANY(b)"
+
     -- gram.y:15985,15987 have only @a_expr qual_Op a_expr@ and
-    -- @qual_Op a_expr@ — the postfix @a_expr qual_Op@ form was removed
+    -- @qual_Op a_expr@ - the postfix @a_expr qual_Op@ form was removed
     -- from Postgres in v14.
     describe "rejects postfix operators" $ do
       itRejects @AExpr "1 +#"
@@ -64,7 +67,7 @@
       -- Reparsing always wraps a parenthesized operand in an explicit
       -- 'InParensCExpr' (parens are themselves a production), so the
       -- fixpoint of render/parse is the parenthesized form, not the bare
-      -- @outer@ below — that's expected and matches how
+      -- @outer@ below - that's expected and matches how
       -- 'PostgresqlSyntax.Ast.AExpr.Qc.Arbitrary'\'s generator pre-wraps
       -- this same shape. What matters here is that the parens are present at
       -- all, and that the fixpoint is stable.
diff --git a/library-internal/PostgresqlSyntax/Algebra.hs b/library-internal/PostgresqlSyntax/Algebra.hs
--- a/library-internal/PostgresqlSyntax/Algebra.hs
+++ b/library-internal/PostgresqlSyntax/Algebra.hs
@@ -17,6 +17,7 @@
     parseMaybeExtended,
     parseExtended,
     parseExtensionChain,
+    Parser,
   )
 where
 
@@ -35,11 +36,11 @@
 -- Laws:
 --
 -- * __Roundtrips__: @parse settings (toText settings a) = Right a@ for every
---   'Settings' — rendering and parsing are inverses.
+--   'Settings' - rendering and parsing are inverses.
 -- * __Congruent rendering__: @a == b => toTextBuilder settings a == toTextBuilder settings b@
---   for every 'Settings' — rendering only depends on the value, not on how it
+--   for every 'Settings' - rendering only depends on the value, not on how it
 --   was constructed. This is what makes it meaningful to say two structurally
---   different shapes can still render to identical text — the ambiguity that
+--   different shapes can still render to identical text - the ambiguity that
 --   'Canonicalizes' exists to resolve.
 class IsAst a where
   -- |
@@ -113,7 +114,7 @@
 -- 'Qc.Property'-checkers for 'Canonicalizes'\'s documented laws, keyed by
 -- name. \"Parse-agreement\" is tested at 'mempty' 'Settings', matching how
 -- 'isAstProperties'\'s \"Renders equal values equally\" property handles \"for
--- every 'Settings'\" — no 'Qc.Arbitrary' 'Settings' instance exists or is
+-- every 'Settings'\" - no 'Qc.Arbitrary' 'Settings' instance exists or is
 -- being added.
 canonicalizesProperties :: forall a. (Canonicalizes a, Eq a, Show a, Qc.Arbitrary a) => [(String, Qc.Property)]
 canonicalizesProperties =
@@ -152,14 +153,14 @@
   ]
 
 -- |
--- A type some of whose grammar productions are left-recursive — i.e. there
+-- A type some of whose grammar productions are left-recursive - i.e. there
 -- is a larger recursive form built by extending a value of this type on its
 -- left. 'parseBase' is everything that is /not/ one of those productions:
 -- the @β@ of @A -> Aα | β@.
 --
 -- This is a strictly weaker claim than 'Extends', which additionally
 -- names the specific @ext@ of one such hub. A type can be 'LeftRecursive'
--- without being any hub's @base@ — 'PostgresqlSyntax.Ast.JoinedTable' and
+-- without being any hub's @base@ - 'PostgresqlSyntax.Ast.JoinedTable' and
 -- 'PostgresqlSyntax.Ast.SimpleSelect' both are, since each is reached by
 -- extending a /different/ type (@table_ref@ and @select_clause@
 -- respectively) yet still has non-left-recursive productions of its own.
@@ -188,7 +189,7 @@
 --
 -- * __Base-parser agreement__: @parser \@base = parseMaybeExtended \@base@
 -- * __Maximal munch__: 'parseExtensions' must not return while a further
---   extension is available — instances build this on 'parseExtensionChain'
+--   extension is available - instances build this on 'parseExtensionChain'
 --   where possible, which already guarantees it.
 class (LeftRecursive base, Refines ext base) => Extends base ext | ext -> base where
   -- | Parse one or more extensions onto an already-parsed left operand,
@@ -249,7 +250,7 @@
 -- Parses one or more items back-to-back, wrapping each in
 -- 'Parser.wrapToHead'\/'Parser.endHead' so that, once an item's own head has
 -- matched, backtracking out of the whole chain (back to "there are no more
--- items") is no longer attempted — matching the hand-written
+-- items") is no longer attempted - matching the hand-written
 -- recursive-descent loops this replaces. This is the shared backtracking
 -- protocol underlying 'Extends'\'s \"Maximal munch\" law: an instance
 -- building 'parseExtensions' on top of this combinator gets the law for
@@ -265,3 +266,5 @@
       pure $ case rest of
         Nothing -> i :| []
         Just (j :| js) -> i :| j : js
+
+type Parser = Parser.HeadedParsec Void Text
diff --git a/library-internal/PostgresqlSyntax/Ast/AExpr.hs b/library-internal/PostgresqlSyntax/Ast/AExpr.hs
--- a/library-internal/PostgresqlSyntax/Ast/AExpr.hs
+++ b/library-internal/PostgresqlSyntax/Ast/AExpr.hs
@@ -142,13 +142,13 @@
       -- right-hand operand via an unrestricted recursive @a_expr@ call, so
       -- rendering it plainly always reconstructs the same shape on reparse.
       -- The *left* position is different: control only returns to
-      -- @suffixRec@'s loop after a __bounded__ production — one that
+      -- @suffixRec@'s loop after a __bounded__ production - one that
       -- doesn't itself end in an unrestricted recursive @a_expr@. A value
       -- shaped like 'PlusAExpr'\/'MinusAExpr'\/'NotAExpr'\/
       -- 'PrefixQualOpAExpr'\/'AtTimeZoneAExpr'\/'SymbolicBinOpAExpr'\/
       -- 'AndAExpr'\/'OrAExpr'\/'VerbalExprBinOpAExpr', or a 'ReversableOpAExpr'
       -- whose 'PostgresqlSyntax.Ast.AExprReversableOp' ends in one too, is
-      -- unbounded — placed there bare, it would greedily re-absorb whatever
+      -- unbounded - placed there bare, it would greedily re-absorb whatever
       -- follows on reparse (e.g. rendering @SymbolicBinOpAExpr (NotAExpr x)
       -- op y@ plainly as @NOT x op y@ reparses as @NotAExpr (SymbolicBinOpAExpr
       -- x op y)@). Parenthesizing it, via the existing @'(' a_expr ')'@
@@ -161,10 +161,10 @@
       -- The @d@ operand of a @LIKE@\/@ILIKE@\/@SIMILAR TO@ production, when
       -- it has a trailing @ESCAPE@ clause of its own (@e@). Since @d@ is
       -- parsed via an unrestricted recursive @a_expr@, rendering it bare
-      -- when it's unbounded (see 'isBoundedAExprOperand') — e.g. a dangling
+      -- when it's unbounded (see 'isBoundedAExprOperand') - e.g. a dangling
       -- operator, or an escape-less 'VerbalExprBinOpAExpr' whose own greedy
       -- @optional escape@ check would otherwise swallow the text meant for
-      -- \*this* production's @ESCAPE@ — reparses differently. Bounded shapes
+      -- \*this* production's @ESCAPE@ - reparses differently. Bounded shapes
       -- (a column reference, a constant, an already-parenthesized
       -- expression, DEFAULT, …) always terminate cleanly and never need the
       -- extra parens, exactly like @renderOperand@'s left position.
@@ -175,7 +175,7 @@
           | otherwise -> TextBuilders.renderInParens (toTextBuilder settings d)
       -- Distinct from 'PostgresqlSyntax.Ast.AExprReversableOp'\'s own
       -- @toTextBuilder@ (which bakes in the "positive" @IS@\/@BETWEEN@\/@IN@
-      -- Parsers.keyword but not the negation) — this one threads the external
+      -- Parsers.keyword but not the negation) - this one threads the external
       -- @Bool@ (@NOT@) in, mirroring the pre-extraction top-level
       -- @aExprReversableOp@ renderer.
       renderAExprReversableOp a = \case
@@ -193,7 +193,7 @@
 
 -- |
 -- Parameterized over the 'PostgresqlSyntax.Ast.CExpr' parser embedded at the
--- base case — the only axis 'filteredParser' needs to customize (via
+-- base case - the only axis 'filteredParser' needs to customize (via
 -- 'PostgresqlSyntax.Ast.CExpr.customizedParser'). Every other occurrence of
 -- @a_expr@\/@b_expr@\/@select_with_parens@ in the grammar below uses the
 -- ordinary, unfiltered parsers, exactly as the pre-extraction
@@ -217,9 +217,9 @@
       asum
         [ overlapsSuffix settings a,
           do
-            Parsers.space1
+            Parsers.space
             b <- Parser.wrapToHead (parser settings)
-            Parsers.space1
+            Parsers.space
             c <- Parser.wrapToHead (parser settings)
             Parsers.space
             d <- Left <$> Parser.wrapToHead (parser settings) <|> Right <$> Parsers.inParens aExpr
@@ -288,7 +288,7 @@
 -- |
 -- The @OVERLAPS@ operator, as a suffix of an already parsed left operand.
 -- Reinterprets the already-parsed base 'AExpr' as a 'Row' rather than
--- speculatively parsing a @row@ on top of it — see the original
+-- speculatively parsing a @row@ on top of it - see the original
 -- @overlapsSuffix@ in the pre-extraction @PostgresqlSyntax.Parsing@ for the
 -- exponential-blowup rationale this avoids.
 overlapsSuffix :: Settings -> AExpr -> Parser AExpr
@@ -308,7 +308,7 @@
 
 -- |
 -- Whether the given 'AExpr' is safe to place in the left\/accumulator
--- position of a suffix production without parenthesizing it — see
+-- position of a suffix production without parenthesizing it - see
 -- @renderOperand@ in the 'IsAst' instance above for why that position is
 -- special. A shape is bounded when parsing it can never end in an
 -- unrestricted recursive @a_expr@ call, i.e. control is guaranteed to
@@ -320,14 +320,14 @@
 -- would re-absorb the suffix that follows (e.g. rendering
 -- @SymbolicBinOpAExpr (NotAExpr x) op y@ plainly as @NOT x op y@ reparses
 -- as @NotAExpr (SymbolicBinOpAExpr x op y)@). It is /not/ a general
--- terminator-keyword guard — it isn't a general-purpose mechanism against
+-- terminator-keyword guard - it isn't a general-purpose mechanism against
 -- an expression swallowing a keyword that terminates an enclosing
 -- production; the only shape that ever created that hazard by construction
 -- was the postfix @a_expr qual_Op@ production, which no longer exists here
 -- or in @references/gram.y@ (see gram.y:15985,15987; Postgres removed
 -- postfix operators in v14). It does incidentally get reused for that
 -- purpose in "PostgresqlSyntax.Ast.TargetEl" (to stop an @OrAExpr@'s right
--- operand from absorbing a following implicit alias) — that's just one
+-- operand from absorbing a following implicit alias) - that's just one
 -- call site's use of it, not evidence of general applicability.
 isBoundedAExprOperand :: AExpr -> Bool
 isBoundedAExprOperand = \case
@@ -378,7 +378,7 @@
 -- indirection-less @select_with_parens@: both parse @x = ANY ((select 1))@.
 -- @suffix@ tries the @select_with_parens@ alternative before the
 -- parenthesized @a_expr@ one (see the @d <- Left <$> ... <|> Right <$> ...@
--- line above), so that's always what the parser returns — never @Right@ —
+-- line above), so that's always what the parser returns - never @Right@ -
 -- making the latter non-canonical for this shape. Both 'arbitrary' and
 -- 'shrink' can otherwise construct it, which renders fine but parses back to
 -- a different, canonical value and so breaks the roundtrip property.
@@ -417,7 +417,7 @@
                   -- whenever there's an escape clause, an unbounded @d@ must
                   -- be pre-wrapped in parens so the generated value already
                   -- matches what parsing the (necessarily parenthesized)
-                  -- rendering reconstructs — the same rule 'safeAExprOperand'
+                  -- rendering reconstructs - the same rule 'safeAExprOperand'
                   -- applies for the left/accumulator position.
                   d <- case e of
                     Nothing -> Gens.downscale Qc.arbitrary
diff --git a/library-internal/PostgresqlSyntax/Ast/AExprReversableOp.hs b/library-internal/PostgresqlSyntax/Ast/AExprReversableOp.hs
--- a/library-internal/PostgresqlSyntax/Ast/AExprReversableOp.hs
+++ b/library-internal/PostgresqlSyntax/Ast/AExprReversableOp.hs
@@ -14,7 +14,7 @@
 
 -- |
 -- The part of the following productions that follows @a_expr [NOT]@ /
--- @b_expr [NOT]@ — the leading @IS@\/@NOT@ toggle itself is external to this
+-- @b_expr [NOT]@ - the leading @IS@\/@NOT@ toggle itself is external to this
 -- type (it lives alongside it, e.g. in @ReversableOpAExpr AExpr Bool
 -- AExprReversableOp@), mirroring how 'PostgresqlSyntax.Ast.VerbalExprBinOp'
 -- keeps @NOT_LA@ external. Only the @IS@\/@BETWEEN@\/@IN@ Parsers.keyword that's
diff --git a/library-internal/PostgresqlSyntax/Ast/BExpr.hs b/library-internal/PostgresqlSyntax/Ast/BExpr.hs
--- a/library-internal/PostgresqlSyntax/Ast/BExpr.hs
+++ b/library-internal/PostgresqlSyntax/Ast/BExpr.hs
@@ -44,8 +44,8 @@
 -- @
 --
 -- Unlike 'PostgresqlSyntax.Ast.AExpr', nothing customizes this parser's
--- @c_expr@\/identifier axis externally, so — despite also being a
--- recursion hub — it needs no @customizedParser@\/@filteredParser@ export.
+-- @c_expr@\/identifier axis externally, so - despite also being a
+-- recursion hub - it needs no @customizedParser@\/@filteredParser@ export.
 data BExpr
   = CExprBExpr CExpr
   | TypecastBExpr BExpr Typename
@@ -67,11 +67,11 @@
     IsOpBExpr a b c -> renderOperand a <> " " <> renderBExprIsOp b c
     where
       -- See 'PostgresqlSyntax.Ast.AExpr'\'s @renderOperand@ for the
-      -- rationale — same left\/accumulator-position hazard, mirrored here
+      -- rationale - same left\/accumulator-position hazard, mirrored here
       -- for 'BExpr'\'s own (smaller) suffix grammar. Unlike 'AExpr', there's
       -- no @'(' b_expr ')'@ production to fall back on, so parenthesizing
       -- reinterprets the operand as an @a_expr@ via
-      -- 'PostgresqlSyntax.Ast.CExpr'\'s @'(' a_expr ')'@ instead — still
+      -- 'PostgresqlSyntax.Ast.CExpr'\'s @'(' a_expr ')'@ instead - still
       -- valid, semantically-equivalent SQL, just not the same 'BExpr' shape
       -- on reparse (only relevant to hand-constructed values; the
       -- 'Qc.Arbitrary' instance below never generates an operand needing
@@ -115,7 +115,7 @@
 
 -- |
 -- Whether the given 'BExpr' is safe to place in the left\/accumulator
--- position of a suffix production without parenthesizing it — see
+-- position of a suffix production without parenthesizing it - see
 -- 'IsAst' 'BExpr'\'s @renderOperand@. Mirrors
 -- 'PostgresqlSyntax.Ast.AExpr.isBoundedAExprOperand'.
 isBoundedBExprOperand :: BExpr -> Bool
diff --git a/library-internal/PostgresqlSyntax/Ast/CExpr.hs b/library-internal/PostgresqlSyntax/Ast/CExpr.hs
--- a/library-internal/PostgresqlSyntax/Ast/CExpr.hs
+++ b/library-internal/PostgresqlSyntax/Ast/CExpr.hs
@@ -78,12 +78,12 @@
 
 -- |
 -- Parameterized over the @ColId@-like identifier parser used by the plain
--- 'ColumnrefCExpr' alternative — the one place 'PostgresqlSyntax.Ast.AExpr'
+-- 'ColumnrefCExpr' alternative - the one place 'PostgresqlSyntax.Ast.AExpr'
 -- \'s @filteredParser@ needs to customize. Every other alternative here
 -- (parenthesized expressions, @ARRAY@, @EXISTS@, function calls, ...) always
 -- uses the ordinary, unfiltered parsers for its nested @a_expr@\/
 -- @select_with_parens@\/etc, exactly as the pre-extraction
--- @customizedCExpr@\/@parenthesizedExprCExpr@ did — the filtering doesn't
+-- @customizedCExpr@\/@parenthesizedExprCExpr@ did - the filtering doesn't
 -- propagate past this one level.
 customizedParser :: Settings -> Parser Ident -> Parser CExpr
 customizedParser settings colIdParser =
@@ -175,7 +175,7 @@
 -- inner @a_expr@ is itself nothing but a bare, indirection-less
 -- @select_with_parens@: both parse @((select 1))@. 'customizedParser' tries
 -- the @select_with_parens@ alternative before @parenthesizedExprCExpr@, so
--- that's always what the parser returns — never 'InParensCExpr' — making
+-- that's always what the parser returns - never 'InParensCExpr' - making
 -- the latter non-canonical for this shape. Both 'arbitrary' and 'shrink' can
 -- otherwise construct it (shrinking the outer indirection to @Nothing@ is
 -- exactly how it arises), which renders fine but parses back to a
diff --git a/library-internal/PostgresqlSyntax/Ast/ConstCharacter.hs b/library-internal/PostgresqlSyntax/Ast/ConstCharacter.hs
--- a/library-internal/PostgresqlSyntax/Ast/ConstCharacter.hs
+++ b/library-internal/PostgresqlSyntax/Ast/ConstCharacter.hs
@@ -31,7 +31,7 @@
   shrink = Qc.genericShrink
 
   -- The length here is parsed via 'Parsers.decimal' (unsigned), so it must
-  -- never be negative — mirroring 'PostgresqlSyntax.Ast.IntervalSecond'\'s
+  -- never be negative - mirroring 'PostgresqlSyntax.Ast.IntervalSecond'\'s
   -- own @nonNegative@.
   arbitrary = ConstCharacter <$> arbitrary <*> Qc.oneof [pure Nothing, Just <$> nonNegativeInt64]
     where
diff --git a/library-internal/PostgresqlSyntax/Ast/ConstDatetime.hs b/library-internal/PostgresqlSyntax/Ast/ConstDatetime.hs
--- a/library-internal/PostgresqlSyntax/Ast/ConstDatetime.hs
+++ b/library-internal/PostgresqlSyntax/Ast/ConstDatetime.hs
@@ -54,7 +54,7 @@
   shrink = Qc.genericShrink
 
   -- The precision here is parsed via 'Parsers.decimal' (unsigned), so it
-  -- must never be negative — mirroring
+  -- must never be negative - mirroring
   -- 'PostgresqlSyntax.Ast.IntervalSecond'\'s own @nonNegative@.
   arbitrary =
     Qc.oneof
diff --git a/library-internal/PostgresqlSyntax/Ast/Fconst.hs b/library-internal/PostgresqlSyntax/Ast/Fconst.hs
--- a/library-internal/PostgresqlSyntax/Ast/Fconst.hs
+++ b/library-internal/PostgresqlSyntax/Ast/Fconst.hs
@@ -21,7 +21,7 @@
 instance Qc.Arbitrary Fconst where
   shrink = Qc.genericShrink
 
-  -- Parsed via 'Parsers.float' (unsigned — the sign, when present, is a
+  -- Parsed via 'Parsers.float' (unsigned - the sign, when present, is a
   -- separate unary @AExpr@\/@BExpr@ operator applied outside this type), so
   -- it must never be negative, mirroring
   -- 'PostgresqlSyntax.Ast.IntervalSecond'\'s own @nonNegative@.
diff --git a/library-internal/PostgresqlSyntax/Ast/FuncApplicationParams.hs b/library-internal/PostgresqlSyntax/Ast/FuncApplicationParams.hs
--- a/library-internal/PostgresqlSyntax/Ast/FuncApplicationParams.hs
+++ b/library-internal/PostgresqlSyntax/Ast/FuncApplicationParams.hs
@@ -73,7 +73,7 @@
       -- @func_arg_list ',' VARIADIC func_arg_expr@: one or more
       -- comma-separated 'FuncArgExpr's, where the final comma is
       -- immediately followed by (and the @VARIADIC@ Parsers.keyword itself consumed
-      -- by) the terminating branch — equivalent to the pre-extraction
+      -- by) the terminating branch - equivalent to the pre-extraction
       -- @sepEnd1 Parsers.commaSeparator (Parsers.keyword "variadic" <* space1) funcArgExpr@.
       listVariadicFuncApplicationParams = do
         argList <- Parser.wrapToHead argListEndingInVariadic
@@ -91,7 +91,7 @@
       -- A bare '*' char can also be the leading char of a longer operator
       -- token (e.g. "*#" in @foo(*# DEFAULT)@'s @PrefixQualOpAExpr@), so
       -- this only commits to the wildcard reading when no further op char
-      -- follows — otherwise it falls through to 'normalFuncApplicationParams',
+      -- follows - otherwise it falls through to 'normalFuncApplicationParams',
       -- which parses the '*' as the start of that operator instead.
       starFuncApplicationParams =
         Parsers.space
diff --git a/library-internal/PostgresqlSyntax/Ast/FuncConstArgs.hs b/library-internal/PostgresqlSyntax/Ast/FuncConstArgs.hs
--- a/library-internal/PostgresqlSyntax/Ast/FuncConstArgs.hs
+++ b/library-internal/PostgresqlSyntax/Ast/FuncConstArgs.hs
@@ -11,7 +11,7 @@
 
 -- |
 -- The parenthesized-argument-list part of a @func_name '(' func_arg_list
--- opt_sort_clause ')' Sconst@ 'PostgresqlSyntax.Ast.AexprConst' — rendered\/
+-- opt_sort_clause ')' Sconst@ 'PostgresqlSyntax.Ast.AexprConst' - rendered\/
 -- parsed without its enclosing parens, which belong to the caller.
 --
 -- ==== References
diff --git a/library-internal/PostgresqlSyntax/Ast/FuncExprCommonSubexpr.hs b/library-internal/PostgresqlSyntax/Ast/FuncExprCommonSubexpr.hs
--- a/library-internal/PostgresqlSyntax/Ast/FuncExprCommonSubexpr.hs
+++ b/library-internal/PostgresqlSyntax/Ast/FuncExprCommonSubexpr.hs
@@ -167,7 +167,7 @@
             [ CollationForFuncExprCommonSubexpr <$> Gens.downscale Qc.arbitrary,
               pure CurrentDateFuncExprCommonSubexpr,
               -- The @Iconst@ here is parsed via 'Parsers.decimal' (unsigned), so
-              -- it must never be negative — mirroring
+              -- it must never be negative - mirroring
               -- 'PostgresqlSyntax.Ast.IntervalSecond'\'s own @nonNegative@.
               CurrentTimeFuncExprCommonSubexpr <$> nonNegativeMaybeInt64,
               CurrentTimestampFuncExprCommonSubexpr <$> nonNegativeMaybeInt64,
diff --git a/library-internal/PostgresqlSyntax/Ast/GroupClause.hs b/library-internal/PostgresqlSyntax/Ast/GroupClause.hs
--- a/library-internal/PostgresqlSyntax/Ast/GroupClause.hs
+++ b/library-internal/PostgresqlSyntax/Ast/GroupClause.hs
@@ -17,7 +17,7 @@
 --   |  /*EMPTY*/
 -- @
 --
--- @set_quantifier@ (@DISTINCT@\/@ALL@) is not modeled here — this
+-- @set_quantifier@ (@DISTINCT@\/@ALL@) is not modeled here - this
 -- codebase's grammar subset doesn't support @GROUP BY DISTINCT@.
 newtype GroupClause = GroupClause (NonEmpty GroupByItem)
   deriving (Show, Generic, Eq, Ord, Data)
diff --git a/library-internal/PostgresqlSyntax/Ast/Ident.hs b/library-internal/PostgresqlSyntax/Ast/Ident.hs
--- a/library-internal/PostgresqlSyntax/Ast/Ident.hs
+++ b/library-internal/PostgresqlSyntax/Ast/Ident.hs
@@ -39,7 +39,7 @@
 -- @
 --
 -- Most grammar positions that hold an identifier (column\/table\/alias
--- names, ...) are actually @ColId@, not bare @IDENT@ — this is the
+-- names, ...) are actually @ColId@, not bare @IDENT@ - this is the
 -- permissive variant that most 'Ident'-typed fields elsewhere in
 -- "PostgresqlSyntax.Ast" should parse with, since 'Ident'\'s own generic
 -- 'parser' only accepts the strict @IDENT@ token (no Parsers.keyword fallback).
diff --git a/library-internal/PostgresqlSyntax/Ast/ImplicitRow.hs b/library-internal/PostgresqlSyntax/Ast/ImplicitRow.hs
--- a/library-internal/PostgresqlSyntax/Ast/ImplicitRow.hs
+++ b/library-internal/PostgresqlSyntax/Ast/ImplicitRow.hs
@@ -25,7 +25,7 @@
 
   -- Parses the shared @a_expr@ once and then decides, from what follows,
   -- whether it's the sole element of the leading 'ExprList' or the trailing
-  -- @a_expr@ — see 'PostgresqlSyntax.Extras.NonEmpty.consAndUnsnoc'.
+  -- @a_expr@ - see 'PostgresqlSyntax.Extras.NonEmpty.consAndUnsnoc'.
   parser settings = Parsers.inParens $ do
     a <- Parser.wrapToHead (parser settings)
     Parsers.commaSeparator
diff --git a/library-internal/PostgresqlSyntax/Ast/JoinedTable.hs b/library-internal/PostgresqlSyntax/Ast/JoinedTable.hs
--- a/library-internal/PostgresqlSyntax/Ast/JoinedTable.hs
+++ b/library-internal/PostgresqlSyntax/Ast/JoinedTable.hs
@@ -35,7 +35,7 @@
 
 -- |
 -- Parsing delegates to 'parseExtended' over the 'Extends' instance
--- below — a bare @table_ref@ parse is greedy, absorbing any trailing @CROSS
+-- below - a bare @table_ref@ parse is greedy, absorbing any trailing @CROSS
 -- JOIN@\/@JOIN@\/@NATURAL JOIN@ continuation into itself, so a
 -- @joined_table@ is never reachable as a bare, zero-extension 'TableRef';
 -- it always needs at least one. Failing that, the only remaining
@@ -57,7 +57,7 @@
 --   | '(' joined_table ')'
 -- @
 --
--- It still recurses — just not on the left, since the opening parenthesis
+-- It still recurses - just not on the left, since the opening parenthesis
 -- has to be consumed first. "PostgresqlSyntax.Ast.TableRef" reaches it
 -- through this class method, which is why 'JoinedTable' needs no helper
 -- export.
@@ -84,7 +84,7 @@
 -- 'TableRef' is the non-recursive base (@β@, its own 'parseBase'). All
 -- three join kinds sit at the same precedence (@%left JOIN CROSS LEFT FULL
 -- RIGHT INNER_P NATURAL@ in @gram.y@), and there's nothing to hold between
--- parsing a join and applying it, so no item type is warranted here —
+-- parsing a join and applying it, so no item type is warranted here -
 -- unlike "PostgresqlSyntax.Ast.SimpleSelect", this hub isn't collect-then-fold.
 instance Extends TableRef JoinedTable where
   -- ==== References
diff --git a/library-internal/PostgresqlSyntax/Ast/Numeric.hs b/library-internal/PostgresqlSyntax/Ast/Numeric.hs
--- a/library-internal/PostgresqlSyntax/Ast/Numeric.hs
+++ b/library-internal/PostgresqlSyntax/Ast/Numeric.hs
@@ -83,7 +83,7 @@
         pure BigintNumeric,
         pure RealNumeric,
         -- The @Iconst@ here is parsed via 'Parsers.decimal' (unsigned), so,
-        -- unlike a plain 'Int64', it must never be negative — mirroring
+        -- unlike a plain 'Int64', it must never be negative - mirroring
         -- 'PostgresqlSyntax.Ast.IntervalSecond'\'s own @nonNegative@.
         FloatNumeric <$> Qc.oneof [pure Nothing, Just <$> nonNegativeInt64],
         pure DoublePrecisionNumeric,
diff --git a/library-internal/PostgresqlSyntax/Ast/ReturningClause.hs b/library-internal/PostgresqlSyntax/Ast/ReturningClause.hs
--- a/library-internal/PostgresqlSyntax/Ast/ReturningClause.hs
+++ b/library-internal/PostgresqlSyntax/Ast/ReturningClause.hs
@@ -16,7 +16,7 @@
 -- @
 --
 -- @returning_with_clause@ (the @WITH (...)@ modifier) is not modeled
--- here — not supported by this codebase's grammar subset.
+-- here - not supported by this codebase's grammar subset.
 newtype ReturningClause = ReturningClause TargetList
   deriving (Show, Generic, Eq, Ord, Data)
 
diff --git a/library-internal/PostgresqlSyntax/Ast/SelectClause.hs b/library-internal/PostgresqlSyntax/Ast/SelectClause.hs
--- a/library-internal/PostgresqlSyntax/Ast/SelectClause.hs
+++ b/library-internal/PostgresqlSyntax/Ast/SelectClause.hs
@@ -16,7 +16,7 @@
 -- @
 --
 -- This type's own 'IsAst' instance is a plain, non-recursive-suffix-aware
--- dispatch — the real @UNION@\/@INTERSECT@\/@EXCEPT@-chaining grammar
+-- dispatch - the real @UNION@\/@INTERSECT@\/@EXCEPT@-chaining grammar
 -- (where a @select_clause@ extends into a bigger
 -- 'PostgresqlSyntax.Ast.SimpleSelect' via its @BinSimpleSelect@
 -- constructor) is hosted in "PostgresqlSyntax.Ast.SimpleSelect" instead,
@@ -34,7 +34,7 @@
 
   -- ==== Law
   --
-  -- @parser = parseMaybeExtended \@SelectClause@ — see
+  -- @parser = parseMaybeExtended \@SelectClause@ - see
   -- 'PostgresqlSyntax.Ast.SimpleSelect'\'s 'PostgresqlSyntax.Algebra.Extends'
   -- instance for the real @select_clause@ grammar, including
   -- @UNION@\/@INTERSECT@\/@EXCEPT@-chaining.
diff --git a/library-internal/PostgresqlSyntax/Ast/SelectFetchFirstValue.hs b/library-internal/PostgresqlSyntax/Ast/SelectFetchFirstValue.hs
--- a/library-internal/PostgresqlSyntax/Ast/SelectFetchFirstValue.hs
+++ b/library-internal/PostgresqlSyntax/Ast/SelectFetchFirstValue.hs
@@ -44,7 +44,7 @@
   -- The magnitude is parsed via unsigned 'Parser.decimal'\/'Fconst' (the
   -- sign is this type's own separate @Bool@ field), so, like
   -- 'PostgresqlSyntax.Ast.IntervalSecond'\'s @nonNegative@, it must never be
-  -- negative itself — otherwise e.g. @NumSelectFetchFirstValue True (Left
+  -- negative itself - otherwise e.g. @NumSelectFetchFirstValue True (Left
   -- (-1))@ renders as @-1@ with no space (a valid unsigned-magnitude
   -- rendering would be @- 1@ or just @-1@ for magnitude 1), doubling up
   -- into @--1@, which reparses as a line comment.
diff --git a/library-internal/PostgresqlSyntax/Ast/SelectNoParens.hs b/library-internal/PostgresqlSyntax/Ast/SelectNoParens.hs
--- a/library-internal/PostgresqlSyntax/Ast/SelectNoParens.hs
+++ b/library-internal/PostgresqlSyntax/Ast/SelectNoParens.hs
@@ -77,8 +77,8 @@
 
 -- |
 -- If a 'SelectNoParens' is merely a trivial wrapper around a single
--- parenthesized select — no with-clause, sort, limit or locking clause of
--- its own — returns the wrapped 'SelectWithParens'. Used by the
+-- parenthesized select - no with-clause, sort, limit or locking clause of
+-- its own - returns the wrapped 'SelectWithParens'. Used by the
 -- 'Refines' instance to canonicalize such wrappers.
 refineToSelectWithParens :: SelectNoParens -> Maybe SelectWithParens
 refineToSelectWithParens = \case
diff --git a/library-internal/PostgresqlSyntax/Ast/SelectStmt.hs b/library-internal/PostgresqlSyntax/Ast/SelectStmt.hs
--- a/library-internal/PostgresqlSyntax/Ast/SelectStmt.hs
+++ b/library-internal/PostgresqlSyntax/Ast/SelectStmt.hs
@@ -32,7 +32,7 @@
   -- @NoParensSelectStmt@'s alternative is tried first, and
   -- 'PostgresqlSyntax.Ast.SelectClause' (reachable from any
   -- @select_no_parens@ with every other clause absent) always accepts a
-  -- parenthesized select too — so any @'(' select ')'@ text always parses
+  -- parenthesized select too - so any @'(' select ')'@ text always parses
   -- as @NoParensSelectStmt (SelectNoParens Nothing (WithParensSelectClause
   -- _) Nothing Nothing Nothing)@, never as a bare @WithParensSelectStmt@.
   -- Generating the latter would therefore never round-trip.
diff --git a/library-internal/PostgresqlSyntax/Ast/SimpleSelect.hs b/library-internal/PostgresqlSyntax/Ast/SimpleSelect.hs
--- a/library-internal/PostgresqlSyntax/Ast/SimpleSelect.hs
+++ b/library-internal/PostgresqlSyntax/Ast/SimpleSelect.hs
@@ -44,7 +44,7 @@
 --
 -- Hosts the real @select_clause@ grammar (including its
 -- @UNION@\/@INTERSECT@\/@EXCEPT@-chaining) for both itself and
--- "PostgresqlSyntax.Ast.SelectNoParens", which shares it — see
+-- "PostgresqlSyntax.Ast.SelectNoParens", which shares it - see
 -- 'PostgresqlSyntax.Ast.SelectClause'\'s module documentation for why.
 data SimpleSelect
   = NormalSimpleSelect (Maybe Targeting) (Maybe IntoClause) (Maybe FromClause) (Maybe WhereClause) (Maybe GroupClause) (Maybe HavingClause) (Maybe WindowClause)
@@ -72,19 +72,19 @@
 
   -- ==== Law
   --
-  -- @parser = parseExtended \@SelectClause \<|\> baseSimpleSelect@ — a bare
+  -- @parser = parseExtended \@SelectClause \<|\> baseSimpleSelect@ - a bare
   -- 'SimpleSelect' is either a @select_clause@ chain of at least one
   -- @UNION@\/@INTERSECT@\/@EXCEPT@ (see 'Extends' below), or, failing
   -- that (no continuation follows), one of the non-chain base cases; it's
   -- never a bare, zero-extension @select_clause@ (that's not a
-  -- 'SimpleSelect' at all — see 'SelectClause'). The chain alternative has
+  -- 'SimpleSelect' at all - see 'SelectClause'). The chain alternative has
   -- to come first: trying 'baseSimpleSelect' alone would succeed on just
   -- the head of a chain and never look for what follows.
   parser settings = parseExtended @SelectClause settings <|> parseBase settings
 
 -- |
 -- The @simple_select@ productions that don't left-recurse through
--- @select_clause@ — i.e. everything but @select_clause BINOP
+-- @select_clause@ - i.e. everything but @select_clause BINOP
 -- select_clause@. "PostgresqlSyntax.Ast.SelectClause" reaches these
 -- through this class method, which is why 'SimpleSelect' needs no helper
 -- export.
@@ -119,14 +119,14 @@
 -- 'SelectBinOp' plus its @ALL@\/@DISTINCT@ qualifier and right operand,
 -- applied via 'BinSimpleSelect'.
 --
--- Keeps the collect-then-fold shape — parsing every 'SelectChainLink' up
--- front via 'parseExtensionChain', then folding via 'foldChain' — rather
+-- Keeps the collect-then-fold shape - parsing every 'SelectChainLink' up
+-- front via 'parseExtensionChain', then folding via 'foldChain' - rather
 -- than folding as it goes, because this hub's items aren't all one
 -- precedence level: @gram.y@ declares @%left UNION EXCEPT@ before (i.e.
 -- binding looser than) @%left INTERSECT@ (gram.y:813-814), both
 -- left-associative, so a uniform left-to-right fold-as-you-parse would
 -- root @a INTERSECT b UNION c@ at @INTERSECT@ and nest @a EXCEPT b EXCEPT
--- c@ to the right — both wrong. 'foldChain' needs the whole flat sequence
+-- c@ to the right - both wrong. 'foldChain' needs the whole flat sequence
 -- in hand to sort that out; see its own docs above.
 instance Extends SelectClause SimpleSelect where
   parseExtensions settings lhs = foldChain lhs <$> parseLinks settings
@@ -147,18 +147,18 @@
 -- |
 -- ==== The precedence fold
 --
--- @go@ applies items to the accumulator one at a time, left to right —
+-- @go@ applies items to the accumulator one at a time, left to right -
 -- which by itself is already left-associative for a run of same-operator
 -- items, INTERSECT included. What needs help is a /low-precedence/ item
 -- (@UNION@\/@EXCEPT@) immediately followed by @INTERSECT@ items: those
 -- bind tighter, so they must combine into that item's right operand
 -- before @go@ applies it, not become separate steps of @go@'s own fold.
--- @absorbIntersect@ does exactly that — and only that: it leaves an
+-- @absorbIntersect@ does exactly that - and only that: it leaves an
 -- @INTERSECT@ item itself untouched (its rest is handled by @go@'s next
 -- iteration, one item at a time), and otherwise absorbs a maximal
 -- trailing run of @INTERSECT@ items into the current item's right
 -- operand. @go@ then continues from whatever @absorbIntersect@ left
--- unconsumed, and either finishes (if nothing's left — the whole point of
+-- unconsumed, and either finishes (if nothing's left - the whole point of
 -- ending on 'applyLink' rather than wrapping it back into a
 -- @SelectClause@ is that the final combination must be the returned
 -- @SimpleSelect@) or continues.
@@ -205,7 +205,7 @@
 -- |
 -- Collapses an arbitrary-shaped @BinSimpleSelect@ chain to the shape
 -- 'foldChain' actually produces for it (left-associated within each
--- precedence level, @INTERSECT@ binding tighter than @UNION@\/@EXCEPT@ —
+-- precedence level, @INTERSECT@ binding tighter than @UNION@\/@EXCEPT@ -
 -- see 'foldChain' above): 'flattenChain' reduces the chain to its flat
 -- sequence of operators and operands regardless of how it's currently
 -- nested, and re-folding that sequence with the same 'foldChain' the
@@ -223,7 +223,7 @@
 -- |
 -- Reduces a @BinSimpleSelect@ chain, in whatever shape it's currently
 -- nested, to its leading operand and the flat, left-to-right sequence of
--- 'SelectChainLink' items that follow it — the inverse of 'foldChain'.
+-- 'SelectChainLink' items that follow it - the inverse of 'foldChain'.
 flattenChain :: SelectClause -> (SelectClause, [SelectChainLink])
 flattenChain (SimpleSelectSelectClause (BinSimpleSelect op lhs distinct rhs)) =
   let (lhsHead, lhsRest) = flattenChain lhs
diff --git a/library-internal/PostgresqlSyntax/Helpers/Parsers.hs b/library-internal/PostgresqlSyntax/Helpers/Parsers.hs
--- a/library-internal/PostgresqlSyntax/Helpers/Parsers.hs
+++ b/library-internal/PostgresqlSyntax/Helpers/Parsers.hs
@@ -214,7 +214,7 @@
 
 -- |
 -- A ColId-like identifier parser (unreserved keyword ∪ col-name keyword)
--- restricted to exclude the given reserved words — needed wherever a
+-- restricted to exclude the given reserved words - needed wherever a
 -- trailing bare word must terminate a construct instead of being consumed
 -- as an identifier. Its only caller is
 -- 'PostgresqlSyntax.Ast.RelationExprOptAlias', which excludes @SET@ only in
diff --git a/library-internal/PostgresqlSyntax/Prelude.hs b/library-internal/PostgresqlSyntax/Prelude.hs
--- a/library-internal/PostgresqlSyntax/Prelude.hs
+++ b/library-internal/PostgresqlSyntax/Prelude.hs
@@ -2,7 +2,6 @@
   ( module Exports,
     suffixRec,
     extendMany,
-    Parser,
   )
 where
 
@@ -65,7 +64,6 @@
 import GHC.Exts as Exports (IsList (Item, fromList), groupWith, inline, lazy, sortWith)
 import GHC.Generics as Exports (Generic, Generic1)
 import GHC.IO.Exception as Exports
-import qualified HeadedMegaparsec
 import Numeric as Exports
 import Prelude as Exports hiding (all, and, any, concat, concatMap, elem, fail, foldl, foldl1, foldr, foldr1, id, mapM, mapM_, maximum, minimum, notElem, or, product, sequence, sequence_, sum, (.))
 import System.Environment as Exports
@@ -95,5 +93,3 @@
       optional (attempt state) >>= \case
         Nothing -> pure state
         Just newState -> loop newState
-
-type Parser = HeadedMegaparsec.HeadedParsec Void Text
diff --git a/library-internal/PostgresqlSyntax/Settings.hs b/library-internal/PostgresqlSyntax/Settings.hs
--- a/library-internal/PostgresqlSyntax/Settings.hs
+++ b/library-internal/PostgresqlSyntax/Settings.hs
@@ -36,7 +36,7 @@
 
 -- |
 -- Resolve the nullability-marker option to its effective value, defaulting to
--- @False@ (standard Postgres). Internal — used at parse\/render sites, not
+-- @False@ (standard Postgres). Internal - used at parse\/render sites, not
 -- re-exported from the "PostgresqlSyntax" facade.
 resolveNullabilityMarkers :: Settings -> Bool
 resolveNullabilityMarkers = fromMaybe False . optNullabilityMarkers
diff --git a/nesting-bench/Main.hs b/nesting-bench/Main.hs
--- a/nesting-bench/Main.hs
+++ b/nesting-bench/Main.hs
@@ -24,7 +24,7 @@
 nestedParens n =
   Text.replicate n "(" <> "a + b" <> Text.replicate n ")"
 
--- | Case 2: the user-reported shape — a sum of @COALESCE@ terms, split into
+-- | Case 2: the user-reported shape - a sum of @COALESCE@ terms, split into
 -- two parenthesised groups subtracted from one another, wrapped in a few
 -- redundant parentheses.
 coalesceSum :: Int -> Int -> Text
diff --git a/postgresql-syntax.cabal b/postgresql-syntax.cabal
--- a/postgresql-syntax.cabal
+++ b/postgresql-syntax.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name: postgresql-syntax
-version: 0.5.0.2
+version: 0.5.0.3
 category: Database, PostgreSQL, Parsing
 synopsis: PostgreSQL AST parsing and rendering
 description:
