作为这个问题的后续,我现在正在尝试解析具有变量和case ... of ...
表达式的表达式语言。语法应该是基于缩进的:
表达式可以跨越多行,只要每一行都相对于第一行缩进即可;即这应该被解析为单个应用程序:
f x y z q
表达式的每个替代项都
case
需要在自己的行上,相对于case
关键字缩进。右侧可以跨越多条线。case E of C -> x D -> f x y
应该被解析成一个
case
有两种选择的单一的,用x
和f x y
作为右手边
我已将代码简化为以下内容:
import qualified Text.Megaparsec.Lexer as L
import Text.Megaparsec hiding (space)
import Text.Megaparsec.Char hiding (space)
import Text.Megaparsec.String
import Control.Monad (void)
import Control.Applicative
data Term = Var String
| App [Term]
| Case Term [(String, Term)]
deriving Show
space :: Parser ()
space = L.space (void spaceChar) empty empty
name :: Parser String
name = try $ do
s <- some letterChar
if s `elem` ["case", "of"]
then fail $ unwords ["Unexpected: reserved word", show s]
else return s
term :: Parser () -> Parser Term
term sp = App <$> atom `sepBy1` try sp
where
atom = choice [ caseBlock
, Var <$> L.lexeme sp name
]
caseBlock = L.lineFold sp $ \sp' ->
Case <$>
(L.symbol sp "case" *> L.lexeme sp (term sp) <* L.symbol sp' "of") <*>
alt sp' `sepBy` try sp' <* sp
alt sp' = L.lineFold sp' $ \sp'' ->
(,) <$> L.lexeme sp' name <* L.symbol sp' "->" <*> term sp''
如您所见,我正在尝试使用此答案中的技术来将具有比关键字缩进更多alt
的 ace 的替代词分开。sp'
case
问题
这似乎适用于仅由应用程序组成的单个表达式:
λ» parseTest (L.lineFold space term) "x y\n z"
App [Var "x",Var "y",Var "z"]
它不适用于使用链接答案中的技术列出此类表达式:
λ» parseTest (L.lineFold space $ \sp -> (term sp `sepBy` try sp)) "x\n y\nz"
3:1:
incorrect indentation (got 1, should be greater than 1)
case
尝试使用行折叠时,表达式失败了:
λ» parseTest (L.lineFold space term) "case x of\n C -> y\n D -> z"
1:5:
Unexpected: reserved word "case"
case
最外层表达式无需折线即可工作,仅适用于一种选择:
λ» parseTest (term space) "case x of\n C -> y\n z"
App [Case (App [Var "x"]) [("C",App [Var "y",Var "z"])]]
但是case
一旦我有多个alt
替代品就会失败:
λ» parseTest (term space) "case x of\n C -> y\n D -> z"
3:2:
incorrect indentation (got 2, should be greater than 2)
我究竟做错了什么?