1use crate::inline_modules;
2use cl_ast::{At, Expr};
3use cl_interpret::{
4 builtin::builtins, convalue::ConValue, env::Environment, error::Error, interpret::Interpret,
5};
6use cl_lexer::Lexer;
7use cl_parser::Parser;
8use std::{
9 fs,
10 io::{Write, stdout},
11};
12
13const PREAMBLE: &str = include_str!("preamble.cl");
14
15pub fn get_env() -> Environment {
16 let mut env = Environment::new();
17 env.add_builtins(&builtins! {
18 fn eval(string) @env {
20 let string = match string.dereference_in(env)? {
21 ConValue::Str(string) => string.to_ref(),
22 ConValue::String(string) => string.as_str(),
23 _ => Err(Error::TypeError("string", string.typename()))?
24 };
25
26 match Parser::new(Lexer::new("eval".into(), string)).parse::<At<Expr>>(0).map(inline_modules) {
27 Err(e) => Ok(ConValue::String(format!("{e}"))),
28 Ok(v) => v.interpret(env),
29 }
30 }
31
32 fn putchar(ConValue::Char(c)) {
34 let mut stdout = stdout().lock();
35 let _ = write!(stdout, "{c}");
36 let _ = stdout.flush();
37 Ok(ConValue::Empty)
38 }
39
40 fn get_line(prompt) @env {
42 let prompt = match prompt.dereference_in(env)? {
43 ConValue::Str(prompt) => prompt.to_ref(),
44 ConValue::String(prompt) => prompt.as_str(),
45 _ => Err(Error::TypeError("string", prompt.typename()))?,
46 };
47 match repline::Repline::new("", prompt, "").read() {
48 Ok(line) => Ok(ConValue::String(line)),
49 Err(repline::Error::CtrlD(line)) => Ok(ConValue::String(line)),
50 Err(repline::Error::CtrlC(_)) => Err(Error::Break(ConValue::Empty)),
51 Err(e) => Ok(ConValue::String(e.to_string())),
52 }
53 }
54
55 fn read_file(path) @env {
57 let path = match path.dereference_in(env)? {
58 ConValue::Str(path) => path.to_ref(),
59 ConValue::String(path) => path.as_str(),
60 _ => Err(Error::TypeError("string", path.typename()))?,
61 };
62 fs::read_to_string(path).map_err(Error::BuiltinError)
63 }
64
65 fn write_file(path, data) @env {
66 let path = match path.dereference_in(env)? {
67 ConValue::Str(v) => v.to_ref(),
68 ConValue::String(v) => v.as_str(),
69 v => Err(Error::TypeError("string", v.typename()))?,
70 };
71 let data = match data.dereference_in(env)? {
72 ConValue::Str(v) => v.to_ref(),
73 ConValue::String(v) => v.as_str(),
74 v => Err(Error::TypeError("string", v.typename()))?,
75 };
76 fs::write(path, data).map_err(Error::BuiltinError)
77 }
78 });
79
80 if let Ok(code) = Parser::new(Lexer::new("".into(), PREAMBLE)).parse::<At<Expr>>(0) {
81 code.interpret(&mut env).expect("PREAMBLE should not fail");
82 }
83 env
84}