-- | Machinery for deciding whether an expression needs to be wrapped in parentheses or not.

module Text.Fixity
    ( Precedence
    , Associativity (..)
    , FixityOver (..)
    , Fixity
    , Direction (..)
    , RenderContextOver (..)
    , RenderContext
    , encloseIn
    , botFixity
    , juxtFixity
    , unitFixity
    , topFixity
    , botRenderContext
    , topRenderContext
    ) where

import Text.Fixity.Internal

-- | Fractional precedence, so that it's always possible to squeeze an operator precedence between
-- two existing precedences. Ranges over @[-20, 120]@. A normal operator should have a precedence
-- within @[0, 100)@. It might be useful to have a negative precedence if you're trying to model
-- some already existing system, for example in Haskell @($)@ has precedence @0@, but clearly
-- @if b then y else f $ x@ should be rendered without any parens, hence the precedence of
-- @if_then_else_@ is less than 0, i.e. negative.
--
-- The precedence of juxtaposition is @100@. Normally you want juxtaposition to have the highest
-- precedence, but some languages have operators that bind tighter than juxtaposition, e.g.
-- Haskell's postfix @_{_}@: @f z { x = y }@ means @f (z {x = y})@.
type Precedence = Double

-- | 'FixityOver' instantiated at 'Precedence'.
type Fixity = FixityOver Precedence

-- | 'FixityOver' instantiated at 'Precedence'.
type RenderContext = RenderContextOver Precedence

-- | A fixity with the lowest precedence.
-- When used as a part of an outer context, never causes addition of parens.
botFixity :: Fixity
botFixity :: Fixity
botFixity = Associativity -> Precedence -> Fixity
forall prec. Associativity -> prec -> FixityOver prec
Fixity Associativity
NonAssociative (-Precedence
20)

-- | The fixity of juxtaposition.
juxtFixity :: Fixity
juxtFixity :: Fixity
juxtFixity = Associativity -> Precedence -> Fixity
forall prec. Associativity -> prec -> FixityOver prec
Fixity Associativity
LeftAssociative Precedence
100

-- | The fixity of a unitary expression which is safe to render
-- without parens in any context.
unitFixity :: Fixity
unitFixity :: Fixity
unitFixity = Associativity -> Precedence -> Fixity
forall prec. Associativity -> prec -> FixityOver prec
Fixity Associativity
NonAssociative Precedence
110

-- | A fixity with the highest precedence.
-- When used as a part of an outer context, always causes addition of parens.
topFixity :: Fixity
topFixity :: Fixity
topFixity = Associativity -> Precedence -> Fixity
forall prec. Associativity -> prec -> FixityOver prec
Fixity Associativity
NonAssociative Precedence
120

-- | An initial 'RenderContext'.
-- An expression printed in this context never gets enclosed in parens.
botRenderContext :: RenderContext
botRenderContext :: RenderContext
botRenderContext = Direction -> Fixity -> RenderContext
forall prec. Direction -> FixityOver prec -> RenderContextOver prec
RenderContext Direction
ToTheRight Fixity
botFixity

-- | An initial 'RenderContext'.
-- An expression printed in this context always gets enclosed in parens.
topRenderContext :: RenderContext
topRenderContext :: RenderContext
topRenderContext = Direction -> Fixity -> RenderContext
forall prec. Direction -> FixityOver prec -> RenderContextOver prec
RenderContext Direction
ToTheRight Fixity
topFixity