1#lang scheme/base
2
3(require syntax/docprovide)
4
5(require (only-in test-engine/test-engine
6                  add-failed-check! failed-check
7                  property-error property-fail)
8         (rename-in scheme/base (cons racket-cons))
9	 test-engine/racket-tests
10	 test-engine/syntax
11         test-engine/srcloc
12	 scheme/class)
13
14(require deinprogramm/sdp/private/module-begin
15	 (except-in deinprogramm/signature/signature signature-violation)
16	 (except-in deinprogramm/signature/signature-syntax property))
17
18(require (for-syntax scheme/base)
19	 (for-syntax stepper/private/syntax-property)
20	 (for-syntax syntax/parse)
21	 (for-syntax racket/struct-info)
22	 syntax/parse)
23
24(require deinprogramm/sdp/record)
25
26(require (only-in lang/private/teachprims define-teach teach-equal? beginner-equal~?))
27
28(require (for-syntax deinprogramm/private/syntax-checkers))
29
30(require (for-syntax "rewrite-error-message.rkt"))
31(require "rewrite-error-message.rkt")
32
33(require (rename-in deinprogramm/quickcheck/quickcheck
34		    (property quickcheck:property)))
35
36(provide provide lib planet rename-out require #%datum #%module-begin #%top-interaction) ; so we can use this as a language
37
38(provide (all-from-out deinprogramm/sdp/record))
39(provide (rename-out (define-record define-record-functions)))
40(provide (all-from-out test-engine/racket-tests))
41(provide signature define-contract :
42	 contract ; legacy
43	 one-of ; deprecated
44	 -> mixed predicate enum combined list-of nonempty-list-of)
45(provide (rename-out (nonempty-list-of cons-list-of)))
46
47(provide number real rational integer integer-from-to natural
48	 boolean true false
49	 string symbol
50	 empty-list
51	 unspecific
52	 any
53	 property)
54
55(provide match)
56
57(define-syntax provide/rename
58  (syntax-rules ()
59    ((provide/rename (here there) ...)
60     (begin
61       (provide (rename-out (here there))) ...))))
62
63(provide/rename
64 (sdp-define define)
65 (sdp-let let)
66 (sdp-let* let*)
67 (sdp-letrec letrec)
68 (sdp-lambda lambda)
69 (sdp-lambda λ)
70 (sdp-cond cond)
71 (sdp-if if)
72 (sdp-else else)
73 (sdp-begin begin)
74 (sdp-and and)
75 (sdp-or or)
76 (sdp-dots ..)
77 (sdp-dots ...)
78 (sdp-dots ....)
79 (sdp-dots .....)
80 (sdp-dots ......)
81 (sdp-app #%app)
82 (sdp-top #%top)
83 (sdp-set! set!))
84
85(provide sdp-advanced-lambda
86	 sdp-advanced-define)
87
88(provide for-all ==>
89	 check-property
90	 expect expect-within expect-member-of expect-range)
91
92(provide quote)
93
94(provide-and-document
95 procedures
96 ("Zahlen"
97  (number? (any -> boolean)
98	   "feststellen, ob ein Wert eine Zahl ist")
99
100  (= (number number number ... -> boolean)
101     "Zahlen auf Gleichheit testen")
102  (< (real real real ... -> boolean)
103     "Zahlen auf kleiner-als testen")
104  (> (real real real ... -> boolean)
105     "Zahlen auf größer-als testen")
106  (<= (real real real ... -> boolean)
107      "Zahlen auf kleiner-gleich testen")
108  (>= (real real real ... -> boolean)
109      "Zahlen auf größer-gleich testen")
110
111  (+ (number number number ... -> number)
112     "Summe berechnen")
113  (- (number number ... -> number)
114     "bei mehr als einem Argument Differenz zwischen der ersten und der Summe aller weiteren Argumente berechnen; bei einem Argument Zahl negieren")
115  (* (number number number ... -> number)
116     "Produkt berechnen")
117  (/ (number number number ... -> number)
118     "das erste Argument durch das Produkt aller weiteren Argumente berechnen")
119  (max (real real ... -> real)
120       "Maximum berechnen")
121  (min (real real ... -> real)
122       "Minimum berechnen")
123  (quotient (integer integer -> integer)
124	    "ganzzahlig dividieren")
125  (remainder (integer integer -> integer)
126	     "Divisionsrest berechnen")
127  (modulo (integer integer -> integer)
128	  "Divisionsmodulo berechnen")
129  (sqrt (number -> number)
130	"Quadratwurzel berechnen")
131  (expt (number number -> number)
132	"Potenz berechnen (erstes Argument hoch zweites Argument)")
133  (abs (real -> real)
134       "Absolutwert berechnen")
135
136  ;; fancy numeric
137  (exp (number -> number)
138       "Exponentialfunktion berechnen (e hoch Argument)")
139  (log (number -> number)
140       "natürlichen Logarithmus (Basis e) berechnen")
141
142  ;; trigonometry
143  (sin (number -> number)
144       "Sinus berechnen (Argument in Radian)")
145  (cos (number -> number)
146       "Cosinus berechnen (Argument in Radian)")
147  (tan (number -> number)
148       "Tangens berechnen (Argument in Radian)")
149  (asin (number -> number)
150	"Arcussinus berechnen (in Radian)")
151  (acos (number -> number)
152	"Arcuscosinus berechnen (in Radian)")
153  (atan (number -> number)
154	"Arcustangens berechnen (in Radian)")
155
156  (exact? (number -> boolean)
157	  "feststellen, ob eine Zahl exakt ist")
158
159  (integer? (any -> boolean)
160	    "feststellen, ob ein Wert eine ganze Zahl ist")
161  (natural? (any -> boolean)
162	    "feststellen, ob ein Wert eine natürliche Zahl (inkl. 0) ist")
163
164  (zero? (number -> boolean)
165	 "feststellen, ob eine Zahl Null ist")
166  (positive? (number -> boolean)
167	     "feststellen, ob eine Zahl positiv ist")
168  (negative? (number -> boolean)
169	     "feststellen, ob eine Zahl negativ ist")
170  (odd? (integer -> boolean)
171	"feststellen, ob eine Zahl ungerade ist")
172  (even? (integer -> boolean)
173	 "feststellen, ob eine Zahl gerade ist")
174
175  (lcm (integer integer ... -> natural)
176       "kleinstes gemeinsames Vielfaches berechnen")
177
178  (gcd (integer integer ... -> natural)
179       "größten gemeinsamen Teiler berechnen")
180
181  (rational? (any -> boolean)
182	     "feststellen, ob eine Zahl rational ist")
183
184  (numerator (rational -> integer)
185	     "Zähler eines Bruchs berechnen")
186
187  (denominator (rational -> natural)
188	       "Nenner eines Bruchs berechnen")
189
190  (inexact? (number -> boolean)
191	    "feststellen, ob eine Zahl inexakt ist")
192
193  (real? (any -> boolean)
194	 "feststellen, ob ein Wert eine reelle Zahl ist")
195
196  (floor (real -> integer)
197	 "nächste ganze Zahl unterhalb einer rellen Zahlen berechnen")
198
199  (ceiling (real -> integer)
200	   "nächste ganze Zahl oberhalb einer rellen Zahlen berechnen")
201
202  (round (real -> integer)
203	 "relle Zahl auf eine ganze Zahl runden")
204
205  (complex? (any -> boolean)
206	    "feststellen, ob ein Wert eine komplexe Zahl ist")
207
208  (make-polar (real real -> number)
209	      "komplexe Zahl aus Abstand zum Ursprung und Winkel berechnen")
210
211  (real-part (number -> real)
212	     "reellen Anteil einer komplexen Zahl extrahieren")
213
214  (imag-part (number -> real)
215	     "imaginären Anteil einer komplexen Zahl extrahieren")
216
217  (magnitude (number -> real)
218	     "Abstand zum Ursprung einer komplexen Zahl berechnen")
219
220  (angle (number -> real)
221	 "Winkel einer komplexen Zahl berechnen")
222
223  (exact->inexact (number -> number)
224		  "eine Zahl durch eine inexakte Zahl annähern")
225
226  (inexact->exact (number -> number)
227		  "eine Zahl durch eine exakte Zahl annähern")
228
229  ;;    "Odds and ends"
230
231  (number->string (number -> string)
232		  "Zahl in Zeichenkette umwandeln")
233
234  (string->number (string -> (mixed number false))
235		  "Zeichenkette in Zahl umwandeln, falls möglich")
236
237  (random (natural -> natural)
238	  "eine natürliche Zufallszahl berechnen, die kleiner als das Argument ist")
239
240  (current-seconds (-> natural)
241		   "aktuelle Zeit in Sekunden seit einem unspezifizierten Startzeitpunkt berechnen"))
242
243 ("boolesche Werte"
244  (boolean? (any -> boolean)
245	    "feststellen, ob ein Wert ein boolescher Wert ist")
246
247  ((sdp-not not) (boolean -> boolean)
248   "booleschen Wert negieren")
249
250  (boolean=? (boolean boolean -> boolean)
251	     "Booleans auf Gleichheit testen")
252
253  (true? (any -> boolean)
254	 "feststellen, ob ein Wert #t ist")
255  (false? (any -> boolean)
256	  "feststellen, ob ein Wert #f ist"))
257
258 ("Listen"
259  (empty list "die leere Liste")
260  ((sdp-cons cons) (%a (list-of %a) -> (list-of %a))
261	     "erzeuge ein Cons aus Element und Liste")
262  (cons? (any -> boolean)
263	 "feststellen, ob ein Wert ein Cons ist")
264  (empty? (any -> boolean)
265	  "feststellen, ob ein Wert die leere Liste ist")
266
267  (first ((list-of %a) -> %a)
268	 "erstes Element eines Cons extrahieren")
269  (rest ((list-of %a) -> (list-of %a))
270	"Rest eines Cons extrahieren")
271
272  (list (%a ... -> (list-of %a))
273	"Liste aus den Argumenten konstruieren")
274
275  (length ((list-of %a) -> natural)
276	  "Länge einer Liste berechnen")
277
278  (filter ((%a -> boolean) (list-of %a) -> (list-of %a))
279	 "Alle Elemente einer Liste extrahieren, für welche die Funktion #t liefert.")
280
281  (fold (%b (%a %b -> %b) (list-of %a) -> %b)
282	 "Liste einfalten.")
283
284
285  ((sdp-append append) ((list-of %a) ... -> (list-of %a))
286   "mehrere Listen aneinanderhängen")
287
288  (list-ref ((list-of %a) natural -> %a)
289	    "das Listenelement an der gegebenen Position extrahieren")
290
291  (reverse ((list-of %a)  -> (list-of %a))
292	   "Liste in umgekehrte Reihenfolge bringen"))
293
294 ;; #### Zeichen sollten noch dazu, Vektoren wahrscheinlich auch
295
296 ("Zeichenketten"
297  (string? (any -> boolean)
298	   "feststellen, ob ein Wert eine Zeichenkette ist")
299
300  (string=? (string string string ... -> boolean)
301	    "Zeichenketten auf Gleichheit testen")
302  (string<? (string string string ... -> boolean)
303	    "Zeichenketten lexikografisch auf kleiner-als testen")
304  (string>? (string string string ... -> boolean)
305	    "Zeichenketten lexikografisch auf größer-als testen")
306  (string<=? (string string string ... -> boolean)
307	     "Zeichenketten lexikografisch auf kleiner-gleich testen")
308  (string>=? (string string string ... -> boolean)
309	     "Zeichenketten lexikografisch auf größer-gleich testen")
310
311  (string-append (string string ... -> string)
312		 "Hängt Zeichenketten zu einer Zeichenkette zusammen")
313
314  (strings-list->string ((list-of string) -> string)
315			"Eine Liste von Zeichenketten in eine Zeichenkette umwandeln")
316
317  (string->strings-list (string -> (list-of string))
318			"Eine Zeichenkette in eine Liste von Zeichenketten mit einzelnen Zeichen umwandeln")
319
320  (string-length (string -> natural)
321		 "Liefert Länge einer Zeichenkette"))
322
323 ("Symbole"
324  (symbol? (any -> boolean)
325	   "feststellen, ob ein Wert ein Symbol ist")
326  (symbol=? (symbol symbol -> boolean)
327	    "Sind zwei Symbole gleich?")
328  (symbol->string (symbol -> string)
329		  "Symbol in Zeichenkette umwandeln")
330  (string->symbol (string -> symbol)
331		  "Zeichenkette in Symbol umwandeln"))
332
333 ("Verschiedenes"
334  (signature? (any -> boolean)
335	      "feststellen, ob ein Wert eine Signatur ist")
336  (equal? (%a %b -> boolean)
337	  "zwei Werte auf Gleichheit testen")
338  (eq? (%a %b -> boolean)
339       "zwei Werte auf Selbheit testen")
340  ((sdp-write-string write-string) (string -> unspecific)
341   "Zeichenkette in REPL ausgeben")
342  (write-newline (-> unspecific)
343		 "Zeilenumbruch ausgeben")
344  (violation (string -> unspecific)
345	     "Programmm mit Fehlermeldung abbrechen")
346
347  (map ((%a -> %b) (list-of %a) -> (list-of %b))
348       "Funktion auf alle Elemente einer Liste anwenden, Liste der Resultate berechnen")
349  (for-each ((%a -> %b) (list-of %a) -> unspecific)
350	    "Funktion von vorn nach hinten auf alle Elemente einer Liste anwenden")
351  (apply (function (list-of %a) -> %b)
352	 "Funktion auf Liste ihrer Argumente anwenden")
353  (read (-> any)
354	"Externe Repräsentation eines Werts in der REPL einlesen und den zugehörigen Wert liefern")))
355
356(define cons
357  (lambda (f r)
358    (when (and (not (null? r))
359               (not (pair? r)))
360      (raise
361       (make-exn:fail:contract
362        (string->immutable-string
363         (format "Zweites Argument zu cons ist keine Liste, sondern ~e" r))
364        (current-continuation-marks))))
365    (racket-cons f r)))
366
367(define-syntax sdp-cons
368  (let ()
369    ;; make it work with match
370    (define-struct cons-info ()
371      #:super struct:struct-info
372      #:property
373      prop:procedure
374      (lambda (_ stx)
375	(syntax-case stx ()
376	  ((self . args) (syntax/loc stx (cons . args)))
377	  (else (syntax/loc stx cons)))))
378    (make-cons-info (lambda ()
379		      (list #f
380			    #'cons
381			    #'cons?
382			    (list #'cdr #'car)
383			    '(#f #f)
384			    #f)))))
385
386(define (first l)
387  (when (not (pair? l))
388    (raise
389     (make-exn:fail:contract
390      (string->immutable-string
391       (format "Argument zu first kein Cons, sondern ~e" l))
392      (current-continuation-marks))))
393  (car l))
394
395(define (rest l)
396  (when (not (pair? l))
397    (raise
398     (make-exn:fail:contract
399      (string->immutable-string
400       (format "Argument zu rest kein Cons, sondern ~e" l))
401      (current-continuation-marks))))
402  (cdr l))
403
404(define empty '())
405
406(define (empty? obj)
407  (null? obj))
408
409(define (cons? obj)
410  (pair? obj))
411
412(define-teach sdp append
413  (lambda args
414    (let loop ((args args)
415	       (seen-rev '()))
416      (when (not (null? args))
417	(let ((arg (car args)))
418	  (when (and (not (null? arg))
419		     (not (pair? arg)))
420	    (raise
421	     (make-exn:fail:contract
422	      (string->immutable-string
423	       (format "Erstes Argument zu append keine Liste, sondern ~e; restliche Argumente:~a"
424		       arg
425		       (apply string-append
426			      (map (lambda (arg)
427				     (format " ~e" arg))
428				   (append (reverse seen-rev)
429					   (list '<...>)
430					   (cdr args))))))
431	      (current-continuation-marks))))
432	  (loop (cdr args)
433		(racket-cons arg seen-rev)))))
434
435
436    (apply append args)))
437
438(define fold
439  (lambda (unit combine lis)
440    (cond
441      ((empty? lis) unit)
442      ((pair? lis)
443       (combine (first lis)
444                (fold unit combine (rest lis))))
445      (else
446       (raise
447	(make-exn:fail:contract
448	 (string->immutable-string
449	  (format "Drittes Argument zu fold keine Liste, sondern ~e; andere Argumente: ~e ~e"
450		  lis
451		  unit combine))
452	 (current-continuation-marks)))))))
453
454(define filter
455  (lambda (p? lis)
456    (when (not (procedure? p?))
457      (raise
458       (make-exn:fail:contract
459	(string->immutable-string
460	 (format "Erstes Argument zu filter keine Funktion, sondern ~e" p?))
461	(current-continuation-marks))))
462    (cond
463     ((empty? lis) '())
464     ((pair? lis)
465      (if (p? (first lis))
466	  (racket-cons (first lis)
467                       (filter p? (rest lis)))
468	  (filter p? (rest lis))))
469     (else
470      (raise
471       (make-exn:fail:contract
472	(string->immutable-string
473	 (format "Zweites Argument zu filter keine Liste, sondern ~e"
474		 lis))
475	(current-continuation-marks)))))))
476
477;; This is copied from collects/lang/private/beginner-funs.rkt
478;; Test-suite support (require is really an effect
479;;  to make sure that it's loaded)
480(require deinprogramm/test-suite)
481
482
483(define-for-syntax (raise-sdp-syntax-error form msg . exprs)
484
485  (define (expr->form expr)
486    (let ((sexpr (syntax->datum expr)))
487      (cond
488       ((identifier? expr) sexpr)
489       ((syntax->list expr)
490	=> (lambda (lis)
491	     (expr->form (car lis))))
492       (else #f))))
493
494  (let ((form
495	 (or form
496	     (if (pair? exprs)
497		 (expr->form (car exprs))
498		 #f))))
499    (raise
500     (exn:fail:syntax (if form
501			  (string-append (format "~a" form) ": " msg)
502			  msg)
503		      (current-continuation-marks)
504		      exprs))))
505
506(define-for-syntax (binding-in-this-module? b)
507  (and (list? b)
508       (module-path-index? (car b))
509       (let-values (((path base) (module-path-index-split (car b))))
510	 (and (not path) (not base)))))
511
512(define-for-syntax (transform-sdp-define stx mutable?)
513  (syntax-case stx ()
514    ((sdp-define)
515     (raise-sdp-syntax-error
516      #f "Definition ohne Operanden" stx))
517    ((sdp-define v)
518     (raise-sdp-syntax-error
519      #f "Definition erwartet zwei Operanden, nicht einen" stx))
520    ((sdp-define var expr)
521     (begin
522       (check-for-id!
523	(syntax var)
524	"Der erste Operand der Definition ist kein Name")
525
526       (let ((binding (identifier-binding (syntax var))))
527	 (when binding
528	   (if (binding-in-this-module? binding)
529	       (raise-sdp-syntax-error
530		#f
531		"Zweite Definition für denselben Namen"
532		stx)
533	       (raise-sdp-syntax-error
534		#f
535		"Dieser Name gehört einer eingebauten Funktion und kann nicht erneut definiert werden" (syntax var)))))
536       (if mutable?
537	   (with-syntax
538	       ((dummy-def (stepper-syntax-property
539			    (syntax (define dummy (lambda () (set! var 'dummy))))
540			    'stepper-skip-completely
541			    #t)))
542	     (syntax/loc stx
543			 (begin
544			   dummy-def
545			   (define var expr))))
546	   (syntax/loc stx (define var expr)))))
547    ((sdp-define v e1 e2 e3 ...)
548     (raise-sdp-syntax-error
549      #f "Definition mit mehr als zwei Operanden" stx))))
550
551(define-syntax (sdp-define stx)
552  (transform-sdp-define stx #f))
553
554(define-syntax (sdp-advanced-define stx)
555  (transform-sdp-define stx #t))
556
557(define-for-syntax (check-body-definitions bodies)
558  (let ((pairs
559	 (map (lambda (stx)
560		;; want to be able to shadow global definitions
561		(syntax-case stx (sdp-define)
562		  ((sdp-define)
563		   (raise-sdp-syntax-error
564		    #f "Definition ohne Operanden" stx))
565		  ((sdp-define v)
566		   (raise-sdp-syntax-error
567		    #f "Definition erwartet zwei Operanden, nicht einen" stx))
568		  ((sdp-define var expr)
569		   (begin
570		     (check-for-id!
571		      (syntax var)
572		      "Der erste Operand der Definition ist kein Name")
573		     (cons #'var (syntax/loc stx (define var expr)))))
574		  ((sdp-define v e1 e2 e3 ...)
575		   (raise-sdp-syntax-error
576		    #f "Definition mit mehr als zwei Operanden" stx))
577		  (else
578		   (raise-sdp-syntax-error
579		    #f "Hier muss Definition stehen" stx))))
580	      bodies)))
581    (let loop ((pairs pairs))
582      (when (pair? pairs)
583	(let ((id (caar pairs)))
584	  (cond
585	   ((memf (lambda (p)
586		    (bound-identifier=? id (car p)))
587		  (cdr pairs))
588	    => (lambda (rest)
589		 (raise-sdp-syntax-error
590		  #f
591		  "Zweite Definition für denselben Namen"
592		  (cdar rest)))))
593	  (loop (cdr pairs)))))
594    (map cdr pairs)))
595
596(define-syntax (sdp-let stx)
597  (syntax-case stx ()
598    ((sdp-let ((var expr) ...) body0 ... body)
599     (begin
600       (check-for-id-list!
601	(syntax->list (syntax (var ...)))
602	"Kein Name in `let-Bindung")
603       (with-syntax (((body0 ...) (check-body-definitions (syntax->list #'(body0 ...)))))
604	 (syntax/loc stx ((lambda (var ...) body0 ... body) expr ...)))))
605    ((sdp-let expr ...)
606     (raise-sdp-syntax-error
607      #f "`let'-Ausdruck erwartet eine Liste von Bindungen (Paare aus Name und Ausdruck) und einen Rumpf" stx))))
608
609(define-syntax (sdp-let* stx)
610  (syntax-case stx ()
611    ((sdp-let* () body0 ... body)
612     (syntax/loc stx (let () body0 ... body)))
613    ((sdp-let* ((var1 expr1) (var2 expr2) ...) body0 ... body)
614     (begin
615       (check-for-id!
616	(syntax var1)
617	"Kein Name in `let*'-Bindung")
618       (with-syntax (((body0 ...) (check-body-definitions (syntax->list #'(body0 ...)))))
619	 (syntax/loc stx ((lambda (var1)
620			    (sdp-let* ((var2 expr2) ...) body0 ... body))
621			  expr1)))))
622    ((sdp-let* expr ...)
623     (raise-sdp-syntax-error
624      #f "`let*'-Ausdruck erwartet eine Liste von Bindungen (Paare aus Name und Ausdruck) und einen Rumpf" stx))))
625
626(define-syntax (sdp-letrec stx)
627  (syntax-case stx ()
628    ((sdp-letrec ((var expr) ...) body0 ... body)
629     (begin
630       (check-for-id-list!
631	(syntax->list (syntax (var ...)))
632	"Kein Name in letrec-Bindung")
633       (with-syntax (((body0 ...) (check-body-definitions (syntax->list #'(body0 ...)))))
634	 (syntax/loc stx (letrec ((var expr) ...) body0 ... body)))))
635    ((sdp-letrec expr ...)
636     (raise-sdp-syntax-error
637      #f "`letrec''-Ausdruck erwartet eine Liste von Bindungen (Paare aus Name und Ausdruck) und einen Rumpf" stx))))
638
639(define-syntax (sdp-lambda stx)
640  (syntax-case stx ()
641    ((sdp-lambda (var ...) body0 ... body)
642     (begin
643       (check-for-id-list!
644	(syntax->list (syntax (var ...)))
645	"Kein Name als Parameter der Abstraktion")
646       (with-syntax (((body0 ...) (check-body-definitions (syntax->list #'(body0 ...)))))
647	 (syntax/loc stx (lambda (var ...) body0 ... body)))))
648    ((sdp-lambda var body ...)
649     (identifier? (syntax var))
650     (raise-sdp-syntax-error
651      #f "Um die Parameter einer Abstraktion gehören Klammern" (syntax var)))
652    ((sdp-lambda var ...)
653     (raise-sdp-syntax-error
654      #f "Fehlerhafte Abstraktion" stx))))
655
656(define-syntax (sdp-advanced-lambda stx)
657  (syntax-case stx ()
658    ((sdp-lambda (var ...) body)
659     (begin
660       (check-for-id-list!
661	(syntax->list (syntax (var ...)))
662	"Kein Name als Parameter der Abstraktion")
663       (syntax/loc stx (lambda (var ...) body))))
664    ((sdp-lambda (var ... . rest) body0 ... body)
665     (begin
666       (check-for-id-list!
667	(syntax->list (syntax (var ...)))
668	"Kein Name als Parameter der Abstraktion")
669       (unless (null? (syntax->datum #'rest))
670	 (check-for-id!
671	  (syntax rest)
672	  "Kein Name als Restlisten-Parameter der Abstraktion"))
673       (with-syntax (((body0 ...) (check-body-definitions (syntax->list #'(body0 ...)))))
674	 (syntax/loc stx (lambda (var ... . rest) body0 ... body)))))
675    ((sdp-lambda var ...)
676     (raise-sdp-syntax-error
677      #f "Fehlerhafte Abstraktion" stx))))
678
679(define-syntax (sdp-begin stx)
680  (syntax-case stx ()
681    ((sdp-begin)
682     (raise-sdp-syntax-error
683      #f "`begin`-Ausdruck braucht mindestens einen Operanden" stx))
684    ((sdp-begin expr1 expr2 ...)
685     (syntax/loc stx (begin expr1 expr2 ...)))))
686
687(define-for-syntax (local-expand-for-error stx ctx stops)
688  ;; This function should only be called in an 'expression
689  ;;  context. In case we mess up, avoid bogus error messages.
690  (when (memq (syntax-local-context) '(expression))
691    (local-expand stx ctx stops)))
692
693(define-for-syntax (ensure-expression stx k)
694  (if (memq (syntax-local-context) '(expression))
695      (k)
696      (stepper-syntax-property #`(begin0 #,stx) 'stepper-skipto skipto/second)))
697
698;; A consistent pattern for stepper-skipto:
699(define-for-syntax (stepper-ignore-checker stx)
700  (stepper-syntax-property stx 'stepper-skipto '(syntax-e cdr syntax-e cdr car)))
701
702;; Raise a syntax error:
703(define-for-syntax (teach-syntax-error form stx detail msg . args)
704  (let ([form (if (eq? form '|function call|) ; ####
705		  form
706		  #f)] ; extract name from stx
707	[msg (apply format msg args)])
708    (if detail
709	(raise-sdp-syntax-error form msg stx detail)
710	(raise-sdp-syntax-error form msg stx))))
711
712;; The syntax error when a form's name doesn't follow a "("
713(define-for-syntax (bad-use-error name stx)
714  (teach-syntax-error
715   name
716   stx
717   #f
718   "`~a' wurde an einer Stelle gefunden, die keiner offenen Klammer folgt"
719   name))
720
721;; Use for messages "expected ..., found <something else>"
722(define-for-syntax (something-else v)
723  (let ([v (syntax-e v)])
724    (cond
725     [(number? v) "eine Zahl"]
726     [(string? v) "eine Zeichenkette"]
727     [else "etwas anderes"])))
728;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
729;; cond
730;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
731
732(define-syntax (sdp-cond stx)
733  (ensure-expression
734   stx
735   (lambda ()
736     (syntax-case stx ()
737       [(_)
738	(teach-syntax-error
739	 'cond
740	 stx
741	 #f
742	 "Bedingung und ein Ausdruck nach `cond' erwartet, aber da ist nichts")]
743       [(_ clause ...)
744	(let* ([clauses (syntax->list (syntax (clause ...)))]
745	       [check-preceding-exprs
746		(lambda (stop-before)
747		  (let/ec k
748		    (for-each (lambda (clause)
749				(if (eq? clause stop-before)
750				    (k #t)
751				    (syntax-case clause ()
752				      [(question body0 ... answer)
753				       (begin
754					 (unless (and (identifier? (syntax question))
755						      (free-identifier=? (syntax question) #'sdp-else))
756					   (local-expand-for-error (syntax question) 'expression null))
757					 (local-expand-for-error #'(let () body0 ... answer) 'expression null))])))
758			      clauses)))])
759	  (let ([checked-clauses
760		 (map
761		  (lambda (clause)
762		    (syntax-case clause (sdp-else)
763		      [(sdp-else body0 ... answer)
764		       (let ([lpos (memq clause clauses)])
765			 (when (not (null? (cdr lpos)))
766			   (teach-syntax-error
767			    'cond
768			    stx
769			    clause
770			    "`else'-Bedingung gefunden, die nicht am Ende des `cond'-Ausdrucks steht"))
771			 (with-syntax ([(body0 ...) (check-body-definitions (syntax->list #'(body0 ...)))]
772				       [new-test (stepper-syntax-property (syntax #t) 'stepper-else #t)])
773			   (syntax/loc clause (new-test body0 ... answer))))]
774		      [(question body0 ... answer)
775		       (begin
776			 (with-syntax ([(body0 ...) (check-body-definitions (syntax->list #'(body0 ...)))]
777				       [verified (stepper-ignore-checker (syntax (verify-boolean question 'cond)))])
778			   (syntax/loc clause (verified body0 ... answer))))]
779		      [()
780		       (check-preceding-exprs clause)
781		       (teach-syntax-error
782			'cond
783			stx
784			clause
785			"Bedingung und Ausdruck in Zweig erwartet, aber Zweig leer")]
786		      [(question?)
787		       (check-preceding-exprs clause)
788		       (teach-syntax-error
789			'cond
790			stx
791			clause
792			"Zweig mit Bedingung und Ausdruck erwartet, aber Zweig enthält nur eine Form")]
793		      [_else
794		       (teach-syntax-error
795			'cond
796			stx
797			clause
798			"Zweig mit Bedingung und Ausdruck erwartet, aber ~a gefunden"
799			(something-else clause))]))
800		  clauses)])
801	    ;; Add `else' clause for error (always):
802	    (let ([clauses (append checked-clauses
803				   (list
804				    (with-syntax ([error-call (syntax/loc stx (error 'cond "alle Bedingungen ergaben #f"))])
805				      (syntax [else error-call]))))])
806	      (with-syntax ([clauses clauses])
807		(syntax/loc stx (cond . clauses))))))]
808       [_else (bad-use-error 'cond stx)]))))
809
810(define-syntax sdp-else
811  (make-set!-transformer
812   (lambda (stx)
813     (define (bad expr)
814       (teach-syntax-error
815	'else
816	expr
817	#f
818	"hier nicht erlaubt, weil kein Bedingung in `cond'-Zweig"))
819     (syntax-case stx (set! x)
820       [(set! e expr) (bad #'e)]
821       [(e . expr) (bad #'e)]
822       [e (bad stx)]))))
823
824;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
825;; if
826;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
827
828(define-syntax (sdp-if stx)
829  (ensure-expression
830   stx
831   (lambda ()
832     (syntax-case stx ()
833       [(_ test then else)
834	(with-syntax ([new-test (stepper-ignore-checker (syntax (verify-boolean test 'if)))])
835	  (syntax/loc stx
836		      (if new-test
837			  then
838			  else)))]
839       [(_ . rest)
840	(let ([n (length (syntax->list (syntax rest)))])
841	  (teach-syntax-error
842	   'if
843	   stx
844	   #f
845	   "Bedingung und zwei Ausdrücke erwartet, aber ~a Form~a gefunden"
846	   (if (zero? n) "keine" n)
847	   (if (= n 1) "" "en")))]
848       [_else (bad-use-error 'if stx)]))))
849
850;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
851;; or, and
852;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
853
854(define-syntaxes (sdp-or sdp-and)
855  (let ([mk
856	 (lambda (where)
857	   (let ([stepper-tag (case where
858				[(or) 'comes-from-or]
859				[(and) 'comes-from-and])])
860	     (with-syntax ([swhere where])
861	       (lambda (stx)
862		 (ensure-expression
863		  stx
864		  (lambda ()
865		    (syntax-case stx ()
866		      [(_ . clauses)
867		       (let ([n (length (syntax->list (syntax clauses)))])
868			 (let loop ([clauses-consumed 0]
869				    [remaining (syntax->list #`clauses)])
870			   (if (null? remaining)
871			       (case where
872				 [(or) #`#f]
873				 [(and) #`#t])
874			       (stepper-syntax-property
875				(stepper-syntax-property
876				 (quasisyntax/loc
877				  stx
878				  (if #,(stepper-ignore-checker (quasisyntax/loc stx (verify-boolean #,(car remaining) 'swhere)))
879				      #,@(case where
880					   [(or) #`(#t
881						    #,(loop (+ clauses-consumed 1) (cdr remaining)))]
882					   [(and) #`(#,(loop (+ clauses-consumed 1) (cdr remaining))
883						     #f)])))
884				 'stepper-hint
885				 stepper-tag)
886				'stepper-and/or-clauses-consumed
887				clauses-consumed))))]
888		      [_else (bad-use-error where stx)])))))))])
889    (values (mk 'or) (mk 'and))))
890
891;; verify-boolean is inserted to check for boolean results:
892(define (verify-boolean b where)
893  (if (or (eq? b #t) (eq? b #f))
894      b
895      (raise
896       (make-exn:fail:contract
897	(string->immutable-string
898	 (format "~a: Testresultat ist nicht boolesch: ~e" where b))
899	(current-continuation-marks)))))
900
901(define-teach sdp not
902  (lambda (b)
903    (verify-boolean b 'not)
904    (not b)))
905
906(define (boolean=? a b)
907  (verify-boolean a 'boolean=?)
908  (verify-boolean b 'boolean=?)
909  (eq? a b))
910
911(define (verify-symbol b where)
912  (if (symbol? b)
913      b
914      (raise
915       (make-exn:fail:contract
916	(string->immutable-string
917	 (format "~a: Wert ist kein Symbol: ~e" where b))
918	(current-continuation-marks)))))
919
920(define (symbol=? a b)
921  (verify-symbol a 'symbol=?)
922  (verify-symbol b 'symbol=?)
923  (eq? a b))
924
925(define-syntax (sdp-app stx)
926  (define (raise-operator-error no-op expr)
927    (raise-sdp-syntax-error #f
928			    (format "Operator darf ~a sein, ist aber ~s" no-op (syntax->datum expr))
929			    expr))
930  (syntax-case stx ()
931    ((_)
932     (raise-sdp-syntax-error
933      #f "Zusammengesetzte Form ohne Operator" (syntax/loc stx ())))
934    ((_ datum1 datum2 ...)
935     (number? (syntax->datum #'datum1))
936     (raise-operator-error "keine Zahl" #'datum1))
937    ((_ datum1 datum2 ...)
938     (boolean? (syntax->datum #'datum1))
939     (raise-operator-error "kein boolesches Literal" #'datum1))
940    ((_ datum1 datum2 ...)
941     (string? (syntax->datum #'datum1))
942     (raise-operator-error "keine Zeichenkette" #'datum1))
943    ((_ datum1 datum2 ...)
944     (char? (syntax->datum #'datum1))
945     (raise-operator-error "kein Zeichen" #'datum1))
946    ((_ datum1 datum2 ...)
947     (syntax/loc stx (#%app datum1 datum2 ...)))))
948
949(define (top/check-defined id)
950  (namespace-variable-value (syntax-e id) #t (lambda () (raise-not-bound-error id))))
951
952(define-syntax (sdp-top stx)
953  (syntax-case stx ()
954    ((_ . id)
955     ;; If we're in a module, we'll need to check that the name
956     ;;  is bound....
957     (if (not (identifier-binding #'id))
958	 (if (syntax-source-module #'id)
959	     ;; ... but it might be defined later in the module, so
960	     ;; delay the check.
961	     (stepper-ignore-checker
962	      (syntax/loc stx (#%app values (sdp-top-continue id))))
963             ;; identifier-finding only returns useful information when inside a module.
964             ;; At the top-level we need to  do the check at runtime. Also, note that at
965             ;; the top level there is no need for stepper annotations
966             (syntax/loc stx (#%app top/check-defined #'id)))
967
968	 (syntax/loc stx (#%top . id))))))
969
970(define-syntax (sdp-top-continue stx)
971  (syntax-case stx ()
972    [(_ id)
973     ;; If there's still no binding, it's an "unknown name" error.
974     (if (not (identifier-binding #'id))
975           ;; If there's still no binding, it's an "unknown name" error.
976           (raise-not-bound-error #'id)
977
978	 ;; Don't use #%top here; id might have become bound to something
979	 ;;  that isn't a value.
980	 #'id)]))
981
982(define-teach sdp write-string
983  (lambda (s)
984    (when (not (string? s))
985      (error "Argument von write-string ist keine Zeichenkette"))
986    (display s)))
987
988(define (write-newline)
989  (newline))
990
991(define (violation text)
992  (error text))
993
994(define (string->strings-list s)
995  (map (lambda (c) (make-string 1 c)) (string->list s)))
996
997(define (strings-list->string l)
998  (if (null? l)
999      ""
1000      (string-append (car l) (strings-list->string (cdr l)))))
1001
1002(define integer (signature/arbitrary arbitrary-integer integer (predicate integer?)))
1003(define (integer-from-to lo hi)
1004  (unless (integer? lo)
1005    (error "Erstes Argument von integer-from-to ist keine ganze Zahl."))
1006  (unless (integer? hi)
1007    (error "Zweites Argument von integer-from-to ist keine ganze Zahl."))
1008  (unless (<= lo hi)
1009    (error "Das erste Argument von integer-from-to ist größer als das zweite."))
1010  (signature/arbitrary (arbitrary-integer-from-to lo hi) integer-from-to
1011                       (predicate (lambda (n)
1012                                    (and (integer? n)
1013                                         (<= lo n hi))))))
1014(define number (signature/arbitrary arbitrary-real number (predicate number?)))
1015(define rational (signature/arbitrary arbitrary-rational rational (predicate rational?)))
1016(define real (signature/arbitrary arbitrary-real real (predicate real?)))
1017
1018(define (natural? x)
1019  (and (integer? x)
1020       (not (negative? x))))
1021
1022(define natural (signature/arbitrary arbitrary-natural natural (predicate natural?)))
1023
1024(define boolean (signature/arbitrary arbitrary-boolean boolean (predicate boolean?)))
1025
1026(define (true? x)
1027  (eq? x #t))
1028
1029(define (false? x)
1030  (eq? x #f))
1031
1032(define true (signature true (enum #t)))
1033(define false (signature false (enum #f)))
1034
1035(define string (signature/arbitrary arbitrary-printable-ascii-string string (predicate string?)))
1036(define symbol (signature/arbitrary arbitrary-symbol symbol (predicate symbol?)))
1037(define empty-list (signature empty-list (enum empty)))
1038
1039(define unspecific (signature unspecific %unspecific))
1040(define any (signature any %any))
1041
1042;; aus collects/lang/private/teach.rkt
1043
1044;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1045;; dots (.. and ... and .... and ..... and ......)
1046;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1047
1048;; Syntax Identifier -> Expression
1049;; Produces an expression which raises an error reporting unfinished code.
1050(define-for-syntax (dots-error stx name)
1051  (quasisyntax/loc stx
1052		   (error (quote (unsyntax name))
1053			  "Fertiger Ausdruck erwartet, aber da sind noch Ellipsen")))
1054
1055;; Expression -> Expression
1056;; Transforms unfinished code (... and the like) to code
1057;; raising an appropriate error.
1058(define-syntax sdp-dots
1059  (make-set!-transformer
1060   (lambda (stx)
1061     (syntax-case stx (set!)
1062       [(set! form expr) (dots-error stx (syntax form))]
1063       [(form . rest) (dots-error stx (syntax form))]
1064       [form (dots-error stx stx)]))))
1065
1066(define-syntaxes (sdp-set! sdp-set!-continue)
1067  (let ((proc
1068	 (lambda (continuing?)
1069	   (lambda (stx)
1070	     (ensure-expression
1071	      stx
1072	      (lambda ()
1073		(syntax-case stx ()
1074		  ((_ id expr)
1075		   (identifier? (syntax id))
1076		   (begin
1077		     ;; Check that id isn't syntax, and not lexical.
1078		     ((with-handlers ((exn:fail? (lambda (exn) void)))
1079			;; First try syntax:
1080			;; If it's a transformer binding, then it can take care of itself...
1081			(if (set!-transformer? (syntax-local-value (syntax id)))
1082			    void  ;; no lex check wanted
1083			    (lambda ()
1084			      (raise-sdp-syntax-error
1085			       #f
1086			       "Nach set! wird eine gebundene Variable erwartet, aber da ist ein Schlüsselwort."
1087			       stx)))))
1088		     ;; If we're in a module, we'd like to check here whether
1089		     ;;  the identier is bound, but we need to delay that check
1090		     ;;  in case the id is defined later in the module. So only
1091		     ;;  do this in continuing mode:
1092		     (when continuing?
1093		       (when (and (not (identifier-binding #'id))
1094				  (syntax-source-module #'id))
1095			 (raise-sdp-syntax-error #f "Ungebundene Variable" #'id)))
1096		     (if continuing?
1097			 (syntax/loc stx (set! id expr))
1098			 (stepper-ignore-checker (syntax/loc stx (#%app values (sdp-set!-continue id expr)))))))
1099		  ((_ id expr)
1100		   (raise-sdp-syntax-error
1101		    #f
1102		    "Nach set! wird eine Variable aber da ist etwas anderes."
1103		    #'id))
1104		  ((_ id)
1105		   (raise-sdp-syntax-error
1106		    #f
1107		    "Nach set! wird eine Variable und ein Ausdruck erwartet - der Ausdruck fehlt."
1108		    stx))
1109		  ((_)
1110		   (raise-sdp-syntax-error
1111		    #f
1112		    "Nach set! wird eine Variable und ein Ausdruck erwartet, aber da ist nichts."
1113		    stx))
1114		  (_else
1115		   (raise-sdp-syntax-error
1116		    #f
1117		    "Inkorrekter set!-Ausdruck."
1118		    stx)))))))))
1119    (values (proc #f)
1120	    (proc #t))))
1121
1122; QuickCheck
1123
1124(define-syntax (for-all stx)
1125  (syntax-case stx ()
1126    ((_ (?clause ...) ?body0 ?body ...)
1127     (with-syntax ((((?id ?arb) ...)
1128		    (map (lambda (pr)
1129			   (syntax-case pr ()
1130			     ((?id ?signature)
1131			      (identifier? #'?id)
1132			      (with-syntax ((?error-call
1133					     (syntax/loc #'?signature (error "Signatur hat keinen Generator"))))
1134				#'(?id
1135				   (or (signature-arbitrary (signature ?signature))
1136				       ?error-call))))
1137			     (_
1138			      (raise-sdp-syntax-error #f "inkorrekte `for-all'-Klausel - sollte die Form (id signature) haben"
1139						      pr))))
1140			 (syntax->list #'(?clause ...)))))
1141
1142       (stepper-syntax-property #'(quickcheck:property
1143				   ((?id ?arb) ...) ?body0 ?body ...)
1144				'stepper-skip-completely
1145				#t)))
1146    ((_ ?something ?body0 ?body ...)
1147     (raise-sdp-syntax-error #f "keine Klauseln der Form (id contr)"
1148			     stx))
1149    ((_ ?something)
1150     (raise-sdp-syntax-error #f "Rumpf fehlt" stx))))
1151
1152
1153(define-syntax (check-property stx)
1154  (unless (memq (syntax-local-context) '(module top-level))
1155    (raise-sdp-syntax-error
1156     #f "`check-property' muss ganz außen stehen" stx))
1157  (syntax-case stx ()
1158    ((_ ?prop)
1159     (stepper-syntax-property
1160      (check-expect-maker stx #'check-property-error #'?prop '()
1161			  'comes-from-check-property)
1162      'stepper-replace
1163      #'#t))
1164    (_ (raise-sdp-syntax-error #f "`check-property' erwartet einen einzelnen Operanden"
1165			       stx))))
1166
1167(define quickcheck-config
1168  (make-config 100
1169               2000
1170               (lambda (n)
1171                 (+ 3 (* n 2)))
1172               values))
1173
1174(define (check-property-error test srcloc)
1175  (with-handlers ((exn:fail?
1176                   (lambda (e)
1177                     (add-failed-check! (failed-check (property-error srcloc e)
1178                                                      (exn-srcloc e))))))
1179    (call-with-values
1180     (lambda ()
1181       (with-handlers
1182           ((exn:assertion-violation?
1183             (lambda (e)
1184               ;; minor kludge to produce comprehensible error message
1185               (if (eq? (exn:assertion-violation-who e) 'coerce->result-generator)
1186                   (raise (make-exn:fail (string-append "Wert muss Eigenschaft oder boolesch sein: "
1187                                                        ((error-value->string-handler)
1188                                                         (car (exn:assertion-violation-irritants e))
1189                                                         100))
1190                                         (exn-continuation-marks e)))
1191                   (raise e)))))
1192         (check-results quickcheck-config (test))))
1193     (lambda (ntest stamps result)
1194       (if (check-result? result)
1195           (begin
1196             (add-failed-check! (failed-check (property-fail srcloc result) #f))
1197             #f)
1198           #t)))))
1199
1200(define (expect v1 v2)
1201  (quickcheck:property () (teach-equal? v1 v2)))
1202
1203(define (ensure-real who n val)
1204  (unless (real? val)
1205    (raise
1206     (make-exn:fail:contract
1207      (string->immutable-string
1208       (format "~a Argument ~e zu `~a' keine reelle Zahl." n val who))
1209      (current-continuation-marks)))))
1210
1211(define (expect-within v1 v2 epsilon)
1212  (ensure-real 'expect-within "Drittes" epsilon)
1213  (quickcheck:property () (beginner-equal~? v1 v2 epsilon)))
1214
1215(define (expect-range val min max)
1216  (ensure-real 'expect-range "Erstes" val)
1217  (ensure-real 'expect-range "Zweites" min)
1218  (ensure-real 'expect-range "Drittes" max)
1219  (quickcheck:property ()
1220		       (and (<= min val)
1221			    (<= val max))))
1222
1223(define (expect-member-of val . candidates)
1224  (quickcheck:property ()
1225		       (ormap (lambda (cand)
1226				(teach-equal? val cand))
1227			      candidates)))
1228
1229(define property (signature (predicate (lambda (x)
1230					(or (boolean? x)
1231					    (property? x))))))
1232
1233
1234(define-syntax (match stx)
1235  (syntax-parse stx
1236    ((_ ?case:expr (?pattern0 ?body0:expr) (?pattern ?body:expr) ...)
1237     (let ()
1238       (define (pattern-variables pat)
1239	 (syntax-case pat (empty sdp-cons list quote ...)
1240	   ((... ...) '())
1241	   (empty '())
1242	   (?var (identifier? #'?var)
1243	     (if (eq? (syntax->datum #'?var) '_)
1244		 '()
1245		 (list #'?var)))
1246	   (?lit (let ((d (syntax->datum #'?lit)))
1247		   (or (string? d) (number? d) (boolean? d)))
1248		 '())
1249	   ('?lit '())
1250	   ((sdp-cons ?pat1 ?pat2)
1251	    (append (pattern-variables #'?pat1) (pattern-variables #'?pat2)))
1252	   ((list) '())
1253	   ((list ?pat0 ?pat ...)
1254	    (apply append (map pattern-variables (syntax->list #'(?pat0 ?pat ...)))))
1255	   ((?const ?pat ...)
1256	    (apply append (map pattern-variables (syntax->list #'(?pat ...)))))))
1257       (define (check pat)
1258	 (let loop ((vars (pattern-variables pat)))
1259	   (when (pair? vars)
1260	     (let ((var (car vars)))
1261	       (when (memf (lambda (other-var)
1262			     (free-identifier=? var other-var))
1263			   (cdr vars))
1264		 (raise-sdp-syntax-error #f "Variable in match-Zweig kommt doppelt vor"
1265					 var))
1266	       (loop (cdr vars))))))
1267       (for-each check (syntax->list #'(?pattern0 ?pattern ...)))
1268       #'(let* ((val ?case)
1269		(nomatch (lambda () (match val (?pattern ?body) ...))))
1270	   (match-helper val ?pattern0 ?body0 (nomatch)))))
1271    ((_ ?case:expr)
1272     (syntax/loc stx (error 'match "keiner der Zweige passte")))))
1273
1274
1275(define (list-length=? lis n)
1276  (cond
1277   ((zero? n) (null? lis))
1278   ((null? lis) #f)
1279   (else
1280    (list-length=? (cdr lis) (- n 1)))))
1281
1282(define-syntax (match-helper stx)
1283  (syntax-case stx ()
1284    ((_ ?id ?pattern0 ?body0 ?nomatch)
1285     (syntax-case #'?pattern0 (empty cons list quote ...)
1286       (empty
1287	#'(if (null? ?id)
1288	      ?body0
1289	      ?nomatch))
1290       ((... ...)
1291	#'?body0)
1292       (?var (identifier? #'?var)
1293	     (if (eq? (syntax->datum #'?var) '_) ; _ is magic
1294		 #'?body0
1295		 #'(let ((?var ?id))
1296		     ?body0)))
1297       (?lit (let ((d (syntax->datum #'?lit)))
1298	       (or (string? d) (number? d) (boolean? d)))
1299	     #'(if (equal? ?id ?lit)
1300		   ?body0
1301		   ?nomatch))
1302       ('?lit
1303	#'(if (equal? ?id '?lit)
1304	      ?body0
1305	      ?nomatch))
1306       ((cons ?pat1 ?pat2)
1307	#'(if (pair? ?id)
1308	      (let ((f (first ?id))
1309		    (r (rest ?id)))
1310		(match-helper f ?pat1
1311			      (match-helper r ?pat2 ?body0 ?nomatch)
1312			      ?nomatch))
1313	      ?nomatch))
1314       ((list)
1315	#'(if (null? ?id)
1316	      ?body0
1317	      ?nomatch))
1318       ((list ?pat0 ?pat ...)
1319	(let* ((pats (syntax->list #'(?pat0 ?pat ...)))
1320	       (cars (generate-temporaries pats))
1321	       (cdrs (generate-temporaries pats)))
1322	#`(if (and (pair? ?id)
1323		   (list-length=? ?id #,(length pats)))
1324	      #,(let recur ((ccdr #'?id)
1325			    (pats pats)
1326			    (cars cars) (cdrs cdrs))
1327		  (if (null? pats)
1328		      #'?body0
1329		      #`(let ((#,(car cars) (car #,ccdr))
1330			      (#,(car cdrs) (cdr #,ccdr)))
1331			  (match-helper #,(car cars) #,(car pats)
1332					#,(recur (car cdrs) (cdr pats) (cdr cars) (cdr cdrs))
1333					?nomatch))))
1334	      ?nomatch)))
1335       ((?const ?pat ...)
1336	(identifier? #'?const)
1337	(let* ((fail (lambda ()
1338		       (raise-sdp-syntax-error #f "Operator in match muss ein Record-Konstruktor sein"
1339					       #'?const)))
1340	       (v (syntax-local-value #'?const fail)))
1341	  (unless (struct-info? v)
1342	    (fail))
1343
1344	  (apply
1345	   (lambda (_ _cons pred rev-selectors _mutators ?)
1346	     (let* ((pats (syntax->list #'(?pat ...)))
1347		    (selectors (reverse rev-selectors))
1348		    (field-ids (generate-temporaries pats)))
1349	       (unless (= (length rev-selectors) (length pats))
1350		 (raise-sdp-syntax-error #f "Die Anzahl der Felder im match stimmt nicht" #'?pattern0))
1351	       #`(if (#,pred ?id)
1352		     #,(let recur ((pats pats)
1353				   (selectors selectors)
1354				   (field-ids field-ids))
1355			 (if (null? pats)
1356			     #'?body0
1357			     #`(let ((#,(car field-ids) (#,(car selectors) ?id)))
1358				 (match-helper #,(car field-ids) #,(car pats)
1359					       #,(recur (cdr pats) (cdr selectors) (cdr field-ids))
1360					       ?nomatch))))
1361		     ?nomatch)))
1362	   (extract-struct-info v))))))))
1363