Skip to main content

conlang/
builtin.rs

1use crate::inline_modules;
2use cl_ast::{At, Expr};
3use cl_interpret::{builtin::builtins, convalue::ConValue, env::Environment, interpret::Interpret};
4use cl_lexer::Lexer;
5use cl_parser::Parser;
6
7pub fn get_env() -> Environment {
8    let mut env = Environment::new();
9    env.add_builtins(&builtins! {
10        /// Lexes, parses, and evaluates an expression in the current env
11        fn eval(string) @env {
12            use cl_interpret::error::Error;
13            let string = match string {
14                ConValue::Str(string) => string.to_ref(),
15                ConValue::String(string) => string.as_str(),
16                ConValue::Ref(v) => {
17                    let string = v.get(env).cloned().unwrap_or_default();
18                    return eval(env, &[string])
19                }
20                _ => Err(Error::TypeError("string", string.typename()))?
21            };
22
23
24
25            match Parser::new(Lexer::new("eval".into(), string)).parse::<At<Expr>>(0).map(inline_modules) {
26                Err(e) => Ok(ConValue::String(format!("{e}"))),
27                Ok(v) => v.interpret(env),
28            }
29        }
30
31        fn putchar(ConValue::Char(c)) {
32            print!("{c}");
33            Ok(ConValue::Empty)
34        }
35
36        /// Gets a line of input from stdin
37        fn get_line(prompt) {
38            use cl_interpret::error::Error;
39            let prompt = match prompt {
40                ConValue::Str(prompt) => prompt.to_ref(),
41                ConValue::String(prompt) => prompt.as_str(),
42                _ => Err(Error::TypeError("string", prompt.typename()))?,
43            };
44            match repline::Repline::new("", prompt, "").read() {
45                Ok(line) => Ok(ConValue::String(line)),
46                Err(repline::Error::CtrlD(line)) => Ok(ConValue::String(line)),
47                Err(repline::Error::CtrlC(_)) => Err(cl_interpret::error::Error::Break(ConValue::Empty)),
48                Err(e) => Ok(ConValue::String(e.to_string())),
49            }
50        }
51    });
52    env
53}