roost_lang/interpreter/
built_in.rs

1use rust_decimal::prelude::ToPrimitive;
2
3use crate::error::{Result, Span};
4#[cfg(feature = "no_std_io")]
5use crate::io::Write;
6#[cfg(not(feature = "no_std_io"))]
7use std::io::Write;
8use std::rc::Rc;
9
10use super::value::{types, Value, WrappedValue};
11
12#[macro_export]
13macro_rules! expect_len {
14    ($args:ident, $num:literal, $name:literal, $span:ident) => {
15        if $args.len() != $num {
16            error!(
17                TypeError,
18                *$span,
19                concat!(
20                    "Function '", $name, "' takes ", $num, " argument", expect_len!(@plural $num),
21                    ", however {} were supplied"
22                ),
23                $args.len(),
24            );
25        }
26    };
27    (@plural 1) => { "" };
28    (@plural $num:literal) => { "s" };
29}
30
31#[cfg(not(feature = "no_std_io"))]
32pub fn print<'tree>(
33    args: Vec<WrappedValue<'tree>>,
34    stdout: &mut impl Write,
35    span: &Span,
36    newline: bool,
37) -> Result<WrappedValue<'tree>> {
38    let args: Vec<_> = args.iter().map(|arg| arg.borrow().to_string()).collect();
39    if let Err(e) = write!(
40        stdout,
41        "{}{}",
42        args.join(" "),
43        if newline { "\n" } else { "" }
44    ) {
45        error!(SystemError, *span, "Failed to write to stdout: {}", e,);
46    }
47    Ok(Value::Null.wrapped())
48}
49
50#[cfg(feature = "no_std_io")]
51pub fn print<'tree>(
52    args: Vec<WrappedValue<'tree>>,
53    stdout: &mut impl Write,
54    _span: &Span,
55    newline: bool,
56) -> Result<WrappedValue<'tree>> {
57    let args: Vec<_> = args.iter().map(|arg| arg.borrow().to_string()).collect();
58    stdout.write(format!(
59        "{}{}",
60        args.join(" "),
61        if newline { "\n" } else { "" }
62    ));
63    Ok(Value::Null.wrapped())
64}
65
66pub fn exit<'tree>(
67    args: Vec<WrappedValue<'tree>>,
68    callback: impl FnOnce(i32),
69    span: &Span,
70) -> Result<WrappedValue<'tree>> {
71    expect_len!(args, 1, "exit", span);
72    if let Value::Number(num) = &*args[0].borrow() {
73        if !num.fract().is_zero() {
74            error!(ValueError, *span, "Exit code has to be an integer");
75        }
76        if let Some(num) = num.to_i32() {
77            callback(num)
78        } else {
79            error!(ValueError, *span, "Exit code is too high or too low");
80        }
81    } else {
82        error!(
83            TypeError,
84            *span, "First argument of function 'exit' has to be of type 'number'",
85        );
86    }
87    Ok(Value::Null.wrapped())
88}
89
90pub fn type_of<'tree>(args: Vec<WrappedValue<'tree>>, span: &Span) -> Result<WrappedValue<'tree>> {
91    expect_len!(args, 1, "typeOf", span);
92    Ok(Value::String(types::type_of(&args[0].borrow()).to_string()).wrapped())
93}
94
95pub fn assert<'tree>(args: Vec<WrappedValue<'tree>>, span: &Span) -> Result<WrappedValue<'tree>> {
96    expect_len!(args, 1, "assert", span);
97    if args[0].borrow().is_false() {
98        error!(RuntimeError, *span, "Assertion failed");
99    }
100    Ok(Value::Null.wrapped())
101}
102
103pub fn throw<'tree>(args: Vec<WrappedValue<'tree>>, span: &Span) -> Result<WrappedValue<'tree>> {
104    expect_len!(args, 1, "throw", span);
105    let borrow = args[0].borrow();
106    let str = match &*borrow {
107        Value::String(str) => str,
108        _ => error!(
109            TypeError,
110            *span, "First argument of function 'throw' has to be of type 'string'",
111        ),
112    };
113    error!(RuntimeError, *span, "{str}",)
114}
115
116#[cfg(not(feature = "no_std_io"))]
117pub fn debug<'tree>(
118    args: Vec<WrappedValue<'tree>>,
119    stderr: &mut impl Write,
120    span: &Span,
121) -> Result<WrappedValue<'tree>> {
122    let arg_strings: Vec<_> = args
123        .iter()
124        .map(|arg| format!("{:?}", arg.borrow()))
125        .collect();
126    if let Err(e) = writeln!(stderr, "{}", arg_strings.join(", ")) {
127        error!(SystemError, *span, "Failed to write to stdout: {}", e,);
128    }
129    if args.len() == 1 {
130        Ok(Rc::clone(&args[0]))
131    } else {
132        Ok(Value::List(args).wrapped())
133    }
134}
135
136#[cfg(feature = "no_std_io")]
137pub fn debug<'tree>(
138    args: Vec<WrappedValue<'tree>>,
139    stderr: &mut impl Write,
140    _span: &Span,
141) -> Result<WrappedValue<'tree>> {
142    let arg_strings: Vec<_> = args
143        .iter()
144        .map(|arg| format!("{:?}", arg.borrow()))
145        .collect();
146    stderr.write(format!("{}\n", arg_strings.join(", ")));
147    if args.len() == 1 {
148        Ok(Rc::clone(&args[0]))
149    } else {
150        Ok(Value::List(args).wrapped())
151    }
152}