use syn::parse::{ParseStream, Result};
use syn::{Expr, Token};
use crate::diag;
use crate::ir::{PropArg, TeksiProperty};
use super::{parse_element, peek_binding, peek_element_start, peek_escape, peek_spread};
pub(crate) fn parse_property_args(input: ParseStream) -> Result<Vec<PropArg>> {
let first = parse_prop_arg(input)?;
let mut args = vec![first];
loop {
if !input.peek(Token![,]) {
break;
}
if comma_begins_new_body_item(input) {
break;
}
let _comma: Token![,] = input.parse()?;
let next = parse_prop_arg(input)?;
args.push(next);
}
Ok(args)
}
fn comma_begins_new_body_item(input: ParseStream) -> bool {
let fork = input.fork();
if fork.parse::<Token![,]>().is_err() {
return false;
}
if fork.peek(Token![if])
|| fork.peek(Token![for])
|| fork.peek(Token![match])
|| fork.peek(Token![let])
{
return true;
}
if peek_spread(&fork) {
return true;
}
if peek_escape(&fork) {
return true;
}
if fork.peek(syn::Ident) && fork.peek2(Token![:]) && !fork.peek2(Token![::]) {
return true;
}
if peek_binding(&fork) {
return true;
}
false
}
fn parse_prop_arg(input: ParseStream) -> Result<PropArg> {
if peek_escape(input) {
let _pound: Token![#] = input.parse()?;
let content;
let _brace = syn::braced!(content in input);
let expr: Expr = content.parse()?;
if !content.is_empty() {
return Err(diag::error(
content.span(),
"expected a single expression inside `#{ ... }`",
));
}
return Ok(PropArg::Escape(expr));
}
if peek_binding(input) {
let name: syn::Ident = input.parse()?;
let _eq: Token![=] = input.parse()?;
let element = parse_element(input)?;
return Ok(PropArg::Binding { name, element });
}
if peek_element_start(input) {
let element = parse_element(input)?;
return Ok(PropArg::Element(element));
}
let expr: Expr = input.parse()?;
Ok(PropArg::Expr(expr))
}
pub(crate) fn parse_property_no_args(input: ParseStream) -> Result<TeksiProperty> {
let name: syn::Ident = input.parse()?;
Ok(TeksiProperty {
name,
args: Vec::new(),
})
}