tool for me to use if i drop nixos
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dmx: add userdata, callstack, and new builtin functions

IamPyu d77292a0 2def1b5c

+248 -98
+90 -63
crates/dmx/src/builtins.rs
··· 1 1 use crate::{ 2 2 Expr, Func, RuntimeError, Scope, Type, 3 3 scope::{ASTRef, ScopeRef}, 4 - value::ExprRef, 4 + value::{ExprRef, Macro, PrimOp, UserData}, 5 5 }; 6 6 use std::sync::Arc; 7 7 ··· 10 10 ("nil", Expr::Nil), 11 11 ("true", Expr::Bool(true)), 12 12 ("false", Expr::Bool(false)), 13 - ("progn!", Expr::Macro(crate::value::Macro(macro_progn))), 14 - ("set!", Expr::Macro(crate::value::Macro(macro_set))), 15 - ("let", Expr::Macro(crate::value::Macro(macro_let))), 16 - ("lambda", Expr::Macro(crate::value::Macro(macro_lambda))), 17 - ("if", Expr::Macro(crate::value::Macro(macro_if))), 18 - ("list", Expr::PrimOp(crate::value::PrimOp(func_list))), 19 - ("debug", Expr::PrimOp(crate::value::PrimOp(func_debug))), 20 - ("nth", Expr::PrimOp(crate::value::PrimOp(func_nth))), 21 - ("map", Expr::PrimOp(crate::value::PrimOp(func_map))), 22 - ("not", Expr::PrimOp(crate::value::PrimOp(func_not))), 23 - ( 24 - "dump-scope", 25 - Expr::PrimOp(crate::value::PrimOp(func_dump_scope)), 26 - ), 27 - ("+", Expr::PrimOp(crate::value::PrimOp(func_add))), 28 - ("-", Expr::PrimOp(crate::value::PrimOp(func_sub))), 29 - ("*", Expr::PrimOp(crate::value::PrimOp(func_mul))), 30 - ("/", Expr::PrimOp(crate::value::PrimOp(func_div))), 13 + ("progn!", Expr::Macro(Macro(macro_progn))), 14 + ("set!", Expr::Macro(Macro(macro_set))), 15 + ("let", Expr::Macro(Macro(macro_let))), 16 + ("lambda", Expr::Macro(Macro(macro_lambda))), 17 + ("if", Expr::Macro(Macro(macro_if))), 18 + ("list", Expr::PrimOp(PrimOp(func_list))), 19 + ("debug", Expr::PrimOp(PrimOp(func_debug))), 20 + ("nth", Expr::PrimOp(PrimOp(func_nth))), 21 + ("map", Expr::PrimOp(PrimOp(func_map))), 22 + ("not", Expr::PrimOp(PrimOp(func_not))), 23 + ("pairs", Expr::PrimOp(PrimOp(func_pairs))), 24 + ("assert", Expr::PrimOp(PrimOp(func_assert))), 25 + ("test-userdata", Expr::PrimOp(PrimOp(func_test_userdata))), 26 + ("+", Expr::PrimOp(PrimOp(func_add))), 27 + ("-", Expr::PrimOp(PrimOp(func_sub))), 28 + ("*", Expr::PrimOp(PrimOp(func_mul))), 29 + ("/", Expr::PrimOp(PrimOp(func_div))), 31 30 ]; 32 31 33 32 for (name, value) in builtins { ··· 42 41 } 43 42 44 43 fn macro_set(scope: ScopeRef, args: ASTRef) -> Result<ExprRef, RuntimeError> { 45 - if args.len() != 1 { 44 + let [t] = &args[..] else { 46 45 return Err(RuntimeError::InvalidArguments(format!( 47 46 "expected 1 argument" 48 47 ))); 49 - } 48 + }; 49 + let t = scope.eval(ExprRef::clone(t))?; 50 50 51 - let t = scope.eval(ExprRef::clone(&args[0]))?; 52 51 match &*t { 53 52 Expr::Map(m) => { 54 53 for (k, v) in m { ··· 67 66 } 68 67 69 68 fn macro_let(scope: ScopeRef, args: ASTRef) -> Result<ExprRef, RuntimeError> { 70 - if args.len() < 2 { 69 + let [t, body @ ..] = &args[..] else { 71 70 return Err(RuntimeError::InvalidArguments(format!( 72 71 "expected 2 or more arguments" 73 72 ))); 74 - } 73 + }; 74 + let t = scope.eval(ExprRef::clone(t))?; 75 75 76 - let t = scope.eval(ExprRef::clone(&args[0]))?; 77 76 match &*t { 78 77 Expr::Map(m) => { 79 78 for (k, v) in m { 80 79 scope.set(k, ExprRef::clone(v)); 81 80 } 82 - let ast = &args[1..]; 81 + let ast = &body; 83 82 scope.eval_ast(&ast) 84 83 } 85 84 _ => { ··· 92 91 } 93 92 94 93 fn macro_lambda(scope: ScopeRef, args: ASTRef) -> Result<ExprRef, RuntimeError> { 95 - if args.len() < 2 { 94 + let [argv, ast @ ..] = &args[..] else { 96 95 return Err(RuntimeError::InvalidArguments(format!( 97 96 "expected 2 or more arguments" 98 97 ))); 99 - } 100 - 101 - let [argv, ast @ ..] = &args[..] else { 102 - unreachable!() 103 98 }; 104 99 105 100 let argn: Vec<String> = match &**argv { ··· 133 128 } 134 129 135 130 fn macro_if(scope: ScopeRef, args: ASTRef) -> Result<ExprRef, RuntimeError> { 136 - if args.len() != 3 { 131 + let [condition, p, q] = &args[..] else { 137 132 return Err(RuntimeError::InvalidArguments(format!( 138 133 "expected 3 arguments" 139 134 ))); 140 - } 141 - 142 - let [condition, p, q] = &args[..] else { 143 - unreachable!() 144 135 }; 145 136 146 137 if scope.eval(ExprRef::clone(condition))?.is_truthy() { ··· 166 157 167 158 fn func_nth(scope: ScopeRef, args: &[ExprRef]) -> Result<ExprRef, RuntimeError> { 168 159 let _ = scope; 169 - if args.len() != 2 { 160 + 161 + let [list, index] = &args[..] else { 170 162 return Err(RuntimeError::InvalidArguments(format!( 171 163 "expected 2 arguments" 172 164 ))); 173 - } 174 - 175 - let [list, index] = &args[..] else { 176 - unreachable!() 177 165 }; 178 166 179 167 match (&**list, &**index) { ··· 192 180 } 193 181 194 182 fn func_map(scope: ScopeRef, args: &[ExprRef]) -> Result<ExprRef, RuntimeError> { 195 - if args.len() != 2 { 183 + let [list, func] = &args[..] else { 196 184 return Err(RuntimeError::InvalidArguments(format!( 197 185 "expected 2 arguments" 198 186 ))); 199 - } 200 - 201 - let [list, func] = &args[..] else { 202 - unreachable!() 203 187 }; 204 188 205 189 match (&**list, &**func) { ··· 219 203 } 220 204 221 205 fn func_not(scope: ScopeRef, args: &[ExprRef]) -> Result<ExprRef, RuntimeError> { 222 - if args.len() != 1 { 223 - return Err(RuntimeError::Exception(format!("expected 1 argument"))); 224 - } 225 - 226 - let [p, ..] = &args[..] else { unreachable!() }; 206 + let [p] = &args[..] else { 207 + return Err(RuntimeError::InvalidArguments(format!( 208 + "expected 1 argument" 209 + ))); 210 + }; 227 211 228 212 Ok(scope.value(Expr::Bool(!p.is_truthy()))) 229 213 } 230 214 231 - fn func_dump_scope(scope: ScopeRef, args: &[ExprRef]) -> Result<ExprRef, RuntimeError> { 232 - let locals = scope.locals.lock().unwrap(); 215 + fn func_pairs(scope: ScopeRef, args: &[ExprRef]) -> Result<ExprRef, RuntimeError> { 216 + let [p] = &args[..] else { 217 + return Err(RuntimeError::InvalidArguments(format!( 218 + "expected 1 argument" 219 + ))); 220 + }; 233 221 234 - for (k, v) in locals.iter().filter_map(|(k, v)| Some((k, v.upgrade()?))) { 235 - eprintln!("{k}: {v}"); 222 + match &**p { 223 + Expr::Map(m) => { 224 + let mut list = Vec::with_capacity(m.capacity()); 225 + for (k, v) in m.iter() { 226 + let pair = Expr::List(vec![ 227 + ExprRef::new(Expr::String(k.to_owned())), 228 + ExprRef::clone(v), 229 + ]); 230 + // list.push(ExprRef::new(Expr::Quote(ExprRef::new(pair)))); 231 + list.push(ExprRef::new(pair)); 232 + } 233 + Ok(scope.value(Expr::List(list))) 234 + } 235 + _ => Err(RuntimeError::InvalidArguments(format!( 236 + "expected map for argument #1" 237 + ))), 236 238 } 239 + } 237 240 238 - if let Some(s) = scope.parent() { 239 - func_dump_scope(s, args)?; 241 + fn func_assert(scope: ScopeRef, args: &[ExprRef]) -> Result<ExprRef, RuntimeError> { 242 + let _ = scope; 243 + 244 + let [message, condition, value] = &args[..] else { 245 + return Err(RuntimeError::InvalidArguments(format!( 246 + "expected 3 arguments" 247 + ))); 248 + }; 249 + 250 + if condition.is_truthy() { 251 + Ok(ExprRef::clone(value)) 252 + } else { 253 + eprintln!("{message}"); 254 + Err(RuntimeError::Exception(format!("assert failed: {message}"))) 240 255 } 256 + } 241 257 242 - Ok(scope.value(Expr::Nil)) 258 + fn func_test_userdata(scope: ScopeRef, args: &[ExprRef]) -> Result<ExprRef, RuntimeError> { 259 + let _ = args; 260 + #[derive(Debug)] 261 + struct Test { 262 + a: i32, 263 + b: i32, 264 + } 265 + 266 + impl UserData for Test { 267 + fn as_string(&self) -> String { 268 + format!("{},{}", self.a, self.b) 269 + } 270 + } 271 + 272 + Ok(scope.value(Test { a: 43, b: 54 }.into_expr())) 243 273 } 244 274 245 275 macro_rules! arithmetic { 246 276 ($name:ident, $operator:ident) => { 247 277 fn $name(scope: ScopeRef, args: &[ExprRef]) -> Result<ExprRef, RuntimeError> { 248 278 let _ = scope; 249 - if args.len() < 1 { 279 + 280 + let [first, rest @ ..] = &args[..] else { 250 281 return Err(RuntimeError::InvalidArguments(format!( 251 282 "expected 1 or more arguments" 252 283 ))); 253 - } 254 - 255 - let [first, rest @ ..] = &args[..] else { 256 - unreachable!() 257 284 }; 258 285 259 286 let mut first = ExprRef::clone(first);
+7 -1
crates/dmx/src/engine.rs
··· 48 48 self.scope.eval_ast(&chunk.ast) 49 49 } 50 50 51 + pub fn eval_chunk_or_dump_stack(&self, chunk: &Chunk) -> Result<ExprRef, RuntimeError> { 52 + self.eval_chunk(chunk).inspect_err(|e| { 53 + self.scope.dump_callstack(Some(e)); 54 + }) 55 + } 56 + 51 57 pub fn get_scope<'engine>(&'engine self) -> &'engine Arc<Scope> { 52 58 &self.scope 53 59 } ··· 87 93 let engine = Engine::new(); 88 94 89 95 let chunk = Chunk::from_source(include_str!("./tests/hello.dmx")).unwrap(); 90 - engine.eval_chunk(&chunk).unwrap(); 96 + engine.eval_chunk_or_dump_stack(&chunk).unwrap(); 91 97 } 92 98 }
+8 -1
crates/dmx/src/lib.rs
··· 1 1 //! dmx expression language 2 2 3 - // TODO: stack traces 3 + // TODO: get line of code of call in stack trace 4 4 5 5 pub mod builtins; 6 6 pub mod engine; ··· 17 17 InvalidArguments(String), 18 18 #[error("exception occured: {0}")] 19 19 Exception(String), 20 + 21 + #[error("mutex poisoned: {0}")] 22 + MutexPoison(#[from] std::sync::PoisonError<Box<dyn std::any::Any>>), 23 + 24 + /// internal use only 25 + #[error("no callstack was found")] 26 + NoCallstack, 20 27 }
+49 -7
crates/dmx/src/scope.rs
··· 1 - use crate::{Expr, Map, RuntimeError}; 1 + use crate::{Expr, Map, RuntimeError, value::ExprRef}; 2 2 use std::{ 3 3 collections::HashMap, 4 4 sync::{Arc, Mutex, Weak}, ··· 11 11 12 12 pub type ScopeRef = Arc<Scope>; 13 13 14 + pub type Callstack = Vec<ExprRef>; 15 + 14 16 /// Scope, should only be accessed via when wrapped in an [Arc] 15 17 pub struct Scope { 16 18 pub(crate) this: Weak<Self>, 17 19 pub(crate) parent: Option<Weak<Self>>, 18 20 pub(crate) locals: Mutex<HashMap<Symbol, Weak<Expr>>>, 19 - pub(crate) values: Mutex<Vec<Arc<Expr>>>, 21 + pub(crate) values: Mutex<Vec<ExprRef>>, 22 + pub(crate) callstack: Option<Mutex<Vec<ExprRef>>>, 20 23 } 21 24 22 25 impl Scope { ··· 26 29 parent: None, 27 30 locals: Mutex::new(HashMap::new()), 28 31 values: Mutex::new(Vec::new()), 32 + callstack: Some(Mutex::new(Vec::new())), 29 33 }) 30 34 } 31 35 ··· 67 71 parent: Some(self.weak()), 68 72 locals: Mutex::new(HashMap::new()), 69 73 values: Mutex::new(Vec::new()), 74 + callstack: None, 70 75 }) 71 76 } 72 77 ··· 82 87 let [func, args @ ..] = &l[..] else { 83 88 unreachable!() 84 89 }; 85 - let func = self.eval(Arc::clone(func))?; 86 - self.call_function(func, args)? 90 + self.call_function(Arc::clone(&func), args)? 87 91 } 88 92 Expr::Map(m) => { 89 93 let mut m2 = Map::new(); ··· 96 100 }) 97 101 } 98 102 103 + pub(crate) fn push_callstack(self: &Arc<Self>, value: ExprRef) -> Result<(), RuntimeError> { 104 + match &self.callstack { 105 + Some(s) => s.lock().unwrap().push(value), 106 + None => { 107 + let p = self.parent().ok_or(RuntimeError::NoCallstack)?; 108 + p.push_callstack(value)?; 109 + } 110 + } 111 + Ok(()) 112 + } 113 + 114 + pub(crate) fn pop_callstack(self: &Arc<Self>) -> Result<Option<ExprRef>, RuntimeError> { 115 + match &self.callstack { 116 + Some(s) => Ok(s.lock().unwrap().pop()), 117 + None => { 118 + let p = self.parent().ok_or(RuntimeError::NoCallstack)?; 119 + p.pop_callstack() 120 + } 121 + } 122 + } 123 + 124 + pub fn dump_callstack(self: &Arc<Self>, err: Option<&RuntimeError>) { 125 + if let Some(e) = err { 126 + eprintln!("error occured: {e}"); 127 + } 128 + eprintln!("callstack dump:"); 129 + while let Ok(Some(e)) = self.pop_callstack() { 130 + eprintln!("...{e}"); 131 + } 132 + } 133 + 99 134 pub fn call_function( 100 135 self: &Arc<Self>, 101 136 func: Arc<Expr>, 102 137 args: &[Arc<Expr>], 103 138 ) -> Result<Arc<Expr>, RuntimeError> { 139 + self.push_callstack(Arc::clone(&func))?; 140 + 141 + let func = self.eval(func)?; 104 142 let branch = self.branch(); 105 - match &*func { 143 + 144 + let out = match &*func { 106 145 Expr::PrimOp(f) => { 107 146 let args: Vec<_> = args 108 147 .iter() ··· 131 170 "attempt to call something that isn't callable" 132 171 ))); 133 172 } 134 - } 173 + }?; 174 + self.pop_callstack()?; 175 + 176 + Ok(out) 135 177 } 136 178 137 179 pub fn eval_ast(self: &Arc<Self>, ast: ASTRef) -> Result<Arc<Expr>, RuntimeError> { ··· 154 196 use super::*; 155 197 156 198 #[test] 157 - fn a() { 199 + fn playground() { 158 200 let s = Scope::new(); 159 201 crate::builtins::load_builtins(&s); 160 202
+5
crates/dmx/src/tests/hello.dmx
··· 7 7 pi 3.1415926535, 8 8 func (lambda (x) (* x 2)), 9 9 } (list (func pi) gtr name pi))) 10 + 11 + (debug "map pairs:") 12 + (debug (map (pairs {a 1, b 2, c 3}) (lambda (x) (nth x 1)))) 13 + 14 + (debug (test-userdata))
+89 -26
crates/dmx/src/value.rs
··· 1 1 use crate::{ 2 - RuntimeError, 2 + RuntimeError, Scope, 3 3 scope::{AST, ASTRef, ScopeRef}, 4 4 }; 5 5 use indexmap::IndexMap; ··· 24 24 #[derive(Debug, Clone, Copy)] 25 25 pub struct PrimOp(pub fn(scope: ScopeRef, args: &[Arc<Expr>]) -> Result<Arc<Expr>, RuntimeError>); 26 26 27 - impl PartialEq for PrimOp { 28 - fn eq(&self, other: &Self) -> bool { 29 - let _ = other; 30 - false 31 - } 27 + // impl PartialEq for PrimOp { 28 + // fn eq(&self, other: &Self) -> bool { 29 + // let _ = other; 30 + // false 31 + // } 32 + // 33 + // fn ne(&self, other: &Self) -> bool { 34 + // let _ = other; 35 + // false 36 + // } 37 + // } 32 38 33 - fn ne(&self, other: &Self) -> bool { 34 - let _ = other; 35 - false 36 - } 37 - } 38 39 #[derive(Debug, Clone, Copy)] 39 40 pub struct Macro(pub fn(scope: ScopeRef, args: ASTRef) -> Result<Arc<Expr>, RuntimeError>); 40 41 41 - impl PartialEq for Macro { 42 - fn eq(&self, other: &Self) -> bool { 43 - let _ = other; 44 - false 45 - } 46 - 47 - fn ne(&self, other: &Self) -> bool { 48 - let _ = other; 49 - false 50 - } 51 - } 42 + // impl PartialEq for Macro { 43 + // fn eq(&self, other: &Self) -> bool { 44 + // let _ = other; 45 + // false 46 + // } 47 + // 48 + // fn ne(&self, other: &Self) -> bool { 49 + // let _ = other; 50 + // false 51 + // } 52 + // } 52 53 53 54 pub type ExprRef = Arc<Expr>; 54 55 pub type ExprWeak = Weak<Expr>; 55 56 56 57 /// Dynamic Expression 57 - #[derive(Default, Debug, Clone, PartialEq)] 58 + #[derive(Default, Debug, Clone)] 58 59 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 59 60 #[cfg_attr(feature = "serde", serde(untagged))] 60 61 pub enum Expr { ··· 74 75 PrimOp(PrimOp), 75 76 #[cfg_attr(feature = "serde", serde(skip))] 76 77 Macro(Macro), 78 + #[cfg_attr(feature = "serde", serde(skip))] 79 + UserData(Arc<dyn UserData>), 80 + } 81 + 82 + impl PartialEq for Expr { 83 + fn eq(&self, other: &Self) -> bool { 84 + match (self, other) { 85 + (Self::Nil, Self::Nil) => true, 86 + (Self::Bool(lhs), Self::Bool(rhs)) => *lhs == *rhs, 87 + (Self::Int(lhs), Self::Int(rhs)) => *lhs == *rhs, 88 + (Self::Float(lhs), Self::Float(rhs)) => *lhs == *rhs, 89 + (Self::Int(lhs), Self::Float(rhs)) => *rhs == *lhs as _, 90 + (Self::Float(lhs), Self::Int(rhs)) => *lhs == *rhs as _, 91 + (Self::Symbol(lhs), Self::Symbol(rhs)) => *lhs == *rhs, 92 + (Self::String(lhs), Self::String(rhs)) => *lhs == *rhs, 93 + (Self::List(lhs), Self::List(rhs)) => *lhs == *rhs, 94 + (Self::Map(lhs), Self::Map(rhs)) => *lhs == *rhs, 95 + (Self::UserData(lhs), Self::UserData(rhs)) => lhs.as_string() == rhs.as_string(), 96 + _ => false, 97 + } 98 + } 77 99 } 78 100 79 101 impl Expr { ··· 150 172 Self::String(s) => write!(f, "{s}"), 151 173 Self::Symbol(s) => write!(f, "'{s}"), 152 174 Self::Quote(q) => write!(f, "`{q}"), 153 - Self::Function(_) => write!(f, "function<@{}>", (self as *const Expr).addr()), 154 - Self::PrimOp(_) => write!(f, "primop<@{}>", (self as *const Expr).addr()), 155 - Self::Macro(_) => write!(f, "macro<@{}>", (self as *const Expr).addr()), 175 + Self::Function(_) => write!(f, "{}", format_memory_address(self, Some("function"))), 176 + Self::PrimOp(_) => write!(f, "{}", format_memory_address(self, Some("primop"))), 177 + Self::Macro(_) => write!(f, "{}", format_memory_address(self, Some("macro"))), 178 + Self::UserData(ud) => write!(f, "{}", ud.as_string()), 156 179 Self::List(l) => { 157 180 write!(f, "(")?; 158 181 let mut iter = l.iter().peekable(); ··· 195 218 Function, 196 219 PrimOp, 197 220 Macro, 221 + UserData, 198 222 } 199 223 200 224 impl Type { ··· 212 236 Self::Function => "function", 213 237 Self::PrimOp => "primop", 214 238 Self::Macro => "macro", 239 + Self::UserData => "userdata", 215 240 } 216 241 } 217 242 } ··· 231 256 Self::Function(_) => Type::Function, 232 257 Self::PrimOp(_) => Type::PrimOp, 233 258 Self::Macro(_) => Type::Macro, 259 + Self::UserData(_) => Type::UserData, 234 260 } 235 261 } 236 262 237 263 pub fn type_of_str(&self) -> &'static str { 238 264 self.type_of().as_str() 239 265 } 266 + } 267 + 268 + pub trait UserData: std::fmt::Debug + 'static { 269 + /// Type name of this userdata 270 + fn type_name(&self) -> &'static str { 271 + "userdata" 272 + } 273 + 274 + /// Display user data as string, default is memory address 275 + fn as_string(&self) -> String { 276 + format_memory_address(self, Some("userdata")) 277 + } 278 + 279 + /// Return whether `self` is callable 280 + fn callable(&self) -> bool { 281 + false 282 + } 283 + 284 + /// Call as callable 285 + fn call(&self, scope: Arc<Scope>) -> Option<Result<ExprRef, RuntimeError>> { 286 + let _ = scope; 287 + None 288 + } 289 + 290 + /// shouldn't be overridden 291 + fn into_expr(self) -> Expr 292 + where 293 + Self: Sized, 294 + { 295 + Expr::UserData(Arc::new(self)) 296 + } 297 + } 298 + 299 + pub fn format_memory_address<T: ?Sized>(x: &T, kind: Option<&str>) -> String { 300 + let addr = (x as *const T).addr(); 301 + let kind = kind.unwrap_or("value"); 302 + format!("{kind}<@{addr}>") 240 303 } 241 304 242 305 #[cfg(test)]