git @ Cat's Eye Technologies Turmac / master src / Main.hs
master

Tree @master (Download .tar.gz)

Main.hs @masterraw · history · blame

-- SPDX-FileCopyrightText: Chris Pressey, the creator of this work, has dedicated it to the public domain.
-- For more information, please refer to <https://unlicense.org/>
-- SPDX-License-Identifier: Unlicense

module Main where

import Data.Char (digitToInt)
import Data.List (intercalate)
import System.Environment
import System.Exit

import Language.Turmac.Model
import Language.Turmac.IR
import Language.Turmac.Parser
import Language.Turmac.Analyzer (isComplete)
import Language.Turmac.Simulator
import Language.Turmac.GenTape
import Language.Turmac.Normalizer
import Language.Turmac.Backend.Python
import Language.Turmac.Backend.Turmac
import Language.Turmac.Backend.IRDump

--
-- Command-line flags
--

data Flags = Flags {
    backend :: String,
    checkComplete :: Bool,
    initialTape :: [Symbol],
    maxSteps :: Integer,
    trace :: Bool
} deriving (Show, Ord, Eq)

defaultFlags = Flags{
    backend = "",
    checkComplete = False,
    initialTape = [],
    maxSteps = 0,
    trace = False
}

parseFlags flags ("--backend":s:rest) =
    parseFlags flags{ backend = s } rest
parseFlags flags ("--check-complete":rest) =
    parseFlags flags{ checkComplete = True } rest
parseFlags flags ("--initial-tape":s:rest) =
    parseFlags flags{ initialTape = words [if c == ',' then ' ' else c|c <- s] } rest
parseFlags flags ("--max-steps":n:rest) =
    parseFlags flags{ maxSteps = read n } rest
parseFlags flags ("--trace":rest) =
    parseFlags flags{ trace = True } rest
parseFlags flags other = (flags, other)

--
-- Parse to IR
--

parse :: Bool -> String -> Either String [TMRule]
parse True input =
    let rules = parseRules input
    in if null rules
       then Left "No valid rules found in input"
       else if not (isComplete rules)
            then Left "Incomplete Turmac description: missing state-symbol combinations"
            else Right $ rules
parse False input = Right $ parseRules input

compileTo :: String -> ([TMRule] -> String)
compileTo "python" = compileToPython
compileTo "turmac" = compileToTurmac
compileTo "normalized-turmac" = compileToNormalizedTurmac
compileTo "ir-dump" = compileToIRDump
compileTo _ = error "--backend must be given when compiling, and must be one of: 'python', 'turmac', 'ir-dump'"

--
-- Driver
--

main = do
    args <- getArgs
    let (flags, args') = parseFlags defaultFlags args
    case args' of
        ["simulate", fileName] -> do
            turmacText <- readFile fileName
            case parse (checkComplete flags) turmacText of
                Right tmRules ->
                    let
                        config = initConfigurationWithInput (initialTape flags)
                        (configs, finalConfig) = simulate tmRules config
                    in do
                        case trace flags of
                            True -> do
                                putStrLn "Simulation History:"
                                mapM_ (putStrLn . show) configs
                                putStrLn "\nFinal Configuration:"
                            False -> do
                                return ()
                        putStrLn $ (show finalConfig) ++ ", Halted: " ++ show (tmHalted finalConfig)
                        exitWith ExitSuccess

        ["compile", fileName] -> do
            turmacText <- readFile fileName
            case parse (checkComplete flags) turmacText of
                Right tmRules -> do
                    putStr $ compileTo (backend flags) tmRules
                    exitWith ExitSuccess

                Left errMsg -> do
                    putStrLn $ "Error parsing input file: " ++ errMsg
                    exitWith $ ExitFailure 1

        ["gentape", str] -> do
            putStr $ generateTapeWriter str
            exitWith ExitSuccess

        _ -> do
            putStrLn "Usage: turmac {flags} simulate <turmac-description-file>"
            putStrLn "       turmac {flags} compile <turmac-description-file>"
            putStrLn "       turmac {flags} gentape <string-of-digits>"
            putStrLn " where flags are:"
            putStrLn "   --backend        : when compiling, specifies backend to use"
            putStrLn "   --check-complete : check description is complete beforehand"
            putStrLn "   --initial-tape   : comma-seperated symbols initially on tape"
            putStrLn "   --trace          : when simulating, display each step taken"
            exitWith $ ExitFailure 2