monkey_rs/eval/
builtin.rs1use std::{fmt, rc::Rc};
4
5use super::error;
6use super::object;
7
8#[derive(Debug, PartialEq, Eq, Clone)]
10pub enum Builtin {
11 Len,
13 First,
15 Last,
17 Rest,
20 Push,
23 Puts,
25}
26
27impl fmt::Display for Builtin {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 Builtin::Len => write!(f, "len"),
31 Builtin::First => write!(f, "first"),
32 Builtin::Last => write!(f, "last"),
33 Builtin::Rest => write!(f, "rest"),
34 Builtin::Push => write!(f, "push"),
35 Builtin::Puts => write!(f, "puts"),
36 }
37 }
38}
39
40impl Builtin {
41 pub fn lookup(name: &str) -> Option<object::Object> {
44 match name {
45 "len" => Some(object::Object::Builtin(Builtin::Len)),
46 "first" => Some(object::Object::Builtin(Builtin::First)),
47 "last" => Some(object::Object::Builtin(Builtin::Last)),
48 "rest" => Some(object::Object::Builtin(Builtin::Rest)),
49 "push" => Some(object::Object::Builtin(Builtin::Push)),
50 "puts" => Some(object::Object::Builtin(Builtin::Puts)),
51 _ => None,
52 }
53 }
54
55 pub fn apply(
57 &self,
58 args: &[Rc<object::Object>],
59 ) -> Result<Rc<object::Object>, error::EvaluationError> {
60 match self {
61 Builtin::Len => {
62 check_args_count(1, args.len())?;
63
64 match &*args[0] {
65 object::Object::String(str) => {
66 Ok(Rc::new(object::Object::Integer(str.len() as i64)))
67 }
68 object::Object::Array(arr) => {
69 Ok(Rc::new(object::Object::Integer(arr.len() as i64)))
70 }
71 other => Err(error::EvaluationError::new(format!(
72 "argument to `len` not supported, got {}",
73 other
74 ))),
75 }
76 }
77 Builtin::First => {
78 check_args_count(1, args.len())?;
79
80 match &*args[0] {
81 object::Object::Array(arr) => match arr.first() {
82 Some(element) => Ok(Rc::clone(element)),
83 None => Ok(Rc::new(object::Object::Null)),
84 },
85 other => Err(error::EvaluationError::new(format!(
86 "argument to `first` must be ARRAY, got {}",
87 other
88 ))),
89 }
90 }
91 Builtin::Last => {
92 check_args_count(1, args.len())?;
93
94 match &*args[0] {
95 object::Object::Array(arr) => match arr.last() {
96 Some(element) => Ok(Rc::clone(element)),
97 None => Ok(Rc::new(object::Object::Null)),
98 },
99 other => Err(error::EvaluationError::new(format!(
100 "argument to `last` must be ARRAY, got {}",
101 other
102 ))),
103 }
104 }
105 Builtin::Rest => {
106 check_args_count(1, args.len())?;
107
108 match &*args[0] {
109 object::Object::Array(arr) => {
110 let length = arr.len();
111 if length > 0 {
112 let new_elements = arr[1..].to_vec();
113 Ok(Rc::new(object::Object::Array(new_elements)))
114 } else {
115 Ok(Rc::new(object::Object::Null))
116 }
117 }
118 other => Err(error::EvaluationError::new(format!(
119 "argument to `rest` must be ARRAY, got {}",
120 other
121 ))),
122 }
123 }
124 Builtin::Push => {
125 check_args_count(2, args.len())?;
126
127 match &*args[0] {
128 object::Object::Array(arr) => {
129 let mut new_elements = arr.clone();
130 new_elements.push(Rc::clone(&args[1]));
131 Ok(Rc::new(object::Object::Array(new_elements)))
132 }
133 other => Err(error::EvaluationError::new(format!(
134 "argument to `push` must be ARRAY, got {}",
135 other
136 ))),
137 }
138 }
139 Builtin::Puts => {
140 args.iter().for_each(|obj| println!("{}", obj));
141
142 Ok(Rc::new(object::Object::Null))
144 }
145 }
146 }
147}
148
149fn check_args_count(expected: usize, actual: usize) -> Result<(), error::EvaluationError> {
151 match expected == actual {
152 true => Ok(()),
153 false => Err(error::EvaluationError::new(format!(
154 "wrong number of arguments: expected={}, got={}",
155 expected, actual
156 ))),
157 }
158}