module Main where import Graphics.UI.GLUT hiding (R, Repeat) import Graphics.UI.GLUT.Turtle import Text.XML.YJSVG import Language.Lojban.Read import System.Environment import System.IO.Unsafe import Data.Maybe import Data.IORef import Data.IORef.Tools import Control.Applicative import Control.Monad main :: IO () main = do prgName <- getProgName rawArgs <- getArgs _args <- initialize prgName rawArgs f <- openField "cakyrespa" 640 480 prompt f ".i " t <- newTurtle f -- pencolor t ((255, 255, 255) :: (Int, Int, Int)) -- fillcolor t ((255, 255, 255) :: (Int, Int, Int)) shape t "turtle" shapesize t 3 3 oninputtext f (processInput f t . cmd) mainLoop cmd :: String -> Command cmd = flip pcmd [] . readLojban pcmd :: Lojban -> [Argument] -> Command pcmd p = case p of Vocative "co'o" -> const COhO TenseGI "ba" b c -> \args -> Commands (pcmd b args) (pcmd c args) Prenex ss b -> const $ CommandList $ do rss <- mapM sumtiToArgument ss return $ pcmd b rss b@(Bridi (Brivla "gasnu") s) -> \args -> fromMaybe (Unknown b) $ readGasnu s args b@(Bridi (Brivla "morji") s) -> const $ fromMaybe (Unknown b) $ readMorji s b@(Bridi (Brivla "klama") s) -> const $ fromMaybe (Unknown b) $ readKlama s b@(Bridi (Brivla "galfi") s) -> const $ fromMaybe (Unknown b) $ readGalfi s b@(Bridi (Brivla "tcidu") s) -> const $ fromMaybe (Unknown b) $ readTcidu s b@(Bridi (Brivla "rejgau") s) -> const $ fromMaybe (Unknown b) $ readRejgau s b@(Bridi (Brivla "viska") s) -> const $ fromMaybe (Unknown b) $ readViska s b@(Bridi (NA (Brivla "viska")) s) -> const $ fromMaybe (Unknown b) $ readNAViska s b@(Bridi (Brivla "cisni") s) -> const $ fromMaybe (Unknown b) $ readCisni s b@(Bridi (Brivla "xruti") s) -> const $ fromMaybe (Unknown b) $ readXruti s b@(Bridi (Brivla "rapli") s) -> const $ fromMaybe (Unknown b) $ readRapli s b@(Bridi (Brivla "carna") s) -> fromMaybe (const $ Unknown b) $ readCarna s b@(Bridi (Brivla "crakla") s) -> fromMaybe (const $ Unknown b) $ readCrakla s b@(Bridi (Brivla "rixykla") s) -> const $ fromMaybe (Unknown b) $ readRixykla s b@(Bridi (Brivla "pilno") s) -> fromMaybe (const $ Unknown b) $ readBAPilno s b@(Bridi (NA (Brivla "pilno")) s) -> const $ fromMaybe (Unknown b) $ readNAPilno s b@(Bridi (Brivla "clugau") s) -> const $ fromMaybe (Unknown b) $ readClugau s r -> const $ Unknown r updateReaders :: (Lojban -> Maybe Command) -> Lojban -> Maybe ([Argument] -> Command) updateReaders reader text = do c <- reader text return $ const c readGasnu s a = do KOhA "ko" <- lookup (FA 1) s LerfuString cmene <- lookup (FA 2) s return $ GASNU cmene a readMorji s = do KOhA "ko" <- lookup (FA 1) s GOI (LerfuString cmene) (LO (DUhU fasnu) _) <- lookup (FA 2) s return $ MORJI cmene $ pcmd fasnu readKlama s = do KOhA "ko" <- lookup (FA 1) s LI (JOhI [Number x, Number y]) <- lookup (FA 2 ) s return $ KLAMA x y readGalfi s = do TUhA (KOhA "ko") <- lookup (FA 1) s LO (Brivla "foldi") Nothing <- lookup (FA 2) s LO (Brivla skari) Nothing <- lookup (FA 3) s clr <- lookup skari skaste return $ let (r, g, b) = clr in FLOSKA r g b readTcidu s = do KOhA "ko" <- lookup (FA 1) s LA (Right (ME (ZOI fp))) <- lookup (FA 2) s return $ READFILE fp readRejgau s = do KOhA "ko" <- lookup (FA 1) s ZOI fp <- lookup (BAI Nothing "me'e") s tai <- lookup (BAI (Just "se") "tai") s case tai of LA (Right (Brivla "cakyrespa")) -> return $ SAVEASCAK fp LA (Left "syvygyd") -> return $ SAVEASSVG fp s -> error $ show s readViska :: [(Tag, Sumti)] -> Maybe Command readViska s = do KOhA "ko" <- lookup (FA 2) s return VISKA readNAViska :: [(Tag, Sumti)] -> Maybe Command readNAViska s = do KOhA "ko" <- lookup (FA 2) s return NAVISKA readNAPilno :: [(Tag, Sumti)] -> Maybe Command readNAPilno s = do KOhA "ko" <- lookup (FA 1) s return NAPILNOLOPENBI readCisni :: [(Tag, Sumti)] -> Maybe Command readCisni s = do LI (Number n) <- lookup (FA 1) s KOhA "ko" <- lookup (FA 2) s return $ CISNI n readXruti :: [(Tag, Sumti)] -> Maybe Command readXruti s = do KOhA "ko" <- lookup (FA 1) s return $ XRUTI readRapli :: [(Tag, Sumti)] -> Maybe Command readRapli s = do LO (NU p) _ <- lookup (FA 1) s LI (Number n) <- lookup (FA 2) s return $ Repeat (round n) (pcmd p []) readClugau :: [(Tag, Sumti)] -> Maybe Command readClugau s = do KOhA "ko" <- lookup (FA 1) s case ((Time ["co'a"], KU) `elem` s, (Time ["co'u"], KU) `elem` s) of (True, False) -> return COhACLUGAU (False, True) -> return COhUCLUGAU _ -> fail "bad" readBAPilno :: [(Tag, Sumti)] -> Maybe ([Argument] -> Command) readBAPilno s = do cm <- readPilno s if (Time ["ba"], KU) `elem` s then return cm else return $ \args -> Commands (cm args) PILNOLOPENBI readPilno :: [(Tag, Sumti)] -> Maybe ([Argument] -> Command) readPilno s = do KOhA "ko" <- lookup (FA 1) s selpli <- lookup (FA 2) s case selpli of LO (Brivla "penbi") (Just (POI (Bridi (Brivla "cisni") [ (FA 1, LI (Number size))]))) -> return $ const $ PEBYCISNI size LO (Linkargs (Brivla "penbi") (SFIhO (Brivla "cisni") (LI (Number size)))) _ -> return $ const $ PEBYCISNI size LO (Brivla "penbi") (Just (POI (Bridi (Brivla skari) []))) -> do (r, g, b) <- lookup skari skaste return $ const $ PEBYSKA r g b LO (Linkargs (Brivla "penbi") (LO (Brivla skari) _)) _ -> do (r, g, b) <- lookup skari skaste return $ const $ PEBYSKA r g b LO (Brivla "penbi") (Just (POI (Bridi (ME me) []))) -> do case me of LO (Brivla skari) _ -> do (r, g, b) <- lookup skari skaste return $ const $ PEBYSKA r g b CEhU i -> return $ \args -> fromMaybe (ErrorC "bad args") $ do skari <- getALO args i pebska <- mapM colorNameToPEBYSKA skari return $ CommandList pebska LO (Brivla "burcu") (Just (POI (Bridi (Brivla skari) []))) -> do (r, g, b) <- lookup skari skaste return $ const $ BURSKA r g b LO (Linkargs (Brivla "burcu") (SFIhO (Brivla "skari") (LO (Brivla skari) _))) _ -> do (r, g, b) <- lookup skari skaste return $ const $ BURSKA r g b LO (Brivla "penbi") Nothing -> return $ const PILNOLOPENBI _ -> return $ const $ UnknownSelpli selpli colorNameToPEBYSKA :: String -> Maybe Command colorNameToPEBYSKA skari = do (r, g, b) <- lookup skari skaste return $ PEBYSKA r g b skaste :: [(String, (Int, Int, Int))] skaste = [ ("xekri", (0, 0, 0)), ("blabi", (255, 255, 255)), ("xunre", (255, 0, 0)), ("labri'o", (0, 255, 0)), -- Lime ("crinyblabi", (0, 255, 0)), -- Lime ("blanu", (0, 0, 255)), ("pelxu", (255, 255, 0)), ("cicna", (0, 255, 255)), ("nukni", (255, 0, 255)), ("rijyska", (192, 192, 192)), -- Silver ("grusi", (128, 128, 128)), -- ("?", (128, 0, 0)), -- Maroon ("alzaityska", (128, 128, 0)), -- Olive ("crino", (0, 128, 0)), ("zirpu", (128, 0, 128)), -- Purple -- ("?", (0, 128, 128)), -- Teal -- ("?", (0, 0, 128)), -- Navy ("bunre", (165, 42, 42)), -- Brown ("narju", (255, 165, 0)), -- Orange ("sloska", (255, 215, 0)), -- Gold ("xunblabi", (255, 192, 203)) -- Pink ] readLAhU2 :: [(Tag, Sumti)] -> Maybe (Either Double Int) readLAhU2 s = do lahu <- lookup (BAI Nothing "la'u") s case lahu of LI (Number d) -> return $ Left d CEhU i -> return $ Right i _ -> fail "bad" readCrakla :: [(Tag, Sumti)] -> Maybe ([Argument] -> Command) readCrakla s = do KOhA "ko" <- lookup (FA 1) s return $ case readLAhU2 s of Just (Left d) -> const $ CRAKLA d Just (Right i) -> \args -> if length args < i then ErrorC $ "too few args " ++ show i ++ " for " ++ show (length args) else case args !! (i - 1) of ADouble d -> CRAKLA d _ -> ErrorC "bad argument" _ -> const $ CRAKLA 100 -- return $ const $ CRAKLA $ maybe 100 (\(Left d) -> d) $ readLAhU2 s readRixykla :: [(Tag, Sumti)] -> Maybe Command readRixykla s = do KOhA "ko" <- lookup (FA 1) s return $ RIXYKLA $ maybe 100 (\(Left d) -> d) $ readLAhU2 s readCarna :: [(Tag, Sumti)] -> Maybe ([Argument] -> Command) readCarna s = do KOhA "ko" <- lookup (FA 1) s LO (Brivla lr) _ <- return $ -- let LO (Brivla lr) _ = fromMaybe (LO (Brivla "zunle") Nothing) $ lookup (FA 3) s -- d = maybe 90 (\(Left d) -> d) $ readLAhU2 s let d = fromMaybe (Left 90) $ readLAhU2 s case lr of "zunle" -> return $ flip (either $ const . ZUNLE) d $ \i args -> maybe (ErrorC "bad args") ZUNLE $ getDouble args i "pritu" -> return $ flip (either $ const . PRITU) d $ \i args -> maybe (ErrorC "bad args") PRITU $ getDouble args i _ -> fail "bad" getDouble :: [Argument] -> Int -> Maybe Double getDouble args i = do when (length args < i) $ fail "bad" ADouble d <- return $ args !! (i - 1) return d getALO :: [Argument] -> Int -> Maybe [String] getALO args i = do when (length args < i) $ fail "bad" ALO s <- return $ args !! (i - 1) return [s] data Argument = ADouble Double | AInt Int | ACommand Command | ALO String | ACons Argument Argument -- deriving Show sumtiToArgument (LI (Number n)) = [ADouble n] sumtiToArgument (LO (Brivla s) _) = [ALO s] sumtiToArgument (STense "ba" s_ t_) = sumtiToArgument s_ ++ sumtiToArgument t_ sumtiToArgument s = error $ "sumtiToArgument :" ++ show s data Command = KLAMA Double Double | CRAKLA Double | RIXYKLA Double | ZUNLE Double | PRITU Double | PEBYCISNI Double | PEBYSKA Int Int Int | BURSKA Int Int Int | FLOSKA Int Int Int | COhACLUGAU | COhUCLUGAU | Commands Command Command | CommandList [Command] | Repeat Int Command | XRUTI | CISNI Double | NAPILNOLOPENBI | PILNOLOPENBI | NAVISKA | VISKA | SAVEASSVG FilePath | SAVEASCAK FilePath | READFILE FilePath | MORJI String ([Argument] -> Command) | GASNU String [Argument] | COhO | Unknown Lojban | ParseErrorC | UnknownSelpli Sumti | ErrorC String -- deriving Show type Table = [(String, [Argument] -> Command)] theTable :: IORef Table theTable = unsafePerformIO $ newIORef [] morji :: String -> ([Argument] -> Command) -> IO () morji cmene fasnu = atomicModifyIORef_ theTable ((cmene, fasnu) :) tcidu :: String -> IO (Maybe ([Argument] -> Command)) tcidu cmene = lookup cmene <$> readIORef theTable data LR = L | R | BadLR deriving Show processInput :: Field -> Turtle -> Command -> IO Bool processInput _ t (KLAMA x y) = goto t x y >> return True processInput _ t (CRAKLA d) = forward t d >> return True processInput _ t (RIXYKLA d) = backward t d >> return True processInput _ t (ZUNLE d) = left t d >> return True processInput _ t (PRITU d) = right t d >> return True processInput _ t (PEBYCISNI s) = pensize t s >> return True processInput _ t (PEBYSKA r g b) = pencolor t (r, g, b) >> return True processInput _ t (BURSKA r g b) = fillcolor t (r, g, b) >> return True processInput _ t (FLOSKA r g b) = bgcolor t (r, g, b) >> return True processInput _ t COhACLUGAU = beginfill t >> return True processInput _ t COhUCLUGAU = endfill t >> return True processInput _ t XRUTI = undo t >> return True processInput _ t (CISNI s) = shapesize t s s >> return True processInput _ t NAPILNOLOPENBI = penup t >> return True processInput _ t PILNOLOPENBI = pendown t >> return True processInput _ t NAVISKA = hideturtle t >> return True processInput _ t VISKA = showturtle t >> return True processInput _ _ COhO = return False processInput f t (Commands c d) = processInput f t c >> processInput f t d processInput f t (CommandList cl) = mapM_ (processInput f t) cl >> return True processInput f t (Repeat n c) = sequence_ (replicate n (processInput f t c)) >> return True processInput f t (MORJI cmene fasnu) = morji cmene fasnu >> return True processInput f t (GASNU cmene sumti) = do mfasnu <- tcidu cmene flip (maybe $ processInput f t $ ErrorC $ "not defined: " ++ cmene) mfasnu $ \fasnu -> processInput f t $ fasnu sumti processInput _ t (SAVEASSVG fp) = do w <- windowWidth t h <- windowHeight t svg <- getSVG t writeFile fp $ showSVG w h svg return True processInput _ t (SAVEASCAK fp) = inputs t >>= writeFile fp . show >> return True processInput _ t (READFILE fp) = readFile fp >>= runInputs t . read >> return True processInput f _ (Unknown u) = do outputString f ".i mi na jimpe" putStr "Unknown " >> print u return True processInput f _ (UnknownSelpli us) = do outputString f ".i mi na djuno lo bi'unai selpli" putStr "Unknown " >> print us return True processInput f _ ParseErrorC = do outputString f ".i di'u na drani fo lo gerna" return True processInput f _ (ErrorC str) = do putStrLn $ "error: " ++ str return True