blob: 89ee3e121872755d3d2001c72d80a5ed001fc1e0 [file] [log] [blame]
-- Copyright 2020 The Fuchsia Authors. All rights reserved.
-- Use of this source code is governed by a BSD-style license that can be
-- found in the LICENSE file.
module Mode exposing
( Map
, Mode(..)
, decode
, decodeMap
, defaultInput
, defaultOutput
, empty
, encode
, encodeMap
, get
, inputs
, insert
, nextInput
, nextOutput
, options
, outputs
, previousInput
, previousOutput
, singleton
, title
)
{-| This module defines the Mode type.
A mode is a format supported by fidlbolt. Some of them, like Fidl and Go,
directly correspond to file types. Others, like BytesPlus and Diff, are more
like abstract parsers/targets.
In fidlbolt, the user selects an input and output mode. Only some input modes
are allowed, and for a given input mode only a some output modes are allowed.
The core functionality of the app is implemented in a set of input-output
transformations. For example, (Fidl, Json) compiles a FIDL file with fidlc;
(Bytes, FidlText) attemps to decode bytes (represented in hex) to FIDL Text.
-}
import Dict exposing (Dict)
import Form exposing (Form)
import Json.Decode as Decode
import Json.Encode as Encode
------------- MODE -------------------------------------------------------------
type Mode
= Bytes
| BytesPlus
| C
| Dart
| Diff
| Fidl
| FidlText
| Go
| Hlcpp
| Json
| Llcpp
| Rust
inputs : List Mode
inputs =
[ Fidl, FidlText, Bytes ]
outputs : Mode -> List Mode
outputs input =
case input of
Fidl ->
[ Fidl, Json, C, Llcpp, Hlcpp, Rust, Go, Dart ]
FidlText ->
-- TODO(mkember): Add BytesPlus once implemented.
[ FidlText, Bytes ]
Bytes ->
-- TODO(mkember): Add BytesPlus once implemented.
[ Bytes, Diff, FidlText ]
_ ->
[]
defaultInput : Mode
defaultInput =
Fidl
defaultOutput : Mode -> Mode
defaultOutput input =
case input of
Fidl ->
Json
FidlText ->
Bytes
Bytes ->
Bytes
_ ->
input
nextInput : Mode -> Mode
nextInput input =
Maybe.withDefault input (getNext input inputs)
previousInput : Mode -> Mode
previousInput input =
Maybe.withDefault input (getPrevious input inputs)
nextOutput : Mode -> Mode -> Mode
nextOutput input output =
Maybe.withDefault output (getNext output (outputs input))
previousOutput : Mode -> Mode -> Mode
previousOutput input output =
Maybe.withDefault output (getPrevious output (outputs input))
getNext : a -> List a -> Maybe a
getNext item list =
let
rec restOfList =
case restOfList of
[] ->
Nothing
[ last ] ->
if last == item then
List.head list
else
Nothing
first :: second :: rest ->
if first == item then
Just second
else
rec (second :: rest)
in
rec list
getPrevious : a -> List a -> Maybe a
getPrevious item list =
getNext item (List.reverse list)
{-| Returns a form containing options for the given input-output transformation.
These get passed along to the server and affect its response.
-}
options : Mode -> Mode -> Form
options input output =
let
files default others =
Form.select "file" "File" (default :: others) (Tuple.first default)
entries =
case ( input, output ) of
( Fidl, Fidl ) ->
[ Form.checkbox "lint" "Lint" False ]
( Fidl, Json ) ->
[ files ( "ir", "Library IR" )
[ ( "schema", "Schema" )
, ( "deps", "Dependencies" )
]
]
( Fidl, Hlcpp ) ->
[ files ( "header", "Header" )
[ ( "source", "Source" )
, ( "tables", "Tables" )
]
]
( Fidl, Llcpp ) ->
[ files ( "header", "Header" )
[ ( "source", "Source" )
, ( "test", "Test base" )
, ( "tables", "Tables" )
]
]
( Fidl, C ) ->
[ files ( "header", "Header" )
[ ( "client", "Client" )
, ( "server", "Server" )
, ( "tables", "Tables" )
]
]
( Fidl, Dart ) ->
[ files ( "library", "Library" )
[ ( "test", "Test base" ) ]
]
( _, Bytes ) ->
[ Form.number "columns" "Columns" 8 (\n -> n > 0)
, Form.number "group" "Grouping" 2 (\n -> n > 0)
, Form.checkbox "offsets" "Line offsets" True
, Form.checkbox "capital" "Capital hex" False
, Form.checkbox "ascii" "ASCII" False
]
( Bytes, Diff ) ->
[ Form.text "separator" "Separator" ";"
]
_ ->
[]
in
Form.define entries
------------- MAP --------------------------------------------------------------
{-| A mapping from modes to a. The key type is String rather than Mode because
non-String keys don't work well in Elm (they aren't comparable).
-}
type alias Map a =
Dict String a
empty : Map a
empty =
Dict.empty
singleton : Mode -> a -> Map a
singleton mode value =
Dict.singleton (toString mode) value
get : Mode -> Map a -> Maybe a
get mode =
Dict.get (toString mode)
insert : Mode -> a -> Map a -> Map a
insert mode value map =
Dict.insert (toString mode) value map
------------- ENCODE / DECODE --------------------------------------------------
encode : Mode -> Encode.Value
encode mode =
Encode.string (toString mode)
decode : Decode.Decoder Mode
decode =
Decode.andThen
(\string ->
case fromString string of
Just mode ->
Decode.succeed mode
Nothing ->
Decode.fail ("Invalid mode: " ++ string)
)
Decode.string
encodeMap : (a -> Encode.Value) -> Map a -> Encode.Value
encodeMap encoder map =
Encode.dict identity encoder map
decodeMap : Decode.Decoder a -> Decode.Decoder (Map a)
decodeMap decoder =
Decode.dict decoder
------------- STRING FUNCTIONS -------------------------------------------------
toString : Mode -> String
toString mode =
case mode of
Bytes ->
"bytes"
BytesPlus ->
"bytes+"
C ->
"c"
Dart ->
"dart"
Diff ->
"diff"
Fidl ->
"fidl"
FidlText ->
"fidltext"
Go ->
"go"
Hlcpp ->
"hlcpp"
Json ->
"json"
Llcpp ->
"llcpp"
Rust ->
"rust"
fromString : String -> Maybe Mode
fromString string =
case string of
"bytes" ->
Just Bytes
"bytes+" ->
Just BytesPlus
"c" ->
Just C
"dart" ->
Just Dart
"diff" ->
Just Diff
"fidl" ->
Just Fidl
"fidltext" ->
Just FidlText
"go" ->
Just Go
"hlcpp" ->
Just Hlcpp
"json" ->
Just Json
"llcpp" ->
Just Llcpp
"rust" ->
Just Rust
_ ->
Nothing
title : Mode -> String
title mode =
case mode of
Bytes ->
"Bytes"
BytesPlus ->
"Bytes+"
C ->
"C"
Dart ->
"Dart"
Diff ->
"Diff"
Fidl ->
"FIDL"
FidlText ->
"FIDL Text"
Go ->
"Go"
Hlcpp ->
"HLCPP"
Json ->
"JSON"
Llcpp ->
"LLCPP"
Rust ->
"Rust"