module Graphics.Implicit.ExtOpenScad.Util.OVal where
import Graphics.Implicit.Definitions
import Graphics.Implicit.ExtOpenScad.Definitions
import qualified Control.Monad as Monad
import Data.Maybe (isJust)
class OTypeMirror a where
fromOObj :: OVal -> Maybe a
toOObj :: a -> OVal
instance OTypeMirror OVal where
fromOObj a = Just a
toOObj a = a
instance OTypeMirror ℝ where
fromOObj (ONum n) = Just n
fromOObj _ = Nothing
toOObj n = ONum n
instance OTypeMirror ℕ where
fromOObj (ONum n) = if n == fromIntegral (floor n) then Just (floor n) else Nothing
fromOObj _ = Nothing
toOObj n = ONum $ fromIntegral n
instance OTypeMirror Bool where
fromOObj (OBool b) = Just b
fromOObj _ = Nothing
toOObj b = OBool b
instance OTypeMirror String where
fromOObj (OString str) = Just str
fromOObj _ = Nothing
toOObj str = OString str
instance forall a. (OTypeMirror a) => OTypeMirror (Maybe a) where
fromOObj a = Just $ fromOObj a
toOObj (Just a) = toOObj a
toOObj Nothing = OUndefined
instance forall a. (OTypeMirror a) => OTypeMirror [a] where
fromOObj (OList list) = Monad.sequence . map fromOObj $ list
fromOObj _ = Nothing
toOObj list = OList $ map toOObj list
instance forall a b. (OTypeMirror a, OTypeMirror b) => OTypeMirror (a,b) where
fromOObj (OList ((fromOObj -> Just a):(fromOObj -> Just b):[])) = Just (a,b)
fromOObj _ = Nothing
toOObj (a,b) = OList [toOObj a, toOObj b]
instance forall a b c. (OTypeMirror a, OTypeMirror b, OTypeMirror c) => OTypeMirror (a,b,c) where
fromOObj (OList ((fromOObj -> Just a):(fromOObj -> Just b):(fromOObj -> Just c):[])) =
Just (a,b,c)
fromOObj _ = Nothing
toOObj (a,b,c) = OList [toOObj a, toOObj b, toOObj c]
instance forall a b. (OTypeMirror a, OTypeMirror b) => OTypeMirror (a -> b) where
fromOObj (OFunc f) = Just $ \input ->
let
oInput = toOObj input
oOutput = f oInput
output = fromOObj oOutput :: Maybe b
in case output of
Just out -> out
Nothing -> error $ "coercing OVal to a -> b isn't always safe; use a -> Maybe b"
++ " (trace: " ++ show oInput ++ " -> " ++ show oOutput ++ " )"
fromOObj _ = Nothing
toOObj f = OFunc $ \oObj ->
case fromOObj oObj :: Maybe a of
Nothing -> OError ["bad input type"]
Just obj -> toOObj $ f obj
instance forall a b. (OTypeMirror a, OTypeMirror b) => OTypeMirror (Either a b) where
fromOObj (fromOObj -> Just (x :: a)) = Just $ Left x
fromOObj (fromOObj -> Just (x :: b)) = Just $ Right x
fromOObj _ = Nothing
toOObj (Right x) = toOObj x
toOObj (Left x) = toOObj x
oTypeStr (OUndefined) = "Undefined"
oTypeStr (OBool _ ) = "Bool"
oTypeStr (ONum _ ) = "Number"
oTypeStr (OList _ ) = "List"
oTypeStr (OString _ ) = "String"
oTypeStr (OFunc _ ) = "Function"
oTypeStr (OModule _ ) = "Module"
oTypeStr (OError _ ) = "Error"
getErrors :: OVal -> Maybe String
getErrors (OError er) = Just $ head er
getErrors (OList l) = Monad.msum $ map getErrors l
getErrors _ = Nothing
type Any = OVal
caseOType = flip ($)
infixr 2 <||>
(<||>) :: forall desiredType out. (OTypeMirror desiredType)
=> (desiredType -> out)
-> (OVal -> out)
-> (OVal -> out)
(<||>) f g = \input ->
let
coerceAttempt = fromOObj input :: Maybe desiredType
in
if isJust coerceAttempt
then f $ (\(Just a) -> a) coerceAttempt
else g input
divideObjs children =
(map fromOObj2 . filter isOObj2 $ children,
map fromOObj3 . filter isOObj3 $ children,
filter (not . isOObj) $ children)
where
isOObj2 (OObj2 _) = True
isOObj2 _ = False
isOObj3 (OObj3 _) = True
isOObj3 _ = False
isOObj (OObj2 _) = True
isOObj (OObj3 _) = True
isOObj _ = False
fromOObj2 (OObj2 x) = x
fromOObj3 (OObj3 x) = x