Indent parsing

As a continuation of this question , I am now trying to parse an expression language with variables and expressions case ... of .... The syntax should be based on indentation:

  • Expressions can span multiple lines if each line is indented relative to the first; that is, it should be analyzed as a single application:

    f x y
      z
     q
    
  • Each alternative expression casemust be in a separate line indented relative to the keyword case. Right sides can span multiple lines.

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

    should be disassembled in one casewith two alternatives: xand f x yhow the right parts

I simplified my code as follows:

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 ernatives 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 ernatives:

位禄 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

, . . , , , , , , :

module Main (main) where

import Control.Applicative
import Control.Monad (void)
import Text.Megaparsec
import Text.Megaparsec.String
import qualified Data.List.NonEmpty    as NE
import qualified Text.Megaparsec.Lexer as L

data Term = Var String
          | App [Term]
          | Case Term [(String, Term)]
          deriving Show

scn :: Parser ()
scn = L.space (void spaceChar) empty empty

sc :: Parser ()
sc = L.space (void $ oneOf " \t") empty empty

name :: Parser String
name = try $ do
  s <- some letterChar
  if s `elem` ["case", "of"]
    then (unexpected . Label . NE.fromList) ("reserved word \"" ++ s ++ "\"")
    else return s

manyTerms :: Parser [Term]
manyTerms = many pTerm

pTerm :: Parser Term
pTerm = caseBlock <|> app -- parse a term first

caseBlock :: Parser Term
caseBlock = L.indentBlock scn $ do
  void (L.symbol sc "case")
  t <- Var <$> L.lexeme sc name -- not sure what sort of syntax case of
       -- case expressions should have, so simplified to vars for now
  void (L.symbol sc "of")
  return (L.IndentSome Nothing (return . Case t) alt)

alt :: Parser (String, Term)
alt = L.lineFold scn $ \sc' ->
  (,) <$> L.lexeme sc' name <* L.symbol sc' "->" <*> pTerm -- (1)

app :: Parser Term
app = L.lineFold scn $ \sc' ->
  App <$> ((Var <$> name) `sepBy1` try sc' <* scn)
  -- simplified here, with some effort should be possible to go from Var to
  -- more general Term in applications

, , , , case .. .

:

位> parseTest pTerm "x y\n z"
App [Var "x",Var "y",Var "z"]
位> parseTest pTerm "x\n y\nz"
App [Var "x",Var "y"]
位> parseTest manyTerms "x\n y\nz"
[App [Var "x",Var "y"],App [Var "z"]]
位> parseTest pTerm "case x of\n C -> y\n D -> z"
Case (Var "x") [("C",App [Var "y"]),("D",App [Var "z"])]
位> parseTest pTerm "case x of\n C -> y\n  z"
3:3:
incorrect indentation (got 3, should be equal to 2)

- (1) . app , ( , - ). , z y, , :

位> parseTest pTerm "case x of\n C -> y\n           z"
Case (Var "x") [("C",App [Var "y",Var "z"])]

, case :

位> parseTest pTerm "case x of\n C -> y\n D -> z"
Case (Var "x") [("C",App [Var "y"]),("D",App [Var "z"])]

Megaparsec . Text.Megaparsec.Lexer , , , .

+1

All Articles