├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── base ├── Cargo.toml ├── bootstrap │ ├── .gitignore │ ├── Bootstrap.lean │ ├── Main.lean │ ├── lake-manifest.json │ └── lakefile.lean └── src │ ├── closure.rs │ ├── external.rs │ ├── lib.rs │ └── typed.rs ├── build.rs ├── build ├── Cargo.toml └── src │ └── lib.rs ├── lean-toolchain └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "autocfg" 7 | version = "1.1.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 10 | 11 | [[package]] 12 | name = "bitflags" 13 | version = "1.3.2" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 16 | 17 | [[package]] 18 | name = "cfg-if" 19 | version = "1.0.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 22 | 23 | [[package]] 24 | name = "lean-base" 25 | version = "0.1.0" 26 | dependencies = [ 27 | "lean-sys", 28 | ] 29 | 30 | [[package]] 31 | name = "lean-build" 32 | version = "0.1.0" 33 | dependencies = [ 34 | "lean-base", 35 | ] 36 | 37 | [[package]] 38 | name = "lean-rs" 39 | version = "0.1.0" 40 | dependencies = [ 41 | "lean-base", 42 | "lean-sys", 43 | ] 44 | 45 | [[package]] 46 | name = "lean-sys" 47 | version = "0.0.6" 48 | source = "git+https://github.com/digama0/lean-sys.git#b09c21af1990c0042c41f30f8feedb669efa2cf9" 49 | dependencies = [ 50 | "libc", 51 | "memoffset", 52 | "parking_lot", 53 | "static_assertions", 54 | ] 55 | 56 | [[package]] 57 | name = "libc" 58 | version = "0.2.147" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" 61 | 62 | [[package]] 63 | name = "lock_api" 64 | version = "0.4.10" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" 67 | dependencies = [ 68 | "autocfg", 69 | "scopeguard", 70 | ] 71 | 72 | [[package]] 73 | name = "memoffset" 74 | version = "0.9.0" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" 77 | dependencies = [ 78 | "autocfg", 79 | ] 80 | 81 | [[package]] 82 | name = "parking_lot" 83 | version = "0.12.1" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 86 | dependencies = [ 87 | "lock_api", 88 | "parking_lot_core", 89 | ] 90 | 91 | [[package]] 92 | name = "parking_lot_core" 93 | version = "0.9.8" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" 96 | dependencies = [ 97 | "cfg-if", 98 | "libc", 99 | "redox_syscall", 100 | "smallvec", 101 | "windows-targets", 102 | ] 103 | 104 | [[package]] 105 | name = "redox_syscall" 106 | version = "0.3.5" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 109 | dependencies = [ 110 | "bitflags", 111 | ] 112 | 113 | [[package]] 114 | name = "scopeguard" 115 | version = "1.2.0" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 118 | 119 | [[package]] 120 | name = "smallvec" 121 | version = "1.11.0" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" 124 | 125 | [[package]] 126 | name = "static_assertions" 127 | version = "1.1.0" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 130 | 131 | [[package]] 132 | name = "windows-targets" 133 | version = "0.48.2" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8" 136 | dependencies = [ 137 | "windows_aarch64_gnullvm", 138 | "windows_aarch64_msvc", 139 | "windows_i686_gnu", 140 | "windows_i686_msvc", 141 | "windows_x86_64_gnu", 142 | "windows_x86_64_gnullvm", 143 | "windows_x86_64_msvc", 144 | ] 145 | 146 | [[package]] 147 | name = "windows_aarch64_gnullvm" 148 | version = "0.48.2" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f" 151 | 152 | [[package]] 153 | name = "windows_aarch64_msvc" 154 | version = "0.48.2" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058" 157 | 158 | [[package]] 159 | name = "windows_i686_gnu" 160 | version = "0.48.2" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd" 163 | 164 | [[package]] 165 | name = "windows_i686_msvc" 166 | version = "0.48.2" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287" 169 | 170 | [[package]] 171 | name = "windows_x86_64_gnu" 172 | version = "0.48.2" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a" 175 | 176 | [[package]] 177 | name = "windows_x86_64_gnullvm" 178 | version = "0.48.2" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d" 181 | 182 | [[package]] 183 | name = "windows_x86_64_msvc" 184 | version = "0.48.2" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9" 187 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lean-rs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | # [profile.release] 9 | # debug = true 10 | 11 | [dependencies] 12 | lean-sys = { git = "https://github.com/digama0/lean-sys.git", version = "0.0.6" } 13 | lean-base = { path = "./base", version = "0.1.0" } 14 | 15 | [features] 16 | 17 | [workspace] 18 | members = [ 19 | "base", 20 | "build" 21 | ] 22 | -------------------------------------------------------------------------------- /base/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lean-base" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | lean-sys = { git = "https://github.com/digama0/lean-sys.git", version = "0.0.6" } 10 | 11 | [features] 12 | nightly = [] 13 | -------------------------------------------------------------------------------- /base/bootstrap/.gitignore: -------------------------------------------------------------------------------- 1 | /.lake 2 | -------------------------------------------------------------------------------- /base/bootstrap/Bootstrap.lean: -------------------------------------------------------------------------------- 1 | import Lean 2 | import Lake.Load.Package 3 | open Lean 4 | 5 | /-- Unsafe implementation of `evalConstCheck`. -/ 6 | unsafe def unsafeEvalConstCheck (env : Environment) (opts : Options) (α) (type : Name) (const : Name) : Except String α := 7 | match env.find? const with 8 | | none => throw s!"unknown constant '{const}'" 9 | | some info => 10 | match info.type with 11 | | Expr.const c _ => 12 | if c != type then 13 | throwUnexpectedType 14 | else 15 | env.evalConst α opts const 16 | | _ => throwUnexpectedType 17 | where 18 | throwUnexpectedType : Except String α := 19 | throw s!"unexpected type at '{const}', `{type}` expected" 20 | 21 | /-- Like `Lean.Environment.evalConstCheck`, but with plain universe-polymorphic `Except`. -/ 22 | @[implemented_by unsafeEvalConstCheck] opaque evalConstCheck' 23 | (env : Environment) (opts : Options) (α) (type : Name) (const : Name) : Except String α 24 | 25 | /-- Load a `PackageConfig` from a configuration environment. -/ 26 | def PackageConfig.loadFromEnv 27 | (env : Environment) (opts := Options.empty) : Except String Lake.PackageConfig := do 28 | let declName ← 29 | match Lake.packageAttr.ext.getState env |>.toList with 30 | | [] => .error s!"configuration file is missing a `package` declaration" 31 | | [name] => pure name 32 | | _ => .error s!"configuration file has multiple `package` declarations" 33 | evalConstCheck' env opts _ ``Lake.PackageConfig declName 34 | 35 | def foo := PackageConfig.loadFromEnv 36 | -------------------------------------------------------------------------------- /base/bootstrap/Main.lean: -------------------------------------------------------------------------------- 1 | import Bootstrap 2 | 3 | def main (_args : List String) : IO Unit := do 4 | match foo (← Lean.mkEmptyEnvironment) with 5 | | .ok _ => panic! "ho" 6 | | .error _ => panic! "hi" 7 | -------------------------------------------------------------------------------- /base/bootstrap/lake-manifest.json: -------------------------------------------------------------------------------- 1 | {"version": 7, 2 | "packagesDir": ".lake/packages", 3 | "packages": [], 4 | "name": "«lean-rs-bootstrap»", 5 | "lakeDir": ".lake"} 6 | -------------------------------------------------------------------------------- /base/bootstrap/lakefile.lean: -------------------------------------------------------------------------------- 1 | import Lake 2 | open Lake DSL 3 | 4 | package «lean-rs-bootstrap» 5 | 6 | @[default_target] lean_lib Bootstrap 7 | @[default_target] lean_exe Main 8 | -------------------------------------------------------------------------------- /base/src/closure.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::too_many_arguments)] 2 | 3 | use crate::TObj; 4 | 5 | impl TObj R> { 6 | pub fn invoke(self) -> TObj { 7 | let f = self.obj.into_raw(); 8 | unsafe { 9 | let res = lean_sys::lean_apply_1(f, lean_sys::lean_box(0)); 10 | TObj::from_raw(res) 11 | } 12 | } 13 | } 14 | 15 | #[cfg(feature = "nightly")] 16 | impl FnOnce<()> for TObj R> { 17 | type Output = TObj; 18 | extern "rust-call" fn call_once(self, _args: ()) -> Self::Output { 19 | self.invoke() 20 | } 21 | } 22 | 23 | macro_rules! fixed_closures { 24 | (@fn $apply_func:ident($($arg:ident),*)) => { 25 | #[allow(non_snake_case)] 26 | impl<$($arg: ?Sized,)* R: ?Sized> TObj R> { 27 | pub fn invoke(self, $($arg: TObj<$arg>,)*) -> TObj { 28 | let f = self.obj.into_raw(); 29 | unsafe { 30 | let res = lean_sys::$apply_func(f, $($arg.into_raw(),)*); 31 | crate:: TObj::from_raw(res) 32 | } 33 | } 34 | } 35 | 36 | #[cfg(feature = "nightly")] 37 | #[allow(non_snake_case)] 38 | impl<$($arg: ?Sized,)* R: ?Sized> FnOnce<($(TObj<$arg>,)*)> for TObj R> { 39 | type Output = TObj; 40 | extern "rust-call" fn call_once(self, ($($arg,)*): ($(TObj<$arg>,)*)) -> Self::Output { 41 | self.invoke($($arg,)*) 42 | } 43 | } 44 | }; 45 | (@impl ($($args:ident)*)) => {}; 46 | (@impl ($($args:ident)*) ($apply_func:ident $arg:ident) $($rest:tt)*) => { 47 | fixed_closures!(@fn $apply_func($($args,)* $arg)); 48 | fixed_closures!(@impl ($($args)* $arg) $($rest)*); 49 | }; 50 | ($($apply_func:ident($arg:ident);)*) => { 51 | fixed_closures!(@impl () $(($apply_func $arg))*); 52 | } 53 | } 54 | 55 | fixed_closures! { 56 | lean_apply_1(T1); 57 | lean_apply_2(T2); 58 | lean_apply_3(T3); 59 | lean_apply_4(T4); 60 | lean_apply_5(T5); 61 | lean_apply_6(T6); 62 | lean_apply_7(T7); 63 | lean_apply_8(T8); 64 | lean_apply_9(T9); 65 | lean_apply_10(T10); 66 | lean_apply_11(T11); 67 | lean_apply_12(T12); 68 | lean_apply_13(T13); 69 | lean_apply_14(T14); 70 | lean_apply_15(T15); 71 | lean_apply_16(T16); 72 | } 73 | -------------------------------------------------------------------------------- /base/src/external.rs: -------------------------------------------------------------------------------- 1 | use std::{ffi::c_void, ops::Deref}; 2 | 3 | use lean_sys::{ 4 | lean_alloc_external, lean_apply_1, lean_external_class, lean_get_external_data, 5 | lean_is_exclusive, lean_register_external_class, 6 | }; 7 | 8 | use crate::{Layout, Obj, ObjPtr, TObj, TObjRef}; 9 | 10 | pub unsafe trait ForeachObj { 11 | fn foreach_obj(&self, _f: &F) {} 12 | } 13 | 14 | unsafe impl ForeachObj for Obj { 15 | fn foreach_obj(&self, f: &F) { 16 | f(self.clone()) 17 | } 18 | } 19 | unsafe impl ForeachObj for TObj { 20 | fn foreach_obj(&self, f: &F) { 21 | self.obj.foreach_obj(f) 22 | } 23 | } 24 | 25 | #[derive(Clone, Copy)] 26 | #[repr(transparent)] 27 | pub struct ExternalClass { 28 | class: lean_external_class, 29 | _phantom: std::marker::PhantomData, 30 | } 31 | 32 | impl Default for ExternalClass { 33 | fn default() -> Self { 34 | Self::CLASS 35 | } 36 | } 37 | 38 | impl ExternalClass { 39 | pub const CLASS: Self = { 40 | unsafe extern "C" fn foreach(data: *mut c_void, closure: ObjPtr) { 41 | let data = data as *mut T; 42 | let f = TObjRef::::from_raw(closure); 43 | (*data).foreach_obj(&move |obj| { 44 | lean_apply_1(f.to_owned().into_raw(), obj.into_raw()); 45 | }) 46 | } 47 | 48 | unsafe extern "C" fn finalize(data: *mut c_void) { 49 | let data = data as *mut T; 50 | drop(Box::from_raw(data)); 51 | } 52 | 53 | Self { 54 | class: lean_external_class { 55 | m_finalize: Some(finalize::), 56 | m_foreach: Some(foreach::), 57 | }, 58 | _phantom: std::marker::PhantomData, 59 | } 60 | }; 61 | 62 | pub const fn raw(&self) -> *mut lean_external_class { 63 | &self.class as *const _ as *mut _ 64 | } 65 | 66 | pub fn register(self) -> &'static Self { 67 | let class = 68 | unsafe { lean_register_external_class(self.class.m_finalize, self.class.m_foreach) }; 69 | unsafe { &*(class as *mut Self) } 70 | } 71 | } 72 | 73 | pub trait AsExternalObj: ForeachObj + Sized + 'static {} 74 | 75 | pub struct External { 76 | data: *mut T, 77 | } 78 | 79 | impl External { 80 | pub fn new(data: T) -> Self { 81 | External { 82 | data: Box::into_raw(Box::new(data)), 83 | } 84 | } 85 | } 86 | 87 | impl Layout for External { 88 | unsafe fn pack_obj(value: Self) -> Obj { 89 | let cls = ExternalClass::::CLASS.raw(); 90 | unsafe { Obj(lean_alloc_external(cls, value.data as *mut c_void)) } 91 | } 92 | 93 | unsafe fn unpack_obj(value: Obj) -> Self { 94 | let data = lean_get_external_data(value.0) as *mut T; 95 | Self { data } 96 | } 97 | } 98 | 99 | impl Deref for TObj> { 100 | type Target = T; 101 | fn deref(&self) -> &Self::Target { 102 | unsafe { &*(lean_get_external_data(self.obj.0) as *mut T) } 103 | } 104 | } 105 | 106 | impl Deref for TObjRef<'_, External> { 107 | type Target = T; 108 | fn deref(&self) -> &Self::Target { 109 | unsafe { &*(lean_get_external_data(self.obj) as *mut T) } 110 | } 111 | } 112 | 113 | impl From for TObj> { 114 | fn from(value: T) -> Self { 115 | External::new(value).pack() 116 | } 117 | } 118 | 119 | impl TObj> { 120 | pub fn make_mut(&mut self) -> &mut T 121 | where 122 | T: Clone, 123 | { 124 | if !unsafe { lean_is_exclusive(self.obj.0) } { 125 | *self = (**self).clone().into(); 126 | } 127 | unsafe { &mut *(lean_get_external_data(self.obj.0) as *mut T) } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /base/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::missing_safety_doc)] 2 | #![cfg_attr(feature = "nightly", feature(fn_traits, unboxed_closures))] 3 | 4 | pub mod closure; 5 | pub mod external; 6 | pub mod typed; 7 | use lean_sys::*; 8 | pub use typed::*; 9 | 10 | pub type ObjPtr = *mut lean_object; 11 | #[repr(transparent)] 12 | pub struct Obj(pub ObjPtr); 13 | impl Drop for Obj { 14 | fn drop(&mut self) { 15 | unsafe { lean_dec(self.0) } 16 | } 17 | } 18 | impl Clone for Obj { 19 | fn clone(&self) -> Self { 20 | unsafe { lean_inc(self.0) }; 21 | Self(self.0) 22 | } 23 | } 24 | impl Obj { 25 | pub const fn from_usize(n: usize) -> Self { 26 | Self(lean_box(n)) 27 | } 28 | 29 | pub const fn from_bool(n: bool) -> Self { 30 | Self(lean_box(n as usize)) 31 | } 32 | 33 | pub unsafe fn ctor_get(&self, i: u32) -> &Self { 34 | debug_assert!(i < lean_ctor_num_objs(self.0)); 35 | &*lean_ctor_obj_cptr(self.0).add(i as usize).cast() 36 | } 37 | 38 | pub unsafe fn ctor_tag(&self) -> u32 { 39 | lean_obj_tag(self.0) 40 | } 41 | 42 | pub fn into_raw(self) -> ObjPtr { 43 | let p = self.0; 44 | std::mem::forget(self); 45 | p 46 | } 47 | 48 | pub unsafe fn ctor(tag: u8, args: [Obj; N], scalars: T) -> Obj { 49 | let o = Obj(lean_alloc_ctor( 50 | tag.into(), 51 | args.len() as u32, 52 | std::mem::size_of::() as _, 53 | )); 54 | let ptr = lean_ctor_obj_cptr(o.0).cast::<[Obj; N]>(); 55 | ptr.write(args); 56 | ptr.add(1).cast::().write(scalars); 57 | o 58 | } 59 | 60 | pub fn mk_string(s: &str) -> Self { 61 | unsafe { Self(lean_mk_string_from_bytes(s.as_ptr(), s.len())) } 62 | } 63 | 64 | pub unsafe fn to_string(&self) -> &str { 65 | std::str::from_utf8_unchecked(std::slice::from_raw_parts( 66 | &*lean_string_cstr(self.0), 67 | lean_string_size(self.0) - 1, 68 | )) 69 | } 70 | } 71 | 72 | pub const NIL: ObjPtr = lean_box(0); 73 | 74 | pub unsafe fn io(res: TObj>) -> Result, Obj> { 75 | match res.unpack() { 76 | IoResult::Ok(val) => Ok(val), 77 | IoResult::Err(res) => Err(res), 78 | } 79 | } 80 | 81 | pub unsafe fn run( 82 | init: Option TObj>>, 83 | body: impl FnOnce() -> Result<(), Obj>, 84 | ) -> Result<(), Obj> { 85 | lean_initialize(); 86 | let res; 87 | if let Some(init) = init { 88 | lean_set_panic_messages(false); 89 | res = io(init(1, NIL)); 90 | lean_set_panic_messages(true); 91 | } else { 92 | res = Ok(TObj::from_raw(NIL)) 93 | } 94 | lean_io_mark_end_initialization(); 95 | let res = res.and_then(|_| { 96 | lean_init_task_manager(); 97 | body() 98 | }); 99 | lean_finalize_task_manager(); 100 | res 101 | } 102 | -------------------------------------------------------------------------------- /base/src/typed.rs: -------------------------------------------------------------------------------- 1 | use std::{marker::PhantomData, ops::Deref}; 2 | 3 | use super::*; 4 | 5 | pub trait Layout { 6 | unsafe fn pack_obj(_: Self) -> Obj; 7 | unsafe fn unpack_obj(_: Obj) -> Self; 8 | fn pack(self) -> TObj 9 | where 10 | Self: Sized, 11 | { 12 | unsafe { TObj::new(Self::pack_obj(self)) } 13 | } 14 | } 15 | 16 | #[repr(transparent)] 17 | pub struct TObj { 18 | pub(crate) obj: Obj, 19 | val: PhantomData, 20 | } 21 | 22 | #[repr(transparent)] 23 | pub struct TObjRef<'a, A: ?Sized> { 24 | pub(crate) obj: ObjPtr, 25 | val: PhantomData<&'a A>, 26 | } 27 | 28 | impl<'a, A: ?Sized> Clone for TObjRef<'a, A> { 29 | fn clone(&self) -> Self { 30 | *self 31 | } 32 | } 33 | 34 | impl<'a, A: ?Sized> Copy for TObjRef<'a, A> {} 35 | 36 | impl Clone for TObj { 37 | fn clone(&self) -> Self { 38 | Self { 39 | obj: self.obj.clone(), 40 | val: self.val, 41 | } 42 | } 43 | } 44 | 45 | impl TObjRef<'_, A> { 46 | pub const unsafe fn from_raw(obj: ObjPtr) -> Self { 47 | Self { 48 | obj, 49 | val: PhantomData, 50 | } 51 | } 52 | pub fn to_owned(self) -> TObj { 53 | unsafe { 54 | lean_inc(self.obj); 55 | TObj::from_raw(self.obj) 56 | } 57 | } 58 | } 59 | 60 | impl TObj { 61 | pub const unsafe fn new(obj: Obj) -> Self { 62 | Self { 63 | obj, 64 | val: PhantomData, 65 | } 66 | } 67 | pub const unsafe fn from_raw(obj: ObjPtr) -> Self { 68 | Self::new(Obj(obj)) 69 | } 70 | pub fn into_obj(self) -> Obj { 71 | self.obj 72 | } 73 | pub fn into_raw(self) -> ObjPtr { 74 | self.obj.into_raw() 75 | } 76 | pub fn unpack(self) -> A 77 | where 78 | A: Layout + Sized, 79 | { 80 | unsafe { A::unpack_obj(self.obj) } 81 | } 82 | pub fn as_ref(&self) -> TObjRef<'_, A> { 83 | TObjRef { 84 | obj: self.obj.0, 85 | val: PhantomData, 86 | } 87 | } 88 | } 89 | 90 | impl Deref for TObj { 91 | type Target = str; 92 | fn deref(&self) -> &Self::Target { 93 | unsafe { self.obj.to_string() } 94 | } 95 | } 96 | 97 | impl From<&str> for TObj { 98 | fn from(value: &str) -> Self { 99 | unsafe { TObj::new(Obj::mk_string(value)) } 100 | } 101 | } 102 | 103 | pub enum List { 104 | Nil, 105 | Cons(TObj, TObj>), 106 | } 107 | 108 | impl Layout for List { 109 | unsafe fn pack_obj(layout: Self) -> Obj { 110 | match layout { 111 | List::Nil => Obj(NIL), 112 | List::Cons(hd, tl) => Obj::ctor(1, [hd.obj, tl.obj], ()), 113 | } 114 | } 115 | 116 | unsafe fn unpack_obj(o: Obj) -> Self { 117 | match o.ctor_tag() { 118 | 0 => Self::Nil, 119 | 1 => Self::Cons( 120 | TObj::new(o.ctor_get(0).clone()), 121 | TObj::new(o.ctor_get(1).clone()), 122 | ), 123 | _ => unreachable!(), 124 | } 125 | } 126 | } 127 | 128 | pub struct Array(PhantomData); 129 | 130 | impl TObj> { 131 | #[allow(clippy::should_implement_trait)] 132 | pub fn from_iter(iter: impl ExactSizeIterator>) -> Self { 133 | let size = iter.len(); 134 | unsafe { 135 | let o = Obj(lean_alloc_array(size, size)); 136 | for (i, val) in iter.enumerate() { 137 | lean_array_set_core(o.0, i, val.into_raw()) 138 | } 139 | Self::new(o) 140 | } 141 | } 142 | } 143 | 144 | impl>> From> for TObj> { 145 | fn from(value: Vec) -> Self { 146 | Self::from_iter(value.into_iter().map(Into::into)) 147 | } 148 | } 149 | 150 | pub enum IoResult { 151 | Ok(TObj), 152 | Err(Obj), 153 | } 154 | 155 | impl Layout for IoResult { 156 | unsafe fn pack_obj(layout: Self) -> Obj { 157 | match layout { 158 | IoResult::Ok(e) => Obj::ctor(0, [e.obj, Obj(NIL)], ()), 159 | IoResult::Err(e) => Obj::ctor(1, [e, Obj(NIL)], ()), 160 | } 161 | } 162 | 163 | unsafe fn unpack_obj(o: Obj) -> Self { 164 | match lean_ptr_tag(o.0) { 165 | 0 => Self::Ok(TObj::new(o.ctor_get(0).clone())), 166 | 1 => Self::Err(o.ctor_get(0).clone()), 167 | _ => unreachable!(), 168 | } 169 | } 170 | } 171 | 172 | pub enum Except { 173 | Err(TObj), 174 | Ok(TObj), 175 | } 176 | 177 | impl Layout for Except { 178 | unsafe fn pack_obj(layout: Self) -> Obj { 179 | match layout { 180 | Except::Err(e) => Obj::ctor(0, [e.obj], ()), 181 | Except::Ok(e) => Obj::ctor(1, [e.obj], ()), 182 | } 183 | } 184 | 185 | unsafe fn unpack_obj(o: Obj) -> Self { 186 | match lean_ptr_tag(o.0) { 187 | 0 => Self::Err(TObj::new(o.ctor_get(0).clone())), 188 | 1 => Self::Ok(TObj::new(o.ctor_get(0).clone())), 189 | _ => unreachable!(), 190 | } 191 | } 192 | } 193 | 194 | pub type LeanOption = Option>; 195 | 196 | impl Layout for LeanOption { 197 | unsafe fn pack_obj(layout: Self) -> Obj { 198 | match layout { 199 | None => Obj(NIL), 200 | Some(e) => Obj::ctor(1, [e.obj], ()), 201 | } 202 | } 203 | 204 | unsafe fn unpack_obj(o: Obj) -> Self { 205 | match lean_ptr_tag(o.0) { 206 | 0 => None, 207 | 1 => Some(TObj::new(o.ctor_get(0).clone())), 208 | _ => unreachable!(), 209 | } 210 | } 211 | } 212 | 213 | pub type Pair = (TObj, TObj); 214 | 215 | impl Layout for Pair { 216 | unsafe fn pack_obj(layout: Self) -> Obj { 217 | Obj::ctor(0, [layout.0.obj, layout.1.obj], ()) 218 | } 219 | 220 | unsafe fn unpack_obj(o: Obj) -> Self { 221 | ( 222 | TObj::new(o.ctor_get(0).clone()), 223 | TObj::new(o.ctor_get(1).clone()), 224 | ) 225 | } 226 | } 227 | 228 | impl Layout for bool { 229 | unsafe fn pack_obj(layout: Self) -> Obj { 230 | Obj(lean_box(layout as usize)) 231 | } 232 | 233 | unsafe fn unpack_obj(o: Obj) -> Self { 234 | lean_unbox(o.into_raw()) != 0 235 | } 236 | } 237 | 238 | impl Layout for usize { 239 | unsafe fn pack_obj(layout: Self) -> Obj { 240 | Obj(lean_box_usize(layout)) 241 | } 242 | 243 | unsafe fn unpack_obj(o: Obj) -> Self { 244 | lean_unbox_usize(o.into_raw()) 245 | } 246 | } 247 | 248 | impl Layout for u64 { 249 | unsafe fn pack_obj(layout: Self) -> Obj { 250 | Obj(lean_box_uint64(layout)) 251 | } 252 | 253 | unsafe fn unpack_obj(o: Obj) -> Self { 254 | lean_unbox_uint64(o.into_raw()) 255 | } 256 | } 257 | 258 | impl Layout for u32 { 259 | unsafe fn pack_obj(layout: Self) -> Obj { 260 | Obj(lean_box_uint32(layout)) 261 | } 262 | 263 | unsafe fn unpack_obj(o: Obj) -> Self { 264 | lean_unbox_uint32(o.into_raw()) 265 | } 266 | } 267 | 268 | impl Layout for u16 { 269 | unsafe fn pack_obj(layout: Self) -> Obj { 270 | Obj(lean_box(layout as usize)) 271 | } 272 | 273 | unsafe fn unpack_obj(o: Obj) -> Self { 274 | lean_unbox(o.into_raw()) as u16 275 | } 276 | } 277 | 278 | impl Layout for u8 { 279 | unsafe fn pack_obj(layout: Self) -> Obj { 280 | Obj(lean_box(layout as usize)) 281 | } 282 | 283 | unsafe fn unpack_obj(o: Obj) -> Self { 284 | lean_unbox(o.into_raw()) as u8 285 | } 286 | } 287 | 288 | impl Layout for f64 { 289 | unsafe fn pack_obj(layout: Self) -> Obj { 290 | Obj(lean_box_float(layout)) 291 | } 292 | 293 | unsafe fn unpack_obj(o: Obj) -> Self { 294 | lean_unbox_float(o.into_raw()) 295 | } 296 | } 297 | 298 | pub struct Environment { 299 | pub const_to_mod_idx: Obj, 300 | pub constants: Obj, 301 | pub extensions: Obj, 302 | pub extra_const_names: Obj, 303 | pub header: Obj, 304 | } 305 | 306 | impl Layout for Environment { 307 | unsafe fn pack_obj( 308 | Environment { 309 | const_to_mod_idx, 310 | constants, 311 | extensions, 312 | extra_const_names, 313 | header, 314 | }: Self, 315 | ) -> Obj { 316 | Obj::ctor( 317 | 0, 318 | [ 319 | const_to_mod_idx, 320 | constants, 321 | extensions, 322 | extra_const_names, 323 | header, 324 | ], 325 | (), 326 | ) 327 | } 328 | 329 | unsafe fn unpack_obj(o: Obj) -> Self { 330 | Self { 331 | const_to_mod_idx: o.ctor_get(0).clone(), 332 | constants: o.ctor_get(1).clone(), 333 | extensions: o.ctor_get(2).clone(), 334 | extra_const_names: o.ctor_get(3).clone(), 335 | header: o.ctor_get(4).clone(), 336 | } 337 | } 338 | } 339 | 340 | pub struct Name; 341 | pub struct Module; 342 | pub struct Options; 343 | pub struct Import; 344 | 345 | #[cfg(test)] 346 | pub(crate) mod test { 347 | use super::*; 348 | 349 | /// Initialize lean_runtime at each thread exactly once 350 | pub fn initialize_thread_local_runtime() { 351 | thread_local! { 352 | static INITIALIZED: std::sync::Once = std::sync::Once::new(); 353 | } 354 | INITIALIZED.with(|x| { 355 | x.call_once(|| unsafe { 356 | lean_sys::lean_initialize_runtime_module(); 357 | }) 358 | }); 359 | } 360 | 361 | #[test] 362 | fn test_u8() { 363 | initialize_thread_local_runtime(); 364 | for i in u8::MIN..u8::MAX { 365 | let o = i.pack(); 366 | assert_eq!(o.unpack(), i); 367 | } 368 | } 369 | 370 | #[test] 371 | fn test_u16() { 372 | initialize_thread_local_runtime(); 373 | for i in 0..16 { 374 | let o = (1u16 << i).pack(); 375 | assert_eq!(o.unpack(), (1u16 << i)); 376 | } 377 | } 378 | 379 | #[test] 380 | fn test_u32() { 381 | initialize_thread_local_runtime(); 382 | for i in 0..32 { 383 | let o = (1u32 << i).pack(); 384 | assert_eq!(o.unpack(), (1u32 << i)); 385 | } 386 | } 387 | 388 | #[test] 389 | fn test_u64() { 390 | initialize_thread_local_runtime(); 391 | for i in 0..64 { 392 | let o = (1u64 << i).pack(); 393 | assert_eq!(o.unpack(), (1u64 << i)); 394 | } 395 | } 396 | 397 | #[test] 398 | fn test_usize() { 399 | initialize_thread_local_runtime(); 400 | for i in 0..usize::BITS { 401 | let o = (1usize << i).pack(); 402 | assert_eq!(o.unpack(), (1usize << i)); 403 | } 404 | } 405 | } 406 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rustc-link-arg=-rdynamic"); 3 | } 4 | -------------------------------------------------------------------------------- /build/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lean-build" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | lean-base = { path = "../base", version = "0.1.0" } 10 | 11 | [features] 12 | -------------------------------------------------------------------------------- /build/src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lean-toolchain: -------------------------------------------------------------------------------- 1 | leanprover/lean4:v4.6.0 2 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use lean_base::*; 2 | use lean_sys::*; 3 | 4 | extern "C" { 5 | fn initialize_Lean(builtin: u8, w: ObjPtr) -> TObj>; 6 | fn l_Lean_findSysroot(_: TObj, w: ObjPtr) -> TObj>; 7 | fn l_Lean_initSearchPath( 8 | leanSysroot: TObj, 9 | sp: TObj>, 10 | w: ObjPtr, 11 | ) -> TObj>; 12 | fn l_String_toName(s: TObj) -> TObj; 13 | fn lean_import_modules( 14 | imports: TObj>, 15 | opts: TObj, 16 | trustLevel: u32, 17 | w: ObjPtr, 18 | ) -> TObj>; 19 | fn l_Lean_SMap_size___rarg(s: ObjPtr) -> Obj; 20 | fn lean_eval_const( 21 | env: TObjRef<'_, Environment>, 22 | opts: TObjRef<'_, Options>, 23 | name: TObjRef<'_, Name>, 24 | ) -> TObj>; 25 | fn lean_run_frontend( 26 | input: TObj, 27 | opts: TObj, 28 | filename: TObj, 29 | main_module: TObj, 30 | trust_level: u32, 31 | ilean_file: TObj>, 32 | w: ObjPtr, 33 | ) -> TObj>>; 34 | fn lean_enable_initializer_execution(w: ObjPtr) -> TObj>; 35 | } 36 | 37 | unsafe fn init() -> Result<(), Obj> { 38 | let sysroot = io(l_Lean_findSysroot("lean".into(), NIL))?; 39 | println!("{:?}", &*sysroot); 40 | io(l_Lean_initSearchPath( 41 | sysroot, 42 | // List::Nil.pack(), 43 | List::Cons("base/bootstrap/.lake/build/lib".into(), List::Nil.pack()).pack(), 44 | NIL, 45 | ))?; 46 | io(lean_enable_initializer_execution(NIL))?; 47 | Ok(()) 48 | } 49 | 50 | unsafe fn import_modules(mods: &[&str], opts: TObj) -> Result, Obj> { 51 | let imports = TObj::from_iter(mods.iter().map(|&mod_| { 52 | let mod_ = l_String_toName(mod_.into()); 53 | TObj::new(Obj::ctor(0, [mod_.into_obj()], false)) 54 | })); 55 | io(lean_import_modules(imports, opts, 0, NIL)) 56 | } 57 | 58 | unsafe fn eval_const( 59 | env: TObjRef, 60 | opts: TObjRef, 61 | decl_name: TObjRef, 62 | ) -> TObj { 63 | match lean_eval_const(env, opts, decl_name).unpack() { 64 | Except::Ok(val) => TObj::new(val.into_obj()), 65 | Except::Err(s) => panic!("{}", &*s), 66 | } 67 | } 68 | fn run_frontend( 69 | file: &str, 70 | opts: TObj, 71 | mod_name: TObj, 72 | ) -> Result, Obj> { 73 | unsafe { 74 | let contents = std::fs::read_to_string(file).unwrap(); 75 | let (env, ok) = io(lean_run_frontend( 76 | (&*contents).into(), 77 | opts, 78 | file.into(), 79 | mod_name, 80 | 1024, 81 | None.pack(), 82 | NIL, 83 | ))? 84 | .unpack(); 85 | assert!(ok.unpack(), "file has errors; aborting"); 86 | Ok(env) 87 | } 88 | } 89 | 90 | unsafe fn body() -> Result<(), Obj> { 91 | let file = std::env::args().nth(1).unwrap_or_else(|| ".".into()) + "/lakefile.lean"; 92 | init()?; 93 | let opts = TObj::::from_raw(NIL); 94 | let env = import_modules(&["Bootstrap"], opts.clone())?; 95 | let s = eval_const::>( 96 | env.as_ref(), 97 | opts.as_ref(), 98 | l_String_toName(TObj::from("foo")).as_ref(), 99 | ); 100 | 101 | let env = run_frontend(&file, opts, l_String_toName("_Lakefile".into()))?; 102 | println!( 103 | "{} constants", 104 | lean_unbox(l_Lean_SMap_size___rarg(env.unpack().constants.0).0) 105 | ); 106 | Ok(()) 107 | } 108 | 109 | fn main() { 110 | unsafe { 111 | // let res = run(Some(initialize_Lean), || body()); 112 | let res = run(None, || body()); 113 | if let Err(res) = res { 114 | lean_io_result_show_error(IoResult::<()>::Err(res).pack().into_obj().0); 115 | } 116 | } 117 | } 118 | --------------------------------------------------------------------------------