packages feed

fnotation-0.1.0.0: src/FNotation/Trees.hs

module FNotation.Trees where

import Data.Maybe (maybeToList)
import Data.Text (Text)
import Diagnostician
import FNotation.Names
import Prettyprinter
import Prelude hiding (head, span)

-- Notation data structure
--------------------------------------------------------------------------------

-- | Notation is the output of parsing.
--
-- Each notation is associated with a span. Most variants store that span; `App`
-- and `Infix` don't because the span can be inferred by looking at the left and
-- right children.
--
-- In the variants which take a span, we put the span last because in the parser
-- we have utility methods which take `Span -> Ntn`, and if the span is last, we
-- can use currying to our advantage here.
data NtnGeneric a
  = App (NtnGeneric a) [NtnGeneric a]
  | Infix (NtnGeneric a) (NtnGeneric a) (NtnGeneric a)
  | Block Name (Maybe (NtnGeneric a)) [NtnGeneric a] a
  | Decl Name (NtnGeneric a) a
  | Tuple [NtnGeneric a] a
  | Ident Name a
  | Keyword Name a
  | Field Name a
  | Tag Name a
  | Int Int a
  | String Text a
  | Error a

type Ntn = NtnGeneric Span

type Ntn0 = NtnGeneric ()

startPos :: Ntn -> Pos
startPos (App f _) = startPos f
startPos (Infix x _ _) = startPos x
startPos (Block _ _ _ s) = s.start
startPos (Decl _ _ s) = s.start
startPos (Ident _ s) = s.start
startPos (Keyword _ s) = s.start
startPos (Field _ s) = s.start
startPos (Tag _ s) = s.start
startPos (Int _ s) = s.start
startPos (String _ s) = s.start
startPos (Tuple _ s) = s.start
startPos (Error s) = s.start

endPos :: Ntn -> Pos
endPos (App _ xs) = endPos (last xs)
endPos (Infix _ _ y) = endPos y
endPos (Block _ _ _ s) = s.end
endPos (Decl _ _ s) = s.end
endPos (Ident _ s) = s.end
endPos (Keyword _ s) = s.end
endPos (Field _ s) = s.end
endPos (Tag _ s) = s.end
endPos (Int _ s) = s.end
endPos (String _ s) = s.end
endPos (Tuple _ s) = s.end
endPos (Error s) = s.end

span :: Ntn -> Span
span n = Span (startPos n) (endPos n)

-- Debug printing for notation
--------------------------------------------------------------------------------

head :: Ntn -> DDoc
head (App _ _) = "App"
head (Infix _ _ _) = "Infix"
head (Block x _ _ _) = "Block" <+> dpretty x
head (Decl x _ _) = "Decl" <+> dpretty x
head (Ident x _) = "Ident" <+> dpretty x
head (Keyword x _) = "Keyword" <+> dpretty x
head (Field x _) = "Field" <+> dpretty x
head (Tag x _) = "Tag" <+> dpretty x
head (Int i _) = "Int" <+> pretty i
head (String i _) = "Int" <+> pretty i
head (Tuple _ _) = "Tuple"
head (Error _) = "Error"

children :: Ntn -> [Ntn]
children (App f xs) = f : xs
children (Infix x op y) = [x, op, y]
children (Block _ mh xs _) = maybeToList mh ++ xs
children (Decl _ x _) = [x]
children (Ident _ _) = []
children (Keyword _ _) = []
children (Field _ _) = []
children (Tag _ _) = []
children (Int _ _) = []
children (String _ _) = []
children (Tuple ns _) = ns
children (Error _) = []

instance DPretty Ntn where
  dpretty n = if null cs then h else vsep [h, indent 2 $ vsep cs]
    where
      h = head n <+> "(" <> dpretty (span n) <> ")"
      cs = map dpretty (children n)