create serde compatible parse error
This commit is contained in:
1 parent
41e905144c
commit
df4ea20bb8
9 files changed
+68
-45
No files matched your search
+2
-1
@@ -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"
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user