2016-12-09 19:31:13 +03:00
|
|
|
{-# LANGUAGE RankNTypes, ScopedTypeVariables #-}
|
2016-12-09 22:42:32 +03:00
|
|
|
module Renderer.SExpression (sExpression) where
|
2016-12-09 19:31:13 +03:00
|
|
|
|
|
|
|
import Data.Bifunctor.Join
|
|
|
|
import Data.Foldable
|
|
|
|
import Data.Functor.Foldable
|
2016-12-09 20:47:51 +03:00
|
|
|
import Data.Functor.Both
|
2016-12-09 19:31:13 +03:00
|
|
|
import Data.Record
|
2016-12-09 22:30:37 +03:00
|
|
|
import Data.Text hiding (foldr, replicate)
|
2016-12-09 19:31:13 +03:00
|
|
|
import Prologue hiding (toList, intercalate)
|
|
|
|
|
|
|
|
import Category as C
|
|
|
|
import Diff
|
|
|
|
import Renderer
|
|
|
|
import Patch
|
|
|
|
import Info
|
|
|
|
import Syntax
|
|
|
|
import Term
|
|
|
|
|
2016-12-09 22:42:32 +03:00
|
|
|
sExpression :: (HasField fields Category, HasField fields SourceSpan) => Renderer (Record fields)
|
|
|
|
sExpression _ diff = SExpressionOutput $ printDiff diff 0
|
2016-12-09 19:31:13 +03:00
|
|
|
|
2016-12-09 22:30:37 +03:00
|
|
|
printDiff :: (HasField fields Category, HasField fields SourceSpan) => Diff (Syntax Text) (Record fields) -> Int -> Text
|
|
|
|
printDiff diff level = case runFree diff of
|
2016-12-09 20:47:51 +03:00
|
|
|
(Pure patch) -> case patch of
|
2016-12-09 22:30:37 +03:00
|
|
|
Insert term -> pad (level - 1) <> "{+" <> printTerm term level <> "}"
|
|
|
|
Delete term -> pad (level - 1) <> "{-" <> printTerm term level <> "}"
|
|
|
|
Replace a b -> pad (level - 1) <> "{" <> printTerm a level <> "->" <> printTerm b level <> "}"
|
|
|
|
(Free (Join (_, annotation) :< syntax)) -> pad level <> "(" <> showAnnotation annotation <> foldr (\d acc -> printDiff d (level + 1) <> acc) "" syntax <> ")"
|
2016-12-09 20:47:51 +03:00
|
|
|
where
|
2016-12-09 22:30:37 +03:00
|
|
|
pad n | n < 1 = ""
|
|
|
|
pad n = "\n" <> mconcat (replicate n " ")
|
2016-12-09 20:47:51 +03:00
|
|
|
|
2016-12-09 22:30:37 +03:00
|
|
|
printTerm :: (HasField fields Category, HasField fields SourceSpan) => Term (Syntax t) (Record fields) -> Int -> Text
|
|
|
|
printTerm term level = go term level 0
|
|
|
|
where
|
|
|
|
pad _ 0 = ""
|
|
|
|
pad p n = "\n" <> mconcat (replicate (p + n) " ")
|
|
|
|
go term parentLevel level = case runCofree term of
|
|
|
|
(annotation :< Leaf _) -> pad parentLevel level <> "(" <> showAnnotation annotation <> ")"
|
|
|
|
(annotation :< syntax) -> pad parentLevel level <> "(" <> showAnnotation annotation <> foldr (\d acc -> go d parentLevel (level + 1) <> acc) "" syntax <> ")"
|
2016-12-09 20:47:51 +03:00
|
|
|
|
2016-12-09 22:30:37 +03:00
|
|
|
showAnnotation :: (HasField fields Category, HasField fields SourceSpan) => Record fields -> Text
|
|
|
|
showAnnotation annotation = categoryName annotation <> " " <> showSourceSpan annotation
|
|
|
|
where
|
|
|
|
showSourceSpan a = start a <> " - " <> end a
|
|
|
|
start = showPoint . spanStart . getField
|
|
|
|
end = showPoint . spanEnd . getField
|
|
|
|
showPoint SourcePos{..} = "[" <> show line <> ", " <> show column <> "]"
|
|
|
|
|
|
|
|
categoryName :: HasField fields Category => Record fields -> Text
|
|
|
|
categoryName = toS . category
|
2016-12-09 20:47:51 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- TODO: Move over to FDocs about how to understand structure of Diff as well as
|
|
|
|
-- the use of Free and Cofree on the different levels.
|
2016-12-09 19:31:13 +03:00
|
|
|
syntaxDiffToText :: HasField fields Category => Diff (Syntax Text) (Record fields) -> Text
|
|
|
|
syntaxDiffToText = cata algebra
|
|
|
|
where
|
2016-12-09 20:47:51 +03:00
|
|
|
algebra :: (HasField fields1 Category, HasField fields Category, Foldable t) => FreeF (TermF t (Both (Record fields1))) (Patch (Term (Syntax Text) (Record fields))) Text -> Text
|
2016-12-09 19:31:13 +03:00
|
|
|
algebra diff = case diff of
|
2016-12-09 20:47:51 +03:00
|
|
|
-- Pure nodes are patches (what's changed)
|
2016-12-09 19:31:13 +03:00
|
|
|
(Pure patch) -> patchFields patch
|
2016-12-09 20:47:51 +03:00
|
|
|
-- Free nodes are context
|
2016-12-09 19:31:13 +03:00
|
|
|
(Free (Join (_, annotation) :< syntax)) -> "(" <> categoryName annotation <> unwords (toList syntax) <> ")"
|
|
|
|
|
|
|
|
patchFields :: HasField fields Category => Patch (Term (Syntax Text) (Record fields)) -> Text
|
|
|
|
patchFields patch = case patch of
|
|
|
|
Insert term -> fields "+" term
|
|
|
|
Delete term -> fields "-" term
|
|
|
|
Replace a b -> "(" <> termFields a <> "->" <> termFields b <> ")"
|
|
|
|
where
|
|
|
|
fields kind term = "(" <> kind <> termFields term <> ")"
|
|
|
|
|
|
|
|
termFields :: HasField fields Category => Term (Syntax Text) (Record fields) -> Text
|
|
|
|
termFields = cata algebra
|
|
|
|
where
|
2016-12-09 20:47:51 +03:00
|
|
|
algebra :: HasField fields Category => TermF (Syntax leaf) (Record fields) Text -> Text
|
2016-12-09 19:31:13 +03:00
|
|
|
algebra term = case term of
|
|
|
|
(annotation :< Leaf _) -> categoryName annotation
|
|
|
|
(annotation :< syntax) -> categoryName annotation <> "(" <> unwords (toList syntax) <> ")"
|