lang_interpreter/interpreter/platform/
wasm.rs1use std::collections::HashMap;
2use std::ffi::OsString;
3use std::io::{Error, ErrorKind};
4use std::mem;
5use std::path::{Path, PathBuf};
6use web_sys::{js_sys, Url, WorkerLocation, XmlHttpRequest, XmlHttpRequestResponseType};
7use web_sys::js_sys::{ArrayBuffer, Uint8Array};
8use web_sys::wasm_bindgen::JsValue;
9use crate::interpreter::data::function::native::NativeError;
10use crate::interpreter::platform::PlatformAPI;
11use crate::regex_patterns;
12
13#[derive(Debug)]
29pub struct WASMPlatformAPI {
30 print_buffer: String,
31 print_error_buffer: String,
32}
33
34impl WASMPlatformAPI {
35 pub fn new() -> Self {
36 Self {
37 print_buffer: String::new(),
38 print_error_buffer: String::new(),
39 }
40 }
41}
42
43impl Default for WASMPlatformAPI {
44 fn default() -> Self {
45 Self::new()
46 }
47}
48
49impl PlatformAPI for WASMPlatformAPI {
50 fn get_lang_files(&self, _: &Path) -> Result<Vec<PathBuf>, Error> {
54 Err(Error::new(
55 ErrorKind::Unsupported,
56 "Not Implemented",
57 ))
58 }
59
60 fn get_lang_path(&self, lang_file: &Path) -> Result<PathBuf, Error> {
61 let path = lang_file;
62 let mut path = path.parent().unwrap_or(Path::new(""));
63 if path == Path::new("") {
64 path = Path::new("./");
65 }
66
67 let path = &*regex_patterns::WASM_STARTS_WITH_MULTIPLE_DOUBLE_SLASH.replace_all(&path.to_string_lossy(), "/").to_string();
68
69 let location = js_sys::Reflect::get(js_sys::global().as_ref(), &"location".into()).map_err(|err| Error::new(
70 ErrorKind::Other,
71 err.as_string().as_deref().unwrap_or("Error"),
72 ))?;
73
74 let location = WorkerLocation::from(location);
75
76 let location = Url::new_with_base(path, &location.href()).map_err(|err| Error::new(
77 ErrorKind::Other,
78 err.as_string().as_deref().unwrap_or("Error"),
79 ))?;
80
81 Ok(PathBuf::from(location.pathname()))
82 }
83
84 fn get_lang_file_name(&self, lang_file: &Path) -> Option<OsString> {
85 let path = lang_file;
86
87 path.file_name().map(|str| str.to_os_string())
88 }
89
90 fn get_lang_reader(&self, lang_file: &Path) -> Result<Box<[u8]>, Error> {
91 #[inline(always)]
92 fn internal(lang_file: &Path) -> Result<Box<[u8]>, JsValue> {
93 let lang_file = &*regex_patterns::WASM_STARTS_WITH_MULTIPLE_DOUBLE_SLASH.replace_all(&lang_file.to_string_lossy(), "/").to_string();
94
95 let request = XmlHttpRequest::new()?;
96 request.set_response_type(XmlHttpRequestResponseType::Arraybuffer);
97 request.open_with_async("GET", lang_file, false)?;
98 request.send()?;
99
100 let status_code = request.status().unwrap_or(500);
101 if status_code != 200 {
102 return Err(format!("Invalid response code: {status_code}").into());
103 }
104
105 let ret = request.response()?;
106 let ret = ArrayBuffer::from(ret);
107 let ret = Uint8Array::new(&ret);
108
109 let mut bytes = vec![0; ret.length() as usize];
110 ret.copy_to(&mut bytes);
111
112 Ok(bytes.into_boxed_slice())
113 }
114
115 internal(lang_file).map_err(|err| Error::new(
116 ErrorKind::Other,
117 err.as_string().as_deref().unwrap_or("Error"),
118 ))
119 }
120
121 fn write_lang_file(&self, _: &Path, _: HashMap<String, String>) -> Result<(), Error> {
125 Err(Error::new(
126 ErrorKind::Unsupported,
127 "Not Implemented",
128 ))
129 }
130
131 fn show_input_dialog(&self, _text: &str) -> Result<String, NativeError> {
135 Err(NativeError::new(
136 "Not Implemented",
137 None,
138 ))
139 }
140
141 fn print(&mut self, text: &str) {
142 self.print_buffer += text;
143 }
144
145 fn println(&mut self, text: &str) {
146 let text = if self.print_buffer.is_empty() {
147 text.to_string()
148 }else {
149 mem::take(&mut self.print_buffer) + text
150 };
151
152 if text.is_empty() {
153 web_sys::console::log_0();
154 }else {
155 web_sys::console::log_1(&text.into());
156 }
157 }
158
159 fn print_error(&mut self, text: &str) {
160 self.print_error_buffer += text;
161 }
162
163 fn println_error(&mut self, text: &str) {
164 let text = if self.print_error_buffer.is_empty() {
165 text.to_string()
166 }else {
167 mem::take(&mut self.print_error_buffer) + text
168 };
169
170 if text.is_empty() {
171 web_sys::console::error_0();
172 }else {
173 web_sys::console::error_1(&text.into());
174 }
175 }
176}