Echo Writes Code

Main.hs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import Orchid.Tokenizer (runTokenizer)
import Orchid.Data (Token(..), renderToken, describeToken)

import qualified Data.Text.IO.Utf8 as Text.IO
import Data.Text (Text)

import qualified Options.Applicative as Options
import Options.Applicative ((<**>))

import qualified System.IO

import qualified Text.Colour.Chunk as Colors
import qualified Text.Colour.Capabilities as TerminalCapabilities

data Arguments = Arguments {
	sourceFile :: Maybe String,
	outputFile :: Maybe String
}

makeArgumentParser :: Options.ParserInfo Arguments
makeArgumentParser = Options.info
	(parseArguments <**> Options.helper)
	(Options.fullDesc <> Options.progDesc "Transforms an Orchid source file into another form" <> Options.header "orchid-cli: The Orchid compiler")

parseArguments :: Options.Parser Arguments
parseArguments = do
	sourceFile <- parseSourceFile
	outputFile <- parseOutputFile
	return Arguments { .. }

parseSourceFile :: Options.Parser (Maybe String)
parseSourceFile = Options.optional $ Options.strArgument (Options.metavar "SOURCE_FILE" <> Options.help "The source file to process")

parseOutputFile :: Options.Parser (Maybe String)
parseOutputFile = Options.optional $ Options.strOption (Options.short 'o' <> Options.long "output-file" <> Options.metavar "OUTPUT_FILE" <> Options.help "The output file to process")

main :: IO ()
main = runOrchidToolchain =<< Options.execParser makeArgumentParser

runOrchidToolchain :: Arguments -> IO ()
runOrchidToolchain (Arguments sourceFile outputFile) = do
	source <- readSourceFile sourceFile
	let result = runTokenizer (filenameOf sourceFile) source
	case result of
		Left e -> putStrLn e
		Right tokens -> renderTokens outputFile tokens

filenameOf :: Maybe String -> String
filenameOf (Just filename) = filename
filenameOf Nothing = "<standard input>"

readSourceFile :: Maybe String -> IO Text
readSourceFile (Just sourceFile) = Text.IO.readFile sourceFile
readSourceFile Nothing = Text.IO.getContents

renderTokens :: Maybe String -> [Token] -> IO ()
renderTokens outputFile tokens = do
	outputHandle <- case outputFile of
		Just path -> System.IO.openFile path System.IO.WriteMode
		Nothing -> return System.IO.stdout
	mapM_ (Text.IO.hPutStrLn outputHandle . displayToken) tokens
	System.IO.hClose outputHandle

displayToken :: Token -> Text
displayToken token = "> " <> description <> ": " <> colorRepresentation representation where
	representation = renderToken token
	description = describeToken token

colorRepresentation :: Text -> Text
colorRepresentation text = Colors.renderChunkText TerminalCapabilities.With8Colours colored where
	colored = Colors.fore Colors.cyan chunk
	chunk = Colors.chunk text