rust runtime

This commit is contained in:
2026-05-19 10:54:14 -06:00
parent 78a4fb402d
commit 4e7ddffbc6
16 changed files with 344 additions and 404 deletions

View File

@@ -27,7 +27,7 @@ import Data.Vector.Strict (Vector)
import Data.Function (fix)
import Effectful.Writer.Static.Local
import Gyehoek.Scheme.Syntax qualified as Lam
import Gyehoek.Scheme.Syntax (Name, Prim(..), Lit(..), Sexp (..))
import Gyehoek.Scheme.Syntax (Name, Prim(..), Lit(..))
import Gyehoek.GenSym
import Control.Monad.Cont
import Data.Foldable
@@ -284,7 +284,7 @@ lowerVal
lowerVal (ValLit (LitInt n)) k = k . lowerInt $ n
lowerVal (ValLit (LitQuote (SexpSymbol s))) k = _aaa
-- lowerVal (ValLit (LitQuote (SexpSymbol s))) k = _aaa
lowerVal (ValLit (LitString s)) k = do
rawString <- gensym

View File

@@ -120,5 +120,5 @@ driver = runGenSym . traverseOf_ (#sourceFiles . folded) \f -> do
anfs <- toANF f exps
qbe <- toQBE f anfs
callQBE f
callGCC f ["../runtime/gyehoek.c"]
callGCC f ["../runtime/target/debug/libgyehoek.a"]
pure ()

BIN
play/t

Binary file not shown.

1
runtime/.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

1
runtime/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
target

56
runtime/Cargo.lock generated Normal file
View File

@@ -0,0 +1,56 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bdwgc-alloc"
version = "0.6.13"
source = "git+https://git.deertopia.net/msyds/bdwgc-rust.git#ccc273a168f3ddfee0a2ae170f561f19da8c274a"
dependencies = [
"cmake",
"libc",
]
[[package]]
name = "cc"
version = "1.2.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "cmake"
version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
dependencies = [
"cc",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "gyehoek"
version = "0.1.0"
dependencies = [
"bdwgc-alloc",
]
[[package]]
name = "libc"
version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"

17
runtime/Cargo.toml Normal file
View File

@@ -0,0 +1,17 @@
[package]
name = "gyehoek"
version = "0.1.0"
edition = "2024"
[lib]
name = "gyehoek"
# crate-type = ["cdylib"]
crate-type = ["staticlib"]
[dependencies]
bdwgc-alloc = { version = "0.6.13"
, default-features = false
, features = ["cmake"] }
[patch.crates-io]
bdwgc-alloc = { git = 'https://git.deertopia.net/msyds/bdwgc-rust.git' }

View File

@@ -1,8 +0,0 @@
all: gyehoek.o
gyehoek.o: gyehoek.c
$(CC) $(CFLAGS) -c gyehoek.c -o gyehoek.o
.PHONY: install
install:
install -Dm644 -t $(out)/lib gyehoek.o

View File

@@ -1,10 +0,0 @@
{ stdenv
, callPackage
, bdwgc ? callPackage ../bdwgc.nix {}
}:
stdenv.mkDerivation {
pname = "gyehoek";
version = "1.0.0";
src = ./.;
}

87
runtime/flake.lock generated Normal file
View File

@@ -0,0 +1,87 @@
{
"nodes": {
"fenix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1779185128,
"narHash": "sha256-Kl2bkmwZJD3n2KWDxuIlturZ7emqRK+anpD1LmDwpmY=",
"owner": "nix-community",
"repo": "fenix",
"rev": "b7bd9323fe26a3b4f4bddbb2c2a1dacabced2f88",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1778869304,
"narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d233902339c02a9c334e7e593de68855ad26c4cb",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"fenix": "fenix",
"nixpkgs": "nixpkgs",
"sydpkgs": "sydpkgs"
}
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1779074864,
"narHash": "sha256-0M3WqsWmtXmv9Ev/vnFfCHosWvISDwiuuhQ104UO3CI=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "cdfe408d4b436e806ff525cb3e67588a6a009ed1",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
},
"sydpkgs": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1778962331,
"narHash": "sha256-qMokSV7hsWYiDCkkBGyG0aD4Ds3JLzJzJ0Cp9f/spJU=",
"ref": "refs/heads/main",
"rev": "59d3a471cd960f9d1f6c645a4fe578a670848e9d",
"revCount": 41,
"type": "git",
"url": "https://git.deertopia.net/msyds/sydpkgs"
},
"original": {
"type": "git",
"url": "https://git.deertopia.net/msyds/sydpkgs"
}
}
},
"root": "root",
"version": 7
}

