packages feed

technique-0.2.5: tests/CheckConcreteSyntax.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}

module CheckConcreteSyntax
  ( checkConcreteSyntax,
    main,
  )
where

import Core.System
import Core.Text.Rope ()
import Core.Text.Utilities
import ExampleProcedure hiding (main)
import Technique.Builtins
import Technique.Formatter
import Technique.Internal
import Technique.Language
import Technique.Quantity
import Test.Hspec

main :: IO ()
main = do
  finally (hspec checkConcreteSyntax) (putStrLn ".")

-- |
-- When we set the expectation using a [quote| ... |] here doc we get a
-- trailing newline that is not present in the rendered AST element. So
-- administratively add one here.
renderTest :: Render a => a -> String
renderTest x = show (highlight x <> line)

-- |
-- These are less tests than a body of code that exercises construction of
-- our concrete syntax tree.
checkConcreteSyntax :: Spec
checkConcreteSyntax = do
  describe "Constructions matching intended language design" $ do
    it "key builtin procedures are available" $ do
      functionName builtinProcedureTask `shouldBe` Identifier "task"

    it "procedure's function name is correct" $ do
      procedureName exampleRoastTurkey `shouldBe` Identifier "roast_turkey"

  describe "Rendering of concrete syntax tree to Technique language" $ do
    it "renders a list as tuple" $ do
      show (commaCat [Identifier "one", Identifier "two", Identifier "three"])
        `shouldBe` "one,two,three"
      show (commaCat ([] :: [Identifier]))
        `shouldBe` ""

    it "renders a tablet as expected" $
      let tablet =
            Tablet
              [ Binding (Label "Final temperature") (Variable 0 [Identifier "temp"]),
                Binding (Label "Cooking time") (Grouping 0 (Amount 0 (Quantity (Decimal 3 0) (Decimal 0 0) 0 "hr")))
              ]
       in do
            renderTest tablet
              `shouldBe` [quote|
[
    "Final temperature" ~ temp
    "Cooking time" ~ (3 hr)
]
|]

  describe "Rendering of a Block" $ do
    it "renders a normal block with indentation" $
      let b =
            Block
              [ Execute 0 (Variable 0 [Identifier "x"])
              ]
       in do
            renderTest b
              `shouldBe` [quote|
{
    x
}
|]

  describe "Rendering of a Procedure" $ do
    it "renders a function signature correctly" $
      let p =
            emptyProcedure
              { procedureName = Identifier "f",
                procedureInput = [Type "X"],
                procedureOutput = [Type "Y"],
                procedureBlock = Block [Execute 0 (Variable 0 [Identifier "z"])]
              }
       in do
            renderTest p
              `shouldBe` [quote|
    f : X -> Y
    {
        z
    }
|]