Basically to parse an identifier, you always check if the identifier is a reserved identifier, and if so you disallow.
A reserved identifier is always a keyword then a conditional. That conditional can be a whitelist or blacklist. It can either say, that these are the things allowed after the keyword, or it can say these things are not allowed after the keyword.
The point is to disambiguate between let from letx.
Hnix uses:
reservedEnd :: Char -> Bool
reservedEnd x = isSpace x ||
x == '{' || x == '(' || x == '[' ||
x == '}' || x == ')' || x == ']' ||
x == ';' || x == ':' || x == '.' ||
x == '"' || x == '\'' || x == ','
reserved :: Text -> Parser ()
reserved n = lexeme $ try $
string n *> lookAhead (void (satisfy reservedEnd) <|> eof)
I decided to simplify to just:
reserved :: Text -> Parser ()
reserved i = (lexeme . MP.try) $
MPC.string i *> MP.lookAhead reservedAfter
where
reservedAfter = MPC.space1 <|> lineComment <|> blockComment <|> MP.eof
This ensures that a reserved identifier is a keyword with some sort of space \t\v... etc the comments and EOF.
Parsing reserved identifiers follows a standard pattern.
Basically to parse an identifier, you always check if the identifier is a reserved identifier, and if so you disallow.
A reserved identifier is always a keyword then a conditional. That conditional can be a whitelist or blacklist. It can either say, that these are the things allowed after the keyword, or it can say these things are not allowed after the keyword.
The point is to disambiguate between
let
fromletx
.Hnix uses:
I decided to simplify to just:
This ensures that a reserved identifier is a keyword with some sort of space
... etc the comments and EOF.
\t
\v
Hopefully the above works.