test: enable all tests, use expect count, add tinycc tests.
[mes.git] / build-aux / diff.scm
1 #! /bin/sh
2 # -*-scheme-*-
3 exec ${GUILE-guile} -L $(dirname 0) -e '(diff)' -s "$0" "$@"
4 !#
5
6 ;;; Mes --- Maxwell Equations of Software
7 ;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
8 ;;;
9 ;;; mes-snarf.scm: This file is part of Mes.
10 ;;;
11 ;;; Mes is free software; you can redistribute it and/or modify it
12 ;;; under the terms of the GNU General Public License as published by
13 ;;; the Free Software Foundation; either version 3 of the License, or (at
14 ;;; your option) any later version.
15 ;;;
16 ;;; Mes is distributed in the hope that it will be useful, but
17 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;;; GNU General Public License for more details.
20 ;;;
21 ;;; You should have received a copy of the GNU General Public License
22 ;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
23
24 (define-module (diff)
25   #:use-module (srfi srfi-1)
26   #:use-module (srfi srfi-9)
27   #:use-module (ice-9 rdelim)
28   #:export (main))
29
30 (cond-expand
31  (mes
32   (define %scheme "mes"))
33  (guile-2
34   (define %scheme "guile")
35   (define-macro (mes-use-module . rest) #t))
36  (guile
37   (use-modules (ice-9 syncase))
38   (define %scheme "guile")
39   (define-macro (mes-use-module . rest) #t)))
40
41 (mes-use-module (mes guile))
42
43 (format (current-error-port) "diff[~a]...\n" %scheme)
44
45 (define (plus a)
46   (string-append "+" a))
47 (define (minus a)
48   (string-append "-" a))
49 (define (keep a)
50   (string-append " " a))
51
52 (define-record-type <hunk> (make-hunk context after removed added)
53   hunk?
54   (context hunk.context)
55   (after hunk.after)
56   (removed hunk.removed)
57   (added hunk.added))
58
59 (define (hunk->lines o)
60   (append `(,(format #f "@@ -~a,~a +~a,~a" (length (hunk.removed o)) (+ 3 (car (hunk.context o))) (length (hunk.added o)) (+ 3 (cadr (hunk.context o))))
61             ,@(map keep (filter identity (cddr (hunk.context o)))))
62           (map minus (hunk.removed o))
63           (map plus (hunk.added o))
64           (map keep (hunk.after o))))
65
66 (define (safe-list-head lst n)
67   (list-head lst (min n (length lst))))
68
69 ;; naive diff
70 (define (diff a b)
71   (let ((a-lines (string-split (with-input-from-file a read-string) #\newline))
72         (b-lines (string-split (with-input-from-file b read-string) #\newline)))
73     (let loop ((context '(1 1 #f #f #f)) (a-lines a-lines) (b-lines b-lines))
74       ;;(format (current-error-port) "loop context=~s\n" context)
75       (cond ((and (null? a-lines) (null? b-lines)) '())
76             ((null? a-lines)
77              (list (make-hunk context (safe-list-head a-lines 3) '() b-lines)))
78             ((null? b-lines)
79              (list (make-hunk context (safe-list-head a-lines 3) a-lines '())))
80             ((equal? (car a-lines) (car b-lines))
81              (loop `(,(1+ (car context))
82                      ,(1+ (cadr context))
83                      ,@(cdddr context)
84                      ,(car a-lines))
85                    (cdr a-lines) (cdr b-lines)))
86             (else
87              (cond ((and (pair? (cdr b-lines)) (equal? (car a-lines) (cadr b-lines)))
88                     (cons (make-hunk context (safe-list-head a-lines 3) '() (list (car b-lines)))
89                           (loop `(,(+ 1 (car context))
90                                   ,(+ 2 (cadr context))
91                                   ,@(cdddr context)
92                                   ,(car a-lines))
93                                 (cdr a-lines) (cddr b-lines))))
94                    ((and (pair? (cdr a-lines)) (equal? (cadr a-lines) (car b-lines)))
95                     (cons (make-hunk context (safe-list-head a-lines 3) (list (car a-lines)) '())
96                           (loop `(,(+ 2 (car context))
97                                   ,(+ 1 (cadr context))
98                                   ,@(cddddr context)
99                                   ,(car a-lines)
100                                   ,(cadr a-lines))
101                                 (cddr a-lines) (cdr b-lines))))
102                    (else (cons (make-hunk context (safe-list-head a-lines 3) (list (car a-lines)) (list (car b-lines)))
103                                (loop `(,(1+ (car context))
104                                        ,(1+ (cadr context))
105                                        ,@(cdddr context)
106                                        ,(car a-lines))
107                                      (cdr a-lines) (cdr b-lines))))))))))
108
109 (define (main args)
110   (let* ((files (cdr args))
111          (files (if (equal? (car files) "-u") (cdr files) files))
112          (hunks (apply diff (list-head files 2))))
113     (when (pair? hunks)
114       (display (string-join (append-map hunk->lines hunks) "\n"))
115       (newline)
116       (exit 1))))