From d0b60ed05147bde5ec0b613ec29da4a223ca70eb Mon Sep 17 00:00:00 2001 From: alex-eg Date: Thu, 14 Aug 2025 14:33:14 +0300 Subject: [PATCH 1/9] add support for begin in Sex begin-wrapped blocks are now creating lexical scopes --- example/list.sex | 13 +++++++------ fmt-c.scm | 3 ++- sexc.scm | 2 +- tests/run.scm | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/example/list.sex b/example/list.sex index 832e401..5cddb77 100644 --- a/example/list.sex +++ b/example/list.sex @@ -38,9 +38,10 @@ (pub defmacro (list-for-each list-type list-var elt-type elt-var what-do) (let ((list-var-2 (cat list-var '-2))) - `((var (pointer ,list-type) ,list-var-2 ,list-var) - (var ,elt-type ,elt-var (-> ,list-var-2 value)) - (while (!= (-> ,list-var-2 next) NULL) - ,what-do - (= ,list-var-2 (-> ,list-var-2 next)) - (= ,elt-var (-> ,list-var-2 value)))))) + `((begin + (var (pointer ,list-type) ,list-var-2 ,list-var) + (var ,elt-type ,elt-var (-> ,list-var-2 value)) + (while (!= (-> ,list-var-2 next) NULL) + ,what-do + (= ,list-var-2 (-> ,list-var-2 next)) + (= ,elt-var (-> ,list-var-2 value))))))) diff --git a/fmt-c.scm b/fmt-c.scm index b924629..0b9fce0 100644 --- a/fmt-c.scm +++ b/fmt-c.scm @@ -218,6 +218,7 @@ ((apply cpp-if/aux (substring/shared (symbol->string (car x)) 1) (cdr x)) st)) ((%endif) ((apply cpp-endif (cdr x)) st)) + ((%block-begin) ((apply c-braced-block #f (cdr x)) st)) ((%block) ((apply c-braced-block (cdr x)) st)) ((%comment) ((apply c-comment (cdr x)) st)) ((:) ((apply c-label (cdr x)) st)) @@ -521,7 +522,7 @@ (define (c-braced-block/aux offset header . body) (lambda (st) - ((cat header (c-open-brace st) (c-indent st offset) + ((cat (if header header "") (c-open-brace st) (c-indent st offset) (apply c-begin body) fl (c-current-indent-string st offset) (c-close-brace st)) st))) diff --git a/sexc.scm b/sexc.scm index cefa70a..4e94b99 100644 --- a/sexc.scm +++ b/sexc.scm @@ -36,7 +36,7 @@ ((fn) '%fun) ((prototype) '%prototype) ((var) '%var) - ((begin) '%begin) + ((begin) '%block-begin) ((define) '%define) ((pointer) '%pointer) ((array) '%array) diff --git a/tests/run.scm b/tests/run.scm index e786828..f6a3386 100644 --- a/tests/run.scm +++ b/tests/run.scm @@ -21,7 +21,7 @@ (test '%fun (atom-to-fmt-c 'fn)) (test '%prototype (atom-to-fmt-c 'prototype)) (test '%var (atom-to-fmt-c 'var)) -(test '%begin (atom-to-fmt-c 'begin)) +(test '%block-begin (atom-to-fmt-c 'begin)) (test '%define (atom-to-fmt-c 'define)) (test '%pointer (atom-to-fmt-c 'pointer)) (test '%array (atom-to-fmt-c 'array)) -- 2.52.0 From 176844171cf08cfcb660924036d263dca1a81946 Mon Sep 17 00:00:00 2001 From: alex-eg Date: Thu, 14 Aug 2025 14:35:20 +0300 Subject: [PATCH 2/9] don't use int as default type for variables, generate error instead --- fmt-c.scm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fmt-c.scm b/fmt-c.scm index 0b9fce0..af1bf8e 100644 --- a/fmt-c.scm +++ b/fmt-c.scm @@ -15,7 +15,6 @@ (define (fmt-macro-params st) (fmt-ref st 'macro-params)) (define (fmt-expression? st) (fmt-ref st 'expression?)) (define (fmt-return? st) (fmt-ref st 'return?)) -(define (fmt-default-type st) (fmt-ref st 'default-type 'int)) (define (fmt-newline-before-brace? st) (fmt-ref st 'newline-before-brace?)) (define (fmt-braceless-bodies? st) (fmt-ref st 'braceless-bodies?)) (define (fmt-non-spaced-ops? st) (fmt-ref st 'non-spaced-ops?)) @@ -608,7 +607,7 @@ (cond ((procedure? x) x) ((pair? x) (c-type (car x) (cadr x))) - (else (cat (lambda (st) ((c-type (fmt-default-type st)) st)) " " x)))) + (else (error "missing type" x)))) (define (c-field x) (cond @@ -624,7 +623,7 @@ (else (c-type (car x) (cadr x)))) (c-type (car x) (fmt-join c-expr (cdr x) ", ")))) - (else (cat (lambda (st) ((c-type (fmt-default-type st)) st)) " " x)))) + (else (error "missing type" x)))) (define (c-param-list ls) (c-in-expr (fmt-join/dot c-param (lambda (dot) (dsp "...")) ls ", "))) -- 2.52.0 From adf845fe01a14937340de85bf79d2de970e9211d Mon Sep 17 00:00:00 2001 From: alex-eg Date: Thu, 14 Aug 2025 14:35:50 +0300 Subject: [PATCH 3/9] generate void in empty argument lists --- fmt-c.scm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fmt-c.scm b/fmt-c.scm index af1bf8e..3f35596 100644 --- a/fmt-c.scm +++ b/fmt-c.scm @@ -626,7 +626,9 @@ (else (error "missing type" x)))) (define (c-param-list ls) - (c-in-expr (fmt-join/dot c-param (lambda (dot) (dsp "...")) ls ", "))) + (if (null? ls) + (c-type 'void) + (c-in-expr (fmt-join/dot c-param (lambda (dot) (dsp "...")) ls ", ")))) (define (c-fun type name params . body) (cat (c-block (c-in-expr (c-prototype type name params)) -- 2.52.0 From 089f9d6a6fd23d01508131f4928dcc546cb2a2e0 Mon Sep 17 00:00:00 2001 From: alex-eg Date: Thu, 21 Aug 2025 18:13:18 +0300 Subject: [PATCH 4/9] fix newline and whitespace after braces in generated C blocks --- fmt-c.scm | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/fmt-c.scm b/fmt-c.scm index 3f35596..71602f4 100644 --- a/fmt-c.scm +++ b/fmt-c.scm @@ -26,6 +26,8 @@ (define (c-in-expr proc) (fmt-let 'expression? #t proc)) (define (c-in-stmt proc) (fmt-let 'expression? #f proc)) +(define (c-reset-newline proc) (fmt-let 'newline-before-brace? #f proc)) + (define (c-in-test proc) (fmt-let 'in-cond? #t (c-in-expr proc))) (define (c-with-op op proc) (fmt-let 'op op proc)) @@ -487,8 +489,12 @@ (define (c-open-brace st) (if (fmt-newline-before-brace? st) - (cat nl (c-current-indent-string st) "{" nl) - (cat " {" nl))) + (begin + (fmt-set! st 'newline-before-brace? #t) + (cat "{" nl)) + (begin + (fmt-set! st 'newline-before-brace? #t) + (cat " {" nl)))) (define (c-close-brace st) (dsp "}")) @@ -590,18 +596,20 @@ ;; basic control structures (define (c-while check . body) - (cat (c-block (cat "while (" (c-in-test (c-expr check)) ")") - (c-in-stmt (apply c-begin body))) - fl)) + (c-reset-newline + (cat (c-block (cat "while (" (c-in-test (c-expr check)) ")") + (c-in-stmt (apply c-begin body))) + fl))) (define (c-for init check update . body) - (cat - (c-block - (c-in-expr - (cat "for (" (c-expr init) "; " (c-in-test (c-expr check)) "; " - (c-expr update ) ")")) - (c-in-stmt (apply c-begin body))) - fl)) + (c-reset-newline + (cat + (c-block + (c-in-expr + (cat "for (" (c-expr init) "; " (c-in-test (c-expr check)) "; " + (c-expr update ) ")")) + (c-in-stmt (apply c-begin body))) + fl))) (define (c-param x) (cond @@ -761,12 +769,13 @@ (c-wrap-stmt (cat "goto " (c-expr label)))) (define (c-switch val . clauses) - (lambda (st) - ((cat "switch (" (c-in-expr val) ")" (c-open-brace st) - (c-indent/switch st) - (c-in-stmt (apply c-begin/aux #t (map c-switch-clause clauses))) fl - (c-current-indent-string st) (c-close-brace st) fl) - st))) + (c-reset-newline + (lambda (st) + ((cat "switch (" (c-in-expr val) ")" (c-open-brace st) + (c-indent/switch st) + (c-in-stmt (apply c-begin/aux #t (map c-switch-clause clauses))) fl + (c-current-indent-string st) (c-close-brace st) fl) + st)))) (define (c-switch-clause/breaks x) (lambda (st) -- 2.52.0 From 568fa51dc7e1e050c174b7008e3aefde54d69ad2 Mon Sep 17 00:00:00 2001 From: alex-eg Date: Thu, 21 Aug 2025 18:15:48 +0300 Subject: [PATCH 5/9] force c89 pedantic compilation mode --- example/test-list.sex | 13 ++++++------- sexc.scm | 9 +++++++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/example/test-list.sex b/example/test-list.sex index 4e4eb63..c4af345 100644 --- a/example/test-list.sex +++ b/example/test-list.sex @@ -1,6 +1,5 @@ (include stdlib.h) (include stddef.h) -(include stdbool.h) (include stdio.h) (chicken-import srfi-1 brev-separate) ; list routines, e.g. fold @@ -16,7 +15,7 @@ ((const char *) c) ((fn bool ((bool val))) not))) -(var foo f #((= .a-field 1.2))) +(var foo f) (list-T int) (make-list-T int #f) @@ -26,7 +25,7 @@ (extern fn void puk ((int a) (float b))) (fn int bar () (return ,(imports-test 10 20 30))) -(pub fn void baz () true) +(pub fn bool baz () (return true)) (extern var int i) (var int j) @@ -34,15 +33,15 @@ (pub fn int main () (var (* list-int) l (make-list-int)) - (printf "Size of the list: %zu\n" (length-list-int l)) + (printf "Size of the list: %lu\n" (length-list-int l)) (add-value-list-int l 3) (add-value-list-int l 4) - (printf "Size of the list: %zu\n" (length-list-int l)) + (printf "Size of the list: %lu\n" (length-list-int l)) (list-for-each list-int l int v (printf "%d " v)) (printf "\n") - (printf "Size of the list: %zu\n" (length-list-int l)) - (printf "%p\n" l->next) + (printf "Size of the list: %lu\n" (length-list-int l)) + (printf "%p\n" (cast void* l->next)) (return 0)) (pub fn void print-list (((const list-int) *l)) diff --git a/sexc.scm b/sexc.scm index 4e94b99..12bde6a 100644 --- a/sexc.scm +++ b/sexc.scm @@ -1,7 +1,8 @@ (declare (unit sexc) (uses fmt-c sex-macros - sex-modules)) + sex-modules + sex-types)) (include "utils.macros.scm") @@ -44,6 +45,10 @@ ((@) 'vector-ref) ((include) '%include) ((cast) '%cast) + ;; uh things we do for c89 compatibility + ((bool) 'int) + ((true) 1) + ((false) 0) (else (if (symbol? atom) (unkebabify atom) @@ -288,7 +293,7 @@ (emit-c sex-forms))) (call-with-values (lambda () - (process compiler (append (list temp-c-out "-o" out-file) + (process compiler (append (list temp-c-out "-o" out-file "-std=c89" "-pedantic") (if (get-arg args 'compile-object #f) (list "-c") (list)) -- 2.52.0 From f3867928e5dac5ac6f595784594bb6c85e0067bd Mon Sep 17 00:00:00 2001 From: alex-eg Date: Thu, 21 Aug 2025 18:16:49 +0300 Subject: [PATCH 6/9] add union to emacs.el keyword list --- sex-mode.el | 1 + 1 file changed, 1 insertion(+) diff --git a/sex-mode.el b/sex-mode.el index 99434c2..8eb676e 100644 --- a/sex-mode.el +++ b/sex-mode.el @@ -80,6 +80,7 @@ All commands in `lisp-mode-shared-map' are inherited by this map.") (put 'pub 'lisp-indent-function 'defun) (put 'defmacro 'lisp-indent-function 'defun) (put 'struct 'lisp-indent-function 'defun) +(put 'union 'lisp-indent-function 'defun) (put 'var 'lisp-indent-function 0) (put 'import 'lisp-indent-function 1) -- 2.52.0 From 7a47475adf765f07ca81b28775a42a2572e6293c Mon Sep 17 00:00:00 2001 From: alex-eg Date: Thu, 21 Aug 2025 18:19:19 +0300 Subject: [PATCH 7/9] split test in separate test files --- Makefile | 8 ++++---- tests/basic.scm | 26 ++++++++++++++++++++++++++ tests/run.scm | 28 ++-------------------------- tests/types.scm | 1 + 4 files changed, 33 insertions(+), 30 deletions(-) create mode 100644 tests/basic.scm create mode 100644 tests/types.scm diff --git a/Makefile b/Makefile index d5cb4f9..9ae4fab 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,9 @@ main.o: main.scm %.o: %.scm $(CHICKEN_C) $< -e -c -o $@ -sex-tests: $(OBJ) tests/run.scm - $(CHICKEN_C) tests/run.scm -c -o sex-tests.o - $(CHICKEN_C) $(OBJ) sex-tests.o -o sex-tests +sex-tests: $(OBJ) tests/*.scm + cd ./tests && $(CHICKEN_C) run.scm -c -o sex-tests.o + $(CHICKEN_C) $(OBJ) ./tests/sex-tests.o -o sex-tests clean: - rm -f $(OBJ) sexc sex-tests main.o sex-test.o + rm -f $(OBJ) sexc sex-tests main.o ./tests/sex-tests.o diff --git a/tests/basic.scm b/tests/basic.scm new file mode 100644 index 0000000..6bb3c70 --- /dev/null +++ b/tests/basic.scm @@ -0,0 +1,26 @@ +;;; unkebabify +(test '- (unkebabify '-)) +(test '-- (unkebabify '--)) +(test '-> (unkebabify '->)) +(test '-= (unkebabify '-=)) +(test 'kebab_case (unkebabify 'kebab-case)) +(test '_what_ (unkebabify '-what-)) +(test 'this->member (unkebabify 'this->member)) +(test '_this_->_member_ (unkebabify '-this-->-member-)) +(test '__->>> (unkebabify '--->>>)) + +;;; atom-to-fmt-c +(test '%fun (atom-to-fmt-c 'fn)) +(test '%prototype (atom-to-fmt-c 'prototype)) +(test '%var (atom-to-fmt-c 'var)) +(test '%block-begin (atom-to-fmt-c 'begin)) +(test '%define (atom-to-fmt-c 'define)) +(test '%pointer (atom-to-fmt-c 'pointer)) +(test '%array (atom-to-fmt-c 'array)) +(test 'vector-ref (atom-to-fmt-c '@)) +(test '%include (atom-to-fmt-c 'include)) +(test '%cast (atom-to-fmt-c 'cast)) + +;;; make-field-access +(test 'a.b (make-field-access '(.b a))) +(test 'a.b.c (make-field-access '(.c a.b))) diff --git a/tests/run.scm b/tests/run.scm index f6a3386..56019ec 100644 --- a/tests/run.scm +++ b/tests/run.scm @@ -6,32 +6,8 @@ srfi-1 test) -;;; unkebabify -(test '- (unkebabify '-)) -(test '-- (unkebabify '--)) -(test '-> (unkebabify '->)) -(test '-= (unkebabify '-=)) -(test 'kebab_case (unkebabify 'kebab-case)) -(test '_what_ (unkebabify '-what-)) -(test 'this->member (unkebabify 'this->member)) -(test '_this_->_member_ (unkebabify '-this-->-member-)) -(test '__->>> (unkebabify '--->>>)) - -;;; atom-to-fmt-c -(test '%fun (atom-to-fmt-c 'fn)) -(test '%prototype (atom-to-fmt-c 'prototype)) -(test '%var (atom-to-fmt-c 'var)) -(test '%block-begin (atom-to-fmt-c 'begin)) -(test '%define (atom-to-fmt-c 'define)) -(test '%pointer (atom-to-fmt-c 'pointer)) -(test '%array (atom-to-fmt-c 'array)) -(test 'vector-ref (atom-to-fmt-c '@)) -(test '%include (atom-to-fmt-c 'include)) -(test '%cast (atom-to-fmt-c 'cast)) - -;;; make-field-access -(test 'a.b (make-field-access '(.b a))) -(test 'a.b.c (make-field-access '(.c a.b))) +(include "basic.scm") +(include "types.scm") ;;; Should be the last in the test suite (test-exit) diff --git a/tests/types.scm b/tests/types.scm new file mode 100644 index 0000000..cb14c40 --- /dev/null +++ b/tests/types.scm @@ -0,0 +1 @@ +(test "char *" (to-c-type '(%pointer char))) -- 2.52.0 From 0928c137804adacc597cbd269277e7602f87849b Mon Sep 17 00:00:00 2001 From: alex-eg Date: Thu, 21 Aug 2025 19:28:46 +0300 Subject: [PATCH 8/9] don't create temp files when compiling --- sexc.scm | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sexc.scm b/sexc.scm index 12bde6a..4dde59e 100644 --- a/sexc.scm +++ b/sexc.scm @@ -13,6 +13,7 @@ (chicken pretty-print) (chicken process) (chicken process-context) + (chicken port) (chicken string) fmt getopt-long @@ -286,19 +287,19 @@ "cc")) (out-file (if (eq? output 'default) "a.out" - output)) - (temp-c-out (create-temporary-file ".sex.c"))) - (with-output-to-file temp-c-out - (lambda () - (emit-c sex-forms))) + output))) (call-with-values (lambda () - (process compiler (append (list temp-c-out "-o" out-file "-std=c89" "-pedantic") + (process compiler (append (list "-o" out-file "-std=c89" "-pedantic" "-x" "c") (if (get-arg args 'compile-object #f) (list "-c") (list)) + (list "-") ; read stdin (get-c-compiler-args args)))) (lambda (out-port in-port pid) + (with-output-to-port in-port + (lambda () (emit-c sex-forms))) + (close-output-port in-port) (process-wait pid))))) (define (process-input input raw-forms) -- 2.52.0 From a3e9b6cb6da6dfd84ba4cfec4fdb8bb98399b7fd Mon Sep 17 00:00:00 2001 From: alex-eg Date: Fri, 22 Aug 2025 13:07:59 +0300 Subject: [PATCH 9/9] add bool true false tests --- tests/basic.scm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/basic.scm b/tests/basic.scm index 6bb3c70..7d00b3f 100644 --- a/tests/basic.scm +++ b/tests/basic.scm @@ -21,6 +21,11 @@ (test '%include (atom-to-fmt-c 'include)) (test '%cast (atom-to-fmt-c 'cast)) +;;; c89 stuff +(test 'int (atom-to-fmt-c 'bool)) +(test 1 (atom-to-fmt-c 'true)) +(test 0 (atom-to-fmt-c 'false)) + ;;; make-field-access (test 'a.b (make-field-access '(.b a))) (test 'a.b.c (make-field-access '(.c a.b))) -- 2.52.0