implicit-0.2.0: tests/ParserSpec/Statement.hs
-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
-- Copyright (C) 2014-2017, Julia Longtin (julial@turinglace.com)
-- Released under the GNU AGPLV3+, see LICENSE
-- statement related hspec tests.
module ParserSpec.Statement (statementSpec) where
import Prelude (String, Maybe(Just), Bool(True), ($))
import Test.Hspec (Spec, Expectation, shouldBe, shouldSatisfy, it, pendingWith, describe)
-- import Text.ParserCombinators.Parsec ()
import ParserSpec.Util (bool, num, minus, mult, index)
import Graphics.Implicit.ExtOpenScad.Definitions (StatementI(StatementI), Symbol, Expr(ListE, LamE, Var), Statement(NewModule, ModuleCall, If, (:=)), Pattern(Name, ListP))
-- Parse an ExtOpenScad program.
import Graphics.Implicit.ExtOpenScad.Parser.Statement (parseProgram)
import Data.Either (Either(Right), isLeft)
-- an expectation that a string become a statement.
infixr 1 -->
(-->) :: String -> [StatementI] -> Expectation
(-->) source stmts =
parseProgram source `shouldBe` Right stmts
-- an expectation that a string generates an error.
parsesAsError :: String -> Expectation
parsesAsError source = parseProgram source `shouldSatisfy` isLeft
single :: Statement StatementI -> [StatementI]
single st = [StatementI 1 st]
call :: Symbol -> [(Maybe Symbol, Expr)] -> [StatementI] -> StatementI
call name args stmts = StatementI 1 (ModuleCall name args stmts)
-- test a simple if block.
ifSpec :: Spec
ifSpec = it "parses" $
"if (true) { a(); } else { b(); }" -->
single ( If (bool True) [call "a" [] []] [call "b" [] []])
-- test assignments.
assignmentSpec :: Spec
assignmentSpec = do
it "parses correctly" $
"y = -5;" --> single ( Name "y" := num (-5))
it "handles pattern matching" $
"[x, y] = [1, 2];" --> single (ListP [Name "x", Name "y"] := ListE [num 1, num 2])
it "handles the function keyword and definitions" $
"function foo(x, y) = x * y;" --> single fooFunction
it "nested indexing" $
"x = [y[0] - z * 2];" -->
single ( Name "x" := ListE [minus [index [Var "y", num 0],
mult [Var "z", num 2]]])
where
fooFunction :: Statement st
fooFunction = Name "foo" := LamE [Name "x", Name "y"]
(mult [Var "x", Var "y"])
emptyFileIssue :: Expectation -> Expectation
emptyFileIssue _ = pendingWith "parser should probably allow empty files"
statementSpec :: Spec
statementSpec = do
describe "assignment" $ assignmentSpec
describe "if" $ ifSpec
describe "empty file" $
it "returns an empty list" $
emptyFileIssue $ "" --> []
describe "line comment" $
it "parses as empty" $ emptyFileIssue $ "// foish bar\n" --> []
describe "module call" $
it "parses" $ "foo();" --> single (ModuleCall "foo" [] [])
describe "difference of two cylinders" $
it "parses correctly" $
"difference(){ cylinder(r=5,h=20); cylinder(r=2,h=20); }"
--> single (
ModuleCall "difference" [] [
call "cylinder" [(Just "r", num 5.0),
(Just "h", num 20.0)]
[],
call "cylinder" [(Just "r", num 2.0),
(Just "h", num 20.0)]
[]])
describe "empty module definition" $
it "parses correctly" $
"module foo_bar() {}" --> single (NewModule "foo_bar" [] [])