Current section
Files
Jump to
Current section
Files
src/rexen@nfa@machine.erl
-module(rexen@nfa@machine).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([new/0, set_initial_state/2, set_ending_states/2, add_state/2, declare_states/2, add_transition/4, evaluate/2]).
-export_type([nfa/0, stack_value/0]).
-type nfa() :: {nfa,
gleam@dict:dict(binary(), rexen@nfa@state:state()),
binary(),
list(binary())}.
-type stack_value() :: {stack_value, integer(), rexen@nfa@state:state()}.
-file("src/rexen/nfa/machine.gleam", 14).
-spec new() -> nfa().
new() ->
{nfa, maps:new(), <<""/utf8>>, []}.
-file("src/rexen/nfa/machine.gleam", 18).
-spec set_initial_state(nfa(), binary()) -> nfa().
set_initial_state(Nfa, State) ->
{nfa, erlang:element(2, Nfa), State, erlang:element(4, Nfa)}.
-file("src/rexen/nfa/machine.gleam", 26).
-spec set_ending_states(nfa(), list(binary())) -> nfa().
set_ending_states(Nfa, Values) ->
{nfa, erlang:element(2, Nfa), erlang:element(3, Nfa), Values}.
-file("src/rexen/nfa/machine.gleam", 34).
-spec add_state(nfa(), binary()) -> nfa().
add_state(Nfa, Name) ->
{nfa,
gleam@dict:insert(
erlang:element(2, Nfa),
Name,
rexen@nfa@state:new(Name)
),
erlang:element(3, Nfa),
erlang:element(4, Nfa)}.
-file("src/rexen/nfa/machine.gleam", 42).
-spec declare_states(nfa(), list(binary())) -> nfa().
declare_states(Nfa, Names) ->
case Names of
[] ->
Nfa;
[Name | Rest] ->
declare_states(add_state(Nfa, Name), Rest)
end.
-file("src/rexen/nfa/machine.gleam", 49).
-spec add_transition(nfa(), binary(), binary(), rexen@nfa@state:matcher()) -> nfa().
add_transition(Nfa, From, To, Matcher) ->
_assert_subject = gleam_stdlib:map_get(erlang:element(2, Nfa), From),
{ok, From_state} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"rexen/nfa/machine"/utf8>>,
function => <<"add_transition"/utf8>>,
line => 55})
end,
_assert_subject@1 = gleam_stdlib:map_get(erlang:element(2, Nfa), To),
{ok, _} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@1,
module => <<"rexen/nfa/machine"/utf8>>,
function => <<"add_transition"/utf8>>,
line => 56})
end,
Transitions = rexen@nfa@state:add_transition(
erlang:element(3, From_state),
{Matcher, To}
),
New_state = {state, erlang:element(2, From_state), Transitions},
{nfa,
gleam@dict:insert(erlang:element(2, Nfa), From, New_state),
erlang:element(3, Nfa),
erlang:element(4, Nfa)}.
-file("src/rexen/nfa/machine.gleam", 110).
-spec process_transitions(
nfa(),
list({rexen@nfa@state:matcher(), binary()}),
list(stack_value()),
stack_value(),
binary()
) -> list(stack_value()).
process_transitions(Nfa, Transitions, Stack, Stkv, Char) ->
case Transitions of
[] ->
Stack;
[{Matcher, Name} | Rest] ->
case rexen@nfa@state:matches(Matcher, Char) of
false ->
process_transitions(Nfa, Rest, Stack, Stkv, Char);
true ->
Index = case rexen@nfa@state:is_epsilon(Matcher) of
true ->
erlang:element(2, Stkv);
false ->
erlang:element(2, Stkv) + 1
end,
_assert_subject = gleam_stdlib:map_get(
erlang:element(2, Nfa),
Name
),
{ok, To} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"rexen/nfa/machine"/utf8>>,
function => <<"process_transitions"/utf8>>,
line => 129})
end,
New_stack = lists:append(Stack, [{stack_value, Index, To}]),
process_transitions(Nfa, Rest, New_stack, Stkv, Char)
end
end.
-file("src/rexen/nfa/machine.gleam", 78).
-spec evaluate_loop(nfa(), binary(), list(stack_value())) -> boolean().
evaluate_loop(Nfa, Input, Stack) ->
case Stack of
[] ->
false;
[Value | Rest] ->
case gleam@list:contains(
erlang:element(4, Nfa),
erlang:element(2, erlang:element(3, Value))
) of
true ->
case string:length(Input) =:= erlang:element(2, Value) of
true ->
true;
false ->
Char = gleam@string:slice(
Input,
erlang:element(2, Value),
1
),
New_stack = process_transitions(
Nfa,
erlang:element(3, erlang:element(3, Value)),
Rest,
Value,
Char
),
evaluate_loop(Nfa, Input, New_stack)
end;
false ->
Char@1 = gleam@string:slice(
Input,
erlang:element(2, Value),
1
),
New_stack@1 = process_transitions(
Nfa,
erlang:element(3, erlang:element(3, Value)),
Rest,
Value,
Char@1
),
evaluate_loop(Nfa, Input, New_stack@1)
end
end.
-file("src/rexen/nfa/machine.gleam", 72).
-spec evaluate(nfa(), binary()) -> boolean().
evaluate(Nfa, Input) ->
_assert_subject = gleam_stdlib:map_get(
erlang:element(2, Nfa),
erlang:element(3, Nfa)
),
{ok, S} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"rexen/nfa/machine"/utf8>>,
function => <<"evaluate"/utf8>>,
line => 73})
end,
Stack = [{stack_value, 0, S}],
evaluate_loop(Nfa, Input, Stack).