packages feed

Jikka-5.1.0.0: test/Jikka/RestrictedPython/Convert/ToCoreSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Jikka.RestrictedPython.Convert.ToCoreSpec (spec) where

import Jikka.Common.Alpha
import Jikka.Common.Error
import qualified Jikka.Core.Format as Y (formatProgram)
import qualified Jikka.Core.Language.BuiltinPatterns as Y
import qualified Jikka.Core.Language.Expr as Y
import Jikka.RestrictedPython.Convert.ToCore (run)
import qualified Jikka.RestrictedPython.Language.Expr as X
import qualified Jikka.RestrictedPython.Language.WithoutLoc as X
import Test.Hspec

run' :: X.Program -> Either Error Y.Program
run' = flip evalAlphaT 0 . run

spec :: Spec
spec = describe "run" $ do
  it "works" $ do
    let prog =
          [ X.ToplevelFunctionDef
              "solve"
              [("n", X.IntTy)]
              X.IntTy
              [ X.If
                  (X.eqExp X.IntTy (X.name "n") (X.constIntExp 0))
                  [ X.Return (X.constIntExp 1)
                  ]
                  [ X.Return (X.binOp (X.name "n") X.Mult (X.call (X.name "solve") [X.binOp (X.name "n") X.Sub (X.constIntExp 1)]))
                  ]
              ]
          ]
    let expected =
          Y.ToplevelLetRec
            "solve"
            [("n", Y.IntTy)]
            Y.IntTy
            ( Y.If'
                (Y.VarTy "$0")
                (Y.Equal' Y.IntTy (Y.Var "n") Y.Lit0)
                Y.Lit1
                ( Y.Mult'
                    (Y.Var "n")
                    (Y.App (Y.Var "solve") (Y.Minus' (Y.Var "n") Y.Lit1))
                )
            )
            (Y.ResultExpr (Y.Var "solve"))
    run' prog `shouldBe` Right expected
  it "converts for-loops to foldl" $ do
    let prog =
          [ X.ToplevelFunctionDef
              "solve"
              [("n", X.IntTy)]
              X.IntTy
              [ X.AnnAssign (X.nameTrg "a") X.IntTy (X.constIntExp 0),
                X.AnnAssign (X.nameTrg "b") X.IntTy (X.constIntExp 1),
                X.For
                  (X.nameTrg "i")
                  (X.call (X.constBuiltinExp X.BuiltinRange1) [X.name "n"])
                  [ X.AnnAssign (X.nameTrg "c") X.IntTy (X.binOp (X.name "a") X.Add (X.name "b")),
                    X.AnnAssign (X.nameTrg "a") X.IntTy (X.name "b"),
                    X.AnnAssign (X.nameTrg "b") X.IntTy (X.name "c")
                  ],
                X.Return (X.name "a")
              ]
          ]
    let expected =
          unlines
            [ "let rec solve (n: int): int =",
              "    let a: $0 =",
              "        0",
              "    in let b: $1 =",
              "        1",
              "    in let $4: $5 * $6 =",
              "        foldl((fun ($4: $5 * $6) ($3: $2) ->",
              "            let b: $5 =",
              "                $4.0",
              "            in let a: $6 =",
              "                $4.1",
              "            in let i: $7 =",
              "                $3",
              "            in let c: $8 =",
              "                a + b",
              "            in let a: $9 =",
              "                b",
              "            in let b: $10 =",
              "                c",
              "            in (b, a)",
              "        ), (b, a), range(n))",
              "    in let b: $5 =",
              "        $4.0",
              "    in let a: $6 =",
              "        $4.1",
              "    in a",
              "in",
              "solve"
            ]
    (Y.formatProgram <$> run' prog) `shouldBe` Right expected
  it "converts if-statements correctly" $ do
    let prog =
          [ X.ToplevelFunctionDef
              "solve"
              []
              X.IntTy
              [ X.If
                  (X.constBoolExp True)
                  [ X.AnnAssign (X.nameTrg "x") X.IntTy (X.constIntExp 1)
                  ]
                  [ X.AnnAssign (X.nameTrg "x") X.IntTy (X.constIntExp 0)
                  ],
                X.Return (X.name "x")
              ]
          ]
    let expected =
          unlines
            [ "let rec solve : int =",
              "    let $2: $1, =",
              "        if true then let x: $3 =",
              "            1",
              "        in (x,) else let x: $5 =",
              "            0",
              "        in (x,)",
              "    in let x: $1 =",
              "        $2.0",
              "    in x",
              "in",
              "solve"
            ]
    (Y.formatProgram <$> run' prog) `shouldBe` Right expected