{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeSynonymInstances #-}

{-
    BNF Converter: Abstract syntax
    Copyright (C) 2004  Author:  Markus Forsberg, Michael Pellauer, Aarne Ranta

-}

module BNFC.CF (
            -- Types.
            CF,
            CFG(..),
            Rule, Rul(..), npRule, valCat, lookupRule, InternalRule(..),
            Pragma(..),
            Exp(..),
            Base(..), Type(..), Signature,
            Literal,
            Symbol,
            KeyWord,
            Position(..), noPosition, prettyPosition, npIdentifier,
            WithPosition(..), blendInPosition,
            RString, RCat,
            Cat(..), strToCat, catToStr,
            BaseCat, TokenCat,
            catString, catInteger, catDouble, catChar, catIdent,
            NonTerminal, SentForm,
            Fun, RFun, IsFun(..),
            Data,           -- describes the abstract syntax of a grammar
            cf2data,        -- translates a grammar to a Data object.
            cf2dataLists,   -- translates to a Data with List categories included.
            getAbstractSyntax,
            -- Literal categories, constants,
            firstEntry,     -- the first entry or the first value category
            baseTokenCatNames,  -- "Char", "Double", "Integer", "String"
            specialCats,    -- ident
            specialCatsP,   -- all literals
            specialData,    -- special data
            isCoercion,     -- wildcards in grammar (avoid syntactic clutter)
            isDefinedRule,  -- defined rules (allows syntactic sugar)
            isProperLabel,  -- not coercion or defined rule
            allCats,        -- all categories of a grammar
            allParserCats, allParserCatsNorm,
            reallyAllCats,
            allCatsNorm,
            allCatsIdNorm,
            allEntryPoints,
            reservedWords,
            cfTokens,
            literals,
            findAllReversibleCats, -- find all reversible categories
            identCat,       -- transforms '[C]' to ListC (others, unchanged).
            isParsable,
            rulesForCat,    -- rules for a given category
            rulesForNormalizedCat,    -- rules for a given category
            ruleGroups,     -- Categories are grouped with their rules.
            ruleGroupsInternals, --As above, but includes internal cats.
            allNames,        -- Checking for non-unique names, like @Name. Name ::= Ident;@.
            filterNonUnique,
            isList,         -- Checks if a category is a list category.
            isTokenCat, maybeTokenCat,
            baseCat,
            sameCat,
            -- Information functions for list functions.
            isNilFun,       -- empty list function? ([])
            isOneFun,       -- one element list function? (:[])
            hasOneFunc,
            getCons,
            getSeparatorByPrecedence,
            isConsFun,      -- constructor function? (:)
            isNilCons,      -- either three of above?
            isEmptyListCat, -- checks if the list permits []
            revSepListRule, -- reverse a rule, if it is of form C t [C].
            normCat,
            isDataCat, isDataOrListCat,
            normCatOfList,  -- Removes precendence information and enclosed List. C1 => C, C2 => C
            catOfList,
            comments,       -- translates the pragmas into two list containing the s./m. comments
            numberOfBlockCommentForms,
            tokenPragmas,   -- get the user-defined regular expression tokens
            tokenNames,     -- get the names of all user-defined tokens
            precCat,        -- get the precendence level of a Cat C1 => 1, C => 0
            precRule,       -- get the precendence level of the value category of a rule.
            isUsedCat,
            isPositionCat,
            hasPositionTokens,
            hasIdent, hasIdentLikeTokens,
            hasLayout,
            layoutPragmas,
            sigLookup      -- Get the type of a rule label.
           ) where

import Control.Monad (guard)
import Data.Char
import Data.Function (on)
import Data.List (nub, intersperse, sort, group, intercalate, find)
import qualified Data.List as List
import Data.List.NonEmpty (pattern (:|), (<|))
import qualified Data.List.NonEmpty as List1
import Data.Maybe
import Data.Map  (Map)
import qualified Data.Map as Map
import Data.Set  (Set)
import qualified Data.Set as Set
import Data.String  (IsString(..))

import BNFC.Abs (Reg())
import BNFC.Par (pCat)
import BNFC.Lex (tokens)
import qualified BNFC.Abs as Abs

import BNFC.Utils (spanEnd)

type List1 = List1.NonEmpty

-- | A context free grammar consists of a set of rules and some extended
-- information (e.g. pragmas, literals, symbols, keywords).

type CF = CFG RFun

-- | A rule consists of a function name, a main category and a sequence of
-- terminals and non-terminals.
--
-- @
--   function_name . Main_Cat ::= sequence
-- @

type Rule = Rul RFun

-- | Polymorphic rule type.

-- N.B.: Was originally made polymorphic for the sake of removed backend --profile.
data Rul function = Rule
  { Rul function -> function
funRule :: function
      -- ^ The function (semantic action) of a rule.
      --   In order to be able to generate data types this must be a constructor
      --   (or an identity function).
  , Rul function -> RCat
valRCat :: RCat
      -- ^ The value category, i.e., the defined non-terminal.
  , Rul function -> SentForm
rhsRule :: SentForm
      -- ^ The sentential form, i.e.,
      --   the list of (non)terminals in the right-hand-side of a rule.
  , Rul function -> InternalRule
internal :: InternalRule
      -- ^ Is this an "internal" rule only for the AST and printing,
      --   not for parsing?
  } deriving (Rul function -> Rul function -> Bool
(Rul function -> Rul function -> Bool)
-> (Rul function -> Rul function -> Bool) -> Eq (Rul function)
forall function.
Eq function =>
Rul function -> Rul function -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Rul function -> Rul function -> Bool
$c/= :: forall function.
Eq function =>
Rul function -> Rul function -> Bool
== :: Rul function -> Rul function -> Bool
$c== :: forall function.
Eq function =>
Rul function -> Rul function -> Bool
Eq, a -> Rul b -> Rul a
(a -> b) -> Rul a -> Rul b
(forall a b. (a -> b) -> Rul a -> Rul b)
-> (forall a b. a -> Rul b -> Rul a) -> Functor Rul
forall a b. a -> Rul b -> Rul a
forall a b. (a -> b) -> Rul a -> Rul b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Rul b -> Rul a
$c<$ :: forall a b. a -> Rul b -> Rul a
fmap :: (a -> b) -> Rul a -> Rul b
$cfmap :: forall a b. (a -> b) -> Rul a -> Rul b
Functor)

data InternalRule
  = Internal  -- ^ @internal@ rule (only for AST & printer)
  | Parsable  -- ^ ordinary rule (also for parser)
  deriving (InternalRule -> InternalRule -> Bool
(InternalRule -> InternalRule -> Bool)
-> (InternalRule -> InternalRule -> Bool) -> Eq InternalRule
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: InternalRule -> InternalRule -> Bool
$c/= :: InternalRule -> InternalRule -> Bool
== :: InternalRule -> InternalRule -> Bool
$c== :: InternalRule -> InternalRule -> Bool
Eq)

instance (Show function) => Show (Rul function) where
  show :: Rul function -> String
show (Rule function
f RCat
cat SentForm
rhs InternalRule
internal) = [String] -> String
unwords ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
    (if InternalRule
internal InternalRule -> InternalRule -> Bool
forall a. Eq a => a -> a -> Bool
== InternalRule
Internal then (String
"internal" String -> [String] -> [String]
forall a. a -> [a] -> [a]
:) else [String] -> [String]
forall a. a -> a
id) ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$
    function -> String
forall a. Show a => a -> String
show function
f String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String
"." String -> [String] -> [String]
forall a. a -> [a] -> [a]
: RCat -> String
forall a. Show a => a -> String
show RCat
cat String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String
"::=" String -> [String] -> [String]
forall a. a -> [a] -> [a]
: (Either Cat String -> String) -> SentForm -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ((Cat -> String) -> ShowS -> Either Cat String -> String
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Cat -> String
forall a. Show a => a -> String
show ShowS
forall a. a -> a
id) SentForm
rhs

-- | A sentential form is a sequence of non-terminals or terminals.
type SentForm = [Either Cat String]

-- | Type of context-free grammars (GFG).

data CFG function = CFG
    { CFG function -> [Pragma]
cfgPragmas        :: [Pragma]
    , CFG function -> Set Cat
cfgUsedCats       :: Set Cat    -- ^ Categories used by the parser.
    , CFG function -> [String]
cfgLiterals       :: [Literal]  -- ^ @Char, String, Ident, Integer, Double@.
                                      --   @String@s are quoted strings,
                                      --   and @Ident@s are unquoted.
    , CFG function -> [String]
cfgSymbols        :: [Symbol]   -- ^ Symbols in the grammar, e.g. “*”, “->”.
    , CFG function -> [String]
cfgKeywords       :: [KeyWord]  -- ^ Reserved words, e.g. @if@, @while@.
    , CFG function -> [Cat]
cfgReversibleCats :: [Cat]      -- ^ Categories that can be made left-recursive.
    , CFG function -> [Rul function]
cfgRules          :: [Rul function]
    , CFG function -> Signature
cfgSignature      :: Signature  -- ^ Types of rule labels, computed from 'cfgRules'.
    } deriving (a -> CFG b -> CFG a
(a -> b) -> CFG a -> CFG b
(forall a b. (a -> b) -> CFG a -> CFG b)
-> (forall a b. a -> CFG b -> CFG a) -> Functor CFG
forall a b. a -> CFG b -> CFG a
forall a b. (a -> b) -> CFG a -> CFG b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> CFG b -> CFG a
$c<$ :: forall a b. a -> CFG b -> CFG a
fmap :: (a -> b) -> CFG a -> CFG b
$cfmap :: forall a b. (a -> b) -> CFG a -> CFG b
Functor)


instance (Show function) => Show (CFG function) where
  show :: CFG function -> String
show CFG{[String]
[Cat]
[Pragma]
[Rul function]
Signature
Set Cat
cfgSignature :: Signature
cfgRules :: [Rul function]
cfgReversibleCats :: [Cat]
cfgKeywords :: [String]
cfgSymbols :: [String]
cfgLiterals :: [String]
cfgUsedCats :: Set Cat
cfgPragmas :: [Pragma]
cfgSignature :: forall function. CFG function -> Signature
cfgRules :: forall function. CFG function -> [Rul function]
cfgReversibleCats :: forall function. CFG function -> [Cat]
cfgKeywords :: forall function. CFG function -> [String]
cfgSymbols :: forall function. CFG function -> [String]
cfgLiterals :: forall function. CFG function -> [String]
cfgUsedCats :: forall function. CFG function -> Set Cat
cfgPragmas :: forall function. CFG function -> [Pragma]
..} = [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (Rul function -> String) -> [Rul function] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Rul function -> String
forall a. Show a => a -> String
show [Rul function]
cfgRules

-- | Types of the rule labels, together with the position of the rule label.
type Signature = Map String (WithPosition Type)

-- | Type of a non-terminal.
data Base = BaseT String
          | ListT Base
    deriving (Base -> Base -> Bool
(Base -> Base -> Bool) -> (Base -> Base -> Bool) -> Eq Base
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Base -> Base -> Bool
$c/= :: Base -> Base -> Bool
== :: Base -> Base -> Bool
$c== :: Base -> Base -> Bool
Eq, Eq Base
Eq Base
-> (Base -> Base -> Ordering)
-> (Base -> Base -> Bool)
-> (Base -> Base -> Bool)
-> (Base -> Base -> Bool)
-> (Base -> Base -> Bool)
-> (Base -> Base -> Base)
-> (Base -> Base -> Base)
-> Ord Base
Base -> Base -> Bool
Base -> Base -> Ordering
Base -> Base -> Base
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Base -> Base -> Base
$cmin :: Base -> Base -> Base
max :: Base -> Base -> Base
$cmax :: Base -> Base -> Base
>= :: Base -> Base -> Bool
$c>= :: Base -> Base -> Bool
> :: Base -> Base -> Bool
$c> :: Base -> Base -> Bool
<= :: Base -> Base -> Bool
$c<= :: Base -> Base -> Bool
< :: Base -> Base -> Bool
$c< :: Base -> Base -> Bool
compare :: Base -> Base -> Ordering
$ccompare :: Base -> Base -> Ordering
$cp1Ord :: Eq Base
Ord)

-- | Type of a rule label.
data Type = FunT [Base] Base
    deriving (Type -> Type -> Bool
(Type -> Type -> Bool) -> (Type -> Type -> Bool) -> Eq Type
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Type -> Type -> Bool
$c/= :: Type -> Type -> Bool
== :: Type -> Type -> Bool
$c== :: Type -> Type -> Bool
Eq, Eq Type
Eq Type
-> (Type -> Type -> Ordering)
-> (Type -> Type -> Bool)
-> (Type -> Type -> Bool)
-> (Type -> Type -> Bool)
-> (Type -> Type -> Bool)
-> (Type -> Type -> Type)
-> (Type -> Type -> Type)
-> Ord Type
Type -> Type -> Bool
Type -> Type -> Ordering
Type -> Type -> Type
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Type -> Type -> Type
$cmin :: Type -> Type -> Type
max :: Type -> Type -> Type
$cmax :: Type -> Type -> Type
>= :: Type -> Type -> Bool
$c>= :: Type -> Type -> Bool
> :: Type -> Type -> Bool
$c> :: Type -> Type -> Bool
<= :: Type -> Type -> Bool
$c<= :: Type -> Type -> Bool
< :: Type -> Type -> Bool
$c< :: Type -> Type -> Bool
compare :: Type -> Type -> Ordering
$ccompare :: Type -> Type -> Ordering
$cp1Ord :: Eq Type
Ord)

instance Show Base where
    show :: Base -> String
show (BaseT String
x) = String
x
    show (ListT Base
t) = String
"[" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Base -> String
forall a. Show a => a -> String
show Base
t String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"]"

instance Show Type where
    show :: Type -> String
show (FunT [Base]
ts Base
t) = [String] -> String
unwords ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ (Base -> String) -> [Base] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Base -> String
forall a. Show a => a -> String
show [Base]
ts [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String
"->", Base -> String
forall a. Show a => a -> String
show Base
t]

-- | Expressions for function definitions.

data Exp
  = App String [Exp]  -- ^ (Possibly defined) label applied to expressions.
  | Var String        -- ^ Function parameter.
  | LitInt Integer
  | LitDouble Double
  | LitChar Char
  | LitString String
  deriving (Exp -> Exp -> Bool
(Exp -> Exp -> Bool) -> (Exp -> Exp -> Bool) -> Eq Exp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Exp -> Exp -> Bool
$c/= :: Exp -> Exp -> Bool
== :: Exp -> Exp -> Bool
$c== :: Exp -> Exp -> Bool
Eq)

instance Show Exp where
    showsPrec :: Int -> Exp -> ShowS
showsPrec Int
p Exp
e =
        case Exp -> Either Exp [Exp]
listView Exp
e of
            Right [Exp]
es    ->
                String -> ShowS
showString String
"["
                ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ShowS -> ShowS -> ShowS) -> ShowS -> [ShowS] -> ShowS
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.) ShowS
forall a. a -> a
id (ShowS -> [ShowS] -> [ShowS]
forall a. a -> [a] -> [a]
intersperse (String -> ShowS
showString String
", ") ([ShowS] -> [ShowS]) -> [ShowS] -> [ShowS]
forall a b. (a -> b) -> a -> b
$ (Exp -> ShowS) -> [Exp] -> [ShowS]
forall a b. (a -> b) -> [a] -> [b]
map Exp -> ShowS
forall a. Show a => a -> ShowS
shows [Exp]
es)
                ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ShowS
