migrate to Chicken 6

This commit is contained in:
2026-09-09 01:09:48 +03:00
parent 9903cae3f7
commit 528f26b7ef
11 changed files with 114 additions and 50 deletions

View File

@@ -15,11 +15,11 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install chicken - name: Install chicken
run: | run: |
wget -N https://code.call-cc.org/releases/5.4.0/chicken-5.4.0.tar.gz wget -N https://code.call-cc.org/releases/6.0.0/chicken-6.0.0.tar.gz
tar zxf chicken-5.4.0.tar.gz tar zxf chicken-6.0.0.tar.gz
sudo apt install -y make sudo apt install -y make
make -C chicken-5.4.0 PLATFORM=linux make -C chicken-6.0.0 PLATFORM=linux
sudo make -C chicken-5.4.0 PLATFORM=linux install sudo make -C chicken-6.0.0 PLATFORM=linux install
- name: Install dependencies - name: Install dependencies
# FIXME: [project-local deps]: use venv or something # FIXME: [project-local deps]: use venv or something
# run: make deps # run: make deps

View File

@@ -58,7 +58,7 @@ sextest:
$(MAKE) -C ./tools/sextest sextest $(MAKE) -C ./tools/sextest sextest
cp ./tools/sextest/sextest . cp ./tools/sextest/sextest .
SEX_TEST_PROGRAMS = hello-world lists comments SEX_TEST_PROGRAMS = hello-world lists comments unicode
run-tests: sexc sex-tests sextest run-tests: sexc sex-tests sextest
./sex-tests && ./sextest --sexc=./sexc $(SEX_TEST_PROGRAMS:%=./tests/sex-programs/%.sex) ./sex-tests && ./sextest --sexc=./sexc $(SEX_TEST_PROGRAMS:%=./tests/sex-programs/%.sex)

View File

