#lang scheme
(require "util.ss")
(provide annotation
annotation-start-char
annotation-end-char
annot-type
compile-and-get-dtypes
format-annot)
(define (compile-and-get-dtypes parent fname settings)
(with-handlers
([exn:fail? (λ (exn) (ocaml:not-installed) #f)])
(define filename
(path->string
(if (eq? (system-type 'os) 'windows)
(ocaml:strip-crlf fname)
fname)))
(define executable-name (path-replace-suffix fname ".exe"))
(define lsm (ocaml:lang-settings-modules settings))
(define annot-filename (path->string (path-replace-suffix filename ".annot")))
(define _ (when (file-exists? annot-filename) (delete-file annot-filename) (sleep 0.01)))
(define lsi
(let
([path-list
(filter
(λ (x) (not (regexp-match "^[ \t\n]*$" x)))
(regexp-split ";" (ocaml:lang-settings-includes settings)))])
(apply string-append (map (λ (x) (format "-I ~a " x)) path-list))))
(define args
(filter
(λ (x) (not (equal? x "")))
(list
#f #f #f
(ocaml:lang-settings-compiler settings)
"-o" (path->string executable-name)
"-dtypes"
lsm
lsi
"-impl" filename)))
(define-values (proc in out err)
(apply subprocess args))
(define annot-table (make-hash))
(subprocess-wait proc)
(call-with-input-file annot-filename (λ (port) (get-annotations annot-table port)))))
(define-struct annotation (start-char end-char type))
(define (get-one-annotation port)
(define begin-char
(begin
(read port) (read port) (read port)))
(define end-char
(begin
(read port) (read port) (read port) (read port)))
(define raw-type-desc
(begin
(read port) (regexp-replace* (regexp "[|]['][|] ") (format "~v" (read port)) "'")))
(define type-desc-length (string-length raw-type-desc))
(define type-desc (substring raw-type-desc 1 (- type-desc-length 1)))
(make-annotation begin-char end-char type-desc))
(define readtable-no-quote
(make-readtable
#f
#\' 'non-terminating-macro (λ (a b c d e f) #'\')
#\` 'non-terminating-macro (λ (a b c d e f) #'\`)
#\, 'non-terminating-macro (λ (a b c d e f) #'\,)))
(define (get-annotations annot-table port)
(define (loop)
(define string-test (read port)) (when (not (eof-object? string-test))
(let ([one-annot (get-one-annotation port)])
(insert-one-annotation annot-table one-annot)
(loop))))
(current-readtable readtable-no-quote)
(loop)
(current-readtable #f)
annot-table)
(define (insert-one-annotation annot-table annot)
(define (insert-one-pos pos)
(define ht-status (hash-ref annot-table pos (λ () #f)))
(unless ht-status
(hash-set! annot-table pos annot)))
(define (loop start end)
(unless (>= start end)
(insert-one-pos start)
(loop (add1 start) end)))
(loop (annotation-start-char annot) (annotation-end-char annot)))
(define (get-first-and-last-end-chars annot-table)
(define end-char-list
(hash-map
annot-table
(λ (key v) key)))
(values
(apply min end-char-list)
(apply max end-char-list)))
(define (annot-type annot)
(format "~a" (annotation-type annot)))
(define (format-annot annot)
(format "~a -> ~a \"~a\""
(annotation-start-char annot)
(annotation-end-char annot)
(annotation-type annot)))