Be sure you put your name and e-mail in a comment at the beginning of the file. Without this you will not get any feedback.
In this homework you will write a parser for a subset of haskell. In order to do this you will need to write indentation sensitive parsers. Which keep track of the column that some sytactic entities start in. This is done with the parsec "layout" combinator. An example is given below that parses a "let" statement (given parsers for declarations (declP) and expressions ("expP")).
letParser declP expP =
do { pos <- getPosition -- This gets the SourcePos
; keyworD "let"
; ds <- layout declP (keyworD "in") -- "in" ends the layout if it is found
; exp <- expP
; return(ds,exp)}
When a parser "p" is "layed out" a "tab stop" is set at the next non-whitespace
character. It the parses a sequence of "p" objects. Lines that begin after
the "tab stop" are continuations of the "p" that started on earlier lines.
Lines that begin at the "tab stop" are the beginning of the next "p". Lines
that start before the "tab stop" end the layout rule. The second argument
to "layout" (keyworD "in") is a parser the forces the layout to end
regardless of the where the line begins. Some layout sensisitve
language copnstructs (such as case, where, and do)
do not have a terminating token, in which case the parser (return ()) will
do.
One can turn off the laout rule by surrounding the sequence of "p" objects by "{" and "}" separating by ";". Thus the following pairs all parse the same.
case x of
[] -> 0
(Cons x xs) -> x + 4
case x of { [] -> 0; (Cons x xs) -> x + 4}
-----------------------------------
let x = 3
y = 5
in x + y
let {x = 3; y = 5} in x+5
-----------------------------------
f x y = x+y+z
where a = 5
z = a - 3
f x y = x+y+z where { a= 5; z = a-3}
Luckily all this is handled by the layout parser combinator. In order to
use the layout combinator one needs a modified version of the Parsec.Token
module. He one we use is called "LayoutToken" and is included here.
Just download this file, along with HW4Template.html.
Rename "HW4Template.html" to "hw4.hs", and keep both files in the same directory.
The language we are interested in has the following abstract syntax. This is a subset of Haskell expressions.
type Var = (SourcePos,String) -- Starts lowercase
type Con = (SourcePos,String) -- Starts with Upper case
type Name = (SourcePos,String) -- Starts with either lower case or uppercase
data Lit
= Int Int
| Char Char
| Unit
| Float Float
data Pat
= Plit Lit -- { 5 or 'c' }
| Pvar Var -- { x }
| Pprod [Pat] -- { (p1,p2,p3) }
| Paspat Var Pat -- { x @ p }
| Pwild -- { _ }
| Pcon Con [Pat] -- C x y (z,a)
data Exp
= Var Name -- { x or Nil }
| Lit Lit -- { 5 or 'c' or 5.6 }
| Prod [Exp] -- { (e1,e2,e3) }
| App Exp Exp -- { f x }
| Lam [Pat] Exp -- { \ p1 p2 -> e }
| Let [Dec] Exp -- { let { x=e1; y=e2 } in e3 }
| Case Exp [Match Pat Exp Dec] -- { case e of { m1; m2 }}
| Do [Stmt Pat Exp Dec] -- { do { p <- e1; e2 } }
-- Let, Case, Do, all use layout
type Match p e d = (SourcePos,p,Body e,[d]) -- case e of { p -> b where decs }
data Body e
= Guarded [(e,e)] -- f p { | e1 = e2 | e3 = e4 } where ds
| Normal e -- f p = { e } where ds
-- Where uses layout
data Stmt p e d
= BindSt SourcePos p e
| LetSt SourcePos [d]
| NoBindSt SourcePos e
data Dec
= Fun SourcePos Var [Match [Pat] Exp Dec] -- { f p1 p2 = b where decs }
| Val SourcePos Pat (Body Exp) [Dec] -- { p = b where decs }
Here is what I expect.