@@ -4,8 +4,8 @@
#+ATTR_HTML: :width 300px #+ATTR_HTML: :width 300px
[[sex.png][file:./sex.png]] [[sex.png][file:./sex.png]]
Sex is a S-expressions language. Sex is written in Chicken, which is a Sex is a S-expressions language. Sex is written in Chicken, which is an
[[https://call-cc.org][R5RS Scheme]]. [[https://call-cc.org][R7RS Scheme]].
Sex is statically typed, compiled general purpose language. Sex is statically typed, compiled general purpose language.
* Compilation * Compilation

View File

@@ -1 +1 @@
fmt getopt-long brev-separate test tree srfi-1 srfi-13 srfi-69 matchable fmt getopt-long brev-separate test srfi-1 srfi-13 srfi-69 matchable

View File

@@ -2,20 +2,28 @@
(import (import
scheme scheme
(scheme base) ; make-parameter
(chicken base) (chicken base)
(chicken string) (chicken string)
(chicken syntax) (chicken syntax)
brev-separate brev-separate ; fn, flatten
fmt fmt
sex-fmt-c sex-fmt-c
matchable matchable
regex (chicken irregex) ; unkebabify
srfi-1 ; lists srfi-1 ; lists
srfi-13 ; strings srfi-13 ; strings
srfi-39 ; parameters
tree
utils) utils)
;;; Map a procedure over every leaf of a tree, preserving its shape.
;;; Was the `tree' egg, which has not been ported to CHICKEN 6. (Its
;;; `flatten', also used here, comes from brev-separate.)
(define (tree-map f tree)
(cond ((null? tree) (list))
((pair? tree) (cons (tree-map f (car tree))
(tree-map f (cdr tree))))
(else (f tree))))
(define (unkebabify sym) (define (unkebabify sym)
(case sym (case sym
((-) sym) ((-) sym)
@@ -24,8 +32,7 @@
((-=) sym) ((-=) sym)
(else (else
(string->symbol (string->symbol
(string-substitute "-(?!>)" "_" (irregex-replace/all "-(?!>)" (symbol->string sym) "_")))))
(symbol->string sym) #t)))))
(define (atom-to-fmt-c atom) (define (atom-to-fmt-c atom)
(case atom (case atom

View File

@@ -12,6 +12,7 @@
(import (import
scheme scheme
(scheme base) ; make-parameter
(chicken base) (chicken base)
(chicken pathname) (chicken pathname)
utils) utils)

View File

@@ -33,6 +33,7 @@
(import (import
scheme scheme
(scheme base) ; string->utf8, bytevector accessors
(chicken base) (chicken base)
fmt fmt
srfi-1 srfi-1
@@ -138,7 +139,31 @@
(case n (case n
((7) "\\a") ((8) "\\b") ((9) "\\t") ((10) "\\n") ((7) "\\a") ((8) "\\b") ((9) "\\t") ((10) "\\n")
((11) "\\v") ((12) "\\f") ((13) "\\r") ((11) "\\v") ((12) "\\f") ((13) "\\r")
(else (string-append "\\x" (number->string (char->integer c) 16))))))) (else (c-octal-escapes c))))))
;; A character outside printable ASCII, as one three-digit octal escape
;; per UTF-8 byte.
;;
;; MODIFIED FROM UPSTREAM fmt-c, which emits "\x" plus the hex of the
;; character. C's \x escape consumes *every* following hex digit, so
;; "\xc3\xa91" is a single out-of-range value rather than two bytes
;; followed by a '1'. Under CHICKEN 6 a character is a codepoint rather
;; than a byte, so the hex form additionally emits "\xe9" for a lone
;; "e-acute" -- not valid UTF-8 -- and "\x65e5" for anything above the
;; Latin-1 range, which does not compile at all. Octal escapes are
;; capped at three digits, so they always self-terminate.
(define (c-octal-escapes c)
(let* ((bytes (string->utf8 (string c)))
(len (bytevector-length bytes)))
(let loop ((i 0) (acc '()))
(if (= i len)
(apply string-append (reverse acc))
(loop (+ i 1)
(cons (let ((oct (number->string (bytevector-u8-ref bytes i) 8)))
(string-append "\\"
(make-string (- 3 (string-length oct)) #\0)
oct))
acc))))))
(define (c-format-number x) (define (c-format-number x)
(if (and (integer? x) (exact? x)) (if (and (integer? x) (exact? x))

View File

@@ -1,4 +1,5 @@
(import scheme (import scheme
(scheme base) ; call/cc
brev-separate brev-separate
(chicken base) (chicken base)
(chicken file) (chicken file)
@@ -16,7 +17,6 @@
semen semen
srfi-1 ; list routines srfi-1 ; list routines
srfi-13 srfi-13
tree
utils) utils)
;;; Main function facilities ;;; Main function facilities
@@ -98,19 +98,20 @@
(out-file (if (eq? output 'default) (out-file (if (eq? output 'default)
"a.out" "a.out"
output))) output)))
(call-with-values ;; `process' hands back one record. Its port accessors are named
(lambda () ;; from the *child's* point of view, so `process-input-port' is the
(process compiler (append (list "-o" out-file "-x" "c") ;; port we write to: the C compiler's stdin.
(if (get-arg args 'compile-object #f) (let* ((proc (process compiler (append (list "-o" out-file "-x" "c")
(list "-c") (if (get-arg args 'compile-object #f)
(list)) (list "-c")
(list "-") ; read stdin (list))
(get-c-compiler-args args)))) (list "-") ; read stdin
(lambda (out-port in-port pid) (get-c-compiler-args args))))
(with-output-to-port in-port (cc-stdin (process-input-port proc)))
(lambda () (emit-c sex-forms))) (with-output-to-port cc-stdin
(close-output-port in-port) (lambda () (emit-c sex-forms)))
(process-wait pid))))) (close-output-port cc-stdin)
(process-wait proc))))
(define (semantic-process-forms raw-forms input-source) (define (semantic-process-forms raw-forms input-source)
(if (eq? input-source 'stdin) (if (eq? input-source 'stdin)

View File

@@ -13,6 +13,14 @@
(test '_this_->_member_ (unkebabify '-this-->-member-)) (test '_this_->_member_ (unkebabify '-this-->-member-))
(test '__->>> (unkebabify '--->>>)) (test '__->>> (unkebabify '--->>>))
;; Non-ASCII identifiers must survive intact. The `regex' egg's
;; string-substitute drops one trailing character per multi-byte
;; character, which renames things silently -- the C still compiles,
;; just under a different name than was written.
(test 'naïve_count (unkebabify 'naïve-count))
(test 'aï_b (unkebabify 'aï-b))
(test 'ïï (unkebabify 'ïï))
;; atom-to-fmt-c ;; atom-to-fmt-c
(test '%fun (atom-to-fmt-c 'fn)) (test '%fun (atom-to-fmt-c 'fn))
(test '%prototype (atom-to-fmt-c 'prototype)) (test '%prototype (atom-to-fmt-c 'prototype))

View File

@@ -0,0 +1,24 @@
(input)
(output "café 日本語 🍺" "café1" "naïve: 3")
(return 0)
;;; Non-ASCII string literals and identifiers.
;;;
;;; Two things are pinned here. First, a character outside printable
;;; ASCII must reach the C compiler as the UTF-8 bytes it was written
;;; as. Octal escapes are used because C's \x escape swallows every
;;; following hex digit: "café1" is the case that catches it, since a
;;; hex escape would run "\xc3\xa9" into the "1" and produce a value out
;;; of range for a char. Second, a kebab-case identifier containing
;;; non-ASCII characters must survive unkebabify intact -- getting this
;;; wrong truncates the name silently, and the program still compiles
;;; and runs, just under a different name than the one written.
(include stdio.h)
(pub fn main () int
(puts "café 日本語 🍺")
(puts "café1")
(var naïve-count int 3)
(printf "naïve: %d\n" naïve-count)
(return 0))

View File

@@ -38,27 +38,25 @@
(get-environment-variable "SEXC") (get-environment-variable "SEXC")
"sexc")) "sexc"))
(compiled-file (create-temporary-file))) (compiled-file (create-temporary-file)))
(call-with-values ;; `process' returns one record; `process-input-port' is named from
(fn ;; the child's side, so it is the port we write to.
(process compiler (let* ((proc (process compiler (append (list "-o" compiled-file) flags)))
(append (list "-o" compiled-file) (sexc-stdin (process-input-port proc)))
flags))) (with-output-to-port sexc-stdin
(lambda (out-port in-port pid) (fn (map (fn (fmt #t x)) src)))
(with-output-to-port in-port (close-output-port sexc-stdin)
(fn (map (fn (fmt #t x)) src))) (call-with-values
(close-output-port in-port) (fn (process-wait proc))
(lambda (pid exited retcode)
(call-with-values (if (= 0 retcode)
(fn (process-wait pid)) compiled-file
(lambda (pid exited retcode) #f))))))
(if (= 0 retcode)
compiled-file
#f)))))))
(define (run-and-check file in out ret) (define (run-and-check file in out ret)
(call-with-values (let* ((proc (process file))
(fn (process file)) (out-port (process-output-port proc)) ; the program's stdout
(lambda (out-port in-port pid) (in-port (process-input-port proc))) ; the program's stdin
(let ()
(when in (when in
(with-output-to-port in-port (with-output-to-port in-port
(fn (map (fn (fmt #t x)) (fn (map (fn (fmt #t x))
@@ -78,7 +76,7 @@
;; TODO: what if the program hangs ;; TODO: what if the program hangs
;; we need some kind of timeout mechanism ;; we need some kind of timeout mechanism
(fn (fn
(process-wait pid)) (process-wait proc))
(lambda (pid exited retcode) (lambda (pid exited retcode)
retcode)))) retcode))))
(and (and
@@ -137,7 +135,7 @@
(print-help) (print-help)
(exit 1)) (exit 1))
(unless (unless
(foldl and (foldl (lambda (a b) (and a b))
#t #t
(map (fn (process-test-file (assoc 'sexc args) x)) (map (fn (process-test-file (assoc 'sexc args) x))
(cdr (assoc '@ args)))) (cdr (assoc '@ args))))