packages feed

morley-1.16.3: src/Morley/Michelson/Parser/Lexer.hs

-- SPDX-FileCopyrightText: 2021 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA

-- TODO [#712]: Remove this next major release
{-# OPTIONS_GHC -Wno-redundant-constraints #-}

module Morley.Michelson.Parser.Lexer
  ( lexeme
  , mSpace
  , spaces
  , symbol
  , symbol'
  , symbol1
  , symbol1'
  , word
  , word'
  , string'
  , parens
  , braces
  , brackets
  , brackets'
  , semicolon
  , comma
  , varID
  ) where

import Prelude hiding (try)

import Data.Char (isDigit, isLower, toLower)
import Data.Text qualified as T
import Text.Megaparsec (Tokens, between, choice, eof, hidden, lookAhead, satisfy, try)
import Text.Megaparsec.Char (lowerChar, space, space1, string)
import Text.Megaparsec.Char.Lexer qualified as L

import Morley.Michelson.Parser.Types (Parser, Parser')
import Morley.Michelson.Untyped qualified as U

-- Lexing
lexeme :: Parser le a -> Parser le a
lexeme = L.lexeme spaces

mSpace :: Parser le ()
mSpace = L.space space1
  (L.skipLineComment "#" >> optionalSemicolon)
  (L.skipBlockComment "/*" "*/" >> optionalSemicolon)
  where
    optionalSemicolon = space >> void (optional semicolon)

spaces :: Parser le ()
spaces =
  (mandatorySpaceOrComment >> mSpace)
  <|> hasFollowingDelimiter ["}", "{", "]", ")", "|", ",", ";", ":", "."]
  <|> eof
  where
    mandatorySpaceOrComment = hidden (space1 <|> L.skipBlockComment "/*" "*/")
    hasFollowingDelimiter = hidden . choice . map (void . lookAhead . string)

symbol :: Tokens Text -> Parser le ()
symbol = void . L.symbol mSpace

symbol' :: Text -> Parser le ()
symbol' str = symbol str <|> symbol (T.map toLower str)

symbol1 :: Tokens Text -> Parser le ()
symbol1 = try . void . L.symbol spaces

symbol1' :: Text -> Parser le ()
symbol1' str = symbol1 str <|> symbol1 (T.map toLower str)

word :: Tokens Text -> a -> Parser le a
word str val = symbol1 str $> val

word' :: Tokens Text -> a -> Parser le a
word' str val = symbol1' str $> val

string' :: Text -> Parser le Text
string' str = string str <|> string (T.map toLower str)

parens :: Parser le a -> Parser le a
parens = between (symbol "(") (symbol ")")

braces :: Parser le a -> Parser le a
braces = between (symbol "{") (symbol "}")

brackets :: Parser le a -> Parser le a
brackets = between (symbol "[") (symbol "]")

brackets' :: Parser le a -> Parser le a
brackets' = between (string "[") (string "]")

semicolon :: Parser le ()
semicolon = symbol ";"

comma :: Parser le ()
comma = symbol ","

varID :: Parser le U.Var
varID = lexeme $ do
  v <- lowerChar
  vs <- many lowerAlphaNumChar
  return $ U.Var (toText (v:vs))
  where
    lowerAlphaNumChar :: Parser' le Char
    lowerAlphaNumChar = satisfy (\x -> isLower x || isDigit x)