packages feed

ascii85x-0.2.4.1: src/Data/TI85/Var.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}

-- | Specifics of the TI-85 variables themselves
-- (i.e. not their representation in the file).
module Data.TI85.Var (
    -- * Types
    Variable(..),
    TINumber(..),
    -- ** Program
    Program(..),
    Token(..),
    -- ** Window Settings
    FuncSettings(..),
    PolarSettings(..),
    ParamSettings(..),
    SavedWinSettings(..),
    -- *** Differential Equations
    DiffEqSettings(..),
    DiffEqAxis(..),
    AxisInd(..),
    -- ** Graph Database
    ModeSettings(..),
    GraphMode(..),
    FuncEqn(..),
    ParamEqn(..),
    DiffEqEqn(..),
    GDBLibEntry(..),
    GDBEqn(..),
    GDBSettings(..),
    GDB(..),
    HasGDB,

    -- * Text Conversion
    showVariable,
    -- ** Variable-specific
    showNumber,
    showProgram,
    showFuncSettings,
    showPolarSettings,
    showParamSettings,
    showDiffEqSettings,
    showWinSettings,
    showGDB,
    showGDBMode,

    -- * IO
    printVariable
    ) where

import Prelude hiding (concat, putStrLn)
import Data.Text (Text, concat, pack, intercalate, unpack)
import Data.Text.IO (putStrLn)
import Data.TI85.Token (TokenDef)
import Data.TI85.Var.Pic

-- * Types

-- | An instance of a token from the `TokenDef`
-- table. This will include actual text that goes
-- along with a token, when it is not a fixed-text
-- token.
data Token = Token TokenDef Text deriving Show

-- | A program is either stored as plaintext
-- (in the TI-86 codepage; see `Data.TI85.Encoding.tiDecode`)
-- or a list of tokens. The two are represented here to
-- maintain that information.
data Program = PlainText Text
    | Tokenized [Token]
    deriving Show

-- | Numerical variables are either Real or Complex.
data TINumber = TIReal Double | TIComplex Double Double deriving Show

-- ** Window Settings

-- | Function window settings
data FuncSettings = FuncSettings {
    fXMin :: TINumber,
    fXMax :: TINumber,
    fXScl :: TINumber,
    fYMin :: TINumber,
    fYMax :: TINumber,
    fYScl :: TINumber
    }
    deriving Show

-- | Polar window settings
data PolarSettings = PolarSettings {
    polThetaMin :: TINumber,
    polThetaMax :: TINumber,
    polThetaStep :: TINumber,
    polXMin :: TINumber,
    polXMax :: TINumber,
    polXScl :: TINumber,
    polYMin :: TINumber,
    polYMax :: TINumber,
    polYScl :: TINumber
    }
    deriving Show

-- | Parametric window settings
data ParamSettings = ParamSettings {
    parTMin :: TINumber,
    parTMax :: TINumber,
    parTStep :: TINumber,
    parXMin :: TINumber,
    parXMax :: TINumber,
    parXScl :: TINumber,
    parYMin :: TINumber,
    parYMax :: TINumber,
    parYScl :: TINumber
    }
    deriving Show

-- | Differential equation axes can come
-- with an index (e.g. Q1-Q9).
data AxisInd = Axis0
    | Axis1
    | Axis2
    | Axis3
    | Axis4
    | Axis5
    | Axis6
    | Axis7
    | Axis8
    | Axis9
    deriving (Show,Eq,Enum)

-- | Differential equation axis type
data DiffEqAxis = AxisT
    | AxisQ AxisInd
    | AxisQ' AxisInd
    deriving Show

-- | Differential equation window settings
data DiffEqSettings = DiffEqSettings {
    diffTol :: TINumber,
    diffTPlot :: TINumber,
    diffTMin :: TINumber,
    diffTMax :: TINumber,
    diffTStep :: TINumber,
    diffXMin :: TINumber,
    diffXMax :: TINumber,
    diffXScl :: TINumber,
    diffYMin :: TINumber,
    diffYMax :: TINumber,
    diffYScl :: TINumber,
    diffXAxis :: DiffEqAxis,
    diffYAxis :: DiffEqAxis
    }
    deriving Show

