-- Simple data type to keep track of character positions -- within a text file or other text stream. module Pappy.Pos where -- BEGIN CODE -- Basic position indicator data type: filename, line number, column number. data Pos = Pos { posFile :: !String, posLine :: !Int, posCol :: !Int } -- Incrementally compute the next position in a text file -- if 'c' is the character at the current position. -- Follows the standard convention of 8-character tab stops. nextPos (Pos file line col) c = if c == '\n' then Pos file (line + 1) 1 else if c == '\t' then Pos file line ((div (col + 8 - 1) 8) * 8 + 1) else Pos file line (col + 1) -- Two positions are equal if each of their elements are equal. instance Eq Pos where Pos f1 l1 c1 == Pos f2 l2 c2 = f1 == f2 && l1 == l2 && c1 == c2 -- Two positions are ordered by line number, then column number. instance Ord Pos where Pos f1 l1 c1 <= Pos f2 l2 c2 = (l1 < l2) || (l1 == l2 && c1 <= c2) -- Standard way to display positions - "file:line:col" instance Show Pos where show (Pos file line col) = file ++ ":" ++ show line ++ ":" ++ show col -- Show a position relative to a base position. -- If the new position is in the same line, just show its column number; -- otherwise if the new position is in the same file, -- just show its line and column numbers; -- otherwise show the complete new position. showPosRel (Pos file line col) (Pos file' line' col') = if (file == file') then if (line == line') then "column " ++ show col' else "line " ++ show line' ++ ", column " ++ show col' else show (Pos file' line' col')