Packages
text_stemmer
0.1.0
Pre-compiled Snowball stemmers for Elixir. Ships 36 stemming algorithms covering a wide range of natural languages, accessible through a single `Text.Stemmer.stem/2` entry point.
Current section
Files
Jump to
Current section
Files
lib/text/stemmer/stemmers/finnish.ex
# Generated by Snowball.Generator — do not edit by hand.
defmodule Text.Stemmer.Stemmers.Finnish do
@moduledoc """
Snowball stemmer for finnish.
Generated from the canonical Snowball algorithm source.
"""
alias Snowball.Runtime
alias Snowball.Grouping
# Groupings
@g_AEI Grouping.from_string("aäei")
@g_C Grouping.from_string("bcdfghjklmnpqrstvwxz")
@g_V1 Grouping.from_string("aeiouyäö")
@g_V2 Grouping.from_string("aeiouäö")
@g_particle_end Grouping.from_string("aeiouyäönt")
# Among tables
@a_0 [
{"mma", -1, 1, nil},
{"imma", 0, -1, nil}
]
@a_1 [
{"i", -1, -1, nil},
{"j", -1, -1, nil}
]
@a_2 [
{"eja", -1, -1, nil},
{"mma", -1, 1, nil},
{"imma", 1, -1, nil},
{"mpa", -1, 1, nil},
{"impa", 3, -1, nil},
{"mmi", -1, 1, nil},
{"immi", 5, -1, nil},
{"mpi", -1, 1, nil},
{"impi", 7, -1, nil},
{"ejä", -1, -1, nil},
{"mmä", -1, 1, nil},
{"immä", 10, -1, nil},
{"mpä", -1, 1, nil},
{"impä", 12, -1, nil}
]
defp a_3 do
[
{"a", -1, 8, nil},
{"lla", 0, -1, nil},
{"na", 0, -1, nil},
{"ssa", 0, -1, nil},
{"ta", 0, -1, nil},
{"lta", 4, -1, nil},
{"sta", 4, -1, nil},
{"tta", 4, 9, nil},
{"lle", -1, -1, nil},
{"ine", -1, -1, nil},
{"ksi", -1, -1, nil},
{"n", -1, 7, nil},
{"han", 11, 1, nil},
{"den", 11, -1, fn state -> case r_VI(state) do {:ok, s} -> s; _ -> :fail end end},
{"seen", 11, -1, fn state -> case r_LONG(state) do {:ok, s} -> s; _ -> :fail end end},
{"hen", 11, 2, nil},
{"tten", 11, -1, fn state -> case r_VI(state) do {:ok, s} -> s; _ -> :fail end end},
{"hin", 11, 3, nil},
{"siin", 11, -1, fn state -> case r_VI(state) do {:ok, s} -> s; _ -> :fail end end},
{"hon", 11, 4, nil},
{"hän", 11, 5, nil},
{"hön", 11, 6, nil},
{"ä", -1, 8, nil},
{"llä", 22, -1, nil},
{"nä", 22, -1, nil},
{"ssä", 22, -1, nil},
{"tä", 22, -1, nil},
{"ltä", 26, -1, nil},
{"stä", 26, -1, nil},
{"ttä", 26, 9, nil}
]
end
@a_4 [
{"aa", -1, -1, nil},
{"ee", -1, -1, nil},
{"ii", -1, -1, nil},
{"oo", -1, -1, nil},
{"uu", -1, -1, nil},
{"ää", -1, -1, nil},
{"öö", -1, -1, nil}
]
@a_5 [
{"lla", -1, -1, nil},
{"na", -1, -1, nil},
{"ssa", -1, -1, nil},
{"ta", -1, -1, nil},
{"lta", 3, -1, nil},
{"sta", 3, -1, nil}
]
@a_6 [
{"llä", -1, -1, nil},
{"nä", -1, -1, nil},
{"ssä", -1, -1, nil},
{"tä", -1, -1, nil},
{"ltä", 3, -1, nil},
{"stä", 3, -1, nil}
]
@a_7 [
{"lle", -1, -1, nil},
{"ine", -1, -1, nil}
]
@a_8 [
{"nsa", -1, 3, nil},
{"mme", -1, 3, nil},
{"nne", -1, 3, nil},
{"ni", -1, 2, nil},
{"si", -1, 1, nil},
{"an", -1, 4, nil},
{"en", -1, 6, nil},
{"än", -1, 5, nil},
{"nsä", -1, 3, nil}
]
@a_9 [
{"pa", -1, 1, nil},
{"sti", -1, 2, nil},
{"kaan", -1, 1, nil},
{"han", -1, 1, nil},
{"kin", -1, 1, nil},
{"hän", -1, 1, nil},
{"kään", -1, 1, nil},
{"ko", -1, 1, nil},
{"pä", -1, 1, nil},
{"kö", -1, 1, nil}
]
@doc """
Stem a word.
### Arguments
* `word` is a UTF-8 binary.
### Returns
* The stemmed UTF-8 binary.
"""
@spec stem(binary()) :: binary()
def stem(word) when is_binary(word) do
state = Runtime.new(word) |> init_vars()
state = run_stem(state)
Runtime.assign_to(state)
end
defp init_vars(state), do: %{state | vars: %{p1: 0, p2: 0, ending_removed: false, x: ""}}
defp run_stem(%Runtime{} = state) do
{_, state} = r_stem(state)
state
end
# Snowball runtime helpers.
defp snowball_do_f(state, fun) do
saved_c = state.cursor
{_, s} = fun.(state)
%{s | cursor: saved_c}
end
defp snowball_do_b(state, fun) do
rel = state.limit - state.cursor
{_, s} = fun.(state)
%{s | cursor: s.limit - rel}
end
defp snowball_test_b(state, fun) do
rel = state.limit - state.cursor
case fun.(state) do
{:ok, s} -> {:ok, %{s | cursor: s.limit - rel}}
{:fail, s} -> {:fail, %{s | cursor: s.limit - rel}}
end
end
defp snowball_try(state, fun) do
rel = state.limit - state.cursor
case fun.(state) do
{:ok, s} -> s
{:fail, s} -> %{s | cursor: s.limit - rel}
end
end
defp snowball_or(state, fun1, fun2) do
rel = state.limit - state.cursor
case fun1.(state) do
{:ok, s} -> {:ok, s}
{:fail, s} -> fun2.(%{s | cursor: s.limit - rel})
end
end
defp lift(state, :fail), do: {:fail, state}
defp lift(_state, %Runtime{} = s), do: {:ok, s}
defp next_codepoint(%Runtime{cursor: c, limit: lim, current: cur} = state) do
case Runtime.codepoint_at(cur, c, lim) do
{_cp, size} -> {:ok, %{state | cursor: c + size}}
:error -> {:fail, state}
end
end
defp next_codepoint_b(%Runtime{cursor: c, limit_backward: lb, current: cur} = state) do
case Runtime.codepoint_before(cur, c, lb) do
{_cp, size} -> {:ok, %{state | cursor: c - size}}
:error -> {:fail, state}
end
end
defp r_tidy(%Runtime{} = state) do
case (fn state ->
(fn ->
case (fn state ->
(fn ->
target = state.vars[:p1]
if target < state.limit_backward or target > state.limit do
{:fail, state}
else
{:ok, %{state | cursor: target}}
end
end).()
end).(state) do
{:fail, _} -> {:fail, state}
{:ok, limit_state} ->
old_lb = state.limit_backward
state = %{state | limit_backward: limit_state.cursor}
case (fn state ->
case (fn state ->
{:ok, snowball_do_b(state, fn state ->
case (fn state ->
snowball_test_b(state, fn state ->
r_LONG(state)
end)
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, %{state | ket: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
next_codepoint_b(state)
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, %{state | bra: state.cursor}}
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
end
r -> r
end
end
r -> r
end
end)}
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, snowball_do_b(state, fn state ->
case (fn state ->
{:ok, %{state | ket: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
lift(state, Runtime.in_grouping_b(state, @g_AEI))
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, %{state | bra: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
lift(state, Runtime.in_grouping_b(state, @g_C))
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
end
r -> r
end
end
end)}
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, snowball_do_b(state, fn state ->
case (fn state ->
{:ok, %{state | ket: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
lift(state, Runtime.eq_s_b(state, "j"))
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, %{state | bra: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
snowball_or(state,
fn state ->
lift(state, Runtime.eq_s_b(state, "o"))
end,
fn state ->
lift(state, Runtime.eq_s_b(state, "u"))
end)
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
end
r -> r
end
end
end)}
end).(state) do
{:ok, state} ->
{:ok, snowball_do_b(state, fn state ->
case (fn state ->
{:ok, %{state | ket: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
lift(state, Runtime.eq_s_b(state, "o"))
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, %{state | bra: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
lift(state, Runtime.eq_s_b(state, "j"))
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
end
r -> r
end
end
end)}
end
end
end
end).(state) do
{:ok, s} -> {:ok, %{s | limit_backward: old_lb}}
end
end
end).()
end).(state) do
{:ok, state} ->
case (fn state ->
lift(state, Runtime.go_in_grouping_b(state, @g_V1))
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, %{state | ket: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
lift(state, Runtime.in_grouping_b(state, @g_C))
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, %{state | bra: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, put_in(state.vars[:x], Runtime.slice_to(state))}
end).(state) do
{:ok, state} ->
case (fn state ->
lift(state, Runtime.eq_s_b(state, state.vars[:x]))
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
end
end
r -> r
end
end
r -> r
end
r -> r
end
end
defp r_t_plural(%Runtime{} = state) do
case (fn state ->
(fn ->
case (fn state ->
(fn ->
target = state.vars[:p1]
if target < state.limit_backward or target > state.limit do
{:fail, state}
else
{:ok, %{state | cursor: target}}
end
end).()
end).(state) do
{:fail, _} -> {:fail, state}
{:ok, limit_state} ->
old_lb = state.limit_backward
state = %{state | limit_backward: limit_state.cursor}
case (fn state ->
case (fn state ->
{:ok, %{state | ket: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
lift(state, Runtime.eq_s_b(state, "t"))
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, %{state | bra: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
snowball_test_b(state, fn state ->
lift(state, Runtime.in_grouping_b(state, @g_V1))
end)
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
end
r -> r
end
end
end).(state) do
{:ok, s} -> {:ok, %{s | limit_backward: old_lb}}
{:fail, s} -> {:fail, %{s | limit_backward: old_lb}}
end
end
end).()
end).(state) do
{:ok, state} ->
case (fn state ->
(fn ->
old_limit = state.limit_backward
case (fn state ->
(fn ->
target = state.vars[:p2]
if target < state.limit_backward or target > state.limit do
{:fail, state}
else
{:ok, %{state | cursor: target}}
end
end).()
end).(state) do
{:fail, _} -> {:fail, state}
{:ok, limit_state} ->
state = %{state | ket: state.cursor, limit_backward: limit_state.cursor}
case Runtime.find_among_b(state, @a_0) do
:fail -> {:fail, %{state | limit_backward: old_limit}}
{%Runtime{} = s, result} ->
state = %{s | bra: s.cursor, limit_backward: old_limit}
case result do
1 ->
(fn state ->
saved_c = state.cursor
case (fn state ->
lift(state, Runtime.eq_s_b(state, "po"))
end).(state) do
{:ok, s} -> {:fail, %{s | cursor: saved_c}}
{:fail, s} -> {:ok, %{s | cursor: saved_c}}
end
end).(state)
_ -> {:ok, state}
end
end
end
end).()
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
r -> r
end
end
defp r_i_plural(%Runtime{} = state) do
case (fn state ->
(fn ->
old_limit = state.limit_backward
case (fn state ->
(fn ->
target = state.vars[:p1]
if target < state.limit_backward or target > state.limit do
{:fail, state}
else
{:ok, %{state | cursor: target}}
end
end).()
end).(state) do
{:fail, _} -> {:fail, state}
{:ok, limit_state} ->
state = %{state | ket: state.cursor, limit_backward: limit_state.cursor}
case Runtime.find_among_b(state, @a_1) do
:fail -> {:fail, %{state | limit_backward: old_limit}}
{%Runtime{} = s, _result} ->
state = %{s | bra: s.cursor, limit_backward: old_limit}
{:ok, state}
end
end
end).()
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
end
defp r_other_endings(%Runtime{} = state) do
case (fn state ->
(fn ->
old_limit = state.limit_backward
case (fn state ->
(fn ->
target = state.vars[:p2]
if target < state.limit_backward or target > state.limit do
{:fail, state}
else
{:ok, %{state | cursor: target}}
end
end).()
end).(state) do
{:fail, _} -> {:fail, state}
{:ok, limit_state} ->
state = %{state | ket: state.cursor, limit_backward: limit_state.cursor}
case Runtime.find_among_b(state, @a_2) do
:fail -> {:fail, %{state | limit_backward: old_limit}}
{%Runtime{} = s, result} ->
state = %{s | bra: s.cursor, limit_backward: old_limit}
case result do
1 ->
(fn state ->
saved_c = state.cursor
case (fn state ->
lift(state, Runtime.eq_s_b(state, "po"))
end).(state) do
{:ok, s} -> {:fail, %{s | cursor: saved_c}}
{:fail, s} -> {:ok, %{s | cursor: saved_c}}
end
end).(state)
_ -> {:ok, state}
end
end
end
end).()
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
end
defp r_case_ending(%Runtime{} = state) do
case (fn state ->
(fn ->
old_limit = state.limit_backward
case (fn state ->
(fn ->
target = state.vars[:p1]
if target < state.limit_backward or target > state.limit do
{:fail, state}
else
{:ok, %{state | cursor: target}}
end
end).()
end).(state) do
{:fail, _} -> {:fail, state}
{:ok, limit_state} ->
state = %{state | ket: state.cursor, limit_backward: limit_state.cursor}
case Runtime.find_among_b(state, a_3()) do
:fail -> {:fail, %{state | limit_backward: old_limit}}
{%Runtime{} = s, result} ->
state = %{s | bra: s.cursor, limit_backward: old_limit}
case result do
1 ->
lift(state, Runtime.eq_s_b(state, "a"))
2 ->
lift(state, Runtime.eq_s_b(state, "e"))
3 ->
lift(state, Runtime.eq_s_b(state, "i"))
4 ->
lift(state, Runtime.eq_s_b(state, "o"))
5 ->
lift(state, Runtime.eq_s_b(state, "ä"))
6 ->
lift(state, Runtime.eq_s_b(state, "ö"))
7 ->
{:ok, snowball_try(state, fn state ->
case (fn state ->
case (fn state ->
snowball_test_b(state, fn state ->
snowball_or(state,
fn state ->
r_LONG(state)
end,
fn state ->
lift(state, Runtime.eq_s_b(state, "ie"))
end)
end)
end).(state) do
{:ok, state} ->
next_codepoint_b(state)
r -> r
end
end).(state) do
{:ok, state} ->
{:ok, %{state | bra: state.cursor}}
r -> r
end
end)}
8 ->
case (fn state ->
lift(state, Runtime.in_grouping_b(state, @g_V1))
end).(state) do
{:ok, state} ->
lift(state, Runtime.in_grouping_b(state, @g_C))
r -> r
end
9 ->
lift(state, Runtime.eq_s_b(state, "e"))
_ -> {:ok, state}
end
end
end
end).()
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, Runtime.slice_del(state)}
end).(state) do
{:ok, state} ->
{:ok, put_in(state.vars[:ending_removed], true)}
end
r -> r
end
end
defp r_VI(%Runtime{} = state) do
case (fn state ->
lift(state, Runtime.eq_s_b(state, "i"))
end).(state) do
{:ok, state} ->
lift(state, Runtime.in_grouping_b(state, @g_V2))
r -> r
end
end
defp r_LONG(%Runtime{} = state) do
(fn ->
case Runtime.find_among_b(state, @a_4) do
:fail -> {:fail, state}
{%Runtime{} = s, _} -> {:ok, s}
end
end).()
end
defp r_possessive(%Runtime{} = state) do
(fn ->
old_limit = state.limit_backward
case (fn state ->
(fn ->
target = state.vars[:p1]
if target < state.limit_backward or target > state.limit do
{:fail, state}
else
{:ok, %{state | cursor: target}}
end
end).()
end).(state) do
{:fail, _} -> {:fail, state}
{:ok, limit_state} ->
state = %{state | ket: state.cursor, limit_backward: limit_state.cursor}
case Runtime.find_among_b(state, @a_8) do
:fail -> {:fail, %{state | limit_backward: old_limit}}
{%Runtime{} = s, result} ->
state = %{s | bra: s.cursor, limit_backward: old_limit}
case result do
1 ->
case (fn state ->
(fn state ->
saved_c = state.cursor
case (fn state ->
lift(state, Runtime.eq_s_b(state, "k"))
end).(state) do
{:ok, s} -> {:fail, %{s | cursor: saved_c}}
{:fail, s} -> {:ok, %{s | cursor: saved_c}}
end
end).(state)
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
2 ->
case (fn state ->
{:ok, Runtime.slice_del(state)}
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, %{state | ket: state.cursor}}
end).(state) do
{:ok, state} ->
case (fn state ->
lift(state, Runtime.eq_s_b(state, "kse"))
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, %{state | bra: state.cursor}}
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_from(state, "ksi")}
end
r -> r
end
end
end
3 ->
{:ok, Runtime.slice_del(state)}
4 ->
case (fn state ->
(fn ->
case Runtime.find_among_b(state, @a_5) do
:fail -> {:fail, state}
{%Runtime{} = s, _} -> {:ok, s}
end
end).()
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
5 ->
case (fn state ->
(fn ->
case Runtime.find_among_b(state, @a_6) do
:fail -> {:fail, state}
{%Runtime{} = s, _} -> {:ok, s}
end
end).()
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
6 ->
case (fn state ->
(fn ->
case Runtime.find_among_b(state, @a_7) do
:fail -> {:fail, state}
{%Runtime{} = s, _} -> {:ok, s}
end
end).()
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
_ -> {:ok, state}
end
end
end
end).()
end
defp r_particle_etc(%Runtime{} = state) do
case (fn state ->
(fn ->
old_limit = state.limit_backward
case (fn state ->
(fn ->
target = state.vars[:p1]
if target < state.limit_backward or target > state.limit do
{:fail, state}
else
{:ok, %{state | cursor: target}}
end
end).()
end).(state) do
{:fail, _} -> {:fail, state}
{:ok, limit_state} ->
state = %{state | ket: state.cursor, limit_backward: limit_state.cursor}
case Runtime.find_among_b(state, @a_9) do
:fail -> {:fail, %{state | limit_backward: old_limit}}
{%Runtime{} = s, result} ->
state = %{s | bra: s.cursor, limit_backward: old_limit}
case result do
1 ->
lift(state, Runtime.in_grouping_b(state, @g_particle_end))
2 ->
r_R2(state)
_ -> {:ok, state}
end
end
end
end).()
end).(state) do
{:ok, state} ->
{:ok, Runtime.slice_del(state)}
r -> r
end
end
defp r_R2(%Runtime{} = state) do
if state.vars[:p2] <= state.cursor, do: {:ok, state}, else: {:fail, state}
end
defp r_mark_regions(%Runtime{} = state) do
case (fn state ->
{:ok, put_in(state.vars[:p1], state.limit)}
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, put_in(state.vars[:p2], state.limit)}
end).(state) do
{:ok, state} ->
case (fn state ->
case Runtime.go_out_grouping(state, @g_V1) do
:fail -> {:fail, state}
%Runtime{} = s -> next_codepoint(s)
end
end).(state) do
{:ok, state} ->
case (fn state ->
case Runtime.go_in_grouping(state, @g_V1) do
:fail -> {:fail, state}
%Runtime{} = s -> next_codepoint(s)
end
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, put_in(state.vars[:p1], state.cursor)}
end).(state) do
{:ok, state} ->
case (fn state ->
case Runtime.go_out_grouping(state, @g_V1) do
:fail -> {:fail, state}
%Runtime{} = s -> next_codepoint(s)
end
end).(state) do
{:ok, state} ->
case (fn state ->
case Runtime.go_in_grouping(state, @g_V1) do
:fail -> {:fail, state}
%Runtime{} = s -> next_codepoint(s)
end
end).(state) do
{:ok, state} ->
{:ok, put_in(state.vars[:p2], state.cursor)}
r -> r
end
r -> r
end
end
r -> r
end
r -> r
end
end
end
end
defp r_stem(%Runtime{} = state) do
case (fn state ->
{:ok, snowball_do_f(state, fn state ->
r_mark_regions(state)
end)}
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, put_in(state.vars[:ending_removed], false)}
end).(state) do
{:ok, state} ->
(fn state ->
old_cursor = state.cursor
old_lb = state.limit_backward
state = %{state | cursor: state.limit, limit_backward: old_cursor}
{tag, s} = (fn state ->
case (fn state ->
{:ok, snowball_do_b(state, fn state ->
r_particle_etc(state)
end)}
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, snowball_do_b(state, fn state ->
r_possessive(state)
end)}
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, snowball_do_b(state, fn state ->
r_case_ending(state)
end)}
end).(state) do
{:ok, state} ->
case (fn state ->
{:ok, snowball_do_b(state, fn state ->
r_other_endings(state)
end)}
end).(state) do
{:ok, state} ->
case (fn state ->
snowball_or(state,
fn state ->
case (fn state ->
if state.vars[:ending_removed], do: {:ok, state}, else: {:fail, state}
end).(state) do
{:ok, state} ->
{:ok, snowball_do_b(state, fn state ->
r_i_plural(state)
end)}
r -> r
end
end,
fn state ->
{:ok, snowball_do_b(state, fn state ->
r_t_plural(state)
end)}
end)
end).(state) do
{:ok, state} ->
{:ok, snowball_do_b(state, fn state ->
r_tidy(state)
end)}
r -> r
end
end
end
end
end
end).(state)
{tag, %{s | cursor: old_cursor, limit_backward: old_lb}}
end).(state)
end
end
end
end