{- CAO Compiler
Copyright (C) 2014 Cryptography and Information Security Group, HASLab - INESC TEC and Universidade do Minho
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . -}
{-# LANGUAGE FlexibleContexts #-}
{- |
Module : $Header$
Description : AST Post processor.
Copyright : (C) 2014 Cryptography and Information Security Group, HASLab - INESC TEC and Universidade do Minho
License : GPL
Maintainer : Paulo Silva
Stability : experimental
Portability : non-portable
Post processes the CAO AST after type checking, introducing explicit casts
when coercions are used.
-}
module Language.CAO.Typechecker.PostProcessor ( annotE ) where
import Language.CAO.Typechecker.Constraint
import Language.CAO.Syntax
import Language.CAO.Syntax.Utils
import Language.CAO.Type
import Language.CAO.Type.Utils
import Language.CAO.Common.Var
import Language.CAO.Common.SrcLoc
--------------------------------------------------------------------------------
annotE :: [Substitution] -> Type Var -> TLExpr Var -> TLExpr Var
annotE sbs tr (L loc (TyE ta l@(Lit _))) = let
ta' = subst' sbs ta
in checkCoerce (L loc $ TyE ta' l) ta' tr
annotE sbs tr (L loc (TyE ta e@(Var _))) = let
ta' = subst' sbs ta
in checkCoerce (L loc $ TyE ta' e) ta' tr
annotE sbs tr (L loc (TyE ta (FunCall fn es))) = let
ta' = subst' sbs ta
FuncSig pts _ _ = typeOf fn
es' = zipWith (annotE sbs) pts es
in checkCoerce (L loc $ TyE ta' $ FunCall fn es') ta' tr
-- A projection is always applied to a structure.
-- There are no coercions, unifications or casts inside strutures.
-- Structures are not algebraic types and cannot be used inside matrices
-- The expression 'se' can only be a struct or a path inside vectors or other
-- structures.
-- Conjecture: there are no undefined annotations inside the path to a structure
annotE sbs tr (L loc (TyE ta e@(StructProj _ _))) = let
ta' = subst' sbs ta
in checkCoerce (L loc $ TyE ta' e) ta' tr
annotE sbs tr (L loc (TyE ta (UnaryOp op e1))) = let
ta' = subst' sbs ta
e1' = annotE sbs ta' e1
in checkCoerce (L loc $ TyE ta' $ UnaryOp op e1') ta' tr
annotE sbs tr (L loc (TyE ta (BinaryOp op e1 e2))) = let
ta' = subst' sbs ta
(e1', e2') = annotOp op sbs ta' e1 e2
in checkCoerce (L loc $ TyE ta' $ BinaryOp op e1' e2') ta' tr
annotE sbs tr (L loc (TyE ta (Access e p))) = let
ta' = subst' sbs ta
e' = annotAccess sbs ta' e (isRange p)
in checkCoerce (L loc $ TyE ta' $ Access e' p) ta' tr
-- XXX: type is being ignored
annotE sbs _ (L loc (TyE ta (Cast b td e))) = let
ta' = subst' sbs ta
te = subst' sbs (typeOf e)
e' = annotE sbs te e
in case checkCoerce e' te ta' of
-- Additional implicit casts may be needed
-- Maintains the original cast external occurrence
L _ (TyE _ (Cast _ _ e'')) -> L loc $ TyE ta' $ Cast b td e''
-- The cast was not necessary (casting the type to itself)
e'' -> e''
--------------------------------------------------------------------------------
annotOp :: BinOp Var -> [Substitution] -> Type Var -> TLExpr Var -> TLExpr Var -> (TLExpr Var, TLExpr Var)
annotOp (ArithOp Power) sbs tr e1 e2 = let
e1' = annotE sbs tr e1
e2' = annotE sbs Int e2
in (e1', e2')
annotOp (ArithOp Times) sbs tr e1 e2 = let
t1 = subst' sbs $ typeOf e1
t2 = subst' sbs $ typeOf e2
in case (t1, t2) of
(Matrix s1 s2 _, Matrix s2' s3 _) -> let
Matrix _ _ tr' = tr
e1' = annotE sbs (Matrix s1 s2 tr') e1
e2' = annotE sbs (Matrix s2' s3 tr') e2
in (e1', e2')
_ -> let
e1' = annotE sbs tr e1
e2' = annotE sbs tr e2
in (e1', e2')
annotOp (CmpOp ty _) sbs Bool e1 e2 = let
tr = subst' sbs ty
e1' = annotE sbs tr e1
e2' = annotE sbs tr e2
in (e1', e2')
annotOp (CmpOp _ _) _ _ _ _ = error ".: Unexpected case for compare operations"
annotOp (BitsSROp _) sbs tr e1 e2 = let
e1' = annotE sbs tr e1
e2' = annotE sbs RInt e2
in (e1', e2')
annotOp Concat sbs tr e1 e2 = case tr of
-- Concatenation of bit strings does not imply any coercion
Bits _ _ -> let
t1 = subst' sbs $ typeOf e1
t2 = subst' sbs $ typeOf e2
e1' = annotE sbs t1 e1
e2' = annotE sbs t2 e2
in (e1', e2')
Vector _ t -> let
-- Maintain the sizes of the expected vector types
Vector k1 _ = subst' sbs $ typeOf e1
Vector k2 _ = subst' sbs $ typeOf e2
e1' = annotE sbs (Vector k1 t) e1
e2' = annotE sbs (Vector k2 t) e2
in (e1', e2')
_ -> error ".: Unexpected case for concat"
annotOp _ sbs tr e1 e2 = let
e1' = annotE sbs tr e1
e2' = annotE sbs tr e2
in (e1', e2')
--------------------------------------------------------------------------------
-- In this function, we have to distinguish the cases of accesses to individual
-- elements, from the case of ranges.
annotAccess :: [Substitution] -> Type Var -> TLExpr Var -> Bool -> TLExpr Var
annotAccess sbs tr e isRng = case subst' sbs (typeOf e) of
t@(Bits _ _) -> annotE sbs t e
Vector k _ -> annotE sbs (Vector k tr') e
Matrix i j _ -> annotE sbs (Matrix i j tr') e
_ -> error ".: Unexpected case for an access"
where
tr' = if isRng then head (innerType tr) else tr
--------------------------------------------------------------------------------
checkCoerce :: TLExpr Var -> Type Var -> Type Var -> TLExpr Var
checkCoerce e tct tct'
| tct == tct' = e
| isModInt tct && isModInt tct' =
let e' = addCoerce e Int
in checkCoerce e' Int tct'
| isModInt tct && isBits tct' =
let e' = addCoerce e Int
in checkCoerce e' Int tct'
| isBits tct && isMod tct' =
let e' = addCoerce e Int
in checkCoerce e' Int tct'
| isInt tct && isModPol tct' =
let bas = extractBottomBaseType tct'
e' = addCoerce e bas
in checkCoerce e' bas tct'
| isMod tct && isModPol tct' && extractBaseType tct' /= tct =
let bas = extractBaseType tct'
e' = addCoerce e bas
in checkCoerce e' bas tct'
| otherwise
= addCoerce e tct'
--------------------------------------------------------------------------------
addCoerce :: TLExpr Var -> Type Var -> TLExpr Var
addCoerce e tct' = let
tct = case tct' of
Tuple tpl -> map (L genSrcLoc . type2TyDecl) tpl
_ -> [L genSrcLoc $ type2TyDecl tct']
in L genSrcLoc $ annTyE tct' $ Cast False tct e
--------------------------------------------------------------------------------