showString String
"]"
            Left (Var String
x)    -> String -> ShowS
showString String
x
            Left (App String
x []) -> String -> ShowS
showString String
x
            Left (App  String
"(:)" [Exp
e1,Exp
e2]) ->
                Bool -> ShowS -> ShowS
showParen (Int
pInt -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>Int
0)
                (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ Int -> Exp -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
1 Exp
e1
                ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ShowS
showString String
" : "
                ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Exp -> ShowS
forall a. Show a => a -> ShowS
shows Exp
e2
            Left (App String
x [Exp]
es) ->
                Bool -> ShowS -> ShowS
showParen (Int
pInt -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>Int
1)
                (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ (ShowS -> ShowS -> ShowS) -> ShowS -> [ShowS] -> ShowS
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.) ShowS
forall a. a -> a
id
                ([ShowS] -> ShowS) -> [ShowS] -> ShowS
forall a b. (a -> b) -> a -> b
$ ShowS -> [ShowS] -> [ShowS]
forall a. a -> [a] -> [a]
intersperse (String -> ShowS
showString String
" ")
                ([ShowS] -> [ShowS]) -> [ShowS] -> [ShowS]
forall a b. (a -> b) -> a -> b
$ String -> ShowS
showString String
x ShowS -> [ShowS] -> [ShowS]
forall a. a -> [a] -> [a]
: (Exp -> ShowS) -> [Exp] -> [ShowS]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Exp -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
2) [Exp]
es
            Left (LitInt Integer
n)     -> Integer -> ShowS
forall a. Show a => a -> ShowS
shows Integer
n
            Left (LitDouble Double
x)  -> Double -> ShowS
forall a. Show a => a -> ShowS
shows Double
x
            Left (LitChar Char
c)    -> Char -> ShowS
forall a. Show a => a -> ShowS
shows Char
c
            Left (LitString String
s)  -> String -> ShowS
forall a. Show a => a -> ShowS
shows String
s
        where
            listView :: Exp -> Either Exp [Exp]
listView (App String
"[]" []) = [Exp] -> Either Exp [Exp]
forall a b. b -> Either a b
Right []
            listView (App String
"(:)" [Exp
e1,Exp
e2])
                | Right [Exp]
es <- Exp -> Either Exp [Exp]
listView Exp
e2   = [Exp] -> Either Exp [Exp]
forall a b. b -> Either a b
Right ([Exp] -> Either Exp [Exp]) -> [Exp] -> Either Exp [Exp]
forall a b. (a -> b) -> a -> b
$ Exp
e1Exp -> [Exp] -> [Exp]
forall a. a -> [a] -> [a]
:[Exp]
es
            listView Exp
x = Exp -> Either Exp [Exp]
forall a b. a -> Either a b
Left Exp
x

-- | Pragmas.

data Pragma
  = CommentS  String              -- ^ for single line comments
  | CommentM (String, String)     -- ^  for multiple-line comments.
  | TokenReg RString Bool Reg     -- ^ for tokens
  | EntryPoints [RCat]
  | Layout [String]
  | LayoutStop [String]
  | LayoutTop
  | FunDef RFun [String] Exp
  deriving (Int -> Pragma -> ShowS
[Pragma] -> ShowS
Pragma -> String
(Int -> Pragma -> ShowS)
-> (Pragma -> String) -> ([Pragma] -> ShowS) -> Show Pragma
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Pragma] -> ShowS
$cshowList :: [Pragma] -> ShowS
show :: Pragma -> String
$cshow :: Pragma -> String
showsPrec :: Int -> Pragma -> ShowS
$cshowsPrec :: Int -> Pragma -> ShowS
Show)

-- | User-defined regular expression tokens
tokenPragmas :: CFG f -> [(TokenCat,Reg)]
tokenPragmas :: CFG f -> [(String, Reg)]
tokenPragmas CFG f
cf = [ (WithPosition String -> String
forall a. WithPosition a -> a
wpThing WithPosition String
name, Reg
e) | TokenReg WithPosition String
name Bool
_ Reg
e <- CFG f -> [Pragma]
forall function. CFG function -> [Pragma]
cfgPragmas CFG f
cf ]

-- | The names of all user-defined tokens.
tokenNames :: CFG f -> [String]
tokenNames :: CFG f -> [String]
tokenNames CFG f
cf = ((String, Reg) -> String) -> [(String, Reg)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, Reg) -> String
forall a b. (a, b) -> a
fst (CFG f -> [(String, Reg)]
forall f. CFG f -> [(String, Reg)]
tokenPragmas CFG f
cf)

