@@ -3,7 +3,7 @@ module Text.Parser
3%default total
3%default total
5-- TODO: Add some primitives for helping with error messages.
5-- TODO: Add some primitives for helping with error messages.
6−-- e.g. perhaps set a string to state what we're currently trying to
6+-- e.g. perhaps set a string to state what we're currently trying to
7-- parse, or to say what the next expected token is in words
7-- parse, or to say what the next expected token is in words
9||| Description of a language's grammar. The `tok` parameter is the type
9||| Description of a language's grammar. The `tok` parameter is the type
@@ -26,14 +26,14 @@ data Grammar : (tok : Type) -> (consumes : Bool) -> Type -> Type where
26 Grammar tok c1 a -> (a -> Grammar tok c2 b) ->
26 Grammar tok c1 a -> (a -> Grammar tok c2 b) ->
27 Grammar tok (c1 || c2) b
27 Grammar tok (c1 || c2) b
28 Alt : {c1, c2 : Bool} ->
28 Alt : {c1, c2 : Bool} ->
29− Grammar tok c1 ty -> Grammar tok c2 ty ->
29+ Grammar tok c1 ty -> Grammar tok c2 ty ->
30 Grammar tok (c1 && c2) ty
30 Grammar tok (c1 && c2) ty
32public export
32public export
33inf : Bool -> Type -> Type
33inf : Bool -> Type -> Type
34inf True t = Inf t
34inf True t = Inf t
35inf False t = t
35inf False t = t
37||| Sequence two grammars. If either consumes some input, the sequence is
37||| Sequence two grammars. If either consumes some input, the sequence is
38||| guaranteed to consume some input. If the first one consumes input, the
38||| guaranteed to consume some input. If the first one consumes input, the
39||| second is allowed to be recursive (because it means some input has been
39||| second is allowed to be recursive (because it means some input has been
@@ -44,11 +44,11 @@ export %inline
44 Grammar tok (c1 || c2) b
44 Grammar tok (c1 || c2) b
45(>>=) {c1 = False} = SeqEmpty
45(>>=) {c1 = False} = SeqEmpty
46(>>=) {c1 = True} = SeqEat
46(>>=) {c1 = True} = SeqEat
48||| Give two alternative grammars. If both consume, the combination is
48||| Give two alternative grammars. If both consume, the combination is
49||| guaranteed to consume.
49||| guaranteed to consume.
51−(<|>) : Grammar tok c1 ty -> Grammar tok c2 ty ->
51+(<|>) : Grammar tok c1 ty -> Grammar tok c2 ty ->
52 Grammar tok (c1 && c2) ty
52 Grammar tok (c1 && c2) ty
53(<|>) = Alt
53(<|>) = Alt
@@ -82,21 +82,21 @@ export
82eof : Grammar tok False ()
82eof : Grammar tok False ()
85−||| Commit to an alternative; if the current branch of an alternative
85+||| Commit to an alternative; if the current branch of an alternative
86||| fails to parse, no more branches will be tried
86||| fails to parse, no more branches will be tried
88commit : Grammar tok False ()
88commit : Grammar tok False ()
89commit = Commit
89commit = Commit
91data ParseResult : List tok -> (consumes : Bool) -> Type -> Type where
91data ParseResult : List tok -> (consumes : Bool) -> Type -> Type where
92− Failure : {xs : List tok} ->
92+ Failure : {xs : List tok} ->
93 (committed : Bool) ->
93 (committed : Bool) ->
94 (err : String) -> (rest : List tok) -> ParseResult xs c ty
94 (err : String) -> (rest : List tok) -> ParseResult xs c ty
95 EmptyRes : (committed : Bool) ->
95 EmptyRes : (committed : Bool) ->
96 (val : ty) -> (more : List tok) -> ParseResult more False ty
96 (val : ty) -> (more : List tok) -> ParseResult more False ty
97 NonEmptyRes : (committed : Bool) ->
97 NonEmptyRes : (committed : Bool) ->
98 (val : ty) -> (more : List tok) ->
98 (val : ty) -> (more : List tok) ->
99− ParseResult (x :: xs ++ more) c ty
99+ ParseResult (x :: xs ++ more) c ty
101weakenRes : {whatever, c : Bool} -> {xs : List tok} ->
101weakenRes : {whatever, c : Bool} -> {xs : List tok} ->
102 ParseResult xs c ty -> ParseResult xs (whatever && c) ty
102 ParseResult xs c ty -> ParseResult xs (whatever && c) ty
@@ -105,13 +105,13 @@ weakenRes {whatever=True} (EmptyRes com val xs) = EmptyRes com val xs
105weakenRes {whatever=False} (EmptyRes com val xs) = EmptyRes com val xs
105weakenRes {whatever=False} (EmptyRes com val xs) = EmptyRes com val xs
106weakenRes (NonEmptyRes com val more) = NonEmptyRes com val more
106weakenRes (NonEmptyRes com val more) = NonEmptyRes com val more
108−shorter : (more : List tok) -> .(ys : List tok) ->
108+shorter : (more : List tok) -> .(ys : List tok) ->
109 LTE (S (length more)) (S (length (ys ++ more)))
109 LTE (S (length more)) (S (length (ys ++ more)))
110shorter more [] = lteRefl
110shorter more [] = lteRefl
111shorter more (x :: xs) = LTESucc (lteSuccLeft (shorter more xs))
111shorter more (x :: xs) = LTESucc (lteSuccLeft (shorter more xs))
113doParse : {c : Bool} ->
113doParse : {c : Bool} ->
114− (commit : Bool) -> (xs : List tok) -> (act : Grammar tok c ty) ->
114+ (commit : Bool) -> (xs : List tok) -> (act : Grammar tok c ty) ->
115 ParseResult xs c ty
115 ParseResult xs c ty
116doParse com xs act with (sizeAccessible xs)
116doParse com xs act with (sizeAccessible xs)
117 doParse com xs (Empty val) | sml = EmptyRes com val xs
117 doParse com xs (Empty val) | sml = EmptyRes com val xs
@@ -120,17 +120,17 @@ doParse com xs act with (sizeAccessible xs)
120 doParse com xs Commit | sml = EmptyRes True () xs
120 doParse com xs Commit | sml = EmptyRes True () xs
122 doParse com [] (Terminal f) | sml = Failure com "End of input" []
122 doParse com [] (Terminal f) | sml = Failure com "End of input" []
123− doParse com (x :: xs) (Terminal f) | sml
123+ doParse com (x :: xs) (Terminal f) | sml
125 (Failure com "Unrecognised token" (x :: xs))
125 (Failure com "Unrecognised token" (x :: xs))
126 (\a => NonEmptyRes com {xs=[]} a xs)
126 (\a => NonEmptyRes com {xs=[]} a xs)
128 doParse com [] EOF | sml = EmptyRes com () []
128 doParse com [] EOF | sml = EmptyRes com () []
129− doParse com (x :: xs) EOF | sml
129+ doParse com (x :: xs) EOF | sml
130 = Failure com "Expected end of input" (x :: xs)
130 = Failure com "Expected end of input" (x :: xs)
131 doParse com [] (NextIs f) | sml = Failure com "End of input" []
131 doParse com [] (NextIs f) | sml = Failure com "End of input" []
132− doParse com (x :: xs) (NextIs f) | sml
132+ doParse com (x :: xs) (NextIs f) | sml
133− = if f x
133+ = if f x
134 then EmptyRes com x (x :: xs)
134 then EmptyRes com x (x :: xs)
135 else Failure com "Unrecognised token" (x :: xs)
135 else Failure com "Unrecognised token" (x :: xs)
136 doParse com xs (Alt x y) | sml with (doParse False xs x | sml)
136 doParse com xs (Alt x y) | sml with (doParse False xs x | sml)
@@ -140,19 +140,19 @@ doParse com xs act with (sizeAccessible xs)
140 then Failure com msg ts
140 then Failure com msg ts
141 else weakenRes (doParse False xs y | sml)
141 else weakenRes (doParse False xs y | sml)
142 -- Successfully parsed the first option, so use the outer commit flag
142 -- Successfully parsed the first option, so use the outer commit flag
143− doParse com xs (Alt x y) | sml | (EmptyRes _ val xs)
143+ doParse com xs (Alt x y) | sml | (EmptyRes _ val xs)
144 = EmptyRes com val xs
144 = EmptyRes com val xs
145− doParse com (z :: (ys ++ more)) (Alt x y) | sml | (NonEmptyRes _ val more)
145+ doParse com (z :: (ys ++ more)) (Alt x y) | sml | (NonEmptyRes _ val more)
146 = NonEmptyRes com val more
146 = NonEmptyRes com val more
147 doParse com xs (SeqEmpty act next) | (Access morerec)
147 doParse com xs (SeqEmpty act next) | (Access morerec)
148 = case doParse com xs act | Access morerec of
148 = case doParse com xs act | Access morerec of
149 Failure com msg ts => Failure com msg ts
149 Failure com msg ts => Failure com msg ts
150− EmptyRes com val xs =>
150+ EmptyRes com val xs =>
151 case doParse com xs (next val) | (Access morerec) of
151 case doParse com xs (next val) | (Access morerec) of
152 Failure com' msg ts => Failure com' msg ts
152 Failure com' msg ts => Failure com' msg ts
153 EmptyRes com' val xs => EmptyRes com' val xs
153 EmptyRes com' val xs => EmptyRes com' val xs
154 NonEmptyRes com' val more => NonEmptyRes com' val more
154 NonEmptyRes com' val more => NonEmptyRes com' val more
155− NonEmptyRes {x} {xs=ys} com val more =>
155+ NonEmptyRes {x} {xs=ys} com val more =>
156 case (doParse com more (next val) | morerec _ (shorter more ys)) of
156 case (doParse com more (next val) | morerec _ (shorter more ys)) of
157 Failure com' msg ts => Failure com' msg ts
157 Failure com' msg ts => Failure com' msg ts
158 EmptyRes com' val _ => NonEmptyRes com' val more
158 EmptyRes com' val _ => NonEmptyRes com' val more
@@ -160,13 +160,13 @@ doParse com xs act with (sizeAccessible xs)
160 rewrite appendAssociative (x :: ys) (x1 :: xs1) more' in
160 rewrite appendAssociative (x :: ys) (x1 :: xs1) more' in
161 NonEmptyRes com' val more'
161 NonEmptyRes com' val more'
162 doParse com xs (SeqEat act next) | sml with (doParse com xs act | sml)
162 doParse com xs (SeqEat act next) | sml with (doParse com xs act | sml)
163− doParse com xs (SeqEat act next) | sml | Failure com' msg ts
163+ doParse com xs (SeqEat act next) | sml | Failure com' msg ts
164 = Failure com' msg ts
164 = Failure com' msg ts
165− doParse com (x :: (ys ++ more)) (SeqEat act next) | (Access morerec) | (NonEmptyRes com' val more)
165+ doParse com (x :: (ys ++ more)) (SeqEat act next) | (Access morerec) | (NonEmptyRes com' val more)
166 = case doParse com' more (next val) | morerec _ (shorter more ys) of
166 = case doParse com' more (next val) | morerec _ (shorter more ys) of
167 Failure com' msg ts => Failure com' msg ts
167 Failure com' msg ts => Failure com' msg ts
168 EmptyRes com' val _ => NonEmptyRes com' val more
168 EmptyRes com' val _ => NonEmptyRes com' val more
169− NonEmptyRes {x=x1} {xs=xs1} com' val more' =>
169+ NonEmptyRes {x=x1} {xs=xs1} com' val more' =>
170 rewrite appendAssociative (x :: ys) (x1 :: xs1) more' in
170 rewrite appendAssociative (x :: ys) (x1 :: xs1) more' in
171 NonEmptyRes com' val more'
171 NonEmptyRes com' val more'
172 -- This next line is not strictly necessary, but it stops the coverage
172 -- This next line is not strictly necessary, but it stops the coverage
@@ -180,7 +180,7 @@ data ParseError tok = Error String (List tok)
180||| returns a pair of the parse result and the unparsed tokens (the remaining
180||| returns a pair of the parse result and the unparsed tokens (the remaining
181||| input).
181||| input).
183−parse : (xs : List tok) -> (act : Grammar tok c ty) ->
183+parse : (xs : List tok) -> (act : Grammar tok c ty) ->
184 Either (ParseError tok) (ty, List tok)
184 Either (ParseError tok) (ty, List tok)
185parse xs act
185parse xs act
186 = case doParse False xs act of
186 = case doParse False xs act of
@@ -190,7 +190,7 @@ parse xs act
191||| Parse one or more things
191||| Parse one or more things
193−some : Grammar tok True a ->
193+some : Grammar tok True a ->
194 Grammar tok True (List a)
194 Grammar tok True (List a)
195some p = do x <- p
195some p = do x <- p
196 (do xs <- some p
196 (do xs <- some p
@@ -198,14 +198,14 @@ some p = do x <- p
199||| Parse zero or more things (may match the empty input)
199||| Parse zero or more things (may match the empty input)
201−many : Grammar tok True a ->
201+many : Grammar tok True a ->
202 Grammar tok False (List a)
202 Grammar tok False (List a)
203many p = some p
203many p = some p
204 <|> pure []
204 <|> pure []
206||| Parse one or more things, separated by another thing
206||| Parse one or more things, separated by another thing
208−sepBy1 : Grammar tok True () -> Grammar tok True a ->
208+sepBy1 : Grammar tok True () -> Grammar tok True a ->
209 Grammar tok True (List a)
209 Grammar tok True (List a)
210sepBy1 sep p = do x <- p
210sepBy1 sep p = do x <- p
@@ -215,7 +215,7 @@ sepBy1 sep p = do x <- p
215||| Parse zero or more things, separated by another thing. May
215||| Parse zero or more things, separated by another thing. May
216||| match the empty input.
216||| match the empty input.
218−sepBy : Grammar tok True () -> Grammar tok True a ->
218+sepBy : Grammar tok True () -> Grammar tok True a ->
219 Grammar tok False (List a)
219 Grammar tok False (List a)
220sepBy sep p = sepBy1 sep p <|> pure []
220sepBy sep p = sepBy1 sep p <|> pure []
@@ -227,3 +227,44 @@ optional : Grammar tok True a -> (ifNothing : a) ->
227optional p def = p <|> pure def
227optional p def = p <|> pure def
230+||| Parse an instance of `p` that is between `left` and `right`.
232+between : (left : Grammar tok True ())
233+ -> (right : Grammar tok True ())
234+ -> (p : Grammar tok True a)
235+ -> Grammar tok True a
236+between left right contents = do
242+||| Parse one or more instances of `p` separated by `s`, returning the
243+||| parsed items and proof the resulting list is non-empty.
245+sepBy1' : (sep : Grammar tok True ())
246+ -> (p : Grammar tok True a)
247+ -> Grammar tok True (xs : List a ** NonEmpty xs)
252+ pure (x :: xs ** IsNonEmpty)) <|> pure ([x] ** IsNonEmpty)
254+||| Parse one or more instances of `p`, returning the parsed items and proof the resulting list is non-empty.
256+some' : (p : Grammar tok True a)
257+ -> Grammar tok True (xs : List a ** NonEmpty xs)
261+ pure (x::xs ** IsNonEmpty)) <|> pure ([x] ** IsNonEmpty)
264+||| Optionally parse a thing. If the grammar provides a default use `optional` instead.
266+maybe : Grammar tok True a
267+ -> Grammar tok False (Maybe a)
269+ (do res <- p; pure $ Just res)