language/indent.rkt
#lang racket

#|

File: indent.rkt
Author: Bill Turtle (wrturtle)

This file handles indentation checking.

|#

(provide check-indent)
(require "../utilities.rkt")

(define checking-indent? (make-parameter #t))
(provide checking-indent?)

(define SLGC-min-offset 2)

;; Same line, same column (for if, elif, else, etc.)
(define (SLSC l1 c1 l2 c2)
  (or (= l1 l2) (= c1 c2)))

;; Same line, greater column
(define (SLGC l1 c1 l2 c2)
  (or (= l1 l2)
      (>= (- c2 c1) SLGC-min-offset)))

;; Same line, greater than or equal to column
(define (SLGEC l1 c1 l2 c2)
  (or (= l1 l2)
      (<= c1 c2)))

(define-syntax-rule (ms s1 s2)
  (vector (syntax-source s1)
          (syntax-line s1)
          (syntax-column s1)
          (syntax-position s1)
          (- (+ (syntax-span s2) (syntax-position s2)) (syntax-position s1))))

(define (check-indent mode stx1 stx2)
  (if (not (checking-indent?))
      #t
      (let ([l1 (syntax-line stx1)]
            [c1 (syntax-column stx1)]
            [l2 (syntax-line stx2)]
            [c2 (syntax-column stx2)])
        (if (and l1 c1 l2 c2)
            (let ([proc (case mode
                          [(SLSC) SLSC]
                          [(SLGC) SLGC]
                          [(SLGEC) SLGEC]
                          [else #f])])
              (if proc
                  ; only meaningful if they come from the same module
                  (if (and (equal? (syntax-source stx1)
                                   (syntax-source stx2))
                           (syntax-source stx1))
                      (if (proc l1 c1 l2 c2)
                          #t
                          (raise-pyret-error "this code is not well-indented"
                                             (ms stx1 stx2)))
                      #t)
                  (error 'check-indent
                         "invalid mode ~S"
                         mode)))
             #t))))