eo-phi-normalizer-2.3.0: src/Language/EO/Phi/ToLaTeX.hs
{- FOURMOLU_DISABLE -}
-- The MIT License (MIT)
-- Copyright (c) 2016-2024 Objectionary.com
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
-- The above copyright notice and this permission notice shall be included
-- in all copies or substantial portions of the Software.
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
{- FOURMOLU_ENABLE -}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Language.EO.Phi.ToLaTeX where
import Data.Foldable (fold)
import Data.List (intersperse)
import Data.String (IsString)
import Data.Text qualified as T
import Language.EO.Phi
import Language.EO.Phi.Rules.Yaml
import Text.Regex (mkRegex, subRegex)
newtype LaTeX = LaTeX {unLaTeX :: String}
deriving newtype (IsString, Semigroup, Monoid)
instance Show LaTeX where
show = latexToString
class ToLatex a where
toLatex :: a -> LaTeX
toLatexString :: a -> String
toLatexString = latexToString . toLatex
instance ToLatex Program where
toLatex (Program bindings) =
"\\Big\\{ " <> toLatex (Formation bindings) <> " \\Big\\}"
instance ToLatex Attribute where
toLatex Phi = "@"
toLatex Rho = "^"
toLatex (Alpha (AlphaIndex a)) = LaTeX ("\\alpha_" ++ tail a)
toLatex (Label (LabelId l)) = LaTeX l
toLatex (MetaAttr (LabelMetaId l)) = LaTeX l
instance ToLatex Binding where
toLatex (AlphaBinding attr obj) = toLatex attr <> " -> " <> toLatex obj
toLatex (EmptyBinding attr) = toLatex attr <> " -> ?"
toLatex (DeltaBinding (Bytes bytes)) = "D> " <> LaTeX bytes
toLatex DeltaEmptyBinding = "D> ?"
toLatex (LambdaBinding (Function fn)) = "L> " <> LaTeX fn
toLatex (MetaBindings (BindingsMetaId x)) = LaTeX x
toLatex (MetaDeltaBinding (BytesMetaId x)) = "D> " <> LaTeX x
instance ToLatex Object where
toLatex (Formation bindings) =
"[[ " <> fold (intersperse ", " (map toLatex bindings)) <> " ]]"
toLatex (Application obj bindings) =
toLatex obj <> "( " <> fold (intersperse ", " (map toLatex bindings)) <> " )"
toLatex (ObjectDispatch obj attr) =
toLatex obj <> "." <> toLatex attr
toLatex GlobalObject = "Q"
toLatex ThisObject = "\\xi"
toLatex Termination = "\\dead"
toLatex (MetaObject (ObjectMetaId metaId)) = LaTeX metaId
toLatex MetaTailContext{} = error "rendering MetaTailContext in LaTex format"
toLatex (MetaFunction _ _) = error "rendering MetaFunction in LaTex format"
toLatex (MetaSubstThis obj1 obj2) = LaTeX "\\mathbb{S}(" <> toLatex obj1 <> ", " <> toLatex obj2 <> ")"
toLatex (MetaContextualize obj1 obj2) = LaTeX "\\lceil" <> toLatex obj1 <> ", " <> toLatex obj2 <> "\\rceil"
toLatex (ConstString string) = "|" <> LaTeX (show string) <> "|"
toLatex (ConstInt n) = LaTeX (show n)
toLatex (ConstFloat x) = LaTeX (show x)
removeOrgEolang :: String -> String
removeOrgEolang = T.unpack . T.replace "Q.org.eolang" "QQ" . T.pack
substituteTau :: String -> String
substituteTau = T.unpack . T.replace "τ" "\\tau" . T.pack
removeExclamationsMarks :: String -> String
removeExclamationsMarks = filter (/= '!')
removeAlpha :: String -> String
removeAlpha s = subRegex (mkRegex "\\\\alpha_([0-9]+) ->") s "\\1->"
-- >>> toLatex ("{ ⟦ α0 ↦ ξ, α1 ↦ Φ.org.eolang.bytes( Δ ⤍ 00- ) ⟧ }" :: Program)
-- \Big\{ [[ 0-> $, 1-> QQ.bytes( D> 00- ) ]] \Big\}
latexToString :: LaTeX -> String
latexToString = removeExclamationsMarks . substituteTau . removeAlpha . removeOrgEolang . unLaTeX
inMathMode :: LaTeX -> LaTeX
inMathMode = (" $ " <>) . (<> " $ ")
-- it's ok without separators here because rules have zero or one constraint from the context
instance ToLatex RuleContext where
toLatex RuleContext{..} =
maybe mempty (\x -> inMathMode $ toLatex GlobalObject <> " -> " <> toLatex x) global_object
<> maybe mempty (\x -> inMathMode (toLatex x) <> " is the scope of the redex") current_object
<> maybe mempty (\x -> toLatex x <> " is the current attribute") current_attribute
instance ToLatex RuleAttribute where
toLatex (ObjectAttr a) = toLatex a
toLatex DeltaAttr = "\\Delta"
toLatex LambdaAttr = "\\lambda"
instance ToLatex Condition where
toLatex (IsNF nf) = inMathMode $ toLatex nf <> "\\in\\mathcal{N}"
toLatex (IsNFInsideFormation nf_inside_formation) =
inMathMode (toLatex nf_inside_formation) <> " is nf inside formation"
toLatex (PresentAttrs (AttrsInBindings attrs bindings)) =
inMathMode $ fold (intersperse ", " (map toLatex attrs)) <> " \\in " <> foldMap toLatex bindings
toLatex (AbsentAttrs (AttrsInBindings attrs bindings)) =
inMathMode $ fold (intersperse ", " (map toLatex attrs)) <> " \\notin " <> foldMap toLatex bindings
toLatex (AttrNotEqual (attr1, attr2)) =
inMathMode $ toLatex attr1 <> " \\neq " <> toLatex attr2
toLatex (ApplyInSubformations apply_in_subformations) =
if not apply_in_subformations then LaTeX "not in subformations" else mempty
toLatex (ApplyInAbstractSubformations apply_in_abstract_subformations) =
if not apply_in_abstract_subformations then LaTeX "not in subformations" else mempty
isNonEmptyContext :: Maybe RuleContext -> Bool
isNonEmptyContext Nothing = False
isNonEmptyContext (Just (RuleContext Nothing Nothing Nothing)) = False
isNonEmptyContext _ = True
-- Renders all conditions on separate lines
instance ToLatex Rule where
toLatex (Rule name _ context _ pattern result _ when _) =
"\\rrule{"
<> LaTeX name
<> "}: &"
<> inMathMode (toLatex pattern)
<> "\\(\\trans\\)"
<> inMathMode (toLatex result)
<> (if not (null when) || isNonEmptyContext context then "\\\\\\text {if }" else mempty)
<> maybe mempty (\c -> "&" <> toLatex c <> "\\\\") context
<> fold (intersperse ",\\\\" (maybe [] (map (("&" <>) . toLatex)) when))
instance ToLatex [Rule] where
toLatex rules =
"\\begin{figure*}\n\\begin{tabular}{rl}\n "
<> fold (intersperse "\\\\\\\\\n " (map toLatex rules))
<> "\n\\end{tabular}\n\\end{figure*}"
-- Renders all conditions in one line
ruleToLatexCompact :: Rule -> LaTeX
ruleToLatexCompact (Rule name _ context _ pattern result _ when _) =
"\\rrule{"
<> LaTeX name
<> "}: "
<> inMathMode (toLatex pattern)
<> "\\(\\trans\\)"
<> inMathMode (toLatex result)
<> (if not (null when) || isNonEmptyContext context then "\\quad\\text {if }" else "")
<> maybe mempty (\c -> toLatex c <> ", ") context
<> fold (intersperse ", " (maybe [] (map toLatex) when))
rulesToLatexCompact :: [Rule] -> LaTeX
rulesToLatexCompact rules =
"\\begin{figure*}\n "
<> fold (intersperse "\\\\\\vspace*{0.5em}\n " (map ruleToLatexCompact rules))
<> "\n\\end{figure*}"