packages feed

language-lustre-1.0.0: Language/Lustre/TypeCheck/Utils.hs

{-# Language OverloadedStrings #-}
module Language.Lustre.TypeCheck.Utils where

import Text.PrettyPrint
import Control.Monad(unless)

import Language.Lustre.AST
import Language.Lustre.Pretty
import Language.Lustre.TypeCheck.Monad
import Language.Lustre.TypeCheck.Constraint


-- | Assert that a given expression has only one type (i.e., is not a tuple)
one :: [a] -> M a
one xs =
  case xs of
    [x] -> pure x
    _   -> arityMismatch (length xs) 1

sameLen :: [a] -> [b] -> M ()
sameLen xs ys
  | a == b    = pure ()
  | otherwise = arityMismatch a b
  where
  a = length xs
  b = length ys

arityMismatch :: Int -> Int -> M a
arityMismatch x y =
  reportError $
  nestedError "Arity mismatch."
    [ "Expected arity:" <+> int x
    , "Actual arity:"   <+> int y
    ]

ctLUB :: CType -> CType -> M CType
ctLUB ct1 ct2 =
  do sameClock (cClock ct1) (cClock ct2)
     ty <- tLUB (cType ct1 )(cType ct2)
     pure CType { cClock = cClock ct1, cType = ty }



--------------------------------------------------------------------------------
-- Clocks


-- | Are these the same clock.  If so, return the one that is NOT a 'ConstExpr'
-- (if any).
sameClock :: IClock -> IClock -> M ()
sameClock x0 y0 =
  do x <- zonkClock x0
     y <- zonkClock y0
     case (x,y) of
       (ClockVar a, _) -> bindClockVar a y
       (_, ClockVar a) -> bindClockVar a x
       (BaseClock,BaseClock) -> pure ()
       (KnownClock a, KnownClock b) -> sameKnownClock a b
       _ -> reportError $ nestedError
             "The given clocks are different:"
             [ "Clock 1:" <+> pp x
             , "Clock 2:" <+> pp y
             ]

-- | Is this the same known clock.
sameKnownClock :: ClockExpr -> ClockExpr -> M ()
sameKnownClock c1@(WhenClock _ e1_init i1) c2@(WhenClock _ e2_init i2) =
  do unless (i1 == i2) $
        reportError $
        nestedError
          "The given clocks are different:"
          [ "Clock 1:" <+> pp c1
          , "Clock 2:" <+> pp c2
          ]
     sameConsts e1_init e2_init

-- | Get the clock of a clock, or fail if we are the base clock.
clockParent :: IClock -> M IClock
clockParent ct0 =
  do ct <- zonkClock ct0
     case ct of
       BaseClock -> reportError "The base clock has no parent."
       KnownClock (WhenClock _ _ i) -> cClock <$> lookupLocal i
                                          -- XXX: This can be a constnat?
       ClockVar _ -> reportError "Failed to infer the expressions's clock"



--------------------------------------------------------------------------------
-- Expressions

binConst :: (Integer -> Integer -> Integer) ->
            Expression -> Expression -> M Expression
binConst f e1 e2 =
  do x <- intConst e1
     y <- intConst e2
     pure $ Lit $ Int $ f x y

addExprs :: Expression -> Expression -> M Expression
addExprs = binConst (+) -- XXX: Can make an expression instead

minExprs :: Expression -> Expression -> M Expression
minExprs = binConst min

maxConsts :: Expression -> Expression -> M Expression
maxConsts = binConst max