use proc_macro2::Span;
use syn::parse::{Parse, ParseStream};
use syn::{Lit, Token, bracketed, parenthesized};
use super::ast::{DslBlock, DslValue};
impl Parse for DslValue {
fn parse(input: ParseStream) -> syn::Result<Self> {
parse_value(input)
}
}
pub fn parse_value(input: ParseStream) -> syn::Result<DslValue> {
if input.peek(syn::LitBool) {
let b: syn::LitBool = input.parse()?;
return Ok(DslValue::Bool(b.value));
}
if input.peek(syn::token::Brace) {
let block: DslBlock = input.parse()?;
return Ok(DslValue::Block(block));
}
if input.peek(syn::token::Bracket) {
let content;
let _ = bracketed!(content in input);
let mut items = Vec::new();
while !content.is_empty() {
items.push(parse_value(&content)?);
if content.is_empty() {
break;
}
content.parse::<Token![,]>()?;
}
return Ok(DslValue::List(items));
}
if input.peek(Token![@]) {
let _: Token![@] = input.parse()?;
let content;
let _ = parenthesized!(content in input);
let expr: syn::Expr = content.parse()?;
if !content.is_empty() {
return Err(syn::Error::new(
content.span(),
"extra tokens after `@(expr)` escape",
));
}
return Ok(DslValue::Expr(expr));
}
if input.peek(Token![-]) && input.peek2(Lit) {
let expr: syn::Expr = input.parse()?;
return Ok(DslValue::Expr(expr));
}
if input.peek(Lit) {
let lit: Lit = input.parse()?;
return Ok(DslValue::Lit(lit));
}
if input.peek(syn::Ident) {
let fork = input.fork();
let _ident: syn::Ident = fork.parse()?;
if fork.peek(Token![::]) {
let path: syn::Path = input.parse()?;
return Ok(DslValue::Path(path));
}
if fork.is_empty()
|| fork.peek(Token![,])
|| fork.peek(syn::token::Brace)
|| fork.peek(syn::token::Bracket)
{
let id: syn::Ident = input.parse()?;
return Ok(DslValue::BareIdent(id));
}
let expr: syn::Expr = input.parse()?;
return Ok(DslValue::Expr(expr));
}
if input.is_empty() {
return Err(syn::Error::new(
Span::call_site(),
"expected a DSL value but the input is empty",
));
}
let expr: syn::Expr = input.parse()?;
Ok(DslValue::Expr(expr))
}