From a2e3441e6937f1769fed3e16a5f7f7135482cf97 Mon Sep 17 00:00:00 2001 From: Akshay Date: Sun, 19 Sep 2021 09:45:06 +0530 Subject: init --- src/lib.rs | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils.rs | 10 ++++ 2 files changed, 160 insertions(+) create mode 100644 src/lib.rs create mode 100644 src/utils.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..37ac261 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,150 @@ +mod utils; + +use js_sys::Array; +use rnix::{parser::ParseError, NodeOrToken, SyntaxElement}; +use wasm_bindgen::prelude::*; + +use std::{convert::From, str::FromStr}; + +#[cfg(feature = "wee_alloc")] +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + +// wrapper type to pass syntax elements to JS +#[wasm_bindgen] +#[derive(Debug, Clone)] +pub struct SynNode { + node: SyntaxElement, +} + +impl SynNode { + pub fn new(node: SyntaxElement) -> Self { + Self { node } + } +} + +#[wasm_bindgen] +impl SynNode { + pub fn children(&self) -> Vec { + match &self.node { + NodeOrToken::Node(n) => n + .children_with_tokens() + .map(SynNode::new) + .map(JsValue::from) + .collect(), + NodeOrToken::Token(_) => vec![], + } + } + + pub fn is_token(&self) -> bool { + self.node.as_token().is_some() + } + + pub fn to_string(&self) -> String { + format!("{:?} {:?}", self.node.kind(), self.node.text_range(),) + } + + pub fn range(&self) -> TextRange { + let r = self.node.text_range(); + (r.start().into(), r.end().into()).into() + } + + pub fn kind(&self) -> String { + format!("{:?}", self.node.kind()) + } + + pub fn text(&self) -> String { + match &self.node { + NodeOrToken::Node(_) => "".into(), + NodeOrToken::Token(t) => format!("{:?}", t.text()), + } + } + + pub fn from_str(s: &str) -> Result { + FromStr::from_str(s) + .map(|p: SynNode| JsValue::from(p)) + .map_err(JsValue::from) + } +} + +impl FromStr for SynNode { + type Err = Array; + fn from_str(s: &str) -> Result { + let source_file = rnix::parse(s); + if source_file.errors().is_empty() { + Ok(Self { + node: NodeOrToken::Node(source_file.as_result().unwrap().node().clone()), + }) + } else { + Err(source_file + .errors() + .iter() + .map(SynErr::new) + .map(JsValue::from) + .collect()) + } + } +} + +#[wasm_bindgen] +#[derive(Debug, Clone)] +struct SynErr { + err: ParseError, +} + +impl SynErr { + pub fn new(err: &ParseError) -> Self { + Self { err: err.clone() } + } +} + +#[wasm_bindgen] +impl SynErr { + pub fn to_string(&self) -> String { + self.err.to_string() + } +} + +#[wasm_bindgen] +pub struct TextRange { + start: u32, + end: u32, +} + +impl From<(u32, u32)> for TextRange { + fn from((start, end): (u32, u32)) -> Self { + TextRange { start, end } + } +} + +impl TextRange { + pub fn to_line_col(&self, source: &str) -> (u32, u32) { + let end = self.end() as usize; + let line = &source[..end].chars().filter(|&c| c == '\n').count() + 1; + let col = &source[..end].rfind('\n').map(|c| end - c).unwrap_or(end); + (line as u32, *col as u32) + } +} + +#[wasm_bindgen] +impl TextRange { + pub fn start(&self) -> u32 { + self.start + } + + pub fn end(&self) -> u32 { + self.end + } + + pub fn line(&self, source: &str) -> u32 { + self.to_line_col(source).0 + } + + pub fn col(&self, source: &str) -> u32 { + self.to_line_col(source).1 + } + + pub fn to_string(&self) -> String { + format!("{}..{}", self.start, self.end) + } +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..b1d7929 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,10 @@ +pub fn set_panic_hook() { + // When the `console_error_panic_hook` feature is enabled, we can call the + // `set_panic_hook` function at least once during initialization, and then + // we will get better error messages if our code ever panics. + // + // For more details see + // https://github.com/rustwasm/console_error_panic_hook#readme + #[cfg(feature = "console_error_panic_hook")] + console_error_panic_hook::set_once(); +} -- cgit v1.2.3