packages feed

cap-1.0: src/Language/Cap/Interpret/Parse.y

{
module Language.Cap.Interpret.Parse 
       (Program,RewriteRule(..),Term(..)
       ,parseProgram,parseTerm
       ,functionName,showRule) where

import Language.Cap.Interpret.Pretty

import Data.Char
}

%name parse Program
%name parseT Exp
%tokentype { Token }
%error { parseError }

%token
    variable    { TokenVariable $$ }
    constructor { TokenConstructor $$ }
    number      { TokenNumber $$ }
    'eof'       { TokenEOF }
    '\n'        { TokenEOR }
    '='         { TokenEq }
    '('         { TokenOB }
    ')'         { TokenCB }

%%

Program        : 'eof'                  { [] }
               | '\n' Program           { $2 }
               | Rule Program           { $1 : $2 }

Rule           : Function '=' Term      { Rule $1 $3 }

Function       : Function Pattern       { TApplication $1 $2 }
               | variable               { TAtom $1 }

Pattern        : '(' Pattern ')'        { $2 }
               | SConstruction          { $1 }
               | variable               { TVariable $1 }
               | number                 { TAtom $1 }

Construction   : '(' Construction ')'   { $2 }
               | Construction Pattern   { TApplication $1 $2 }
               | constructor            { TAtom $1 }

SConstruction  : '(' Construction ')'   { $2 }
               | constructor            { TAtom $1 }

TConstruction  : '(' TConstruction ')'  { $2 }
               | TConstruction STerm    { TApplication $1 $2 }
               | constructor            { TAtom $1 }

STConstruction : '(' TConstruction ')'  { $2 }
               | constructor            { TAtom $1 }

Term           : '(' Term ')'           { $2 }
               | Term STerm             { TApplication $1 $2 }
               | TConstruction          { $1 }
               | variable               { TAtom $1 }
               | number                 { TAtom $1 }

STerm          : '(' Term ')'           { $2 }
               | STConstruction         { $1 }
               | variable               { TAtom $1 }
               | number                 { TAtom $1 }

Exp            : Term 'eof'             { $1 }

{

-- | Terms are atoms, applications or variables.  When used on the LHS of a
--   rule, the function symbol must be an atom, and all arguments must be atoms
--   variables or applications of constructors.
data Term = TAtom String
          | TVariable String
          | TApplication Term Term
          deriving (Show,Read)

-- | A rewrite rule is made up of a pattern to match against, and a right hand
--   side to rewrite to.
data RewriteRule = Rule Term Term
                   deriving (Show,Read)

-- | Programs are simply lots of rewrite rules.
type Program = [RewriteRule]

parseError :: [Token] -> a
parseError x = error ("Out of cheese error, redo from start. " ++ show x)

data Token = TokenVariable String
           | TokenConstructor String
           | TokenNumber String
           | TokenEOR
           | TokenEOF
           | TokenEq
           | TokenOB
           | TokenCB
             deriving Show

lexer :: String -> [Token]
lexer []                   = [TokenEOF]
lexer ('\r':cs)            = TokenEOR : lexer cs
lexer ('\n':cs)            = TokenEOR : lexer cs
lexer (c:cs)
  | isSpace c              = lexer cs
  | isAlpha c && isUpper c = lexText TokenConstructor (c:cs)
  | isAlpha c && isLower c = lexText TokenVariable (c:cs)
  | isDigit c              = lexNum (c:cs)
lexer ('=':cs) = TokenEq : lexer cs
lexer ('(':cs) = TokenOB : lexer cs
lexer (')':cs) = TokenCB : lexer cs

lexNum cs = TokenNumber num : lexer rest
            where (num,rest) = span isDigit cs

lexText cons cs = cons text : lexer rest
                  where
                    (text,rest) = span isAlpha cs

-- | Takes a string representation of a pragram and parses into a list of rules
parseProgram :: String -> Program
parseProgram = sortVariables . parse . lexer

-- | Takes a string representation of a term and parses it
parseTerm :: String -> Term
parseTerm = parseT . lexer

sortVariables :: Program -> Program
sortVariables =
  map sortRuleVariables
  where
    sortRuleVariables :: RewriteRule -> RewriteRule
    sortRuleVariables (Rule p t) = Rule p (makeVariables t $ collectBindings p)
    
    collectBindings (TAtom _) = []
    collectBindings (TApplication i j) = collectBindings i ++ collectBindings j
    collectBindings (TVariable n) = [n]
    
    makeVariables t@(TAtom x) bs
      | x `elem` bs = TVariable x
      | otherwise   = TAtom x
    makeVariables (TApplication i j) bs =
      TApplication (makeVariables i bs) (makeVariables j bs)
    makeVariables x bs = x

-- | Returns the name of the function defined in a given rewrite rule
functionName :: RewriteRule -> String
functionName (Rule t _) =
  tHead t
  where
    tHead :: Term -> String
    tHead (TAtom x) = x
    tHead (TVariable x) = x
    tHead (TApplication f _) = tHead f

-- | Pretty prints a given rewrite rule
showRule :: RewriteRule -> String
showRule (Rule p e) =
  pretty (toPrettyTerm p) ++ " = " ++ pretty (toPrettyTerm e) ++ "\n"
  where
    toPrettyTerm (TAtom x) = PAtom x
    toPrettyTerm (TVariable x) = PAtom x
    toPrettyTerm (TApplication f a) =
      PApplication (toPrettyTerm f) (toPrettyTerm a)
}