packages feed

timberc-1.0.1: src/Fixity.hs

-- The Timber compiler <timber-lang.org>
--
-- Copyright 2008 Johan Nordlander <nordland@csee.ltu.se>
-- All rights reserved.
-- 
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
-- 
-- 1. Redistributions of source code must retain the above copyright
--    notice, this list of conditions and the following disclaimer.
-- 
-- 2. Redistributions in binary form must reproduce the above copyright
--    notice, this list of conditions and the following disclaimer in the
--    documentation and/or other materials provided with the distribution.
-- 
-- 3. Neither the names of the copyright holder and any identified
--    contributors, nor the names of their affiliations, may be used to 
--    endorse or promote products derived from this software without 
--    specific prior written permission.
-- 
-- THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
-- OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-- DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
-- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-- ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.

module Fixity where

import Common
import Syntax
import List(sort)

type Precedence         = Int
data Associativity      = LeftAss | RightAss | NonAss deriving (Eq,Show)

data Fixity             = Fixity Associativity Precedence deriving (Eq,Show)

data OpExp              = Nil Exp | Cons OpExp Name Exp 

fixity :: String -> Fixity
fixity op               = case lookup op fixTable of
                            Just f  -> f
                            Nothing -> fixFromChars op
  where fixTable        = [(":",  Fixity RightAss 5),
                           ("++", Fixity RightAss 5),
                           ("+",  Fixity LeftAss  6),
                           ("-",  Fixity LeftAss  6),
                           ("*",  Fixity LeftAss  7),
                           ("/",  Fixity LeftAss  7),
                           ("div",Fixity LeftAss  7),
                           ("mod",Fixity LeftAss  7),
                           ("@",  Fixity RightAss 9),
                           ("^",  Fixity RightAss 8),
                           ("==", Fixity NonAss   4),
                           ("/=", Fixity NonAss   4),
                           ("<",  Fixity NonAss   4),
                           ("<=", Fixity NonAss   4),
                           (">",  Fixity NonAss   4),
                           (">=", Fixity NonAss   4),
                           ("&&", Fixity RightAss 3),
                           ("||", Fixity RightAss 2),
                           (">>", Fixity LeftAss  1),
                           (">>=",Fixity LeftAss  1),
                           ("$",  Fixity RightAss 0)
                          ]
        fixFromChars op = case sort (nub (intersect op "+-*/<>")) of
                            "+"  -> Fixity LeftAss 6
                            "-"  -> Fixity LeftAss 6
                            "+-" -> Fixity LeftAss 6
                            "*"  -> Fixity LeftAss 7
                            "/"  -> Fixity LeftAss 7
                            "*/" -> Fixity LeftAss 7
                            "<"  -> Fixity NonAss  4
                            ">"  -> Fixity NonAss  4
                            "<>" -> Fixity NonAss  4
                            _    -> Fixity LeftAss 9

{-
Transforms a tree of infix expressions as produced by the parser 
(i.e., with all operators treated as left associative and of equal precedence) 
to a new tree reflecting operator associativity and precedence as given by
the function fixity.

Invariant: at each call to push, the second and third arguments have
the same length.
-}

transFix :: OpExp -> Exp
transFix e                          = push e [] []
  where push (Cons l o r) (o':os) es
          | prec==prec' && (ass/=ass' || ass==NonAss)
                                    = errorIds "Operator associativity ambiguity with operators" [o,o']
          | prec<prec' || (prec==prec' && ass==RightAss)
                                    = push (Cons l o (opApp r o' (head es))) os (tail es)
          where Fixity ass  prec    = fixity (show o)
                Fixity ass' prec'   = fixity (show o')
        push (Cons l o r) os es     = push l (o:os) (r:es)
        push (Nil e) os es          = popAll os (e:es)
        opApp l o r                 = EAp (EAp (op2exp o) l) r
         
        popAll (o:os) (e1:e2:es)    = popAll os (opApp e1 o e2:es)
        popAll [] es                = head es