SeqSim/src/SeqSim/Render.elm

121 lines
4.0 KiB
Elm

module SeqSim.Render exposing (view)
import SeqSim.Model exposing (Model, Msg(..))
import SeqSim.Parser exposing (parse, vars, valid, varsValid, Prog, Source(..))
import SeqSim.Evaluator exposing (..)
import Maybe.Extra exposing (combine)
import List.Extra exposing (zip, getAt)
import Tuple exposing (second)
import Html exposing (Html, text, textarea, input, label, small, div, span, button, a, h1, h2, h3, h4, h5, br)
import Html.Attributes exposing (class, classList, id, for, type_, value, href)
import Html.Events exposing (onClick, onInput)
view : Model -> List (Html Msg)
view m =
[ div [ class "container" ]
[ h1 [] [ text "Sequential Consistency Simulator" ]
, viewProgs m.programs
, viewOutcomes m
]
]
toolbar : Html Msg
toolbar = div [ class"btn-group" ]
[ button
[ type_ "button"
, class "btn btn-primary"
, onClick AddProgram ]
[ text "Add Program" ]
]
viewProgs : List String -> Html Msg
viewProgs ps = div []
[ h2 [] [ text "Programs" ]
, toolbar
, div [ class "mt-2 row row-cols-1 row-cols-md-2 row-cols-lg-4" ]
<| List.indexedMap viewProg ps
]
viewProg : Int -> String -> Html Msg
viewProg i s = div [ class "col mb-2" ]
[ div [ class "card" ]
[ div [ class "card-body" ]
[ h5 [ class "card-title" ] [ text <| "Program " ++ String.fromInt (i+1) ]
, viewProgValidity s
, textarea [ class "mt-2 mb-2 form-control", onInput (ChangeProgram i), value s ] [ ]
, a [ class "btn btn-outline-danger", onClick (DeleteProgram i) ] [ text "Remove" ]
]
]
]
viewProgValidity : String -> Html Msg
viewProgValidity s =
if valid s
then span [ class "text-success" ] [ text "Valid" ]
else span [ class "text-danger" ] [ text "Invalid" ]
viewOutcomes : Model -> Html Msg
viewOutcomes m = div []
[ h2 [] [ text "Possible Outcomes" ]
, div [ class "form-group" ]
[ label [ for "variables" ] [ text "Interesting Variables" ]
, input
[ type_ "text"
, id "variables"
, class "form-control"
, if String.isEmpty m.variables
then classList []
else if varsValid m.variables then class "is-valid" else class "is-invalid"
, value m.variables
, onInput ChangeVariables
] []
, small [ class "form-text text-muted" ]
[ text "Enter the variables you want included in the final outcomes, separated by a comma."
]
]
, viewOutcomeTable m
]
viewOutcomeTable : Model -> Html Msg
viewOutcomeTable m =
case (vars m.variables, combine <| List.map parse m.programs) of
(Just (x::xs), Just ps) ->
let all = allOutcomes (x::xs) ps
in div [ class "card" ] <| List.singleton <| div [ class "card-body" ]
[ div [ class "row" ]
[ div [ class "col border-right col-auto" ]
<| List.indexedMap (viewRow (x::xs))
<| List.map second all
, div [ class "col" ] <|
case Maybe.andThen (\i -> getAt i all) m.selected of
Nothing -> []
Just (p, o) ->
[ viewProgStr p
]
]
]
_ -> div [] []
viewRow : List String -> Int -> List Int -> Html Msg
viewRow xs i vs = div []
[ a [ href "#", onClick (SelectOutcome i) ]
[ text <| stringFromOutcome xs vs
]
]
stringFromOutcome : List String -> List Int -> String
stringFromOutcome xs vs = List.map2 (\x v -> x ++ " = " ++ String.fromInt v) xs vs
|> String.join ", "
viewProgStr : Prog -> Html Msg
viewProgStr p =
let
sourceStr s =
case s of
Var x -> x
Const i -> String.fromInt i
in
List.map (\(x, s) -> text <| x ++ " = " ++ sourceStr s) p
|> List.intersperse (br [] [])
|> div []