packages feed

snail-0.1.2.2: example/Main.hs

module Main where

import Snail
import Control.Monad.Except
import Data.Text (Text)
import Data.Text qualified as Text
import Text.Read (readMaybe)

data Operation = Addition | Multiplication 
  deriving (Eq, Show)

data Ast
  = AstInt Integer
  | AstOperation Operation Ast Ast
  deriving (Eq, Show)

data LangError 
  = UnknownLexeme Text
  | UnknownOperation Text
  | TextLiteralUnsupported
  | EmptyExpression
  deriving (Eq, Show)

parseLeaf :: (MonadError LangError m) => Text -> m Ast
parseLeaf = \case
  txt ->
    case readMaybe @Integer $ Text.unpack txt of
      Nothing -> throwError $ UnknownLexeme txt
      Just int -> pure $ AstInt int

parseOp :: (MonadError LangError m) => Text -> m Operation
parseOp = \case
  "+" -> pure Addition
  "*" -> pure Multiplication
  txt -> throwError $ UnknownOperation txt

fromSnail :: (MonadError LangError m) => SnailAst -> m Ast
fromSnail = \case
  -- no text literals are supported in this language
  TextLiteral _ -> throwError TextLiteralUnsupported
  -- `X` where `X` is a leaf in 'Ast'
  Lexeme (_, leaf) -> parseLeaf leaf
  SExpression _ _ [Lexeme (_, txt), argumentOne, argumentTwo] -> do
    op <- parseOp txt
    one <- fromSnail argumentOne
    two <- fromSnail argumentTwo
    pure $ AstOperation op one two
  -- empty expressions are invalid
  SExpression _ _ [] -> throwError EmptyExpression
  -- expression of expressions, e.g. `((X))` -> `(X)`
  SExpression leading fence exprs ->
    fromSnail . unwrap . SExpression leading fence $ unwrap <$> exprs

main :: IO ()
main = do
  case parseSnail "(+ 1 2)" of
    Left err -> print $ "Unable to parse snail: " <> show err
    Right [snail] -> runExceptT (fromSnail snail) >>= print
    Right _ -> putStrLn "Excepted single expression"