ocypode_lang/runtime/builtins/
functions.rs1use crate::{
2 ast::*,
3 errors::{Error as OYError, ErrorKind as OYErrorKind, Result as OYResult},
4};
5
6pub fn format(args: Vec<ObjectExpression>, call_span: Span) -> OYResult<ObjectExpression> {
16 let format = &args[0];
18 let args = &args[1];
19 let format = match format {
20 ObjectExpression::String(format, _) => format,
21 _ => {
22 return Err(OYError::new(
23 OYErrorKind::UnexpectedType("String".to_owned(), format.type_name().to_owned()),
24 format.span(),
25 ))
26 }
27 };
28 let args: Vec<_> = match args {
29 ObjectExpression::Array(args, _) => args
30 .iter()
31 .map(|arg| match arg {
32 ExpressionStatement::Value(ValueExpression::Object(obj)) => obj,
33 _ => unreachable!(
34 "The interpreter should have checked that the arguments are objects"
35 ),
36 })
37 .collect(),
38 _ => {
39 return Err(OYError::new(
40 OYErrorKind::UnexpectedType("Array".to_owned(), args.type_name().to_owned()),
41 args.span(),
42 ))
43 }
44 };
45 let mut result = String::new();
46 let mut arg_index = 0;
47 let mut placeholder = false;
48 let mut close_placeholder = false;
49 let mut placeholder_number = String::new();
50
51 let placeholder_count = regex::Regex::new(r"\{(\d+)?\}")
52 .unwrap()
53 .find_iter(format)
54 .count();
55 let placeholder_count_without_index = regex::Regex::new(r"\{\}")
56 .unwrap()
57 .find_iter(format)
58 .count();
59
60 if args.len() > placeholder_count {
61 return Err(OYError::new(
62 OYErrorKind::FormatError(
63 format!(
64 "Too many arguments for format string, expected {}, got {}",
65 placeholder_count, args.len()
66 ),
67 format!("The format string has {} placeholders, remove the extra arguments or add more placeholders", placeholder_count),
68 ),
69 call_span,
70 ));
71 }
72 if placeholder_count_without_index > args.len() {
73 return Err(OYError::new(
74 OYErrorKind::FormatError(
75 "Too many placeholders without index for format string".to_owned()
76 ,
77 format!("| The format string has {} placeholders without index\n| and there are only {} arguments, you can add more\n| arguments or remove the extra placeholders",
78 placeholder_count_without_index, args.len()
79 ),
80 ),
81 call_span,
82 ));
83 }
84
85 for c in format.chars() {
86 if placeholder {
87 if c == '}' {
88 if placeholder_number.is_empty() {
89 if arg_index < args.len() {
90 result.push_str(&args[arg_index].to_string());
91 arg_index += 1;
92 }
93 } else {
94 let placeholder_number: usize = placeholder_number.parse().map_err(|_| {
95 OYError::new(
96 OYErrorKind::FormatError(
97 format!("Invalid placeholder index `{}`", placeholder_number),
98 "The placeholder index must be a number".to_owned(),
99 ),
100 call_span,
101 )
102 })?;
103 if placeholder_number < args.len() {
104 result.push_str(&args[placeholder_number].to_string());
105 } else {
106 return Err(OYError::new(
107 OYErrorKind::FormatError(
108 format!(
109 "The placeholder index `{}` is out of range.",
110 placeholder_number
111 ),
112 format!("The maximum index is {}", placeholder_count),
113 ),
114 call_span,
115 ));
116 }
117 }
118 placeholder = false;
119 placeholder_number.clear();
120 } else if c == '{' {
121 result.push('{');
122 placeholder = false;
123 } else if c.is_numeric() {
124 placeholder_number.push(c);
125 } else {
126 return Err(OYError::new(
127 OYErrorKind::FormatError(
128 format!("Invalid placeholder `{}`", c),
129 "The placeholder must contain the index or nothing".to_owned(),
130 ),
131 call_span,
132 ));
133 }
134 } else if c == '{' {
135 placeholder = true;
136 } else if c == '}' && !close_placeholder {
137 close_placeholder = true;
138 } else if c == '}' && close_placeholder {
139 result.push('}');
140 close_placeholder = false;
141 } else if close_placeholder {
142 return Err(OYError::new(
144 OYErrorKind::FormatError(
145 "Unclosed placeholder".to_owned(),
146 "The placeholder must be closed with `}`".to_owned(),
147 ),
148 call_span,
149 ));
150 } else {
151 result.push(c);
152 }
153 }
154 Ok(ObjectExpression::String(result, call_span))
155}
156
157pub fn print(args: Vec<ObjectExpression>, call_span: Span) -> OYResult<ObjectExpression> {
161 print!("{}", print_result(args)?);
162 Ok(ObjectExpression::Nil(call_span))
163}
164
165pub fn println(args: Vec<ObjectExpression>, call_span: Span) -> OYResult<ObjectExpression> {
167 println!("{}", print_result(args)?);
168 Ok(ObjectExpression::Nil(call_span))
169}
170
171pub fn input(args: Vec<ObjectExpression>, call_span: Span) -> OYResult<ObjectExpression> {
174 let prompt = match &args[0] {
175 ObjectExpression::String(prompt, _) => prompt,
176 _ => {
177 return Err(OYError::new(
178 OYErrorKind::UnexpectedType("String".to_owned(), args[0].type_name().to_owned()),
179 args[0].span(),
180 ))
181 }
182 };
183 let input = rustyline::DefaultEditor::new()
184 .map_err(|_| {
185 OYError::new(
186 OYErrorKind::Runtime("Failed to read a line from stdin".to_owned()),
187 call_span,
188 )
189 })?
190 .readline(prompt)
191 .map_err(|_| {
192 OYError::new(
193 OYErrorKind::Runtime("Failed to read a line from stdin".to_owned()),
194 call_span,
195 )
196 })?;
197 Ok(ObjectExpression::String(input, call_span))
198}
199
200pub fn len(args: Vec<ObjectExpression>, call_span: Span) -> OYResult<ObjectExpression> {
202 let len = match &args[0] {
203 ObjectExpression::Array(array, _) => array.len().to_string(),
204 ObjectExpression::String(string, _) => string.chars().count().to_string(),
205 _ => {
206 return Err(OYError::new(
207 OYErrorKind::UnexpectedType(
208 "Array or String".to_owned(),
209 args[0].type_name().to_owned(),
210 ),
211 args[0].span(),
212 ))
213 }
214 };
215 Ok(ObjectExpression::Int(
216 len.parse().map_err(|err| {
217 OYError::new(
218 OYErrorKind::Runtime(format!(
219 "Failed to parse the length of the array/string: {}",
220 err
221 )),
222 call_span,
223 )
224 })?,
225 call_span,
226 ))
227}
228
229pub fn push(mut args: Vec<ObjectExpression>, call_span: Span) -> OYResult<ObjectExpression> {
231 let object = args.pop().unwrap();
232 let array = args.pop().unwrap();
233 let mut array: Vec<_> = match array {
234 ObjectExpression::Array(array, _) => array,
235 _ => {
236 return Err(OYError::new(
237 OYErrorKind::UnexpectedType("Array".to_owned(), args[0].type_name().to_owned()),
238 args[0].span(),
239 ))
240 }
241 };
242 array.push(ExpressionStatement::Value(ValueExpression::Object(object)));
243 Ok(ObjectExpression::Array(array, call_span))
244}
245
246pub fn pop(mut args: Vec<ObjectExpression>, call_span: Span) -> OYResult<ObjectExpression> {
248 let array = args.pop().unwrap();
249 let mut array: Vec<_> = match array {
250 ObjectExpression::Array(array, _) => array,
251 _ => {
252 return Err(OYError::new(
253 OYErrorKind::UnexpectedType("Array".to_owned(), args[0].type_name().to_owned()),
254 args[0].span(),
255 ))
256 }
257 };
258 array.pop();
259 Ok(ObjectExpression::Array(array, call_span))
260}
261
262fn print_result(mut args: Vec<ObjectExpression>) -> OYResult<String> {
263 let args = args
264 .pop()
265 .expect("The interpreter should have checked that the arguments are not empty");
266 Ok(match args {
267 ObjectExpression::Array(args, _) => args
268 .into_iter()
269 .map(|arg| match arg {
270 ExpressionStatement::Value(ValueExpression::Object(obj)) => obj.to_string(),
271 _ => unreachable!(
272 "The interpreter should have checked that the arguments are objects, {:?}",
273 arg
274 ),
275 })
276 .collect(),
277 _ => {
278 return Err(OYError::new(
279 OYErrorKind::UnexpectedType("Array".to_owned(), args.type_name().to_owned()),
280 args.span(),
281 ))
282 }
283 })
284}