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