diff --git a/play/car.scm b/play/car.scm new file mode 100644 index 0000000..8fd7653 --- /dev/null +++ b/play/car.scm @@ -0,0 +1 @@ +(prim:write (prim:car (prim:cons 123 456))) diff --git a/play/cdr.scm b/play/cdr.scm new file mode 100644 index 0000000..e3abdb6 --- /dev/null +++ b/play/cdr.scm @@ -0,0 +1 @@ +(prim:write (prim:cdr (prim:cons 123 456))) diff --git a/runtime/src/capi.rs b/runtime/src/capi.rs new file mode 100644 index 0000000..3884bb8 --- /dev/null +++ b/runtime/src/capi.rs @@ -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 ()) +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 431fe85..d6be78b 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -4,4 +4,5 @@ mod gc; mod scm; mod primitives; - +mod obarray; +mod capi; diff --git a/runtime/src/obarray.rs b/runtime/src/obarray.rs new file mode 100644 index 0000000..30dd04f --- /dev/null +++ b/runtime/src/obarray.rs @@ -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 ); + +pub fn hash () { +} diff --git a/runtime/src/obarray/fnv1a.rs b/runtime/src/obarray/fnv1a.rs new file mode 100644 index 0000000..3d95577 --- /dev/null +++ b/runtime/src/obarray/fnv1a.rs @@ -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; diff --git a/runtime/src/primitives.rs b/runtime/src/primitives.rs index 3c17d66..bb74b82 100644 --- a/runtime/src/primitives.rs +++ b/runtime/src/primitives.rs @@ -13,6 +13,7 @@ pub extern "C" fn scm_write (x: scm_bits) -> scm_bits { scm_write (cdr); print! (")"); }, + SCM::String (s) => print! ("\"{s}\""), SCM::Nil => print! ("()"), SCM::False => print! ("#f"), SCM::True => print! ("#t"), diff --git a/runtime/src/scm.rs b/runtime/src/scm.rs index 320b9d4..41d5c6e 100644 --- a/runtime/src/scm.rs +++ b/runtime/src/scm.rs @@ -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:: ()) }; + 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:: (); + 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! () +} diff --git a/runtime/src/weak-set.rs b/runtime/src/weak-set.rs deleted file mode 100644 index 551e803..0000000 --- a/runtime/src/weak-set.rs +++ /dev/null @@ -1,2 +0,0 @@ -use std::collections; -