{-# LANGUAGE FlexibleContexts #-}

-- |
-- Module      : Jikka.RestrictedPython.Convert.ResolveBuiltin
-- Description : resolves names of builtin functions using information of arity. / arity の情報を使いながら組み込み関数を名前解決します。
-- Copyright   : (c) Kimiyuki Onaka, 2021
-- License     : Apache License 2.0
-- Maintainer  : kimiyuki95@gmail.com
-- Stability   : experimental
-- Portability : portable
module Jikka.RestrictedPython.Convert.ResolveBuiltin
  ( run,
  )
where

import Jikka.Common.Alpha
import Jikka.Common.Error
import Jikka.RestrictedPython.Language.Builtin
import Jikka.RestrictedPython.Language.Expr
import Jikka.RestrictedPython.Language.Lint
import Jikka.RestrictedPython.Language.Util

runExpr :: (MonadAlpha m, MonadError Error m) => Expr' -> m Expr'
runExpr :: Expr' -> m Expr'
runExpr = (Expr' -> m Expr') -> Expr' -> m Expr'
forall (m :: * -> *).
Monad m =>
(Expr' -> m Expr') -> Expr' -> m Expr'
mapSubExprM Expr' -> m Expr'
forall (m :: * -> *).
(MonadAlpha m, MonadError Error m) =>
Expr' -> m Expr'
go
  where
    go :: (MonadAlpha m, MonadError Error m) => Expr' -> m Expr'
    go :: Expr' -> m Expr'
go Expr'
e = case Expr' -> Expr
forall a. WithLoc' a -> a
value' Expr'
e of
      Name VarName'
x -> VarName' -> m Expr'
forall (m :: * -> *).
(MonadAlpha m, MonadError Error m) =>
VarName' -> m Expr'
resolveUniqueBuiltin VarName'
x
      Call (WithLoc' Maybe Loc
_ (Name VarName'
f)) [Expr']
args -> Maybe Loc -> Expr -> Expr'
forall a. Maybe Loc -> a -> WithLoc' a
WithLoc' (Expr' -> Maybe Loc
forall a. WithLoc' a -> Maybe Loc
loc' Expr'
e) (Expr -> Expr') -> m Expr -> m Expr'
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Expr' -> [Expr'] -> Expr
Call (Expr' -> [Expr'] -> Expr) -> m Expr' -> m ([Expr'] -> Expr)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> VarName' -> Int -> m Expr'
forall (m :: * -> *).
(MonadAlpha m, MonadError Error m) =>
VarName' -> Int -> m Expr'
resolveBuiltin VarName'
f ([Expr'] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Expr']
args) m ([Expr'] -> Expr) -> m [Expr'] -> m Expr
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [Expr'] -> m [Expr']
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Expr']
args)
      Attribute Expr'
e' Attribute'
a -> Maybe Loc -> Expr -> Expr'
forall a. Maybe Loc -> a -> WithLoc' a
WithLoc' (Expr' -> Maybe Loc
forall a. WithLoc' a -> Maybe Loc
loc' Expr'
e) (Expr -> Expr') -> m Expr -> m Expr'
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expr' -> Attribute' -> m Expr
forall (m :: * -> *).
(MonadAlpha m, MonadError Error m) =>
Expr' -> Attribute' -> m Expr
resolveAttribute Expr'
e' Attribute'
a
      Expr
_ -> Expr' -> m Expr'
forall (m :: * -> *) a. Monad m => a -> m a
return Expr'
e

-- | `run` resolves types of polymorphic builtin functions.
-- This assumes there are no assignments to builtin functions, i.e. `doesntHaveAssignmentToBuiltin`.
--
-- For example, the @max@ of @max(xs)@ has a type \(\mathbf{list}(\alpha) \to \alpha\) but the @max@ of @max(x, y, z)@ has a type \(\alpha \times \alpha \times \alpha \to \alpha\).
-- So this function converts @Var "max"@ to @BuiltinMax1 t@, @BuiltinMax t 2@, @BuiltinMax t 3@, etc..
run :: (MonadAlpha m, MonadError Error m) => Program -> m Program
run :: Program -> m Program
run Program
prog = String -> m Program -> m Program
forall (m :: * -> *) a. MonadError Error m => String -> m a -> m a
wrapError' String
"Jikka.RestrictedPython.Convert.ResolveBuiltin" (m Program -> m Program) -> m Program -> m Program
forall a b. (a -> b) -> a -> b
$ do
  Program -> m ()
forall (m :: * -> *). MonadError Error m => Program -> m ()
ensureDoesntHaveAssignmentToBuiltin Program
prog
  Program
prog <- (Expr' -> m Expr') -> Program -> m Program
forall (m :: * -> *).
Monad m =>
(Expr' -> m Expr') -> Program -> m Program
mapExprM Expr' -> m Expr'
forall (m :: * -> *).
(MonadAlpha m, MonadError Error m) =>
Expr' -> m Expr'
runExpr Program
prog
  Program -> m ()
forall (m :: * -> *). MonadError Error m => Program -> m ()
ensureDoesntHaveNonResolvedBuiltin Program
prog
  Program -> m Program
forall (m :: * -> *) a. Monad m => a -> m a
return Program
prog