#lang scheme/base
(require srfi/13/string
scheme/list
"token.ss")
(provide (struct-out token)
cursor? cursor-advance cursor-rewind cursor-current cursor-position
(rename-out [build-cursor make-cursor]))
(define-struct cursor (max-backtrack history future position)
#:property
prop:custom-write
(lambda (c port write?)
(let ([history (cursor-history c)]
[max-backtrack (cursor-max-backtrack c)])
(fprintf port "#<cursor:~a:(~a)>"
(position-line (cursor-position c))
(string-join
(append (map (lambda (token)
(format "~v" (token-type token)))
(reverse
(if max-backtrack
(take history (min (length history) max-backtrack))
history)))
'(".")
(map (lambda (t)
(format "~v" (token-type t)))
(cursor-future c)))
" "
'infix)))))
(define (cursor-advance c get-next)
(let* ([max-backtrack (cursor-max-backtrack c)]
[history (cursor-history c)]
[future (cursor-future c)]
[position (cursor-position c)]
[next (if (null? future)
(get-next)
(car future))])
(make-cursor max-backtrack
(cons next history)
(if (null? future) null (cdr future))
(region-end (token-location next)))))
(define (length-without-newlines ls)
(cond
[(null? ls) 0]
[(eq? (token-type (car ls)) 'NEWLINE)
(length-without-newlines (cdr ls))]
[else (add1 (length-without-newlines (cdr ls)))]))
(define (cursor-rewind c)
(let ([max-backtrack (cursor-max-backtrack c)]
[history (cursor-history c)]
[future (cursor-future c)]
[position (cursor-position c)])
(when (null? history)
(error 'cursor-rewind "cannot rewind initial cursor"))
(when (= (length-without-newlines future) max-backtrack)
(error 'cursor-rewind "exceeded backtracking limit"))
(let* ([last (car history)]
[newlines (if (eq? (token-type last) 'NEWLINE)
(token-contents last)
0)])
(make-cursor max-backtrack
(cdr history)
(cons last future)
(region-start (token-location last))))))
(define (cursor-current c)
(let ([history (cursor-history c)])
(and (pair? history) (car history))))
(define (build-cursor max-backtrack)
(make-cursor max-backtrack null null (make-position 1 1 0)))