module Compiler.Erlang.GlobalOpts

import Data.List
import Data.List1
import Data.Strings
import Compiler.Erlang.Name


%default total


public export
data OutputFormat = ErlangSource | ErlangSourcePretty | AbstractFormat | BeamFromErlangSource | BeamFromAbstractFormat

public export
record GlobalOpts where
  constructor MkGlobalOpts
  outputFormat : OutputFormat
  prefixStr : String
  inlineSize : Nat

export
defaultGlobalOpts : GlobalOpts
defaultGlobalOpts = MkGlobalOpts BeamFromErlangSource "Idris" 0


data Flag
  = SetOutputFormat OutputFormat
  | SetPrefix String
  | SetInlineSize Nat

flagToOpts : Flag -> GlobalOpts -> GlobalOpts
flagToOpts (SetOutputFormat outputFormat) opts = record { outputFormat = outputFormat } opts
flagToOpts (SetPrefix prefixStr) opts = record { prefixStr = prefixStr } opts
flagToOpts (SetInlineSize inlineSize) opts = record { inlineSize = inlineSize } opts

flagsToOpts : List Flag -> GlobalOpts
flagsToOpts flags = flagsToOpts' flags defaultGlobalOpts
  where
    flagsToOpts' : List Flag -> GlobalOpts -> GlobalOpts
    flagsToOpts' [] opts = opts
    flagsToOpts' (flag :: flags) opts = flagsToOpts' flags (flagToOpts flag opts)

parseOutputFormat : String -> Maybe OutputFormat
parseOutputFormat "erl" = Just ErlangSource
parseOutputFormat "erl-pretty" = Just ErlangSourcePretty
parseOutputFormat "abstr" = Just AbstractFormat
parseOutputFormat "beam" = Just BeamFromErlangSource
parseOutputFormat "beam-abstr" = Just BeamFromAbstractFormat
parseOutputFormat _ = Nothing

stringToFlags : List String -> List Flag
stringToFlags ds = mapMaybe parseFlag (map (\d => assert_total (words d)) ds) -- TODO: Remove `assert_total` when `words` is total
  where
    parseFlag : List String -> Maybe Flag
    parseFlag ["format", format] = SetOutputFormat <$> parseOutputFormat format
    parseFlag ["prefix", prefixStr] = Just $ SetPrefix prefixStr
    parseFlag ["inline", inlineSize] = Just $ SetInlineSize (integerToNat (cast inlineSize))
    parseFlag _ = Nothing

export
parseOpts : List String -> GlobalOpts
parseOpts str = flagsToOpts (stringToFlags str)
