Compare commits

..

No commits in common. "master" and "v0.36.0" have entirely different histories.

29 changed files with 118 additions and 653 deletions

View file

@ -1,27 +0,0 @@
name: C Runtime Unit Tests
#on: [create]
on: [push]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
arch: [64]
steps:
# Install dependencies
- name: Install libck
run: sudo apt-get install libck-dev
#- name: Install Cyclone
# run: |
# wget https://github.com/cyclone-scheme/binary-releases/raw/master/ubuntu-18.04-lts/cyclone-scheme_0.30.0_amd64.deb
# sudo apt install ./cyclone-scheme_0.30.0_amd64.deb
- uses: actions/checkout@v1
# Execute runtime library unit tests
- name: make test-lib
run: make libcyclone.a && make test-lib && ./test-lib

View file

@ -1,22 +0,0 @@
name: Ubuntu Linux Build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
arch: [32, 64]
steps:
- uses: actions/checkout@v1
- name: Install deps
run: sudo apt-get install indent
- name: Install ck
run: sudo apt-get install libck-dev
- name: make runtime
run: make libcyclone.a

View file

@ -16,6 +16,5 @@ jobs:
- name: Install deps - name: Install deps
run: sudo apt-get install -y indent run: sudo apt-get install -y indent
- name: formatting - name: formatting
run: | run: make test-format
make test-format

View file

@ -21,7 +21,7 @@ jobs:
- name: upload deb - name: upload deb
if: matrix.arch == '64' if: matrix.arch == '64'
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v1
with: with:
name: cyclone-scheme docs name: cyclone-scheme docs
path: html.tar.bz2 path: html.tar.bz2

View file

@ -1,21 +1,5 @@
# Changelog # Changelog
## 0.37.0 - TBD
Bug Fixes
- Yorick Hardy fixed the runtime to return the appropriate types of objects to exception handlers.
- Yorick Hardy modified the runtime to allow `thread-terminate!` to take a thread object as an argument, per SRFI 18.
- @nmeum fixed `open_memstream`/`fmemopen` feature detection with GCC >= 14.
- Fixed a bug in `apply` where an error may be raised when processing quoted sub-expressions. For example the following would throw an error: `(apply cons '(5 (1 2)))`. Thanks to @srgx for the bug report!
- Fixed a beta expansion optimization bug where code such as the following would cause the compiler to hang. Thanks to Yorick Hardy for the bug report:
(define (compile-forever x) x (compile-forever x))
- Added a fix from Yorick Hardy to define `*ai-v4mapped*` to zero on platforms where `AI_V4MAPPED` is undefined.
- Updated `sqrt` to properly handle complex results given non-complex input. EG: `(sqrt -1) ==> 1i`. And updated the parser to properly handle `+i` and `-i`. Thanks to Christopher Hebert for the bug reports!
- Updated `cond-expand` to raise an error if no clauses match, instead of returning `#t`.
## 0.36.0 - February 14, 2024 ## 0.36.0 - February 14, 2024
Features Features

View file

