{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -- | This module contains very basic definitions for Futhark - so basic, -- that they can be shared between the internal and external -- representation. module Language.Futhark.Core ( Uniqueness(..) , StreamOrd(..) , Commutativity(..) -- * Location utilities , locStr , locStrRel , prettyStacktrace -- * Name handling , Name , nameToString , nameFromString , nameToText , nameFromText , VName(..) , baseTag , baseName , baseString , pretty , quote , pquote -- * Special identifiers , defaultEntryPoint -- * Integer re-export , Int8, Int16, Int32, Int64 , Word8, Word16, Word32, Word64 ) where import Data.Int (Int8, Int16, Int32, Int64) import Data.String import Data.Word (Word8, Word16, Word32, Word64) import Data.Loc import qualified Data.Text as T import Futhark.Util.Pretty -- | The uniqueness attribute of a type. This essentially indicates -- whether or not in-place modifications are acceptable. With respect -- to ordering, 'Unique' is greater than 'Nonunique'. data Uniqueness = Nonunique -- ^ May have references outside current function. | Unique -- ^ No references outside current function. deriving (Eq, Ord, Show) instance Semigroup Uniqueness where (<>) = min instance Monoid Uniqueness where mempty = Unique instance Pretty Uniqueness where ppr Unique = star ppr Nonunique = empty data StreamOrd = InOrder | Disorder deriving (Eq, Ord, Show) -- | Whether some operator is commutative or not. The 'Monoid' -- instance returns the least commutative of its arguments. data Commutativity = Noncommutative | Commutative deriving (Eq, Ord, Show) instance Semigroup Commutativity where (<>) = min instance Monoid Commutativity where mempty = Commutative -- | The name of the default program entry point (main). defaultEntryPoint :: Name defaultEntryPoint = nameFromString "main" -- | The abstract (not really) type representing names in the Futhark -- compiler. 'String's, being lists of characters, are very slow, -- while 'T.Text's are based on byte-arrays. newtype Name = Name T.Text deriving (Show, Eq, Ord, IsString, Semigroup) instance Pretty Name where ppr = text . nameToString -- | Convert a name to the corresponding list of characters. nameToString :: Name -> String nameToString (Name t) = T.unpack t -- | Convert a list of characters to the corresponding name. nameFromString :: String -> Name nameFromString = Name . T.pack -- | Convert a name to the corresponding 'T.Text'. nameToText :: Name -> T.Text nameToText (Name t) = t -- | Convert a 'T.Text' to the corresponding name. nameFromText :: T.Text -> Name nameFromText = Name -- | A human-readable location string, of the form -- @filename:lineno:columnno@. This follows the GNU coding standards -- for error messages: -- https://www.gnu.org/prep/standards/html_node/Errors.html -- -- This function assumes that both start and end position is in the -- same file (it is not clear what the alternative would even mean). locStr :: Located a => a -> String locStr a = case locOf a of NoLoc -> "unknown location" Loc (Pos file line1 col1 _) (Pos _ line2 col2 _) -- Do not show line2 if it is identical to line1. | line1 == line2 -> first_part ++ "-" ++ show col2 | otherwise -> first_part ++ "-" ++ show line2 ++ ":" ++ show col2 where first_part = file ++ ":" ++ show line1 ++ ":" ++ show col1 -- | Like 'locStr', but @locStrRel prev now@ prints the location @now@ -- with the file name left out if the same as @prev@. This is useful -- when printing messages that are all in the context of some -- initially printed location (e.g. the first mention contains the -- file name; the rest just line and column name). locStrRel :: (Located a, Located b) => a -> b -> String locStrRel a b = case (locOf a, locOf b) of (Loc (Pos a_file _ _ _) _, Loc (Pos b_file line1 col1 _) (Pos _ line2 col2 _)) | a_file == b_file, line1 == line2 -> first_part ++ "-" ++ show col2 | a_file == b_file -> first_part ++ "-" ++ show line2 ++ ":" ++ show col2 where first_part = show line1 ++ ":" ++ show col1 _ -> locStr b -- | Given a list of strings representing entries in the stack trace -- and the index of the frame to highlight, produce a final -- newline-terminated string for showing to the user. This string -- should also be preceded by a newline. The most recent stack frame -- must come first in the list. prettyStacktrace :: Int -> [String] -> String prettyStacktrace cur = unlines . zipWith f [(0::Int)..] where -- Formatting hack: assume no stack is deeper than 100 -- elements. Since Futhark does not support recursion, going -- beyond that would require a truly perverse program. f i x = (if cur == i then "-> " else " ") ++ '#' : show i ++ (if i > 9 then "" else " ") ++ " " ++ x -- | A name tagged with some integer. Only the integer is used in -- comparisons, no matter the type of @vn@. data VName = VName !Name !Int deriving (Show) -- | Return the tag contained in the 'VName'. baseTag :: VName -> Int baseTag (VName _ tag) = tag -- | Return the name contained in the 'VName'. baseName :: VName -> Name baseName (VName vn _) = vn -- | Return the base 'Name' converted to a string. baseString :: VName -> String baseString = nameToString . baseName instance Eq VName where VName _ x == VName _ y = x == y instance Ord VName where VName _ x `compare` VName _ y = x `compare` y -- | Enclose a string in the prefered quotes used in error messages. -- These are picked to not collide with characters permitted in -- identifiers. quote :: String -> String quote s = "\"" ++ s ++ "\"" -- | As 'quote', but works on prettyprinted representation. pquote :: Doc -> Doc pquote = dquotes