Compare commits

...

2 Commits

Author SHA1 Message Date
94be79c529 strings 2026-05-23 13:30:44 -06:00
2ccf7ca27d move code out of root 2026-05-22 15:23:31 -06:00
9 changed files with 153 additions and 23 deletions

1
play/car.scm Normal file
View File

@@ -0,0 +1 @@
(prim:write (prim:car (prim:cons 123 456)))

1
play/cdr.scm Normal file
View File

@@ -0,0 +1 @@
(prim:write (prim:cdr (prim:cons 123 456)))

13
runtime/src/capi.rs Normal file
View File

@@ -0,0 +1,13 @@
use std::slice;
use crate::scm::scm_bits;
use crate::scm;
#[unsafe(no_mangle)]
pub extern "C" fn scm_from_utf8_string (
ptr : *const u8,
len : usize
) -> scm_bits {
let bytes = unsafe { slice::from_raw_parts (ptr, len) };
scm::make_string (str::from_utf8 (bytes).unwrap ())
}

View File

@@ -1,26 +1,8 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
use std::{io::{stdout, Write}};
mod gc;
mod scm;
use scm::{scm_bits, SCM};
#[unsafe(no_mangle)]
pub extern "C" fn scm_write (x: scm_bits) -> scm_bits {
match scm::unpack (x) {
SCM::SmallInt (n) => print! ("{n}"),
SCM::Cons (car, cdr) => {
print! ("(");
scm_write (car);
print! (" . ");
scm_write (cdr);
print! (")");
},
SCM::Nil => print! ("()"),
SCM::False => print! ("#f"),
SCM::True => print! ("#t"),
};
let _ = stdout ().flush ();
return 0;
}
mod primitives;
mod obarray;
mod capi;

10
runtime/src/obarray.rs Normal file
View File

@@ -0,0 +1,10 @@
use std::{collections::HashMap, hash::{BuildHasher, Hasher}};
use crate::scm::scm_bits;
use crate::scm;
mod fnv1a;
pub struct Obarray (HashMap <String, scm_bits>);
pub fn hash () {
}

View File

@@ -0,0 +1,28 @@
use std::{collections::HashMap, hash::{BuildHasher, Hasher}};
pub struct FNV1a (u64);
pub struct SymbolHash;
impl Hasher for FNV1a {
fn finish (&self) -> u64 {
self.0
}
fn write (&mut self, bytes: &[u8]) {
for b in bytes {
self.0 ^= *b as u64;
self.0 *= prime;
}
}
}
impl BuildHasher for SymbolHash {
type Hasher = FNV1a;
fn build_hasher (&self) -> Self::Hasher {
FNV1a (offset_basis)
}
}
const offset_basis : u64 = 0xcbf29ce484222325;
const prime : u64 = 0x100000001b3;

23
runtime/src/primitives.rs Normal file
View File

@@ -0,0 +1,23 @@
use crate::scm;
use crate::scm::{scm_bits, SCM};
use std::io::{stdout, Write};
#[unsafe(no_mangle)]
pub extern "C" fn scm_write (x: scm_bits) -> scm_bits {
match scm::unpack (x) {
SCM::SmallInt (n) => print! ("{n}"),
SCM::Cons (car, cdr) => {
print! ("(");
scm_write (car);
print! (" . ");
scm_write (cdr);
print! (")");
},
SCM::String (s) => print! ("\"{s}\""),
SCM::Nil => print! ("()"),
SCM::False => print! ("#f"),
SCM::True => print! ("#t"),
};
let _ = stdout ().flush ();
return 0;
}

View File

@@ -1,6 +1,10 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
use std::slice;
use crate::gc;
pub type scm_bits = u64;
pub const tc2_int : u64 = 2;
@@ -16,6 +20,7 @@ pub const tc7_string : u64 = 0x15;
pub enum SCM {
SmallInt (i64),
Cons (scm_bits, scm_bits),
String (String),
Nil,
False,
True,
@@ -35,6 +40,18 @@ pub fn unpack (x : scm_bits) -> SCM {
} else if is_cons (x) {
// `car` x and `cdr` x are safe iff `is_cons` x.
unsafe { SCM::Cons (car (x), cdr (x)) }
} else if is_string (x) {
let len = unsafe { cell_word (x, 1) };
let str_beginning = (x as *const scm_bits).wrapping_add (2) as *const u8;
let slice = unsafe {
str::from_utf8 (
slice::from_raw_parts (
str_beginning,
len.try_into ().unwrap ()
)
).unwrap ()
};
return SCM::String (String::from (slice));
} else {
// concat_panic! ("don't know how to unpack: ", x)
panic! ("don't know how to unpack {x:#016x}")
@@ -49,6 +66,10 @@ const fn is_immediate (x: scm_bits) -> bool {
6 & x != 0
}
fn is_string (x: scm_bits) -> bool {
has_tc7 (x, tc7_string)
}
fn is_cons (x: scm_bits) -> bool {
// safety of `cell_type` is mutually exclusive with
// `is_immediate`, so this is okay.
@@ -57,6 +78,12 @@ fn is_cons (x: scm_bits) -> bool {
}
}
fn has_tc7 (x: scm_bits, tc7: u64) -> bool {
unsafe {
! is_immediate (x) && (0x7f & cell_type (x)) == tc7
}
}
unsafe fn cell_type (x: scm_bits) -> scm_bits {
unsafe { cell_word (x, 0) }
}
@@ -75,3 +102,50 @@ unsafe fn car (x: scm_bits) -> scm_bits {
unsafe fn cdr (x: scm_bits) -> scm_bits {
unsafe { cell_word (x, 1) }
}
pub unsafe fn words (tag : scm_bits, n : usize) -> *mut scm_bits {
let r = unsafe { gc::malloc (n * size_of::<scm_bits> ()) };
unsafe { *r = tag };
return r
}
pub fn pack_ptr (obj : *const scm_bits) -> scm_bits {
obj as scm_bits
}
pub unsafe fn set_word (obj : *mut scm_bits, ix : usize, val : scm_bits) {
let x = obj.wrapping_add (ix);
unsafe { *x = val; }
}
pub fn make_string_from_raw_parts (
ptr : *const u8,
len : usize
) -> scm_bits {
let bytes = unsafe { slice::from_raw_parts (ptr, len) };
make_string (str::from_utf8 (bytes).unwrap ())
}
pub fn make_string (s : &str) -> scm_bits {
let len = s.len ();
let size_of_tag_and_len = 2 * size_of::<scm_bits> ();
let size_of_contents = len;
let r = unsafe { gc::malloc (size_of_tag_and_len + size_of_contents) };
unsafe {
set_word (r, 0, tc7_string);
set_word (r, 1, len as u64);
}
let str_beginning = r.wrapping_add (2) as *mut u8;
for (i, b) in s.as_bytes ().iter ().enumerate () {
unsafe { *(str_beginning.wrapping_add (i)) = *b };
}
return pack_ptr (r)
}
pub fn make_symbol (name : &str) -> scm_bits {
todo! ()
}

View File

@@ -1,2 +0,0 @@
use std::collections;