Skip to main content

sirius/
bindings.rs

1//! Wasm bindings.
2
3use js_sys::Function;
4use wasm_bindgen::prelude::*;
5
6extern crate console_error_panic_hook;
7
8use crate::solver::Solver;
9
10use super::error::Error;
11use super::parser::{
12    ParserOutput,
13    lexer::{Tok, Token, tokenize},
14};
15use super::typechecker::check;
16
17fn serialize_token(t: &Token) -> Option<JsValue> {
18    let d = match &t.data {
19        Tok::Identifier(_) => 0,
20        Tok::Op(_) => 1,
21        Tok::AssignOp(_) => 1,
22        Tok::Float(_) => 2,
23        Tok::Int(_) => 2,
24        Tok::Keyword(_) => 3,
25        Tok::Error(_) => 4,
26        Tok::IndentError(_) => 4,
27        Tok::Comment => 5,
28        _ => return None,
29    };
30
31    let obj = js_sys::Object::new();
32    js_sys::Reflect::set(&obj, &JsValue::from("line"), &JsValue::from(t.line)).ok()?;
33    js_sys::Reflect::set(&obj, &JsValue::from("start"), &JsValue::from(t.start)).ok()?;
34    js_sys::Reflect::set(&obj, &JsValue::from("end"), &JsValue::from(t.end)).ok()?;
35    js_sys::Reflect::set(&obj, &JsValue::from("data"), &JsValue::from(d)).ok()?;
36
37    Some(obj.into())
38}
39
40fn serialize_error(e: &Error, tokens: &[Token]) -> Option<JsValue> {
41    let obj = js_sys::Object::new();
42    js_sys::Reflect::set(
43        &obj,
44        &JsValue::from("type"),
45        &JsValue::from(e.data.error_type.to_string()),
46    )
47    .ok()?;
48    js_sys::Reflect::set(
49        &obj,
50        &JsValue::from("message"),
51        &JsValue::from(e.data.message.clone()),
52    )
53    .ok()?;
54    js_sys::Reflect::set(
55        &obj,
56        &JsValue::from("start_line"),
57        &JsValue::from(tokens[e.start].line),
58    )
59    .ok()?;
60    js_sys::Reflect::set(
61        &obj,
62        &JsValue::from("start_column"),
63        &JsValue::from(tokens[e.start].start),
64    )
65    .ok()?;
66    js_sys::Reflect::set(
67        &obj,
68        &JsValue::from("end_line"),
69        &JsValue::from(tokens[if e.end == 0 { e.end } else { e.end - 1 }].line),
70    )
71    .ok()?;
72    js_sys::Reflect::set(
73        &obj,
74        &JsValue::from("end_column"),
75        &JsValue::from(tokens[if e.end == 0 { e.end } else { e.end - 1 }].end),
76    )
77    .ok()?;
78    Some(obj.into())
79}
80
81fn serialize_type_tokens(c: &ParserOutput) -> Option<JsValue> {
82    let mut type_token_pos = vec![];
83    for i in 0..c.tokens.len() {
84        let t = &c.tokens[i];
85        if t.is_type_ann {
86            let obj = js_sys::Object::new();
87            js_sys::Reflect::set(&obj, &JsValue::from("line"), &JsValue::from(t.line)).ok()?;
88            js_sys::Reflect::set(&obj, &JsValue::from("start"), &JsValue::from(t.start)).ok()?;
89            if i < c.tokens.len() - 1 && c.tokens[i + 1].is_type_ann {
90                js_sys::Reflect::set(
91                    &obj,
92                    &JsValue::from("end"),
93                    &JsValue::from(c.tokens[i + 1].start),
94                )
95                .ok()?;
96            } else {
97                js_sys::Reflect::set(&obj, &JsValue::from("end"), &JsValue::from(t.end)).ok()?;
98            }
99            type_token_pos.push(obj);
100        }
101    }
102    Some(type_token_pos.into())
103}
104
105#[wasm_bindgen]
106extern "C" {
107    #[wasm_bindgen(js_namespace = console)]
108    pub fn log(s: &str);
109}
110
111#[wasm_bindgen(start)]
112fn start() {
113    console_error_panic_hook::set_once()
114}
115
116#[wasm_bindgen]
117pub fn lex(code: &str) -> Vec<JsValue> {
118    let tokens = tokenize(code);
119    tokens.iter().filter_map(serialize_token).collect()
120}
121
122#[wasm_bindgen]
123pub fn compile(code: &str, z3_callback: Function) -> JsValue {
124    let mut output = ParserOutput::parse(code);
125    let mut solver = Solver::new_wasm(z3_callback);
126    let type_errors = check(&output, &mut solver);
127    output.errors.extend(type_errors);
128
129    let errors = output
130        .errors
131        .iter()
132        .filter_map(|e| serialize_error(e, &output.tokens))
133        .collect::<Vec<_>>();
134
135    let type_tokens = serialize_type_tokens(&output);
136    let obj = js_sys::Object::new();
137    let _ = js_sys::Reflect::set(&obj, &JsValue::from("errors"), &JsValue::from(errors));
138    let _ = js_sys::Reflect::set(
139        &obj,
140        &JsValue::from("type_tokens"),
141        &JsValue::from(type_tokens),
142    );
143    obj.into()
144}