axel-0.0.1: src/Axel/Parse/AST.hs
-- NOTE Because this file will be used as the header of auto-generated macro programs,
-- it can't have any project-specific dependencies (such as `Fix`).
module Axel.Parse.AST where
import Data.IORef (IORef, modifyIORef, newIORef, readIORef)
import System.IO.Unsafe (unsafePerformIO)
-- TODO `Expression` should probably be `Traversable`, use recursion schemes, etc.
-- I should provide `toFix` and `fromFix` functions for macros to take advantage of.
-- (Maybe all macros have the argument automatically `fromFix`-ed to make consumption simpler?)
data Expression
= LiteralChar Char
| LiteralInt Int
| LiteralString String
| SExpression [Expression]
| Symbol String
deriving (Eq, Show)
-- ******************************
-- Internal utilities
-- ******************************
toAxel :: Expression -> String
toAxel (LiteralChar x) = ['\\', x]
toAxel (LiteralInt x) = show x
toAxel (LiteralString xs) = "\"" ++ xs ++ "\""
toAxel (SExpression xs) = "(" ++ unwords (map toAxel xs) ++ ")"
toAxel (Symbol x) = x
-- ******************************
-- Macro definition utilities
-- ******************************
{-# NOINLINE gensymCounter #-}
gensymCounter :: IORef Int
gensymCounter = unsafePerformIO $ newIORef 0
gensym :: IO Expression
gensym = do
suffix <- readIORef gensymCounter
let identifier = "aXEL_AUTOGENERATED_IDENTIFIER_" ++ show suffix
modifyIORef gensymCounter succ
pure $ Symbol identifier