Skip to content

Commit 43a97a6

Browse files
committedJan 19, 2015
attoparsec and operators
1 parent 5183e19 commit 43a97a6

File tree

6 files changed

+355
-9
lines changed

6 files changed

+355
-9
lines changed
 

‎008_extended_parser.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ bit of a riddle about this error came to be.
329329

330330
```haskell
331331
Cannot unify types:
332-
Int
332+
Int
333333
with
334334
Bool
335335
in the definition of 'foo'
@@ -462,14 +462,14 @@ them. Before we'd have a little riddle in order to guess which
462462

463463
```haskell
464464
Cannot unify types:
465-
Int
466-
Introduced at line 27 column 5
465+
Int
466+
Introduced at line 27 column 5
467467

468468
f 2 3
469469

470470
with
471-
Int -> c
472-
Introduced at line 5 column 9
471+
Int -> c
472+
Introduced at line 5 column 9
473473

474474
let f x y = x y
475475
```
@@ -738,6 +738,6 @@ parser is rather sophisicated.
738738
One of the few papers ever written in Type Error reporting gives some techniques
739739
for presentation and tracing provenance:
740740

741-
* [Top Quality Type Error Messages](www.staff.science.uu.nl/~swier101/Papers/Theses/TopQuality.pdf)
741+
* [Top Quality Type Error Messages](http://www.staff.science.uu.nl/~swier101/Papers/Theses/TopQuality.pdf)
742742

743743
\clearpage

‎Makefile

+16-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,21 @@ FILTER = includes.hs
77
TEMPLATE_HTML = template.html
88
TEMPLATE_TEX = template.latex
99

10-
SRC = $(wildcard *.md)
10+
#SRC = $(wildcard *.md)
11+
SRC = 000_introduction.md \
12+
001_basics.md \
13+
002_parsers.md \
14+
003_lambda_calculus.md \
15+
004_type_systems.md \
16+
005_evaluation.md \
17+
006_hindley_milner.md \
18+
007_path.md \
19+
008_extended_parser.md \
20+
009_datatypes.md \
21+
010_renamer.md \
22+
011_pattern_matching.md \
23+
#012_systemf.md
24+
#026_llvm.md
1125
OBJ = $(SRC:.md=.html)
1226

1327
all: $(OBJ) top
@@ -23,7 +37,7 @@ all: $(OBJ) top
2337

2438
pdf: $(FILTER)
2539
# $(PANDOC) --filter ${FILTER} -f $(IFORMAT) --template $(TEMPLATE_TEX) --latex-engine=xelatex $(FLAGS) -o WYAH.pdf title.md 0*.md contributing.md
26-
$(PANDOC) --filter ${FILTER} -f $(IFORMAT) --template $(TEMPLATE_TEX) --latex-engine=xelatex $(FLAGS) -o WYAH.pdf title.md 0*.md
40+
$(PANDOC) --filter ${FILTER} -f $(IFORMAT) --template $(TEMPLATE_TEX) --latex-engine=xelatex $(FLAGS) -o WYAH.pdf title.md $(SRC)
2741

2842
epub: $(FILTER)
2943
$(PANDOC) --filter ${FILTER} -f $(IFORMAT) $(FLAGS) -o WYAH.epub 0*.md

‎chapter7/poly/Infer.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ infer env ex = case ex of
165165
(s2, t2) <- infer env tr
166166
(s3, t3) <- infer env fl
167167
s4 <- unify (apply (compose s2 s3) t1) typeBool
168-
s5 <- unify (apply s4 t2) (apply s4 t3)
168+
s5 <- unify (apply (compose s1 s4) t2) (apply (compose s1 s4) t3)
169169
let s6 = s4 `compose` s5
170170
return (s6, apply s6 t2)
171171

‎chapter9/attoparsec/Main.hs

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
3+
4+
import Control.Applicative
5+
import Data.Attoparsec.Text
6+
import qualified Data.Text as T
7+
import qualified Data.Text.IO as T
8+
import Data.List (foldl1')
9+
10+
data Name
11+
= Gen Int
12+
| Name T.Text
13+
deriving (Eq, Show, Ord)
14+
15+
data Expr
16+
= Var Name
17+
| App Expr Expr
18+
| Lam [Name] Expr
19+
| Lit Int
20+
| Prim PrimOp
21+
deriving (Eq, Show)
22+
23+
data PrimOp
24+
= Add
25+
| Sub
26+
| Mul
27+
| Div
28+
deriving (Eq, Show)
29+
30+
data Defn = Defn Name Expr
31+
deriving (Eq, Show)
32+
33+
name :: Parser Name
34+
name = Name . T.pack <$> many1 letter
35+
36+
num :: Parser Expr
37+
num = Lit <$> signed decimal
38+
39+
var :: Parser Expr
40+
var = Var <$> name
41+
42+
lam :: Parser Expr
43+
lam = do
44+
string "\\"
45+
vars <- many1 (skipSpace *> name)
46+
skipSpace *> string "->"
47+
body <- expr
48+
return (Lam vars body)
49+
50+
eparen :: Parser Expr
51+
eparen = char '(' *> expr <* skipSpace <* char ')'
52+
53+
prim :: Parser Expr
54+
prim = Prim <$> (
55+
char '+' *> return Add
56+
<|> char '-' *> return Sub
57+
<|> char '*' *> return Mul
58+
<|> char '/' *> return Div)
59+
60+
expr :: Parser Expr
61+
expr = foldl1' App <$> many1 (skipSpace *> atom)
62+
63+
atom :: Parser Expr
64+
atom = try lam
65+
<|> eparen
66+
<|> prim
67+
<|> var
68+
<|> num
69+
70+
def :: Parser Defn
71+
def = do
72+
skipSpace
73+
nm <- name
74+
skipSpace *> char '=' *> skipSpace
75+
ex <- expr
76+
skipSpace <* char ';'
77+
return $ Defn nm ex
78+
79+
file :: T.Text -> Either String [Defn]
80+
file = parseOnly (many def <* skipSpace)
81+
82+
parseFile :: FilePath -> IO (Either T.Text [Defn])
83+
parseFile path = do
84+
contents <- T.readFile path
85+
case file contents of
86+
Left a -> return $ Left (T.pack a)
87+
Right b -> return $ Right b
88+
89+
main :: IO (Either T.Text [Defn])
90+
main = parseFile "simple.ml"

‎chapter9/operators/Parser.hs

+231
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
module Main where
2+
3+
import qualified Text.Parsec.Expr as Ex
4+
import qualified Text.Parsec.Token as Tok
5+
6+
import Text.Parsec.Language (haskellStyle)
7+
8+
import Data.List
9+
import Data.Function
10+
11+
import Control.Monad.Identity (Identity)
12+
13+
import Text.Parsec
14+
import qualified Text.Parsec as P
15+
16+
type Name = String
17+
18+
data Expr
19+
= Var Name
20+
| Lam Name Expr
21+
| App Expr Expr
22+
| Let Name Expr Expr
23+
| BinOp Name Expr Expr
24+
| UnOp Name Expr
25+
deriving (Show)
26+
27+
data Assoc
28+
= OpLeft
29+
| OpRight
30+
| OpNone
31+
| OpPrefix
32+
| OpPostfix
33+
deriving Show
34+
35+
data Decl
36+
= LetDecl Expr
37+
| OpDecl OperatorDef
38+
deriving (Show)
39+
40+
type Op x = Ex.Operator String ParseState Identity x
41+
type Parser a = Parsec String ParseState a
42+
data ParseState = ParseState [OperatorDef] deriving Show
43+
44+
data OperatorDef = OperatorDef {
45+
oassoc :: Assoc
46+
, oprec :: Integer
47+
, otok :: Name
48+
} deriving Show
49+
50+
lexer :: Tok.GenTokenParser String u Identity
51+
lexer = Tok.makeTokenParser style
52+
where ops = ["->","\\","+","*","<","=","[","]","_"]
53+
names = ["let","in","infixl", "infixr", "infix", "postfix", "prefix"]
54+
style = haskellStyle { Tok.reservedOpNames = ops
55+
, Tok.reservedNames = names
56+
, Tok.identLetter = alphaNum <|> oneOf "#'_"
57+
, Tok.commentLine = "--"
58+
}
59+
60+
reserved = Tok.reserved lexer
61+
reservedOp = Tok.reservedOp lexer
62+
identifier = Tok.identifier lexer
63+
parens = Tok.parens lexer
64+
brackets = Tok.brackets lexer
65+
braces = Tok.braces lexer
66+
commaSep = Tok.commaSep lexer
67+
semi = Tok.semi lexer
68+
integer = Tok.integer lexer
69+
chr = Tok.charLiteral lexer
70+
str = Tok.stringLiteral lexer
71+
operator = Tok.operator lexer
72+
73+
contents :: Parser a -> Parser a
74+
contents p = do
75+
Tok.whiteSpace lexer
76+
r <- p
77+
eof
78+
return r
79+
80+
expr :: Parser Expr
81+
expr = do
82+
es <- many1 term
83+
return (foldl1 App es)
84+
85+
lambda :: Parser Expr
86+
lambda = do
87+
reservedOp "\\"
88+
args <- identifier
89+
reservedOp "->"
90+
body <- expr
91+
return $ Lam args body
92+
93+
letin :: Parser Expr
94+
letin = do
95+
reserved "let"
96+
x <- identifier
97+
reservedOp "="
98+
e1 <- expr
99+
reserved "in"
100+
e2 <- expr
101+
return (Let x e1 e2)
102+
103+
variable :: Parser Expr
104+
variable = do
105+
x <- identifier
106+
return (Var x)
107+
108+
109+
addOperator :: OperatorDef -> Parser ()
110+
addOperator a = P.modifyState $ \(ParseState ops) -> ParseState (a : ops)
111+
112+
mkTable :: ParseState -> [[Op Expr]]
113+
mkTable (ParseState ops) =
114+
map (map toParser) $
115+
groupBy ((==) `on` oprec) $
116+
reverse $ sortBy (compare `on` oprec) $ ops
117+
118+
toParser :: OperatorDef -> Op Expr
119+
toParser (OperatorDef ass _ tok) = case ass of
120+
OpLeft -> infixOp tok (BinOp tok) (toAssoc ass)
121+
OpRight -> infixOp tok (BinOp tok) (toAssoc ass)
122+
OpNone -> infixOp tok (BinOp tok) (toAssoc ass)
123+
OpPrefix -> prefixOp tok (UnOp tok)
124+
OpPostfix -> postfixOp tok (UnOp tok)
125+
where
126+
toAssoc OpLeft = Ex.AssocLeft
127+
toAssoc OpRight = Ex.AssocRight
128+
toAssoc OpNone = Ex.AssocNone
129+
toAssoc _ = error "no associativity"
130+
131+
infixOp :: String -> (a -> a -> a) -> Ex.Assoc -> Op a
132+
infixOp x f = Ex.Infix (reservedOp x >> return f)
133+
134+
prefixOp :: String -> (a -> a) -> Ex.Operator String u Identity a
135+
prefixOp name f = Ex.Prefix (reservedOp name >> return f)
136+
137+
postfixOp :: String -> (a -> a) -> Ex.Operator String u Identity a
138+
postfixOp name f = Ex.Postfix (reservedOp name >> return f)
139+
140+
term :: Parser Expr
141+
term = do
142+
tbl <- getState
143+
let table = mkTable tbl
144+
Ex.buildExpressionParser table aexp
145+
146+
aexp :: Parser Expr
147+
aexp = letin
148+
<|> lambda
149+
<|> variable
150+
<|> parens expr
151+
152+
letdecl :: Parser Decl
153+
letdecl = do
154+
e <- expr
155+
return $ LetDecl e
156+
157+
158+
opleft :: Parser Decl
159+
opleft = do
160+
reserved "infixl"
161+
prec <- integer
162+
sym <- parens operator
163+
let op = (OperatorDef OpLeft prec sym)
164+
addOperator op
165+
return $ OpDecl op
166+
167+
opright :: Parser Decl
168+
opright = do
169+
reserved "infixr"
170+
prec <- integer
171+
sym <- parens operator
172+
let op = (OperatorDef OpRight prec sym)
173+
addOperator op
174+
return $ OpDecl op
175+
176+
opnone :: Parser Decl
177+
opnone = do
178+
reserved "infix"
179+
prec <- integer
180+
sym <- parens operator
181+
let op = (OperatorDef OpNone prec sym)
182+
addOperator op
183+
return $ OpDecl op
184+
185+
opprefix :: Parser Decl
186+
opprefix = do
187+
reserved "prefix"
188+
prec <- integer
189+
sym <- parens operator
190+
let op = OperatorDef OpPrefix prec sym
191+
addOperator op
192+
return $ OpDecl op
193+
194+
oppostfix :: Parser Decl
195+
oppostfix = do
196+
reserved "postfix"
197+
prec <- integer
198+
sym <- parens operator
199+
let op = OperatorDef OpPostfix prec sym
200+
addOperator op
201+
return $ OpDecl op
202+
203+
decl :: Parser Decl
204+
decl =
205+
try letdecl
206+
<|> opleft
207+
<|> opright
208+
<|> opnone
209+
<|> opprefix
210+
<|> oppostfix
211+
212+
top :: Parser Decl
213+
top = do
214+
x <- decl
215+
P.optional semi
216+
return x
217+
218+
219+
modl :: Parser [Decl]
220+
modl = many top
221+
222+
parseModule :: SourceName -> String -> Either ParseError [Decl]
223+
parseModule filePath = P.runParser (contents modl) (ParseState []) filePath
224+
225+
main :: IO ()
226+
main = do
227+
input <- readFile "test.in"
228+
let res = parseModule "<stdin>" input
229+
case res of
230+
Left err -> print err
231+
Right ast -> mapM_ print ast

‎chapter9/operators/test.fun

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
infixl 3 ($);
2+
infixr 4 (#);
3+
4+
infix 4 (.);
5+
6+
prefix 10 (-);
7+
postfix 10 (!);
8+
9+
let a = y in a $ a $ (-a)!;
10+
let b = y in a # a # a $ b;
11+
let c = y in a # a # a # b;

0 commit comments

Comments
 (0)
Please sign in to comment.