1use std::collections::HashMap;
11
12use crate::value::{RuntimeError, Value, aver_display};
13
14pub fn register(global: &mut HashMap<String, Value>) {
15 let mut members = HashMap::new();
16 for method in &["print", "error", "warn", "readLine"] {
17 members.insert(
18 method.to_string(),
19 Value::Builtin(format!("Console.{}", method)),
20 );
21 }
22 global.insert(
23 "Console".to_string(),
24 Value::Namespace {
25 name: "Console".to_string(),
26 members,
27 },
28 );
29}
30
31pub fn effects(name: &str) -> &'static [&'static str] {
32 match name {
33 "Console.print" | "Console.error" | "Console.warn" | "Console.readLine" => &["Console"],
34 _ => &[],
35 }
36}
37
38pub fn call(name: &str, args: &[Value]) -> Option<Result<Value, RuntimeError>> {
40 match name {
41 "Console.print" => Some(one_msg(name, &args, |s| {
42 println!("{}", s);
43 })),
44 "Console.error" => Some(one_msg(name, &args, |s| {
45 eprintln!("{}", s);
46 })),
47 "Console.warn" => Some(one_msg(name, &args, |s| {
48 eprintln!("[warn] {}", s);
49 })),
50 "Console.readLine" => Some(read_line(&args)),
51 _ => None,
52 }
53}
54
55fn one_msg(name: &str, args: &[Value], emit: impl Fn(&str)) -> Result<Value, RuntimeError> {
58 if args.len() != 1 {
59 return Err(RuntimeError::Error(format!(
60 "{}() takes 1 argument, got {}",
61 name,
62 args.len()
63 )));
64 }
65 if let Some(s) = aver_display(&args[0]) {
66 emit(&s);
67 }
68 Ok(Value::Unit)
69}
70
71fn read_line(args: &[Value]) -> Result<Value, RuntimeError> {
72 if !args.is_empty() {
73 return Err(RuntimeError::Error(format!(
74 "Console.readLine() takes 0 arguments, got {}",
75 args.len()
76 )));
77 }
78 let mut line = String::new();
79 match std::io::stdin().read_line(&mut line) {
80 Ok(0) => Ok(Value::Err(Box::new(Value::Str("EOF".to_string())))),
81 Ok(_) => {
82 if line.ends_with('\n') {
84 line.pop();
85 }
86 if line.ends_with('\r') {
87 line.pop();
88 }
89 Ok(Value::Ok(Box::new(Value::Str(line))))
90 }
91 Err(e) => Ok(Value::Err(Box::new(Value::Str(e.to_string())))),
92 }
93}