Skip to content

Commit 664674a

Browse files
committed
added the zero or one functionality using the QMark operator
1 parent b7c4e62 commit 664674a

1 file changed

Lines changed: 34 additions & 4 deletions

File tree

src/rexen/nfa/thompson.gleam

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import gleam/dict
22
import gleam/int
33
import gleam/list
44
import gleam/string
5-
import rexen/grammar.{type Token, Asterix, Bar, Dot, Letter, Operator}
5+
import rexen/grammar.{type Token, Asterix, Bar, Dot, Letter, Operator, QMark}
66
import rexen/nfa/machine
77
import rexen/nfa/state
88

@@ -37,7 +37,7 @@ fn to_nfa_loop(
3737
Operator(variant) -> {
3838
case variant {
3939
Asterix(_) -> {
40-
case one_step_stack(stack) {
40+
case one_step_stack(stack, closure) {
4141
Error(err) -> {
4242
Error(
4343
err
@@ -47,6 +47,17 @@ fn to_nfa_loop(
4747
Ok(new_stack) -> to_nfa_loop(rest, new_stack)
4848
}
4949
}
50+
QMark(_) -> {
51+
case one_step_stack(stack, zero_or_one) {
52+
Error(err) -> {
53+
Error(
54+
err <> ". Hint: zero or more (QMark) requires 1 preceding
55+
character (ie. a?)",
56+
)
57+
}
58+
Ok(new_stack) -> to_nfa_loop(rest, new_stack)
59+
}
60+
}
5061
Dot(_) -> {
5162
case two_step_stack(stack, concat) {
5263
Error(err) -> {
@@ -78,11 +89,15 @@ fn to_nfa_loop(
7889
}
7990
}
8091

81-
fn one_step_stack(stack: List(machine.NFA)) -> Result(List(machine.NFA), String) {
92+
// fn zero_or_more(a: machine.NFA) -> machine.NFA {
93+
fn one_step_stack(
94+
stack: List(machine.NFA),
95+
func: fn(machine.NFA) -> machine.NFA,
96+
) -> Result(List(machine.NFA), String) {
8297
case stack {
8398
[] -> Error("Expected 1 nfa on the stack, got none")
8499
[val, ..rest] -> {
85-
let nfa = closure(val)
100+
let nfa = func(val)
86101
Ok(list.prepend(rest, nfa))
87102
}
88103
}
@@ -118,6 +133,21 @@ fn single_char(char: String) -> machine.NFA {
118133
|> machine.add_transition("q0", "q1", state.CharacterMatcher(char))
119134
}
120135

136+
fn zero_or_one(a: machine.NFA) -> machine.NFA {
137+
let last_state = "q" <> int.to_string(dict.size(a.states) + 1)
138+
let subject = update_nfa_labels(a, 1)
139+
machine.declare_states(subject, ["q0", last_state])
140+
|> transition_ending_states(
141+
subject.ending_states,
142+
last_state,
143+
state.EpsilonMatcher,
144+
)
145+
|> machine.add_transition("q0", subject.initial_state, state.EpsilonMatcher)
146+
|> machine.add_transition("q0", last_state, state.EpsilonMatcher)
147+
|> machine.set_initial_state("q0")
148+
|> machine.set_ending_states([last_state])
149+
}
150+
121151
fn closure(a: machine.NFA) -> machine.NFA {
122152
let last_state = "q" <> int.to_string(dict.size(a.states) + 1)
123153
let subject = update_nfa_labels(a, 1)

0 commit comments

Comments
 (0)