From cb30e4a916a86797ac82c2649934a56357ddd28e Mon Sep 17 00:00:00 2001 From: alex-eg Date: Fri, 26 Sep 2025 14:50:52 +0300 Subject: [PATCH 1/4] update Readme.org --- Readme.org | 14 ++++++++------ sexc.scm | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Readme.org b/Readme.org index 9cb2da9..ef990a5 100644 --- a/Readme.org +++ b/Readme.org @@ -1,6 +1,7 @@ * The Sex language Sex is a S-expressions language. Sex is written in Chicken, which is a [[https://call-cc.org][R5RS Scheme]]. +Sex is statically typed, compiled general purpose language. * Compilation First, get yourself a Chicken, then, some Chicken deps. You also will @@ -25,10 +26,11 @@ Options: --c-compiler=ARG Select C compiler. Defaults to value of SEX_CC environment variable, or if it is empty, to cc -c, --compile-object Compile object file instead of executable program - -E, --preprocess Emit C code + -C, --preprocess Emit C code --public-interface Get module's public interface -h, --help Show this help - -m, --macro-expand Emit macro-expanded Sex code + -m, --macro-expand Emit macro-expanded semantically processed Sex code + (sort of IR). May be useful for debugging -o, --output=ARG Write output to file. Default file name is a.out. If -E or -m options are provided, defaults to stdout #+end_src @@ -71,9 +73,9 @@ Hello, Alex! Just ~(include "Your/Favourite/Library.h")~ and use it as you would have is C. -** Auto unkebabification +*** Auto kebabification For hardcore fans of traditional Lisp naming convention, -Sex offers automatic unkebabification of all symbols, i.e. no more +Sex offers automatic kebabification of all symbols, i.e. no more ugly ~GL_ARRAY_BUFFER~ s in your code, they may be written in their proper form: ~GL-ARRAY-BUFFER~. @@ -114,8 +116,8 @@ return Sex code. **** Wrapper for checking return codes #+begin_src scheme (pub defmacro (check-sdl-return call message ret-code) - `((if (< 0 ,call) - (begin + `(if (< 0 ,call) + (begin (puts ,message) (return ,ret-code))))) diff --git a/sexc.scm b/sexc.scm index cded18f..1cd80cd 100644 --- a/sexc.scm +++ b/sexc.scm @@ -41,7 +41,7 @@ (required #f) (value #f) (single-char #\h)) - (macro-expand "Emit macro-expanded Sex code" + (macro-expand "Emit macro-expanded semantically processed Sex code" (required #f) (value #f) (single-char #\m)) -- 2.52.0 From 6bf4ff5ba57ace7e33bb95742a7ee8b172db6783 Mon Sep 17 00:00:00 2001 From: alex-eg Date: Fri, 26 Sep 2025 14:51:00 +0300 Subject: [PATCH 2/4] don't force c89 after all --- sexc.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sexc.scm b/sexc.scm index 1cd80cd..9fc4e2f 100644 --- a/sexc.scm +++ b/sexc.scm @@ -99,7 +99,7 @@ output))) (call-with-values (lambda () - (process compiler (append (list "-o" out-file "-std=c89" "-pedantic" "-x" "c") + (process compiler (append (list "-o" out-file "-x" "c") (if (get-arg args 'compile-object #f) (list "-c") (list)) -- 2.52.0 From 97acf9d0f434a018a05725583d39cfb642969f34 Mon Sep 17 00:00:00 2001 From: alex-eg Date: Fri, 26 Sep 2025 16:52:34 +0300 Subject: [PATCH 3/4] enable prefix form for keywords I like writing :keyword more than #:keyword. That hash sign seems redundant --- Makefile | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index eb30c48..5702ab8 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,21 @@ CHICKEN_C = csc +CSC_FLAGS = -K prefix MODULES = sexc fmt-c fmt-c-writer semen sex-macros sex-modules sex-reader utils OBJ = $(MODULES:%=%.o) sexc: main.o $(OBJ) - $(CHICKEN_C) $^ -o $@ + $(CHICKEN_C) $(CSC_FLAGS) $^ -o $@ main.o: main.scm - $(CHICKEN_C) $< -c -o $@ + $(CHICKEN_C) $(CSC_FLAGS) $< -c -o $@ %.o: %.scm - $(CHICKEN_C) $< -e -c -o $@ + $(CHICKEN_C) $(CSC_FLAGS) $< -e -c -o $@ 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 + cd ./tests && $(CHICKEN_C) $(CSC_FLAGS) run.scm -c -o sex-tests.o + $(CHICKEN_C) $(CSC_FLAGS) $(OBJ) ./tests/sex-tests.o -o sex-tests clean: rm -f $(OBJ) sexc sex-tests main.o ./tests/sex-tests.o -- 2.52.0 From 6ac58926d90aa08a5b5e79533843466bf32b2e50 Mon Sep 17 00:00:00 2001 From: alex-eg Date: Fri, 26 Sep 2025 16:53:38 +0300 Subject: [PATCH 4/4] add initial lambda support No closures for now, but solid groundwork is laid. --- example/lambdas.sex | 31 +++++++++++++++++++ semen.scm | 74 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 example/lambdas.sex diff --git a/example/lambdas.sex b/example/lambdas.sex new file mode 100644 index 0000000..acbdfd6 --- /dev/null +++ b/example/lambdas.sex @@ -0,0 +1,31 @@ +(include stdio.h) + +(fn int sum ((int a) (int b)) + (return (+ a b))) + +(pub fn int main () + (var int a 10) + (var int b 20) + (var (fn int ((int) (int))) sum-fn sum) + + (var (fn int ((int) (int))) sum-lambda + + (lambda int ((int a) (int b)) () + (return (+ a b)))) + + (var (fn int ((int))) sum-lambda-2 + + (lambda int ((int a)) () + (return (+ a 20)))) + + (printf "Hello from main fn!\n") + (printf "We will now perform some function calling.\n") + + (printf "Calling fn ptr: %d\n" (sum-fn a b)) + (printf "Calling lambda: %d\n" (sum-lambda a b)) + (printf "Calling other lambda: %d\n" (sum-lambda-2 a)) + (printf "Calling lambda inplace: %d\n" ((lambda int ((int a) (int b)) () + (return (+ a b 100))) + a b)) + + (return 0)) diff --git a/semen.scm b/semen.scm index afdff0f..4c5a239 100644 --- a/semen.scm +++ b/semen.scm @@ -4,10 +4,13 @@ (uses sex-macros sex-modules)) -(import fmt - matchable ; pattern matching - srfi-1 ; list routines - ) +(import + (chicken string) + fmt + matchable ; pattern matching + srfi-1 ; list routines + srfi-69 ; hash tables + ) ;;; for lambda extraction, docstring processing, macro expansion, ;;; injection of module headers, i.e. all things that rearrange code @@ -83,21 +86,24 @@ "Walk the form recursively and expand all macros, until none is left." (semen-walk-form form - (lambda (subform) + (lambda (subform env) (if (sex-macro? subform) (apply-macro subform) - subform)))) + subform)) + #f)) -;;; TODO: for greater inspiration, see SBCL's walk.lisp -(define (semen-walk-form form walk-fn) +;;; TODO: for greater inspiration, see SBCL's walk.lisp and their +;;; template system. Maybe it is worth it to implement something +;;; similar here +(define (semen-walk-form form walk-fn env) (if (atom? form) form - (let ((new-form (walk-fn form))) + (let ((new-form (walk-fn form env))) (cond ((not (eq? form new-form)) - (semen-walk-form new-form walk-fn)) + (semen-walk-form new-form walk-fn env)) (else (recons new-form - (semen-walk-form (car new-form) walk-fn) - (semen-walk-form (cdr new-form) walk-fn))))))) + (semen-walk-form (car new-form) walk-fn env) + (semen-walk-form (cdr new-form) walk-fn env))))))) (define (recons old-cons new-car new-cdr) (if (and (eq? new-car (car old-cons)) @@ -105,9 +111,49 @@ old-cons (cons new-car new-cdr))) +;;; Fn processing + (define (process-fn sex-fn acc) - (let ((expanded (semen-macro-expand sex-fn))) - (cons expanded acc))) + (let* ((expanded (semen-macro-expand sex-fn)) + (env (make-hash-table)) + (processed + (semen-walk-form + expanded + semen-fn-walker + (begin + (set! (hash-table-ref env :fn-name) (sex-fn-name expanded)) + (set! (hash-table-ref env :lambda-counter) 0) + (set! (hash-table-ref env :lambda-aux-code) (list)) + env)))) + + (cons processed + (append (hash-table-ref env :lambda-aux-code) acc)))) + +(define (semen-fn-walker form env) + (if (eq? 'lambda (car form)) + (let ((lambda-name (semen-make-lambda-name (hash-table-ref env :fn-name) + (hash-table-ref env :lambda-counter)))) + (set! (hash-table-ref env :lambda-aux-code) + (cons (semen-make-aux-lambda-struct lambda-name form) + (hash-table-ref env :lambda-aux-code))) + (set! (hash-table-ref env :lambda-counter) + (+ (hash-table-ref env :lambda-counter) 1)) + lambda-name) + form)) + +(define (semen-make-lambda-name enclosing-fn-name counter) + (string->symbol + (fmt #f "__lambda_" counter "_" enclosing-fn-name))) + +(define (semen-make-aux-lambda-struct name form) + (match form + (('lambda ret-type arglist captures . body) + ;; Captures are ignored for now, but + ;; we'll need them for TODO: closures support + `(fn ,ret-type ,name ,arglist ,@body)) + (else (assert #f (fmt #f "Malformed lambda " form))))) + +;;; Struct (define (process-struct sex-struct acc) (cons sex-struct acc)) -- 2.52.0