4

この質問へのフォローアップとして、変数と式を持つ式言語を解析しようとしていますcase ... of ...。構文はインデントベースにする必要があります。

  • すべての行が最初の行に対してインデントされている限り、式は複数の行にまたがることができます。つまり、これは単一のアプリケーションとして解析する必要があります。

    f x y
      z
     q
    
  • 式の各選択肢は、キーワードcaseに対してインデントされた独自の行にある必要があります。case右側は複数の行にまたがることができます。

    case E of
      C -> x
      D -> f x
       y
    

    右辺としてと をcase使用して、2 つの選択肢を持つ単一に解析する必要があります。xf 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エルナティブを分離しようとしています。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最も外側の式では行を折りたたむことなく、1 つの選択肢のみで機能します。

λ» 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)

私は何を間違っていますか?

4

1 に答える 1