-- | Saved window settings, used for ZRCL.
data SavedWinSettings = SavedWinSettings {
    zThetaMin :: TINumber,
    zThetaMax :: TINumber,
    zThetaStep :: TINumber,
    ztPlot :: TINumber,
    ztMin :: TINumber,
    ztMax :: TINumber,
    ztStep :: TINumber,
    zxMin :: TINumber,
    zxMax :: TINumber,
    zxScl :: TINumber,
    zyMin :: TINumber,
    zyMax :: TINumber,
    zyScl :: TINumber
    }
    deriving Show

data ModeSettings = ModeSettings {
    modeDrawDot :: Bool,
    modeSimulG :: Bool,
    modeGridOn :: Bool,
    modePolarGC :: Bool,
    modeCoordOff :: Bool,
    modeAxesOff :: Bool,
    modeLabelOn :: Bool
    }
    deriving Show

-- | There are four graph modes, each with
-- its own set of window ranges and equation
-- types.
data GraphMode = Func | Polar | Param | DiffEq

-- | Plain functions and Polar functions both use
-- a single equation.
type FuncEqn = Text

-- | Parametric functions use a pair of equations
data ParamEqn = ParamEqn {
    xEqn :: Text,
    yEqn :: Text
    } deriving Show

-- | Differential equations have a single equation
-- paired with an initial condition.
data DiffEqEqn = DiffEqEqn {
    diffEqn :: Text,
    diffIC :: Double
    } deriving Show

class HasGDB (a :: GraphMode) where
    type GDBEqn a :: *
    type GDBSettings a :: *

    showGDBSettings :: GDB a -> Text
    showGDBHeader :: GDB a -> Text

    showGDBLib :: GDB a -> Text
    showGDBLib gdb = intercalate "\n" (map showGDBEntry (gdbLib gdb))

    showGDBEntry :: GDBLibEntry a -> Text

instance HasGDB Func where
    type GDBEqn Func = FuncEqn
    type GDBSettings Func = FuncSettings

    showGDBSettings gdb = showFuncSettings (gdbSettings gdb)
    showGDBHeader _ = "ID\tSelected\tEquation\n"
    showGDBEntry (GDBLibEntry entryId selected eqn) =
        showText entryId <> "\t"
        <> showText selected <> "\t"
        <> eqn

instance HasGDB Polar where
    type GDBEqn Polar = FuncEqn
    type GDBSettings Polar = PolarSettings
    showGDBSettings gdb = showPolarSettings (gdbSettings gdb)
    showGDBHeader _ = "ID\tSelected\tEquation\n"
    showGDBEntry (GDBLibEntry entryId selected eqn) =
        showText entryId <> "\t"
        <> showText selected <> "\t"
        <> eqn

instance HasGDB Param where
    type GDBEqn Param = ParamEqn
    type GDBSettings Param = ParamSettings
    showGDBSettings gdb = showParamSettings (gdbSettings gdb)
    showGDBHeader _ = "ID\tSelected\tx-Equation\ty-Equation\n"
    showGDBEntry (GDBLibEntry entryId selected eqn) =
        showText entryId <> "\t"
        <> showText selected <> "\t"
        <> xEqn eqn <> "\t"
        <> yEqn eqn

instance HasGDB DiffEq where
    type GDBEqn DiffEq = DiffEqEqn
    type GDBSettings DiffEq = DiffEqSettings
    showGDBSettings gdb = showDiffEqSettings (gdbSettings gdb)
    showGDBHeader _ = "ID\tSelected\tEquation\tInitial Condition\n"
    showGDBEntry (GDBLibEntry entryId selected eqn) =
        showText entryId <> "\t"
        <> showText selected <> "\t"
        <> diffEqn eqn <> "\t"
        <> showText (diffIC eqn)


-- | A graph database entry, containing a
-- function ID, whether or not it is currently
-- selected, and the equations that define the
-- function.
data GDBLibEntry (a :: GraphMode) = GDBLibEntry {
        libId :: Int,
        libSelected :: Bool,
        libEqn :: GDBEqn a
        }

-- | A graph database contains mode settings, window
-- settings, and a library of functions. The latter two
-- depend on the graphcs mode.
data GDB (a :: GraphMode) = GDB {
        gdbMode :: ModeSettings,
        gdbSettings :: GDBSettings a,
        gdbLib :: [GDBLibEntry a]
        }

