Packages
finitomata
0.13.0
0.41.0
0.40.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.1
0.30.3
0.30.2
0.30.1
0.30.0
0.29.10
0.29.9
0.29.8
0.29.7
0.29.6
0.29.5
0.29.4
0.29.3
0.29.2
0.29.1
0.29.0
0.28.1
0.28.0
0.27.1
0.27.0
0.26.4
0.26.3
0.26.2
0.26.1
0.26.0
0.25.0
0.24.4
0.24.3
0.24.2
0.24.1
0.24.0
0.23.7
0.23.6
0.23.5
0.23.4
0.23.3
0.23.2
0.23.1
0.23.0
0.22.1
0.22.0
0.21.4
0.21.3
0.21.2
0.21.1
0.21.0
0.20.2
0.20.1
0.20.0
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.1
0.17.0
0.16.0
0.15.1
0.15.0
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.1
0.12.0
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.1
0.1.0
The FSM implementation generated from PlantUML textual representation.
Current section
Files
Jump to
Current section
Files
lib/finitomata/parser/plant_uml.ex
defmodule Finitomata.PlantUML do
@moduledoc false
import NimbleParsec
alias Finitomata.Parser
@behaviour Parser
@alphanumeric [?a..?z, ?A..?Z, ?0..?9, ?_]
blankspace = ignore(ascii_string([?\s], min: 1))
transition_op = string("-->")
event_op = string(":")
event =
ascii_char([?a..?z])
|> optional(ascii_string(@alphanumeric, min: 1))
|> optional(ascii_char([??, ?!]))
|> reduce({IO, :iodata_to_binary, []})
state = choice([string("[*]"), event])
plant_line =
optional(blankspace)
|> concat(state)
|> ignore(blankspace)
|> ignore(transition_op)
|> ignore(blankspace)
|> concat(state)
|> ignore(blankspace)
|> ignore(event_op)
|> ignore(blankspace)
|> concat(event)
|> optional(blankspace)
|> ignore(choice([times(string("\n"), min: 1), eos()]))
|> tag(:transition)
malformed =
optional(utf8_string([not: ?\n], min: 1))
|> string("\n")
|> pre_traverse(:abort)
@doc ~S"""
iex> {:ok, result, _, _, _, _} = Finitomata.PlantUML.transition("state1 --> state2 : succeeded")
iex> result
[transition: ["state1", "state2", "succeeded"]]
iex> {:error, message, _, _, _, _} = Finitomata.PlantUML.transition("state1 --> State2 : succeeded")
iex> String.slice(message, 0..14)
"expected string"
"""
defparsec(:transition, plant_line)
@doc ~S"""
iex> {:ok, result, _, _, _, _} = Finitomata.PlantUML.fsm("s1 --> s2 : ok\ns2 --> [*] : ko")
iex> result
[transition: ["s1", "s2", "ok"], transition: ["s2", "[*]", "ko"]]
"""
defparsec(:fsm, times(choice([plant_line, malformed]), min: 1))
@doc ~S"""
iex> {:ok, result, _, _, _, _} = Finitomata.PlantUML.fsm("s1 --> s2 : ok\ns2 --> [*] : ko")
...> Finitomata.PlantUML.validate(result)
{:error, :initial_state}
iex> {:ok, result, _, _, _, _} = Finitomata.PlantUML.fsm("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> [*] : ko")
...> Finitomata.PlantUML.validate(result)
{:ok,
[
%Finitomata.Transition{event: :foo, from: :*, to: :s1},
%Finitomata.Transition{event: :ok, from: :s1, to: :s2},
%Finitomata.Transition{event: :ko, from: :s2, to: :*}
]}
"""
@impl Parser
def validate(parsed), do: Finitomata.validate(parsed)
@doc ~S"""
iex> Finitomata.PlantUML.parse("[*] --> s1 : ok\ns2 --> [*] : ko")
{:error, :orphan_from_state}
iex> Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> [*] : ko")
{:ok,
[
%Finitomata.Transition{event: :foo, from: :*, to: :s1},
%Finitomata.Transition{event: :ok, from: :s1, to: :s2},
%Finitomata.Transition{event: :ko, from: :s2, to: :*}
]}
"""
@impl Parser
def parse(input) do
case fsm(input) do
{:ok, result, _, _, _, _} ->
validate(result)
{:error, "[line: " <> _ = msg, _rest, context, _, _} ->
[numbers, msg] = String.split(msg, "|||")
{numbers, []} = Code.eval_string(numbers)
{:error, msg, numbers[:rest], context, {numbers[:line], numbers[:column]},
numbers[:offset]}
error ->
error
end
end
@impl Parser
def lint(input) when is_binary(input), do: "@startuml\n\n" <> input <> "\n@enduml"
@spec abort(
String.t(),
[String.t()],
map(),
{non_neg_integer, non_neg_integer},
non_neg_integer
) :: {:error, binary()}
defp abort(rest, content, _context, {line, column}, offset) do
rest = content |> Enum.reverse() |> Enum.join() |> Kernel.<>(rest)
meta = inspect(line: line, column: column, offset: offset, rest: rest)
{:error, meta <> "|||malformed FSM transition, expected `from --> to : event`"}
end
end