(module state mzscheme
(require (prefix e: "edges.ss")
(prefix q: "queue.ss")
(lib "plt-match.ss"))
(provide make
goto
fail
output
(rename set-State-output! set-output!)
add-output!
(rename set-State-fail! set-fail!)
extend
extend*
out-labels
out-states
breadth-first)
(define-struct State (depth edges fail output))
(define (make depth)
(make-State depth (e:make 0) (void) (list)))
(define (add-output! state elt)
(match state
[(struct State (depth edges fail output))
(when (not (member elt output))
(set-State-output! state (cons elt output)))]
[else (raise-type-error 'add-output "State" state)]))
(define (out-labels state)
(match state
[(struct State (depth edges fail output))
(e:labels edges)]))
(define (out-states state)
(match state
[(struct State (depth edges fail output))
(e:states edges)]))
(define (goto state label)
(match state
[(struct State (depth edges fail output))
(let ((x (e:get edges label)))
(if x
x
(if (= depth 0) state (void))))]
[else (raise-type-error 'goto "State" state)]))
(define (fail state)
(match state
[(struct State (depth edges fail output))
fail]
[else (raise-type-error 'fail "State" state)]))
(define (output state)
(match state
[(struct State (depth edges fail output))
output]
[else (raise-type-error 'output "State" state)]))
(define (extend state label)
(match state
[(struct State (depth edges fail output))
(let ((new-state (make (+ depth 1))))
(e:put! edges label new-state)
new-state)]
[else (raise-type-error 'goto "State" state)]))
(define (extend* state labels)
(let loop ((n state)
(labels labels))
(if (null? labels)
n
(if (e:get (State-edges n) (car labels))
(loop (goto n (car labels)) (cdr labels))
(loop (extend n (car labels)) (cdr labels))))))
(define (breadth-first f Q)
(let loop ((Q Q))
(if (q:empty? Q)
(void)
(let*-values ([(x Q) (q:remove Q)]
[(Q) (q:insert* Q (out-states x))])
(begin
(f x)
(loop Q))))))
)