instance HasGDB a => Show (GDB (a :: GraphMode)) where
    show gdb = unpack $ showGDB gdb


-- | Variables have a type and type-specific data.
-- See also `Data.TI85.File.Variable.VarType`.
data Variable =
    TIScalar TINumber
    | TIVector [TINumber]
    | TIList [TINumber]
    | TIMatrix [[TINumber]]
    | TIConstant TINumber
    | TIEquation Text
    | TIString Text
    | TIProgram Program
    | TIPicture TIBitmap
    | TIFuncSettings FuncSettings
    | TIPolarSettings PolarSettings
    | TIParamSettings ParamSettings
    | TIDiffEqSettings DiffEqSettings
    | TIZRCL SavedWinSettings
    | TIFuncGDB (GDB Func)
    | TIPolarGDB (GDB Polar)
    | TIParamGDB (GDB Param)
    | TIDiffEqGDB (GDB DiffEq)
    deriving Show

-- * Text Conversion

-- | Utility for converting a showable
-- to Text.
showText :: Show a => a -> Text
showText = pack.show

-- | Convert a TINumber to Text.
showNumber :: TINumber -> Text
showNumber (TIReal x) = showText x
showNumber (TIComplex x y) = showText x <> "+" <> showText y <> "i"

-- | Convert a Program to Text.
showProgram :: Program -> Text
showProgram (PlainText progText) = progText
showProgram (Tokenized tokens) =
    foldMap (\(Token _ t) -> t) tokens

-- ** Window Settings

-- | Function window settings.
showFuncSettings :: FuncSettings -> Text
showFuncSettings settings =
    "\nxMin: " <> showNumber (fXMin settings)
    <> "\nxMax: " <> showNumber (fXMax settings)
    <> "\nxScl: " <> showNumber (fXScl settings)
    <> "\nyMin: " <> showNumber (fYMin settings)
    <> "\nyMax: " <> showNumber (fYMax settings)
    <> "\nyScl: " <> showNumber (fYScl settings)

-- | Polar window settings.
showPolarSettings :: PolarSettings -> Text
showPolarSettings settings =
    "\nθMin: " <> showNumber (polThetaMin settings)
    <> "\nθMax: " <> showNumber (polThetaMax settings)
    <> "\nθStep: " <> showNumber (polThetaStep settings)
    <> "\nxMin: " <> showNumber (polXMin settings)
    <> "\nxMax: " <> showNumber (polXMax settings)
    <> "\nxScl: " <> showNumber (polXScl settings)
    <> "\nyMin: " <> showNumber (polYMin settings)
    <> "\nyMax: " <> showNumber (polYMax settings)
    <> "\nyScl: " <> showNumber (polYScl settings)

-- | Parametric window settings.
showParamSettings :: ParamSettings -> Text
showParamSettings settings =
    "\ntMin: " <> showNumber (parTMin settings)
    <> "\ntMax: " <> showNumber (parTMax settings)
    <> "\ntStep: " <> showNumber (parTStep settings)
    <> "\nxMin: " <> showNumber (parXMin settings)
    <> "\nxMax: " <> showNumber (parXMax settings)
    <> "\nxScl: " <> showNumber (parXScl settings)
    <> "\nyMin: " <> showNumber (parYMin settings)
    <> "\nyMax: " <> showNumber (parYMax settings)
    <> "\nyScl: " <> showNumber (parYScl settings)

