packages feed

zwirn-0.2.2.0: src/zwirn-lang/Zwirn/Language/Macro.hs

module Zwirn.Language.Macro where

import Control.Monad.State (StateT, lift, modify, runStateT)
import qualified Data.Map as Map
import qualified Data.Text as T
import Zwirn.Language.Location (Located (..), RealSrcLoc (..), SrcLoc (..))
import Zwirn.Language.Pretty (ppterm)
import Zwirn.Language.Syntax (LocTerm, Term (..))

type MacroMap = Map.Map T.Text LocTerm

-- represents the code edit that replaces the text at editPos with editText
data CodeEdit = CodeEdit
  { editPos :: RealSrcLoc,
    editText :: T.Text
  }
  deriving (Eq, Show)

-- a simple monad that accumulates code edits
type MacroMonad = StateT [CodeEdit] Maybe

defaultMacroMap :: MacroMap
defaultMacroMap = Map.fromList [("num", Located (SrcLoc (RealSrcLoc "internal" 0 0 0 1)) (TNum "1"))]

runMacros :: LocTerm -> MacroMap -> Maybe (LocTerm, [CodeEdit])
runMacros t mmap = runStateT (substituteMacros mmap t) []

substituteMacros :: MacroMap -> LocTerm -> MacroMonad LocTerm
substituteMacros _ t@(Located _ (TNum _)) = return t
substituteMacros _ t@(Located _ (TText _)) = return t
substituteMacros _ t@(Located _ (TVar _)) = return t
substituteMacros ms (Located (SrcLoc oldPos@(RealSrcLoc doc stln stch _ _)) (TMacro name)) = do
  (Located p m) <- lift $ Map.lookup name ms
  let replace = ppterm m
  case p of
    NoLoc -> lift Nothing
    SrcLoc (RealSrcLoc _ stln' _ enln' ench') -> do
      let newPos = RealSrcLoc doc stln stch (stln + (enln' - stln')) ench'
          edit = CodeEdit oldPos replace
      modify (edit :)
      return $ Located (SrcLoc newPos) m
substituteMacros _ t@(Located _ TRest) = return t
substituteMacros ms (Located p (TBracket t)) = do
  s <- substituteMacros ms t
  return $ Located p (TBracket s)
substituteMacros ms (Located p (TRepeat t i)) = do
  s <- substituteMacros ms t
  return $ Located p (TRepeat s i)
substituteMacros ms (Located p (TLambda x t)) = do
  s <- substituteMacros ms t
  return $ Located p (TLambda x s)
substituteMacros ms (Located p (TSectionL t x)) = do
  s <- substituteMacros ms t
  return $ Located p (TSectionL s x)
substituteMacros ms (Located p (TSectionR x t)) = do
  s <- substituteMacros ms t
  return $ Located p (TSectionR x s)
substituteMacros ms (Located p (TSeq ts)) = do
  ss <- mapM (substituteMacros ms) ts
  return $ Located p (TSeq ss)
substituteMacros ms (Located p (TStack ts)) = do
  ss <- mapM (substituteMacros ms) ts
  return $ Located p (TStack ss)
substituteMacros ms (Located p (TAlt ts)) = do
  ss <- mapM (substituteMacros ms) ts
  return $ Located p (TAlt ss)
substituteMacros ms (Located p (TChoice i ts)) = do
  ss <- mapM (substituteMacros ms) ts
  return $ Located p (TChoice i ss)
substituteMacros ms (Located p (TPoly t1 t2)) = do
  s1 <- substituteMacros ms t1
  s2 <- substituteMacros ms t2
  return $ Located p (TPoly s1 s2)
substituteMacros ms (Located p (TApp t1 t2)) = do
  s1 <- substituteMacros ms t1
  s2 <- substituteMacros ms t2
  return $ Located p (TApp s1 s2)
substituteMacros ms (Located p (TInfix t1 n t2)) = do
  s1 <- substituteMacros ms t1
  s2 <- substituteMacros ms t2
  return $ Located p (TInfix s1 n s2)
substituteMacros ms (Located p (TIfThenElse t1 t2 Nothing)) = do
  s1 <- substituteMacros ms t1
  s2 <- substituteMacros ms t2
  return $ Located p (TIfThenElse s1 s2 Nothing)
substituteMacros ms (Located p (TEnum k t1 t2)) = do
  s1 <- substituteMacros ms t1
  s2 <- substituteMacros ms t2
  return $ Located p (TEnum k s1 s2)
substituteMacros ms (Located p (TEnumThen k t1 t2 t3)) = do
  s1 <- substituteMacros ms t1
  s2 <- substituteMacros ms t2
  s3 <- substituteMacros ms t3
  return $ Located p (TEnumThen k s1 s2 s3)
substituteMacros ms (Located p (TIfThenElse t1 t2 (Just t3))) = do
  s1 <- substituteMacros ms t1
  s2 <- substituteMacros ms t2
  s3 <- substituteMacros ms t3
  return $ Located p (TIfThenElse s1 s2 (Just s3))
substituteMacros _ _ = lift Nothing