layoutPragmas :: CF -> (Bool,[String],[String])
layoutPragmas :: CF -> (Bool, [String], [String])
layoutPragmas CF
cf = let ps :: [Pragma]
ps = CF -> [Pragma]
forall function. CFG function -> [Pragma]
cfgPragmas CF
cf in (
  Bool -> Bool
not ([()] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [() | Pragma
LayoutTop  <- [Pragma]
ps]),   -- if there's layout betw top-level
  [[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[String]
ss | Layout [String]
ss     <- [Pragma]
ps],    -- layout-block starting words
  [[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[String]
ss | LayoutStop [String]
ss <- [Pragma]
ps]     -- layout-block ending words
  )

hasLayout :: CF -> Bool
hasLayout :: CF -> Bool
hasLayout CF
cf = case CF -> (Bool, [String], [String])
layoutPragmas CF
cf of
  (Bool
t,[String]
ws,[String]
_) -> Bool
t Bool -> Bool -> Bool
|| Bool -> Bool
not ([String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
ws)   -- (True,[],_) means: top-level layout only

-- | Literal: builtin-token types Char, String, Ident, Integer, Double.
type Literal = String
type Symbol  = String
type KeyWord = String

------------------------------------------------------------------------------
-- Identifiers with position information
------------------------------------------------------------------------------

-- | Source positions.
data Position
  = NoPosition
  | Position
    { Position -> String
posFile    :: FilePath  -- ^ Name of the grammar file.
    , Position -> Int
posLine    :: Int       -- ^ Line in the grammar file.
    , Position -> Int
posColumn  :: Int       -- ^ Column in the grammar file.
    } deriving (Int -> Position -> ShowS
[Position] -> ShowS
Position -> String
(Int -> Position -> ShowS)
-> (Position -> String) -> ([Position] -> ShowS) -> Show Position
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Position] -> ShowS
$cshowList :: [Position] -> ShowS
show :: Position -> String
$cshow :: Position -> String
showsPrec :: Int -> Position -> ShowS
$cshowsPrec :: Int -> Position -> ShowS
Show, Position -> Position -> Bool
(Position -> Position -> Bool)
-> (Position -> Position -> Bool) -> Eq Position
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Position -> Position -> Bool
$c/= :: Position -> Position -> Bool
== :: Position -> Position -> Bool
$c== :: Position -> Position -> Bool
Eq, Eq Position
Eq Position
-> (Position -> Position -> Ordering)
-> (Position -> Position -> Bool)
-> (Position -> Position -> Bool)
-> (Position -> Position -> Bool)
-> (Position -> Position -> Bool)
-> (Position -> Position -> Position)
-> (Position -> Position -> Position)
-> Ord Position
Position -> Position -> Bool
Position -> Position -> Ordering
Position -> Position -> Position
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Position -> Position -> Position
$cmin :: Position -> Position -> Position
max :: Position -> Position -> Position
$cmax :: Position -> Position -> Position
>= :: Position -> Position -> Bool
$c>= :: Position -> Position -> Bool
> :: Position -> Position -> Bool
$c> :: Position -> Position -> Bool
<= :: Position -> Position -> Bool
$c<= :: Position -> Position -> Bool
< :: Position -> Position -> Bool
$c< :: Position -> Position -> Bool
compare :: Position -> Position -> Ordering
$ccompare :: Position -> Position -> Ordering
$cp1Ord :: Eq Position
Ord)

prettyPosition :: Position -> String
prettyPosition :: Position -> String
prettyPosition = \case
  Position
NoPosition -> String
""
  Position String
file Int
line Int
col -> String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
List.intercalate String
":" [ String
file, Int -> String
forall a. Show a => a -> String
show Int
line, Int -> String
forall a. Show a => a -> String
show Int
col, String
"" ]

data WithPosition a = WithPosition
  { WithPosition a -> Position
wpPosition :: Position
  , WithPosition a -> a
wpThing    :: a
  } deriving (Int -> WithPosition a -> ShowS
[WithPosition a] -> ShowS
WithPosition a -> String
(Int -> WithPosition a -> ShowS)
-> (WithPosition a -> String)
-> ([WithPosition a] -> ShowS)
-> Show (WithPosition a)
forall a. Show a => Int -> WithPosition a -> ShowS
forall a. Show a => [WithPosition a] -> ShowS
forall a. Show a => WithPosition a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [WithPosition a] -> ShowS
$cshowList :: forall a. Show a => [WithPosition a] -> ShowS
show :: WithPosition a -> String
$cshow :: forall a. Show a => WithPosition a -> String
showsPrec :: Int -> WithPosition a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> WithPosition a -> ShowS
Show, a -> WithPosition b -> WithPosition a
(a -> b) -> WithPosition a -> WithPosition b
(forall a b. (a -> b) -> WithPosition a -> WithPosition b)
-> (forall a b. a -> WithPosition b -> WithPosition a)
-> Functor WithPosition
forall a b. a -> WithPosition b -> WithPosition a
forall a b. (a -> b) -> WithPosition a -> WithPosition b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> WithPosition b -> WithPosition a
$c<$ :: forall a b. a -> WithPosition b -> WithPosition a
fmap :: (a -> b) -> WithPosition a -> WithPosition b
$cfmap :: forall a b. (a -> b) -> WithPosition a -> WithPosition b
Functor, WithPosition a -> Bool
(a -> m) -> WithPosition a -> m
(a -> b -> b) -> b -> WithPosition a -> b
(forall m. Monoid m => WithPosition m -> m)
-> (forall m a. Monoid m => (a -> m) -> WithPosition a -> m)
-> (forall m a. Monoid m => (a -> m) -> WithPosition a -> m)
-> (forall a b. (a -> b -> b) -> b -> WithPosition a -> b)
-> (forall a b. (a -> b -> b) -> b -> WithPosition a -> b)
-> (forall b a. (b -> a -> b) -> b -> WithPosition a -> b)
-> (forall b a. (b -> a -> b) -> b -> WithPosition a -> b)
-> (forall a. (a -> a -> a) -> WithPosition a -> a)
-> (forall a. (a -> a -> a) -> WithPosition a -> a)
-> (forall a. WithPosition a -> [a])
-> (forall a. WithPosition a -> Bool)
-> (forall a. WithPosition a -> Int)
-> (forall a. Eq a => a -> WithPosition a -> Bool)
-> (forall a. Ord a => WithPosition a -> a)
-> (forall a. Ord a => WithPosition a -> a)
-> (forall a. Num a => WithPosition a -> a)
-> (forall a. Num a => WithPosition a -> a)
-> Foldable WithPosition
forall a. Eq a => a -> WithPosition a -> Bool
forall a. Num a => WithPosition a -> a
forall a. Ord a => WithPosition a -> a
forall m. Monoid m => WithPosition m -> m
forall a. WithPosition a -> Bool
forall a. WithPosition a -> Int
forall a. WithPosition a -> [a]
forall a. (a -> a -> a) -> WithPosition a -> a
forall m a. Monoid m => (a -> m) -> WithPosition a -> m
forall b a. (b -> a -> b) -> b -> WithPosition a -> b
forall a b. (a -> b -> b) -> b -> WithPosition a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
product :: WithPosition a -> a
$cproduct :: forall a. Num a => WithPosition a -> a
sum :: WithPosition a -> a
$csum :: forall a. Num a => WithPosition a -> a
minimum :: WithPosition a -> a
$cminimum :: forall a. Ord a => WithPosition a -> a
maximum :: WithPosition a -> a
$cmaximum :: forall a. Ord a => WithPosition a -> a
elem :: a -> WithPosition a -> Bool
$celem :: forall a. Eq a => a -> WithPosition a -> Bool
length :: WithPosition a -> Int
$clength :: forall a. WithPosition a -> Int
null :: WithPosition a -> Bool
$cnull :: forall a. WithPosition a -> Bool
toList :: WithPosition a -> [a]
$ctoList :: forall a. WithPosition a -> [a]
foldl1 :: (a -> a -> a) -> WithPosition a -> a
$cfoldl1 :: forall a. (a -> a -> a) -> WithPosition a -> a
foldr1 :: (a -> a -> a) -> WithPosition a -> a
$cfoldr1 :: forall a. (a -> a -> a) -> WithPosition a -> a
foldl' :: (b -> a -> b) -> b -> WithPosition a -> b
$cfoldl' :: forall b a. (b -> a -> b) -> b -> WithPosition a -> b
foldl :: (b -> a -> b) -> b -> WithPosition a -> b
$cfoldl :: forall b a. (b -> a -> b) -> b -> WithPosition a -> b
foldr' :: (a -> b -> b) -> b -> WithPosition a -> b
$cfoldr' :: forall a b. (a -> b -> b) -> b -> WithPosition a -> b
foldr :: (a -> b -> b) -> b -> WithPosition a -> b
$cfoldr :: forall a b. (a -> b -> b) -> b -> WithPosition a -> b
foldMap' :: (a -> m) -> WithPosition a -> m
$cfoldMap' :: forall m a. Monoid m => (a -> m) -> WithPosition a -> m
foldMap :: (a -> m) -> WithPosition a -> m
$cfoldMap :: forall m a. Monoid m => (a -> m) -> WithPosition a -> m
fold :: WithPosition m -> m
$cfold :: forall m. Monoid m => WithPosition m -> m
Foldable, Functor WithPosition
Foldable WithPosition
Functor WithPosition
-> Foldable WithPosition
-> (forall (f :: * -> *) a b.
    Applicative f =>
    (a -> f b) -> WithPosition a -> f (WithPosition b))
-> (forall (f :: * -> *) a.
    Applicative f =>
    WithPosition (f a) -> f (WithPosition a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> WithPosition a -> m (WithPosition b))
-> (forall (m :: * -> *) a.
    Monad m =>
    WithPosition (m a) -> m (WithPosition a))
-> Traversable WithPosition
(a -> f b) -> WithPosition a -> f (WithPosition b)
forall (t :: * -> *).
Functor t
-> Foldable t
-> (forall (f :: * -> *) a b.
    Applicative f =>
    (a -> f b) -> t a -> f (t b))
-> (forall (f :: * -> *) a. Applicative f => t (f a) -> f (t a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> t a -> m (t b))
-> (forall (m :: * -> *) a. Monad m => t (m a) -> m (t a))
-> Traversable t
forall (m :: * -> *) a.
Monad m =>
WithPosition (m a) -> m (WithPosition a)
forall (f :: * -> *) a.
Applicative f =>
WithPosition (f a) -> f (WithPosition a)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> WithPosition a -> m (WithPosition b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> WithPosition a -> f (WithPosition b)
sequence :: WithPosition (m a) -> m (WithPosition a)
$csequence :: forall (m :: * -> *) a.
Monad m =>
WithPosition (m a) -> m (WithPosition a)
mapM :: (a -> m b) -> WithPosition a -> m (WithPosition b)
$cmapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> WithPosition a -> m (WithPosition b)
sequenceA :: WithPosition (f a) -> f (WithPosition a)
$csequenceA :: forall (f :: * -> *) a.
Applicative f =>
WithPosition (f a) -> f (WithPosition a)
traverse :: (a -> f b) -> WithPosition a -> f (WithPosition b)
$ctraverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> WithPosition a -> f (WithPosition b)
$cp2Traversable :: Foldable WithPosition
$cp1Traversable :: Functor WithPosition
Traversable)

-- | Ignore position in equality and ordering.
instance Eq  a => Eq  (WithPosition a) where == :: WithPosition a -> WithPosition a -> Bool
(==)    = a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(==)    (a -> a -> Bool)
-> (WithPosition a -> a)
-> WithPosition a
-> WithPosition a
-> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` WithPosition a -> a
forall a. WithPosition a -> a
wpThing
instance Ord a => Ord (WithPosition a) where compare :: WithPosition a -> WithPosition a -> Ordering
compare = a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (a -> a -> Ordering)
-> (WithPosition a -> a)
-> WithPosition a
-> WithPosition a
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` WithPosition a -> a
forall a. WithPosition a -> a
wpThing

noPosition :: a -> WithPosition a
noPosition :: a -> WithPosition a
noPosition = Position -> a -> WithPosition a
forall a. Position -> a -> WithPosition a
WithPosition Position
NoPosition

-- | A "ranged string" (terminology from Agda code base).
type RString = WithPosition String

-- | Prefix string with pretty-printed position information.
blendInPosition :: RString -> String
blendInPosition :: WithPosition String -> String
blendInPosition (WithPosition Position
pos String
msg)
  | String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
p    = String
msg
  | Bool
otherwise = [String] -> String
unwords [ String
p, String
msg ]
  where
  p :: String
p = Position -> String
prettyPosition Position
pos

type RCat    = WithPosition Cat

valCat :: Rul fun -> Cat
valCat :: Rul fun -> Cat
valCat = RCat -> Cat
forall a. WithPosition a -> a
wpThing (RCat -> Cat) -> (Rul fun -> RCat) -> Rul fun -> Cat
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rul fun -> RCat
forall function. Rul function -> RCat
valRCat

npRule :: Fun -> Cat -> SentForm -> InternalRule -> Rule
npRule :: String -> Cat -> SentForm -> InternalRule -> Rule
npRule String
f Cat
c SentForm
r InternalRule
internal = WithPosition String -> RCat -> SentForm -> InternalRule -> Rule
forall function.
function -> RCat -> SentForm -> InternalRule -> Rul function
Rule (String -> WithPosition String
forall a. a -> WithPosition a
noPosition String
f) (Cat -> RCat
forall a. a -> WithPosition a
noPosition Cat
c) SentForm
r InternalRule
internal

npIdentifier :: String -> Abs.Identifier
npIdentifier :: String -> Identifier
npIdentifier String
x = ((Int, Int), String) -> Identifier
Abs.Identifier ((Int
0, Int
0), String
x)

-- identifierName :: Identifier -> String
-- identifierName (Identifier (_, x)) = x

-- identifierPosition :: String -> Identifier -> Position
-- identifierPosition file (Identifier ((line, col), _)) = Position file line col

------------------------------------------------------------------------------
-- Categories
------------------------------------------------------------------------------

-- | Categories are the non-terminals of the grammar.
data Cat
  = Cat String               -- ^ Ordinary non-terminal.
  | TokenCat TokenCat        -- ^ Token types (like @Ident@, @Integer@, ..., user-defined).
  | ListCat Cat              -- ^ List non-terminals, e.g., @[Ident]@, @[Exp]@, @[Exp1]@.
  | CoercCat String Integer  -- ^ E.g. @Exp1@, @Exp2@.
  deriving (Cat -> Cat -> Bool
(Cat -> Cat -> Bool) -> (Cat -> Cat -> Bool) -> Eq Cat
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Cat -> Cat -> Bool
$c/= :: Cat -> Cat -> Bool
== :: Cat -> Cat -> Bool
$c== :: Cat -> Cat -> Bool
Eq, Eq Cat
Eq Cat
-> (Cat -> Cat -> Ordering)
-> (Cat -> Cat -> Bool)
-> (Cat -> Cat -> Bool)
-> (Cat -> Cat -> Bool)
-> (Cat -> Cat -> Bool)
-> (Cat -> Cat -> Cat)
-> (Cat -> Cat -> Cat)
-> Ord Cat
Cat -> Cat -> Bool
Cat -> Cat -> Ordering
Cat -> Cat -> Cat
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Cat -> Cat -> Cat
$cmin :: Cat -> Cat -> Cat
max :: Cat -> Cat -> Cat
$cmax :: Cat -> Cat -> Cat
>= :: Cat -> Cat -> Bool
$c>= :: Cat -> Cat -> Bool
> :: Cat -> Cat -> Bool
$c> :: Cat -> Cat -> Bool
<= :: Cat -> Cat -> Bool
$c<= :: Cat -> Cat -> Bool
< :: Cat -> Cat -> Bool
$c< :: Cat -> Cat -> Bool
compare :: Cat -> Cat -> Ordering
$ccompare :: Cat -> Cat -> Ordering
$cp1Ord :: Eq Cat
Ord)

type TokenCat = String
type BaseCat  = String

-- An alias for Cat used in many backends:
type NonTerminal = Cat

-- | Render category symbols as strings
catToStr :: Cat -> String
catToStr :: Cat -> String
catToStr = \case
  Cat String
s        -> String
s
  TokenCat String
s   -> String
s
  ListCat Cat
c    -> String
"[" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Cat -> String
catToStr Cat
c String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"]"
  CoercCat String
s Integer
i -> String
s String -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> String
forall a. Show a => a -> String
show Integer
i

instance Show Cat where
  show :: Cat -> String
show = Cat -> String
catToStr

-- | Reads a string into a category. This should only need to handle
-- the case of simple categories (with or without coercion) since list
-- categories are parsed in the grammar already. To be on the safe side here,
-- we still call the parser function that parses categries.
strToCat :: String -> Cat
strToCat :: String -> Cat
strToCat String
s =
    case [Token] -> Either String Cat
pCat (String -> [Token]
tokens String
s) of
        Right Cat
c -> Cat -> Cat
cat2cat Cat
c
        Left String
_ -> String -> Cat
Cat String
s -- error $ "Error parsing cat " ++ s ++ " (" ++ e ++ ")"
                       -- Might be one of the "Internal cat" which are not
                       -- really parsable...
  where
  cat2cat :: Cat -> Cat
cat2cat = \case
    Abs.IdCat (Abs.Identifier ((Int, Int)
_pos, String
x))
      | String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
ds   -> if String
c String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
specialCatsP then String -> Cat
TokenCat String
c else String -> Cat
Cat String
c
      | Bool
otherwise -> String -> Integer -> Cat
CoercCat String
c (String -> Integer
forall a. Read a => String -> a
read String
ds)
      where (String
ds, String
c) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
spanEnd Char -> Bool
isDigit String
x
    Abs.ListCat Cat
c -> Cat -> Cat
ListCat (Cat -> Cat
cat2cat Cat
c)

-- Build-in categories contants
catString, catInteger, catDouble, catChar, catIdent :: TokenCat
catString :: String
catString  = String
"String"
catInteger :: String
catInteger = String
"Integer"
catDouble :: String
catDouble  = String
"Double"
catChar :: String
catChar    = String
"Char"
catIdent :: String
catIdent   = String
"Ident"

-- | Token categories corresponding to base types.
baseTokenCatNames :: [TokenCat]
baseTokenCatNames :: [String]
baseTokenCatNames = [ String
catChar, String
catDouble, String
catInteger, String
catString ]

-- the parser needs these
specialCatsP :: [TokenCat]
specialCatsP :: [String]
specialCatsP = String
catIdent String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
baseTokenCatNames

-- | Does the category correspond to a data type?
isDataCat :: Cat -> Bool
isDataCat :: Cat -> Bool
isDataCat Cat
c = Cat -> Bool
isDataOrListCat Cat
c Bool -> Bool -> Bool
&& Bool -> Bool
not (Cat -> Bool
isList Cat
c)

isDataOrListCat :: Cat -> Bool
isDataOrListCat :: Cat -> Bool
isDataOrListCat (CoercCat String
_ Integer
_)  = Bool
False
isDataOrListCat (Cat (Char
'@':String
_))   = Bool
False
isDataOrListCat (ListCat Cat
c)     = Cat -> Bool
isDataOrListCat Cat
c
isDataOrListCat Cat
_               = Bool
True

-- | Categories C1, C2,... (one digit at the end) are variants of C. This function
-- returns true if two category are variants of the same abstract category.
-- E.g.
--
-- >>> sameCat (Cat "Abc") (CoercCat "Abc" 44)
-- True

sameCat :: Cat -> Cat -> Bool
sameCat :: Cat -> Cat -> Bool
sameCat (CoercCat String
c1 Integer
_) (CoercCat String
c2 Integer
_) = String
c1 String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
c2
sameCat (Cat String
c1)        (CoercCat String
c2 Integer
_) = String
c1 String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
c2
sameCat (CoercCat String
c1 Integer
_) (Cat String
c2)        = String
c1 String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
c2
sameCat Cat
c1              Cat
c2              = Cat
c1 Cat -> Cat -> Bool
forall a. Eq a => a -> a -> Bool
== Cat
c2

-- | Removes precedence information. C1 => C, [C2] => [C]
normCat :: Cat -> Cat
normCat :: Cat -> Cat
normCat (ListCat Cat
c) = Cat -> Cat
ListCat (Cat -> Cat
normCat Cat
c)
normCat (CoercCat String
c Integer
_) = String -> Cat
Cat String
c
normCat Cat
c = Cat
c

normCatOfList :: Cat -> Cat
normCatOfList :: Cat -> Cat
normCatOfList = Cat -> Cat
normCat (Cat -> Cat) -> (Cat -> Cat) -> Cat -> Cat
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cat -> Cat
catOfList

-- | When given a list Cat, i.e. '[C]', it removes the square
-- brackets, and adds the prefix List, i.e. 'ListC'.  (for Happy and
-- Latex)
identCat :: Cat -> String
identCat :: Cat -> String
identCat (ListCat Cat
c) = String
"List" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Cat -> String
identCat Cat
c
identCat Cat
c = Cat -> String
catToStr Cat
c

isList :: Cat -> Bool
isList :: Cat -> Bool
isList (ListCat Cat
_) = Bool
True
isList Cat
_           = Bool
False

-- | Get the underlying category identifier.
baseCat :: Cat -> Either BaseCat TokenCat
baseCat :: Cat -> Either String String
baseCat = \case
  ListCat Cat
c    -> Cat -> Either String String
baseCat Cat
c
  CoercCat String
x Integer
_ -> String -> Either String String
forall a b. a -> Either a b
Left String
x
  Cat String
x        -> String -> Either String String
forall a b. a -> Either a b
Left String
x
  TokenCat String
x   -> String -> Either String String
forall a b. b -> Either a b
Right String
x

isTokenCat :: Cat -> Bool
isTokenCat :: Cat -> Bool
isTokenCat (TokenCat String
_) = Bool
True
isTokenCat Cat
_            = Bool
False

maybeTokenCat :: Cat -> Maybe TokenCat
maybeTokenCat :: Cat -> Maybe String
maybeTokenCat = \case
  TokenCat String
c -> String -> Maybe String
forall a. a -> Maybe a
Just String
c
  Cat
_          -> Maybe String
forall a. Maybe a
Nothing

-- | Unwraps the list constructor from the category name.
--   E.g. @[C1] => C1@.
catOfList :: Cat -> Cat
catOfList :: Cat -> Cat
catOfList (ListCat Cat
c) = Cat
c
catOfList Cat
c = Cat
c

------------------------------------------------------------------------------
-- Functions
------------------------------------------------------------------------------

-- | Fun is the function name of a rule.
type Fun     = String
type RFun    = RString

instance IsString RFun where
  fromString :: String -> WithPosition String
fromString = String -> WithPosition String
forall a. a -> WithPosition a
noPosition

class IsFun a where
  funName :: a -> String

instance IsFun String where
  funName :: ShowS
funName = ShowS
forall a. a -> a
id

instance IsFun a => IsFun (WithPosition a) where
  funName :: WithPosition a -> String
funName = a -> String
forall a. IsFun a => a -> String
funName (a -> String) -> (WithPosition a -> a) -> WithPosition a -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WithPosition a -> a
forall a. WithPosition a -> a
wpThing

funNameSatisfies :: IsFun a => (String -> Bool) -> a -> Bool
funNameSatisfies :: (String -> Bool) -> a -> Bool
funNameSatisfies String -> Bool
f = String -> Bool
f (String -> Bool) -> (a -> String) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. IsFun a => a -> String
funName

-- | Is this function just a coercion? (I.e. the identity)
isCoercion :: IsFun a => a -> Bool
isCoercion :: a -> Bool
isCoercion = (String -> Bool) -> a -> Bool
forall a. IsFun a => (String -> Bool) -> a -> Bool
funNameSatisfies (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"_") -- perhaps this should be changed to "id"?

isDefinedRule :: IsFun a => a -> Bool
isDefinedRule :: a -> Bool
isDefinedRule = (String -> Bool) -> a -> Bool
forall a. IsFun a => (String -> Bool) -> a -> Bool
funNameSatisfies ((String -> Bool) -> a -> Bool) -> (String -> Bool) -> a -> Bool
forall a b. (a -> b) -> a -> b
$ \case
  (Char
x:String
_) -> Char -> Bool
isLower Char
x
  []    -> String -> Bool
forall a. HasCallStack => String -> a
error String
"isDefinedRule: empty function name"

-- isDefinedRule :: Fun -> Bool
-- isDefinedRule (WithPosition _ (x:_)) = isLower x
-- isDefinedRule (WithPosition pos []) = error $
--   unwords [ prettyPosition pos, "isDefinedRule: empty function name" ]

isProperLabel :: IsFun a => a -> Bool
isProperLabel :: a -> Bool
isProperLabel a
f = Bool -> Bool
not (a -> Bool
forall a. IsFun a => a -> Bool
isCoercion a
f Bool -> Bool -> Bool
|| a -> Bool
forall a. IsFun a => a -> Bool
isDefinedRule a
f)

isNilFun, isOneFun, isConsFun, isNilCons,isConcatFun :: IsFun a => a -> Bool
isNilCons :: a -> Bool
isNilCons a
f = a -> Bool
forall a. IsFun a => a -> Bool
isNilFun a
f Bool -> Bool -> Bool
|| a -> Bool
forall a. IsFun a => a -> Bool
isOneFun a
f Bool -> Bool -> Bool
|| a -> Bool
forall a. IsFun a => a -> Bool
isConsFun a
f Bool -> Bool -> Bool
|| a -> Bool
forall a. IsFun a => a -> Bool
isConcatFun a
f
isNilFun :: a -> Bool
isNilFun    = (String -> Bool) -> a -> Bool
forall a. IsFun a => (String -> Bool) -> a -> Bool
funNameSatisfies (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"[]")
isOneFun :: a -> Bool
isOneFun    = (String -> Bool) -> a -> Bool
forall a. IsFun a => (String -> Bool) -> a -> Bool
funNameSatisfies (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"(:[])")
isConsFun :: a -> Bool
isConsFun   = (String -> Bool) -> a -> Bool
forall a. IsFun a => (String -> Bool) -> a -> Bool
funNameSatisfies (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"(:)")
isConcatFun :: a -> Bool
isConcatFun = (String -> Bool) -> a -> Bool
forall a. IsFun a => (String -> Bool) -> a -> Bool
funNameSatisfies (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"(++)")

------------------------------------------------------------------------------

-- | The abstract syntax of a grammar.
type Data = (Cat, [(String, [Cat])])

-- | @firstEntry@ returns the first of the @entrypoints@,
--   or (if none), the first parsable @Cat@egory appearing in the grammar.

firstEntry :: CF -> Cat
firstEntry :: CF -> Cat
firstEntry CF
cf = NonEmpty Cat -> Cat
forall a. NonEmpty a -> a
List1.head (NonEmpty Cat -> Cat) -> NonEmpty Cat -> Cat
forall a b. (a -> b) -> a -> b
$ CF -> NonEmpty Cat
forall f. CFG f -> NonEmpty Cat
allEntryPoints CF
cf

-- aggressively ban nonunique names (AR 31/5/2012)

-- | Constructors and categories.
allNames :: CF -> [RString]
allNames :: CF -> [WithPosition String]
allNames CF
cf =
  [ WithPosition String
f | WithPosition String
f <- (Rule -> WithPosition String) -> [Rule] -> [WithPosition String]
forall a b. (a -> b) -> [a] -> [b]
map Rule -> WithPosition String
forall function. Rul function -> function
funRule ([Rule] -> [WithPosition String])
-> [Rule] -> [WithPosition String]
forall a b. (a -> b) -> a -> b
$ CF -> [Rule]
forall function. CFG function -> [Rul function]
cfgRules CF
cf
      , Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ WithPosition String -> Bool
forall a. IsFun a => a -> Bool
isNilCons WithPosition String
f
      , Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ WithPosition String -> Bool
forall a. IsFun a => a -> Bool
isCoercion WithPosition String
f
  ] [WithPosition String]
-> [WithPosition String] -> [WithPosition String]
forall a. [a] -> [a] -> [a]
++
  CF -> [WithPosition String]
allCatsIdNorm CF
cf
    -- Put the categories after the labels so that the error location
    -- for a non-unique name is at the label rather than the category.

-- | Get all elements with more than one occurrence.
filterNonUnique :: (Ord a) => [a] -> [a]
filterNonUnique :: [a] -> [a]
filterNonUnique [a]
xs = [ a
x | (a
x:a
_:[a]
_) <- [a] -> [[a]]
forall a. Eq a => [a] -> [[a]]
group ([a] -> [[a]]) -> [a] -> [[a]]
forall a b. (a -> b) -> a -> b
$ [a] -> [a]
forall a. Ord a => [a] -> [a]
sort [a]
xs ]


-- | Extract the comment pragmas.
commentPragmas :: [Pragma] -> [Pragma]
commentPragmas :: [Pragma] -> [Pragma]
commentPragmas = (Pragma -> Bool) -> [Pragma] -> [Pragma]
forall a. (a -> Bool) -> [a] -> [a]
filter Pragma -> Bool
isComment
 where isComment :: Pragma -> Bool
isComment (CommentS String
_) = Bool
True
       isComment (CommentM (String, String)
_) = Bool
True
       isComment Pragma
_            = Bool
False

lookupRule :: Eq f => f -> [Rul f] -> Maybe (Cat, SentForm)
lookupRule :: f -> [Rul f] -> Maybe (Cat, SentForm)
lookupRule f
f = f -> [(f, (Cat, SentForm))] -> Maybe (Cat, SentForm)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup f
f ([(f, (Cat, SentForm))] -> Maybe (Cat, SentForm))
-> ([Rul f] -> [(f, (Cat, SentForm))])
-> [Rul f]
-> Maybe (Cat, SentForm)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Rul f -> (f, (Cat, SentForm)))
-> [Rul f] -> [(f, (Cat, SentForm))]
forall a b. (a -> b) -> [a] -> [b]
map Rul f -> (f, (Cat, SentForm))
forall a. Rul a -> (a, (Cat, SentForm))
unRule
  where unRule :: Rul a -> (a, (Cat, SentForm))
unRule (Rule a
f' RCat
c SentForm
rhs InternalRule
_internal) = (a
f', (RCat -> Cat
forall a. WithPosition a -> a
wpThing RCat
c, SentForm
rhs))

-- | Returns all parseable rules that construct the given Cat.
--   Whitespace separators have been removed.
rulesForCat :: CF -> Cat -> [Rule]
rulesForCat :: CF -> Cat -> [Rule]
rulesForCat CF
cf Cat
cat =
  [ Rule -> Rule
forall f. Rul f -> Rul f
removeWhiteSpaceSeparators Rule
r | Rule
r <- CF -> [Rule]
forall function. CFG function -> [Rul function]
cfgRules CF
cf, Rule -> Bool
forall f. Rul f -> Bool
isParsable Rule
r, Rule -> Cat
forall fun. Rul fun -> Cat
valCat Rule
r Cat -> Cat -> Bool
forall a. Eq a => a -> a -> Bool
== Cat
cat]

removeWhiteSpaceSeparators :: Rul f -> Rul f
removeWhiteSpaceSeparators :: Rul f -> Rul f
removeWhiteSpaceSeparators = (SentForm -> SentForm) -> Rul f -> Rul f
forall f. (SentForm -> SentForm) -> Rul f -> Rul f
mapRhs ((SentForm -> SentForm) -> Rul f -> Rul f)
-> (SentForm -> SentForm) -> Rul f -> Rul f
forall a b. (a -> b) -> a -> b
$ (Either Cat String -> Maybe (Either Cat String))
-> SentForm -> SentForm
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ((Either Cat String -> Maybe (Either Cat String))
 -> SentForm -> SentForm)
-> (Either Cat String -> Maybe (Either Cat String))
-> SentForm
-> SentForm
forall a b. (a -> b) -> a -> b
$ (Cat -> Maybe (Either Cat String))
-> (String -> Maybe (Either Cat String))
-> Either Cat String
-> Maybe (Either Cat String)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Either Cat String -> Maybe (Either Cat String)
forall a. a -> Maybe a
Just (Either Cat String -> Maybe (Either Cat String))
-> (Cat -> Either Cat String) -> Cat -> Maybe (Either Cat String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cat -> Either Cat String
forall a b. a -> Either a b
Left) ((String -> Maybe (Either Cat String))
 -> Either Cat String -> Maybe (Either Cat String))
-> (String -> Maybe (Either Cat String))
-> Either Cat String
-> Maybe (Either Cat String)
forall a b. (a -> b) -> a -> b
$ \ String
sep ->
  if (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isSpace String
sep then Maybe (Either Cat String)
forall a. Maybe a
Nothing else Either Cat String -> Maybe (Either Cat String)
forall a. a -> Maybe a
Just (String -> Either Cat String
forall a b. b -> Either a b
Right String
sep)

-- | Modify the 'rhsRule' part of a 'Rule'.
mapRhs :: (SentForm -> SentForm) -> Rul f -> Rul f
mapRhs :: (SentForm -> SentForm) -> Rul f -> Rul f
mapRhs SentForm -> SentForm
f Rul f
r = Rul f
r { rhsRule :: SentForm
rhsRule = SentForm -> SentForm
f (SentForm -> SentForm) -> SentForm -> SentForm
forall a b. (a -> b) -> a -> b
$ Rul f -> SentForm
forall function. Rul function -> SentForm
rhsRule Rul f
r }

-- | Like rulesForCat but for normalized value categories.
-- I.e., `rulesForCat (Cat "Exp")` will return rules for category Exp but also
-- Exp1, Exp2... in case of coercion
rulesForNormalizedCat :: CF -> Cat -> [Rule]
rulesForNormalizedCat :: CF -> Cat -> [Rule]
rulesForNormalizedCat CF
cf Cat
cat =
    [Rule
r | Rule
r <- CF -> [Rule]
forall function. CFG function -> [Rul function]
cfgRules CF
cf, Rule -> Bool
forall f. Rul f -> Bool
isParsable Rule
r, Cat -> Cat
normCat (Rule -> Cat
forall fun. Rul fun -> Cat
valCat Rule
r) Cat -> Cat -> Bool
forall a. Eq a => a -> a -> Bool
== Cat
cat]

-- | As rulesForCat, but this version doesn't exclude internal rules.
rulesForCat' :: CF -> Cat -> [Rule]
rulesForCat' :: CF -> Cat -> [Rule]
rulesForCat' CF
cf Cat
cat = [Rule
r | Rule
r <- CF -> [Rule]
forall function. CFG function -> [Rul function]
cfgRules CF
cf, Rule -> Cat
forall fun. Rul fun -> Cat
valCat Rule
r Cat -> Cat -> Bool
forall a. Eq a => a -> a -> Bool
== Cat
cat]

-- | Get all categories of a grammar matching the filter.
--   (No Cat w/o production returned; no duplicates.)
allCats :: (InternalRule -> Bool) -> CFG f -> [Cat]
allCats :: (InternalRule -> Bool) -> CFG f -> [Cat]
allCats InternalRule -> Bool
pred = [Cat] -> [Cat]
forall a. Eq a => [a] -> [a]
nub ([Cat] -> [Cat]) -> (CFG f -> [Cat]) -> CFG f -> [Cat]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Rul f -> Cat) -> [Rul f] -> [Cat]
forall a b. (a -> b) -> [a] -> [b]
map Rul f -> Cat
forall fun. Rul fun -> Cat
valCat ([Rul f] -> [Cat]) -> (CFG f -> [Rul f]) -> CFG f -> [Cat]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Rul f -> Bool) -> [Rul f] -> [Rul f]
forall a. (a -> Bool) -> [a] -> [a]
filter (InternalRule -> Bool
pred (InternalRule -> Bool) -> (Rul f -> InternalRule) -> Rul f -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rul f -> InternalRule
forall function. Rul function -> InternalRule
internal) ([Rul f] -> [Rul f]) -> (CFG f -> [Rul f]) -> CFG f -> [Rul f]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CFG f -> [Rul f]
forall function. CFG function -> [Rul function]
cfgRules

-- | Get all categories of a grammar.
--   (No Cat w/o production returned; no duplicates.)
reallyAllCats :: CFG f -> [Cat]
reallyAllCats :: CFG f -> [Cat]
reallyAllCats = (InternalRule -> Bool) -> CFG f -> [Cat]
forall f. (InternalRule -> Bool) -> CFG f -> [Cat]
allCats ((InternalRule -> Bool) -> CFG f -> [Cat])
-> (InternalRule -> Bool) -> CFG f -> [Cat]
forall a b. (a -> b) -> a -> b
$ Bool -> InternalRule -> Bool
forall a b. a -> b -> a
const Bool
True

allParserCats :: CFG f -> [Cat]
allParserCats :: CFG f -> [Cat]
allParserCats = (InternalRule -> Bool) -> CFG f -> [Cat]
forall f. (InternalRule -> Bool) -> CFG f -> [Cat]
allCats (InternalRule -> InternalRule -> Bool
forall a. Eq a => a -> a -> Bool
== InternalRule
Parsable)

-- | Gets all normalized identified Categories
allCatsIdNorm :: CF -> [RString]
allCatsIdNorm :: CF -> [WithPosition String]
allCatsIdNorm = [WithPosition String] -> [WithPosition String]
forall a. Eq a => [a] -> [a]
nub ([WithPosition String] -> [WithPosition String])
-> (CF -> [WithPosition String]) -> CF -> [WithPosition String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Rule -> WithPosition String) -> [Rule] -> [WithPosition String]
forall a b. (a -> b) -> [a] -> [b]
map ((Cat -> String) -> RCat -> WithPosition String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Cat -> String
identCat (Cat -> String) -> (Cat -> Cat) -> Cat -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cat -> Cat
normCat) (RCat -> WithPosition String)
-> (Rule -> RCat) -> Rule -> WithPosition String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rule -> RCat
forall function. Rul function -> RCat
valRCat) ([Rule] -> [WithPosition String])
-> (CF -> [Rule]) -> CF -> [WithPosition String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CF -> [Rule]
forall function. CFG function -> [Rul function]
cfgRules

-- | Get all normalized Cat
allCatsNorm :: CF -> [Cat]
allCatsNorm :: CF -> [Cat]
allCatsNorm = [Cat] -> [Cat]
forall a. Eq a => [a] -> [a]
nub ([Cat] -> [Cat]) -> (CF -> [Cat]) -> CF -> [Cat]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Rule -> Cat) -> [Rule] -> [Cat]
forall a b. (a -> b) -> [a] -> [b]
map (Cat -> Cat
normCat (Cat -> Cat) -> (Rule -> Cat) -> Rule -> Cat
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rule -> Cat
forall fun. Rul fun -> Cat
valCat) ([Rule] -> [Cat]) -> (CF -> [Rule]) -> CF -> [Cat]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CF -> [Rule]
forall function. CFG function -> [Rul function]
cfgRules

-- | Get all normalized Cat
allParserCatsNorm :: CFG f -> [Cat]
allParserCatsNorm :: CFG f -> [Cat]
allParserCatsNorm = [Cat] -> [Cat]
forall a. Eq a => [a] -> [a]
nub ([Cat] -> [Cat]) -> (CFG f -> [Cat]) -> CFG f -> [Cat]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Cat -> Cat) -> [Cat] -> [Cat]
forall a b. (a -> b) -> [a] -> [b]
map Cat -> Cat
normCat ([Cat] -> [Cat]) -> (CFG f -> [Cat]) -> CFG f -> [Cat]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CFG f -> [Cat]
forall function. CFG function -> [Cat]
allParserCats

