Пакеты ошибок после разбора с мегапарсек - PullRequest
0 голосов
/ 30 января 2019

В настоящее время у меня есть рабочий анализатор в мегапарсек, где я создаю AST для своей программы.Теперь я хочу выполнить некоторые операции над пропуском в моем AST, при этом используя те же самые ошибки, что и анализатор.Хотя этот этап после синтаксического анализа, мне интересно, есть ли общие методы для мегапарсек в этом.Есть ли способ для меня извлечь каждую строку и комментарий (используемый в комплекте) и добавить его к каждому элементу в моем AST?Есть ли другой способ, которым люди решают эту проблему?

Заранее извиняюсь, если это звучит открыто, но я в основном задаюсь вопросом: есть ли лучшие идеи, чем получение номеров строк и создание связок самостоятельно.Я все еще новичок в Haskell, поэтому я не смог правильно перемещаться по всему исходному коду.

1 Ответ

0 голосов
/ 05 февраля 2019

На это ответил разработчик megaparsec здесь .

Подводя итог, парсеры имеют функцию getOffset, которая возвращает текущий индекс символа.Вы можете использовать это вместе с начальным PosState для создания пакета ошибок, который позже вы сможете распечатать.

У меня есть пример проекта в потоке github , и вставьте его снова здесь:

module TestParser where

import           Data.List.NonEmpty as NonEmpty
import qualified Data.Maybe         as Maybe
import qualified Data.Set           as Set
import           Data.Void
import           Parser
import           Text.Megaparsec

data Sample
  = Test Int
         String
  | TestBlock [Sample]
  | TestBlank
  deriving (Show, Eq)

sampleParser :: Parser Sample
sampleParser = do
  l <- many testParser
  return $ f l
  where
    f []  = TestBlank
    f [s] = s
    f p   = TestBlock p

testParser :: Parser Sample
testParser = do
  offset <- getOffset
  test <- symbol "test"
  return $ Test offset test

fullTestParser :: Parser Sample
fullTestParser = baseParser testParser

testParse :: String -> Maybe (ParseErrorBundle String Void)
testParse input =
  case parse (baseParser sampleParser) "" input of
    Left e -> Just e
    Right x -> do
      (offset, msg) <- testVerify x
      let initialState =
            PosState
              { pstateInput = input
              , pstateOffset = 0
              , pstateSourcePos = initialPos ""
              , pstateTabWidth = defaultTabWidth
              , pstateLinePrefix = ""
              }
      let errorBundle =
            ParseErrorBundle
              { bundleErrors = NonEmpty.fromList [TrivialError offset Nothing Set.empty]
                            -- ^ A collection of 'ParseError's that is sorted by parse error offsets
              , bundlePosState = initialState
                            -- ^ State that is used for line\/column calculation
              }
      return errorBundle

-- Sample verify; throw an error on the second test key
testVerify :: Sample -> Maybe (Int, String)
testVerify tree =
  case tree of
    TestBlock [_, Test a _, _] -> Just (a, "Bad")
    _                          -> Nothing

testMain :: IO ()
testMain = do
  testExample "test test test"
  putStrLn "Done"

testExample :: String -> IO ()
testExample input =
  case testParse input of
    Just error -> putStrLn (errorBundlePretty error)
    Nothing    -> putStrLn "pass"

Некоторые части взяты из других файлов, но важные части находятся в коде.

...