-
Notifications
You must be signed in to change notification settings - Fork 2
/
Parse.hs
135 lines (111 loc) · 4.71 KB
/
Parse.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
module Parse where
import Control.Applicative
import Control.Monad
import Data.Char
import Data.Maybe
import SExp
import Syntax
type Parse = Either String
parseModule :: SExp -> Parse Module
parseModule src = mapM parseDecl =<< expectList "module" src
parseDecl :: SExp -> Parse Decl
parseDecl src = do
list <- expectList "declaration" src
case list of
SymS "def":nameSym:body -> do
name <- expectSym "top-level variable" nameSym
VarD (stringVar name) <$> parseDo body
_ -> Left $ "unknown type of declaration: " ++ show src
parseExpr :: SExp -> Parse Expr
parseExpr src = case src of
SymS sym -> return $ Ref $ stringVar sym
LitS (SExp.IntL k) -> return $ Lit (Syntax.IntL $ fromIntegral k)
LitS (SExp.StringL k) -> return $ Lit (Syntax.StringL k)
ListS (hd:rest) -> case hd of
-- "do" translates to Let, "let" translates to Letrec.
SymS "do" -> parseDo rest
SymS "let" -> parseLet rest
SymS "\\" -> parseLam rest
SymS "case" -> parseCase rest
SymS "<-" -> parseAssign rest
SymS "while" -> parseWhile rest
SymS "js" -> parseJS rest
SymS "typed" -> parseTyped rest
_ -> App <$> parseExpr hd <*> mapM parseExpr rest
_ -> Left $ "unknown type of expression: " ++ show src
parseDo, parseLet, parseLam, parseCase, parseAssign, parseWhile, parseJS, parseTyped :: [SExp] -> Parse Expr
parseDo [] = Left "empty do expression"
parseDo list = do
stmts <- mapM parseStmt list
let (si, sl) = (init stmts, last stmts)
lst <- case sl of
ExpStmt exp -> return exp
_ -> Left $ "do expression must end with an expression: " ++ show list
return $ foldr toLet lst si
where
toLet stmt body = case stmt of
ExpStmt exp -> Let UnitP exp body
BindStmt pat exp -> Let pat exp body
data Stmt = ExpStmt Expr | BindStmt Pat Expr
parseStmt :: SExp -> Parse Stmt
parseStmt src = parseBindStmt src `orElse` (ExpStmt <$> parseExpr src)
parseBindStmt :: SExp -> Parse Stmt
parseBindStmt src = do
list <- expectList "bind statement" src
case list of
[pat,SymS "=", body] -> BindStmt <$> parsePat pat <*> parseExpr body
_ -> Left "malformed bind statement"
parseLet _ = Left $ "sorry, let expression is not supported yet"
parseLam list = case break isRightArrow list of
(paramSrcs, _:body) -> do
pats <- mapM parsePat paramSrcs
params <- forM pats $ \pat -> case pat of
VarP var -> return var
_ -> Left $ "sorry, you can't bind a non-variable pattern in a lambda yet"
Lam params <$> parseDo body
_ -> Left $ "malformed lambda: " ++ show list
where
isRightArrow (SymS "->") = True
isRightArrow _ = False
parseCase [] = Left "empty case"
parseCase (scr:branchSrcs) = Case <$> parseExpr scr <*> mapM parseBranch branchSrcs
parseBranch :: SExp -> Parse Branch
parseBranch (ListS (pat:body)) = (,) <$> parsePat pat <*> parseDo body
parseBranch list = Left $ "malformed branch: " ++ show list
parseAssign [pat, exp] = Assign <$> parsePat pat <*> parseExpr exp
parseAssign list = Left $ "malformed assignment: " ++ show list
parseWhile [] = Left "empty while"
parseWhile (cond:body) = While <$> parseExpr cond <*> parseDo body
parseJS [LitS (SExp.StringL js)] = return $ JS js
parseJS list = Left $ "malformed js embedding: " ++ show list
parseTyped [exp, ty] = Typed <$> parseExpr exp <*> parseType ty
parseTyped list = Left $ "malformed ::: " ++ show list
parsePat :: SExp -> Parse Pat
parsePat src = case src of
SymS k
| isConstructorSymbol k -> return $ ConstructorP (stringVar k) []
| otherwise -> return $ VarP (stringVar k)
LitS (SExp.IntL k) -> return $ IntP (fromIntegral k)
LitS (SExp.StringL k) -> return $ StringP k
ListS [] -> return UnitP
ListS (SymS hd:args)
| isConstructorSymbol hd -> ConstructorP (stringVar hd) <$> mapM parsePat args
_ -> Left $ "malformed pattern: " ++ show src
where
isConstructorSymbol = maybe False isUpper . listToMaybe
parseType :: SExp -> Parse Type
parseType src = case src of
SymS k -> return $ ConstT (stringVar k) -- no way to write a type variable, for now
ListS (hd:args) -> AppT <$> parseType hd <*> mapM parseType args
_ -> Left $ "malformed type expression: " ++ show src
expectList :: String -> SExp -> Parse [SExp]
expectList desc sexp = case sexp of
ListS list -> return list
_ -> Left $ desc ++ ": expecting a list but got " ++ show sexp
expectSym :: String -> SExp -> Parse String
expectSym desc sexp = case sexp of
SymS sym -> return sym
_ -> Left $ desc ++ ": expecting a symbol but got " ++ show sexp
orElse :: Parse a -> Parse a -> Parse a
orElse Left{} x = x
orElse x _ = x