1extern crate chrono;
2use super::{Opcode, Stack, Val};
3use crate::error;
4use crate::lang::Error;
5use std::convert::TryFrom;
6use std::rc::Rc;
7
8type Result<T> = std::result::Result<T, Error>;
9
10pub struct Function {}
11
12impl Function {
13 pub fn opcode_and_arity(func_name: &str) -> Option<(Opcode, std::ops::RangeInclusive<usize>)> {
14 match func_name {
15 "ABS" => Some((Opcode::Abs, 1..=1)),
16 "ASC" => Some((Opcode::Asc, 1..=1)),
17 "ATN" => Some((Opcode::Atn, 1..=1)),
18 "CDBL" => Some((Opcode::Cdbl, 1..=1)),
19 "CHR$" => Some((Opcode::Chr, 1..=1)),
20 "CINT" => Some((Opcode::Cint, 1..=1)),
21 "COS" => Some((Opcode::Cos, 1..=1)),
22 "CSNG" => Some((Opcode::Csng, 1..=1)),
23 "DATE$" => Some((Opcode::Date, 0..=0)),
24 "EXP" => Some((Opcode::Exp, 1..=1)),
25 "FIX" => Some((Opcode::Fix, 1..=1)),
26 "HEX$" => Some((Opcode::Hex, 1..=1)),
27 "INKEY$" => Some((Opcode::Inkey, 0..=0)),
28 "INSTR" => Some((Opcode::Instr, 2..=3)),
29 "INT" => Some((Opcode::Int, 1..=1)),
30 "LEFT$" => Some((Opcode::Left, 2..=2)),
31 "LEN" => Some((Opcode::Len, 1..=1)),
32 "LOG" => Some((Opcode::Log, 1..=1)),
33 "MID$" => Some((Opcode::Mid, 2..=3)),
34 "OCT$" => Some((Opcode::Oct, 1..=1)),
35 "POS" => Some((Opcode::Pos, 0..=1)),
36 "RIGHT$" => Some((Opcode::Right, 2..=2)),
37 "RND" => Some((Opcode::Rnd, 0..=1)),
38 "SGN" => Some((Opcode::Sgn, 1..=1)),
39 "SIN" => Some((Opcode::Sin, 1..=1)),
40 "SPC" => Some((Opcode::Spc, 1..=1)),
41 "SQR" => Some((Opcode::Sqr, 1..=1)),
42 "STR$" => Some((Opcode::Str, 1..=1)),
43 "STRING$" => Some((Opcode::String, 2..=2)),
44 "TAB" => Some((Opcode::Tab, 1..=1)),
45 "TAN" => Some((Opcode::Tan, 1..=1)),
46 "TIME$" => Some((Opcode::Time, 0..=0)),
47 "VAL" => Some((Opcode::Val, 1..=1)),
48 _ => None,
49 }
50 }
51
52 pub fn abs(val: Val) -> Result<Val> {
53 use Val::*;
54 match val {
55 Integer(n) => Ok(Integer(n.abs())),
56 Single(n) => Ok(Single(n.abs())),
57 Double(n) => Ok(Double(n.abs())),
58 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
59 }
60 }
61
62 pub fn asc(string: Val) -> Result<Val> {
63 let string = Rc::<str>::try_from(string)?;
64 match string.chars().next() {
65 Some(ch) => {
66 let num = u32::from(ch);
67 if num <= i16::max_value() as u32 {
68 Ok(Val::Integer(num as i16))
69 } else if num <= 16_777_216 {
70 Ok(Val::Single(num as f32))
71 } else {
72 Ok(Val::Double(num as f64))
73 }
74 }
75 None => Err(error!(IllegalFunctionCall)),
76 }
77 }
78
79 pub fn atn(val: Val) -> Result<Val> {
80 use Val::*;
81 match val {
82 Integer(n) => Ok(Single((n as f32).atan())),
83 Single(n) => Ok(Single(n.atan())),
84 Double(n) => Ok(Double(n.atan())),
85 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
86 }
87 }
88
89 pub fn cdbl(val: Val) -> Result<Val> {
90 use Val::*;
91 match val {
92 Integer(n) => Ok(Double(n as f64)),
93 Single(n) => Ok(Double(n as f64)),
94 Double(n) => Ok(Double(n)),
95 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
96 }
97 }
98
99 pub fn chr(val: Val) -> Result<Val> {
100 match char::try_from(u32::try_from(val)?) {
101 Ok(ch) => Ok(Val::String(ch.to_string().into())),
102 Err(_) => Err(error!(Overflow)),
103 }
104 }
105
106 pub fn cint(val: Val) -> Result<Val> {
107 Ok(Val::Integer(i16::try_from(val)?))
108 }
109
110 pub fn cos(val: Val) -> Result<Val> {
111 use Val::*;
112 match val {
113 Integer(n) => Ok(Single((n as f32).cos())),
114 Single(n) => Ok(Single(n.cos())),
115 Double(n) => Ok(Double(n.cos())),
116 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
117 }
118 }
119
120 pub fn csng(val: Val) -> Result<Val> {
121 use Val::*;
122 match val {
123 Integer(n) => Ok(Single(n as f32)),
124 Single(n) => Ok(Single(n)),
125 Double(n) => Ok(Single(n as f32)),
126 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
127 }
128 }
129
130 pub fn date() -> Result<Val> {
131 Ok(Val::String(
132 chrono::Local::now().format("%m-%d-%Y").to_string().into(),
133 ))
134 }
135
136 pub fn exp(val: Val) -> Result<Val> {
137 use Val::*;
138 match val {
139 Integer(n) => Ok(Single((n as f32).exp())),
140 Single(n) => Ok(Single(n.exp())),
141 Double(n) => Ok(Double(n.exp())),
142 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
143 }
144 }
145
146 pub fn fix(val: Val) -> Result<Val> {
147 use Val::*;
148 match val {
149 Integer(n) => Ok(Integer(n)),
150 Single(n) => Ok(Single(n.trunc())),
151 Double(n) => Ok(Double(n.trunc())),
152 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
153 }
154 }
155
156 pub fn hex(val: Val) -> Result<Val> {
157 let num = i16::try_from(val)?;
158 Ok(Val::String(format!("{:X}", num).into()))
159 }
160
161 pub fn instr(mut vec_val: Stack<Val>) -> Result<Val> {
162 let pattern = Rc::<str>::try_from(vec_val.pop()?)?;
163 let string = Rc::<str>::try_from(vec_val.pop()?)?;
164 let start = match vec_val.pop() {
165 Ok(n) => i16::try_from(n)?,
166 Err(_) => 1,
167 } as usize;
168 if start == 0 {
169 return Err(error!(IllegalFunctionCall; "START IS 0"));
170 }
171 let ch_idx = match string.char_indices().nth(start - 1) {
172 Some((pos, _ch)) => pos,
173 None => return Ok(Val::Integer(0)),
174 };
175 let string: Rc<str> = string[ch_idx..].into(); let index = match string.find(pattern.as_ref()) {
177 Some(n) => n,
178 None => 0,
179 };
180 let str_index = string
181 .char_indices()
182 .enumerate()
183 .find_map(|(str_idx, (ch_idx, _ch))| {
184 if ch_idx == index {
185 Some(str_idx + start)
186 } else {
187 None
188 }
189 });
190 match str_index {
191 Some(n) => Ok(Val::try_from(n)?),
192 None => Ok(Val::Integer(0)),
193 }
194 }
195
196 pub fn int(val: Val) -> Result<Val> {
197 use Val::*;
198 match val {
199 Integer(n) => Ok(Integer(n)),
200 Single(n) => Ok(Single(n.floor())),
201 Double(n) => Ok(Double(n.floor())),
202 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
203 }
204 }
205
206 pub fn left(string: Val, len: Val) -> Result<Val> {
207 let len = usize::try_from(len)?;
208 let string = Rc::<str>::try_from(string)?;
209 match string.char_indices().nth(len) {
210 Some((pos, _ch)) => Ok(Val::String(string[..pos].into())),
211 None => Ok(Val::String(string)),
212 }
213 }
214
215 pub fn len(string: Val) -> Result<Val> {
216 let string = Rc::<str>::try_from(string)?;
217 Ok(Val::try_from(string.chars().count())?)
218 }
219
220 pub fn log(val: Val) -> Result<Val> {
221 use Val::*;
222 match val {
223 Integer(n) => Ok(Single((n as f32).ln())),
224 Single(n) => Ok(Single(n.ln())),
225 Double(n) => Ok(Double(n.ln())),
226 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
227 }
228 }
229
230 pub fn mid(mut args: Stack<Val>) -> Result<Val> {
231 let len = match args.len() {
232 3 => Some(u16::try_from(args.pop()?)?),
233 _ => None,
234 };
235 let pos = usize::try_from(args.pop()?)?;
236 if pos == 0 {
237 return Err(error!(Overflow));
238 }
239 let string = Rc::<str>::try_from(args.pop()?)?;
240 match string.char_indices().nth(pos - 1) {
241 Some((pos, _ch)) => match len {
242 None => Ok(Val::String(string[pos..].into())),
243 Some(len) => {
244 let string: Rc<str> = string[pos..].into();
245 match string.char_indices().nth(len as usize) {
246 Some((pos, _ch)) => Ok(Val::String(string[..pos].into())),
247 None => Ok(Val::String(string)),
248 }
249 }
250 },
251 None => Ok(Val::String(string)),
252 }
253 }
254
255 pub fn oct(val: Val) -> Result<Val> {
256 let num = i16::try_from(val)?;
257 Ok(Val::String(format!("{:o}", num).into()))
258 }
259
260 pub fn pos(print_col: usize) -> Result<Val> {
261 match i16::try_from(print_col) {
262 Ok(pos) => Ok(Val::Integer(pos)),
263 Err(_) => Err(error!(Overflow)),
264 }
265 }
266
267 pub fn right(string: Val, len: Val) -> Result<Val> {
268 let len = usize::try_from(len)?;
269 if len == 0 {
270 return Ok(Val::String("".into()));
271 }
272 let string = Rc::<str>::try_from(string)?;
273 match string.char_indices().rev().nth(len - 1) {
274 Some((pos, _ch)) => Ok(Val::String(string[pos..].into())),
275 None => Ok(Val::String(string)),
276 }
277 }
278
279 pub fn rnd(st: &mut (u32, u32, u32), mut vec_val: Stack<Val>) -> Result<Val> {
280 let val = match vec_val.pop() {
281 Ok(s) => f32::try_from(s)?,
282 Err(_) => 1.0,
283 };
284 if val < 0.0 {
285 let seed = u32::from_le_bytes(val.to_be_bytes()) & 0x_00FF_FFFF;
286 st.0 = seed;
287 st.1 = seed;
288 st.2 = seed;
289 }
290 if val != 0.0 {
291 st.0 = (171 * st.0) % 30269;
292 st.1 = (172 * st.1) % 30307;
293 st.2 = (170 * st.2) % 30323;
294 }
295 Ok(Val::Single(
296 (st.0 as f32 / 30269.0 + st.1 as f32 / 30307.0 + st.2 as f32 / 30323.0) % 1.0,
297 ))
298 }
299
300 pub fn sgn(val: Val) -> Result<Val> {
301 use Val::*;
302 match val {
303 Integer(n) => Ok(Integer(if n == 0 {
304 0
305 } else if n.is_negative() {
306 -1
307 } else {
308 1
309 })),
310 Single(n) => Ok(Integer(if n == 0.0 {
311 0
312 } else if n.is_sign_negative() {
313 -1
314 } else {
315 1
316 })),
317 Double(n) => Ok(Integer(if n == 0.0 {
318 0
319 } else if n.is_sign_negative() {
320 -1
321 } else {
322 1
323 })),
324 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
325 }
326 }
327
328 pub fn sin(val: Val) -> Result<Val> {
329 use Val::*;
330 match val {
331 Integer(n) => Ok(Single((n as f32).sin())),
332 Single(n) => Ok(Single(n.sin())),
333 Double(n) => Ok(Double(n.sin())),
334 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
335 }
336 }
337
338 pub fn spc(val: Val) -> Result<Val> {
339 let len = usize::try_from(val)?;
340 if len > 255 {
341 return Err(error!(Overflow));
342 }
343 Ok(Val::String(" ".repeat(len).into()))
344 }
345
346 pub fn sqr(val: Val) -> Result<Val> {
347 use Val::*;
348 match val {
349 Integer(n) => Ok(Single((n as f32).sqrt())),
350 Single(n) => Ok(Single(n.sqrt())),
351 Double(n) => Ok(Double(n.sqrt())),
352 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
353 }
354 }
355
356 pub fn str(val: Val) -> Result<Val> {
357 use Val::*;
358 match val {
359 Integer(_) | Single(_) | Double(_) => Ok(String(format!("{}", val).into())),
360 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
361 }
362 }
363
364 pub fn string(num: Val, ch: Val) -> Result<Val> {
365 let num = usize::try_from(num)?;
366 if num > 255 {
367 return Err(error!(Overflow));
368 }
369 let ch = match ch {
370 Val::String(s) => match s.chars().next() {
371 Some(ch) => ch,
372 None => return Err(error!(IllegalFunctionCall)),
373 },
374 _ => {
375 let num = u32::try_from(ch)?;
376 match char::try_from(num) {
377 Ok(ch) => ch,
378 _ => return Err(error!(Overflow)),
379 }
380 }
381 };
382 Ok(Val::String(ch.to_string().repeat(num).into()))
383 }
384
385 pub fn tab(print_col: usize, val: Val) -> Result<Val> {
386 let tab = i16::try_from(val)?;
387 if tab < -255 || tab > 255 {
388 return Err(error!(Overflow));
389 }
390 let len = if tab < 0 {
391 let tab = -tab as usize;
392 tab - (print_col % tab)
393 } else if tab as usize > print_col {
394 tab as usize - print_col
395 } else {
396 0
397 };
398 Ok(Val::String(" ".repeat(len).into()))
399 }
400
401 pub fn tan(val: Val) -> Result<Val> {
402 use Val::*;
403 match val {
404 Integer(n) => Ok(Single((n as f32).tan())),
405 Single(n) => Ok(Single(n.tan())),
406 Double(n) => Ok(Double(n.tan())),
407 String(_) | Return(_) | Next(_) => Err(error!(TypeMismatch)),
408 }
409 }
410
411 pub fn time() -> Result<Val> {
412 Ok(Val::String(
413 chrono::Local::now().format("%H:%M:%S").to_string().into(),
414 ))
415 }
416
417 pub fn val(val: Val) -> Result<Val> {
418 if let Val::String(s) = val {
419 let mut s = s.trim();
420 while let Some((idx, _)) = s.char_indices().last() {
421 let v = Val::from(s);
422 if !matches!(v, Val::String(_)) {
423 return Ok(v);
424 }
425 s = &s[0..idx];
426 }
427 Ok(Val::Integer(0))
428 } else {
429 Err(error!(TypeMismatch))
430 }
431 }
432}