packages feed

language-qux 0.1.1.3 → 0.2.0.0

raw patch · 15 files changed

+913/−702 lines, 15 filesdep +llvm-general-purePVP ok

version bump matches the API change (PVP)

Dependencies added: llvm-general-pure

API changes (from Hackage documentation)

- Language.Qux.Annotated.Exception: duplicateFunctionName :: Decl SourcePos -> TypeException
- Language.Qux.Annotated.Exception: duplicateParameterName :: Id SourcePos -> TypeException
- Language.Qux.Annotated.Exception: invalidArgumentsCount :: Expr SourcePos -> Int -> TypeException
- Language.Qux.Annotated.Exception: mismatchedType :: Type SourcePos -> [Type] -> TypeException
- Language.Qux.Annotated.Exception: undefinedFunctionCall :: Expr SourcePos -> TypeException
- Language.Qux.Annotated.PrettyPrinter: LeftMode :: Mode
- Language.Qux.Annotated.PrettyPrinter: OneLineMode :: Mode
- Language.Qux.Annotated.PrettyPrinter: PageMode :: Mode
- Language.Qux.Annotated.PrettyPrinter: Style :: Mode -> Int -> Float -> Style
- Language.Qux.Annotated.PrettyPrinter: ZigZagMode :: Mode
- Language.Qux.Annotated.PrettyPrinter: [lineLength] :: Style -> Int
- Language.Qux.Annotated.PrettyPrinter: [mode] :: Style -> Mode
- Language.Qux.Annotated.PrettyPrinter: [ribbonsPerLine] :: Style -> Float
- Language.Qux.Annotated.PrettyPrinter: class Pretty a
- Language.Qux.Annotated.PrettyPrinter: data Mode :: *
- Language.Qux.Annotated.PrettyPrinter: data Style :: *
- Language.Qux.Annotated.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Decl a)
- Language.Qux.Annotated.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Expr a)
- Language.Qux.Annotated.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Id a)
- Language.Qux.Annotated.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Program a)
- Language.Qux.Annotated.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Stmt a)
- Language.Qux.Annotated.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Type a)
- Language.Qux.Annotated.PrettyPrinter: pPrint :: Pretty a => a -> Doc
- Language.Qux.Annotated.PrettyPrinter: pPrintList :: Pretty a => PrettyLevel -> [a] -> Doc
- Language.Qux.Annotated.PrettyPrinter: pPrintPrec :: Pretty a => PrettyLevel -> Rational -> a -> Doc
- Language.Qux.Annotated.PrettyPrinter: render :: Doc -> String
- Language.Qux.Annotated.PrettyPrinter: renderOneLine :: Doc -> String
- Language.Qux.Annotated.PrettyPrinter: renderStyle :: Style -> Doc -> String
- Language.Qux.Annotated.Simplify: sDecl :: Decl a -> Decl
- Language.Qux.Annotated.Simplify: sExpr :: Expr a -> Expr
- Language.Qux.Annotated.Simplify: sId :: Id a -> String
- Language.Qux.Annotated.Simplify: sProgram :: Program a -> Program
- Language.Qux.Annotated.Simplify: sStmt :: Stmt a -> Stmt
- Language.Qux.Annotated.Simplify: sType :: Type a -> Type
- Language.Qux.Annotated.Syntax: name :: Decl a -> Id a
- Language.Qux.Annotated.Syntax: parameterNames :: Decl a -> [Id a]
- Language.Qux.Annotated.Syntax: parameterTypes :: Decl a -> [Type a]
- Language.Qux.Annotated.Syntax: parameters :: Decl a -> [(Type a, Id a)]
- Language.Qux.Annotated.Syntax: returnType :: Decl a -> Type a
- Language.Qux.Annotated.Syntax: stmts :: Decl a -> [Stmt a]
- Language.Qux.Annotated.TypeChecker: checkValue :: Value -> Check Type
- Language.Qux.Annotated.TypeChecker: type Evaluation = StateT Locals (Reader Context)
- Language.Qux.Interpreter: context :: Program -> Context
- Language.Qux.Interpreter: data Context
- Language.Qux.Interpreter: evalExpr :: Expr -> Evaluation Value
- Language.Qux.Interpreter: exec :: Program -> Id -> [Value] -> Value
- Language.Qux.Interpreter: execStmt :: Stmt -> Execution ()
- Language.Qux.Interpreter: runExecution :: (a -> Value) -> Execution a -> Evaluation Value
- Language.Qux.Interpreter: type Evaluation = StateT Locals (Reader Context)
- Language.Qux.Interpreter: type Execution = EitherT Value Evaluation
- Language.Qux.Interpreter: type Locals = Map Id Value
- Language.Qux.PrettyPrinter: LeftMode :: Mode
- Language.Qux.PrettyPrinter: OneLineMode :: Mode
- Language.Qux.PrettyPrinter: PageMode :: Mode
- Language.Qux.PrettyPrinter: Style :: Mode -> Int -> Float -> Style
- Language.Qux.PrettyPrinter: ZigZagMode :: Mode
- Language.Qux.PrettyPrinter: [lineLength] :: Style -> Int
- Language.Qux.PrettyPrinter: [mode] :: Style -> Mode
- Language.Qux.PrettyPrinter: [ribbonsPerLine] :: Style -> Float
- Language.Qux.PrettyPrinter: class Pretty a
- Language.Qux.PrettyPrinter: data Mode :: *
- Language.Qux.PrettyPrinter: data Style :: *
- Language.Qux.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.BinaryOp
- Language.Qux.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Decl
- Language.Qux.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Expr
- Language.Qux.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Program
- Language.Qux.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Stmt
- Language.Qux.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Type
- Language.Qux.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.UnaryOp
- Language.Qux.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Value
- Language.Qux.PrettyPrinter: instance Text.PrettyPrint.HughesPJClass.Pretty Text.PrettyPrint.HughesPJ.Doc
- Language.Qux.PrettyPrinter: pPrint :: Pretty a => a -> Doc
- Language.Qux.PrettyPrinter: pPrintList :: Pretty a => PrettyLevel -> [a] -> Doc
- Language.Qux.PrettyPrinter: pPrintPrec :: Pretty a => PrettyLevel -> Rational -> a -> Doc
- Language.Qux.PrettyPrinter: render :: Doc -> String
- Language.Qux.PrettyPrinter: renderOneLine :: Doc -> String
- Language.Qux.PrettyPrinter: renderStyle :: Style -> Doc -> String
- Language.Qux.Syntax: name :: Decl -> Id
- Language.Qux.Syntax: newtype Program
- Language.Qux.Syntax: parameterNames :: Decl -> [Id]
- Language.Qux.Syntax: parameterTypes :: Decl -> [Type]
- Language.Qux.Syntax: parameters :: Decl -> [(Type, Id)]
- Language.Qux.Syntax: returnType :: Decl -> Type
- Language.Qux.Syntax: stmts :: Decl -> [Stmt]
- Language.Qux.Syntax: types :: Decl -> [Type]
- Language.Qux.Version: major :: Integer
- Language.Qux.Version: minor :: Integer
- Language.Qux.Version: patch :: Integer
+ Language.Qux.Annotated.Exception: DuplicateFunctionName :: SourcePos -> Id -> TypeException
+ Language.Qux.Annotated.Exception: DuplicateParameterName :: SourcePos -> Id -> TypeException
+ Language.Qux.Annotated.Exception: InvalidFunctionCall :: SourcePos -> Int -> Int -> TypeException
+ Language.Qux.Annotated.Exception: MismatchedType :: SourcePos -> Id -> [Id] -> TypeException
+ Language.Qux.Annotated.Exception: TypeException :: SourcePos -> String -> TypeException
+ Language.Qux.Annotated.Exception: instance GHC.Classes.Eq Language.Qux.Annotated.Exception.TypeException
+ Language.Qux.Annotated.Exception: message :: TypeException -> String
+ Language.Qux.Annotated.Exception: pos :: TypeException -> SourcePos
+ Language.Qux.Annotated.Parser: id_ :: Parser (Id SourcePos)
+ Language.Qux.Annotated.Syntax: TypedExpr :: a -> Type -> (Expr a) -> Expr a
+ Language.Qux.Annotated.Syntax: class Simplifiable n r | n -> r
+ Language.Qux.Annotated.Syntax: instance GHC.Base.Functor Language.Qux.Annotated.Syntax.Decl
+ Language.Qux.Annotated.Syntax: instance GHC.Base.Functor Language.Qux.Annotated.Syntax.Expr
+ Language.Qux.Annotated.Syntax: instance GHC.Base.Functor Language.Qux.Annotated.Syntax.Id
+ Language.Qux.Annotated.Syntax: instance GHC.Base.Functor Language.Qux.Annotated.Syntax.Program
+ Language.Qux.Annotated.Syntax: instance GHC.Base.Functor Language.Qux.Annotated.Syntax.Stmt
+ Language.Qux.Annotated.Syntax: instance GHC.Base.Functor Language.Qux.Annotated.Syntax.Type
+ Language.Qux.Annotated.Syntax: instance Language.Qux.Annotated.Syntax.Simplifiable (Language.Qux.Annotated.Syntax.Decl a) Language.Qux.Syntax.Decl
+ Language.Qux.Annotated.Syntax: instance Language.Qux.Annotated.Syntax.Simplifiable (Language.Qux.Annotated.Syntax.Expr a) Language.Qux.Syntax.Expr
+ Language.Qux.Annotated.Syntax: instance Language.Qux.Annotated.Syntax.Simplifiable (Language.Qux.Annotated.Syntax.Id a) [GHC.Types.Char]
+ Language.Qux.Annotated.Syntax: instance Language.Qux.Annotated.Syntax.Simplifiable (Language.Qux.Annotated.Syntax.Program a) Language.Qux.Syntax.Program
+ Language.Qux.Annotated.Syntax: instance Language.Qux.Annotated.Syntax.Simplifiable (Language.Qux.Annotated.Syntax.Stmt a) Language.Qux.Syntax.Stmt
+ Language.Qux.Annotated.Syntax: instance Language.Qux.Annotated.Syntax.Simplifiable (Language.Qux.Annotated.Syntax.Type a) Language.Qux.Syntax.Type
+ Language.Qux.Annotated.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Decl a)
+ Language.Qux.Annotated.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Expr a)
+ Language.Qux.Annotated.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Id a)
+ Language.Qux.Annotated.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Program a)
+ Language.Qux.Annotated.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Stmt a)
+ Language.Qux.Annotated.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty (Language.Qux.Annotated.Syntax.Type a)
+ Language.Qux.Annotated.Syntax: simp :: Simplifiable n r => n -> r
+ Language.Qux.Annotated.TypeChecker: Context :: Map Id [Type] -> Context
+ Language.Qux.Annotated.TypeChecker: [functions] :: Context -> Map Id [Type]
+ Language.Qux.Annotated.TypeChecker: emptyContext :: Context
+ Language.Qux.Annotated.TypeChecker: execCheck :: Check a -> Context -> [TypeException]
+ Language.Qux.Annotated.TypeChecker: retrieve :: MonadReader Context m => Id -> StateT Locals m (Maybe [Type])
+ Language.Qux.Annotated.TypeChecker: runCheck :: Check a -> Context -> (a, [TypeException])
+ Language.Qux.Annotated.TypeResolver: Context :: Map Id [Type] -> Context
+ Language.Qux.Annotated.TypeResolver: [functions] :: Context -> Map Id [Type]
+ Language.Qux.Annotated.TypeResolver: context :: Program -> Context
+ Language.Qux.Annotated.TypeResolver: data Context
+ Language.Qux.Annotated.TypeResolver: emptyContext :: Context
+ Language.Qux.Annotated.TypeResolver: extractType :: Expr a -> Type
+ Language.Qux.Annotated.TypeResolver: resolve :: Program SourcePos -> Program SourcePos
+ Language.Qux.Annotated.TypeResolver: resolveDecl :: Decl SourcePos -> Resolve (Decl SourcePos)
+ Language.Qux.Annotated.TypeResolver: resolveExpr :: Expr SourcePos -> StateT Locals Resolve (Expr SourcePos)
+ Language.Qux.Annotated.TypeResolver: resolveProgram :: Program SourcePos -> Resolve (Program SourcePos)
+ Language.Qux.Annotated.TypeResolver: resolveStmt :: Stmt SourcePos -> StateT Locals Resolve (Stmt SourcePos)
+ Language.Qux.Annotated.TypeResolver: resolveValue :: Value -> Type
+ Language.Qux.Annotated.TypeResolver: retrieve :: MonadReader Context m => Id -> StateT Locals m (Maybe [Type])
+ Language.Qux.Annotated.TypeResolver: runResolve :: Resolve a -> Context -> a
+ Language.Qux.Annotated.TypeResolver: type Locals = Map Id Type
+ Language.Qux.Annotated.TypeResolver: type Resolve = Reader Context
+ Language.Qux.Llvm.Compiler: compile :: Program -> Module
+ Language.Qux.Llvm.Compiler: instance GHC.Show.Show Language.Qux.Llvm.Compiler.Context
+ Language.Qux.Syntax: TypedExpr :: Type -> Expr -> Expr
+ Language.Qux.Syntax: data Program
+ Language.Qux.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.BinaryOp
+ Language.Qux.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Decl
+ Language.Qux.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Expr
+ Language.Qux.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Program
+ Language.Qux.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Stmt
+ Language.Qux.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Type
+ Language.Qux.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.UnaryOp
+ Language.Qux.Syntax: instance Text.PrettyPrint.HughesPJClass.Pretty Language.Qux.Syntax.Value
- Language.Qux.Annotated.Syntax: Program :: a -> [Decl a] -> Program a
+ Language.Qux.Annotated.Syntax: Program :: a -> [Id a] -> [Decl a] -> Program a
- Language.Qux.Annotated.Syntax: ann :: Annotated node => node a -> a
+ Language.Qux.Annotated.Syntax: ann :: Annotated n => n a -> a
- Language.Qux.Annotated.Syntax: class Annotated node
+ Language.Qux.Annotated.Syntax: class Annotated n
- Language.Qux.Annotated.TypeChecker: check :: Program SourcePos -> Except TypeException ()
+ Language.Qux.Annotated.TypeChecker: check :: Program SourcePos -> [TypeException]
- Language.Qux.Annotated.TypeChecker: checkExpr :: Expr SourcePos -> Check Type
+ Language.Qux.Annotated.TypeChecker: checkExpr :: Expr SourcePos -> StateT Locals Check Type
- Language.Qux.Annotated.TypeChecker: checkStmt :: Stmt SourcePos -> Check ()
+ Language.Qux.Annotated.TypeChecker: checkStmt :: Stmt SourcePos -> StateT Locals Check ()
- Language.Qux.Annotated.TypeChecker: type Check = ExceptT TypeException Evaluation
+ Language.Qux.Annotated.TypeChecker: type Check = ReaderT Context (Writer [TypeException])
- Language.Qux.Syntax: Program :: [Decl] -> Program
+ Language.Qux.Syntax: Program :: [Id] -> [Decl] -> Program
- Language.Qux.Version: version :: [Char]
+ Language.Qux.Version: version :: Version