-- | Is the category is used on an rhs?
--   Includes internal rules.
isUsedCat :: CFG f -> Cat -> Bool
isUsedCat :: CFG f -> Cat -> Bool
isUsedCat CFG f
cf = (Cat -> Set Cat -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member` CFG f -> Set Cat
forall function. CFG function -> Set Cat
cfgUsedCats CFG f
cf)

-- | Group all parsable categories with their rules.
--   Deletes whitespace separators, as they will not become part of the parsing rules.
ruleGroups :: CF -> [(Cat,[Rule])]
ruleGroups :: CF -> [(Cat, [Rule])]
ruleGroups CF
cf = [(Cat
c, CF -> Cat -> [Rule]
rulesForCat CF
cf Cat
c) | Cat
c <- CF -> [Cat]
forall function. CFG function -> [Cat]
allParserCats CF
cf]

-- | Group all categories with their rules including internal rules.
ruleGroupsInternals :: CF -> [(Cat,[Rule])]
ruleGroupsInternals :: CF -> [(Cat, [Rule])]
ruleGroupsInternals CF
cf = [(Cat
c, CF -> Cat -> [Rule]
rulesForCat' CF
cf Cat
c) | Cat
c <- CF -> [Cat]
forall function. CFG function -> [Cat]
reallyAllCats CF
cf]

-- | Get all literals of a grammar. (e.g. String, Double)
literals :: CFG f -> [TokenCat]
literals :: CFG f -> [String]
literals CFG f
cf = CFG f -> [String]
forall function. CFG function -> [String]
cfgLiterals CFG f
cf [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ ((String, Reg) -> String) -> [(String, Reg)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, Reg) -> String
forall a b. (a, b) -> a
fst (CFG f -> [(String, Reg)]
forall f. CFG f -> [(String, Reg)]
tokenPragmas CFG f
cf)

-- | Get the keywords of a grammar.
reservedWords :: CFG f -> [String]
reservedWords :: CFG f -> [String]
reservedWords = [String] -> [String]
forall a. Ord a => [a] -> [a]
sort ([String] -> [String]) -> (CFG f -> [String]) -> CFG f -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CFG f -> [String]
forall function. CFG function -> [String]
cfgKeywords

-- | Canonical, numbered list of symbols and reserved words. (These do
-- not end up in the AST.)
cfTokens :: CFG f -> [(String,Int)]
cfTokens :: CFG f -> [(String, Int)]
cfTokens CFG f
cf = [String] -> [Int] -> [(String, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip ([String] -> [String]
forall a. Ord a => [a] -> [a]
sort (CFG f -> [String]
forall function. CFG function -> [String]
cfgSymbols CFG f
cf [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ CFG f -> [String]
forall function. CFG function -> [String]
reservedWords CFG f
cf)) [Int
1..]
-- NOTE: some backends (incl. Haskell) assume that this list is sorted.

-- | Comments can be defined by the 'comment' pragma
comments :: CF -> ([(String,String)],[String])
comments :: CF -> ([(String, String)], [String])
comments CF
cf = ([(String, String)
p | CommentM (String, String)
p <- [Pragma]
xs], [String
s | CommentS String
s <- [Pragma]
xs])
  where
  xs :: [Pragma]
xs = [Pragma] -> [Pragma]
commentPragmas (CF -> [Pragma]
forall function. CFG function -> [Pragma]
cfgPragmas CF
cf)

-- | Number of block comment forms defined in the grammar file.
numberOfBlockCommentForms :: CF -> Int
numberOfBlockCommentForms :: CF -> Int
numberOfBlockCommentForms = [(String, String)] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([(String, String)] -> Int)
-> (CF -> [(String, String)]) -> CF -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([(String, String)], [String]) -> [(String, String)]
forall a b. (a, b) -> a
fst (([(String, String)], [String]) -> [(String, String)])
-> (CF -> ([(String, String)], [String]))
-> CF
-> [(String, String)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CF -> ([(String, String)], [String])
comments


-- built-in categories (corresponds to lexer)

-- | Whether the grammar uses the predefined Ident type.
hasIdent :: CFG f -> Bool
hasIdent :: CFG f -> Bool
hasIdent CFG f
cf = CFG f -> Cat -> Bool
forall f. CFG f -> Cat -> Bool
isUsedCat CFG f
cf (Cat -> Bool) -> Cat -> Bool
forall a b. (a -> b) -> a -> b
$ String -> Cat
TokenCat String
catIdent


-- these need new datatypes

-- | Categories corresponding to tokens. These end up in the
-- AST. (unlike tokens returned by 'cfTokens')
specialCats :: CF -> [TokenCat]
specialCats :: CF -> [String]
specialCats CF
cf = (if CF -> Bool
forall f. CFG f -> Bool
hasIdent CF
cf then (String
catIdentString -> [String] -> [String]
forall a. a -> [a] -> [a]
:) else [String] -> [String]
forall a. a -> a
id) (((String, Reg) -> String) -> [(String, Reg)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, Reg) -> String
forall a b. (a, b) -> a
fst (CF -> [(String, Reg)]
forall f. CFG f -> [(String, Reg)]
tokenPragmas CF
cf))


-- * abstract syntax trees: data type definitions
--
-- The abstract syntax, instantiated by the Data type, is the type signatures
-- of all the constructors.

-- | Return the abstract syntax of the grammar.
-- All categories are normalized, so a rule like:
--     EAdd . Exp2 ::= Exp2 "+" Exp3 ;
-- Will give the following signature: EAdd : Exp -> Exp -> Exp
getAbstractSyntax :: CF -> [Data]
getAbstractSyntax :: CF -> [Data]
getAbstractSyntax CF
cf = [ ( Cat
c, [(String, [Cat])] -> [(String, [Cat])]
forall a. Eq a => [a] -> [a]
nub (Cat -> [(String, [Cat])]
constructors Cat
c) ) | Cat
c <- CF -> [Cat]
allCatsNorm CF
cf ]
  where
    constructors :: Cat -> [(String, [Cat])]
constructors Cat
cat = do
        Rule
rule <- CF -> [Rule]
forall function. CFG function -> [Rul function]
cfgRules CF
cf
        let f :: WithPosition String
f = Rule -> WithPosition String
forall function. Rul function -> function
funRule Rule
rule
        Bool -> [()]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> [()]) -> Bool -> [()]
forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not (WithPosition String -> Bool
forall a. IsFun a => a -> Bool
isDefinedRule WithPosition String
f)
        Bool -> [()]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> [()]) -> Bool -> [()]
forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not (WithPosition String -> Bool
forall a. IsFun a => a -> Bool
isCoercion WithPosition String
f)
        Bool -> [()]
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> [()]) -> Bool -> [()]
forall a b. (a -> b) -> a -> b
$ Cat -> Cat
normCat (Rule -> Cat
forall fun. Rul fun -> Cat
valCat Rule
rule) Cat -> Cat -> Bool
forall a. Eq a => a -> a -> Bool
== Cat
cat
        let cs :: [Cat]
cs = [Cat -> Cat
normCat Cat
c | Left Cat
c <- Rule -> SentForm
forall function. Rul function -> SentForm
rhsRule Rule
rule ]
        (String, [Cat]) -> [(String, [Cat])]
forall (m :: * -> *) a. Monad m => a -> m a
return (WithPosition String -> String
forall a. WithPosition a -> a
wpThing WithPosition String
f, [Cat]
cs)


-- | All the functions below implement the idea of getting the
-- abstract syntax of the grammar with some variation but they seem to do a
-- poor job at handling corner cases involving coercions.
-- Use 'getAbstractSyntax' instead if possible.

cf2data' :: (Cat -> Bool) -> CF -> [Data]
cf2data' :: (Cat -> Bool) -> CF -> [Data]
cf2data' Cat -> Bool
predicate CF
cf =
  [(Cat
cat, [(String, [Cat])] -> [(String, [Cat])]
forall a. Eq a => [a] -> [a]
nub ((Rule -> (String, [Cat])) -> [Rule] -> [(String, [Cat])]
forall a b. (a -> b) -> [a] -> [b]
map Rule -> (String, [Cat])
forall a. Rul (WithPosition a) -> (a, [Cat])
mkData [Rule
r | Rule
r <- CF -> [Rule]
forall function. CFG function -> [Rul function]
cfgRules CF
cf,
                              let f :: WithPosition String
f = Rule -> WithPosition String
forall function. Rul function -> function
funRule Rule
r,
                              Bool -> Bool
not (WithPosition String -> Bool
forall a. IsFun a => a -> Bool
isDefinedRule WithPosition String
f),
                              Bool -> Bool
not (WithPosition String -> Bool
forall a. IsFun a => a -> Bool
isCoercion WithPosition String
f), Cat -> Cat -> Bool
sameCat Cat
cat (Rule -> Cat
forall fun. Rul fun -> Cat
valCat Rule
r)]))
      | Cat
cat <- [Cat] -> [Cat]
forall a. Eq a => [a] -> [a]
nub ([Cat] -> [Cat]) -> [Cat] -> [Cat]
forall a b. (a -> b) -> a -> b
$ (Cat -> Cat) -> [Cat] -> [Cat]
forall a b. (a -> b) -> [a] -> [b]
map Cat -> Cat
normCat ([Cat] -> [Cat]) -> [Cat] -> [Cat]
forall a b. (a -> b) -> a -> b
$ (Cat -> Bool) -> [Cat] -> [Cat]
forall a. (a -> Bool) -> [a] -> [a]
filter Cat -> Bool
predicate ([Cat] -> [Cat]) -> [Cat] -> [Cat]
forall a b. (a -> b) -> a -> b
$ CF -> [Cat]
forall function. CFG function -> [Cat]
reallyAllCats CF
cf ]
 where
  mkData :: Rul (WithPosition a) -> (a, [Cat])
mkData (Rule WithPosition a
f RCat
_ SentForm
its InternalRule
_) = (WithPosition a -> a
forall a. WithPosition a -> a
wpThing WithPosition a
f, [Cat -> Cat
normCat Cat
c | Left Cat
c <- SentForm
its ])

cf2data :: CF -> [Data]
cf2data :: CF -> [Data]
cf2data = (Cat -> Bool) -> CF -> [Data]
cf2data' ((Cat -> Bool) -> CF -> [Data]) -> (Cat -> Bool) -> CF -> [Data]
forall a b. (a -> b) -> a -> b
$ Cat -> Bool
isDataCat (Cat -> Bool) -> (Cat -> Cat) -> Cat -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cat -> Cat
normCat

cf2dataLists :: CF -> [Data]
cf2dataLists :: CF -> [Data]
cf2dataLists = (Cat -> Bool) -> CF -> [Data]
cf2data' ((Cat -> Bool) -> CF -> [Data]) -> (Cat -> Bool) -> CF -> [Data]
forall a b. (a -> b) -> a -> b
$ Cat -> Bool
isDataOrListCat (Cat -> Bool) -> (Cat -> Cat) -> Cat -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cat -> Cat
normCat

specialData :: CF -> [Data]
specialData :: CF -> [Data]
specialData CF
cf = [(String -> Cat
TokenCat String
name, [(String
name, [String -> Cat
TokenCat String
catString])]) | String
name <- CF -> [String]
specialCats CF
cf]

-- | Get the type of a rule label.
sigLookup :: IsFun a => a -> CF -> Maybe (WithPosition Type)
sigLookup :: a -> CF -> Maybe (WithPosition Type)
sigLookup a
f = String -> Signature -> Maybe (WithPosition Type)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (a -> String
forall a. IsFun a => a -> String
funName a
f) (Signature -> Maybe (WithPosition Type))
-> (CF -> Signature) -> CF -> Maybe (WithPosition Type)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CF -> Signature
forall function. CFG function -> Signature
cfgSignature


-- | Checks if the rule is parsable.
isParsable :: Rul f -> Bool
isParsable :: Rul f -> Bool
isParsable = (InternalRule
Parsable InternalRule -> InternalRule -> Bool
forall a. Eq a => a -> a -> Bool
==) (InternalRule -> Bool) -> (Rul f -> InternalRule) -> Rul f -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rul f -> InternalRule
forall function. Rul function -> InternalRule
internal


-- | Checks if the list has a non-empty rule.
hasOneFunc :: [Rule] -> Bool
hasOneFunc :: [Rule] -> Bool
hasOneFunc = (Rule -> Bool) -> [Rule] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (WithPosition String -> Bool
forall a. IsFun a => a -> Bool
isOneFun (WithPosition String -> Bool)
-> (Rule -> WithPosition String) -> Rule -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rule -> WithPosition String
forall function. Rul function -> function
funRule)

-- | Gets the separator for a list.
getCons :: [Rule] -> String
getCons :: [Rule] -> String
getCons [Rule]
rs = case (Rule -> Bool) -> [Rule] -> Maybe Rule
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (WithPosition String -> Bool
forall a. IsFun a => a -> Bool
isConsFun (WithPosition String -> Bool)
-> (Rule -> WithPosition String) -> Rule -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rule -> WithPosition String
forall function. Rul function -> function
funRule) [Rule]
rs of
    Just (Rule WithPosition String
_ RCat
_ SentForm
cats InternalRule
_) -> SentForm -> String
forall a a. [Either a [a]] -> [a]
seper SentForm
cats
    Maybe Rule
Nothing              -> ShowS
forall a. HasCallStack => String -> a
error ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ String
"getCons: no construction function found in "
                                  String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " ((Rule -> String) -> [Rule] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (WithPosition String -> String
forall a. Show a => a -> String
show (WithPosition String -> String)
-> (Rule -> WithPosition String) -> Rule -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rule -> WithPosition String
forall function. Rul function -> function
funRule) [Rule]
rs)
  where
    seper :: [Either a [a]] -> [a]
seper [] = []
    seper (Right [a]
x:[Either a [a]]
_) = [a]
x
    seper (Left a
_:[Either a [a]]
xs) = [Either a [a]] -> [a]
seper [Either a [a]]
xs

-- | Helper function that gets the list separator by precedence level
getSeparatorByPrecedence :: [Rule] -> [(Integer,String)]
getSeparatorByPrecedence :: [Rule] -> [(Integer, String)]
getSeparatorByPrecedence [Rule]
rules = [ (Integer
p, [Rule] -> String
getCons (Integer -> [Rule]
getRulesFor Integer
p)) | Integer
p <- [Integer]
precedences ]
  where
    precedences :: [Integer]
precedences = Set Integer -> [Integer]
forall a. Set a -> [a]
Set.toDescList (Set Integer -> [Integer])
-> ([Integer] -> Set Integer) -> [Integer] -> [Integer]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Integer] -> Set Integer
forall a. Ord a => [a] -> Set a
Set.fromList ([Integer] -> [Integer]) -> [Integer] -> [Integer]
forall a b. (a -> b) -> a -> b
$ (Rule -> Integer) -> [Rule] -> [Integer]
forall a b. (a -> b) -> [a] -> [b]
map Rule -> Integer
forall f. Rul f -> Integer
precRule [Rule]
rules
    getRulesFor :: Integer -> [Rule]
getRulesFor Integer
p = [ Rule
r | Rule
r <- [Rule]
rules, Rule -> Integer
forall f. Rul f -> Integer
precRule Rule
r Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
p ]

isEmptyListCat :: CF -> Cat -> Bool
isEmptyListCat :: CF -> Cat -> Bool
isEmptyListCat CF
cf Cat
c = String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem String
"[]" ([String] -> Bool) -> [String] -> Bool
forall a b. (a -> b) -> a -> b
$ (Rule -> String) -> [Rule] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (WithPosition String -> String
forall a. WithPosition a -> a
wpThing (WithPosition String -> String)
-> (Rule -> WithPosition String) -> Rule -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rule -> WithPosition String
forall function. Rul function -> function
funRule) ([Rule] -> [String]) -> [Rule] -> [String]
forall a b. (a -> b) -> a -> b
$ CF -> Cat -> [Rule]
rulesForCat' CF
cf Cat
c

isNonterm :: Either Cat String -> Bool
isNonterm :: Either Cat String -> Bool
isNonterm (Left Cat
_) = Bool
True
isNonterm (Right String
_) = Bool
False

-- used in Happy to parse lists of form 'C t [C]' in reverse order
-- applies only if the [] rule has no terminals
revSepListRule :: Rul f -> Rul f
revSepListRule :: Rul f -> Rul f
revSepListRule (Rule f
f RCat
c SentForm
ts InternalRule
internal) = f -> RCat -> SentForm -> InternalRule -> Rul f
forall function.
function -> RCat -> SentForm -> InternalRule -> Rul function
Rule f
f RCat
c (Either Cat String
xs Either Cat String -> SentForm -> SentForm
forall a. a -> [a] -> [a]
: Either Cat String
x Either Cat String -> SentForm -> SentForm
forall a. a -> [a] -> [a]
: SentForm
sep) InternalRule
internal where
  (Either Cat String
x,SentForm
sep,Either Cat String
xs) = (SentForm -> Either Cat String
forall a. [a] -> a
head SentForm
ts, SentForm -> SentForm
forall a. [a] -> [a]
init (SentForm -> SentForm
forall a. [a] -> [a]
tail SentForm
ts), SentForm -> Either Cat String
forall a. [a] -> a
last SentForm
ts)
-- invariant: test in findAllReversibleCats have been performed

findAllReversibleCats :: CF -> [Cat]
findAllReversibleCats :: CF -> [Cat]
findAllReversibleCats CF
cf = [Cat
c | (Cat
c,[Rule]
r) <- CF -> [(Cat, [Rule])]
ruleGroups CF
cf, Cat -> [Rule] -> Bool
forall a. IsFun a => Cat -> [Rul a] -> Bool
isRev Cat
c [Rule]
r] where
  isRev :: Cat -> [Rul a] -> Bool
isRev Cat
c [Rul a]
rs = case [Rul a]
rs of
     [Rul a
r1,Rul a
r2] | Cat -> Bool
isList Cat
c -> if a -> Bool
forall a. IsFun a => a -> Bool
isConsFun (Rul a -> a
forall function. Rul function -> function
funRule Rul a
r2)
                             then Rul a -> Rul a -> Bool
forall a a. (IsFun a, IsFun a) => Rul a -> Rul a -> Bool
tryRev Rul a
r2 Rul a
r1
                           else a -> Bool
forall a. IsFun a => a -> Bool
isConsFun (Rul a -> a
forall function. Rul function -> function
funRule Rul a
r1) Bool -> Bool -> Bool
&& Rul a -> Rul a -> Bool
forall a a. (IsFun a, IsFun a) => Rul a -> Rul a -> Bool
tryRev Rul a
r1 Rul a
r2
     [Rul a]
_ -> Bool
False
  tryRev :: Rul a -> Rul a -> Bool
tryRev (Rule a
f RCat
_ ts :: SentForm
ts@(Either Cat String
x:Either Cat String
_:SentForm
_) InternalRule
_) Rul a
r = Rul a -> Bool
forall a. IsFun a => Rul a -> Bool
isEmptyNilRule Rul a
r Bool -> Bool -> Bool
&&
                                        a -> Bool
forall a. IsFun a => a -> Bool
isConsFun a
f Bool -> Bool -> Bool
&& Either Cat String -> Bool
isNonterm Either Cat String
x Bool -> Bool -> Bool
&& Either Cat String -> Bool
isNonterm (SentForm -> Either Cat String
forall a. [a] -> a
last SentForm
ts)
  tryRev Rul a
_ Rul a
_ = Bool
False

isEmptyNilRule :: IsFun a => Rul a -> Bool
isEmptyNilRule :: Rul a -> Bool
isEmptyNilRule (Rule a
f RCat
_ SentForm
ts InternalRule
_) = a -> Bool
forall a. IsFun a => a -> Bool
isNilFun a
f Bool -> Bool -> Bool
&& SentForm -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null SentForm
ts

-- | Returns the precedence of a category symbol.
-- E.g.
-- >>> precCat (CoercCat "Abc" 4)
-- 4
precCat :: Cat -> Integer
precCat :: Cat -> Integer
precCat (CoercCat String
_ Integer
i) = Integer
i
precCat (ListCat Cat
c) = Cat -> Integer
precCat Cat
c
precCat Cat
_ = Integer
0

precRule :: Rul f -> Integer
precRule :: Rul f -> Integer
precRule = Cat -> Integer
precCat (Cat -> Integer) -> (Rul f -> Cat) -> Rul f -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rul f -> Cat
forall fun. Rul fun -> Cat
valCat

-- | Defines or uses the grammar token types like @Ident@?
--   Excludes position tokens.
hasIdentLikeTokens :: CFG g -> Bool
hasIdentLikeTokens :: CFG g -> Bool
hasIdentLikeTokens CFG g
cf = CFG g -> Bool
forall f. CFG f -> Bool
hasIdent CFG g
cf Bool -> Bool -> Bool
|| [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or [ Bool -> Bool
not Bool
b | TokenReg WithPosition String
_ Bool
b Reg
_ <- CFG g -> [Pragma]
forall function. CFG function -> [Pragma]
cfgPragmas CFG g
cf ]

-- | Is there a @position token@ declaration in the grammar?
hasPositionTokens :: CFG g -> Bool
hasPositionTokens :: CFG g -> Bool
hasPositionTokens CFG g
cf = [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or [ Bool
b | TokenReg WithPosition String
_ Bool
b Reg
_ <- CFG g -> [Pragma]
forall function. CFG function -> [Pragma]
cfgPragmas CFG g
cf ]

-- | Does the category have a position stored in AST?
isPositionCat :: CFG f -> TokenCat -> Bool
isPositionCat :: CFG f -> String -> Bool
isPositionCat CFG f
cf String
cat = [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or [ Bool
b | TokenReg WithPosition String
name Bool
b Reg
_ <- CFG f -> [Pragma]
forall function. CFG function -> [Pragma]
cfgPragmas CFG f
cf, WithPosition String -> String
forall a. WithPosition a -> a
wpThing WithPosition String
name String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
cat]


-- | Categories that are entry points to the parser.
--
--   These are either the declared @entrypoints@ (in the original order),
--   or, if no @entrypoints@ were declared explicitly,
--   all parsable categories (in the order of declaration in the grammar file).
allEntryPoints :: CFG f -> List1 Cat
allEntryPoints :: CFG f -> NonEmpty Cat
allEntryPoints CFG f
cf =
  case [[RCat]] -> [RCat]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ [RCat]
cats | EntryPoints [RCat]
cats <- CFG f -> [Pragma]
forall function. CFG function -> [Pragma]
cfgPragmas CFG f
cf ] of
    []   -> [Cat] -> NonEmpty Cat
forall a. [a] -> NonEmpty a
List1.fromList ([Cat] -> NonEmpty Cat) -> [Cat] -> NonEmpty Cat
forall a b. (a -> b) -> a -> b
$ CFG f -> [Cat]
forall function. CFG function -> [Cat]
allParserCats CFG f
cf  -- assumed to be non-empty
    RCat
c:[RCat]
cs -> (RCat -> Cat) -> NonEmpty RCat -> NonEmpty Cat
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap RCat -> Cat
forall a. WithPosition a -> a
wpThing (RCat
c RCat -> [RCat] -> NonEmpty RCat
forall a. a -> [a] -> NonEmpty a
:| [RCat]
cs)