-- | DiffEq window settings.
showDiffEqSettings :: DiffEqSettings -> Text
showDiffEqSettings settings =
    "\ndiffTol: " <> showNumber (diffTol settings)
    <> "\ntPlot: " <> showNumber (diffTPlot settings)
    <> "\ntMin: " <> showNumber (diffTMin settings)
    <> "\ntMax: " <> showNumber (diffTMax settings)
    <> "\ntStep: " <> showNumber (diffTStep settings)
    <> "\nxMin: " <> showNumber (diffXMin settings)
    <> "\nxMax: " <> showNumber (diffXMax settings)
    <> "\nxScl: " <> showNumber (diffXScl settings)
    <> "\nyMin: " <> showNumber (diffYMin settings)
    <> "\nyMax: " <> showNumber (diffYMax settings)
    <> "\nyScl: " <> showNumber (diffYScl settings)
    <> "\nxAxis: " <> showAxis (diffXAxis settings)
    <> "\nyAxis: " <> showAxis (diffYAxis settings)
  where
    showAxis :: DiffEqAxis -> Text
    showAxis AxisT = "t"
    showAxis (AxisQ ai) =
        let ind = fromEnum ai
        in if ind == 0
            then "Q"
            else "Q" <> showText ind
    showAxis (AxisQ' ai) =
        let ind = fromEnum ai
        in if ind == 0
            then "Q'"
            else "Q'" <> showText ind

-- | Saved window settings.
showWinSettings :: SavedWinSettings -> Text
showWinSettings settings =
    "\nzθMin: " <> showNumber (zThetaMin settings)
    <> "\nzθMax: " <> showNumber (zThetaMax settings)
    <> "\nzθStep: " <> showNumber (zThetaStep settings)
    <> "\nztPlot: " <> showNumber (ztPlot settings)
    <> "\nztMin: " <> showNumber (ztMin settings)
    <> "\nztMax: " <> showNumber (ztMax settings)
    <> "\nztStep: " <> showNumber (ztStep settings)
    <> "\nzxMin: " <> showNumber (zxMin settings)
    <> "\nzxMax: " <> showNumber (zxMax settings)
    <> "\nzxScl: " <> showNumber (zxScl settings)
    <> "\nzyMin: " <> showNumber (zyMin settings)
    <> "\nzyMax: " <> showNumber (zyMax settings)
    <> "\nzyScl: " <> showNumber (zyScl settings)

showGDBMode :: ModeSettings -> Text
showGDBMode mode =
    "Dot/Line: " <> if modeDrawDot mode then "Dot" else "Line" <> "\n"
    <> "Simul/Seq: " <> if modeSimulG mode then "Simul" else "Seq" <> "\n"
    <> "Grid: " <> showText (modeGridOn mode) <> "\n"
    <> "Polar: " <> showText (modePolarGC mode) <> "\n"
    <> "Coord: " <> showText (not $ modeCoordOff mode) <> "\n"
    <> "Axes: " <> showText (not $ modeAxesOff mode) <> "\n"
    <> "Label: " <> showText (modeLabelOn mode) <> "\n"

showGDB :: HasGDB (a :: GraphMode) => GDB (a :: GraphMode) -> Text
showGDB gdb =
    "Mode Settings:\n"
    <> showGDBMode (gdbMode gdb) <> "\n"
    <> "Window Settings:"
    <> showGDBSettings gdb <> "\n\n"
    <> "Library:\n"
    <> showGDBHeader gdb
    <> showGDBLib gdb

-- | Convert a Variable to Text
showVariable :: Variable -> Text
showVariable (TIScalar tn) = showNumber tn
showVariable (TIVector tns) =
    let nums = map showNumber tns
    in "<" <> intercalate "," nums <> ">"
showVariable (TIList tns) =
    let nums = map showNumber tns
    in "[" <> intercalate "," nums <> "]"
showVariable (TIMatrix tnss) =
    let rows = [ intercalate "," $ map showNumber row | row <- tnss ]
    in "<<" <> intercalate "\n  " rows <> ">>"
showVariable (TIConstant tn) = showNumber tn
showVariable (TIEquation txt) = txt
showVariable (TIString txt) = txt
showVariable (TIProgram pro) = showProgram pro
showVariable (TIPicture pic) = showAsciiArt pic
showVariable (TIFuncSettings settings) = showFuncSettings settings
showVariable (TIPolarSettings settings) = showPolarSettings settings
showVariable (TIParamSettings settings) = showParamSettings settings
showVariable (TIDiffEqSettings settings) = showDiffEqSettings settings
showVariable (TIZRCL settings) = showWinSettings settings
showVariable (TIFuncGDB gdb) = showGDB gdb
showVariable (TIPolarGDB gdb) = showGDB gdb
showVariable (TIParamGDB gdb) = showGDB gdb
showVariable (TIDiffEqGDB gdb) = showGDB gdb

-- * IO

-- | Print a textual representation of a Variable.
printVariable :: Variable -> IO ()
printVariable = putStrLn.showVariable