@ -131,10 +131,7 @@ tags :
ctags -R * ctags -R *
format : gc.c runtime.c ffi.c hashset.c mstreams.c ck-polyfill.c ck-polyfill.h $(HEADER_DIR)/*.h format : gc.c runtime.c ffi.c hashset.c mstreams.c ck-polyfill.c ck-polyfill.h $(HEADER_DIR)/*.h
$(FORMAT_CMD) $(HEADER_DIR)/hashset.h $(FORMAT_CMD) $(HEADER_DIR)/*.h
$(FORMAT_CMD) $(HEADER_DIR)/runtime.h
$(FORMAT_CMD) $(HEADER_DIR)/runtime-main.h
$(FORMAT_CMD) $(HEADER_DIR)/types.h
$(FORMAT_CMD) ck-polyfill.c $(FORMAT_CMD) ck-polyfill.c
$(FORMAT_CMD) ck-polyfill.h $(FORMAT_CMD) ck-polyfill.h
$(FORMAT_CMD) ffi.c $(FORMAT_CMD) ffi.c
@ -144,17 +141,7 @@ format : gc.c runtime.c ffi.c hashset.c mstreams.c ck-polyfill.c ck-polyfill.h $
$(FORMAT_CMD) runtime.c $(FORMAT_CMD) runtime.c
test-format : test-format :
./scripts/check-c-formatting.sh $(HEADER_DIR)/hashset.h
./scripts/check-c-formatting.sh $(HEADER_DIR)/runtime.h
./scripts/check-c-formatting.sh $(HEADER_DIR)/runtime-main.h
./scripts/check-c-formatting.sh $(HEADER_DIR)/types.h
# ./scripts/check-c-formatting.sh ffi.c
# ./scripts/check-c-formatting.sh gc.c
./scripts/check-c-formatting.sh hashset.c ./scripts/check-c-formatting.sh hashset.c
# ./scripts/check-c-formatting.sh mstreams.c
# ./scripts/check-c-formatting.sh runtime.c
# ./scripts/check-c-formatting.sh ck-polyfill.c
# ./scripts/check-c-formatting.sh ck-polyfill.h
# This is a test directive used to test changes to a SLD file # This is a test directive used to test changes to a SLD file
# EG: make sld SLDPATH=scheme/cyclone SLD=macros # EG: make sld SLDPATH=scheme/cyclone SLD=macros
@ -355,7 +342,3 @@ install-bin : cyclone icyc
$(MKDIR) $(DESTDIR)$(BINDIR) $(MKDIR) $(DESTDIR)$(BINDIR)
$(INSTALL) -m0755 cyclone $(DESTDIR)$(BINDIR)/ $(INSTALL) -m0755 cyclone $(DESTDIR)$(BINDIR)/
$(INSTALL) -m0755 icyc $(DESTDIR)$(BINDIR)/ $(INSTALL) -m0755 icyc $(DESTDIR)$(BINDIR)/
# TODO: is this linking in local lcyclone or the system one????
test-lib: test-lib.c
$(CCOMP) -g test-lib.c -o test-lib -L . $(LIBS)

View file

@ -91,9 +91,8 @@ DESTDIR ?=
# Automatically detect platform-specific flags, instead of using autoconf # Automatically detect platform-specific flags, instead of using autoconf
#CYC_PLATFORM_HAS_MEMSTREAM ?= 1 #CYC_PLATFORM_HAS_MEMSTREAM ?= 1
HASH := \# # Needed for compatibility with GNU Make < 4.3 <https://lists.gnu.org/archive/html/info-gnu/2020-01/msg00004.html> CYC_PLATFORM_HAS_MEMSTREAM := $(shell echo "main(){char *buf; int len; open_memstream(&buf, &len);}" | $(CC) -xc - >/dev/null 2>/dev/null && echo 1 || echo 0)
CYC_PLATFORM_HAS_MEMSTREAM := $(shell printf "$(HASH)include <stdio.h>\n%s\n" "int main(void){char *buf; size_t len; open_memstream(&buf, &len); return 0;}" | $(CC) -xc - >/dev/null 2>/dev/null && echo 1 || echo 0) CYC_PLATFORM_HAS_FMEMOPEN := $(shell echo "main(){char *buf; fmemopen(&buf, 0, \"r\");}" | $(CC) -xc - >/dev/null 2>/dev/null && echo 1 || echo 0)
CYC_PLATFORM_HAS_FMEMOPEN := $(shell printf "$(HASH)include <stdio.h>\n%s\n" "int main(void){char *buf; fmemopen(&buf, 0, \"r\"); return 0;}" | $(CC) -xc - >/dev/null 2>/dev/null && echo 1 || echo 0)
# code from chibi's makefile to detect platform # code from chibi's makefile to detect platform
ifndef PLATFORM ifndef PLATFORM

View file

@ -15,8 +15,3 @@ Steps for making a release of Cyclone:
- Update release on Homebrew (automated) - Update release on Homebrew (automated)
- Update release on Dockerhub (push to bitbucket) - Update release on Dockerhub (push to bitbucket)
- Upload new binary from cyclone-bootstrap release build to the cyclone-scheme "packages" repo - Upload new binary from cyclone-bootstrap release build to the cyclone-scheme "packages" repo
- Update WASM hosted Cyclone
- Trigger CI action on the WASM repo to recompile the WASM binary: https://github.com/cyclone-scheme/wasm-terminal
- Download the generated `.zip` artifact
- Extract `terminal.js` and `terminal.wasm` and copy to the `_site` directory in the repo to update the build
- Optionally update year in the `terminal.html` file

View file

@ -92,9 +92,9 @@ The current thread exits the running state as if its quantum had expired.
# thread-terminate! # thread-terminate!
(thread-terminate! thread) (thread-terminate!)
Immediately abort the given thread. Immediately abort the current thread.
# thread-join! # thread-join!

105
gc.c
View file

@ -55,7 +55,6 @@ static unsigned char gc_color_purple = 1; // There are many "shades" of pu
static int gc_status_col = STATUS_SYNC1; static int gc_status_col = STATUS_SYNC1;
static int gc_stage = STAGE_RESTING; static int gc_stage = STAGE_RESTING;
static int gc_threads_merged = 0;
// Does not need sync, only used by collector thread // Does not need sync, only used by collector thread
static void **mark_stack = NULL; static void **mark_stack = NULL;
@ -1902,38 +1901,6 @@ void gc_mut_update(gc_thread_data * thd, object old_obj, object value)
} }
} }
static void gc_sweep_primordial_thread_heap()
{
int heap_type, must_free;
gc_heap *h, *prev, *next, *sweep;
pthread_mutex_lock(&(primordial_thread->lock));
for (heap_type = 0; heap_type < NUM_HEAP_TYPES; heap_type++) {
prev = primordial_thread->heap->heap[heap_type];
h = prev->next;
while (h != NULL) {
next = h->next;
must_free = 0;
if (h->is_unswept) {
if (h->type <= LAST_FIXED_SIZE_HEAP_TYPE) {
sweep = gc_sweep_fixed_size(h, primordial_thread);
} else {
sweep = gc_sweep(h, primordial_thread);
}
must_free = (sweep == NULL);
} else {
must_free = gc_is_heap_empty(h);
}
if (must_free) {
gc_heap_free(h, prev);
} else {
prev = h;
}
h = next;
}
}
pthread_mutex_unlock(&(primordial_thread->lock));
}
/** /**
* @brief Called by a mutator to cooperate with the collector thread * @brief Called by a mutator to cooperate with the collector thread
* @param thd Mutator's thread data * @param thd Mutator's thread data
@ -1944,23 +1911,11 @@ static void gc_sweep_primordial_thread_heap()
*/ */
void gc_mut_cooperate(gc_thread_data * thd, int buf_len) void gc_mut_cooperate(gc_thread_data * thd, int buf_len)
{ {
int i, status_c, status_m, stage, merged; int i, status_c, status_m;
#if GC_DEBUG_VERBOSE #if GC_DEBUG_VERBOSE
int debug_print = 0; int debug_print = 0;
#endif #endif
// Since terminated threads' heap pages are merged into
// the primordial thread's heap, it may be that a sweep
// for the primordeal thread is never triggered even though
// the heep keeps growing. Perform a sweep here if necessary.
stage = ck_pr_load_int(&gc_stage);
merged = ck_pr_load_int(&gc_threads_merged);
if ((thd == primordial_thread) && (merged == 1)
&& ((stage == STAGE_SWEEPING) || (stage == STAGE_RESTING))) {
gc_sweep_primordial_thread_heap();
ck_pr_cas_int(&gc_threads_merged, 1, 0);
}
// Handle any pending marks from write barrier // Handle any pending marks from write barrier
gc_sum_pending_writes(thd, 0); gc_sum_pending_writes(thd, 0);
@ -2784,28 +2739,10 @@ void gc_thread_data_free(gc_thread_data * thd)
* *
* This function assumes appropriate locks are already held. * This function assumes appropriate locks are already held.
*/ */
int gc_heap_merge(gc_heap * hdest, gc_heap * hsrc) void gc_heap_merge(gc_heap * hdest, gc_heap * hsrc)
{ {
int freed = 0;
gc_heap *last = gc_heap_last(hdest); gc_heap *last = gc_heap_last(hdest);
gc_heap *cur = hsrc, *prev = last, *next;
last->next = hsrc; last->next = hsrc;
// free any empty heaps and convert remaining heaps
// to free list so that they can be swept
while (cur != NULL) {
cur->is_unswept = 1;
next = cur->next;
if (gc_is_heap_empty(cur)) {
freed += cur->size;
gc_heap_free(cur, prev);
} else {
gc_convert_heap_page_to_free_list(cur, primordial_thread);
ck_pr_cas_int(&gc_threads_merged, 0, 1);
prev = cur;
}
cur = next;
}
return freed;
} }
/** /**
@ -2818,47 +2755,15 @@ int gc_heap_merge(gc_heap * hdest, gc_heap * hsrc)
void gc_merge_all_heaps(gc_thread_data * dest, gc_thread_data * src) void gc_merge_all_heaps(gc_thread_data * dest, gc_thread_data * src)
{ {
gc_heap *hdest, *hsrc; gc_heap *hdest, *hsrc;
int freed, heap_type, i; int heap_type;
pair_type *context = NULL;
vector_type *v = src->scm_thread_obj;
// The following objects are part of the thread context and should
// be stored on the primordial thread's heap. Make this explicit by
// including it in the thread object.
if (src->gc_num_args > 0) {
for (i = src->gc_num_args - 1; i >= 0; --i) {
context = gc_alloc_pair(dest, (src->gc_args)[i], context);
}
}
if (src->gc_cont != NULL && is_object_type(src->gc_cont)) {
context = gc_alloc_pair(dest, src->gc_cont, context);
}
if (src->exception_handler_stack != NULL) {
context = gc_alloc_pair(dest, src->exception_handler_stack, context);
}
if (src->param_objs != NULL) {
context = gc_alloc_pair(dest, src->param_objs, context);
}
if (context != NULL) {
gc_mark_black(context);
v->elements[8] = context;
}
for (heap_type = 0; heap_type < NUM_HEAP_TYPES; heap_type++) { for (heap_type = 0; heap_type < NUM_HEAP_TYPES; heap_type++) {
hdest = dest->heap->heap[heap_type]; hdest = dest->heap->heap[heap_type];
hsrc = src->heap->heap[heap_type]; hsrc = src->heap->heap[heap_type];
if (!hdest) {
fprintf(stderr,
"WARNING !!!!! merging heap type %d does not happen: hdest = %p hsrc = %p size = %d\n",
heap_type, hdest, hsrc, hsrc->size);
fflush(stderr);
}
if (hdest && hsrc) { if (hdest && hsrc) {
freed = gc_heap_merge(hdest, hsrc); gc_heap_merge(hdest, hsrc);
ck_pr_add_ptr(&(dest->cached_heap_total_sizes[heap_type]), ck_pr_add_ptr(&(dest->cached_heap_total_sizes[heap_type]),
ck_pr_load_ptr(&(src->cached_heap_total_sizes[heap_type])) - ck_pr_load_ptr(&(src->cached_heap_total_sizes[heap_type])));
freed);
ck_pr_add_ptr(&(dest->cached_heap_free_sizes[heap_type]), ck_pr_add_ptr(&(dest->cached_heap_free_sizes[heap_type]),
ck_pr_load_ptr(&(src->cached_heap_free_sizes[heap_type]))); ck_pr_load_ptr(&(src->cached_heap_free_sizes[heap_type])));
} }

View file

@ -1,87 +0,0 @@
;; cyclone.scm
(use-modules
(gnu packages)
(gnu packages multiprecision)
((guix licenses)
#:select (gpl2 gpl2+ lgpl2.0+ lgpl2.1 lgpl2.1+ lgpl3+ asl2.0
bsd-0 bsd-3 cc-by-sa4.0 non-copyleft expat
public-domain))
(guix gexp)
(guix packages)
(guix download)
(guix git-download)
(guix utils)
(guix build-system gnu)
(gnu packages c))
(define-public cyclone
(package
(name "cyclone")
(version "0.36.0")
(source (origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/justinethier/cyclone-bootstrap")
(commit (string-append "v" version))))
(sha256
(base32
"0fv0mnrn5shbx77383f4mbkvc4i9yyj1bjm3dfyhipnaqapbhqpi"))
(file-name (git-file-name name version))))
(build-system gnu-build-system)
(arguments
(list
#:test-target "test"
#:make-flags #~(list (string-append
"CC=" #$(this-package-input "gcc-toolchain")
"/bin/gcc")
(string-append "PREFIX=" #$output)
(string-append "COMP_INCDIRS=-I$(PREFIX)/include -I"
#$(this-package-input "gcc-toolchain")
"/include")
(string-append
"COMP_LIBDIRS=-L$(PREFIX)/lib "
"-Wl,-rpath=" #$(this-package-input "ck") "/lib "
"-L" #$(this-package-input "ck") "/lib "
"-Wl,-rpath=" #$(this-package-input "libtommath")
"/lib "
"-L" #$(this-package-input "libtommath") "/lib "
"-Wl,-rpath="
#$(this-package-input "gcc-toolchain") "/lib "
"-L" #$(this-package-input "gcc-toolchain")
"/lib"))
#:phases #~(modify-phases %standard-phases
(delete 'configure) ; no configure script
(add-before 'build 'replace-cyclonebn
(lambda* (#:key outputs #:allow-other-keys)
(substitute* "Makefile"
(("-lcyclonebn")
"-ltommath")
(("^[$][(]CYC_BN_LIB[)] :")
"dont-build-cyclonebn :")
(("^ [$][(]INSTALL[)] .* [$][(]CYC_BN_LIB[)].*$")
"#dont-install-cyclonebn\n")
(("[$][(]CYC_BN_LIB[)]")
""))
(substitute* "Makefile.config"
(("-lcyclonebn")
"-ltommath"))))
(add-after 'install 'wrap
(lambda _
(wrap-program (string-append #$output "/bin/cyclone")
`("LIBRARY_PATH" ":" prefix
,(list (string-append
#$(this-package-input "gcc-toolchain")
"/lib")))))))))
(inputs (list ck libtommath (module-ref (resolve-interface
'(gnu packages commencement))
'gcc-toolchain)))
(home-page "https://justinethier.github.io/cyclone/")
(synopsis "R7RS Scheme to C compiler")
(description
"Cyclone Scheme is a R7RS Scheme-to-C compiler that uses a variant of
Cheney on the MTA to implement full tail recursion, continuations, and
generational garbage collection. It also includes the Winds package manager
for installing Cyclone libraries.")
(license expat)))
cyclone

View file

@ -256,7 +256,7 @@ extern "C" {
/* callback for mp_prime_random, should fill dst with random bytes and return how many read [upto len] */ /* callback for mp_prime_random, should fill dst with random bytes and return how many read [upto len] */
typedef int private_mp_prime_callback(unsigned char *dst, int len, void *dat); typedef int private_mp_prime_callback(unsigned char *dst, int len, void *dat);
typedef private_mp_prime_callback MP_DEPRECATED(mp_rand_source) typedef private_mp_prime_callback MP_DEPRECATED(mp_rand_source)
ltm_prime_callback; ltm_prime_callback;
/* error code to char* string */ /* error code to char* string */
const char *mp_error_to_string(mp_err code) MP_WUR; const char *mp_error_to_string(mp_err code) MP_WUR;
@ -766,14 +766,15 @@ extern "C" {
MP_DEPRECATED(mp_ubin_size) int mp_unsigned_bin_size(const mp_int * MP_DEPRECATED(mp_ubin_size) int mp_unsigned_bin_size(const mp_int *
a) MP_WUR; a) MP_WUR;
MP_DEPRECATED(mp_from_ubin) mp_err mp_read_unsigned_bin(mp_int * a, const unsigned char MP_DEPRECATED(mp_from_ubin) mp_err mp_read_unsigned_bin(mp_int * a,
const unsigned char
*b, int c) MP_WUR; *b, int c) MP_WUR;
MP_DEPRECATED(mp_to_ubin) mp_err mp_to_unsigned_bin(const mp_int * a, MP_DEPRECATED(mp_to_ubin) mp_err mp_to_unsigned_bin(const mp_int * a,
unsigned char *b) MP_WUR; unsigned char *b) MP_WUR;
MP_DEPRECATED(mp_to_ubin) mp_err mp_to_unsigned_bin_n(const mp_int * a, MP_DEPRECATED(mp_to_ubin) mp_err mp_to_unsigned_bin_n(const mp_int * a,
unsigned char *b, unsigned char *b,
unsigned long *outlen) unsigned long *outlen)
MP_WUR; MP_WUR;
MP_DEPRECATED(mp_sbin_size) int mp_signed_bin_size(const mp_int * a) MP_WUR; MP_DEPRECATED(mp_sbin_size) int mp_signed_bin_size(const mp_int * a) MP_WUR;
MP_DEPRECATED(mp_from_sbin) mp_err mp_read_signed_bin(mp_int * a, MP_DEPRECATED(mp_from_sbin) mp_err mp_read_signed_bin(mp_int * a,
@ -784,7 +785,7 @@ extern "C" {
MP_DEPRECATED(mp_to_sbin) mp_err mp_to_signed_bin_n(const mp_int * a, MP_DEPRECATED(mp_to_sbin) mp_err mp_to_signed_bin_n(const mp_int * a,
unsigned char *b, unsigned char *b,
unsigned long *outlen) unsigned long *outlen)
MP_WUR; MP_WUR;
size_t mp_ubin_size(const mp_int * a) MP_WUR; size_t mp_ubin_size(const mp_int * a) MP_WUR;
mp_err mp_from_ubin(mp_int * a, const unsigned char *buf, size_t size) MP_WUR; mp_err mp_from_ubin(mp_int * a, const unsigned char *buf, size_t size) MP_WUR;

View file

@ -385,7 +385,7 @@ int gc_is_mutator_new(gc_thread_data * thd);
void gc_sleep_ms(int ms); void gc_sleep_ms(int ms);
gc_heap *gc_heap_create(int heap_type, size_t size, gc_thread_data * thd); gc_heap *gc_heap_create(int heap_type, size_t size, gc_thread_data * thd);
gc_heap *gc_heap_free(gc_heap * page, gc_heap * prev_page); gc_heap *gc_heap_free(gc_heap * page, gc_heap * prev_page);
int gc_heap_merge(gc_heap * hdest, gc_heap * hsrc); void gc_heap_merge(gc_heap * hdest, gc_heap * hsrc);
void gc_merge_all_heaps(gc_thread_data * dest, gc_thread_data * src); void gc_merge_all_heaps(gc_thread_data * dest, gc_thread_data * src);
void gc_print_stats(gc_heap * h); void gc_print_stats(gc_heap * h);
gc_heap *gc_grow_heap(gc_heap * h, size_t size, gc_thread_data * thd); gc_heap *gc_grow_heap(gc_heap * h, size_t size, gc_thread_data * thd);
@ -1261,9 +1261,6 @@ typedef pair_type *pair;
n->pair_car = a; \ n->pair_car = a; \
n->pair_cdr = d; n->pair_cdr = d;
/** Create a new pair in the thread's heap */
void *gc_alloc_pair(gc_thread_data * data, object head, object tail);
/** /**
* Set members of the given pair * Set members of the given pair
* @param n - Pointer to a pair object * @param n - Pointer to a pair object

141
runtime.c
View file

@ -8,7 +8,6 @@
* This file contains the C runtime used by compiled programs. * This file contains the C runtime used by compiled programs.
*/ */
#include <assert.h>
#include <ck_hs.h> #include <ck_hs.h>
#include <ck_ht.h> #include <ck_ht.h>
#include <ck_pr.h> #include <ck_pr.h>
@ -30,8 +29,6 @@ static uint32_t Cyc_utf8_decode(uint32_t * state, uint32_t * codep,
static int Cyc_utf8_count_code_points_and_bytes(uint8_t * s, static int Cyc_utf8_count_code_points_and_bytes(uint8_t * s,
char_type * codepoint, char_type * codepoint,
int *cpts, int *bytes); int *cpts, int *bytes);
void gc_start_major_collection(gc_thread_data * thd);
static void Cyc_cancel_thread(gc_thread_data * thd);
/* Error checking section - type mismatch, num args, etc */ /* Error checking section - type mismatch, num args, etc */
/* Type names to use for error messages */ /* Type names to use for error messages */
@ -214,8 +211,6 @@ const object Cyc_RECORD_MARKER = &__RECORD;
static ck_hs_t lib_table; static ck_hs_t lib_table;
static ck_hs_t symbol_table; static ck_hs_t symbol_table;
static int symbol_table_initial_size = 4096; static int symbol_table_initial_size = 4096;
static int cyclone_thread_key_create = 1;
static pthread_key_t cyclone_thread_key;
static pthread_mutex_t symbol_table_lock; static pthread_mutex_t symbol_table_lock;
char **env_variables = NULL; char **env_variables = NULL;
@ -706,30 +701,24 @@ object Cyc_default_exception_handler(void *data, object _, int argc,
{ {
object err = args[0]; object err = args[0];
int is_msg = 1; int is_msg = 1;
fprintf(stderr, "Error: ");
if ((err == NULL) || is_value_type(err) || type_of(err) != pair_tag || type_of(car(err)) != symbol_tag) { if ((err == NULL) || is_value_type(err) || type_of(err) != pair_tag) {
fprintf(stderr, "Error: ");
Cyc_display(data, err, stderr); Cyc_display(data, err, stderr);
} else { } else {
if (strncmp(((symbol) car(err))->desc, "error", 5) == 0) { // Error is list of form (type arg1 ... argn)
fprintf(stderr, "Error: "); err = cdr(err); // skip type field
// Error is list of form (type arg1 ... argn) for (; (err != NULL); err = cdr(err)) { // output with no enclosing parens
err = cdr(err); // skip type field if (is_msg && is_object_type(car(err)) && type_of(car(err)) == string_tag) {
for (; (err != NULL); err = cdr(err)) { // output with no enclosing parens is_msg = 0;
if (is_msg && is_object_type(car(err)) && type_of(car(err)) == string_tag) { Cyc_display(data, car(err), stderr);
is_msg = 0; if (cdr(err)) {
Cyc_display(data, car(err), stderr); fprintf(stderr, ": ");
if (cdr(err)) {
fprintf(stderr, ": ");
}
} else {
Cyc_write(data, car(err), stderr);
fprintf(stderr, " ");
} }
} else {
Cyc_write(data, car(err), stderr);
fprintf(stderr, " ");
} }
} else {
fprintf(stderr, "Error: ");
Cyc_display(data, cdr(err), stderr);
} }
} }
@ -5371,7 +5360,7 @@ void _Cyc_91end_91thread_67(void *data, object clo, int argc, object * args)
vector_type *v = d->scm_thread_obj; vector_type *v = d->scm_thread_obj;
v->elements[7] = args[0]; // Store thread result v->elements[7] = args[0]; // Store thread result
Cyc_end_thread(d); Cyc_end_thread((gc_thread_data *) data);
object cont = args[0]; object cont = args[0];
return_closcall1(data, cont, boolean_f); return_closcall1(data, cont, boolean_f);
} }
@ -6423,16 +6412,15 @@ int gc_minor(void *data, object low_limit, object high_limit, closure cont,
exit(1); exit(1);
} }
if (cont != NULL) { gc_move2heap(cont);
gc_move2heap(cont); ((gc_thread_data *) data)->gc_cont = cont;
((gc_thread_data *) data)->gc_cont = cont; ((gc_thread_data *) data)->gc_num_args = num_args;
((gc_thread_data *) data)->gc_num_args = num_args;
for (i = 0; i < num_args; i++) { for (i = 0; i < num_args; i++) {
gc_move2heap(args[i]); gc_move2heap(args[i]);
((gc_thread_data *) data)->gc_args[i] = args[i]; ((gc_thread_data *) data)->gc_args[i] = args[i];
}
} }
// Transport exception stack // Transport exception stack
gc_move2heap(((gc_thread_data *) data)->exception_handler_stack); gc_move2heap(((gc_thread_data *) data)->exception_handler_stack);
gc_move2heap(((gc_thread_data *) data)->param_objs); gc_move2heap(((gc_thread_data *) data)->param_objs);
@ -6569,13 +6557,8 @@ void GC(void *data, closure cont, object * args, int num_args)
#ifdef CYC_HIGH_RES_TIMERS #ifdef CYC_HIGH_RES_TIMERS
hrt_log_delta("minor gc", tstamp); hrt_log_delta("minor gc", tstamp);
#endif #endif
// if this thread has a continuation (i.e. it is not cancelled) // Let it all go, Neo...
// then we can continue after the minor GC, otherwise we return longjmp(*(((gc_thread_data *) data)->jmp_start), 1);
// to the destructor which initiated the minor GC.
if (cont != NULL) {
// Let it all go, Neo...
longjmp(*(((gc_thread_data *) data)->jmp_start), 1);
}
} }
/** /**
@ -6615,8 +6598,9 @@ void Cyc_make_shared_object(void *data, object k, object obj)
case port_tag: case port_tag:
case c_opaque_tag: case c_opaque_tag:
case complex_num_tag:{ case complex_num_tag:{
object hp = gc_alloc(heap, gc_allocated_bytes(obj, NULL, NULL), obj, thd, object hp =
heap_grown); gc_alloc(heap, gc_allocated_bytes(obj, NULL, NULL), obj, thd,
heap_grown);
return_closcall1(data, k, hp); return_closcall1(data, k, hp);
} }
// Objs w/children force minor GC to guarantee everything is relocated: // Objs w/children force minor GC to guarantee everything is relocated:
@ -6801,8 +6785,7 @@ static primitive_type Cyc_91installation_91dir_primitive =
{ {0}, primitive_tag, &_Cyc_91installation_91dir, "Cyc-installation-dir" }; { {0}, primitive_tag, &_Cyc_91installation_91dir, "Cyc-installation-dir" };
static primitive_type Cyc_91compilation_91environment_primitive = static primitive_type Cyc_91compilation_91environment_primitive =
{ {0}, primitive_tag, &_Cyc_91compilation_91environment, { {0}, primitive_tag, &_Cyc_91compilation_91environment,
"Cyc-compilation-environment" "Cyc-compilation-environment" };
};
static primitive_type command_91line_91arguments_primitive = static primitive_type command_91line_91arguments_primitive =
{ {0}, primitive_tag, &_command_91line_91arguments, "command-line-arguments" { {0}, primitive_tag, &_command_91line_91arguments, "command-line-arguments"
}; };
@ -6883,12 +6866,10 @@ static primitive_type open_91output_91file_primitive =
{ {0}, primitive_tag, &_open_91output_91file, "open-output-file" }; { {0}, primitive_tag, &_open_91output_91file, "open-output-file" };
static primitive_type open_91binary_91input_91file_primitive = static primitive_type open_91binary_91input_91file_primitive =
{ {0}, primitive_tag, &_open_91binary_91input_91file, { {0}, primitive_tag, &_open_91binary_91input_91file,
"open-binary-input-file" "open-binary-input-file" };
};
static primitive_type open_91binary_91output_91file_primitive = static primitive_type open_91binary_91output_91file_primitive =
{ {0}, primitive_tag, &_open_91binary_91output_91file, { {0}, primitive_tag, &_open_91binary_91output_91file,
"open-binary-output-file" "open-binary-output-file" };
};
static primitive_type close_91port_primitive = static primitive_type close_91port_primitive =
{ {0}, primitive_tag, &_close_91port, "close-port" }; { {0}, primitive_tag, &_close_91port, "close-port" };
static primitive_type close_91input_91port_primitive = static primitive_type close_91input_91port_primitive =
@ -6897,8 +6878,7 @@ static primitive_type close_91output_91port_primitive =
{ {0}, primitive_tag, &_close_91output_91port, "close-output-port" }; { {0}, primitive_tag, &_close_91output_91port, "close-output-port" };
static primitive_type Cyc_91flush_91output_91port_primitive = static primitive_type Cyc_91flush_91output_91port_primitive =
{ {0}, primitive_tag, &_Cyc_91flush_91output_91port, { {0}, primitive_tag, &_Cyc_91flush_91output_91port,
"Cyc-flush-output-port" "Cyc-flush-output-port" };
};
static primitive_type file_91exists_127_primitive = static primitive_type file_91exists_127_primitive =
{ {0}, primitive_tag, &_file_91exists_127, "file-exists?" }; { {0}, primitive_tag, &_file_91exists_127, "file-exists?" };
static primitive_type delete_91file_primitive = static primitive_type delete_91file_primitive =
@ -7145,12 +7125,6 @@ void *Cyc_init_thread(object thread_and_thunk, int argc, object * args)
gc_add_mutator(thd); gc_add_mutator(thd);
ck_pr_cas_int((int *)&(thd->thread_state), CYC_THREAD_STATE_NEW, ck_pr_cas_int((int *)&(thd->thread_state), CYC_THREAD_STATE_NEW,
CYC_THREAD_STATE_RUNNABLE); CYC_THREAD_STATE_RUNNABLE);
if (ck_pr_cas_int(&cyclone_thread_key_create, 1, 0)) {
int r = pthread_key_create(&cyclone_thread_key,
(void (*)(void *))Cyc_cancel_thread);
assert(r == 0);
}
pthread_setspecific(cyclone_thread_key, thd);
Cyc_start_trampoline(thd); Cyc_start_trampoline(thd);
return NULL; return NULL;
} }
@ -7207,25 +7181,9 @@ void Cyc_exit_thread(void *data, object _, int argc, object * args)
gc_remove_mutator(thd); gc_remove_mutator(thd);
ck_pr_cas_int((int *)&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE, ck_pr_cas_int((int *)&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE,
CYC_THREAD_STATE_TERMINATED); CYC_THREAD_STATE_TERMINATED);
gc_start_major_collection(thd);
pthread_exit(NULL); pthread_exit(NULL);
} }
/**
* Cancel a thread
*/
static void Cyc_cancel_thread(gc_thread_data * thd)
{
// do a minor GC without a continuation, so that we return
// here without performing a longjmp
GC(thd, (closure) NULL, (object *) NULL, 0);
if (gc_is_mutator_active(thd)) {
gc_remove_mutator(thd);
}
ck_pr_cas_int((int *)&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE,
CYC_THREAD_STATE_TERMINATED);
}
/** /**
* @brief Accept a number of seconds to sleep according to SRFI-18 * @brief Accept a number of seconds to sleep according to SRFI-18
*/ */
@ -7578,11 +7536,11 @@ static void _read_add_to_tok_buf(port_type * p, char c)
*/ */
static int _read_is_numeric(const char *tok, int len) static int _read_is_numeric(const char *tok, int len)
{ {
return (len && ((isdigit(tok[0])) || (((len == 2) && tok[1] == 'i') return (len &&
&& (tok[0] == '-' || tok[0] == '+')) || ((isdigit(tok[0])) ||
((len > 1) && tok[0] == '.' && isdigit(tok[1])) || ((len > 1) && tok[0] == '.' && isdigit(tok[1])) ||
((len > 1) && (tok[1] == '.' || isdigit(tok[1])) ((len > 1) && (tok[1] == '.' || isdigit(tok[1]))
&& (tok[0] == '-' || tok[0] == '+')))); && (tok[0] == '-' || tok[0] == '+'))));
} }
/** /**
@ -7973,6 +7931,9 @@ static void _read_return_number(void *data, port_type * p, int base, int exact)
*/ */
static void _read_return_complex_number(void *data, port_type * p, int len) static void _read_return_complex_number(void *data, port_type * p, int len)
{ {
// TODO: return complex num, see _read_return_number for possible template
// probably want to have that function extract/identify the real/imaginary components.
// can just scan the buffer and read out start/end index of each number.
int i; int i;
make_empty_vector(vec); make_empty_vector(vec);
make_string(str, p->tok_buf); make_string(str, p->tok_buf);
@ -8541,32 +8502,32 @@ static const uint8_t utf8d[] = {
// The first part of the table maps bytes to character classes that // The first part of the table maps bytes to character classes that
// to reduce the size of the transition table and create bitmasks. // to reduce the size of the transition table and create bitmasks.
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
// The second part is a transition table that maps a combination // The second part is a transition table that maps a combination
// of a state of the automaton and a character class to a state. // of a state of the automaton and a character class to a state.
0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, 12, 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12,
12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24,
12, 24, 12, 12, 12, 24, 12, 12,
12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12,
12, 12, 24, 12, 12, 12, 12, 24, 12, 12,
12, 12, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12,
36, 12, 36, 12, 12, 36, 12, 36, 12, 12,
12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
}; };
@ -8806,7 +8767,7 @@ int num2ratio(double x, double *numerator, double *denominator)
double round_to_nearest_even(double x) double round_to_nearest_even(double x)
{ {
return x - remainder(x, 1.0); return x-remainder(x,1.0);
} }
/** /**

View file

@ -407,7 +407,7 @@
(else (error "cond-expand: bad feature" x))) (else (error "cond-expand: bad feature" x)))
(memq x (features)))) (memq x (features))))
(let expand ((ls (cdr expr))) (let expand ((ls (cdr expr)))
(cond ((null? ls) (error "cond-expand: no expansions" expr)) (cond ((null? ls)) ; (error "cond-expand: no expansions" expr)
((not (pair? (car ls))) (error "cond-expand: bad clause" (car ls))) ((not (pair? (car ls))) (error "cond-expand: bad clause" (car ls)))
((eq? 'else (caar ls)) ;(identifier->symbol (caar ls))) ((eq? 'else (caar ls)) ;(identifier->symbol (caar ls)))
(if (pair? (cdr ls)) (if (pair? (cdr ls))
@ -1251,16 +1251,13 @@
(define error-object-message car) (define error-object-message car)
(define error-object-irritants cdr) (define error-object-irritants cdr)
(define (error msg . args) (define (error msg . args)
(raise-error (cons msg args))) (raise (cons msg args)))
(define (raise obj) (define (raise obj)
((Cyc-current-exception-handler) ((Cyc-current-exception-handler)
(cons 'raised obj))) (cons 'raised (if (pair? obj) obj (list obj)))))
(define (raise-continuable obj) (define (raise-continuable obj)
((Cyc-current-exception-handler) ((Cyc-current-exception-handler)
(cons 'continuable obj))) (cons 'continuable (if (pair? obj) obj (list obj)))))
(define (raise-error obj)
((Cyc-current-exception-handler)
(cons 'error obj)))
;; A simpler exception handler based on the one from Bigloo: ;; A simpler exception handler based on the one from Bigloo:
;; https://www-sop.inria.fr/indes/fp/Bigloo/doc/bigloo-17.html#g20889 ;; https://www-sop.inria.fr/indes/fp/Bigloo/doc/bigloo-17.html#g20889
;(define (with-handler handler body) ;(define (with-handler handler body)
@ -1440,10 +1437,10 @@
(error "exact non-negative integer required" k)) (error "exact non-negative integer required" k))
(let* ((s (if (bignum? k) (let* ((s (if (bignum? k)
(bignum-sqrt k) (bignum-sqrt k)
(exact (truncate (_sqrt k))))) (exact (truncate (sqrt k)))))
(r (- k (* s s)))) (r (- k (* s s))))
(values s r))) (values s r)))
(define-c _sqrt (define-c sqrt
"(void *data, int argc, closure _, object k, object z)" "(void *data, int argc, closure _, object k, object z)"
" return_inexact_double_op(data, k, sqrt, z);" " return_inexact_double_op(data, k, sqrt, z);"
"(void *data, object ptr, object z)" "(void *data, object ptr, object z)"

View file

@ -18,7 +18,7 @@
memloc memloc
) )
(begin (begin
(define *version-number* "0.37.0") (define *version-number* "0.36.0")
(define *version-name* "") (define *version-name* "")
(define *version* (string-append *version-number* " " *version-name* "")) (define *version* (string-append *version-number* " " *version-name* ""))
@ -32,7 +32,7 @@
@@ @@ Cyclone Scheme->C compiler @@ @@ Cyclone Scheme->C compiler
,@ http://justinethier.github.io/cyclone/ ,@ http://justinethier.github.io/cyclone/
'@ '@
.@ (c) 2014-2025 Justin Ethier .@ (c) 2014-2024 Justin Ethier
@@ #@ Version " *version* " @@ #@ Version " *version* "
`@@@#@@@. `@@@#@@@.
#@@@@@ #@@@@@

View file

@ -20,8 +20,7 @@
(srfi 2) (srfi 2)
(srfi 69) (srfi 69)
) )
) ))
(else #f))
;; symbol -> hash-table -> boolean ;; symbol -> hash-table -> boolean
;; Is it OK to inline code replacing ref, based on call graph data from lookup table? ;; Is it OK to inline code replacing ref, based on call graph data from lookup table?
@ -262,5 +261,4 @@
; (ast:ast->pp-sexp ; (ast:ast->pp-sexp
; (opt:local-var-reduction (ast:sexp->ast sexp))) ; (opt:local-var-reduction (ast:sexp->ast sexp)))
;) ;)
) ))
(else #f))

View file

@ -14,9 +14,7 @@
(scheme cyclone ast) (scheme cyclone ast)
(scheme cyclone primitives) (scheme cyclone primitives)
(scheme cyclone util) (scheme cyclone util)
(scheme cyclone pretty-print))) (scheme cyclone pretty-print))))
(else
#f))
;; Local variable reduction: ;; Local variable reduction:
;; Reduce given sexp by replacing certain lambda calls with a let containing ;; Reduce given sexp by replacing certain lambda calls with a let containing
@ -436,5 +434,4 @@
(ast:ast->pp-sexp (ast:ast->pp-sexp
(opt:local-var-reduction (ast:sexp->ast sexp))) (opt:local-var-reduction (ast:sexp->ast sexp)))
) )
) ))
(else #f))

View file

@ -18,9 +18,9 @@
(scheme cyclone util) (scheme cyclone util)
(scheme cyclone pretty-print) (scheme cyclone pretty-print)
(srfi 2) (srfi 2)
(srfi 69))) (srfi 69)
(else )
#f)) ))
;; Predicate to determine if a function can be memoized ;; Predicate to determine if a function can be memoized
;; var - symbol - global name of the function ;; var - symbol - global name of the function
@ -371,5 +371,4 @@
;; ; (ast:ast->pp-sexp ;; ; (ast:ast->pp-sexp
;; ; (opt:local-var-reduction (ast:sexp->ast sexp))) ;; ; (opt:local-var-reduction (ast:sexp->ast sexp)))
;; ;) ;; ;)
) ))
(else #f))

View file

@ -1665,7 +1665,7 @@
;; Full beta expansion phase, make a pass over all of the program's AST ;; Full beta expansion phase, make a pass over all of the program's AST
(define (opt:beta-expand exp) (define (opt:beta-expand exp)
;(trace:info `(opt:beta-expand ,exp)) (flush-output-port) ;(write `(DEBUG opt:beta-expand ,exp)) (newline)
(cond (cond
((ast:lambda? exp) ((ast:lambda? exp)
(ast:%make-lambda (ast:%make-lambda
@ -1694,7 +1694,6 @@
(else exp))) (else exp)))
(define (analyze-cps exp) (define (analyze-cps exp)
;(trace:info `(analyze-cps ,exp))
(analyze:find-named-lets exp) (analyze:find-named-lets exp)
(analyze:find-direct-recursive-calls exp) (analyze:find-direct-recursive-calls exp)
(analyze:find-recursive-calls exp) (analyze:find-recursive-calls exp)
@ -2231,17 +2230,11 @@
(scan (if->then exp) def-sym) (scan (if->then exp) def-sym)
(scan (if->else exp) def-sym)) (scan (if->else exp) def-sym))
((app? exp) ((app? exp)
;(trace:info `(analyze:find-recursive-calls scan app ,exp)) (when (equal? (car exp) def-sym)
(cond (trace:info `("recursive call" ,exp))
((equal? (car exp) def-sym) (with-var! def-sym (lambda (var)
(trace:info `("recursive call" ,exp)) (adbv:set-self-rec-call! var #t)))
(with-var! def-sym (lambda (var) ))
(adbv:set-self-rec-call! var #t))))
(else
(for-each
(lambda (e)
(scan e def-sym))
exp))))
(else #f))) (else #f)))
;; TODO: probably not good enough, what about recursive functions that are not top-level?? ;; TODO: probably not good enough, what about recursive functions that are not top-level??

View file

@ -14,8 +14,7 @@
(scheme base) (scheme base)
(scheme read) (scheme read)
(scheme cyclone pretty-print) (scheme cyclone pretty-print)
(scheme cyclone util))) (scheme cyclone util))))
(else #f))
;; ;;
;; TODO: call this from cyclone.scm after it works, probably after "resolve macros" ;; TODO: call this from cyclone.scm after it works, probably after "resolve macros"
@ -60,9 +59,7 @@
(define (search exp vars) (define (search exp vars)
(cond-expand (cond-expand
(program (program
(pretty-print `(search ,exp ,vars))(newline)) ;; Debugging (pretty-print `(search ,exp ,vars))(newline))) ;; Debugging
(else
#f))
(cond (cond
;((ast:lambda? exp) 'TODO) ;((ast:lambda? exp) 'TODO)
((const? exp) #f) ((const? exp) #f)
@ -114,5 +111,4 @@
;(if 1 2 3 4) ;(if 1 2 3 4)
(let ((sexp (read-all (open-input-file "validation.scm")))) (let ((sexp (read-all (open-input-file "validation.scm"))))
(validate-keyword-syntax sexp))) (validate-keyword-syntax sexp))))
(else #f))

View file

@ -89,26 +89,17 @@
((analyze exp *global-environment* rename-env '()) *global-environment*) ((analyze exp *global-environment* rename-env '()) *global-environment*)
((analyze exp (car env) rename-env '()) (car env)))) ((analyze exp (car env) rename-env '()) (car env))))
;; Called from the C runtime to support apply
(define (eval-from-c exp . _env) (define (eval-from-c exp . _env)
(let ((env (if (null? _env) *global-environment* (car _env)))) (let ((env (if (null? _env) *global-environment* (car _env))))
(eval (wrapc exp) env))) (eval (wrapc exp) env)))
;; Helper function for eval-from-c ;; Expressions received from C code are already evaluated, but sometimes too much so.
;; ;; Try to wrap
;; Expressions received from C code are already evaluated,
;; however any quoted expressions will have the quotes
;; stripped off. This is a problem for expressions that
;; aren't self evaluating - like (1 2) - so we re-quote
;; the expressions here so a subsequent eval will work.
;;
(define (wrapc exp) (define (wrapc exp)
(cond (cond
((application? exp) ((application? exp)
(cond (cond
((or (primitive-procedure? (car exp)) ((compound-procedure? (car exp))
(compound-procedure? (car exp))
(procedure? (car exp)))
(cons (cons
(car exp) (car exp)
(map (map

View file

@ -69,6 +69,7 @@
(/ (c-log z1) (c-log z2*))))) (/ (c-log z1) (c-log z2*)))))
(define-inexact-op c-log "log" "clog") (define-inexact-op c-log "log" "clog")
(define-inexact-op exp "exp" "cexp") (define-inexact-op exp "exp" "cexp")
(define-inexact-op sqrt "sqrt" "csqrt")
(define-inexact-op sin "sin" "csin") (define-inexact-op sin "sin" "csin")
(define-inexact-op cos "cos" "ccos") (define-inexact-op cos "cos" "ccos")
(define-inexact-op tan "tan" "ctan") (define-inexact-op tan "tan" "ctan")
@ -92,58 +93,4 @@
(* (if (eqv? y -0.0) -1 1) (* (if (eqv? y -0.0) -1 1)
(if (eqv? x -0.0) 3.141592653589793 x)) (if (eqv? x -0.0) 3.141592653589793 x))
(atan1 (/ y x)))))))) (atan1 (/ y x))))))))
(define-c
sqrt
"(void *data, int argc, closure _, object k, object z)"
" double complex result;
Cyc_check_num(data, z);
if (obj_is_int(z)) {
result = csqrt(obj_obj2int(z));
} else if (type_of(z) == integer_tag) {
result = csqrt(((integer_type *)z)->value);
} else if (type_of(z) == bignum_tag) {
result = csqrt(mp_get_double(&bignum_value(z)));
} else if (type_of(z) == complex_num_tag) {
result = csqrt(complex_num_value(z));
} else {
result = csqrt(((double_type *)z)->value);
}
if (cimag(result) == 0.0) {
if (obj_is_int(z) && creal(result) == round(creal(result))) {
return_closcall1(data, k, obj_int2obj(creal(result)));
}
make_double(d, creal(result));
return_closcall1(data, k, &d);
} else {
complex_num_type cn;
assign_complex_num((&cn), result);
return_closcall1(data, k, &cn);
} "
"(void *data, object ptr, object z)"
" double complex result;
Cyc_check_num(data, z);
if (obj_is_int(z)) {
result = csqrt(obj_obj2int(z));
} else if (type_of(z) == integer_tag) {
result = csqrt(((integer_type *)z)->value);
} else if (type_of(z) == bignum_tag) {
result = csqrt(mp_get_double(&bignum_value(z)));
} else if (type_of(z) == complex_num_tag) {
result = csqrt(complex_num_value(z));
} else {
result = csqrt(((double_type *)z)->value);
}
if (cimag(result) == 0.0) {
if (obj_is_int(z) && creal(result) == round(creal(result))) {
return obj_int2obj(creal(result));
}
assign_double(ptr, creal(result));
} else {
assign_complex_num(ptr, result);
}
return ptr;
")
)) ))

View file

@ -294,10 +294,7 @@
(substring t 0 end) (substring t 0 end)
(substring t end (- len 1)))) (substring t end (- len 1))))
(real (string->number real-str)) (real (string->number real-str))
(imag (cond (imag (string->number imag-str))
((equal? "+" imag-str) 1) ;; Special case, +i w/no number
((equal? "-" imag-str) -1) ;; Special case, -i
(else (string->number imag-str))))
) )
(Cyc-make-rect real imag))) (Cyc-make-rect real imag)))
(else (else

View file

@ -20,9 +20,9 @@
(define (repl) (define (repl)
(with-handler (with-handler
(lambda (obj) (lambda (obj)
(display "Error: ")
(cond (cond
((error-object? obj) ((error-object? obj)
(display "Error: ")
(display (error-object-message obj)) (display (error-object-message obj))
(if (not (null? (error-object-irritants obj))) (if (not (null? (error-object-irritants obj)))
(display ": ")) (display ": "))
@ -31,8 +31,18 @@
(write o) (write o)
(display " ")) (display " "))
(error-object-irritants obj))) (error-object-irritants obj)))
((pair? obj)
(when (string? (car obj))
(display (car obj))
(if (not (null? (cdr obj)))
(display ": "))
(set! obj (cdr obj)))
(for-each
(lambda (o)
(write o)
(display " "))
obj))
(else (else
(display "Error: ")
(display obj))) (display obj)))
(newline) (newline)
(repl)) (repl))

View file

@ -388,7 +388,7 @@
#ifdef AI_V4MAPPED #ifdef AI_V4MAPPED
return_closcall1(data, k, obj_int2obj(AI_V4MAPPED)); return_closcall1(data, k, obj_int2obj(AI_V4MAPPED));
#else #else
return_closcall1(data, k, obj_int2obj(0)); Cyc_rt_raise_msg(data, \"AI_V4MAPPED is not available on this platform\");
#endif #endif
") ")
(define *ai-all* (ai-all)) (define *ai-all* (ai-all))
@ -398,7 +398,7 @@
#ifdef AI_ALL #ifdef AI_ALL
return_closcall1(data, k, obj_int2obj(AI_ALL)); return_closcall1(data, k, obj_int2obj(AI_ALL));
#else #else
return_closcall1(data, k, obj_int2obj(0)); Cyc_rt_raise_msg(data, \"AI_ALL is not available on this platform\");
#endif #endif
") ")
(make-const ai-addrconfig "AI_ADDRCONFIG" ) (make-const ai-addrconfig "AI_ADDRCONFIG" )

View file

@ -74,7 +74,6 @@
;; - internal ;; - internal
;; - end of thread cont (or #f for default) ;; - end of thread cont (or #f for default)
;; - end-result - Result of thread that terminates successfully ;; - end-result - Result of thread that terminates successfully
;; - internal thread context at termination, e.g. parameterised objects
(vector (vector
'cyc-thread-obj 'cyc-thread-obj
thunk thunk
@ -83,7 +82,6 @@
#f #f
#f #f
#f #f
#f
#f))) #f)))
(define (thread-name t) (vector-ref t 3)) (define (thread-name t) (vector-ref t 3))
@ -100,7 +98,7 @@
(%get-thread-data)) (%get-thread-data))
(define *primordial-thread* (define *primordial-thread*
(vector 'cyc-thread-obj #f #f "main thread" #f #f #f #f)) (vector 'cyc-thread-obj #f #f "main thread" #f #f))
(define-c %current-thread (define-c %current-thread
"(void *data, int argc, closure _, object k)" "(void *data, int argc, closure _, object k)"
@ -120,21 +118,13 @@
make_c_opaque(co, td); make_c_opaque(co, td);
return_closcall1(data, k, &co); ") return_closcall1(data, k, &co); ")
(define-c %end-thread!
"(void *data, int argc, closure _, object k, object ret)"
" gc_thread_data *d = data;
vector_type *v = d->scm_thread_obj;
v->elements[7] = ret; // Store thread result
Cyc_end_thread(d);
return_closcall1(data, k, boolean_f);")
(define (thread-start! t) (define (thread-start! t)
;; Initiate a GC prior to running the thread, in case ;; Initiate a GC prior to running the thread, in case
;; it contains any closures on the "parent" thread's stack ;; it contains any closures on the "parent" thread's stack
(let* ((thunk (vector-ref t 1)) (let* ((thunk (vector-ref t 1))
(thread-params (cons t (lambda () (thread-params (cons t (lambda ()
(vector-set! t 5 #f) (vector-set! t 5 #f)
(let ((r (thunk))) (%end-thread! r)))))) (thunk)))))
(vector-set! t 5 (%get-thread-data)) ;; Temporarily make parent thread (vector-set! t 5 (%get-thread-data)) ;; Temporarily make parent thread
;; data available for child init ;; data available for child init
(Cyc-minor-gc) (Cyc-minor-gc)
@ -142,33 +132,9 @@
t)) t))
(define (thread-yield!) (thread-sleep! 1)) (define (thread-yield!) (thread-sleep! 1))
(define-c thread-terminate!
(define-c %thread-terminate! "(void *data, object _, int argc, object *args)"
"(void *data, int argc, closure _, object k, object thread_data_opaque)" " Cyc_end_thread(data); ")
" gc_thread_data *td;
if (thread_data_opaque == boolean_f) {
/* primordial thread */
__halt(boolean_f);
} else {
td = (gc_thread_data *)(opaque_ptr(thread_data_opaque));
if (td == data) {
Cyc_end_thread(td);
} else {
pthread_cancel(td->thread_id);
}
}
return_closcall1(data, k, boolean_t);")
(define (thread-terminate! t)
(cond
((and (thread? t)
(or (Cyc-opaque? (vector-ref t 2)) (equal? *primordial-thread* t)))
(begin
(Cyc-minor-gc)
(vector-set! t 5 (%get-thread-data)) ;; remember calling thread
(%thread-terminate! (vector-ref t 2))
#t))
(else
#f))) ;; TODO: raise an error instead?
;; TODO: not good enough, need to return value from thread ;; TODO: not good enough, need to return value from thread
;; TODO: perhaps not an ideal solution using a loop/polling below, but good ;; TODO: perhaps not an ideal solution using a loop/polling below, but good
@ -190,7 +156,6 @@
(cond (cond
((and (thread? t) (Cyc-opaque? (vector-ref t 2))) ((and (thread? t) (Cyc-opaque? (vector-ref t 2)))
(%thread-join! (vector-ref t 2)) (%thread-join! (vector-ref t 2))
(Cyc-minor-gc)
(vector-ref t 7)) (vector-ref t 7))
(else (else
#f))) ;; TODO: raise an error instead? #f))) ;; TODO: raise an error instead?

View file

@ -1,51 +0,0 @@
#include <stdio.h>
#include <assert.h>
#include "include/cyclone/types.h"
#include "include/cyclone/runtime.h"
#include "include/cyclone/runtime-main.h"
/* Future considerations:
int main(int argc, char **argv, char **envp)
{gc_thread_data *thd;
long stack_size = global_stack_size = STACK_SIZE;
long heap_size = global_heap_size = HEAP_SIZE;
init_polyfills();
mclosure0(clos_halt,&Cyc_halt); // Halt if final closure is reached
mclosure0(entry_pt,&c_entry_pt); // First function to execute
_cyc_argc = argc;
_cyc_argv = argv;
set_env_variables(envp);
gc_initialize();
thd = malloc(sizeof(gc_thread_data));
gc_thread_data_init(thd, 0, (char *) &stack_size, stack_size);
thd->gc_cont = &entry_pt;
thd->gc_args[0] = &clos_halt;
thd->gc_num_args = 1;
thd->thread_id = pthread_self();
gc_add_mutator(thd);
Cyc_heap_init(heap_size);
thd->thread_state = CYC_THREAD_STATE_RUNNABLE;
Cyc_start_trampoline(thd);
return 0;}
*/
void test_exact() {
common_type ptr;
make_double(d, 42.5);
assert(obj_int2obj(42) == Cyc_exact_no_cps(NULL, &ptr, obj_int2obj(42)));
object result = Cyc_exact_no_cps(NULL, &ptr, &d);
assert( result == obj_int2obj(43));
// TODO: unit tests for below as examples:
//void Cyc_exact(void *data, object cont, object z)
}
int main(){
assert(boolean_t == boolean_t);
assert(boolean_t != boolean_f);
test_exact();
printf("All tests passed successfully!\n");
return 0;
}

View file

@ -9,9 +9,6 @@
(import (import
(scheme base) (scheme base)
(scheme eval)
(scheme inexact)
(scheme write)
(cyclone test)) (cyclone test))
@ -33,12 +30,6 @@
(test '() (make-list -2)) (test '() (make-list -2))
) )
(test-group
"apply"
(test '(5 1 2) (eval '(apply cons '(5 (1 2)))))
(test '(5 1 2) (apply cons '(5 (1 2))))
)
(cond-expand (cond-expand
(memory streams (memory streams
(test-group (test-group
@ -55,7 +46,6 @@
(test "o" (read-line p)) (test "o" (read-line p))
) )
) )
(else #f)
) )
(test-group (test-group
@ -112,18 +102,6 @@
(test 2.0 (denominator (inexact (/ 6 4)))) (test 2.0 (denominator (inexact (/ 6 4))))
) )
(test-group
"sqrt"
(test 1i (sqrt -1))
(test 1i (sqrt -1.0))
(test +i (sqrt -1.0))
(test 2 (sqrt 4))
(test 2.0 (sqrt 4.0))
(test 2i (sqrt -4.0))
(test #t (complex? (sqrt -1)))
(test #t (complex? (sqrt -i)))
)
(test-group (test-group
"exact" "exact"
(test -1 (exact -1)) (test -1 (exact -1))
@ -173,45 +151,5 @@
(test #f (memq 0.0 (list m))) (test #f (memq 0.0 (list m)))
) )
(test-group
"exception handling"
(define (capture-output thunk)
(let ((output-string (open-output-string)))
(parameterize ((current-output-port output-string))
(thunk))
(let ((result (get-output-string output-string)))
(close-output-port output-string)
result)))
(test
"should be a number65"
(capture-output
(lambda ()
(with-exception-handler
(lambda (con)
(cond
((string? con)
(display con))
(else
(display "a warning has been issued")))
42)
(lambda ()
(display
(+ (raise-continuable "should be a number")
23)))))))
(test
"condition: an-error"
(capture-output
(lambda ()
(call-with-current-continuation
(lambda (k)
(with-exception-handler
(lambda (x)
(display "condition: ")
(write x)
(k "exception"))
(lambda ()
(+ 1 (raise 'an-error)))))))))
)
(test-exit) (test-exit)