userdiff: add support for Scheme

Add a diff driver for Scheme-like languages which recognizes top level
and local `define` forms, whether it is a function definition, binding,
syntax definition or a user-defined `define-xyzzy` form.

Also supports R6RS `library` forms, `module` forms along with class and
struct declarations used in Racket (PLT Scheme).

Alternate "def" syntax such as those in Gerbil Scheme are also
supported, like defstruct, defsyntax and so on.

The rationale for picking `define` forms for the hunk headers is because
it is usually the only significant form for defining the structure of
the program, and it is a common pattern for schemers to have local
function definitions to hide their visibility, so it is not only the top
level `define`'s that are of interest. Schemers also extend the language
with macros to provide their own define forms (for example, something
like a `define-test-suite`) which is also captured in the hunk header.

Since it is common practice to extend syntax with variants of a form
like `module+`, `class*` etc, those have been supported as well.

The word regex is a best-effort attempt to conform to R7RS[1] valid
identifiers, symbols and numbers.

[1] https://small.r7rs.org/attachment/r7rs.pdf (section 2.1)

Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Atharva Raykar 2021-04-08 14:44:43 +05:30 коммит произвёл Junio C Hamano
Родитель 84d06cdc06
Коммит a437390310
18 изменённых файлов: 101 добавлений и 0 удалений

Просмотреть файл

@ -845,6 +845,8 @@ patterns are available:
- `rust` suitable for source code in the Rust language.
- `scheme` suitable for source code in the Scheme language.
- `tex` suitable for source code for LaTeX documents.

Просмотреть файл

@ -48,6 +48,7 @@ diffpatterns="
python
ruby
rust
scheme
tex
custom1
custom2

7
t/t4018/scheme-class Normal file
Просмотреть файл

@ -0,0 +1,7 @@
(define book-class%
(class* () object% RIGHT
(field (pages 5))
(field (ChangeMe 5))
(define/public (letters)
(* pages 500))
(super-new)))

4
t/t4018/scheme-def Normal file
Просмотреть файл

@ -0,0 +1,4 @@
(def (some-func x y z) RIGHT
(let ((a x)
(b y))
(ChangeMe a b)))

Просмотреть файл

@ -0,0 +1,4 @@
(defmethod {print point} RIGHT
(lambda (self)
(with ((point x y) self)
(printf "{ChangeMe x:~a y:~a}~n" x y))))

Просмотреть файл

@ -0,0 +1,7 @@
(define bar-class%
(class object%
(field (info 5))
(define/public (foo) RIGHT
(+ info 42)
(* info ChangeMe))
(super-new)))

Просмотреть файл

@ -0,0 +1,8 @@
(define-syntax define-test-suite RIGHT
(syntax-rules ()
((_ suite-name (name test) ChangeMe ...)
(define suite-name
(let ((tests
`((name . ,test) ...)))
(lambda ()
(run-suite 'suite-name tests)))))))

Просмотреть файл

@ -0,0 +1,4 @@
(define* (some-func x y z) RIGHT
(let ((a x)
(b y))
(ChangeMe a b)))

11
t/t4018/scheme-library Normal file
Просмотреть файл

@ -0,0 +1,11 @@
(library (my-helpers id-stuff) RIGHT
(export find-dup)
(import (ChangeMe))
(define (find-dup l)
(and (pair? l)
(let loop ((rest (cdr l)))
(cond
[(null? rest) (find-dup (cdr l))]
[(bound-identifier=? (car l) (car rest))
(car rest)]
[else (loop (cdr rest))])))))

Просмотреть файл

@ -0,0 +1,4 @@
(define (higher-order)
(define local-function RIGHT
(lambda (x)
(car "this is" "ChangeMe"))))

6
t/t4018/scheme-module Normal file
Просмотреть файл

@ -0,0 +1,6 @@
(module A RIGHT
(export with-display-exception)
(extern (display-exception display-exception ChangeMe))
(def (with-display-exception thunk)
(with-catch (lambda (e) (display-exception e (current-error-port)) e)
thunk)))

Просмотреть файл

@ -0,0 +1,4 @@
(define (some-func x y z) RIGHT
(let ((a x)
(b y))
(ChangeMe a b)))

Просмотреть файл

@ -0,0 +1,6 @@
(define-test-suite record\ case-tests RIGHT
(record-case-1 (lambda (fail)
(let ((a (make-foo 1 2)))
(record-case a
((bar x) (ChangeMe))
((foo a b) (+ a b)))))))

Просмотреть файл

@ -325,6 +325,7 @@ test_language_driver perl
test_language_driver php
test_language_driver python
test_language_driver ruby
test_language_driver scheme
test_language_driver tex
test_expect_success 'word-diff with diff.sbe' '

11
t/t4034/scheme/expect Normal file
Просмотреть файл

@ -0,0 +1,11 @@
<BOLD>diff --git a/pre b/post<RESET>
<BOLD>index 74b6605..63b6ac4 100644<RESET>
<BOLD>--- a/pre<RESET>
<BOLD>+++ b/post<RESET>
<CYAN>@@ -1,6 +1,6 @@<RESET>
(define (<RED>myfunc a b<RESET><GREEN>my-func first second<RESET>)
; This is a <RED>really<RESET><GREEN>(moderately)<RESET> cool function.
(<RED>this\place<RESET><GREEN>that\place<RESET> (+ 3 4))
(define <RED>some-text<RESET><GREEN>|a greeting|<RESET> "hello")
(let ((c (<RED>+ a b<RESET><GREEN>add1 first<RESET>)))
(format "one more than the total is %d" (<RED>add1<RESET><GREEN>+<RESET> c <GREEN>second<RESET>))))

6
t/t4034/scheme/post Normal file
Просмотреть файл

@ -0,0 +1,6 @@
(define (my-func first second)
; This is a (moderately) cool function.
(that\place (+ 3 4))
(define |a greeting| "hello")
(let ((c (add1 first)))
(format "one more than the total is %d" (+ c second))))

6
t/t4034/scheme/pre Normal file
Просмотреть файл

@ -0,0 +1,6 @@
(define (myfunc a b)
; This is a really cool function.
(this\place (+ 3 4))
(define some-text "hello")
(let ((c (+ a b)))
(format "one more than the total is %d" (add1 c))))

Просмотреть файл

@ -191,6 +191,15 @@ PATTERNS("rust",
"[a-zA-Z_][a-zA-Z0-9_]*"
"|[0-9][0-9_a-fA-Fiosuxz]*(\\.([0-9]*[eE][+-]?)?[0-9_fF]*)?"
"|[-+*\\/<>%&^|=!:]=|<<=?|>>=?|&&|\\|\\||->|=>|\\.{2}=|\\.{3}|::"),
PATTERNS("scheme",
"^[\t ]*(\\(((define|def(struct|syntax|class|method|rules|record|proto|alias)?)[-*/ \t]|(library|module|struct|class)[*+ \t]).*)$",
/*
* R7RS valid identifiers include any sequence enclosed
* within vertical lines having no backslashes
*/
"\\|([^\\\\]*)\\|"
/* All other words should be delimited by spaces or parentheses */
"|([^][)(}{[ \t])+"),
PATTERNS("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
"[={}\"]|[^={}\" \t]+"),
PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",