tree-based source processing language
5
fork

Configure Feed

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

simplify builtins more

+129 -183
+125 -179
src/builtins.rs
··· 3 3 use crate::{ 4 4 ast, 5 5 eval::{Context, Error, Result, Value}, 6 - Wrap 6 + Wrap, 7 7 }; 8 8 9 - pub static BUILTINS: LazyLock<HashMap<&'static str, Box<dyn Builtin + Sync + Send>>> = 10 - LazyLock::new(|| { 11 - [ 12 - Print.boxed(), 13 - IsUpper.boxed(), 14 - IsLower.boxed(), 15 - Substr.boxed(), 16 - Text.boxed(), 17 - Parent.boxed(), 18 - Children.boxed(), 19 - Length.boxed(), 20 - Kind.boxed(), 21 - ] 22 - .into_iter() 23 - .map(|b| (b.id(), b)) 24 - .collect() 25 - }); 26 - 27 - pub(crate) trait Builtin 28 - where 29 - Self: 'static, 30 - { 31 - /// Name of this function 32 - fn id(&self) -> &'static str; 33 - 34 - /// Function description 35 - fn eval(&self, ctx: &mut Context, args: &[ast::Expr]) -> Result; 36 - 37 - /// Anything that is Builtin can be turned into a trait object 38 - fn boxed(self) -> Box<dyn Builtin + Sync + Send> 39 - where 40 - Self: Sized + Sync + Send, 41 - { 42 - Box::new(self) as Box<dyn Builtin + Sync + Send> 9 + macro_rules! builtins { 10 + ($($f:ident),* $(,)?) => { 11 + pub static BUILTINS: LazyLock<HashMap<&'static str, Box<dyn Fn(&mut Context, &[ast::Expr]) -> Result + Sync + Send>>> = 12 + LazyLock::new(|| { 13 + [ 14 + $(( 15 + stringify!($f), 16 + Box::new($f) as Box<dyn Fn(&mut Context, &[ast::Expr]) -> Result + Sync + Send>, 17 + )),* 18 + ] 19 + .into_iter() 20 + .collect() 21 + }); 43 22 } 44 23 } 45 24 46 - fn get_args<const N: usize>(args: &[ast::Expr]) -> std::result::Result<&[ast::Expr; N], Error> { 47 - args.try_into().map_err(|_| Error::IncorrectArgFormat { 48 - wanted: N, 49 - got: args.len(), 50 - }) 51 - } 52 - 53 - struct Print; 54 - impl Builtin for Print { 55 - fn id(&self) -> &'static str { 56 - "print" 57 - } 25 + builtins! { 26 + print, 58 27 59 - fn eval(&self, ctx: &mut Context, args: &[ast::Expr]) -> Result { 60 - for arg in args { 61 - let val = ctx.eval_expr(arg)?; 62 - print!("{val}"); 63 - } 64 - Ok(Value::Unit) 65 - } 66 - } 28 + // string 29 + isupper, 30 + islower, 31 + substr, 67 32 68 - struct IsUpper; 69 - impl Builtin for IsUpper { 70 - fn id(&self) -> &'static str { 71 - "isupper" 72 - } 33 + // node 34 + text, 35 + parent, 36 + children, 37 + kind, 73 38 74 - fn eval(&self, ctx: &mut Context, args: &[ast::Expr]) -> Result { 75 - Ok(ctx 76 - .eval_expr(&get_args::<1>(args)?[0])? 77 - .as_str()? 78 - .chars() 79 - .all(|c| c.is_ascii_uppercase()) 80 - .into()) 81 - } 39 + // list 40 + length, 41 + member, 82 42 } 83 43 84 - struct IsLower; 85 - impl Builtin for IsLower { 86 - fn id(&self) -> &'static str { 87 - "islower" 44 + fn print(ctx: &mut Context, args: &[ast::Expr]) -> Result { 45 + for arg in args { 46 + let val = ctx.eval_expr(arg)?; 47 + print!("{val}"); 88 48 } 49 + Ok(Value::Unit) 50 + } 89 51 90 - fn eval(&self, ctx: &mut Context, args: &[ast::Expr]) -> Result { 91 - Ok(ctx 92 - .eval_expr(&get_args::<1>(args)?[0])? 93 - .as_str()? 94 - .chars() 95 - .all(|c| c.is_ascii_lowercase()) 96 - .into()) 97 - } 52 + fn isupper(ctx: &mut Context, args: &[ast::Expr]) -> Result { 53 + Ok(ctx 54 + .eval_expr(&get_args::<1>(args)?[0])? 55 + .as_str()? 56 + .chars() 57 + .all(|c| c.is_ascii_uppercase()) 58 + .into()) 98 59 } 99 60 100 - struct Substr; 101 - impl Builtin for Substr { 102 - fn id(&self) -> &'static str { 103 - "substr" 104 - } 61 + fn islower(ctx: &mut Context, args: &[ast::Expr]) -> Result { 62 + Ok(ctx 63 + .eval_expr(&get_args::<1>(args)?[0])? 64 + .as_str()? 65 + .chars() 66 + .all(|c| c.is_ascii_lowercase()) 67 + .into()) 68 + } 105 69 106 - fn eval(&self, ctx: &mut Context, args: &[ast::Expr]) -> Result { 107 - if let Ok([string, start, end]) = get_args::<3>(args) { 108 - let v = ctx.eval_expr(string)?; 109 - let s = v.as_str()?; 110 - let start = ctx.eval_expr(start)?.as_int()?; 111 - let end = ctx.eval_expr(end)?.as_int()?; 112 - if start < 0 || start >= s.len() as i128 || end >= s.len() as i128 || start > end { 113 - return Err(Error::InvalidStringSlice { 114 - length: s.len(), 115 - start, 116 - end, 117 - }); 118 - } 119 - Ok(s[start as usize..end as usize].into()) 120 - } else { 121 - let [string, end] = get_args::<2>(args)?; 122 - let v = ctx.eval_expr(string)?; 123 - let s = v.as_str()?; 124 - let end = ctx.eval_expr(end)?.as_int()?; 125 - if end >= s.len() as i128 { 126 - return Err(Error::InvalidStringSlice { 127 - length: s.len(), 128 - start: 0, 129 - end, 130 - }); 131 - } 132 - Ok(s[..end as usize].into()) 70 + fn substr(ctx: &mut Context, args: &[ast::Expr]) -> Result { 71 + if let Ok([string, start, end]) = get_args::<3>(args) { 72 + let v = ctx.eval_expr(string)?; 73 + let s = v.as_str()?; 74 + let start = ctx.eval_expr(start)?.as_int()?; 75 + let end = ctx.eval_expr(end)?.as_int()?; 76 + if start < 0 || start >= s.len() as i128 || end >= s.len() as i128 || start > end { 77 + return Err(Error::InvalidStringSlice { 78 + length: s.len(), 79 + start, 80 + end, 81 + }); 133 82 } 83 + Ok(s[start as usize..end as usize].into()) 84 + } else { 85 + let [string, end] = get_args::<2>(args)?; 86 + let v = ctx.eval_expr(string)?; 87 + let s = v.as_str()?; 88 + let end = ctx.eval_expr(end)?.as_int()?; 89 + if end >= s.len() as i128 { 90 + return Err(Error::InvalidStringSlice { 91 + length: s.len(), 92 + start: 0, 93 + end, 94 + }); 95 + } 96 + Ok(s[..end as usize].into()) 134 97 } 135 98 } 136 99 137 - struct Text; 138 - impl Builtin for Text { 139 - fn id(&self) -> &'static str { 140 - "text" 141 - } 142 - 143 - fn eval(&self, ctx: &mut Context, args: &[ast::Expr]) -> Result { 144 - let v = ctx.eval_expr(&get_args::<1>(args)?[0])?; 145 - let id = v.as_node()?; 146 - let node = ctx.get_node_by_id(id).unwrap(); 147 - let text = node 148 - .utf8_text(ctx.input_src.as_ref().unwrap().as_bytes()) 149 - .unwrap(); 150 - text.to_owned().wrap(Value::String).wrap(Ok) 151 - } 100 + fn text(ctx: &mut Context, args: &[ast::Expr]) -> Result { 101 + let v = ctx.eval_expr(&get_args::<1>(args)?[0])?; 102 + let id = v.as_node()?; 103 + let node = ctx.get_node_by_id(id).unwrap(); 104 + let text = node 105 + .utf8_text(ctx.input_src.as_ref().unwrap().as_bytes()) 106 + .unwrap(); 107 + text.to_owned().wrap(Value::String).wrap(Ok) 152 108 } 153 109 154 - struct Parent; 155 - impl Builtin for Parent { 156 - fn id(&self) -> &'static str { 157 - "parent" 158 - } 159 - 160 - fn eval(&self, ctx: &mut Context, args: &[ast::Expr]) -> Result { 161 - let v = ctx.eval_expr(&get_args::<1>(args)?[0])?; 162 - let id = v.as_node()?; 163 - let node = ctx.get_node_by_id(id).unwrap(); 164 - let parent = node.parent(); 165 - parent 166 - .map(|n| Value::Node(n.id())) 167 - .ok_or(Error::NoParentNode(node)) 168 - } 110 + fn parent(ctx: &mut Context, args: &[ast::Expr]) -> Result { 111 + let v = ctx.eval_expr(&get_args::<1>(args)?[0])?; 112 + let id = v.as_node()?; 113 + let node = ctx.get_node_by_id(id).unwrap(); 114 + let parent = node.parent(); 115 + parent 116 + .map(|n| Value::Node(n.id())) 117 + .ok_or(Error::NoParentNode(node)) 169 118 } 170 119 171 - struct Children; 172 - impl Builtin for Children { 173 - fn id(&self) -> &'static str { 174 - "children" 175 - } 176 - 177 - fn eval(&self, ctx: &mut Context, args: &[ast::Expr]) -> Result { 178 - let v = ctx.eval_expr(&get_args::<1>(args)?[0])?; 179 - let id = v.as_node()?; 180 - let node = ctx.get_node_by_id(id).unwrap(); 181 - let children = node 182 - .children(&mut node.walk()) 183 - .map(|c| Value::Node(c.id())) 184 - .collect::<Vec<_>>(); 185 - Ok(Value::List(children)) 186 - } 120 + fn children(ctx: &mut Context, args: &[ast::Expr]) -> Result { 121 + let v = ctx.eval_expr(&get_args::<1>(args)?[0])?; 122 + let id = v.as_node()?; 123 + let node = ctx.get_node_by_id(id).unwrap(); 124 + let children = node 125 + .children(&mut node.walk()) 126 + .map(|c| Value::Node(c.id())) 127 + .collect::<Vec<_>>(); 128 + Ok(Value::List(children)) 187 129 } 188 130 189 - struct Length; 190 - impl Builtin for Length { 191 - fn id(&self) -> &'static str { 192 - "length" 193 - } 131 + fn length(ctx: &mut Context, args: &[ast::Expr]) -> Result { 132 + let v = ctx.eval_expr(&get_args::<1>(args)?[0])?; 133 + let l = v.as_list()?; 134 + (l.len() as i128).wrap(Value::Integer).wrap(Ok) 135 + } 194 136 195 - fn eval(&self, ctx: &mut Context, args: &[ast::Expr]) -> Result { 196 - let v = ctx.eval_expr(&get_args::<1>(args)?[0])?; 197 - let l = v.as_list()?; 198 - (l.len() as i128).wrap(Value::Integer).wrap(Ok) 199 - } 137 + fn kind(ctx: &mut Context, args: &[ast::Expr]) -> Result { 138 + let v = ctx.eval_expr(&get_args::<1>(args)?[0])?; 139 + let id = v.as_node()?; 140 + let node = ctx.get_node_by_id(id).unwrap(); 141 + node.kind().to_owned().wrap(Value::String).wrap(Ok) 200 142 } 201 143 202 - struct Kind; 203 - impl Builtin for Kind { 204 - fn id(&self) -> &'static str { 205 - "kind" 206 - } 144 + fn member(ctx: &mut Context, args: &[ast::Expr]) -> Result { 145 + let [list_expr, element_expr] = get_args::<2>(args)?; 146 + let list = ctx.eval_expr(&list_expr)?; 147 + let v = list.as_list()?; 148 + let element = ctx.eval_expr(&element_expr)?; 149 + v.iter() 150 + .any(|item| item == &element) 151 + .wrap(Value::Boolean) 152 + .wrap(Ok) 153 + } 207 154 208 - fn eval(&self, ctx: &mut Context, args: &[ast::Expr]) -> Result { 209 - let v = ctx.eval_expr(&get_args::<1>(args)?[0])?; 210 - let id = v.as_node()?; 211 - let node = ctx.get_node_by_id(id).unwrap(); 212 - node.kind().to_owned().wrap(Value::String).wrap(Ok) 213 - } 155 + fn get_args<const N: usize>(args: &[ast::Expr]) -> std::result::Result<&[ast::Expr; N], Error> { 156 + args.try_into().map_err(|_| Error::IncorrectArgFormat { 157 + wanted: N, 158 + got: args.len(), 159 + }) 214 160 }
+4 -4
src/eval.rs
··· 696 696 } 697 697 698 698 fn eval_call(&mut self, call: &ast::Call) -> Result { 699 - (&*crate::builtins::BUILTINS) 700 - .get(call.function.as_str()) 701 - .ok_or_else(|| Error::FailedLookup(call.function.to_owned()))? 702 - .eval(self, call.parameters.as_slice()) 699 + ((&*crate::builtins::BUILTINS) 700 + .get(call.function.as_str()) 701 + .ok_or_else(|| Error::FailedLookup(call.function.to_owned()))?) 702 + (self, call.parameters.as_slice()) 703 703 } 704 704 705 705 fn eval_list(&mut self, list: &ast::List) -> Result {