70
runtime/flake.nix Normal file
View File

@@ -0,0 +1,70 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
fenix = {
url = "github:nix-community/fenix";
inputs.nixpkgs.follows = "nixpkgs";
};
sydpkgs = {
url = "git+https://git.deertopia.net/msyds/sydpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { self, nixpkgs, fenix, sydpkgs, ... }:
let
supportedSystems = [
"aarch64-darwin" "aarch64-linux"
"x86_64-darwin" "x86_64-linux"
];
each-system = f: nixpkgs.lib.genAttrs supportedSystems (system: f rec {
pkgs = import nixpkgs {
inherit system overlays;
};
inherit (pkgs) lib;
inherit system;
});
overlays = [
(final: prev: {
inherit (sydpkgs.packages.${final.stdenv.hostPlatform.system})
bdwgc;
})
fenix.overlays.default
];
in {
_pkgs = each-system ({ pkgs, ... }: pkgs);
packages = each-system ({ pkgs, ... }: {
default = pkgs.callPackage ./. {};
});
devShells = each-system ({ pkgs, lib, ... }: {
default = pkgs.mkShell {
RUSTFLAGS = "-L " + lib.makeLibraryPath [
pkgs.bdwgc
];
packages = [
pkgs.pkg-config
pkgs.bdwgc
(pkgs.fenix.complete.withComponents [
"cargo" "clippy" "rust-src" "rustc" "rustfmt"
])
pkgs.rust-analyzer-nightly
pkgs.cmake
];
};
});
};
nixConfig = {
extra-substituters = [
"https://fenix.cachix.org"
];
extra-trusted-public-keys = [
"fenix.cachix.org-1:ecJhr+RdYEdcVgUkjruiYhjbBloIEGov7bos90cZi0Q="
];
};
}

View File

@@ -1,122 +0,0 @@
#include <stdio.h>
#include <gc.h>
#include <string.h>
#include "gyehoek.h"
const long scm_tc3_cons = 0;
const long scm_tc7_weak_set = 0x55;
const long scm_tc7_symbol = 0x05;
const long scm_tc7_string = 0x15;
SCM scm_newline () {
putc ('\n', stdout);
return SCM_PACK(NULL);
}
size_t scm_c_string_length (SCM str) {
return SCM_CELL_WORD (str, 1);
}
const char *scm_c_string_chars (SCM str) {
return (const char *) SCM_UNPACK_POINTER (SCM_CELL_OBJECT (str, 2));
}
static void scm_write_string (SCM x) {
const size_t len = scm_c_string_length (x);
const char *s = scm_c_string_chars (x);
/* FIXME: this is a very naïve implementation with no escaping. */
printf ("some unrelated unicode lol: %s\n", "왜 하냐??");
printf ("\"%.*s\"", (int) len, s);
}
SCM scm_write (SCM x) {
if (SCM_IMP (x)) {
printf ("%ld", SCM_UNPACK (x) >> 2);
} else if (SCM_CONSP (x)) {
printf ("(");
scm_write (scm_car (x));
printf (" . ");
scm_write (scm_cdr (x));
printf (")");
} else if (SCM_STRINGP (x)) {
scm_write_string (x);
} else {
printf ("#<heap object 0x%016lx>", SCM_UNPACK (x));
}
return SCM_PACK(NULL);
}
SCM scm_car (SCM x) {
return SCM_CELL_OBJECT (x, 0);
}
SCM scm_cdr (SCM x) {
return SCM_CELL_OBJECT (x, 1);
}
SCM scm_words (scm_t_bits word_0, uint32_t n_words) {
scm_t_bits *r = GC_malloc (n_words * sizeof (scm_t_bits));
r[0] = word_0;
return SCM_PACK (r);
}
SCM scm_from_utf8_string (const char *str, size_t len) {
SCM r = scm_words (scm_tc7_string, 3);
SCM_SET_CELL_WORD (r, 1, len);
SCM_SET_CELL_WORD (r, 2, str);
return r;
}
SCM scm_from_cstring (const char *str) {
return scm_from_utf8_string (str, strlen (str));
}
unsigned long scm_c_hash (SCM str) {
const unsigned long offset_basis = 0xcbf29ce484222325;
const unsigned long prime = 0x100000001b3;
const size_t len = scm_c_string_length (str);
const char *bytes = scm_c_string_chars (str);
unsigned long hash = offset_basis;
for (const char *c = bytes; c < bytes + len; c++) {
hash ^= *c;
hash *= prime;
}
// mask off MSB, since we use it to mark tombstones in weak-set.c.
/* hash &= 0x7fffffffffffffff; */
// shift off MSB, since we use it to mark tombstones in weak-set.c.
/* hash >>= 1; */
/* ensure hash is non-zero */
hash |= hash == 0;
return hash;
}
SCM scm_str_to_symbol (SCM str) {
}
SCM scm_from_utf8_symbol (const char *s, size_t len) {
}
SCM scm_cons (SCM car, SCM cdr) {
scm_t_bits *r = GC_malloc (2 * sizeof (scm_t_bits));
r[0] = SCM_UNPACK (car);
r[1] = SCM_UNPACK (cdr);
return SCM_PACK (r);
}
SCM scm_make_symbol (SCM name, unsigned long hash) {
SCM r = scm_words(scm_tc7_symbol, 3);
SCM_SET_CELL_WORD (r, 1, hash);
SCM_SET_CELL_OBJECT (r, 2, name);
return r;
}

