Просмотр исходного кода

create serde compatible parse error

Demonthos 3 лет назад
Родитель
Сommit
df4ea20bb8

+ 2 - 1
Cargo.toml

@@ -85,7 +85,8 @@ serde_json = "1.0.79"
 rand = { version = "0.8.4", features = ["small_rng"] }
 tokio = { version = "1.16.1", features = ["full"] }
 reqwest = { version = "0.11.9", features = ["json"] }
-dioxus = { path = ".", features = ["desktop", "ssr", "router", "fermi", "tui"] }
+# dioxus = { path = ".", features = ["desktop", "ssr", "router", "fermi", "tui"] }
+dioxus = { path = ".", features = ["desktop"] }
 fern = { version = "0.6.0", features = ["colored"] }
 criterion = "0.3.5"
 thiserror = "1.0.30"

+ 2 - 2
packages/core-macro/src/lib.rs

@@ -192,11 +192,11 @@ pub fn rsx(s: TokenStream) -> TokenStream {
                     Ok(captured) => {
                         let lazy = quote::quote! {
                             LazyNodes::new(move |__cx|{
+                                let code_location = get_line_num();
                                 let captured = #captured;
-                                let line_num = get_line_num();
                                 let text = #rsx_text;
 
-                                resolve_scope(line_num, text, captured, __cx)
+                                resolve_scope(code_location, text, captured, __cx)
                             })
                         };
                         if let Some(cx) = captured.custom_context {

+ 5 - 11
packages/desktop/src/controller.rs

@@ -81,17 +81,11 @@ impl DesktopController {
                     impl ErrorHandler for DesktopErrorHandler {
                         fn handle_error(&self, err: Error) {
                             if let Some(conn) = &mut *self.latest_connection.lock().unwrap() {
-                                match err {
-                                    Error::RecompileRequiredError(reason) => {
-                                        conn.get_mut()
-                                            .write_all(
-                                                (serde_json::to_string(&reason).unwrap() + "\n")
-                                                    .as_bytes(),
-                                            )
-                                            .unwrap();
-                                    }
-                                    Error::ParseError(err) => log::warn!("{}", err),
-                                }
+                                conn.get_mut()
+                                    .write_all(
+                                        (serde_json::to_string(&err).unwrap() + "\n").as_bytes(),
+                                    )
+                                    .unwrap();
                             }
                         }
                     }

+ 1 - 0
packages/rsx_interpreter/Cargo.toml

@@ -6,6 +6,7 @@ license = "MIT/Apache-2.0"
 
 [dependencies]
 syn = { version = "1.0", features = ["extra-traits"] }
+proc-macro2 = { version = "1.0.39", features = ["span-locations"] }
 quote = "1.0"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"

+ 5 - 0
packages/rsx_interpreter/src/captuered_context.rs

@@ -4,6 +4,8 @@ use dioxus_rsx::{
 };
 use quote::{quote, ToTokens, TokenStreamExt};
 use syn::{Expr, Ident, Result};
+
+use crate::CodeLocation;
 #[derive(Default)]
 pub struct CapturedContextBuilder {
     pub ifmted: Vec<IfmtInput>,
@@ -137,6 +139,7 @@ impl ToTokens for CapturedContextBuilder {
                 iterators: vec![#((#iterators_str, #iterators)),*],
                 expressions: vec![#((#captured_attr_expressions_text, #captured_expressions.to_string())),*],
                 listeners: vec![#((#listeners_str, #listeners)),*],
+                location: code_location.clone()
             }
         })
     }
@@ -155,6 +158,8 @@ pub struct CapturedContext<'a> {
     pub expressions: Vec<(&'static str, String)>,
     // map listener code to the resulting listener
     pub listeners: Vec<(&'static str, Listener<'a>)>,
+    // used to provide better error messages
+    pub location: CodeLocation,
 }
 
 pub struct IfmtArgs {

+ 25 - 2
packages/rsx_interpreter/src/error.rs

@@ -1,9 +1,11 @@
 use serde::{Deserialize, Serialize};
 
+use crate::CodeLocation;
+
 /// An error produced when interperting the rsx
-#[derive(Debug)]
+#[derive(Debug, Serialize, Deserialize)]
 pub enum Error {
-    ParseError(syn::Error),
+    ParseError(ParseError),
     RecompileRequiredError(RecompileReason),
 }
 
@@ -14,3 +16,24 @@ pub enum RecompileReason {
     CapturedComponent(String),
     CapturedListener(String),
 }
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct ParseError {
+    pub message: String,
+    pub location: CodeLocation,
+}
+
+impl ParseError {
+    pub fn new(error: syn::Error, mut location: CodeLocation) -> Self {
+        let message = error.to_string();
+        let syn_call_site = error.span().start();
+        location.line += syn_call_site.line as u32;
+        if syn_call_site.line == 0{
+            location.column += syn_call_site.column as u32;
+        }
+        else{
+            location.column = syn_call_site.column as u32;
+        }
+        ParseError { message, location }
+    }
+}

+ 23 - 18
packages/rsx_interpreter/src/interperter.rs

@@ -7,7 +7,7 @@ use syn::{parse2, parse_str, Expr};
 use crate::attributes::attrbute_to_static_str;
 use crate::captuered_context::{CapturedContext, IfmtArgs};
 use crate::elements::element_to_static_str;
-use crate::error::{Error, RecompileReason};
+use crate::error::{Error, ParseError, RecompileReason};
 
 fn resolve_ifmt(ifmt: &IfmtInput, captured: &IfmtArgs) -> Result<String, Error> {
     let mut result = String::new();
@@ -64,7 +64,8 @@ fn build_node<'a>(
     let bump = factory.bump();
     match node {
         BodyNode::Text(text) => {
-            let ifmt = IfmtInput::from_str(&text.value()).map_err(|err| Error::ParseError(err))?;
+            let ifmt = IfmtInput::from_str(&text.value())
+                .map_err(|err| Error::ParseError(ParseError::new(err, ctx.location.clone())))?;
             let text = bump.alloc(resolve_ifmt(&ifmt, &ctx.captured)?);
             Ok(factory.text(format_args!("{}", text)))
         }
@@ -76,14 +77,16 @@ fn build_node<'a>(
                         let (name, value, span): (String, IfmtInput, Span) = match &attr.attr {
                             ElementAttr::AttrText { name, value } => (
                                 name.to_string(),
-                                IfmtInput::from_str(&value.value())
-                                    .map_err(|err| Error::ParseError(err))?,
+                                IfmtInput::from_str(&value.value()).map_err(|err| {
+                                    Error::ParseError(ParseError::new(err, ctx.location.clone()))
+                                })?,
                                 name.span(),
                             ),
                             ElementAttr::CustomAttrText { name, value } => (
                                 name.value(),
-                                IfmtInput::from_str(&value.value())
-                                    .map_err(|err| Error::ParseError(err))?,
+                                IfmtInput::from_str(&value.value()).map_err(|err| {
+                                    Error::ParseError(ParseError::new(err, ctx.location.clone()))
+                                })?,
                                 name.span(),
                             ),
                             _ => unreachable!(),
@@ -99,9 +102,9 @@ fn build_node<'a>(
                                 namespace,
                             });
                         } else {
-                            return Err(Error::ParseError(syn::Error::new(
-                                span,
-                                "unknown attribute",
+                            return Err(Error::ParseError(ParseError::new(
+                                syn::Error::new(span, "unknown attribute"),
+                                ctx.location.clone(),
                             )));
                         }
                     }
@@ -152,8 +155,9 @@ fn build_node<'a>(
             for attr in el.attributes {
                 match attr.attr {
                     ElementAttr::EventTokens { .. } => {
-                        let expr: Expr =
-                            parse2(attr.to_token_stream()).map_err(|err| Error::ParseError(err))?;
+                        let expr: Expr = parse2(attr.to_token_stream()).map_err(|err| {
+                            Error::ParseError(ParseError::new(err, ctx.location.clone()))
+                        })?;
                         if let Some(idx) = ctx.listeners.iter().position(|(code, _)| {
                             if let Ok(parsed) = parse_str::<Expr>(*code) {
                                 parsed == expr
@@ -186,8 +190,9 @@ fn build_node<'a>(
                         None,
                     )),
                     Some(lit) => {
-                        let ifmt: IfmtInput =
-                            parse_str(&lit.value()).map_err(|err| Error::ParseError(err))?;
+                        let ifmt: IfmtInput = parse_str(&lit.value()).map_err(|err| {
+                            Error::ParseError(ParseError::new(err, ctx.location.clone()))
+                        })?;
                         let key = bump.alloc(resolve_ifmt(&ifmt, &ctx.captured)?);
 
                         Ok(factory.raw_element(
@@ -201,15 +206,15 @@ fn build_node<'a>(
                     }
                 }
             } else {
-                Err(Error::ParseError(syn::Error::new(
-                    el.name.span(),
-                    "unknown element",
+                Err(Error::ParseError(ParseError::new(
+                    syn::Error::new(el.name.span(), "unknown element"),
+                    ctx.location.clone(),
                 )))
             }
         }
         BodyNode::Component(comp) => {
-            let expr: Expr =
-                parse2(comp.to_token_stream()).map_err(|err| Error::ParseError(err))?;
+            let expr: Expr = parse2(comp.to_token_stream())
+                .map_err(|err| Error::ParseError(ParseError::new(err, ctx.location.clone())))?;
             if let Some(idx) = ctx.components.iter().position(|(code, _)| {
                 if let Ok(parsed) = parse_str::<Expr>(*code) {
                     parsed == expr

+ 3 - 2
packages/rsx_interpreter/src/lib.rs

@@ -1,7 +1,7 @@
 use captuered_context::CapturedContext;
 use dioxus_core::{NodeFactory, SchedulerMsg, VNode};
 use dioxus_hooks::UnboundedSender;
-use error::Error;
+use error::{Error, ParseError};
 use interperter::build;
 use lazy_static::lazy_static;
 use serde::{Deserialize, Serialize};
@@ -71,7 +71,8 @@ fn interpert_rsx<'a, 'b>(
     context: captuered_context::CapturedContext<'a>,
 ) -> Result<VNode<'a>, Error> {
     build(
-        parse_str(text).map_err(|err| Error::ParseError(err))?,
+        parse_str(text)
+            .map_err(|err| Error::ParseError(ParseError::new(err, context.location.clone())))?,
         context,
         &factory,
     )

+ 2 - 9
packages/web/src/lib.rs

@@ -275,15 +275,8 @@ pub async fn run_with_props<T: 'static + Send>(root: Component<T>, root_props: T
         // forward stream to the websocket
         dom.base_scope().spawn_forever(async move {
             while let Some(err) = error_channel_receiver.next().await {
-                match err {
-                    Error::RecompileRequiredError(err) => {
-                        ws.send_with_str(serde_json::to_string(&err).unwrap().as_str())
-                            .unwrap();
-                    }
-                    Error::ParseError(err) => {
-                        web_sys::console::warn_1(&wasm_bindgen::JsValue::from_str(&err.to_string()))
-                    }
-                }
+                ws.send_with_str(serde_json::to_string(&err).unwrap().as_str())
+                    .unwrap();
             }
         });
     }