create serde compatible parse error

This commit is contained in:
Demonthos committed 2022-06-15 12:58:08 -05:00
1 parent 41e905144c
commit df4ea20bb8
9 files changed
+68 -45

No files matched your search

+2 -1
View File
@@ -85,7 +85,8 @@ serde_json = "1.0.79"
rand = { version = "0.8.4", features = ["small_rng"] } rand = { version = "0.8.4", features = ["small_rng"] }
tokio = { version = "1.16.1", features = ["full"] } tokio = { version = "1.16.1", features = ["full"] }
reqwest = { version = "0.11.9", features = ["json"] } 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"] } fern = { version = "0.6.0", features = ["colored"] }
criterion = "0.3.5" criterion = "0.3.5"
thiserror = "1.0.30" thiserror = "1.0.30"
+2 -2
View File
@@ -192,11 +192,11 @@ pub fn rsx(s: TokenStream) -> TokenStream {
Ok(captured) => { Ok(captured) => {
let lazy = quote::quote! { let lazy = quote::quote! {
LazyNodes::new(move |__cx|{ LazyNodes::new(move |__cx|{
let code_location = get_line_num();
let captured = #captured; let captured = #captured;
let line_num = get_line_num();
let text = #rsx_text; 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 { if let Some(cx) = captured.custom_context {
+5 -11
View File
@@ -81,17 +81,11 @@ impl DesktopController {
impl ErrorHandler for DesktopErrorHandler { impl ErrorHandler for DesktopErrorHandler {
fn handle_error(&self, err: Error) { fn handle_error(&self, err: Error) {
if let Some(conn) = &mut *self.latest_connection.lock().unwrap() { if let Some(conn) = &mut *self.latest_connection.lock().unwrap() {
match err { conn.get_mut()
Error::RecompileRequiredError(reason) => { .write_all(
conn.get_mut() (serde_json::to_string(&err).unwrap() + "\n").as_bytes(),
.write_all( )
(serde_json::to_string(&reason).unwrap() + "\n") .unwrap();
.as_bytes(),
)
.unwrap();
}
Error::ParseError(err) => log::warn!("{}", err),
}
} }
} }
} }
+1
View File
@@ -6,6 +6,7 @@ license = "MIT/Apache-2.0"
[dependencies] [dependencies]
syn = { version = "1.0", features = ["extra-traits"] } syn = { version = "1.0", features = ["extra-traits"] }
proc-macro2 = { version = "1.0.39", features = ["span-locations"] }
quote = "1.0" quote = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
@@ -4,6 +4,8 @@ use dioxus_rsx::{
}; };
use quote::{quote, ToTokens, TokenStreamExt}; use quote::{quote, ToTokens, TokenStreamExt};
use syn::{Expr, Ident, Result}; use syn::{Expr, Ident, Result};
use crate::CodeLocation;
#[derive(Default)] #[derive(Default)]
pub struct CapturedContextBuilder { pub struct CapturedContextBuilder {
pub ifmted: Vec<IfmtInput>, pub ifmted: Vec<IfmtInput>,
@@ -137,6 +139,7 @@ impl ToTokens for CapturedContextBuilder {
iterators: vec![#((#iterators_str, #iterators)),*], iterators: vec![#((#iterators_str, #iterators)),*],
expressions: vec![#((#captured_attr_expressions_text, #captured_expressions.to_string())),*], expressions: vec![#((#captured_attr_expressions_text, #captured_expressions.to_string())),*],
listeners: vec![#((#listeners_str, #listeners)),*], listeners: vec![#((#listeners_str, #listeners)),*],
location: code_location.clone()
} }
}) })
} }
@@ -155,6 +158,8 @@ pub struct CapturedContext<'a> {
pub expressions: Vec<(&'static str, String)>, pub expressions: Vec<(&'static str, String)>,
// map listener code to the resulting listener // map listener code to the resulting listener
pub listeners: Vec<(&'static str, Listener<'a>)>, pub listeners: Vec<(&'static str, Listener<'a>)>,
// used to provide better error messages
pub location: CodeLocation,
} }
pub struct IfmtArgs { pub struct IfmtArgs {
+25 -2
View File
@@ -1,9 +1,11 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::CodeLocation;
/// An error produced when interperting the rsx /// An error produced when interperting the rsx
#[derive(Debug)] #[derive(Debug, Serialize, Deserialize)]
pub enum Error { pub enum Error {
ParseError(syn::Error), ParseError(ParseError),
RecompileRequiredError(RecompileReason), RecompileRequiredError(RecompileReason),
} }
@@ -14,3 +16,24 @@ pub enum RecompileReason {
CapturedComponent(String), CapturedComponent(String),
CapturedListener(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
View File
@@ -7,7 +7,7 @@ use syn::{parse2, parse_str, Expr};
use crate::attributes::attrbute_to_static_str; use crate::attributes::attrbute_to_static_str;
use crate::captuered_context::{CapturedContext, IfmtArgs}; use crate::captuered_context::{CapturedContext, IfmtArgs};
use crate::elements::element_to_static_str; 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> { fn resolve_ifmt(ifmt: &IfmtInput, captured: &IfmtArgs) -> Result<String, Error> {
let mut result = String::new(); let mut result = String::new();
@@ -64,7 +64,8 @@ fn build_node<'a>(
let bump = factory.bump(); let bump = factory.bump();
match node { match node {
BodyNode::Text(text) => { 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)?); let text = bump.alloc(resolve_ifmt(&ifmt, &ctx.captured)?);
Ok(factory.text(format_args!("{}", text))) Ok(factory.text(format_args!("{}", text)))
} }
@@ -76,14 +77,16 @@ fn build_node<'a>(
let (name, value, span): (String, IfmtInput, Span) = match &attr.attr { let (name, value, span): (String, IfmtInput, Span) = match &attr.attr {
ElementAttr::AttrText { name, value } => ( ElementAttr::AttrText { name, value } => (
name.to_string(), name.to_string(),
IfmtInput::from_str(&value.value()) IfmtInput::from_str(&value.value()).map_err(|err| {
.map_err(|err| Error::ParseError(err))?, Error::ParseError(ParseError::new(err, ctx.location.clone()))
})?,
name.span(), name.span(),
), ),
ElementAttr::CustomAttrText { name, value } => ( ElementAttr::CustomAttrText { name, value } => (
name.value(), name.value(),
IfmtInput::from_str(&value.value()) IfmtInput::from_str(&value.value()).map_err(|err| {
.map_err(|err| Error::ParseError(err))?, Error::ParseError(ParseError::new(err, ctx.location.clone()))
})?,
name.span(), name.span(),
), ),
_ => unreachable!(), _ => unreachable!(),
@@ -99,9 +102,9 @@ fn build_node<'a>(
namespace, namespace,
}); });
} else { } else {
return Err(Error::ParseError(syn::Error::new( return Err(Error::ParseError(ParseError::new(
span, syn::Error::new(span, "unknown attribute"),
"unknown attribute", ctx.location.clone(),
))); )));
} }
} }
@@ -152,8 +155,9 @@ fn build_node<'a>(
for attr in el.attributes { for attr in el.attributes {
match attr.attr { match attr.attr {
ElementAttr::EventTokens { .. } => { ElementAttr::EventTokens { .. } => {
let expr: Expr = let expr: Expr = parse2(attr.to_token_stream()).map_err(|err| {
parse2(attr.to_token_stream()).map_err(|err| Error::ParseError(err))?; Error::ParseError(ParseError::new(err, ctx.location.clone()))
})?;
if let Some(idx) = ctx.listeners.iter().position(|(code, _)| { if let Some(idx) = ctx.listeners.iter().position(|(code, _)| {
if let Ok(parsed) = parse_str::<Expr>(*code) { if let Ok(parsed) = parse_str::<Expr>(*code) {
parsed == expr parsed == expr
@@ -186,8 +190,9 @@ fn build_node<'a>(
None, None,
)), )),
Some(lit) => { Some(lit) => {
let ifmt: IfmtInput = let ifmt: IfmtInput = parse_str(&lit.value()).map_err(|err| {
parse_str(&lit.value()).map_err(|err| Error::ParseError(err))?; Error::ParseError(ParseError::new(err, ctx.location.clone()))
})?;
let key = bump.alloc(resolve_ifmt(&ifmt, &ctx.captured)?); let key = bump.alloc(resolve_ifmt(&ifmt, &ctx.captured)?);
Ok(factory.raw_element( Ok(factory.raw_element(
@@ -201,15 +206,15 @@ fn build_node<'a>(
} }
} }
} else { } else {
Err(Error::ParseError(syn::Error::new( Err(Error::ParseError(ParseError::new(
el.name.span(), syn::Error::new(el.name.span(), "unknown element"),
"unknown element", ctx.location.clone(),
))) )))
} }
} }
BodyNode::Component(comp) => { BodyNode::Component(comp) => {
let expr: Expr = let expr: Expr = parse2(comp.to_token_stream())
parse2(comp.to_token_stream()).map_err(|err| Error::ParseError(err))?; .map_err(|err| Error::ParseError(ParseError::new(err, ctx.location.clone())))?;
if let Some(idx) = ctx.components.iter().position(|(code, _)| { if let Some(idx) = ctx.components.iter().position(|(code, _)| {
if let Ok(parsed) = parse_str::<Expr>(*code) { if let Ok(parsed) = parse_str::<Expr>(*code) {
parsed == expr parsed == expr
+3 -2
View File
@@ -1,7 +1,7 @@
use captuered_context::CapturedContext; use captuered_context::CapturedContext;
use dioxus_core::{NodeFactory, SchedulerMsg, VNode}; use dioxus_core::{NodeFactory, SchedulerMsg, VNode};
use dioxus_hooks::UnboundedSender; use dioxus_hooks::UnboundedSender;
use error::Error; use error::{Error, ParseError};
use interperter::build; use interperter::build;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -71,7 +71,8 @@ fn interpert_rsx<'a, 'b>(
context: captuered_context::CapturedContext<'a>, context: captuered_context::CapturedContext<'a>,
) -> Result<VNode<'a>, Error> { ) -> Result<VNode<'a>, Error> {
build( 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, context,
&factory, &factory,
) )
+2 -9
View File
@@ -275,15 +275,8 @@ pub async fn run_with_props<T: 'static + Send>(root: Component<T>, root_props: T
// forward stream to the websocket // forward stream to the websocket
dom.base_scope().spawn_forever(async move { dom.base_scope().spawn_forever(async move {
while let Some(err) = error_channel_receiver.next().await { while let Some(err) = error_channel_receiver.next().await {
match err { ws.send_with_str(serde_json::to_string(&err).unwrap().as_str())
Error::RecompileRequiredError(err) => { .unwrap();
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()))
}
}
} }
}); });
} }