View File

@@ -1,119 +0,0 @@
#ifndef GYEHOEK_H
#define GYEHOEK_H
#include <stddef.h>
#include <stdint.h>
typedef uintptr_t scm_t_bits;
typedef union SCM { struct { scm_t_bits n; } n; } SCM;
#define SCM_UNPACK(x) ((x).n.n)
#define SCM_PACK(x) ((SCM) { { (scm_t_bits) (x) } })
#define SCM_IMP(x) (6 & SCM_UNPACK (x))
#define SCM_NIMP(x) (!SCM_IMP (x))
#define SCM_HEAP_OBJECT_P(x) (SCM_NIMP (x))
#define SCM_UNPACK_POINTER(x) ((scm_t_bits *) (SCM_UNPACK (x)))
#define SCM_PACK_POINTER(x) (SCM_PACK ((scm_t_bits) (x)))
#define SCM_FALSE 0b00100
#define SCM_TRUE 0b01100
#define SCM_EOL 0b10100
#if (-1 >> 2 == -1) && (-4 >> 2 == -1) && (-5 >> 2 == -2) && (-8 >> 2 == -2)
# define SCM_SRS(x, y) ((x) >> (y))
#else
# define SCM_SRS(x, y) \
((x) < 0 \
? -1 - (scm_t_signed_bits) (~(scm_t_bits)(x) >> (y)) \
: ((x) >> (y)))
#endif
#define SCM_MAKE_SMALL_INT(x) (SCM_SRS ((long)(x), 2) + 2)
#define SCM_GET_SMALL_INT(x) (SCM_UNPACK (x) >> 2)
/* Checking if a SCM variable holds a pair (for historical reasons, in
Guile also known as a cons-cell): This is done by first checking that
the SCM variable holds a heap object, and second, by checking that
tc1==0 holds for the SCM_CELL_TYPE of the SCM variable. */
#define SCM_CONSP(x) (!SCM_IMP (x) && ((1 & SCM_CELL_TYPE (x)) == 0))
#define scm_tc2_int 2
#define SCM_ITAG3(x) (7 & SCM_UNPACK (x))
#define SCM_TYP3(x) (7 & SCM_CELL_TYPE (x))
/* #define scm_tc3_cons 0 */
extern const long scm_tc3_cons;
SCM scm_cons (SCM car, SCM cdr);
SCM scm_car (SCM x);
SCM scm_cdr (SCM x);
#define SCM_UNPACK_POINTER(x) ((scm_t_bits *) (SCM_UNPACK (x)))
#define SCM_PACK_POINTER(x) (SCM_PACK ((scm_t_bits) (x)))
#define SCM_CELL_OBJECT(x, n) (((SCM *)SCM_UNPACK_POINTER (x)) [n])
#define SCM_CELL_WORD(x, n) (SCM_UNPACK (SCM_CELL_OBJECT ((x), (n))))
#define SCM_SET_CELL_OBJECT(x, n, v) \
((((SCM *)SCM_UNPACK_POINTER (x)) [n]) = (v))
#define SCM_SET_CELL_WORD(x, n, v) \
(SCM_SET_CELL_OBJECT ((x), (n), SCM_PACK (v)))
#define SCM_CELL_TYPE(x) SCM_CELL_WORD (x, 0)
#define SCM_TYP7(x) (0x7f & SCM_CELL_TYPE (x))
#define SCM_HAS_HEAP_TYPE(x, type, tag) \
(SCM_NIMP (x) && type (x) == (tag))
#define SCM_HAS_TYP7(x, tag) (SCM_HAS_HEAP_TYPE (x, SCM_TYP7, tag))
extern const long scm_tc7_weak_set;
extern const long scm_tc7_symbol;
extern const long scm_tc7_string;
/// Strings
#define SCM_STRINGP(x) (SCM_TYP7 (x) == scm_tc7_string)
size_t scm_c_string_length (SCM str);
const char *scm_c_string_chars (SCM str);
/// Symbols
#define SCM_SYMBOLP(x) (SCM_TYP7 (x) == scm_tc7_symbol)
unsigned long scm_c_hash (SCM str);
SCM scm_words (scm_t_bits word_0, uint32_t n_words);
/* Construct a Scheme string. */
SCM scm_from_utf8_string (const char *str, size_t len);
SCM scm_from_cstring (const char *str);
/* Intern a symbol with a UTF-8 string name. */
SCM scm_from_utf8_symbol (const char *s, size_t len);
SCM scm_make_symbol (SCM name, unsigned long hash);
SCM scm_write (SCM);
#endif /* GYEHOEK_H */

