@@ -2,7 +2,7 @@ import gleam/dict
22import gleam/int
33import gleam/list
44import 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 }
66import rexen/nfa/machine
77import 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+
121151fn 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