on master help sign in
Total rewrite of the parser. Removes dependency on my custom parser combinators library, and as a result, produces much better error messages. Only partially complete right now.
8805c68evancz
elm/src/Parse/Binop.hs+9−7
@@ -1,21 +1,23 @@
1module Binop (binops) where
1module Binop (binops) where
2
2
3import Ast
3import Ast
4−import Combinators
5import Control.Monad (liftM,guard)
4import Control.Monad (liftM,guard)
6import Control.Monad.Error
5import Control.Monad.Error
7import Data.List (foldl',splitAt,elemIndices,group,groupBy,sortBy,find)
6import Data.List (foldl',splitAt,elemIndices,group,groupBy,sortBy,find)
8import qualified Data.Map as Map
7import qualified Data.Map as Map
9import Data.Maybe (mapMaybe)
8import Data.Maybe (mapMaybe)
10
9
10+import Text.Parsec
11+import ParseLib
12+
11−data Assoc = L | Non | R deriving (Eq,Show)
13+data Assoc = L | N | R deriving (Eq,Show)
12
14
13table = [ (9, R, ".")
15table = [ (9, R, ".")
14 , (7, L, "*"), (7, L, "/"), (7, L, "mod")
16 , (7, L, "*"), (7, L, "/"), (7, L, "mod")
15 , (6, L, "+"), (6, L, "-")
17 , (6, L, "+"), (6, L, "-")
16 , (5, R, ":" ), (5, R, "++")
18 , (5, R, ":" ), (5, R, "++")
17− , (4, Non, "<="), (4, Non, ">="), (4, Non, "<")
19+ , (4, N, "<="), (4, N, ">="), (4, N, "<")
18− , (4, Non, "=="), (4, Non, "/="), (4, Non, ">")
20+ , (4, N, "=="), (4, N, "/="), (4, N, ">")
19 , (3, R, "&&")
21 , (3, R, "&&")
20 , (2, R, "||")
22 , (2, R, "||")
21 , (0, R, "$")
23 , (0, R, "$")
@@ -25,10 +27,10 @@ sortOps = sortBy (\(i,_,_) (j,_,_) -> compare i j)
25
27
26binops term anyOp = do
28binops term anyOp = do
27 e <- term
29 e <- term
28− (ops,es) <- liftM unzip $ star (do { op <- anyOp; e <- term; return (op,e) })
30+ (ops,es) <- liftM unzip $ many (do { op <- lexeme anyOp; e <- term; return (op,e) })
29 case binopOf Map.empty (sortOps table) ops (e:es) of
31 case binopOf Map.empty (sortOps table) ops (e:es) of
30 Right e -> return e
32 Right e -> return e
31− Left msg -> zero
33+ Left msg -> mzero
32
34
33binopSplit seen opTable i ops es =
35binopSplit seen opTable i ops es =
34 case (splitAt i ops, splitAt (i+1) es) of
36 case (splitAt i ops, splitAt (i+1) es) of
@@ -54,7 +56,7 @@ binopOf seen (tbl@((lvl, assoc, op):rest)) ops es =
54 i:_ -> case Map.lookup lvl seen of
56 i:_ -> case Map.lookup lvl seen of
55 Nothing -> binopSplit (Map.insert lvl (R,op) seen) tbl i ops es
57 Nothing -> binopSplit (Map.insert lvl (R,op) seen) tbl i ops es
56 Just (assoc',op') ->
58 Just (assoc',op') ->
57− if assoc == assoc' && assoc /= Non then
59+ if assoc == assoc' && assoc /= N then
58 binopSplit seen tbl i ops es
60 binopSplit seen tbl i ops es
59 else Left $ errorMessage lvl op assoc op' assoc'
61 else Left $ errorMessage lvl op assoc op' assoc'
60
62
elm/src/Parse/Combinators.hsdeleted−82
@@ -1,82 +0,0 @@
1−module Combinators where
2−import Control.Monad
3−import Data.Char
4−import Data.List (sortBy,foldl',foldl1')
5−
6−newtype Parser from to = Parser ([from] -> [(to,[from])])
7−--newtype Parser a = Parser (String -> [(a,String)])
8−
9−parse (Parser p) = p
10−
11−instance Monad (Parser from) where
12− return a = Parser (\cs -> [(a,cs)])
13− p >>= f = Parser (\cs -> concat [parse (f a) cs' | (a,cs') <- parse p cs])
14−
15−instance MonadPlus (Parser from) where
16− mzero = Parser $ const []
17− mplus p q = Parser (\cs -> parse p cs ++ parse q cs)
18−
19−-- True recursive descent, tries everything.
20−p +++ q = mplus p q
21−
22−-- Get the first parse.
23−p +|+ q = Parser (\cs -> case parse (mplus p q) cs of
24− [] -> []
25− (x:xs) -> [x])
26−
27−zero = Parser $ const []
28−
29−item = Parser (\cs -> case cs of
30− [] -> []
31− (c:cs) -> [(c,cs)])
32−
33−sat p = do {c <- item; if p c then return c else mzero}
34−
35−char c = sat (c ==)
36−
37−string "" = return ""
38−string (c:cs) = do {char c; string cs; return (c:cs)}
39−
40−star p = plus p +++ return []
41−plus p = do {a <- p; as <- star p; return (a:as)}
42−
43−optional p = (Just `liftM` p) +++ return Nothing
44−
45−nospace = guard . (==0) . length =<< space
46−space = star $ sat isSpace
47−space1 = plus $ sat isSpace
48−newline = do
49− star $ char ' ' +++ char '\t'
50− char '\n'
51− space
52− return ""
53−
54−digit = do {x <- sat isDigit; return (ord x - ord '0')}
55−integer = do {i <- plus digit; return $ foldl' (\a d -> 10 * a + d) 0 i}
56−
57−variable = do
58− shd <- sat isLower;
59− stl <- star $ sat (\c -> isAlphaNum c || c == '_')
60− return $ shd:stl
61−
62−sepBy sep p = sepBy1 sep p +++ return []
63−
64−sepBy1 sep p = do
65− x <- p
66− xs <- star (sep >> p)
67− return $ x:xs
68−
69−select = foldl1' (+|+)
70−
71−chainl p op a = chainl1 p op +++ return a
72−chainl1 p op = do {a <- p; rest a}
73− where
74− rest a = (do f <- op
75− b <- p
76− rest (f a b)) +++ return a
77−
78−extractResult err parse =
79− case parse of
80− (r,[]) : _ -> Right r
81− _ : rest -> extractResult err rest
82− [] -> Left err
elm/src/Parse/Lexer.hsdeleted−84
@@ -1,84 +0,0 @@
1−
2−module Lexer (tokenize) where
3−
4−import Control.Applicative ((<|>), (<$>), (<*>))
5−import Data.Char (isSymbol)
6−import Text.Parsec (Parsec, alphaNum, anyChar, char, choice, digit, eof, letter,
7− many, many1, manyTill, newline, notFollowedBy, oneOf, parse,
8− satisfy, string, try, upper)
9−import Tokens
10−import Control.Monad (liftM)
11−
12−token :: Parsec String u Token
13−token = NUMBER <$> integer
14− <|> whitespace
15− <|> chrs [ ('(',LPAREN) , (')',RPAREN)
16− , ('{',LBRACE) , ('}',RBRACE)
17− , ('[',LBRACKET), (']',RBRACKET)
18− , (',',COMMA) , (';',SEMI), ('_',UNDERSCORE)
19− , ('\\',LAMBDA) , ('\x03BB',LAMBDA) ]
20− <|> reserveds [ ("True",TRUE), ("False",FALSE)
21− , ("if",IF), ("then",THEN), ("else",ELSE)
22− , ("case",CASE), ("of",OF), ("data", DATA)
23− , ("let",LET), ("in",IN) ]
24− <|> do { char '`'; v <- variable; char '`'; return $ OP v }
25− <|> anyOp
26− <|> do { char '"'; s <- many $ backslashed <|> satisfy (/='"'); char '"'
27− ; return $ STRING s}
28− <|> do { char '\''; c <- backslashed <|> satisfy (/='\''); char '\''
29− ; return $ CHAR c}
30− <|> (ID <$> variable)
31− <|> typeVar
32− <|> do { try $ string "\r\n" <|> string "\n"; return NEWLINE }
33−
34−chrs :: [(Char, Token)] -> Parsec String u Token
35−chrs = choice . map chr
36− where chr (c, t) = char c >> return t
37−
38−reserveds :: [(String, Token)] -> Parsec String u Token
39−reserveds = choice . map reserved
40− where reserved (s, t) = try $ string s >>
41− notFollowedBy (alphaNum <|> char '_') >>
42− return t
43−
44−anyOp = do op <- many1 (satisfy isSymbol <|> oneOf "+-/*=.$<>:&|^?%#@~!")
45− case op of { ".." -> return DOT2
46− ; "->" -> return ARROW; "\8594" -> return ARROW
47− ; _ -> return $ OP op }
48−
49−backslashed :: Parsec String u Char
50−backslashed = do { char '\\'; c <- anyChar
51− ; return . read $ ['\'','\\',c,'\''] }
52−
53−integer :: Parsec String u Int
54−integer = read <$> many1 digit
55−
56−variable :: Parsec String u String
57−variable = identifier $ letter <|> char '_'
58−
59−typeVar :: Parsec String u Token
60−typeVar = TYPE <$> identifier upper
61−
62−identifier :: Parsec String u Char -> Parsec String u String
63−identifier c = (:) <$> c <*> (many $ alphaNum <|> oneOf "_\'")
64−
65−---- White Space and comments ----
66−
67−whitespace = (lineComment >> return NEWLINE) <|>
68− (many1 (multiComment <|> many1 (char ' ')) >> return SPACES)
69−lineComment = do try $ string "--"
70− manyTill anyChar $ newline <|> (eof >> return '\n')
71−
72−multiComment = do { try $ string "{-"; closeComment }
73−closeComment = manyTill anyChar . choice $
74− [ try $ string "-}"
75− , do { try $ string "{-"; closeComment; closeComment }
76− ]
77−
78−tokenParser :: Parsec String u [Token]
79−tokenParser = many1 token
80−
81−tokenize :: String -> Either String [Token]
82−tokenize s = case parse tokenParser "" s of
83− Right ts -> Right ts
84− Left err -> Left $ "Syntax error: " ++ show err
elm/src/Parse/ParseLib.hsnew file+40
@@ -0,0 +1,40 @@
1+
2+module ParseLib where
3+
4+import Ast
5+import Control.Monad
6+import Data.Char (isSymbol)
7+import Text.Parsec
8+
9+reserved = [ "if", "then", "else"
10+ , "case", "of", "data"
11+ , "let", "in" ]
12+
13+expecting = flip (<?>)
14+
15+var :: (Monad m) => ParsecT [Char] u m String
16+var = do
17+ c <- letter {-lower-} <|> char '_'
18+ cs <- many $ alphaNum <|> char '_' <|> char '\''
19+ guard $ c:cs `notElem` reserved
20+ return $ c:cs
21+
22+anyOp :: (Monad m) => ParsecT [Char] u m String
23+anyOp = many1 (satisfy isSymbol <|> oneOf "+-/*=.$<>:&|^?%#@~!")
24+
25+lexeme p = do e <- p ; whitespace ; return e
26+
27+whitespace :: (Monad m) => ParsecT [Char] u m String
28+whitespace = try $ many (char ' ')
29+
30+betwixt a b = between (char a) (char b <?> "closing '" ++ [b] ++ "'")
31+betwixtSpcs a b = between (lexeme $ char a) (char b <?> "closing '" ++ [b] ++ "'")
32+
33+listOf p = betwixtSpcs '[' ']' $ p `sepBy` lexeme (char ',')
34+
35+accessible expr = do
36+ e <- expr
37+ access <- optionMaybe (char '.')
38+ case access of
39+ Just '.' -> accessible (Access e `liftM` var)
40+ Nothing -> return e
elm/src/Parse/Parser.hs+81−82
@@ -1,115 +1,114 @@
1module Parser where
1module Parser where
2
2
3import Ast
3import Ast
4−import Binop (binops)
4+import Control.Applicative ((<$>), (<*>))
5−import Combinators
6−import Control.Monad (liftM)
5+import Control.Monad
6+import Data.Char (isSymbol, isDigit)
7import Data.List (foldl')
7import Data.List (foldl')
8−import Guid
8+import Text.Parsec
9−import Lexer
9+
10−import ParserLib
10+import ParseLib
11−import ParseTypes (datatype)
12−import ParsePatterns
13−import Tokens
11+import Patterns
14−import Types (Type (VarT))
12+import Binop
15
13
16-------- Basic Terms --------
14-------- Basic Terms --------
17
15
18−numTerm = do { whitespace; t <- item
16+numTerm :: (Monad m) => ParsecT [Char] u m Expr
19− ; case t of { NUMBER n -> return $ Number n; _ -> zero } }
17+numTerm = liftM (Number . read) (many1 digit) <?> "number"
20−strTerm = do { whitespace; t <- item
18+
21− ; case t of { STRING cs -> return $ Str cs
19+strTerm :: (Monad m) => ParsecT [Char] u m Expr
22− ; _ -> zero } }
20+strTerm = expecting "string" . liftM Str . betwixt '"' '"' . many $ noneOf "\""
23
21
24−varTerm = Var `liftM` var
22+varTerm :: (Monad m) => ParsecT [Char] u m Expr
25−chrTerm = Chr `liftM` chr
23+varTerm = toVar <$> var <?> "variable"
26
24
27−trueTerm = do { t TRUE; return $ Boolean True }
25+toVar v = case v of "True" -> Boolean True
28−falseTerm = do { t FALSE; return $ Boolean False }
26+ "False" -> Boolean False
27+ _ -> Var v
28+
29+chrTerm :: (Monad m) => ParsecT [Char] u m Expr
30+chrTerm = Chr <$> betwixt '\'' '\'' anyChar <?> "character"
29
31
30
32
31-------- Complex Terms --------
33-------- Complex Terms --------
32
34
33−listTerm = (do { t LBRACKET; start <- expr; t DOT2; end <- expr; t RBRACKET
35+listTerm = expecting "list" . betwixtSpcs '[' ']' $ choice
34− ; return $ Range start end }) +|+
36+ [ try $ do { lo <- expr; string ".." ; Range lo <$> expr }
35− (do { t LBRACKET; es <- sepBy (t COMMA) expr; t RBRACKET
37+ , list <$> expr `sepBy` lexeme (char ',')
36− ; return $ list es })
38+ ]
37−
39+
38−parensTerm = (do { t LPAREN; op <- anyOp; t RPAREN
40+parensTerm = expecting "parenthesized expression" . betwixtSpcs '(' ')' $ choice
41+ [ do op <- anyOp
39− ; return . Lambda "x" . Lambda "y" $
42+ return . Lambda "x" . Lambda "y" $ Binop op (Var "x") (Var "y")
40− Binop op (Var "x") (Var "y") }) +|+
43+ , do es <- expr `sepBy` lexeme (char ',')
41− (do { t LPAREN; es <- sepBy (t COMMA) expr; t RPAREN
42− ; return $ case es of { [e] -> e; _ -> tuple es } })
44+ return $ case es of { [e] -> e; _ -> tuple es }
43−
45+ ]
46+
44−term = select [ numTerm
47+term = lexeme (choice [ numTerm, strTerm, chrTerm
45− , strTerm
48+ , accessible varTerm
46− , accessible varTerm
47− , chrTerm
48− , trueTerm
49− , falseTerm
50− , listTerm
49+ , listTerm, parensTerm ])
51− , accessible parensTerm
50+ <?> "basic term (number, variable, etc.)"
52− ]
53
51
54-------- Applications --------
52-------- Applications --------
55
53
56appExpr = do
54appExpr = do
57− tlist <- plus term
55+ tlist <- many1 (try term)
58 return $ case tlist of
56 return $ case tlist of
59 t:[] -> t
57 t:[] -> t
60 t:ts -> foldl' App t ts
58 t:ts -> foldl' App t ts
61
59
62−
63−-------- Expressions with infix operators --------
60+-------- Normal Expressions --------
64
61
65binaryExpr = binops appExpr anyOp
62binaryExpr = binops appExpr anyOp
66
63
64+ifExpr = expecting "if expression" $
65+ do symbol "if" ; e1 <- expr
66+ symbol "then" ; e2 <- expr
67+ expecting "else branch" $ do
68+ symbol "else" ; If e1 e2 <$> expr
69+
70+lambdaExpr = do lexeme $ oneOf "\\\x03BB"
71+ args <- patternTerm `endBy1` whitespace
72+ arrow
73+ e <- expr
74+ return $ makeFunction args e
75+
76+assignExpr = do
77+ patterns <- patternTerm `endBy1` whitespace; symbol "="; exp <- expr
78+ case patterns of
79+ PVar f : args -> return (f, makeFunction args exp)
80+ [PData x ps] -> if "Tuple" == take 5 x && all isDigit (drop 5 x) then
81+ fail "matching tuples is not yet supported in this context"
82+ else fail $ "Only tuples can be matched in this context, " ++
83+ "not other abstract data types such as lists."
84+ _ -> fail $ "Variables in assign statement are not acceptable: " ++
85+ "only named variables, named functions, and tuples are okay."
67
86
68−-------- Normal Expressions --------
87+letExpr = do
88+ symbol "let"; brace <- optionMaybe . lexeme $ char '{'
89+ case brace of
90+ Nothing -> do f <- assignExpr; symbol "in"; e <- expr; return (Let [f] e)
91+ Just '{' -> do fs <- assignExpr `sepBy1` symbol ";"
92+ symbol "}" ; symbol "in"; e <- expr
93+ return (Let fs e)
69
94
70−ifExpr = do { t IF; e1 <- expr; t THEN; e2 <- expr; t ELSE; e3 <- expr
95+caseExpr = do
71− ; return $ If e1 e2 e3 }
96+ symbol "case"; e <- expr; symbol "of"
97+ betwixtSpcs '{' '}' $ Case e <$> case_ `sepBy1` symbol ";"
98+ where case_ = do p <- patternExpr; whitespace; arrow; e <- expr; return (p,e)
72
99
73−lambdaExpr = do { t LAMBDA; vs <- plus var; t ARROW; e <- expr
74− ; return $ foldr Lambda e vs }
75
100
76−assignExpr = whitespace >> assignExprNospace
101+expr = choice [ ifExpr, letExpr, caseExpr, lambdaExpr, binaryExpr ]
77−assignExprNospace = do
78− p:ps <- plus patternTerm; assign; e <- expr
79− case p:ps of
80− PVar x : _ -> return (x, foldr func e ps)
81− where func PAnything e' = Lambda "_" e'
82− func (PVar x) e' = Lambda x e'
83− func p' e' = Lambda "_temp" (Case (Var "_temp") [(p', e')])
84−-- _ : [] -> return $ \hole -> Case e [(p,hole)]
85− _ -> zero
86
102
87−letExpr = do
103+aoeu = parse (between whitespace eof expr) ""
88− t LET; brace <- optional $ t LBRACE
89− case brace of
90− Nothing -> do f <- assignExpr; t IN; e <- expr; return (Let [f] e)
91− Just LBRACE -> do fs <- sepBy1 (t SEMI) assignExpr; t RBRACE; t IN;
92− e <- expr; return (Let fs e)
93
104
94−caseExpr = do
105+symbol = lexeme . try . string
95− t CASE; e <- expr; t OF; t LBRACE
106+arrow = symbol "->" <|> symbol "\8594"
96− cases <- sepBy1 (t SEMI)
107+
97− (do { p <- patternExpr; t ARROW; e <- expr; return (p,e) })
108+def = do (f,e) <- assignExpr
98− t RBRACE
99− return $ Case e cases
100−
101−-------- All Expressions --------
102−
103−expr = select [ letExpr
104− , binaryExpr
105− , ifExpr
106− , caseExpr
107− , lambdaExpr
108− ]
109−
110−def = do (f,e) <- assignExprNospace
111 return ([f], [e], guid >>= \x -> return [VarT x])
109 return ([f], [e], guid >>= \x -> return [VarT x])
112
110
111+{--
113defs = do
112defs = do
114 (fss,ess,tss) <- unzip3 `liftM` plus (whitespace >> plus (sat (==NEWLINE)) >> def +|+ datatype)
113 (fss,ess,tss) <- unzip3 `liftM` plus (whitespace >> plus (sat (==NEWLINE)) >> def +|+ datatype)
115 let (fs,es,ts) = (concat fss, concat ess, concat `liftM` sequence tss)
114 let (fs,es,ts) = (concat fss, concat ess, concat `liftM` sequence tss)
@@ -117,5 +116,5 @@ defs = do
117 return (Let (zip fs es) (Var "main"), liftM (zip fs) ts)
116 return (Let (zip fs es) (Var "main"), liftM (zip fs) ts)
118
117
119err = "Parse Error: Better error messages to come!"
118err = "Parse Error: Better error messages to come!"
120−toExpr = extractResult err . parse expr
121−toDefs = extractResult err . parse defs . (NEWLINE:)
119+toDefs = parse defs . ('\n':)
120+--}
elm/src/Parse/ParserLib.hsdeleted−38
@@ -1,38 +0,0 @@
1−module ParserLib where
2−
3−import Ast
4−import Combinators
5−import Data.Char (isUpper,isLower)
6−import Control.Monad (liftM,guard)
7−import Tokens
8−
9−varNoSpace = do { t <- item; case t of { ID v -> return v; _ -> zero } }
10−var = whitespace >> varNoSpace
11−capVar = do whitespace; t <- item
12− case t of { ID (v:vs) -> guard (isUpper v) >> return (v:vs) ; _ -> zero }
13−lowVar = do whitespace; t <- item
14− case t of { ID (v:vs) -> guard (isLower v) >> return (v:vs) ; _ -> zero }
15−
16−chr = do { whitespace; t <- item; case t of { CHAR c -> return c; _ -> zero } }
17−
18−tNoSpace token = sat (==token)
19−tWithSpace token = forcedWS >> sat (==token)
20−t token = whitespace >> sat (==token)
21−
22−forcedWS = do { sat (==SPACES); star nl_space } +|+ plus nl_space
23− where nl_space = plus (sat (==NEWLINE)) >> sat (==SPACES)
24−whitespace = optional forcedWS
25−
26−accessible exp = do
27− e <- exp
28− access <- optional $ opParserNospace (==".")
29− case access of
30− Just "." -> accessible (Access e `liftM` var)
31− Nothing -> return e
32−
33−opParserNospace pred =
34− do { t <- item
35− ; case t of { OP op -> if pred op then return op else zero; _ -> zero } }
36−opParser pred = whitespace >> opParserNospace pred
37−anyOp = opParser (const True)
38−assign = opParser (=="=")
elm/src/Parse/Patterns.hsnew file+42
@@ -0,0 +1,42 @@
1+module Patterns (patternTerm, patternExpr, makeFunction) where
2+
3+import Ast
4+import Data.Char (isUpper)
5+import Control.Applicative ((<$>))
6+import Control.Monad
7+import Text.Parsec
8+import ParseLib
9+
10+makeFunction args body = foldr func body args
11+ where func PAnything e = Lambda "_" e
12+ func (PVar x) e = Lambda x e
13+ func p e = "t" `Lambda` Case (Var "t") [(p,e)]
14+
15+patternBasic :: Monad m => ParsecT [Char] u m Pattern
16+patternBasic =
17+ choice [ char '_' >> return PAnything
18+ , do x@(c:_) <- var
19+ if isUpper c then PData x <$> patternTerm `endBy` whitespace
20+ else return $ PVar x
21+ ]
22+
23+patternTuple :: Monad m => ParsecT [Char] u m Pattern
24+patternTuple = do ps <- betwixtSpcs '(' ')' $ patternExpr `sepBy` lexeme (char ',')
25+ return $ case ps of { [p] -> p; _ -> ptuple ps }
26+
27+patternCons :: Monad m => ParsecT [Char] u m Pattern
28+patternCons = do
29+ p <- patternTerm
30+ colon <- optionMaybe (char ':')
31+ case colon of
32+ Just ':' -> pcons p <$> patternExpr
33+ Nothing -> return p
34+
35+patternList :: Monad m => ParsecT [Char] u m Pattern
36+patternList = plist <$> listOf patternExpr
37+
38+patternTerm :: Monad m => ParsecT [Char] u m Pattern
39+patternTerm = patternTuple <|> patternList <|> patternBasic <?> "pattern"
40+
41+patternExpr :: Monad m => ParsecT [Char] u m Pattern
42+patternExpr = patternTuple <|> patternList <|> patternCons <?> "pattern"
elm/src/Parse/Tokens.hsdeleted−17
@@ -1,17 +0,0 @@
1−
2−module Tokens where
3−
4−data Token =
5− NUMBER Int | ID String | TYPE String |
6− CHAR Char | STRING String |
7− LAMBDA | ARROW | OP String | DOT2 | UNDERSCORE |
8− LPAREN | RPAREN |
9− LBRACE | RBRACE |
10− LBRACKET | RBRACKET |
11− COMMA | SEMI |
12− TRUE | FALSE |
13− IF | THEN | ELSE |
14− CASE | OF | LET | IN |
15− SPACES | NEWLINE | DATA
16− deriving (Show, Eq)
17−