1mod utils;
2
3use crate::utils::set_panic_hook;
4use compiler::compiler::Compiler;
5use compiler::snapshot::{read_bytecode, write_bytecode};
6use compiler::snapshot_layout::describe_bytecode;
7use parser::parse as parser_pase;
8use parser::parse_ast_json_string;
9use wasm_bindgen::prelude::*;
10use wasm_bindgen::throw_str;
11
12const PLAYGROUND_GC_INSTRUCTION_BUDGET: usize = 10_000;
13
14#[cfg(feature = "wee_alloc")]
17#[global_allocator]
18static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
19
20#[wasm_bindgen]
21pub fn parse(input: &str) -> String {
22 set_panic_hook();
23 match parse_ast_json_string(input) {
24 Ok(node) => node.to_string(),
25 Err(e) => throw_str(format!("parse error: {}", e[0]).as_str()),
26 }
27}
28
29#[wasm_bindgen]
30pub fn compile(input: &str) -> String {
31 set_panic_hook();
32
33 let program = match parser_pase(input) {
34 Ok(ast) => ast,
35 Err(e) => throw_str(format!("parse error: {}", e[0]).as_str()),
36 };
37 let mut compiler = Compiler::new();
38 match compiler.compile(&program) {
39 Ok(bytecode) => return bytecode.instructions.string(),
40 Err(e) => throw_str(format!("compile error: {}", e).as_str()),
41 }
42}
43
44#[wasm_bindgen]
45pub fn compile_detail(input: &str) -> String {
46 set_panic_hook();
47
48 let program = match parser_pase(input) {
49 Ok(ast) => ast,
50 Err(e) => throw_str(format!("parse error: {}", e[0]).as_str()),
51 };
52 let mut compiler = Compiler::new();
53 match compiler.compile(&program) {
54 Ok(bytecode) => return bytecode.string(),
55 Err(e) => throw_str(format!("compile error: {}", e).as_str()),
56 }
57}
58
59#[wasm_bindgen]
60pub fn compile_with_debug(input: &str) -> String {
61 set_panic_hook();
62
63 let program = match parser_pase(input) {
64 Ok(ast) => ast,
65 Err(e) => throw_str(format!("parse error: {}", e[0]).as_str()),
66 };
67 let mut compiler = Compiler::new();
68 match compiler.compile(&program) {
69 Ok(bytecode) => match serde_json::to_string(&bytecode.debug_view()) {
70 Ok(json) => json,
71 Err(e) => throw_str(format!("json error: {}", e).as_str()),
72 },
73 Err(e) => throw_str(format!("compile error: {}", e).as_str()),
74 }
75}
76
77#[wasm_bindgen]
82pub fn run_gc_with_report(input: &str) -> String {
83 set_panic_hook();
84
85 let envelope = match gc::run_source_with_report(input, PLAYGROUND_GC_INSTRUCTION_BUDGET) {
86 Ok(success) => serde_json::json!({
87 "status": "ok",
88 "result": success.result,
89 "report": success.report,
90 }),
91 Err(error) => serde_json::json!({
92 "status": "error",
93 "stage": error.stage,
94 "message": error.message,
95 "span": error.span,
96 }),
97 };
98
99 serde_json::to_string(&envelope).expect("GC run envelope serialization should not fail")
100}
101
102#[wasm_bindgen]
109pub fn compile_to_snapshot(input: &str, strip_debug: bool) -> String {
110 set_panic_hook();
111
112 let envelope = match snapshot_envelope(input, strip_debug) {
113 Ok(envelope) => envelope,
114 Err((stage, message)) => serde_json::json!({
115 "status": "error",
116 "stage": stage,
117 "message": message,
118 }),
119 };
120 serde_json::to_string(&envelope).expect("snapshot envelope serialization should not fail")
121}
122
123fn snapshot_envelope(
124 input: &str,
125 strip_debug: bool,
126) -> Result<serde_json::Value, (&'static str, String)> {
127 let program = parser_pase(input).map_err(|errors| {
128 let message = errors
129 .first()
130 .cloned()
131 .unwrap_or_else(|| "unknown parse error".to_string());
132 ("parse", message)
133 })?;
134 let mut compiler = Compiler::new();
135 let bytecode = compiler
136 .compile(&program)
137 .map_err(|message| ("compile", message))?;
138 let bytes = write_bytecode(&bytecode, strip_debug)
139 .map_err(|error| ("snapshot", format!("{:?}", error)))?;
140 let layout = describe_bytecode(&bytes).map_err(|error| ("snapshot", format!("{:?}", error)))?;
141 Ok(serde_json::json!({
142 "status": "ok",
143 "bytesHex": hex_encode(&bytes),
144 "layout": layout,
145 }))
146}
147
148fn hex_encode(bytes: &[u8]) -> String {
149 use std::fmt::Write;
150
151 let mut out = String::with_capacity(bytes.len() * 2);
152 for byte in bytes {
153 write!(out, "{:02x}", byte).expect("writing to a String cannot fail");
154 }
155 out
156}
157
158#[wasm_bindgen]
166pub fn run_snapshot(bytes: &[u8]) -> String {
167 set_panic_hook();
168
169 let envelope = match read_bytecode(bytes) {
170 Ok(bytecode) => match gc::run_bytecode(bytecode, PLAYGROUND_GC_INSTRUCTION_BUDGET) {
171 Ok(result) => serde_json::json!({
172 "status": "ok",
173 "result": result,
174 }),
175 Err(error) => serde_json::json!({
176 "status": "error",
177 "stage": "runtime",
178 "message": error.message,
179 "span": error.span,
180 }),
181 },
182 Err(error) => serde_json::json!({
183 "status": "error",
184 "stage": "snapshot",
185 "message": format!("{:?}", error),
186 "span": null,
187 }),
188 };
189 serde_json::to_string(&envelope).expect("snapshot run envelope serialization should not fail")
190}