Skip to content

Commit dde7d28

Browse files
author
Alex Gryzlov
committed
commands parser, formatting
1 parent a31d1e3 commit dde7d28

File tree

1 file changed

+80
-107
lines changed

1 file changed

+80
-107
lines changed

src/ImpParser.lidr

Lines changed: 80 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ The development of the Imp language in `Imp.lidr` completely ignores issues of
77
concrete syntax -- how an ascii string that a programmer might write gets
88
translated into abstract syntax trees defined by the datatypes `aexp`, `bexp`,
99
and `com`. In this chapter, we illustrate how the rest of the story can be
10-
filled in by building a simple lexical analyzer and parser using Coq's
10+
filled in by building a simple lexical analyzer and parser using Idris's
1111
functional programming facilities.
1212

1313
It is not important to understand all the details here (and accordingly, the
@@ -18,15 +18,6 @@ code -- most of it is not very complicated, though the parser relies on some
1818
most readers will probably want to just skim down to the Examples section at the
1919
very end to get the punchline.
2020

21-
22-
Set Warnings "-notation-overridden,-parsing,-deprecated-implicit-arguments".
23-
Require Import Coq.Strings.String.
24-
Require Import Coq.Strings.Ascii.
25-
Require Import Coq.Arith.Arith.
26-
Require Import Coq.Arith.EqNat.
27-
Require Import Coq.Lists.List.
28-
Import ListNotations.
29-
3021
> import Maps
3122
> import Imp
3223
>
@@ -37,9 +28,9 @@ Import ListNotations.
3728

3829
> isLowerAlpha : (c : Char) -> Bool
3930
> isLowerAlpha c = isLower c || isDigit c
40-
31+
>
4132
> data Chartype = White | Alpha | Digit | Other
42-
33+
>
4334
> classifyChar : (c : Char) -> Chartype
4435
> classifyChar c =
4536
> if isSpace c then
@@ -50,10 +41,10 @@ Import ListNotations.
5041
> Digit
5142
> else
5243
> Other
53-
44+
>
5445
> Token : Type
5546
> Token = String
56-
47+
>
5748
> tokenizeHelper : (cls : Chartype) -> (acc, xs : List Char) -> List (List Char)
5849
> tokenizeHelper cls acc xs =
5950
> case xs of
@@ -79,12 +70,13 @@ Import ListNotations.
7970
> tk = case acc of
8071
> [] => []
8172
> (_::_) => [reverse acc]
82-
73+
>
8374
> tokenize : (s : String) -> List String
8475
> tokenize s = map pack (tokenizeHelper White [] (unpack s))
85-
76+
>
8677
> tokenizeEx1 : tokenize "abc12==3 223*(3+(a+c))" = ["abc","12","==","3","223","*","(","3","+","(","a","+","c",")",")"]
8778
> tokenizeEx1 = Refl
79+
>
8880

8981
=== Parsing
9082

@@ -95,6 +87,7 @@ An `option` type with error messages:
9587
> data OptionE : (x : Type) -> Type where
9688
> SomeE : x -> OptionE x
9789
> NoneE : String -> OptionE x
90+
>
9891

9992
Some interface instances to make writing nested match-expressions on `OptionE`
10093
more convenient.
@@ -104,69 +97,75 @@ more convenient.
10497
> Functor OptionE where
10598
> map f (SomeE x) = SomeE (f x)
10699
> map _ (NoneE err) = NoneE err
107-
100+
>
108101
> Applicative OptionE where
109102
> pure = SomeE
110103
> (SomeE f) <*> (SomeE x) = SomeE (f x)
111104
> (SomeE _) <*> (NoneE e2) = NoneE e2
112105
> (NoneE e1) <*> (SomeE _) = NoneE e1
113106
> (NoneE e1) <*> (NoneE e2) = NoneE (e1 ++ ";" ++ e2)
114-
107+
>
115108
> Alternative OptionE where
116-
> empty = NoneE ""
117-
> (SomeE x) <|> _ = SomeE x
118-
> (NoneE _) <|> v = v
119-
109+
> empty = NoneE ""
110+
> (SomeE x) <|> _ = SomeE x
111+
> (NoneE _) <|> v = v
112+
>
120113
> Monad OptionE where
121-
> (NoneE e) >>= _ = NoneE e
122-
> (SomeE x) >>= k = k x
114+
> (NoneE e) >>= _ = NoneE e
115+
> (SomeE x) >>= k = k x
116+
>
123117

124118
==== Generic Combinators for Building Parsers
125119

126120
> Parser : (t : Type) -> Type
127121
> Parser t = List Token -> OptionE (t, List Token)
128-
122+
>
129123
> manyHelper : (p : Parser t) -> (acc : List t) -> (steps : Nat) -> Parser (List t)
130124
> manyHelper p acc Z _ = NoneE "Too many recursive calls"
131125
> manyHelper p acc (S steps') xs with (p xs)
132126
> | NoneE _ = SomeE (reverse acc, xs)
133127
> | SomeE (t', xs') = manyHelper p (t'::acc) steps' xs'
128+
>
134129

135130
A (step-indexed) parser that expects zero or more `p`s:
136131

137132
> many : (p : Parser t) -> (steps : Nat) -> Parser (List t)
138133
> many p steps = manyHelper p [] steps
134+
>
139135

140136
A parser that expects a given token, followed by `p`:
141137

142138
> firstExpect : (a : Token) -> (p : Parser t) -> Parser t
143-
> firstExpect a p (x::xs) = if x == a then p xs else NoneE ("expected '" ++ a ++ "'.")
144-
> firstExpect a _ [] = NoneE ("expected '" ++ a ++ "'.")
139+
> firstExpect a p (x::xs) = if x == a then p xs else NoneE ("Expected '" ++ a ++ "'")
140+
> firstExpect a _ [] = NoneE ("Expected '" ++ a ++ "'")
141+
>
145142

146143
A parser that expects a particular token:
147144

148145
> expect : (t : Token) -> Parser ()
149146
> expect t = firstExpect t (\xs => SomeE ((), xs))
150-
147+
>
151148
==== A Recursive-Descent Parser for Imp
152149

153150
Identifiers:
154151

155152
> parseIdentifier : Parser Id
156153
> parseIdentifier [] = NoneE "Expected identifier"
157-
> parseIdentifier (x::xs') =
154+
> parseIdentifier (x::xs) =
158155
> if all isLowerAlpha (unpack x)
159-
> then SomeE (MkId x, xs')
156+
> then SomeE (MkId x, xs)
160157
> else NoneE ("Illegal identifier:'" ++ x ++ "'")
158+
>
161159

162160
Numbers:
163161

164162
> parseNumber : Parser Nat
165163
> parseNumber [] = NoneE "Expected number"
166-
> parseNumber (x::xs') =
164+
> parseNumber (x::xs) =
167165
> if all isDigit (unpack x)
168-
> then SomeE (foldl (\n, d => 10 * n + (cast (ord d - ord '0'))) 0 (unpack x), xs')
166+
> then SomeE (foldl (\n, d => 10 * n + (cast (ord d - ord '0'))) 0 (unpack x), xs)
169167
> else NoneE "Expected number"
168+
>
170169

171170
Parse arithmetic expressions
172171

@@ -213,24 +212,25 @@ Parse arithmetic expressions
213212
>
214213
> parseAExp : (steps : Nat) -> Parser AExp
215214
> parseAExp = parseSumExp
215+
>
216216

217217
Parsing boolean expressions:
218218

219219
> mutual
220220
> parseAtomicExp : (steps : Nat) -> Parser BExp
221221
> parseAtomicExp Z _ = NoneE "Too many recursive calls"
222222
> parseAtomicExp (S steps') xs =
223-
> (do (u, rest) <- expect "true" xs
223+
> (do (_, rest) <- expect "true" xs
224224
> pure (BTrue, rest))
225225
> <|>
226-
> (do (u, rest) <- expect "false" xs
226+
> (do (_, rest) <- expect "false" xs
227227
> pure (BFalse, rest))
228228
> <|>
229229
> (do (e, rest) <- firstExpect "not" (parseAtomicExp steps') xs
230230
> pure (BNot e, rest))
231231
> <|>
232232
> (do (e, rest) <- firstExpect "(" (parseConjunctionExp steps') xs
233-
> (u, rest') <- expect ")" rest
233+
> (_, rest') <- expect ")" rest
234234
> pure (e, rest'))
235235
> <|>
236236
> (do (e, rest) <- parseProductExp steps' xs
@@ -251,85 +251,58 @@ Parsing boolean expressions:
251251
>
252252
> parseBExp : (steps : Nat) -> Parser BExp
253253
> parseBExp = parseConjunctionExp
254+
>
255+
> testParsing : (p : Nat -> Parser t) -> (s : String) -> OptionE (t, List Token)
256+
> testParsing p s = p 100 (tokenize s)
257+
>
254258

255-
``coq
256-
Check parseConjunctionExp.
257-
258-
Definition testParsing {X : Type}
259-
(p : nat ->
260-
list token ->
261-
optionE (X * list token))
262-
(s : string) :=
263-
let t := tokenize s in
264-
p 100 t.
259+
\todo[inline]{The second one seems designed to fail}
265260

266-
(*
267-
Eval compute in
268-
testParsing parseProductExp "x*y*(x*x)*x".
261+
```idris
262+
λΠ> testParsing parseProductExp "x*y*(x*x)*x"
269263

270-
Eval compute in
271-
testParsing parseConjunctionExp "not((x==x||x*x<=(x*x)*x)&&x==x".
272-
*)
264+
λΠ> testParsing parseConjunctionExp "not((x==x||x*x<=(x*x)*x)&&x==x"
273265
```
274266

275267
Parsing commands:
276268

277-
```coq
278-
Fixpoint parseSimpleCommand (steps:nat)
279-
(xs : list token) :=
280-
match steps with
281-
| 0 => NoneE "Too many recursive calls"
282-
| S steps' =>
283-
DO (u, rest) <-- expect "SKIP" xs;
284-
SomeE (SKIP, rest)
285-
OR DO (e,rest) <--
286-
firstExpect "IF" (parseBExp steps') xs;
287-
DO (c,rest') <==
288-
firstExpect "THEN"
289-
(parseSequencedCommand steps') rest;
290-
DO (c',rest'') <==
291-
firstExpect "ELSE"
292-
(parseSequencedCommand steps') rest';
293-
DO (u,rest''') <==
294-
expect "END" rest'';
295-
SomeE(IFB e THEN c ELSE c' FI, rest''')
296-
OR DO (e,rest) <--
297-
firstExpect "WHILE"
298-
(parseBExp steps') xs;
299-
DO (c,rest') <==
300-
firstExpect "DO"
301-
(parseSequencedCommand steps') rest;
302-
DO (u,rest'') <==
303-
expect "END" rest';
304-
SomeE(WHILE e DO c END, rest'')
305-
OR DO (i, rest) <==
306-
parseIdentifier xs;
307-
DO (e, rest') <==
308-
firstExpect ":=" (parseAExp steps') rest;
309-
SomeE(i ::= e, rest')
310-
end
311-
312-
with parseSequencedCommand (steps:nat)
313-
(xs : list token) :=
314-
match steps with
315-
| 0 => NoneE "Too many recursive calls"
316-
| S steps' =>
317-
DO (c, rest) <==
318-
parseSimpleCommand steps' xs;
319-
DO (c', rest') <--
320-
firstExpect ";;"
321-
(parseSequencedCommand steps') rest;
322-
SomeE(c ;; c', rest')
323-
OR
324-
SomeE(c, rest)
325-
end.
326-
327-
Definition bignumber := 1000.
328-
329-
Definition parse (str : string) : optionE (com * list token) :=
330-
let tokens := tokenize str in
331-
parseSequencedCommand bignumber tokens.
332-
```
269+
> mutual
270+
> parseSimpleCommand : (steps : Nat) -> Parser Com
271+
> parseSimpleCommand Z _ = NoneE "Too many recursive calls"
272+
> parseSimpleCommand (S steps') xs =
273+
> (do (_, rest) <- expect "SKIP" xs
274+
> pure (SKIP, rest))
275+
> <|>
276+
> (do (e, rest) <- firstExpect "IF" (parseBExp steps') xs
277+
> (c, rest') <- firstExpect "THEN" (parseSequencedCommand steps') rest
278+
> (c', rest'') <- firstExpect "ELSE" (parseSequencedCommand steps') rest'
279+
> (_, rest''') <- expect "END" rest''
280+
> pure (IFB e THEN c ELSE c' FI, rest'''))
281+
> <|>
282+
> (do (e, rest) <- firstExpect "WHILE" (parseBExp steps') xs
283+
> (c, rest') <- firstExpect "DO" (parseSequencedCommand steps') rest
284+
> (_, rest'') <- expect "END" rest'
285+
> pure (WHILE e DO c END, rest''))
286+
> <|>
287+
> (do (i, rest) <- parseIdentifier xs;
288+
> (e, rest') <- firstExpect ":=" (parseAExp steps') rest
289+
> pure (i ::= e, rest'))
290+
>
291+
> parseSequencedCommand : (steps : Nat) -> Parser Com
292+
> parseSequencedCommand Z _ = NoneE "Too many recursive calls"
293+
> parseSequencedCommand (S steps') xs =
294+
> do (c, rest) <- parseSimpleCommand steps' xs
295+
> ((do (c', rest') <- firstExpect ";;" (parseSequencedCommand steps') rest
296+
> pure (c ;; c', rest'))
297+
> <|>
298+
> (pure (c, rest)))
299+
>
300+
> bignumber : Nat
301+
> bignumber = 1000
302+
>
303+
> parse : (str : String) -> OptionE (Com, List Token)
304+
> parse str = parseSequencedCommand bignumber (tokenize str)
305+
>
333306

334307
== Examples
335308

0 commit comments

Comments
 (0)