@@ -167,20 +167,35 @@ export
167167symbol : Lexer
168168symbol = some (pred (\x => not (isAlphaNum x) && not (isSpace x)))
169169
170−strChar : Lexer
171−strChar = (is '\\' <+> any) <|> isNot '"'
170+||| Recognise zero or more occurrences of a sub-lexer between
171+||| delimiting lexers
172+export
173+surround : (start : Lexer) -> (end : Lexer) -> (l : Lexer) -> Lexer
174+surround start end l = start <+> manyTill l end
175+
176+||| Recognise zero or more occurrences of a sub-lexer surrounded
177+||| by the same quote lexer on both sides (useful for strings)
178+export
179+quote : (q : Lexer) -> (l : Lexer) -> Lexer
180+quote q l = surround q q l
181+
182+||| Recognise an escape character (often '\\') followed by a sub-lexer
183+export
184+escape : (esc : Char) -> Lexer -> Lexer
185+escape esc l = is esc <+> l
172186
173187||| Recognise a string literal, including escaped characters.
174188||| (Note: doesn't yet handle escape sequences such as \123)
175189export
176190stringLit : Lexer
177−stringLit = is '"' <+> many strChar <+> is '"'
191+stringLit = quote (is '"') (escape '\\' any <|> any)
178192
179193||| Recognise a character literal, including escaped characters.
180194||| (Note: doesn't yet handle escape sequences such as \123)
181195export
182196charLit : Lexer
183−charLit = is '\'' <+> strChar <+> is '\''
197+charLit = let q = '\'' in
198+ is q <+> (escape '\\' any <|> isNot q) <+> is q
184199
185200||| Recognise an integer literal (possibly with a '-' prefix)
186201export