1-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net>2--3-- SPDX-License-Identifier: GPL-3.0-only45module Language.QBE6 ( Program,7 Definition (..),8 globalFuncs,9 Language.QBE.parse,10 ExecError (..),11 parseAndFind,12 )13where1415import Control.Monad.Catch (Exception, MonadThrow, throwM)16import Data.List (find)17import Data.Maybe (mapMaybe)18import Language.QBE.Parser (dataDef, fileDef, funcDef, skipInitComments, typeDef)19import Language.QBE.Types (DataDef, FuncDef, GlobalIdent, TypeDef, fName)20import Text.ParserCombinators.Parsec21 ( ParseError,22 Parser,23 SourceName,24 choice,25 eof,26 many,27 parse,28 try,29 )3031data Definition32 = DefData DataDef33 | DefType TypeDef34 | DefFunc FuncDef35 | DefFile String36 deriving (Eq, Show)3738parseDef :: Parser Definition39parseDef =40 choice41 [ DefType <$> typeDef,42 -- Need to try funcDef as both funcDef and43 -- dataDef start with a linkage definition.44 --45 -- TODO: Try parsing linkage then funcDef <|> dataDef.46 DefData <$> try dataDef,47 DefFunc <$> funcDef,48 DefFile <$> fileDef49 ]5051type Program = [Definition]5253globalFuncs :: Program -> [FuncDef]54globalFuncs = mapMaybe globalFuncs'55 where56 globalFuncs' :: Definition -> Maybe FuncDef57 globalFuncs' (DefFunc f) = Just f58 globalFuncs' _ = Nothing5960parse :: SourceName -> String -> Either ParseError Program61parse =62 Text.ParserCombinators.Parsec.parse63 (skipInitComments *> many parseDef <* eof)6465------------------------------------------------------------------------6667data ExecError68 = ESyntaxError ParseError69 | EUnknownEntry GlobalIdent70 deriving (Show)7172instance Exception ExecError7374-- | Utility function for the common task of parsing an input as a QBE75-- 'Program' and, within that program, finding the entry function. If the76-- function doesn't exist or a the input is invalid an exception is thrown.77parseAndFind ::78 (MonadThrow m) =>79 GlobalIdent ->80 String ->81 m (Program, FuncDef)82parseAndFind entryIdent input = do83 prog <- case Language.QBE.parse "" input of -- TODO: file name84 Right rt -> pure rt85 Left err -> throwM $ ESyntaxError err8687 let funcs = globalFuncs prog88 func <- case find (\f -> fName f == entryIdent) funcs of89 Just x -> pure x90 Nothing -> throwM $ EUnknownEntry entryIdent9192 pure (prog, func)