1-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net>2--3-- SPDX-License-Identifier: GPL-3.0-only45-- | This module provides top-level definitions for representing programs6-- written in the [QBE](https://c9x.me/compile/) intermediate representation.7module Language.QBE8 ( Program,9 Definition (..),10 localDefs,11 typeDefs,12 globalFuncs,13 Language.QBE.parse,14 ExecError (..),15 parseAndFind,16 )17where1819import Control.Monad.Catch (Exception, MonadThrow, throwM)20import Data.List (find)21import Data.Maybe (mapMaybe)22import Language.QBE.Parser (dataDef, fileDef, funcDef, skipInitComments, typeDef)23import Language.QBE.Types qualified as QBE24import Text.ParserCombinators.Parsec25 ( ParseError,26 Parser,27 SourceName,28 choice,29 eof,30 many,31 parse,32 try,33 )3435-- | A QBE program consists of a sequence of definitions. Four types of objects36-- can be defined: aggregate types, data, functions, and debugging information.37--38-- See also: The corresponding section of the [QBE specification](https://c9x.me/compile/doc/il-v1.2.html#Definitions).39data Definition40 = -- | Definition of data (e.g. a string).41 DefData QBE.DataDef42 | -- | Definition of an aggregate data type.43 DefType QBE.TypeDef44 | -- | Definition of a function.45 DefFunc QBE.FuncDef46 | -- | Definition of a debug file.47 DefFile String48 deriving (Eq, Show)4950parseDef :: Parser Definition51parseDef =52 choice53 [ DefType <$> typeDef,54 -- Need to try funcDef as both funcDef and55 -- dataDef start with a linkage definition.56 --57 -- TODO: Try parsing linkage then funcDef <|> dataDef.58 DefData <$> try dataDef,59 DefFunc <$> funcDef,60 DefFile <$> fileDef61 ]6263-- | A parsed QBE program, represented as a list of 'Definition' values.64type Program = [Definition]6566-- | Wrapper to parse a QBE program using 'Text.ParserCombinators.Parsec.parse'.67parse :: SourceName -> String -> Either ParseError Program68parse =69 Text.ParserCombinators.Parsec.parse70 (skipInitComments *> many parseDef <* eof)7172-- | Utility function to obtain all functions defined in a QBE 'Program'.73globalFuncs :: Program -> [QBE.FuncDef]74globalFuncs = mapMaybe globalFuncs'75 where76 globalFuncs' :: Definition -> Maybe QBE.FuncDef77 globalFuncs' (DefFunc f) = Just f78 globalFuncs' _ = Nothing7980-- | Returns all non-exported data and function definitions of a 'Program'.81localDefs :: Program -> [QBE.GlobalIdent]82localDefs = mapMaybe go83 where84 isGlobal :: [QBE.Linkage] -> Bool85 isGlobal = elem QBE.LExport8687 go :: Definition -> Maybe QBE.GlobalIdent88 go (DefData dd)89 | isGlobal (QBE.linkage dd) = Nothing90 | otherwise = Just (QBE.name dd)91 go (DefFunc fd)92 | isGlobal (QBE.fLinkage fd) = Nothing93 | otherwise = Just (QBE.fName fd)94 go _ = Nothing9596-- | Returns all defined types of a 'Program'.97typeDefs :: Program -> [QBE.UserIdent]98typeDefs = mapMaybe go99 where100 go :: Definition -> Maybe QBE.UserIdent101 go (DefType ty) = Just $ QBE.aggName ty102 go _ = Nothing103104------------------------------------------------------------------------105106-- | Custom 'Exception' used for error handling in 'parseAndFind'.107data ExecError108 = -- | The input is not a valid QBE program.109 ESyntaxError ParseError110 | -- | The given entry function is not defined in the QBE program.111 EUnknownEntry QBE.GlobalIdent112 deriving (Show)113114instance Exception ExecError115116-- | Utility function for the common task of parsing an input as a QBE117-- 'Program' and, within that program, finding the entry function. If the118-- function doesn't exist or a the input is invalid a 'ExecError' exception119-- is thrown.120parseAndFind ::121 (MonadThrow m) =>122 QBE.GlobalIdent ->123 String ->124 m (Program, QBE.FuncDef)125parseAndFind entryIdent input = do126 prog <- case Language.QBE.parse "" input of -- TODO: file name127 Right rt -> pure rt128 Left err -> throwM $ ESyntaxError err129130 let funcs = globalFuncs prog131 func <- case find (\f -> QBE.fName f == entryIdent) funcs of132 Just x -> pure x133 Nothing -> throwM $ EUnknownEntry entryIdent134135 pure (prog, func)