(cond-expand (chicken (use test fmt fmt-c)) (gauche (use gauche.test) (use text.fmt) (use text.fmt.c) (define test-begin test-start) (define orig-test (with-module gauche.test test)) (define-syntax test (syntax-rules () ((test name expected expr) (orig-test name expected (lambda () expr))) ((test expected expr) (orig-test (let ((s (with-output-to-string (lambda () (write 'expr))))) (substring s 0 (min 60 (string-length s)))) expected (lambda () expr))) ))) (else)) (test-begin "fmt-c") (test "if (1) { 2; } else { 3; } " (fmt #f (c-if 1 2 3))) (test "if (x ? y : z) { 2; } else { 3; } " (fmt #f (c-if (c-if 'x 'y 'z) 2 3))) (test "int square (int x) { return x * x; } " (fmt #f (c-fun 'int 'square '((int x)) (c* 'x 'x)))) (test "int foo (int x, int y, int z) { if (x ? y : z) { return 2; } else { return 3; } } " (fmt #f (c-fun 'int 'foo '((int x) (int y) (int z)) (c-if (c-if 'x 'y 'z) 2 3)))) (test "void bar (int mode, const char* msg, unsigned int arg) { if (mode == 1) { printf(msg); } else { printf(msg, arg); } } " (fmt #f (c-fun 'void 'bar '((int mode) ((const char %pointer) msg) ((unsigned int) arg)) (c-if (c== 'mode 1) '(printf msg) '(printf msg arg))))) (test "while ((line = readline()) != EOF) { printf(\"%s\", line); } " (fmt #f (c-while (c!= (c= 'line '(readline)) 'EOF) '(printf "%s" line)))) (test "switch (y) { case 1: x = 1; break; case 2: x = 4; break; default: x = 5; break; } " (fmt #f (c-switch 'y (c-case 1 (c= 'x 1)) (c-case 2 (c= 'x 4)) (c-default (c= 'x 5))))) (test "switch (y) { case 1: x = 1; break; case 2: x = 4; default: x = 5; break; } " (fmt #f (c-switch 'y (c-case 1 (c= 'x 1)) (c-case/fallthrough 2 (c= 'x 4)) (c-default (c= 'x 5))))) (test "switch (y) { case 1: x = 1; break; case 2: x = 4; break; default: x = 5; break; } " (fmt #f (c-switch 'y '((1) (= x 1)) '((2) (= x 4)) '(else (= x 5))))) (test "switch (y) { case 1: x = 1; break; case 2: x = 4; break; default: x = 5; break; } " (fmt #f (c-expr '(switch y ((1) (= x 1)) ((2) (= x 4)) (else (= x 5)))))) (test "int q (int x) { switch (x) { case 1: return 1; case 2: return 4; default: return 5; } } " (fmt #f (c-fun 'int 'q '(x) (c-switch 'x '((1) 1) '((2) 4) '(else 5))))) (test "for (i = 0; i < n; i++) { printf(\"i: %d\"); } " (fmt #f (c-for (c= 'i 0) (c< 'i 'n) (c++/post 'i) '(printf "i: %d")))) (test "a * x + b * y == c;\n" (fmt #f (c== (c+ (c* 'a 'x) (c* 'b 'y)) 'c))) (test "a * x + b * y == c;\n" (fmt #f (c-expr '(== (+ (* a x) (* b y)) c)))) (test "(a + x) * (b + y) == c;\n" (fmt #f (c-expr '(== (* (+ a x) (+ b y)) c)))) (test "(abracadabra!!!! + xylophone????) * (bananarama____ + yellowstonepark~~~~) * (cryptoanalysis + zebramania);\n" (fmt #f (c-expr '(* (+ abracadabra!!!! xylophone????) (+ bananarama____ yellowstonepark~~~~) (+ cryptoanalysis zebramania))))) (test "abracadabra(xylophone, bananarama, yellowstonepark, cryptoanalysis, zebramania, delightful, wubbleflubbery);\n" (fmt #f (c-expr '(abracadabra xylophone bananarama yellowstonepark cryptoanalysis zebramania delightful wubbleflubbery)))) (test "#define foo(x, y) (((x) + (y)))\n" (fmt #f (cpp-define '(foo (int x) (int y)) (c+ 'x 'y)))) (test "#define min(x, y) (((x) < (y)) ? (x) : (y))\n" (fmt #f (cpp-define '(min x y) (c-if (c< 'x 'y) 'x 'y)))) (test "#define foo(x, y) (abracadabra(((x) + (y)), \\ xylophone, \\ bananarama, \\ yellowstonepark, \\ cryptoanalysis, \\ zebramania, \\ delightful, \\ wubbleflubbery))\n" (fmt #f (cpp-define '(foo x y) '(abracadabra (+ x y) xylophone bananarama yellowstonepark cryptoanalysis zebramania delightful wubbleflubbery)))) (test "#ifndef FOO_H #define FOO_H extern int foo (); #endif /* ! FOO_H */ " (fmt #f (cpp-wrap-header 'FOO_H (c-extern (c-prototype 'int 'foo '()))))) (test "/* this is a /\\* nested *\\/ comment */" (fmt #f (c-comment " this is a " (c-comment " nested ") " comment "))) ;; the initial leading space is annoying but hard to remove at the ;; moment - the important thing is we preserve indentation in the body (test "switch (y) { case 1: x = 1; break; #ifdef H_TWO case 2: x = 4; break; #endif /* H_TWO */ default: x = 5; break; } " (fmt #f (c-expr `(switch y ((1) (= x 1)) ,(cpp-ifdef 'H_TWO (c-case '(2) '(= x 4))) (else (= x 5)))))) (test "#define eprintf(...) (fprintf(stderr, __VA_ARGS__))\n" (fmt #f (c-expr '(%define (eprintf . args) (fprintf stderr args))))) (test "struct point { int x; int y; }; " (fmt #f (c-expr `(struct point (x y))))) (test "struct employee { short age; char* name; struct { int year; int month; int day; } dob; } __attribute__ ((packed)); " (fmt #f (c-expr `(struct employee ((short age) ((char %pointer) name) ((struct (year month day)) dob)) (%attribute packed) )))) (test "struct employee { short age; char* name; struct { int year; int month; int day; } dob; } __attribute__ ((packed)); " (fmt #f (c-struct 'employee '((short age) ((char %pointer) name) ((struct (year month day)) dob)) (c-attribute 'packed) ))) (test "union object { char tag; struct { char tag; char* data; } string; struct { char tag; void* car; void* cdr; } pair; struct { char tag; unsigned int length; void* data; } vector; }; " (fmt #f (c-expr '(union object ((char tag) ((struct ((char tag) (char* data))) string) ((struct ((char tag) (void* car) (void* cdr))) pair) ((struct ((char tag) ((unsigned int) length) (void* data))) vector) ))))) (test "enum type_tags { TYPE_CHAR, TYPE_FIXNUM, TYPE_BOOLEAN, TYPE_NULL, TYPE_EOF, TYPE_STRING, TYPE_PAIR, TYPE_VECTOR }; " (fmt #f (c-expr '(enum type_tags (TYPE_CHAR TYPE_FIXNUM TYPE_BOOLEAN TYPE_NULL TYPE_EOF TYPE_STRING TYPE_PAIR TYPE_VECTOR))))) (test "#define OP_EVAL 0xFE\n" (fmt #f (radix 16 (cpp-define 'OP_EVAL 254)))) (test-end)