packages feed

MicroHs-0.15.0.0: lib/Mhs/Reflect.hs

module Mhs.Reflect where
import Data.Int
import Data.Word
import System.IO.Serialize
import System.IO.StringHandle

newtype Exp a = Exp UExp
  deriving (Eq, Show)

type Label = Int

data UExp
  = App UExp UExp
  | Lit Literal
  | Lbl Label UExp
  | Ref Label
  deriving (Eq, Show)

data Literal
  = Prim    String
  | Int     Int
  | Int64   Int64
  | Integer Integer
  | Bytes   [Word8]
  | Float   Float
  | Double  Double
  deriving (Eq, Show)

reflect :: a -> IO (Exp a)
reflect a = Exp . parse . dropHeader <$> handleWriteToString (\ h -> hSerialize h a)

-- The first two lines are version and number of definitions
dropHeader = dropWhile (/= '\n') . drop 1 . dropWhile (/= '\n')

str :: a -> IO String
str a = handleWriteToString (\ h -> hSerialize h a)

parse :: String -> UExp
parse = parseStk []
  where
    nonSP c = c /= ' ' && c /= '\n'
    lit stk con cs =
      case span nonSP cs of
        (p, cs') -> parseStk (Lit (con p) : stk) cs'
    parseStk stk [] = error "parse: EOF"
    parseStk stk (c:cs) =
      case c of
        ' '  -> parseStk stk cs
        '\n' -> parseStk stk cs
        '@'  -> case stk of
                  x:y:stk' -> parseStk (App y x : stk') cs
                  _ -> error "parse: App"
        '}'  -> case stk of
                  [x] -> x
                  _ -> error "parse: }"
        '%' -> lit stk (Integer . read) cs
        '&' | '&':cs' <- cs -> lit stk (Float  . read) cs'
            | otherwise     -> lit stk (Double . read) cs
        '#' | '#':cs' <- cs -> lit stk (Int64  . read) cs'
            | otherwise     -> lit stk (Int    . read) cs
        '[' -> undefined -- array
        '_' ->
          case span nonSP cs of
            (l, cs') -> parseStk (Ref (read l) : stk) cs'
        ':' ->
          case span nonSP cs of
            (l, cs') ->
              case stk of
                x : stk' -> parseStk (Lbl (read l) x : stk') cs'
                _ -> error "parse: :"
        '"' ->
          case getString cs of
            (s, cs') -> parseStk (Lit (Bytes s) : stk) cs'
        '^' -> undefined -- FFI
        ';' -> undefined -- C function pointer
        _   -> lit stk Prim (c:cs)
          
    getString :: String -> ([Word8], String)
    getString = get []
      where
        get :: [Word8] -> String -> ([Word8], String)
        get _ [] = error "getString"
        get bs ('"':cs) = (reverse bs, cs)
        get bs ('\\':'?':cs) = get (0x7f : bs) cs
        get bs ('\\':'_':cs) = get (0xff : bs) cs
        get bs ('\\':  c:cs) = get (byte c : bs) cs
        get bs ('^':c:cs)    = get (b : bs) cs
          where b | d < 0x40  =  d `rem` 0x20
                  | otherwise = (d `rem` 0x20) + 0x80
                d = byte c
        get bs ('|':c:cs)    = get (byte c + 0x80 : bs) cs
        get bs (c:cs)        = get (byte c : bs) cs
    byte :: Char -> Word8
    byte = fromIntegral . fromEnum

main :: IO ()
main = do
  let f x = x+1 :: Int
  print (f 5)
  x <- reflect (f)
  print x