Files

language-qux.cabal view
@@ -1,12 +1,14 @@ name:           language-qux-version:        0.1.1.3+version:        0.2.0.0  author:         Henry J. Wylde maintainer:     public@hjwylde.com homepage:       https://github.com/qux-lang/language-qux  synopsis:       Utilities for working with the Qux language--- description:+description:    Qux is an experimental language developed from the ground up with the aim of static+                compile time verification. This package provides tools for working with it (parsing,+                compiling, pretty printing and type checking).  license:        BSD3 license-file:   LICENSE@@ -20,24 +22,29 @@     exposed-modules:         Language.Qux.Annotated.Exception,         Language.Qux.Annotated.Parser,-        Language.Qux.Annotated.PrettyPrinter,-        Language.Qux.Annotated.Simplify,         Language.Qux.Annotated.Syntax,         Language.Qux.Annotated.TypeChecker,-        Language.Qux.Interpreter,-        Language.Qux.PrettyPrinter,+        Language.Qux.Annotated.TypeResolver,+        Language.Qux.Llvm.Compiler,         Language.Qux.Syntax,         Language.Qux.Version     other-modules:         Language.Qux.Lexer,+        Language.Qux.Llvm.Builder,         Paths_language_qux      default-language: Haskell2010+    other-extensions:+        DeriveFunctor,+        FlexibleInstances,+        FunctionalDependencies,+        MultiParamTypeClasses     build-depends:         base >= 4.8 && < 5,         containers == 0.5.*,         either == 4.*,         indents >= 0.3.3 && < 0.4,+        llvm-general-pure == 3.4.*,         mtl == 2.*,         parsec == 3.*,         pretty >= 1.1.2 && < 2,
src/Language/Qux/Annotated/Exception.hs view
@@ -7,68 +7,59 @@ License     : BSD3 Maintainer  : public@hjwylde.com -Exceptions and utility creation functions.+Exceptions and utility functions. -}  module Language.Qux.Annotated.Exception (-    -- * Type exceptions-    TypeException,--    -- ** Creation functions-    duplicateFunctionName, duplicateParameterName, invalidArgumentsCount, mismatchedType,-    undefinedFunctionCall+    -- * Type exception+    TypeException(..),+    pos, message, ) where  import Data.List (intercalate) -import Language.Qux.Annotated.Parser (SourcePos, sourceName, sourceLine, sourceColumn)-import Language.Qux.Annotated.PrettyPrinter-import qualified Language.Qux.Annotated.Syntax as Ann+import Language.Qux.Annotated.Parser (SourcePos) import Language.Qux.Syntax -import Text.PrettyPrint (doubleQuotes) ---- | An exception that occurs during type checking. See "Language.Qux.TypeChecker".-data TypeException = TypeException SourcePos String+-- | An exception that occurs during type checking. See "Language.Qux.Annotated.TypeChecker".+data TypeException  = TypeException SourcePos String        -- ^ A generic type exception with a+                                                            --   position and message.+                    | DuplicateFunctionName SourcePos Id    -- ^ Indicates a function of the given+                                                            --   name already exists.+                    | DuplicateParameterName SourcePos Id   -- ^ Indicates a parameter of the given+                                                            --   name already exists.+                    | InvalidFunctionCall SourcePos Int Int -- ^ Indicates the wrong number of+                                                            --   arguments was passed to the+                                                            --   function call.+                    | MismatchedType SourcePos Id [Id]      -- ^ Indicates a type mismatch.+    deriving Eq  instance Show TypeException where-    show (TypeException pos message) = show pos ++ ":\n" ++ message-+    show e = show (pos e) ++ ":\n" ++ message e --- |    @duplciateFunctionName decl@ creates a 'TypeException' indicating that a duplicate function---      declaration @decl@ was found.-duplicateFunctionName :: Ann.Decl SourcePos -> TypeException-duplicateFunctionName (Ann.FunctionDecl pos (Ann.Id _ name) _ _) = TypeException pos ("duplicate function name \"" ++ name ++ "\"")+-- | Extracts the source position from the exception.+pos :: TypeException -> SourcePos+pos (TypeException p _)             = p+pos (DuplicateFunctionName p _)     = p+pos (DuplicateParameterName p _)    = p+pos (InvalidFunctionCall p _ _)     = p+pos (MismatchedType p _ _)          = p --- |    @duplicateParameterName parameter@ creates a 'TypeException' indicating that a duplicate---      parameter @parameter@ was found.-duplicateParameterName :: Ann.Id SourcePos -> TypeException-duplicateParameterName (Ann.Id pos name) = TypeException pos ("duplicate parameter name \"" ++ name ++ "\"")------ |    @invalidArgumentsCount received expected@ creates a 'TypeException' indicating that an---      application call (@received@) with an invalid number of arguments was passed to a function---      expecting @expected@.-invalidArgumentsCount :: Ann.Expr SourcePos -> Int -> TypeException-invalidArgumentsCount (Ann.ApplicationExpr pos _ arguments) expected = TypeException pos $ intercalate " " [-    "invalid arguments count", show $ length arguments,+-- | Creates a human understandable message from the exception.+message :: TypeException -> String+message (TypeException _ m)                         = m+message (DuplicateFunctionName _ name)              = "duplicate function name \"" ++ name ++ "\""+message (DuplicateParameterName _ name)             = "duplicate parameter name \"" ++ name ++ "\""+message (InvalidFunctionCall _ received expected)   = intercalate " " [+    "invalid arguments count", show received,     "\nexpecting", show expected     ]---- |    @mismatchedType received expects@ creates a 'TypeException' indicating that one of @expects@---      was expected.-mismatchedType :: Ann.Type SourcePos -> [Type] -> TypeException-mismatchedType received expects = TypeException (Ann.ann received) $ intercalate " " [-    "unexpected type", renderOneLine $ doubleQuotes (pPrint received),-    "\nexpecting", sentence "or" (map (renderOneLine . doubleQuotes . pPrint) expects)+message (MismatchedType _ received expects)         = intercalate " " [+    "unexpected type", "\"" ++ received ++ "\"",+    "\nexpecting", sentence "or" expects     ]---- | @undefinedFunctionCall app@ creates a 'TypeException' indicating that an application call--- (@app@) was made to an undefined function.-undefinedFunctionCall :: Ann.Expr SourcePos -> TypeException-undefinedFunctionCall (Ann.ApplicationExpr pos (Ann.Id _ name) _) = TypeException pos ("call to undefined function \"" ++ name ++ "\"")--sentence :: String -> [String] -> String-sentence _ [x]  = x-sentence sep xs = intercalate " " [intercalate ", " (map show $ init xs), sep, show $ last xs]+    where+        sentence _ [x]  = x+        sentence sep xs = intercalate " " [intercalate ", " (map show $ init xs), sep, show $ last xs] 
src/Language/Qux/Annotated/Parser.hs view
@@ -11,15 +11,16 @@ -}  module Language.Qux.Annotated.Parser (-    -- * Types-    Parser, ParseError, SourcePos,-    sourceName, sourceLine, sourceColumn,--    -- ** Parsing+    -- * Parser type+    Parser, ParseError,     parse, -    -- ** Parsers-    program, decl, stmt, expr, value, type_+    -- * Source position type+    SourcePos,+    sourceName, sourceLine, sourceColumn,++    -- * Parsers+    id_, program, decl, stmt, expr, value, type_ ) where  import Control.Monad.State@@ -28,7 +29,7 @@ import Language.Qux.Annotated.Syntax import Language.Qux.Lexer -import Text.Parsec hiding (State, parse)+import Text.Parsec          hiding (State, parse) import Text.Parsec.Expr import Text.Parsec.Indent @@ -36,10 +37,9 @@ -- | A 'ParsecT' that retains indentation information. type Parser a = ParsecT String () (State SourcePos) a ---- |    @parse parser sourceName input@ parses @input@ using @parser@.---      Returns either a 'ParseError' or @a@.---      This method wraps 'runParserT' by running the indentation resolver over the parser's state.+-- | @parse parser sourceName input@ parses @input@ using @parser@.+--   Returns either a 'ParseError' or @a@.+--   This method wraps 'runParserT' by running the indentation resolver over the parser's state. parse :: Parser a -> SourceName -> String -> Except ParseError a parse parser sourceName input = except $ runIndent sourceName (runParserT parser () sourceName input) @@ -52,46 +52,52 @@ program :: Parser (Program SourcePos) program = do     pos <- getPosition+     whiteSpace     checkIndent+    reserved "module"+    module_ <- sepBy1 id_ dot+    checkIndent     decls <- block decl     eof-    return $ Program pos decls+    return $ Program pos module_ decls+    <?> "program"  -- | 'Decl' parser. decl :: Parser (Decl SourcePos) decl = do     pos <- getPosition+     name <- id_-    symbol "::"+    symbol_ "::"     parameters <- (try $ (,) <$> type_ <*> id_) `endBy` rightArrow     returnType <- type_     colon     indented     stmts <- block stmt+     return $ FunctionDecl pos name (parameters ++ [(returnType, Id pos "@")]) stmts     <?> "function declaration"  -- | 'Stmt' parser. stmt :: Parser (Stmt SourcePos)-stmt = choice [-    ifStmt,-    returnStmt,-    whileStmt-    ] <?> "statement"+stmt = choice [ifStmt, returnStmt, whileStmt] <?> "statement"     where         ifStmt      = do             pos <- getPosition+             reserved "if"             condition <- expr             colon             indented             trueStmts <- block stmt             falseStmts <- option [] (checkIndent >> withBlock' (do { reserved "else"; colon }) stmt)+             return $ IfStmt pos condition trueStmts falseStmts         returnStmt  = ReturnStmt <$> getPosition <* reserved "return" <*> expr         whileStmt   = do             pos <- getPosition+             withBlock (WhileStmt pos) (reserved "while" *> expr <* colon) stmt  -- | 'Expr' parser.@@ -145,12 +151,14 @@ unaryExpr :: UnaryOp -> String -> Parser ((Expr SourcePos) -> (Expr SourcePos)) unaryExpr op sym = getPosition >>= \pos -> UnaryExpr pos op <$ operator sym --- | 'Value' parser.+-- |    'Value' parser.+--      A value doesn't have a source position attached as this can be retrieved from a 'ValueExpr'. value :: Parser Value value = choice [     BoolValue False <$  reserved "false",     BoolValue True  <$  reserved "true",     IntValue        <$> natural,+    ListValue       <$> brackets (value `sepEndBy` comma),     NilValue        <$  reserved "nil"     ] <?> "value" 
− src/Language/Qux/Annotated/PrettyPrinter.hs
@@ -1,47 +0,0 @@--{-|-Module      : Language.Qux.Annotated.PrettyPrinter-Description : Pretty instances and rendering functions for Qux language elements.--Copyright   : (c) Henry J. Wylde, 2015-License     : BSD3-Maintainer  : public@hjwylde.com--"Text.PrettyPrint" instances and rendering functions for Qux language elements.--To render a program, call: @render $ pPrint program@--}--module Language.Qux.Annotated.PrettyPrinter (-    -- Types-    Pretty(..), Style(..), Mode(..),--    -- * Rendering-    render, renderStyle, renderOneLine-) where--import Language.Qux.Annotated.Simplify-import Language.Qux.Annotated.Syntax-import Language.Qux.PrettyPrinter--import Text.PrettyPrint (text)---instance Pretty (Id a) where-    pPrint = text . sId--instance Pretty (Program a) where-    pPrint = pPrint . sProgram--instance Pretty (Decl a) where-    pPrint = pPrint . sDecl--instance Pretty (Stmt a) where-    pPrint = pPrint . sStmt--instance Pretty (Expr a) where-    pPrint = pPrint . sExpr--instance Pretty (Type a) where-    pPrint = pPrint . sType-
− src/Language/Qux/Annotated/Simplify.hs
@@ -1,58 +0,0 @@--{-|-Module      : Language.Qux.Annotated.Simplify-Description : Simplify functions that return abstract syntax tree nodes without annotations.--Copyright   : (c) Henry J. Wylde, 2015-License     : BSD3-Maintainer  : public@hjwylde.com--Simplify functions that return abstract syntax tree nodes without annotations.--}--module Language.Qux.Annotated.Simplify (-    -- * Functions-    sId, sProgram, sDecl, sStmt, sExpr, sType-) where--import qualified Language.Qux.Annotated.Syntax as Ann-import Language.Qux.Syntax----- | Simplifies an identifier.-sId :: Ann.Id a -> String-sId (Ann.Id _ id) = id---- | Simplifies a program.-sProgram :: Ann.Program a -> Program-sProgram (Ann.Program _ decls) = Program $ map sDecl decls---- | Simplifies a declaration.-sDecl :: Ann.Decl a -> Decl-sDecl (Ann.FunctionDecl _ id parameters stmts) = FunctionDecl (sId id) (map (tmap sType sId) parameters) (map sStmt stmts)---- | Simplifies a statement.-sStmt :: Ann.Stmt a -> Stmt-sStmt (Ann.IfStmt _ condition trueStmts falseStmts) = IfStmt (sExpr condition) (map sStmt trueStmts) (map sStmt falseStmts)-sStmt (Ann.ReturnStmt _ expr)                       = ReturnStmt (sExpr expr)-sStmt (Ann.WhileStmt _ condition stmts)             = WhileStmt (sExpr condition) (map sStmt stmts)---- | Simplifies an expression.-sExpr :: Ann.Expr a -> Expr-sExpr (Ann.ApplicationExpr _ id arguments)  = ApplicationExpr (sId id) (map sExpr arguments)-sExpr (Ann.BinaryExpr _ op lhs rhs)         = BinaryExpr op (sExpr lhs) (sExpr rhs)-sExpr (Ann.ListExpr _ elements)             = ListExpr (map sExpr elements)-sExpr (Ann.UnaryExpr _ op expr)             = UnaryExpr op (sExpr expr)-sExpr (Ann.ValueExpr _ value)               = ValueExpr value---- | Simplifies a type.-sType :: Ann.Type a -> Type-sType (Ann.BoolType _)          = BoolType-sType (Ann.IntType _)           = IntType-sType (Ann.ListType _ inner)    = ListType $ sType inner-sType (Ann.NilType _)           = NilType---tmap :: (a -> b) -> (c -> d) -> (a, c) -> (b, d)-tmap f g (a, c) = (f a, g c)-
src/Language/Qux/Annotated/Syntax.hs view
@@ -8,112 +8,165 @@ Maintainer  : public@hjwylde.com  Abstract syntax tree nodes with annotations.- The annotation style was inspired by haskell-src-exts.++Instances of 'Simplifiable' are provided for simplifying a node down to it's unannotated form and of+    'Pretty' for pretty printing. -} +{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+ module Language.Qux.Annotated.Syntax (-    -- * Type class+    -- * Type classes     Annotated(..),--    -- ** Annotated nodes-    Id(..), Program(..),--    Decl(..),-    name, parameters, parameterNames, parameterTypes, returnType, stmts,+    Simplifiable(..), -    Stmt(..), Expr(..), Type(..),+    -- * Annotated nodes+    Id(..), Program(..), Decl(..), Stmt(..), Expr(..), Type(..), -    -- ** Regular nodes+    -- * Regular nodes     BinaryOp(..), UnaryOp(..), Value(..) ) where -import Language.Qux.Syntax (BinaryOp(..), UnaryOp(..), Value(..))+import              Language.Qux.Syntax (BinaryOp(..), UnaryOp(..), Value(..))+import qualified    Language.Qux.Syntax as S +import Text.PrettyPrint.HughesPJClass + -- | An annotated class.-class Annotated node where-    ann :: node a -> a+--   Annotations are used for attaching data to a node, such as a 'Text.Parsec.SourcePos'.+class Annotated n where+    ann :: n a -> a +-- | A simplifiable class.+--   Simplifiable is used to simplify a node to a a simpler form.+--   See "Language.Qux.Syntax" for simpler forms of the nodes defined here.+class Simplifiable n r | n -> r where+    simp :: n -> r --- | An identifier.++-- | An identifier. Identifiers should match '[a-z_][a-zA-Z0-9_']*'. data Id a = Id a String-    deriving (Eq, Show)+    deriving (Eq, Functor, Show)  instance Annotated Id where     ann (Id a _) = a --- | A program is a list of declarations.-data Program a = Program a [Decl a]-    deriving (Eq, Show)+instance Simplifiable (Id a) [Char] where+    simp (Id _ id_) = id_ -instance Annotated Program where-    ann (Program a _) = a+instance Pretty (Id a) where+    pPrint = text . simp --- | A declaration.-data Decl a = FunctionDecl a (Id a) [(Type a, Id a)] [Stmt a] -- ^ A name, list of ('Type', 'Id') parameters and statements. The return type is treated as a parameter with id "@".-    deriving (Eq, Show) -instance Annotated Decl where-    ann (FunctionDecl a _ _ _) = a+-- | A program is a module identifier (list of 'Id''s) and a list of declarations.+data Program a = Program a [Id a] [Decl a]+    deriving (Eq, Functor, Show) -name :: Decl a -> Id a-name (FunctionDecl _ n _ _) = n+instance Annotated Program where+    ann (Program a _ _) = a -types :: Decl a -> [Type a]-types (FunctionDecl _ _ ps _) = map fst ps+instance Simplifiable (Program a) S.Program where+    simp (Program _ module_ decls) = S.Program (map simp module_) (map simp decls) -parameters :: Decl a -> [(Type a, Id a)]-parameters (FunctionDecl _ _ ps _) = init ps+instance Pretty (Program a) where+    pPrint = pPrint . simp -parameterNames :: Decl a -> [Id a]-parameterNames = (map snd) . parameters -parameterTypes :: Decl a -> [Type a]-parameterTypes = (map fst) . parameters+-- | A declaration.+data Decl a = FunctionDecl a (Id a) [(Type a, Id a)] [Stmt a]   -- ^ A name, list of ('Type', 'Id') parameters and statements.+                                                                --   The return type is treated as a parameter with id '@'.+    deriving (Eq, Functor, Show) -returnType :: Decl a -> Type a-returnType (FunctionDecl _ _ ps _) = fst $ last ps+instance Annotated Decl where+    ann (FunctionDecl a _ _ _) = a -stmts :: Decl a -> [Stmt a]-stmts (FunctionDecl _ _ _ ss) = ss+instance Simplifiable (Decl a) S.Decl where+    simp (FunctionDecl _ name parameters stmts) = S.FunctionDecl (simp name) (map (tmap simp simp) parameters) (map simp stmts) +instance Pretty (Decl a) where+    pPrint = pPrint . simp++ -- | A statement. data Stmt a = IfStmt a (Expr a) [Stmt a] [Stmt a]   -- ^ A condition, true block and false block of statements.             | ReturnStmt a (Expr a)                 -- ^ An expression.             | WhileStmt a (Expr a) [Stmt a]         -- ^ A condition and block of statements.-    deriving (Eq, Show)+    deriving (Eq, Functor, Show)  instance Annotated Stmt where     ann (IfStmt a _ _ _)    = a     ann (ReturnStmt a _)    = a     ann (WhileStmt a _ _)   = a +instance Simplifiable (Stmt a) S.Stmt where+    simp (IfStmt _ condition trueStmts falseStmts)  = S.IfStmt (simp condition) (map simp trueStmts) (map simp falseStmts)+    simp (ReturnStmt _ expr)                        = S.ReturnStmt (simp expr)+    simp (WhileStmt _ condition stmts)              = S.WhileStmt (simp condition) (map simp stmts)++instance Pretty (Stmt a) where+    pPrint = pPrint . simp++ -- | A complex expression.-data Expr a = ApplicationExpr a (Id a) [Expr a]         -- ^ A function name to call and the arguments to pass.+data Expr a = ApplicationExpr a (Id a) [Expr a]         -- ^ A function name to call and the arguments to pass as parameters.             | BinaryExpr a BinaryOp (Expr a) (Expr a)   -- ^ A binary operation.-            | ListExpr a [Expr a]                       -- ^ A list of expressions.-            | UnaryExpr a UnaryOp (Expr a)              -- ^ A unary oepration.+            | ListExpr a [Expr a]                       -- ^ A list expression.+            | TypedExpr a S.Type (Expr a)               -- ^ A typed expression.+                                                        --   See "Language.Qux.Annotated.TypeResolver".+            | UnaryExpr a UnaryOp (Expr a)              -- ^ A unary operation.             | ValueExpr a Value                         -- ^ A raw value.-    deriving (Eq, Show)+    deriving (Eq, Functor, Show)  instance Annotated Expr where     ann (ApplicationExpr a _ _) = a     ann (BinaryExpr a _ _ _)    = a     ann (ListExpr a _)          = a+    ann (TypedExpr a _ _)       = a     ann (UnaryExpr a _ _)       = a     ann (ValueExpr a _)         = a +instance Simplifiable (Expr a) S.Expr where+    simp (ApplicationExpr _ id arguments)   = S.ApplicationExpr (simp id) (map simp arguments)+    simp (BinaryExpr _ op lhs rhs)          = S.BinaryExpr op (simp lhs) (simp rhs)+    simp (ListExpr _ elements)              = S.ListExpr (map simp elements)+    simp (TypedExpr _ type_ expr)           = S.TypedExpr type_ (simp expr)+    simp (UnaryExpr _ op expr)              = S.UnaryExpr op (simp expr)+    simp (ValueExpr _ value)                = S.ValueExpr value++instance Pretty (Expr a) where+    pPrint = pPrint . simp++ -- | A type. data Type a = BoolType a             | IntType a             | ListType a (Type a) -- ^ A list type with an inner type.             | NilType a-    deriving (Eq, Show)+    deriving (Eq, Functor, Show)  instance Annotated Type where     ann (BoolType a)    = a     ann (IntType a)     = a     ann (ListType a _)  = a     ann (NilType a)     = a++instance Simplifiable (Type a) S.Type where+    simp (BoolType _)       = S.BoolType+    simp (IntType _)        = S.IntType+    simp (ListType _ inner) = S.ListType $ simp inner+    simp (NilType _)        = S.NilType++instance Pretty (Type a) where+    pPrint = pPrint . simp+++-- Helper methods++tmap :: (a -> b) -> (c -> d) -> (a, c) -> (b, d)+tmap f g (a, c) = (f a, g c) 
src/Language/Qux/Annotated/TypeChecker.hs view
@@ -15,171 +15,150 @@  module Language.Qux.Annotated.TypeChecker (     -- * Environment-    Evaluation, Check,--    -- * Contexts-    Context, Locals,-    context,+    Check,+    runCheck, execCheck, -    -- * Type checking+    -- * Global context+    Context(..),+    context, emptyContext, -    -- ** Program checking-    check,+    -- * Local context+    Locals,+    retrieve, -    -- ** Other node checking-    checkProgram, checkDecl, checkStmt, checkExpr, checkValue+    -- * Type checking+    check, checkProgram, checkDecl, checkStmt, checkExpr ) where -import Control.Applicative-import Control.Monad.Except import Control.Monad.Reader import Control.Monad.State--import Data.Function (on)-import Data.List ((\\), nubBy)-import Data.Map (Map, (!))-import qualified Data.Map as Map-import Data.Maybe (fromJust, isNothing)--import Language.Qux.Annotated.Exception-import Language.Qux.Annotated.Parser (SourcePos)-import Language.Qux.Annotated.Simplify-import qualified Language.Qux.Annotated.Syntax as Ann-import Language.Qux.Syntax----- |    An environment that holds the global types (@Reader Context@) and the local types---      (@Locals@).-type Evaluation = StateT Locals (Reader Context)---- |    Either a 'TypeException' or an @a@.---      Contains an underlying 'Evaluation' in the monad transformer.-type Check = ExceptT TypeException Evaluation+import Control.Monad.Writer +import              Data.Function   (on)+import              Data.List       ((\\), nubBy)+import              Data.Map        ((!))+import qualified    Data.Map        as Map --- |    Global context that holds function definition types.---      The function name and parameter types are held.-data Context = Context {-    functions :: Map Id [Type]-    }+import              Language.Qux.Annotated.Exception+import              Language.Qux.Annotated.Parser       (SourcePos)+import              Language.Qux.Annotated.Syntax       (simp)+import qualified    Language.Qux.Annotated.Syntax       as Ann+import              Language.Qux.Annotated.TypeResolver+import              Language.Qux.Syntax --- | Local context.-type Locals = Map Id Type+import Text.PrettyPrint+import Text.PrettyPrint.HughesPJClass  --- | Returns a context for the given program.-context :: Program -> Context-context (Program decls) = Context { functions = Map.fromList $ map (\d -> (name d, types d)) decls }--retrieve :: Id -> Evaluation (Maybe [Type])-retrieve name = do-    maybeLocal  <- gets $ (fmap (:[])) . (Map.lookup name)-    maybeDef    <- asks $ (Map.lookup name) . functions+-- | A type that allows collecting errors while type checking a program.+--   Requires a 'Context' for evaluation.+type Check = ReaderT Context (Writer [TypeException]) -    return $ maybeLocal <|> maybeDef+-- | Runs the given check with the context.+runCheck :: Check a -> Context -> (a, [TypeException])+runCheck check context = runWriter $ runReaderT check context -once :: Monad m => MonadState s m => (s -> s) -> m a -> m a-once f m = get >>= \save -> modify f >> m <* put save+-- | Runs the given check with the context and extracts the exceptions.+execCheck :: Check a -> Context -> [TypeException]+execCheck check context = execWriter $ runReaderT check context  --- |    Type checks the program.---      If an exception occurs then the result will be a 'TypeException', otherwise 'Nothing'.---      This function wraps 'checkProgram' by building and evaluating the environment under---      the hood.-check :: Ann.Program SourcePos -> Except TypeException ()-check program = mapExceptT-    (return-        . flip runReader (context $ sProgram program)-        . flip evalStateT Map.empty)-    (checkProgram program)+-- | Type checks the program, returning any errors that are found.+--   A result of @[]@ indicates the program is well-typed.+check :: Ann.Program SourcePos -> [TypeException]+check program = execCheck (checkProgram program) (context $ simp program)  -- | Type checks a program. checkProgram :: Ann.Program SourcePos -> Check ()-checkProgram (Ann.Program _ decls) = do-    when (not $ null duplicates) (throwError $ duplicateFunctionName (head duplicates))--    mapM_ checkDecl decls+checkProgram (Ann.Program _ _ decls)+    | null duplicates   = mapM_ checkDecl decls+    | otherwise         = tell $ [DuplicateFunctionName pos name | (Ann.FunctionDecl _ (Ann.Id pos name) _ _) <- duplicates]     where-        duplicates = decls \\ nubBy ((==) `on` sId . Ann.name) decls+        duplicates                      = decls \\ nubBy ((==) `on` simp . name) decls+        name (Ann.FunctionDecl _ n _ _) = n  -- | Type checks a declaration. checkDecl :: Ann.Decl SourcePos -> Check ()-checkDecl (Ann.FunctionDecl pos name parameters stmts) = do-    when (not $ null duplicates) (throwError $ duplicateParameterName (head $ map snd duplicates))--    once (Map.union $ Map.fromList (map (\(t, p) -> (sId p, sType t)) parameters)) (checkBlock stmts)+checkDecl (Ann.FunctionDecl _ _ parameters stmts)+    | null duplicates   = evalStateT (checkBlock stmts) (Map.fromList [(simp p, simp t) | (t, p) <- parameters])+    | otherwise         = tell $ [DuplicateParameterName pos name | (_, Ann.Id pos name) <- duplicates]     where-        duplicates = parameters \\ nubBy ((==) `on` sId . snd) parameters+        duplicates = parameters \\ nubBy ((==) `on` simp . snd) parameters -checkBlock :: [Ann.Stmt SourcePos] -> Check ()+checkBlock :: [Ann.Stmt SourcePos] -> StateT Locals Check () checkBlock = mapM_ checkStmt --- -- | Type checks a statement.-checkStmt :: Ann.Stmt SourcePos -> Check ()+-- | Type checks a statement.+checkStmt :: Ann.Stmt SourcePos -> StateT Locals Check () checkStmt (Ann.IfStmt _ condition trueStmts falseStmts)   = do-    expectExpr condition [BoolType]+    expectExpr_ condition [BoolType]      checkBlock trueStmts     checkBlock falseStmts checkStmt (Ann.ReturnStmt _ expr)                         = do     expected <- gets (! "@") -    void $ expectExpr expr [expected]+    expectExpr_ expr [expected] checkStmt (Ann.WhileStmt _ condition stmts)               = do-    expectExpr condition [BoolType]+    expectExpr_ condition [BoolType]      checkBlock stmts  -- | Type checks an expression.-checkExpr :: Ann.Expr SourcePos -> Check Type-checkExpr e@(Ann.ApplicationExpr pos name arguments)    = do-    maybeTypes <- lift $ retrieve (sId name)-    when (isNothing maybeTypes) (throwError $ undefinedFunctionCall e)+checkExpr :: Ann.Expr SourcePos -> StateT Locals Check Type+checkExpr (Ann.TypedExpr _ type_ (Ann.ApplicationExpr pos name arguments))  = retrieve (simp name) >>= maybe+    (error "internal error: undefined function call has no type (try applying name resolution)")+    (\types -> do+        let expected = init types -    let expected = init $ fromJust maybeTypes+        zipWithM_ expectExpr arguments $ map (:[]) expected -    case length expected == length arguments of-        True    -> zipWithM expectExpr arguments $ map (:[]) expected-        False   -> throwError $ invalidArgumentsCount e (length expected)+        when (length expected /= length arguments) $ tell [InvalidFunctionCall pos (length arguments) (length expected)] -    return $ last (fromJust maybeTypes)-checkExpr (Ann.BinaryExpr _ op lhs rhs)-    | op `elem` [Acc]               = do-    list <- expectExpr lhs [ListType undefined]-    let (ListType inner) = list in-        expectExpr rhs [IntType] >> return inner-    | op `elem` [Mul, Div, Mod]     = expectExpr lhs [IntType] >> expectExpr rhs [IntType]-    | op `elem` [Add, Sub]          = expectExpr lhs [IntType, ListType undefined] >>= (expectExpr rhs) . (:[])-    | op `elem` [Lt, Lte, Gt, Gte]  = expectExpr lhs [IntType] >> expectExpr rhs [IntType] >> return BoolType-    | op `elem` [Eq, Neq]           = ((:[]) <$> checkExpr lhs >>= expectExpr rhs) >> return BoolType-checkExpr (Ann.ListExpr _ [])                           = return $ ListType undefined-checkExpr (Ann.ListExpr _ elements)                     = do-    expected <- checkExpr $ head elements+        return type_)+checkExpr (Ann.TypedExpr _ type_ (Ann.BinaryExpr _ op lhs rhs))+    | op `elem` [Acc]                       = expectExpr_ lhs [ListType type_] >> expectExpr_ rhs [IntType] >> return type_+    | op `elem` [Mul, Div, Mod, Add, Sub]   = expectExpr_ lhs [type_] >> expectExpr rhs [type_]+    | op `elem` [Lt, Lte, Gt, Gte]          = expectExpr_ lhs [IntType] >> expectExpr_ rhs [IntType] >> return type_+    | op `elem` [Eq, Neq]                   = checkExpr lhs >>= expectExpr rhs . (:[]) >> return type_+    | otherwise                             = error $ "internal error: type checking for \"" ++ show op ++ "\" not implemented"+checkExpr (Ann.TypedExpr _ type_ (Ann.ListExpr _ elements))                 = do+    let (ListType inner) = type_ -    mapM_ (flip expectExpr [expected]) (tail elements) >> return expected-checkExpr (Ann.UnaryExpr _ op expr)-    | op `elem` [Len]               = expectExpr expr [ListType undefined] >> return IntType-    | op `elem` [Neg]               = expectExpr expr [IntType]-checkExpr (Ann.ValueExpr _ value)                       = checkValue value+    mapM_ (flip expectExpr [inner]) elements --- -- | Type checks a value.-checkValue :: Value -> Check Type-checkValue (BoolValue _)        = return BoolType-checkValue (IntValue _)         = return IntType-checkValue NilValue             = return NilType+    return type_+checkExpr (Ann.TypedExpr _ type_ (Ann.UnaryExpr _ op expr))+    | op `elem` [Len]               = expectExpr_ expr [ListType $ error "internal error: top type not implemented"] >> return type_+    | op `elem` [Neg]               = expectExpr expr [type_]+    | otherwise                     = error $ "internal error: " ++ show op ++ " not implemented"+checkExpr (Ann.TypedExpr _ type_ (Ann.ValueExpr _ _))                       = return type_+checkExpr _                                                                 = error "internal error: cannot check the type of a non-typed expression (try applying type resolution)"  -expectExpr :: Ann.Expr SourcePos -> [Type] -> Check Type-expectExpr expr expects = (attach (Ann.ann expr) <$> checkExpr expr) >>= flip expectType expects+expectExpr :: Ann.Expr SourcePos -> [Type] -> StateT Locals Check Type+expectExpr expr expects = do+    type_ <- (attach (Ann.ann expr) <$> checkExpr expr) +    lift $ expectType type_ expects++expectExpr_ :: Ann.Expr SourcePos -> [Type] -> StateT Locals Check ()+expectExpr_ = fmap void . expectExpr+ expectType :: Ann.Type SourcePos -> [Type] -> Check Type expectType received expects-    | sType received `elem` expects = return $ sType received-    | otherwise                     = throwError $ mismatchedType received expects+    | simp received `elem` expects  = return $ simp received+    | otherwise                     = do+        tell [MismatchedType (Ann.ann received) (renderOneLine $ pPrint received) (map (renderOneLine . pPrint) expects)] +        return $ simp received+ attach :: SourcePos -> Type -> Ann.Type SourcePos attach pos BoolType         = Ann.BoolType pos-attach pos IntType          = Ann.IntType pos+attach pos IntType          = Ann.IntType  pos attach pos (ListType inner) = Ann.ListType pos (attach undefined inner)-attach pos NilType          = Ann.NilType pos+attach pos NilType          = Ann.NilType  pos++renderOneLine :: Doc -> String+renderOneLine = renderStyle (style { mode = OneLineMode }) 
+ src/Language/Qux/Annotated/TypeResolver.hs view
@@ -0,0 +1,187 @@++{-|+Module      : Language.Qux.Annotated.TypeResolver+Description : Type resolving functions that transform the abstract syntax tree to a typed one.++Copyright   : (c) Henry J. Wylde, 2015+License     : BSD3+Maintainer  : public@hjwylde.com++Type resolving functions that transform the abstract syntax tree to a typed one.++These functions will transform every 'Ann.Expr' into an 'Ann.TypedExpr' and return the transformed+    tree.+The "Language.Qux.Annotated.TypeChecker" and "Language.Qux.Llvm.Compiler" modules require the tree+    to be typed.+-}++{-# LANGUAGE FlexibleContexts #-}++module Language.Qux.Annotated.TypeResolver (+    -- * Environment+    Resolve,+    runResolve,++    -- * Global context+    Context(..),+    context, emptyContext,++    -- * Local context+    Locals,+    retrieve,++    -- * Type resolving+    resolve, resolveProgram, resolveDecl, resolveStmt, resolveExpr, resolveValue,+    extractType+) where++import Control.Applicative+import Control.Monad.Reader+import Control.Monad.State++import              Data.List   (nub)+import              Data.Map    (Map)+import qualified    Data.Map    as Map++import              Language.Qux.Annotated.Parser (SourcePos)+import              Language.Qux.Annotated.Syntax (simp)+import qualified    Language.Qux.Annotated.Syntax as Ann+import              Language.Qux.Syntax+++-- | A type that allows resolving types.+--   Requires a 'Context' for evaluation.+type Resolve = Reader Context++-- | Runs the given resolve with the context.+runResolve :: Resolve a -> Context -> a+runResolve = runReader+++-- | Global context that holds function definition types.+data Context = Context {+    functions :: Map Id [Type] -- ^ A map of function names to parameter types.+    }++-- | Returns a context for the given program.+context :: Program -> Context+context (Program _ decls) = Context {+    functions = Map.fromList $ [(name, map fst parameters) | (FunctionDecl name parameters _) <- decls]+    }++-- | An empty context.+emptyContext :: Context+emptyContext = Context { functions = Map.empty }+++-- | Local context.+--   This is a map of variable names to types (e.g., parameters).+type Locals = Map Id Type++-- | Retrieves the type of the given identifier.+--   Preference is placed on local variables.+--   A local variable type is a singleton list,+--   while a function type is it's parameter types and return type.+retrieve :: MonadReader Context m => Id -> StateT Locals m (Maybe [Type])+retrieve name = do+    maybeLocal  <- gets $ (fmap (:[])) . (Map.lookup name)+    maybeDef    <- asks $ (Map.lookup name) . functions++    return $ maybeLocal <|> maybeDef+++-- | Resolves the types of the program, returning the modified syntax tree.+resolve :: Ann.Program SourcePos -> Ann.Program SourcePos+resolve program = runResolve (resolveProgram program) (context $ simp program)++-- | Resolves the types of a program.+resolveProgram :: Ann.Program SourcePos -> Resolve (Ann.Program SourcePos)+resolveProgram (Ann.Program pos module_ decls) = mapM resolveDecl decls >>= \decls' -> return $ Ann.Program pos module_ decls'++-- | Resolves the types of a declaration.+resolveDecl :: Ann.Decl SourcePos -> Resolve (Ann.Decl SourcePos)+resolveDecl (Ann.FunctionDecl pos name parameters stmts) = do+    stmts' <- evalStateT (resolveBlock stmts) (Map.fromList [(simp p, simp t) | (t, p) <- parameters])++    return $ Ann.FunctionDecl pos name parameters stmts'++resolveBlock :: [Ann.Stmt SourcePos] -> StateT Locals Resolve [Ann.Stmt SourcePos]+resolveBlock = mapM resolveStmt++-- | Resolves the types of a statement.+resolveStmt :: Ann.Stmt SourcePos -> StateT Locals Resolve (Ann.Stmt SourcePos)+resolveStmt (Ann.IfStmt pos condition trueStmts falseStmts) = do+    condition'  <- resolveExpr condition+    trueStmts'  <- resolveBlock trueStmts+    falseStmts' <- resolveBlock falseStmts++    return $ Ann.IfStmt pos condition' trueStmts' falseStmts'+resolveStmt (Ann.ReturnStmt pos expr)                       = do+    expr' <- resolveExpr expr++    return $ Ann.ReturnStmt pos expr'+resolveStmt (Ann.WhileStmt pos condition stmts)             = do+    condition'  <- resolveExpr condition+    stmts'      <- resolveBlock stmts++    return $ Ann.WhileStmt pos condition' stmts'++-- | Resolves the types of an expression.+resolveExpr :: Ann.Expr SourcePos -> StateT Locals Resolve (Ann.Expr SourcePos)+resolveExpr (Ann.ApplicationExpr pos name arguments)    = retrieve (simp name) >>= maybe+    (error "internal error: undefined function call has no type (try applying name resolution)")+    (\types -> do+        arguments_ <- mapM resolveExpr arguments++        return $ Ann.TypedExpr pos (last types) (Ann.ApplicationExpr pos name arguments_))+resolveExpr (Ann.BinaryExpr pos op lhs rhs)             = do+    lhs' <- resolveExpr lhs+    rhs' <- resolveExpr rhs++    let type_ = case op of+            Acc -> let (ListType inner) = extractType lhs' in inner+            Mul -> IntType+            Div -> IntType+            Mod -> IntType+            Add -> extractType lhs'+            Sub -> extractType lhs'+            Lt  -> BoolType+            Lte -> BoolType+            Gt  -> BoolType+            Gte -> BoolType+            Eq  -> BoolType+            Neq -> BoolType++    return $ Ann.TypedExpr pos type_ (Ann.BinaryExpr pos op lhs' rhs')+resolveExpr (Ann.ListExpr pos elements)                 = do+    elements' <- mapM resolveExpr elements++    let types = map extractType elements'++    case length (nub types) == 1 of+        True    -> return $ Ann.TypedExpr pos (ListType $ head types) (Ann.ListExpr pos elements')+        False   -> error "internal error: top type not implemented"+resolveExpr e@(Ann.TypedExpr _ _ _)                     = return e+resolveExpr (Ann.UnaryExpr pos op expr)                 = do+    expr' <- resolveExpr expr++    return $ Ann.TypedExpr pos IntType (Ann.UnaryExpr pos op expr')+resolveExpr e@(Ann.ValueExpr pos value)                 = return $ Ann.TypedExpr pos (resolveValue value) e++-- | Resolves the type of a value.+resolveValue :: Value -> Type+resolveValue (BoolValue _)          = BoolType+resolveValue (IntValue _)           = IntType+resolveValue (ListValue elements)   = case length (nub types) == 1 of+    True    -> ListType $ head types+    False   -> error "internal error: top type not implemented"+    where+        types = map resolveValue elements+resolveValue NilValue               = NilType++-- | Extracts the type from a 'Ann.TypedExpr'.+--   If the expression isn't an 'Ann.TypedExpr', an error is raised.+extractType :: Ann.Expr a -> Type+extractType (Ann.TypedExpr _ type_ _)  = type_+extractType _                          = error "internal error: type resolution not complete"+
− src/Language/Qux/Interpreter.hs
@@ -1,154 +0,0 @@--{-|-Module      : Language.Qux.Interpreter-Description : Functions for executing a program and retrieving the return result.--Copyright   : (c) Henry J. Wylde, 2015-License     : BSD3-Maintainer  : public@hjwylde.com--Functions for executing a program and retrieving the return result.--This module assumes the program is well-formed.-That is, it must be well-typed (see "Language.Qux.TypeChecker").--}--module Language.Qux.Interpreter (-    -- * Environment-    Execution, Evaluation,-    runExecution,--    -- * Contexts-    Context, Locals,-    context,--    -- * Interpreter--    -- ** Program  execution-    exec, execStmt,--    -- ** Expression evaluation-    evalExpr-) where--import Control.Monad.Reader-import Control.Monad.State-import Control.Monad.Trans.Either--import Data.List ((\\))-import Data.Map (Map, (!))-import qualified Data.Map as Map-import Data.Maybe (fromJust, isJust)--import Language.Qux.Syntax----- |    An environment that holds the global state (@Reader Context@) and the local state---      (@Locals@).---      It supports breaking out of execution (via 'EitherT Value').-type Execution = EitherT Value Evaluation---- |    An environment that holds the global state (@Reader Context@) and the local state---      (@Locals@).---      Purely for evaluation of expressions---this environment does not support breaking out of---      execution.-type Evaluation = StateT Locals (Reader Context)---runExecution :: (a -> Value) -> Execution a -> Evaluation Value-runExecution f exec = either id f <$> runEitherT exec----- |    Global context that holds function definitions.---      The function name, parameter names and statements are held.-data Context = Context {-    functions :: Map Id ([Id], [Stmt])-    }---- | Local context.-type Locals = Map Id Value----- | Returns a context for the given program.-context :: Program -> Context-context (Program decls) = Context { functions = Map.fromList $ map (\d -> (name d, (parameterNames d, stmts d))) decls }--once :: Monad m => MonadState s m => (s -> s) -> m a -> m a-once f m = get >>= \save -> modify f >> m <* put save----- |    @exec program entry arguments@ executes @entry@ (passing it @arguments@) in the context---      of @program@.---      This function wraps 'execFunction' by building and evaluating the environment under---      the hood.-exec :: Program -> Id -> [Value] -> Value-exec program entry arguments = runReader (evalStateT (evalApplicationExpr entry arguments) Map.empty) (context program)--execBlock :: [Stmt] -> Execution ()-execBlock = mapM_ execStmt---- | Executes the statement in a breaking environment.-execStmt :: Stmt -> Execution ()-execStmt (IfStmt condition trueStmts falseStmts) = do-    result <- lift $ evalExpr condition--    execBlock $ case runBoolValue result of-        True    -> trueStmts-        False   -> falseStmts-execStmt (ReturnStmt expr)                       = lift (evalExpr expr) >>= left-execStmt s@(WhileStmt condition stmts)           = do-    result <- lift $ evalExpr condition--    when (runBoolValue result) $ execBlock stmts >> execStmt s---- | Reduces the expression to a value (normal form).-evalExpr :: Expr -> Evaluation Value-evalExpr (ApplicationExpr name arguments) = mapM evalExpr arguments >>= evalApplicationExpr name-evalExpr (BinaryExpr op lhs rhs)          = do-    lhs' <- evalExpr lhs-    rhs' <- evalExpr rhs--    evalBinaryExpr op lhs' rhs'-evalExpr (ListExpr exprs)                 = ListValue <$> mapM evalExpr exprs-evalExpr (UnaryExpr op expr)              = evalExpr expr >>= evalUnaryExpr op-evalExpr (ValueExpr value)                = return value--evalApplicationExpr :: Id -> [Value] -> Evaluation Value-evalApplicationExpr name arguments = do-    maybeValue <- gets $ Map.lookup name--    if isJust maybeValue then-        return $ fromJust maybeValue-    else do-        (parameters, stmts) <- asks $ (! name) . functions--        once (Map.union $ Map.fromList (zip parameters arguments)) (runExecution undefined (execBlock stmts))--evalBinaryExpr :: BinaryOp -> Value -> Value -> Evaluation Value-evalBinaryExpr Acc (ListValue elements) (IntValue rhs)    = return $ elements !! (fromInteger rhs)-evalBinaryExpr Mul (IntValue lhs)  (IntValue rhs)         = return $ IntValue   (lhs * rhs)-evalBinaryExpr Div (IntValue lhs)  (IntValue rhs)         = return $ IntValue   (lhs `div` rhs)-evalBinaryExpr Mod (IntValue lhs)  (IntValue rhs)         = return $ IntValue   (lhs `mod` rhs)-evalBinaryExpr Add (IntValue lhs)  (IntValue rhs)         = return $ IntValue   (lhs + rhs)-evalBinaryExpr Add (ListValue lhs) (ListValue rhs)        = return $ ListValue  (lhs ++ rhs)-evalBinaryExpr Sub (IntValue lhs)  (IntValue rhs)         = return $ IntValue   (lhs - rhs)-evalBinaryExpr Sub (ListValue lhs) (ListValue rhs)        = return $ ListValue  (lhs \\ rhs)-evalBinaryExpr Lt  (IntValue lhs)  (IntValue rhs)         = return $ BoolValue  (lhs < rhs)-evalBinaryExpr Lte (IntValue lhs)  (IntValue rhs)         = return $ BoolValue  (lhs <= rhs)-evalBinaryExpr Gt  (IntValue lhs)  (IntValue rhs)         = return $ BoolValue  (lhs > rhs)-evalBinaryExpr Gte (IntValue lhs)  (IntValue rhs)         = return $ BoolValue  (lhs >= rhs)-evalBinaryExpr Eq  (BoolValue lhs) (BoolValue rhs)        = return $ BoolValue  (lhs == rhs)-evalBinaryExpr Eq  (IntValue lhs)  (IntValue rhs)         = return $ BoolValue  (lhs == rhs)-evalBinaryExpr Eq  (ListValue lhs) (ListValue rhs)        = return $ BoolValue  (lhs == rhs)-evalBinaryExpr Eq  NilValue        NilValue               = return $ BoolValue  True-evalBinaryExpr Eq  _               _                      = return $ BoolValue  False-evalBinaryExpr Neq lhs             rhs                    = evalBinaryExpr Eq lhs rhs >>= return . BoolValue . not . runBoolValue--evalUnaryExpr :: UnaryOp -> Value -> Evaluation Value-evalUnaryExpr Len (ListValue elements)  = return $ IntValue (toInteger $ length elements)-evalUnaryExpr Neg (IntValue value)      = return $ IntValue (-value)---runBoolValue :: Value -> Bool-runBoolValue (BoolValue value) = value-
src/Language/Qux/Lexer.hs view
@@ -10,85 +10,73 @@ A "Text.Parsec" lexer for the Qux language. -} -module Language.Qux.Lexer (-    -- * Lexer-    lexer,--    -- ** Language elements-    identifier, natural, operator, reserved, symbol, whiteSpace,+{-# OPTIONS_HADDOCK hide, prune #-} -    -- ** Symbols-    brackets, colon, comma, parens, pipes, rightArrow-) where+module Language.Qux.Lexer where  import Control.Monad.State -import Text.Parsec hiding (State)-import qualified Text.Parsec.Token as Token+import              Text.Parsec         hiding (State)+import qualified    Text.Parsec.Token   as Token  --- | Lexer for the Qux language definition.+lexer :: Token.GenTokenParser String u (State SourcePos) lexer = Token.makeTokenParser quxDef  --- | Lexemes an identifier matching @[a-zA-Z_][a-zA-Z_']*@.+identifier :: ParsecT String u (State SourcePos) String identifier = Token.identifier lexer --- | Lexemes a natural number (decimal, octal or hex).+natural :: ParsecT String u (State SourcePos) Integer natural = Token.natural lexer --- | Lexemes a reserved operator from 'operators'.+operator :: String -> ParsecT String u (State SourcePos) () operator = Token.reservedOp lexer --- | Lexemes a reserved keyword from 'keywords'.+reserved :: String -> ParsecT String u (State SourcePos) () reserved = Token.reserved lexer --- | Lexemes a symbol.+symbol :: String -> ParsecT String u (State SourcePos) String symbol = Token.symbol lexer --- |    Lexemes white space.---      White space includes comments.+symbol_ :: String -> ParsecT String u (State SourcePos) ()+symbol_ = void . symbol++whiteSpace :: ParsecT String u (State SourcePos) () whiteSpace = Token.whiteSpace lexer  --- | @brackets p@ lexemes @p@ surrounded by @[..]@.+brackets :: ParsecT String u (State SourcePos) a -> ParsecT String u (State SourcePos) a brackets = Token.brackets lexer --- | Lexemes a colon, @:@.-colon = Token.colon lexer+colon :: ParsecT String u (State SourcePos) ()+colon = symbol_ ":" --- | Lexemes a comma, @,@.-comma = Token.comma lexer+comma :: ParsecT String u (State SourcePos) ()+comma = symbol_ "," --- | @parens p@ lexemes @p@ surrounded by @(..)@.+dot :: ParsecT String u (State SourcePos) ()+dot = symbol_ "."++parens :: ParsecT String u (State SourcePos) a -> ParsecT String u (State SourcePos) a parens = Token.parens lexer --- | @pipes p@ lexemes @p@ surrounded by @|..|@.+pipes :: ParsecT String u (State SourcePos) a -> ParsecT String u (State SourcePos) a pipes p = Token.lexeme lexer $ between (symbol "|") (symbol "|") p --- | Lexemes a right arrow, @->@.-rightArrow = symbol "->"+rightArrow :: ParsecT String u (State SourcePos) ()+rightArrow = symbol_ "->"   quxDef :: Token.GenLanguageDef String u (State SourcePos)-quxDef = Token.LanguageDef-    commentStart-    commentEnd-    commentLine-    nestedComments-    identStart-    identLetter-    opStart-    opLetter-    reservedNames-    reservedOpNames-    caseSensitive+quxDef = Token.LanguageDef commentStart commentEnd commentLine nestedComments identStart identLetter+    opStart opLetter reservedNames reservedOpNames caseSensitive         where             commentStart    = "/*"             commentEnd      = "*/"             commentLine     = "#"             nestedComments  = False-            identStart      = letter <|> char '_'+            identStart      = lower <|> char '_'             identLetter     = alphaNum <|> oneOf ['_', '\'']             opStart         = oneOf []             opLetter        = oneOf []@@ -96,13 +84,15 @@             reservedOpNames = operators             caseSensitive   = True +keywords :: [String] keywords = [     "_",-    "else", "if", "return", "while",+    "else", "if", "module", "return", "while",     "false", "nil", "true",     "Bool", "Int", "Nil"     ] +operators :: [String] operators = [     "!!", "|",     "*", "/", "%",
+ src/Language/Qux/Llvm/Builder.hs view
@@ -0,0 +1,80 @@++{-|+Module      : Language.Qux.Llvm.Builder+Description : Build utilities for the LLVM compiler.++Copyright   : (c) Henry J. Wylde, 2015+License     : BSD3+Maintainer  : public@hjwylde.com++Build utilities for the LLVM compiler, see "Compiler".+-}++{-# OPTIONS_HADDOCK hide, prune #-}+{-# LANGUAGE FlexibleContexts #-}++module Language.Qux.Llvm.Builder where++import Control.Monad.State++import              Data.Map (Map)+import qualified    Data.Map as Map++import LLVM.General.AST+++data Builder = Builder {+    currentBlock    :: Name,+    blocks          :: Map Name BlockBuilder,+    counter         :: Word+    }++initialBuilder :: Builder+initialBuilder = Builder {+    currentBlock    = Name ".0",+    blocks          = Map.singleton (Name ".0") defaultBlockBuilder { name = Name ".0" },+    counter         = 1+    }++data BlockBuilder = BlockBuilder {+    name :: Name,+    stack :: [Named Instruction],+    term :: Maybe (Named Terminator)+    }++defaultBlockBuilder :: BlockBuilder+defaultBlockBuilder = BlockBuilder {+    name    = error "no block name set",+    stack   = [],+    term    = Nothing+    }++getBlock :: Monad m => MonadState Builder m => m Name+getBlock = gets currentBlock++setBlock :: Monad m => MonadState Builder m => Name -> m ()+setBlock name = modify $ \s -> s { currentBlock = name }++addBlock :: Monad m => MonadState Builder m => Name -> m ()+addBlock name' = modify $ \s -> s { blocks = Map.insert name' defaultBlockBuilder { name = name' } (blocks s) }++modifyBlock :: Monad m => MonadState Builder m => (BlockBuilder -> BlockBuilder) -> m ()+modifyBlock f = do+    c <- current+    modify $ \s -> s { blocks = Map.insert (name c) (f c) (blocks s) }++current :: Monad m => MonadState Builder m => m BlockBuilder+current = getBlock >>= \name -> gets (flip (Map.!) name . blocks)++append :: Monad m => MonadState Builder m => Named Instruction -> m ()+append instr = modifyBlock $ \b -> b { stack = stack b ++ [instr] }++terminate :: Monad m => MonadState Builder m => Named Terminator -> m ()+terminate term = modifyBlock $ \b -> b { term = Just term }++freeName :: Monad m => MonadState Builder m => m String+freeName = (("." ++) . show) <$> freeUnName++freeUnName :: Monad m => MonadState Builder m => m Word+freeUnName = gets counter <* modify (\s -> s { counter = counter s + 1 })+
+ src/Language/Qux/Llvm/Compiler.hs view
@@ -0,0 +1,221 @@++{-|+Module      : Language.Qux.Llvm.Compiler+Description : Compiles a Qux program into LLVM IR.++Copyright   : (c) Henry J. Wylde, 2015+License     : BSD3+Maintainer  : public@hjwylde.com++A compiler that takes a 'Program' and outputs a LLVM 'Module'.+-}++module Language.Qux.Llvm.Compiler (+    -- * Compilation+    compile+) where++import Control.Monad.Reader+import Control.Monad.State++import              Data.List   (intercalate)+import              Data.Map    (Map)+import qualified    Data.Map    as Map+import              Data.Maybe+import              Data.Tuple  (swap)++import Language.Qux.Llvm.Builder    as B+import Language.Qux.Syntax          as Qux++import LLVM.General.AST                     as Llvm+import LLVM.General.AST.CallingConvention+import LLVM.General.AST.Constant            hiding (exact, nsw, nuw, operand0, operand1)+import LLVM.General.AST.Global              as G+import LLVM.General.AST.IntegerPredicate+import LLVM.General.AST.Type++import Prelude hiding (EQ)+++data Context = Context {+    functions   :: Map Id [Qux.Type],+    locals      :: Map Id Qux.Type+    } deriving Show++context :: Program -> Context+context (Program _ decls) = Context {+    functions   = Map.fromList [(name, map fst parameters) | (FunctionDecl name parameters _) <- decls],+    locals      = Map.empty+    }+++-- | Compiles the program into a LLVM 'Module'.+--   Generally speaking, compilation is done using the defaults.+--   Any exceptions to this will be clearly noted.+compile :: Program -> Module+compile program = runReader (compileProgram program) (context program)++compileProgram :: Program -> Reader Context Module+compileProgram (Program module_ decls) = do+    definitions <- mapM compileDecl decls++    return $ defaultModule {+        moduleName = intercalate "." module_,+        moduleDefinitions = definitions+        }++compileDecl :: Decl -> Reader Context Definition+compileDecl (FunctionDecl name' parameters stmts) = local (\r -> r { locals = Map.fromList $ map swap (init parameters) }) $ do+    blockBuilder <- execStateT (mapM_ compileStmt stmts) initialBuilder++    return $ GlobalDefinition functionDefaults {+        G.name          = Name name',+        G.returnType    = compileType $ fst (last parameters),+        G.parameters    = ([Parameter (compileType t) (Name p) [] | (t, p) <- init parameters], False),+        basicBlocks     = map (\b -> BasicBlock (B.name b) (stack b) (fromJust $ term b)) (Map.elems $ blocks blockBuilder)+        }++compileStmt :: Stmt -> StateT Builder (Reader Context) ()+compileStmt (IfStmt condition trueStmts falseStmts) = do+    operand <- compileExpr condition++    thenLabel <- Name <$> freeName+    elseLabel <- Name <$> freeName+    exitLabel <- Name <$> freeName++    terminate $ Do Llvm.CondBr { condition = operand, trueDest = thenLabel, falseDest = elseLabel, metadata' = [] }++    addBlock thenLabel >> setBlock thenLabel+    mapM_ compileStmt trueStmts++    c <- current+    when (isNothing $ term c) $ terminate (Do Llvm.Br { dest = exitLabel, metadata' = [] })++    addBlock elseLabel >> setBlock elseLabel+    mapM_ compileStmt falseStmts++    c <- current+    when (isNothing $ term c) $ terminate (Do Llvm.Br { dest = exitLabel, metadata' = [] })++    addBlock exitLabel >> setBlock exitLabel+    terminate $ Do Llvm.Unreachable { metadata' = [] }+compileStmt (ReturnStmt expr)                       = do+    operand <- compileExpr expr++    terminate $ Do Ret { returnOperand = Just operand, metadata' = [] }+compileStmt (WhileStmt condition stmts)             = do+    whileLabel  <- Name <$> freeName+    loopLabel   <- Name <$> freeName+    exitLabel   <- Name <$> freeName++    terminate $ Do Llvm.Br { dest = whileLabel, metadata' = [] }++    addBlock whileLabel >> setBlock whileLabel+    operand <- compileExpr condition+    terminate $ Do Llvm.CondBr { condition = operand, trueDest = loopLabel, falseDest = exitLabel, metadata' = [] }++    addBlock loopLabel >> setBlock loopLabel+    mapM_ compileStmt stmts++    c <- current+    when (isNothing $ term c) $ terminate (Do Llvm.Br { dest = whileLabel, metadata' = [] })++    addBlock exitLabel >> setBlock exitLabel+    terminate $ Do Llvm.Unreachable { metadata' = [] }++compileExpr :: Expr -> StateT Builder (Reader Context) Operand+compileExpr (TypedExpr type_ (ApplicationExpr name' arguments)) = do+    operands <- mapM compileExpr arguments++    n <- freeName++    asks (Map.member name' . locals) >>= \isLocal -> case isLocal of+        True    -> return $ LocalReference (compileType type_) (Name name')+        False   -> do+            append $ Name n := Call {+                isTailCall = False,+                Llvm.callingConvention = C,+                Llvm.returnAttributes = [],+                function = Right $ ConstantOperand $ GlobalReference (compileType type_) (Name name'),+                arguments = [(op, []) | op <- operands],+                Llvm.functionAttributes = [],+                metadata = []+                }++            return $ LocalReference (compileType type_) (Name n)+compileExpr (TypedExpr type_ (BinaryExpr op lhs rhs))           = do+    lhsOperand <- compileExpr lhs+    rhsOperand <- compileExpr rhs++    n <- freeName++    case op of+        Qux.Acc -> error "internal error: compilation for \"!!\" not implemented"+        Qux.Mul -> do+            append $ Name n := Llvm.Mul { nsw = False, nuw = False, operand0 = lhsOperand, operand1 = rhsOperand, metadata = [] }+            return $ LocalReference (compileType type_) (Name n)+        Qux.Div -> do+            append $ Name n := Llvm.SDiv { exact = False, operand0 = lhsOperand, operand1 = rhsOperand, metadata = [] }+            return $ LocalReference (compileType type_) (Name n)+        Qux.Mod -> do+            append $ Name n := Llvm.SRem { operand0 = lhsOperand, operand1 = rhsOperand, metadata = [] }+            return $ LocalReference (compileType type_) (Name n)+        Qux.Add -> do+            append $ Name n := Llvm.Add { nsw = False, nuw = False, operand0 = lhsOperand, operand1 = rhsOperand, metadata = [] }+            return $ LocalReference (compileType type_) (Name n)+        Qux.Sub -> do+            append $ Name n := Llvm.Sub { nsw = False, nuw = False, operand0 = lhsOperand, operand1 = rhsOperand, metadata = [] }+            return $ LocalReference (compileType type_) (Name n)+        Qux.Lt  -> do+            append $ Name n := Llvm.ICmp { Llvm.iPredicate = SLT, operand0 = lhsOperand, operand1 = rhsOperand, metadata = [] }+            return $ LocalReference (compileType type_) (Name n)+        Qux.Lte -> do+            append $ Name n := Llvm.ICmp { Llvm.iPredicate = SLE, operand0 = lhsOperand, operand1 = rhsOperand, metadata = [] }+            return $ LocalReference (compileType type_) (Name n)+        Qux.Gt  -> do+            append $ Name n := Llvm.ICmp { Llvm.iPredicate = SGT, operand0 = lhsOperand, operand1 = rhsOperand, metadata = [] }+            return $ LocalReference (compileType type_) (Name n)+        Qux.Gte -> do+            append $ Name n := Llvm.ICmp { Llvm.iPredicate = SGE, operand0 = lhsOperand, operand1 = rhsOperand, metadata = [] }+            return $ LocalReference (compileType type_) (Name n)+        Qux.Eq  -> do+            append $ Name n := Llvm.ICmp { Llvm.iPredicate = EQ, operand0 = lhsOperand, operand1 = rhsOperand, metadata = [] }+            return $ LocalReference (compileType type_) (Name n)+        Qux.Neq -> do+            append $ Name n := Llvm.ICmp { Llvm.iPredicate = NE, operand0 = lhsOperand, operand1 = rhsOperand, metadata = [] }+            return $ LocalReference (compileType type_) (Name n)+compileExpr (TypedExpr _ (ListExpr _))                          = error "internal error: compilation for lists not implemented"+compileExpr (TypedExpr type_ (UnaryExpr op expr))               = do+    operand <- compileExpr expr++    n <- freeName++    case op of+        Len -> error "internal error: compilation for \"|..|\" not implemented"+        Neg -> append $ Name n := Llvm.Mul {+            nsw = False, nuw = False, metadata = [],+            operand0 = operand, operand1 = (ConstantOperand $ Int { integerBits = 32, integerValue = -1 })+            }++    return $ LocalReference (compileType type_) (Name n)+compileExpr (TypedExpr _ (ValueExpr value))                     = return $ ConstantOperand (compileValue value)+compileExpr _                                                   = error "internal error: cannot compile a non-typed expression (try applying type resolution)"++compileValue :: Value -> Constant+compileValue (BoolValue bool)   = Int {+    integerBits = 1,+    integerValue = toInteger (fromEnum bool)+    }+compileValue (IntValue int)     = Int {+    integerBits = 32,+    integerValue = toInteger int+    }+compileValue (ListValue _)      = error "internal error: compilation for lists not implemented"+compileValue NilValue           = error "internal error: compilation for nil not implemented"++compileType :: Qux.Type -> Llvm.Type+compileType BoolType        = i1+compileType IntType         = i32+compileType (ListType _)    = error "internal error: compilation for list types not implemented"+compileType NilType         = error "internal error: compilation for nil types not implemented"+
− src/Language/Qux/PrettyPrinter.hs
@@ -1,111 +0,0 @@--{-|-Module      : Language.Qux.PrettyPrinter-Description : Pretty instances and rendering functions for Qux language elements.--Copyright   : (c) Henry J. Wylde, 2015-License     : BSD3-Maintainer  : public@hjwylde.com--"Text.PrettyPrint" instances and rendering functions for Qux language elements.--To render a program, call: @render $ pPrint program@--}--module Language.Qux.PrettyPrinter (-    -- * Types-    Pretty(..), Style(..), Mode(..),--    -- * Rendering-    render, renderStyle, renderOneLine-) where--import Data.Char (toLower)--import Language.Qux.Syntax--import Text.PrettyPrint-import Text.PrettyPrint.HughesPJClass----- TODO (hjw): use maybeParens to avoid using so many parenthesis---- | Like 'render', but renders the doc on one line.-renderOneLine :: Doc -> String-renderOneLine = renderStyle (style { mode = OneLineMode })---instance Pretty Doc where-    pPrint = id--instance Pretty Program where-    pPrint (Program decls) = vcat $ map (($+$ emptyLine) . pPrint) decls--instance Pretty Decl where-    pPrint (FunctionDecl name parameters stmts) = vcat [-        text name <+> text "::" <+> parametersDoc <> colon,-        nest 4 (block stmts)-        ]-        where-            parametersDoc = fsep $ punctuate-                (space <> text "->")-                (map (\(t, p) -> pPrint t <+> (if p == "@" then empty else text p)) parameters)--instance Pretty Stmt where-    pPrint (IfStmt condition trueStmts falseStmts)  = vcat [-        text "if" <+> pPrint condition <> colon,-        nest 4 (block trueStmts),-        if null falseStmts then empty else text "else:",-        nest 4 (block falseStmts)-        ]-    pPrint (ReturnStmt expr)                        = text "return" <+> pPrint expr-    pPrint (WhileStmt condition stmts)              = vcat [-        text "while" <+> pPrint condition <> colon,-        nest 4 (block stmts)-        ]--instance Pretty Expr where-    pPrint (ApplicationExpr name arguments) = text name <+> fsep (map pPrint arguments)-    pPrint (BinaryExpr op lhs rhs)          = parens $ fsep [pPrint lhs, pPrint op, pPrint rhs]-    pPrint (ListExpr elements)              = brackets $ fsep (punctuate comma (map pPrint elements))-    pPrint (UnaryExpr Len expr)             = pipes $ pPrint expr-    pPrint (UnaryExpr op expr)              = pPrint op <> pPrint expr-    pPrint (ValueExpr value)                = pPrint value--instance Pretty BinaryOp where-    pPrint Acc = text "!!"-    pPrint Mul = text "*"-    pPrint Div = text "/"-    pPrint Mod = text "%"-    pPrint Add = text "+"-    pPrint Sub = text "-"-    pPrint Lt  = text "<"-    pPrint Lte = text "<="-    pPrint Gt  = text ">"-    pPrint Gte = text ">="-    pPrint Eq  = text "=="-    pPrint Neq = text "!="--instance Pretty UnaryOp where-    pPrint Neg = text "-"--instance Pretty Value where-    pPrint (BoolValue bool)     = text $ map toLower (show bool)-    pPrint (IntValue int)       = text $ show int-    pPrint (ListValue elements) = brackets $ fsep (punctuate comma (map pPrint elements))-    pPrint NilValue             = text "nil"--instance Pretty Type where-    pPrint BoolType         = text "Bool"-    pPrint IntType          = text "Int"-    pPrint (ListType inner) = brackets $ pPrint inner-    pPrint NilType          = text "Nil"---block :: [Stmt] -> Doc-block = vcat . (map pPrint)--emptyLine = text ""--pipes doc = char '|' <> doc <> char '|'-
src/Language/Qux/Syntax.hs view
@@ -8,83 +8,162 @@ Maintainer  : public@hjwylde.com  Abstract syntax tree nodes.++Instances of 'Pretty' are provided for pretty printing. -} -module Language.Qux.Syntax where+module Language.Qux.Syntax (+    -- * Nodes+    Id, Program(..), Decl(..), Stmt(..), Expr(..), BinaryOp(..), UnaryOp(..), Value(..), Type(..)+) where +import Data.Char (toLower) --- | An identifier.+import Text.PrettyPrint+import Text.PrettyPrint.HughesPJClass+++-- | An identifier. Identifiers should match '[a-z_][a-zA-Z0-9_']*'. type Id = String --- * Nodes --- | A program is a list of declarations.-newtype Program = Program [Decl]+-- | A program is a module identifier (list of 'Id''s) and a list of declarations.+data Program = Program [Id] [Decl]     deriving (Eq, Show) +instance Pretty Program where+    pPrint (Program module_ decls) = vcat $ map ($+$ text "") ([+        text "module" <+> hcat (punctuate (char '.') (map text module_))+        ] ++ map pPrint decls)++ -- | A declaration.-data Decl = FunctionDecl Id [(Type, Id)] [Stmt] -- ^ A name, list of ('Type', 'Id') parameters and statements. The return type is treated as a parameter with id "@".+data Decl = FunctionDecl Id [(Type, Id)] [Stmt] -- ^ A name, list of ('Type', 'Id') parameters and statements.+                                                --   The return type is treated as a parameter with id '@'.     deriving (Eq, Show) -name :: Decl -> Id-name (FunctionDecl n _ _) = n+instance Pretty Decl where+    pPrint (FunctionDecl name parameters stmts) = vcat [+        text name <+> text "::" <+> parametersDoc <> colon,+        nest 4 (block stmts)+        ]+        where+            parametersDoc = fsep $ punctuate+                (space <> text "->")+                (map (\(t, p) -> pPrint t <+> (if p == "@" then empty else text p)) parameters) -types :: Decl -> [Type]-types (FunctionDecl _ ps _) = map fst ps -parameters :: Decl -> [(Type, Id)]-parameters (FunctionDecl _ ps _) = init ps--parameterNames :: Decl -> [Id]-parameterNames = (map snd) . parameters--parameterTypes :: Decl -> [Type]-parameterTypes = (map fst) . parameters--returnType :: Decl -> Type-returnType (FunctionDecl _ ps _) = fst $ last ps--stmts :: Decl -> [Stmt]-stmts (FunctionDecl _ _ ss) = ss- -- | A statement. data Stmt   = IfStmt Expr [Stmt] [Stmt] -- ^ A condition, true block and false block of statements.             | ReturnStmt Expr           -- ^ An expression.             | WhileStmt Expr [Stmt]     -- ^ A condition and block of statements.     deriving (Eq, Show) +instance Pretty Stmt where+    pPrint (IfStmt condition trueStmts falseStmts)  = vcat [+        text "if" <+> pPrint condition <> colon,+        nest 4 (block trueStmts),+        if null falseStmts then empty else text "else:",+        nest 4 (block falseStmts)+        ]+    pPrint (ReturnStmt expr)                        = text "return" <+> pPrint expr+    pPrint (WhileStmt condition stmts)              = vcat [+        text "while" <+> pPrint condition <> colon,+        nest 4 (block stmts)+        ]++ -- | A complex expression.-data Expr   = ApplicationExpr Id [Expr]     -- ^ A function name to call and the arguments to pass.+data Expr   = ApplicationExpr Id [Expr]     -- ^ A function name to call and the arguments to pass+                                            --   as parameters.             | BinaryExpr BinaryOp Expr Expr -- ^ A binary operation.-            | ListExpr [Expr]               -- ^ A list of expressions.-            | UnaryExpr UnaryOp Expr        -- ^ A unary oepration.+            | ListExpr [Expr]               -- ^ A list expression.+            | TypedExpr Type Expr           -- ^ A typed expression.+                                            --   See "Language.Qux.Annotated.TypeResolver".+            | UnaryExpr UnaryOp Expr        -- ^ A unary operation.             | ValueExpr Value               -- ^ A raw value.     deriving (Eq, Show) +instance Pretty Expr where+    pPrint (ApplicationExpr name arguments) = text name <+> fsep (map pPrint arguments)+    pPrint (BinaryExpr op lhs rhs)          = parens $ fsep [pPrint lhs, pPrint op, pPrint rhs]+    pPrint (ListExpr elements)              = brackets $ fsep (punctuate comma (map pPrint elements))+    pPrint (TypedExpr _ expr)               = pPrint expr+    pPrint (UnaryExpr Len expr)             = char '|' <> pPrint expr <> char '|'+    pPrint (UnaryExpr op expr)              = pPrint op <> pPrint expr+    pPrint (ValueExpr value)                = pPrint value++ -- | A binary operator.-data BinaryOp   = Acc-                | Mul | Div | Mod-                | Add | Sub-                | Lt  | Lte | Gt | Gte-                | Eq  | Neq+data BinaryOp   = Acc -- ^ List access.+                | Mul -- ^ Multiplicaiton.+                | Div -- ^ Division.+                | Mod -- ^ Modulus.+                | Add -- ^ Addition.+                | Sub -- ^ Subtraction.+                | Lt  -- ^ Less than.+                | Lte -- ^ Less than or equal to.+                | Gt  -- ^ Greater than.+                | Gte -- ^ Greater than or equal to.+                | Eq  -- ^ Equal to.+                | Neq -- ^ Not equal to.     deriving (Eq, Show) +instance Pretty BinaryOp where+    pPrint Acc = text "!!"+    pPrint Mul = text "*"+    pPrint Div = text "/"+    pPrint Mod = text "%"+    pPrint Add = text "+"+    pPrint Sub = text "-"+    pPrint Lt  = text "<"+    pPrint Lte = text "<="+    pPrint Gt  = text ">"+    pPrint Gte = text ">="+    pPrint Eq  = text "=="+    pPrint Neq = text "!="++ -- | A unary operator.-data UnaryOp    = Len-                | Neg+data UnaryOp    = Len -- ^ List length.+                | Neg -- ^ Negation.     deriving (Eq, Show) +instance Pretty UnaryOp where+    pPrint Len = text "length"+    pPrint Neg = text "-"++ -- | A value is considered to be in it's normal form. data Value  = BoolValue Bool    -- ^ A boolean.             | IntValue Integer  -- ^ An unbounded integer.-            | ListValue [Value] -- ^ A normalised list of values.+            | ListValue [Value] -- ^ A normalised list value.             | NilValue          -- ^ A unit value.     deriving (Eq, Show) +instance Pretty Value where+    pPrint (BoolValue bool)     = text $ map toLower (show bool)+    pPrint (IntValue int)       = text $ show int+    pPrint (ListValue elements) = brackets $ fsep (punctuate comma (map pPrint elements))+    pPrint NilValue             = text "nil"++ -- | A type. data Type   = BoolType             | IntType             | ListType Type -- ^ A list type with an inner type.             | NilType     deriving (Eq, Show)++instance Pretty Type where+    pPrint BoolType         = text "Bool"+    pPrint IntType          = text "Int"+    pPrint (ListType inner) = brackets $ pPrint inner+    pPrint NilType          = text "Nil"+++-- Helper methods++block :: [Stmt] -> Doc+block = vcat . (map pPrint) 
src/Language/Qux/Version.hs view
@@ -1,34 +1,20 @@  {-| Module      : Language.Qux.Version-Description : Haskell constants of the language version.+Description : Haskell constant of the language version.  Copyright   : (c) Henry J. Wylde, 2015 License     : BSD3 Maintainer  : public@hjwylde.com -Haskell constants of the language version.+Haskell constant of the language version. -} -module Language.Qux.Version where--import Data.List (intercalate)----- * Version---- | The version formatted as "major.minor.patch".-version = intercalate "." (map show [major, minor, patch])----- ** Components---- | The major component.-major = 0---- | The minor component.-minor = 1+module Language.Qux.Version (+    -- * Version+    -- | The language version.+    version+) where --- | The patch component.-patch = 1+import Paths_language_qux (version)