#lang scheme
(require "../private/regexp.ss")
(define-struct parse-state (final prior) #:prefab)
(define-struct final-block () #:prefab)
(define-struct (prompt-block final-block) (text) #:prefab)
(define-struct (partial-block final-block) (line block) #:prefab)
(define-struct parse-block (text) #:prefab)
(define-struct (text-block parse-block) () #:prefab)
(define-struct (tree-block parse-block) () #:prefab)
(define empty-parse-state
(make-parse-state (make-partial-block "" (make-text-block "")) null))
(define (parse string state)
(match state
[(struct parse-state [(struct partial-block [line block]) blocks])
(parse-partial (string-append line string) block blocks)]))
(define (parse-partial text block blocks)
(match block
[(struct text-block [old-text])
(parse-text text old-text blocks)]
[(struct tree-block [old-text])
(parse-tree text old-text blocks)]))
(define (parse-text new-text old-text complete)
(match new-text
[(pregexp #px"(?s:^(.*?)#<\\\\<0(.*)$)" (list _ pre post))
(parse-tree
post "" (cons (make-text-block (string-append old-text pre)) complete))]
[(pregexp #px"(?s:^(.*\n|)(ACL2 p?!?s?>)$)" (list _ pre post))
(make-parse-state
(make-prompt-block post)
(cons (make-text-block (string-append old-text pre)) complete))]
[(pregexp #px"(?s:^(.*?)([^\n]*)$)" (list _ pre post))
(make-parse-state
(make-partial-block post (make-text-block (string-append old-text pre)))
complete)]))
(define (parse-tree new-text old-text complete)
(match new-text
[(pregexp #px"(?s:^(.*?)#>\\\\>(.*)$)" (list _ pre post))
(parse-text
post "" (cons (make-tree-block (string-append old-text pre)) complete))]
[(pregexp #px"(?s:^(.*?)([^\n]*)$)" (list _ pre post))
(make-parse-state
(make-partial-block post (make-tree-block (string-append old-text pre)))
complete)]))
(define (parse-success? state)
(not (parse-failure? state)))
(define (parse-failure? state)
(ormap block-failure? (parse-state-prior state)))
(define (block-failure? block)
(cond
[(tree-block? block) #f]
[(text-block? block) (line-success? (parse-block-text block))]))
(define (line-success? line)
(regexp-match?
(pregexp
(regexp-or
(regexp-quote "************ ABORTING from raw Lisp ***********")
(regexp-quote "******** FAILED ********")
(regexp-quote "HARD ACL2 ERROR in")
(regexp-quote "ACL2 Error in")))
line))
(define lbracket (regexp-quote "["))
(define rbracket (regexp-quote "]"))
(define prime (regexp-quote "'"))
(define slash (regexp-quote "/"))
(define asterisk (regexp-quote "*"))
(define dot (regexp-quote "."))
(define bar (regexp-quote "|"))
(define start "^")
(define end "$")
(define number "\\d+")
(define space (regexp-star (regexp-quote " ")))
(define dotted-number-regexp
(regexp-sequence number (regexp-star dot number)))
(define forcing-round-regexp
(regexp-sequence lbracket number rbracket))
(define prime-regexp
(regexp-or (regexp-star prime)
(regexp-sequence prime number prime)))
(define subgoal-regexp
(regexp-sequence (regexp-maybe forcing-round-regexp)
(regexp-quote "Subgoal ")
(regexp-maybe asterisk dotted-number-regexp slash)
dotted-number-regexp
prime-regexp))
(define goal-regexp
(regexp-sequence (regexp-quote "Goal") prime-regexp))
(define pushed-goal-regexp
(regexp-sequence asterisk dotted-number-regexp))
(define goal-spec-regexp
(regexp-or goal-regexp subgoal-regexp pushed-goal-regexp))
(define checkpoint-regexp (regexp-maybe (regexp-quote "c")))
(define process-regexp ".*")
(define goal-line-regexp
(regexp-multi
(regexp-sequence #:start start #:end end #:between space
checkpoint-regexp
(regexp-maybe number)
(regexp-star bar space)
(regexp-save goal-spec-regexp)
process-regexp)))
(define (parse-subgoals proof-tree)
(let loop ([index 0])
(match (regexp-match-positions (pregexp goal-line-regexp) proof-tree index)
[#f null]
[(list (cons line-start line-end) (cons name-start name-end))
(cons (list (substring proof-tree name-start name-end)
line-start line-end)
(loop line-end))])))
(define (parse-finished? parse)
(prompt-block? (parse-state-final parse)))
(define (parse-state-blocks parse)
(append
(cond
[(parse-state-final parse) => list]
[else null])
(parse-state-prior parse)))
(define (parse-prompt parse)
(match (parse-state-final parse)
[(struct prompt-block [text]) text]
[_ ""]))
(define (parse-last-proof-tree parse)
(cond
[(findf tree-block? (parse-state-prior parse)) => parse-block-text]
[else ""]))
(define (parse-normal-text parse)
(apply string-append (parse-normal-strings parse)))
(define (parse-normal-strings parse)
(append (prior-normal-strings (parse-state-prior parse))
(final-normal-strings (parse-state-final parse))))
(define (prior-normal-strings priors)
(block-normal-strings (reverse priors)))
(define (block-normal-strings blocks)
(map block-normal-string blocks))
(define (block-normal-string block)
(match block
[(struct text-block [text]) text]
[(struct tree-block [_]) ""]))
(define (final-normal-strings final)
(match final
[(struct prompt-block [prompt]) null]
[(struct partial-block [partial block])
(list (block-normal-string block) partial)]))
(provide/contract
[parse-state? (-> any/c boolean?)]
[parse-block? (-> any/c boolean?)]
[text-block? (-> any/c boolean?)]
[tree-block? (-> any/c boolean?)]
[make-parse-state
(-> final-block? (listof parse-block?) parse-state?)]
[make-text-block (-> string? parse-block?)]
[make-tree-block (-> string? parse-block?)]
[make-partial-block (-> string? parse-block? final-block?)]
[make-prompt-block (-> string? final-block?)]
[parse-state-blocks
(-> parse-state? (listof (or/c parse-block? partial-block?)))]
[parse-block-text (-> parse-block? string?)]
[empty-parse-state parse-state?]
[parse (-> string? parse-state? parse-state?)]
[parse-finished? (-> parse-state? boolean?)]
[parse-success? (-> (and/c parse-state? parse-finished?) boolean?)]
[parse-prompt (-> parse-state? string?)]
[parse-normal-text (-> parse-state? string?)]
[parse-last-proof-tree (-> parse-state? string?)]
[parse-subgoals
(-> string? (listof (list/c string?
exact-nonnegative-integer?
exact-nonnegative-integer?)))])