1use std::collections::HashMap;
11use std::sync::Arc as Rc;
12
13use crate::nan_value::{Arena, NanValue};
14use crate::value::{RuntimeError, Value, aver_display};
15
16pub fn register(global: &mut HashMap<String, Value>) {
17 let mut members = HashMap::new();
18 for method in &["print", "error", "warn", "readLine"] {
19 members.insert(
20 method.to_string(),
21 Value::Builtin(format!("Console.{}", method)),
22 );
23 }
24 global.insert(
25 "Console".to_string(),
26 Value::Namespace {
27 name: "Console".to_string(),
28 members,
29 },
30 );
31}
32
33pub const DECLARED_EFFECTS: &[&str] = &[
34 "Console.print",
35 "Console.error",
36 "Console.warn",
37 "Console.readLine",
38];
39
40pub fn effects(name: &str) -> &'static [&'static str] {
41 match name {
42 "Console.print" => &["Console.print"],
43 "Console.error" => &["Console.error"],
44 "Console.warn" => &["Console.warn"],
45 "Console.readLine" => &["Console.readLine"],
46 _ => &[],
47 }
48}
49
50pub fn call(name: &str, args: &[Value]) -> Option<Result<Value, RuntimeError>> {
52 match name {
53 "Console.print" => Some(one_msg(name, args, |s| {
54 println!("{}", s);
55 })),
56 "Console.error" => Some(one_msg(name, args, |s| {
57 eprintln!("{}", s);
58 })),
59 "Console.warn" => Some(one_msg(name, args, |s| {
60 eprintln!("[warn] {}", s);
61 })),
62 "Console.readLine" => Some(read_line(args)),
63 _ => None,
64 }
65}
66
67fn one_msg(name: &str, args: &[Value], emit: impl Fn(&str)) -> Result<Value, RuntimeError> {
70 if args.len() != 1 {
71 return Err(RuntimeError::Error(format!(
72 "{}() takes 1 argument, got {}",
73 name,
74 args.len()
75 )));
76 }
77 if let Some(s) = aver_display(&args[0]) {
78 emit(&s);
79 }
80 Ok(Value::Unit)
81}
82
83fn read_line(args: &[Value]) -> Result<Value, RuntimeError> {
84 if !args.is_empty() {
85 return Err(RuntimeError::Error(format!(
86 "Console.readLine() takes 0 arguments, got {}",
87 args.len()
88 )));
89 }
90 match aver_rt::read_line() {
91 Ok(line) => Ok(Value::Ok(Box::new(Value::Str(line)))),
92 Err(e) => Ok(Value::Err(Box::new(Value::Str(e)))),
93 }
94}
95
96pub fn register_nv(global: &mut HashMap<String, NanValue>, arena: &mut Arena) {
99 let methods = &["print", "error", "warn", "readLine"];
100 let mut members: Vec<(Rc<str>, NanValue)> = Vec::with_capacity(methods.len());
101 for method in methods {
102 let idx = arena.push_builtin(&format!("Console.{}", method));
103 members.push((Rc::from(*method), NanValue::new_builtin(idx)));
104 }
105 let ns_idx = arena.push(crate::nan_value::ArenaEntry::Namespace {
106 name: Rc::from("Console"),
107 members,
108 });
109 global.insert("Console".to_string(), NanValue::new_namespace(ns_idx));
110}
111
112pub fn call_nv(
113 name: &str,
114 args: &[NanValue],
115 arena: &mut Arena,
116) -> Option<Result<NanValue, RuntimeError>> {
117 match name {
118 "Console.print" => Some(one_msg_nv(name, args, arena, |s| {
119 println!("{}", s);
120 })),
121 "Console.error" => Some(one_msg_nv(name, args, arena, |s| {
122 eprintln!("{}", s);
123 })),
124 "Console.warn" => Some(one_msg_nv(name, args, arena, |s| {
125 eprintln!("[warn] {}", s);
126 })),
127 "Console.readLine" => Some(read_line_nv(args, arena)),
128 _ => None,
129 }
130}
131
132fn one_msg_nv(
133 name: &str,
134 args: &[NanValue],
135 arena: &mut Arena,
136 emit: impl Fn(&str),
137) -> Result<NanValue, RuntimeError> {
138 if args.len() != 1 {
139 return Err(RuntimeError::Error(format!(
140 "{}() takes 1 argument, got {}",
141 name,
142 args.len()
143 )));
144 }
145 if let Some(s) = args[0].display(arena) {
146 emit(&s);
147 }
148 Ok(NanValue::UNIT)
149}
150
151fn read_line_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
152 if !args.is_empty() {
153 return Err(RuntimeError::Error(format!(
154 "Console.readLine() takes 0 arguments, got {}",
155 args.len()
156 )));
157 }
158 match aver_rt::read_line() {
159 Ok(line) => {
160 let inner = NanValue::new_string_value(&line, arena);
161 Ok(NanValue::new_ok_value(inner, arena))
162 }
163 Err(e) => {
164 let inner = NanValue::new_string_value(&e, arena);
165 Ok(NanValue::new_err_value(inner, arena))
166 }
167 }
168}