109
runtime/src/lib.rs Normal file
View File

@@ -0,0 +1,109 @@
use std::{io::{stdout, Write}};
const scm_tc3_cons: u64 = 0;
const scm_tc2_int: u64 = 2;
type scm_bits = u64;
#[repr(C)]
#[derive(Clone, Copy)]
struct SCM {
n : scm_bits
}
fn scm_pack (bits : scm_bits) -> SCM {
SCM {n: bits}
}
fn scm_unpack (x : SCM) -> scm_bits {
x.n
}
fn scm_unpack_pointer (x : SCM) -> *mut scm_bits {
x.n as *mut scm_bits
}
fn scm_pack_pointer (x : *const scm_bits) -> SCM {
SCM {n: x as scm_bits}
}
fn scm_cell_object (x: SCM, n: usize) -> SCM {
let p = scm_unpack_pointer (x) as *mut SCM;
unsafe {
*(p.wrapping_add (n))
}
}
fn scm_cell_word (x: SCM, n: usize) -> scm_bits {
scm_unpack (scm_cell_object (x, n))
}
fn is_immediate (x: SCM) -> bool {
6 & scm_unpack (x) != 0
}
fn scm_cell_type (x: SCM) -> scm_bits {
scm_cell_word (x, 0)
}
fn is_cons (x: SCM) -> bool {
! is_immediate (x) && (1 & scm_cell_type (x)) == 0
}
fn is_small_int (x: SCM) -> bool {
3 & scm_unpack (x) == scm_tc2_int
}
fn get_small_int (x: SCM) -> scm_bits {
scm_unpack (x) >> 2
}
fn scm_car (x: SCM) -> SCM {
scm_cell_object (x, 0)
}
fn scm_cdr (x: SCM) -> SCM {
scm_cell_object (x, 1)
}
#[unsafe(no_mangle)]
pub extern "C" fn scm_write (x: SCM) -> SCM {
if is_small_int (x) {
print! ("{:?}", get_small_int (x));
} else if is_cons (x) {
print! ("(");
scm_write (scm_car (x));
print! (" . ");
scm_write (scm_cdr (x));
print! (")");
} else {
let ty = if is_immediate (x) { "immediate" } else { "heap object" };
print! ("#<{ty} {:#016x}>", scm_unpack (x));
}
stdout ().flush ();
return scm_pack (0);
}
#[unsafe(no_mangle)]
pub extern "C" fn scm_from_utf8_string (s: scm_bits, len: scm_bits) -> scm_bits {
println! ("scm_from_utf8_string");
return 0;
}
pub fn add (left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works () {
let result = add (2, 2);
assert_eq! (result, 4);
}
}

View File

