Advertisement
Guest User

Anonymous III

a guest
Aug 17th, 2009
270
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Haskell 10.48 KB | None | 0 0
  1. --
  2. -- lisp0.hs
  3. --
  4. -- Compilation:
  5. --
  6. --   ghc -XTemplateHaskell --make -O lisp0.hs lisp1.hs lisp2.hs lisp3.hs -o test
  7. --
  8. module HSLispDecl where
  9.  
  10. data LispV =    LispCons  LispV LispV
  11.            |    LispInt Integer
  12.            |    LispString String
  13.            |    LispSymbol String
  14.            |    LispFun ([LispV] -> IO LispV)
  15.            |    LispNIL
  16.            |    LispT
  17.            |    LispF
  18.  
  19. data LispAst =  LAapply LispAst [LispAst]
  20.              |  LAconst LispV
  21.              |  LAvar   String
  22.              |  LAglobfun String
  23.              |  LAfun   [String] LispAst
  24.              |  LAblock [LispAst]
  25.              |  LAif    LispAst LispAst LispAst
  26.              |  LAlet   String LispAst LispAst deriving (Show)
  27.  
  28. data LispTop =  LAdefun String [String] LispAst
  29.              |  LAexpr   LispAst deriving (Show)
  30.  
  31. --
  32. -- Translating core Lisp lists into a Lisp AST
  33. --
  34.  
  35. expr2AST :: LispV -> LispAst
  36.  
  37. expr2AST (LispCons (LispSymbol "lambda")
  38.                        (LispCons args body)) = compLambda args body
  39. expr2AST (LispCons (LispSymbol "if")
  40.                    (LispCons cnd
  41.                     (LispCons iftr LispNIL))) = compIf2 cnd iftr
  42. expr2AST (LispCons (LispSymbol "if")
  43.                    (LispCons cnd
  44.                     (LispCons iftr
  45.                      (LispCons iffl LispNIL)))) = compIf3 cnd iftr iffl
  46. expr2AST (LispCons (LispSymbol "quote")
  47.                    (LispCons v LispNIL)) = LAconst v
  48. expr2AST (LispCons (LispSymbol "begin") body) = compBody body
  49. expr2AST (LispCons (LispSymbol "let")
  50.                    (LispCons letdefs letbody)) = compLet letdefs letbody
  51. expr2AST (LispCons fn args) = compApp fn args
  52. expr2AST (LispSymbol s) = LAvar s
  53. expr2AST other = LAconst other
  54.  
  55. expr2TOP (LispCons (LispSymbol "defun")
  56.                    (LispCons (LispSymbol nm)
  57.                              (LispCons args
  58.                                        body))) = compDefun nm args body
  59. expr2TOP other = LAexpr (expr2AST other)
  60.  
  61. compDefun nm args body = LAdefun nm (map lispGetArg (lisp2list args))
  62.                                  (compBody body)
  63.  
  64. compLambda args body = LAfun (map lispGetArg (lisp2list args)) (compBody body)
  65. compIf2 cnd iftr = compIf3 cnd iftr LispNIL
  66. compIf3 cnd iftr iffl = LAif (expr2AST cnd) (expr2AST iftr) (expr2AST iffl)
  67. compBody (LispCons v LispNIL) = expr2AST v
  68. compBody LispNIL = expr2AST LispNIL
  69. compBody other = LAblock (map expr2AST (lisp2list other))
  70. compApp fn args = LAapply (expr2AST fn) (map expr2AST (lisp2list args))
  71. compLet (LispCons (LispCons (LispSymbol nm) (LispCons v LispNIL))
  72.                   rest) body = LAlet nm (expr2AST v) (compLet rest body)
  73. compLet LispNIL body = compBody body
  74.  
  75. lisp2list (LispCons a rest) = a : (lisp2list rest)
  76. lisp2list LispNIL = []
  77.  
  78. lispGetArg (LispSymbol s) = s
  79.  
  80. --
  81. -- A couple of utility functions
  82. --
  83.  
  84.  
  85. lispList :: [LispV] -> LispV
  86. lispList (hd : tl) = LispCons hd (lispList tl)
  87. lispList [] = LispNIL
  88.  
  89. lispDottedList :: [LispV] -> LispV -> LispV
  90. lispDottedList (hd : tl) x = LispCons hd (lispDottedList tl x)
  91. lispDottedList [] x = x
  92.  
  93.  
  94. instance Show LispV where
  95.     show (LispCons a b) = "(" ++ (show a) ++ " . " ++ (show b)
  96.     show (LispInt i) = show i
  97.     show (LispString s) = "\"" ++ s ++ "\""
  98.     show (LispSymbol s) = s
  99.     show (LispFun f) = "<FUN>"
  100.     show LispNIL = "()"
  101.     show LispT = "#t"
  102.     show LispF = "#f"
  103.  
  104. -- lisp1.hs
  105. module HSLisp (compile_expr, lispApp, compile_top, sanitiseAST, sanitiseTOP) where
  106. import Language.Haskell.TH
  107. import HSLispDecl
  108.  
  109. lispApp (LispFun f) args = f args
  110.  
  111. compile_top :: LispTop -> DecQ
  112. compile_top (LAdefun nm args body) =
  113.     funD (mkName ("lisp_" ++ nm))
  114.          [(clause [(listP (map (\n -> varP (mkName n)) args))]
  115.                       (normalB (compile_expr body)) [])]
  116.  
  117. compile_expr :: LispAst -> ExpQ
  118.  
  119. compile_expr (LAapply (LAglobfun fn) args) =
  120.     do nms <- mapM (\n -> newName "a") args
  121.        ca  <- mapM compile_expr args
  122.        bo  <- appE (varE (mkName fn)) (listE (map varE nms))
  123.        return (gendefs (zip nms ca) bo)
  124.  
  125. compile_expr (LAapply fn args) =
  126.     do nms <- mapM (\n -> newName "a") (fn : args)
  127.        ca  <- mapM compile_expr (fn : args)
  128.        bo  <- appE (appE (varE (mkName "lispApp")) (varE (head nms))) (listE (map varE (tail nms)))
  129.        return (gendefs (zip nms ca) bo)
  130.  
  131. compile_expr (LAvar s) = makeret (varE (mkName s))
  132. compile_expr (LAglobfun s) = makefun (varE (mkName s))
  133.  
  134. compile_expr (LAfun args body) =
  135.     makefun (lamE [(listP (map (\n -> varP (mkName n)) args))] (compile_expr body))
  136. compile_expr (LAconst c) = compile_const c
  137. compile_expr (LAlet nm v body) =
  138.     doE [(bindS (varP (mkName nm)) (compile_expr v)),
  139.          (noBindS (compile_expr body))]
  140. compile_expr (LAif e1 e2 e3) =
  141.     do
  142.       nm1 <- newName "i"
  143.       e1' <- compile_expr e1
  144.      e2' <- compile_expr e2
  145.       e3' <- compile_expr e3
  146.      return (gendefs [(nm1,e1')]
  147.                (CaseE (VarE nm1)
  148.                       [(Match lisp_T (NormalB e2') []),
  149.                       (Match lisp_F (NormalB e3') [])]))
  150. compile_expr (LAblock exprs) =
  151.     do ca <- mapM compile_expr exprs
  152.        return (DoE (map (\e -> (NoBindS e)) ca))
  153.  
  154. makefun v =  makeret (appE (conE (mkName "LispFun")) v)
  155. makectr n v = makeret (appE (conE (mkName n)) (litE v))
  156.  
  157. compile_const (LispInt i) = makectr "LispInt" (integerL i)
  158. compile_const (LispString s) = makectr "LispString" (stringL s)
  159. compile_const (LispSymbol s) = makectr "LispSymbol" (stringL s)
  160. compile_const (LispNIL) = makeret (conE (mkName "LispNIL"))
  161. compile_const (LispT) = makeret (conE (mkName "LispT"))
  162. compile_const (LispF) = makeret (conE (mkName "LispF"))
  163. compile_const (LispCons a b) = makeret (appE (appE (conE (mkName "LispCons"))
  164.                                               (compile_const a))
  165.                                         (compile_const b))
  166.  
  167.  
  168. gendefs l bo = DoE ((map (\(a,b) -> (BindS (VarP a) b)) l) ++ [NoBindS bo])
  169.  
  170.  
  171. lisp_T = ConP (mkName "LispT") []
  172. lisp_F = ConP (mkName "LispF") []
  173.  
  174. makeret v = appE (varE (mkName "return")) v
  175.  
  176. --
  177. -- All the non-local names are considered global functions.
  178. -- There's no way to share the context between top-level definitions
  179. -- in Template Haskell.
  180. --
  181.  
  182. sanitiseAST env (LAapply a ars) = LAapply (sanitiseAST env a) (map (sanitiseAST env) ars)
  183. sanitiseAST env (LAconst c) = LAconst c
  184. sanitiseAST env (LAvar v) = if v `elem` env then (LAvar v) else (LAglobfun ("lisp_"++v))
  185. sanitiseAST env (LAglobfun v) = LAglobfun v
  186. sanitiseAST env (LAfun args b) = LAfun args (sanitiseAST (args ++ env) b)
  187. sanitiseAST env (LAblock b) = LAblock (map (sanitiseAST env) b)
  188. sanitiseAST env (LAif a b c) = LAif (sanitiseAST env a) (sanitiseAST env b) (sanitiseAST env c)
  189. sanitiseAST env (LAlet nm v b) = LAlet nm (sanitiseAST env v) (sanitiseAST (nm:env) b)
  190.  
  191.  
  192. sanitiseTOP (LAdefun nm args body) = LAdefun nm args (sanitiseAST args body)
  193. sanitiseTOP (LAexpr e) = LAexpr (sanitiseAST [] e)-- lisp2.hs
  194. module HSLispParse (parseExpr, thlisp, thlisptop, tplisp)
  195. where
  196. import Text.ParserCombinators.Parsec hiding (spaces)
  197. import HSLispDecl
  198. import HSLisp
  199. import Language.Haskell.TH
  200.  
  201.  
  202. symbol :: Parser Char
  203. symbol = oneOf "_$#"
  204.  
  205. spaces :: Parser ()
  206. spaces = skipMany1 space
  207.  
  208. parseString :: Parser LispV
  209. parseString = do char '"'
  210.                  x <- many (noneOf "\"")
  211.                  char '"'
  212.                  return $ LispString x
  213.  
  214. parseSymb :: Parser LispV
  215. parseSymb = do first <- letter <|> symbol
  216.                rest <- many (letter <|> digit <|> symbol)
  217.                let symb = [first] ++ rest
  218.                return $ case symb of
  219.                           "#t" -> LispT
  220.                           "#f" -> LispF
  221.                           otherwise -> LispSymbol symb
  222.  
  223. parseNumber :: Parser LispV
  224. parseNumber = fmap (LispInt . read) $ many1 digit
  225.  
  226. parseList :: Parser LispV
  227. parseList = fmap lispList $ sepBy parseExpr spaces
  228.  
  229. parseDottedList :: Parser LispV
  230. parseDottedList = do
  231.     head <- endBy parseExpr spaces
  232.     tail <- char '.' >> spaces >> parseExpr
  233.     return $ lispDottedList head tail
  234.  
  235. parseQuoted q1 q2 = do
  236.     char q1
  237.     x <- parseExpr
  238.     return $ lispList [LispSymbol q2, x]
  239.  
  240. parseExpr :: Parser LispV
  241. parseExpr = parseSymb
  242.         <|> parseString
  243.         <|> parseNumber
  244.         <|> (parseQuoted '\'' "quote")
  245.         <|> (parseQuoted '`' "quasiquote")
  246.         <|> (parseQuoted ',' "unquote")
  247.         <|> do char '('
  248.                x <- (try parseList) <|> parseDottedList
  249.                char ')'
  250.                return x
  251.  
  252.  
  253. thlisp :: String -> ExpQ
  254. thlisp input =
  255.     case (parse parseExpr "lisp" input) of
  256.         Left err -> compile_expr (LAconst (LispNIL))
  257.         Right val -> compile_expr (sanitiseAST [] (expr2AST val))
  258.  
  259. thlisptop :: String -> Q [Dec]
  260. thlisptop input =
  261.     do
  262.       r <-
  263.           case (parse parseExpr "lisp" input) of
  264.             Left err -> compile_top (LAexpr (LAconst (LispNIL)))
  265.             Right val -> compile_top (sanitiseTOP (expr2TOP val))
  266.       return [r]
  267.  
  268. tplisp input =
  269.     case (parse parseExpr "lisp" input) of
  270.       Left err -> compile_expr (LAconst (LispNIL))
  271.       Right val -> compile_expr (sanitiseAST [] (expr2AST val))
  272.  
  273.  
  274. -- lisp3.hs
  275. module Main where
  276. import Language.Haskell.TH
  277. import HSLispDecl
  278. import HSLisp
  279. import HSLispParse
  280.  
  281. -- Functions to be used by Lisp programs
  282. lisp_print [a] = do print a
  283.                     return LispNIL
  284.  
  285. lisp_plus [(LispInt a),(LispInt b)] = return (LispInt (a+b))
  286. lisp_mul [(LispInt a),(LispInt b)] = return (LispInt (a*b))
  287. lisp_minus [(LispInt a),(LispInt b)] = return (LispInt (a-b))
  288.  
  289. lisp_car [(LispCons a b)] = return a
  290. lisp_cdr [(LispCons a b)] = return b
  291. lisp_cons [a,b] = return (LispCons a b)
  292. lisp_nullp [LispNIL] = return LispT
  293. lisp_nullp [other] = return LispF
  294. lisp_not [LispT] = return LispF
  295. lisp_not [LispF] = return LispT
  296. lisp_eq [(LispInt a),(LispInt b)] = return (if (a==b) then LispT else LispF)
  297. lisp_eq [a,b] = return LispF
  298.  
  299. -- Toplevel Lisp definition
  300. $(thlisptop "(defun fact (x) (if (eq x 1) 1 (mul x (fact (minus x 1)))))")
  301.  
  302. -- Expression-level Lisp code
  303. main =
  304.     do
  305.       $(thlisp "(begin (print \"Hello, \") (print \" ... world!\"))")
  306.       $(thlisp "(let ((a 2) (b 2)) (print (plus a b)))")
  307.       $(thlisp "((lambda (a b) (print a) (print b) (print (plus a b))) 2 20)")
  308.       $(thlisp "(print (fact 10))")
  309.       $(thlisp "(let ((a 2) (b 3)) (print (if (eq a b) (mul a b) (plus a b))))")
  310.  
  311.       -- Inspecting the generated code:
  312.       i <- runQ (tplisp "((lambda (a b) (print a) (print b) (print (plus a b))) 2 20)")
  313.       putStrLn (pprint i)
  314.  
  315.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement