curry-frontend-0.2.1: src/Curry/Syntax/LexComb.lhs
% -*- LaTeX -*-
% $Id: LexComb.lhs,v 1.16 2004/01/20 16:44:14 wlux Exp $
%
% Copyright (c) 1999-2004, Wolfgang Lux
% See LICENSE for the full license.
%
\nwfilename{LexComb.lhs}
\section{Lexing combinators}
The module \texttt{LexComb} provides the basic types and combinators
to implement the lexers. The combinators use continuation passing code
in a monadic style. The first argument of the continuation function is
the string to be parsed, the second is the current position, and the
third is a flag which signals the lexer that it is lexing the
beginning of a line and therefore has to check for layout tokens. The
fourth argument is a stack of indentations that is used to handle
nested layout groups.
\begin{verbatim}
> module Curry.Syntax.LexComb where
> import Data.Char
> import Curry.Base.MessageMonad
> import Curry.Base.Position
> infixl 1 `thenP`, `thenP_`
> type Indent = Int
> type Context = [Indent]
> type P a = Position -> String -> Bool -> Context -> MsgMonad a
> parse :: P a -> FilePath -> String -> MsgMonad a
> parse p fn s = p (first fn) s False []
\end{verbatim}
Monad functions for the lexer.
\begin{verbatim}
> returnP :: a -> P a
> returnP x _ _ _ _ = return x
> thenP :: P a -> (a -> P b) -> P b
> thenP lex k pos s bol ctxt = lex pos s bol ctxt >>= \x -> k x pos s bol ctxt
> thenP_ :: P a -> P b -> P b
> p1 `thenP_` p2 = p1 `thenP` \_ -> p2
> failP :: Position -> String -> P a
> failP pos msg _ _ _ _ = failWith (parseError pos msg)
> closeP0 :: P a -> P (P a)
> closeP0 lex pos s bol ctxt = return (\_ _ _ _ -> lex pos s bol ctxt)
> closeP1 :: (a -> P b) -> P (a -> P b)
> closeP1 f pos s bol ctxt = return (\x _ _ _ _ -> f x pos s bol ctxt)
> parseError :: Position -> String -> String
> parseError p what = "\n" ++ show p ++ ": " ++ what
\end{verbatim}
Combinators that handle layout.
\begin{verbatim}
> pushContext :: Int -> P a -> P a
> pushContext col cont pos s bol ctxt = cont pos s bol (col:ctxt)
> popContext :: P a -> P a
> popContext cont pos s bol (_:ctxt) = cont pos s bol ctxt
> popContext cont pos s bol [] =
> error "parse error: popping layout from empty context stack. \
> \Perhaps you have inserted too many '}'?"
\end{verbatim}
Conversions from strings into numbers.
\begin{verbatim}
> convertSignedIntegral :: Num a => a -> String -> a
> convertSignedIntegral b ('+':s) = convertIntegral b s
> convertSignedIntegral b ('-':s) = - convertIntegral b s
> convertSignedIntegral b s = convertIntegral b s
> convertIntegral :: Num a => a -> String -> a
> convertIntegral b = foldl op 0
> where m `op` n | isDigit n = b * m + fromIntegral (ord n - ord0)
> | isUpper n = b * m + fromIntegral (ord n - ordA)
> | otherwise = b * m + fromIntegral (ord n - orda)
> ord0 = ord '0'
> ordA = ord 'A' - 10
> orda = ord 'a' - 10
> convertSignedFloating :: Fractional a => String -> String -> Int -> a
> convertSignedFloating ('+':m) f e = convertFloating m f e
> convertSignedFloating ('-':m) f e = - convertFloating m f e
> convertSignedFloating m f e = convertFloating m f e
> convertFloating :: Fractional a => String -> String -> Int -> a
> convertFloating m f e
> | e' == 0 = m'
> | e' > 0 = m' * 10^e'
> | otherwise = m' / 10^(-e')
> where m' = convertIntegral 10 (m ++ f)
> e' = e - length f
\end{verbatim}