@@ -1,122 +0,0 @@
#include <gc.h>
#include <gc/gc.h>
#include <string.h>
#include "gyehoek.h"
#include "weak-set.h"
typedef struct {
unsigned long hash;
scm_t_bits key;
} scm_t_weak_entry;
/* struct weak_entry_data { */
/* scm_t_weak_entry *in; */
/* scm_t_weak_entry *out; */
/* }; */
typedef struct {
scm_t_weak_entry *entries; /* the data */
unsigned long size; /* total number of slots. */
unsigned long n_items; /* number of items in set */
unsigned long lower; /* when to shrink */
unsigned long upper; /* when to grow */
int size_index; /* index into hashset_size */
int min_size_index; /* minimum size_index */
} scm_t_weak_set;
/* Growing or shrinking is triggered when the load factor
*
* L = N / S (N: number of items in set, S: bucket vector length)
*
* passes an upper limit of 0.9 or a lower limit of 0.2.
*
* The implementation stores the upper and lower number of items which
* trigger a resize in the hashset object.
*
* Possible hash set sizes (primes) are stored in the array
* hashset_size.
*/
static unsigned long hashset_size[] = {
31, 61, 113, 223, 443, 883, 1759, 3517, 7027, 14051, 28099, 56197, 112363,
224717, 449419, 898823, 1797641, 3595271, 7190537, 14381041, 28762081,
57524111, 115048217, 230096423
};
#define HASHSET_SIZE_N (sizeof(hashset_size)/sizeof(unsigned long))
SCM scm_c_make_weak_set (unsigned long k) {
scm_t_weak_set *set = GC_malloc (sizeof (scm_t_weak_set));
/* i ripped this from guile and i'm not sure what it's for ^w^. */
int i = 0, n = k ? k : 31;
while (i + 1 < HASHSET_SIZE_N && n > hashset_size[i])
++i;
n = hashset_size[i];
set->entries = GC_malloc_atomic (n * sizeof(scm_t_weak_entry));
memset (set->entries, 0, n * sizeof(scm_t_weak_entry));
set->n_items = 0;
set->size = n;
set->lower = 0;
set->upper = 9 * n / 10;
set->size_index = i;
set->min_size_index = i;
SCM r = scm_words (scm_tc7_weak_set, 2);
SCM_SET_CELL_WORD (r, 1, set);
return r;
}
static int
apply_pred (scm_t_weak_entry *entry, scm_t_set_predicate_fn pred
, void *closure) {
scm_t_weak_entry copy;
memcpy (&copy, entry, sizeof (scm_t_weak_entry));
return pred (SCM_PACK (copy.key), closure);
}
static SCM
find_bucket (scm_t_weak_set *set, unsigned long hash,
SCM key, scm_t_set_predicate_fn pred, void *closure,
unsigned long p) {
const unsigned long other_hash = set->entries[p].hash;
if (other_hash == 0) {
set->entries[p].hash = hash;
set->entries[p].key = SCM_UNPACK (key);
set->n_items++;
return key;
} else if (hash == other_hash
// guile passes a copy.. is this important for weak
// references...
&& pred (SCM_PACK (set->entries[p].key), closure)) {
return SCM_PACK (set->entries[p].key);
} else {
/* i have faith in gcc's TCO. */
return find_bucket (set, hash, key, pred, closure,
(p + 1) % set->size);
}
}
#define SCM_WEAK_SET(x) ((scm_t_weak_set *) SCM_CELL_WORD (x, 1))
SCM scm_c_weak_set_insert (SCM set, unsigned long hash,
SCM key, scm_t_set_predicate_fn pred,
void *closure) {
scm_t_weak_set *s = SCM_WEAK_SET (set);
unsigned long size = s->size;
if (s->n_items > s->upper) {
/* resize */
}
return find_bucket (s, hash, key, pred, closure, hash % size);
}
SCM scm_c_weak_set_lookup (scm_t_weak_set *set, unsigned long hash, SCM dflt) {
}
unsigned long weak_set_count (SCM set) {
return (SCM_WEAK_SET (set))->n_items;
}

View File

@@ -1,20 +0,0 @@
#ifndef WEAK_SET_H
#define WEAK_SET_H
#include "gyehoek.h"
#define SCM_WEAK_SET_P(x) (SCM_HAS_TYP7 (x, scm_tc7_weak_set))
/* Function that returns nonzero if the given object is the one we are
looking for. */
typedef int (*scm_t_set_predicate_fn) (SCM obj, void *closure);
SCM scm_c_make_weak_set (unsigned long k);
SCM scm_c_weak_set_insert (SCM set, unsigned long hash,
SCM key, scm_t_set_predicate_fn pred,
void* closure);
unsigned long weak_set_count (SCM set);
#endif /* WEAK_SET_H */