Fix for latest syn changes

This commit is contained in:
Andrey Tkachenko 2018-10-12 15:23:31 +04:00
parent f5ce2c9564
commit 8e67c1a054
7 changed files with 140 additions and 114 deletions

View File

@ -1,4 +1,4 @@
#![feature(proc_macro_non_items)] #![feature(proc_macro_hygiene)]
#![allow(dead_code)] #![allow(dead_code)]
#[macro_use] #[macro_use]

View File

@ -11,6 +11,7 @@ syn = {version = "*", features=["full", "extra-traits"]}
quote = "*" quote = "*"
proc-macro2 = {version = "*", features=["nightly", "proc-macro"]} proc-macro2 = {version = "*", features=["nightly", "proc-macro"]}
maple-core = { path="../maple-core" } maple-core = { path="../maple-core" }
nom = "4.1.0"
[lib] [lib]
proc-macro = true proc-macro = true

View File

@ -0,0 +1,15 @@
#![feature(proc_macro_hygiene)]
use maple_macro::view;
fn main() {
view! {
<test dasdasd="string">
<div dasdasd=4.6>
"dasdasdasdasdas"
{ 1 + 1 }
{ ... test() }
</div>
<div />
</test>
}
}

View File

@ -1,39 +1,42 @@
use syn::{Expr, ExprLit, Ident}; use syn::parse::{Parse, ParseStream, Result};
use syn::synom::Synom;
use quote::ToTokens; use quote::ToTokens;
#[derive(Debug)] #[derive(Debug)]
crate struct Attribute { crate struct Attribute {
pub name: Ident, pub name: syn::Ident,
eq: Token![=],
pub value: AttributeValue pub value: AttributeValue
} }
impl Synom for Attribute { impl Parse for Attribute {
named!(parse -> Self, do_parse!( fn parse(input: ParseStream) -> Result<Self> {
name: syn!(Ident) >> Ok(Self {
punct!(=) >> name: input.parse()?,
value: syn!(AttributeValue) >> eq: input.parse()?,
value: input.parse()?,
(Attribute { name, value }) })
)); }
} }
#[derive(Debug)] #[derive(Debug)]
crate enum AttributeValue { pub enum AttributeValue {
Expr(Expr), Expr(syn::Expr),
Literal(ExprLit) Literal(syn::Lit)
} }
impl Synom for AttributeValue { impl Parse for AttributeValue {
named!(parse -> Self, do_parse!( fn parse(input: ParseStream) -> Result<Self> {
value: alt!( if input.peek(syn::Lit) {
syn!(ExprLit) => { |d| AttributeValue::Literal(d) } Ok(AttributeValue::Literal(input.parse()?))
| } else if input.peek(syn::token::Brace) {
braces!(syn!(Expr)) => { |d| AttributeValue::Expr(d.1) } let content;
) >> braced!(content in input);
(value) Ok(AttributeValue::Expr(content.parse()?))
)); } else {
Err(input.error("Expected a literal or { expression }"))
}
}
} }
impl ToTokens for AttributeValue { impl ToTokens for AttributeValue {

View File

@ -1,3 +1,4 @@
#![feature(crate_visibility_modifier)]
mod attribute; mod attribute;
mod node; mod node;
@ -8,16 +9,15 @@ extern crate syn;
#[macro_use] #[macro_use]
extern crate quote; extern crate quote;
extern crate proc_macro;
use proc_macro::{TokenStream}; use self::proc_macro::{TokenStream};
use syn::synom::Synom;
use syn::{TypePath, Ident, Expr}; use syn::{TypePath, Ident, Expr};
use syn::buffer::{TokenBuffer};
// use syn::parsers::{named, do_parse, punct, syn, call, alt, braces, many0};
use quote::*; use quote::*;
use self::node::Node; use self::node::Node;
use self::attribute::{Attribute, AttributeValue}; use self::attribute::{Attribute, AttributeValue};
use self::tag::Tag;
fn visit_attribute(ident: &Ident, attr: &Attribute, _ctx: &TypePath) -> impl ToTokens { fn visit_attribute(ident: &Ident, attr: &Attribute, _ctx: &TypePath) -> impl ToTokens {
let attr_name = &attr.name; let attr_name = &attr.name;
@ -110,25 +110,25 @@ fn visit_node(parent: &str, idx: &mut u32, node: &Node, stream: &mut proc_macro2
#[proc_macro] #[proc_macro]
pub fn view(input: TokenStream) -> TokenStream { pub fn view(input: TokenStream) -> TokenStream {
let buffer = TokenBuffer::new(input); let toks = match syn::parse(input) {
let cursor = buffer.begin(); Ok(root) => {
let res = Node::parse(cursor);
let mut output = proc_macro2::TokenStream::new(); let mut output = proc_macro2::TokenStream::new();
let mut thread = proc_macro2::TokenStream::new(); let mut thread = proc_macro2::TokenStream::new();
let mut idx = 0; let mut idx = 0;
match res { visit_node("default", &mut idx, &root, &mut output, &mut thread);
Ok((root, _)) => visit_node("default", &mut idx, &root, &mut output, &mut thread),
Err(err) => panic!("Error: {:?}", err)
};
let toks = quote! {{ quote! {{
let ctx_default = DefaultContext; let ctx_default = DefaultContext;
#output #output
#thread #thread
p0 p0
}}; }}
}
Err(err) => err.to_compile_error()
};
toks.into() toks.into()
} }

View File

@ -1,34 +1,36 @@
use syn::synom::Synom; use syn::parse::{Parse, ParseStream, Result};
use syn::{LitStr, Expr}; use quote::ToTokens;
use crate::tag::Tag;
use crate::tag::Tag;
#[derive(Debug)] #[derive(Debug)]
crate enum Node { crate enum Node {
Tag(Tag), Tag(Tag),
Text(LitStr), Text(syn::LitStr),
Expr(Expr), Expr(syn::Expr),
Embed(Expr) Embed(syn::Expr)
} }
impl Synom for Node { impl Parse for Node {
named!(parse -> Self, do_parse!( fn parse(input: ParseStream) -> Result<Self> {
value: alt!( if input.peek(syn::LitStr) {
syn!(Tag) => { |tag| Node::Tag(tag) } Ok(Node::Text(input.parse()?))
| } else if input.peek(syn::token::Brace) {
braces!( let content;
do_parse!( braced!(content in input);
punct!(.) >>
punct!(.) >>
punct!(.) >>
tt: syn!(Expr) >> (tt)
)) => { |d| Node::Embed(d.1) }
|
braces!(syn!(Expr)) => { |d| Node::Expr(d.1) }
|
syn!(LitStr) => { |_str| Node::Text(_str) }
) >>
(value) Ok(if content.peek(Token![...]) {
)); content.parse::<Token![...]>()?;
let expr = content.parse::<syn::Expr>()?;
Node::Embed(expr)
} else {
let expr = content.parse::<syn::Expr>()?;
Node::Expr(expr)
})
} else {
Ok(Node::Tag(input.parse()?))
}
}
} }

View File

@ -1,7 +1,7 @@
use crate::attribute::Attribute; use crate::attribute::Attribute;
use crate::node::Node; use crate::node::Node;
use syn::TypePath; use syn::TypePath;
use syn::synom::Synom; use syn::parse::{Parse, ParseStream, Result};
#[derive(Debug)] #[derive(Debug)]
crate struct Tag { crate struct Tag {
@ -10,49 +10,54 @@ crate struct Tag {
pub body: Vec<Node> pub body: Vec<Node>
} }
impl Tag { impl Parse for Tag {
pub fn new(open: TypePath, close: Option<TypePath>, attrs: Vec<Attribute>, body: Vec<Node>) -> Result<Self, String> { fn parse(input: ParseStream) -> Result<Self> {
if let Some(close_ref) = &close { let mut attrs: Vec<Attribute> = Vec::new();
if &open != close_ref { let mut children: Vec<Node> = Vec::new();
return Err(format!("Open({}) and closing({}) tags are not matching!", quote!{#open}, quote!{#close_ref})) let mut open_path: TypePath;
} let mut close_path: TypePath;
// parsing opening "<"
input.parse::<Token![<]>()?;
// parsing tag name
open_path = input.parse()?;
// parsing attributes
while input.peek(syn::Ident) {
attrs.push(input.parse()?);
} }
if input.peek(Token![/]) && input.peek2(Token![>]) {
// parsing closing "/>"
input.parse::<Token![/]>()?;
input.parse::<Token![>]>()?;
close_path = open_path.clone();
} else {
// parsing closing ">"
input.parse::<Token![>]>()?;
// parsing children
while !(input.peek(Token![<]) && input.peek2(Token![/])) {
children.push(input.parse()?);
}
// parsing closing "</{tag path}>"
input.parse::<Token![<]>()?;
input.parse::<Token![/]>()?;
close_path = input.parse()?;
input.parse::<Token![>]>()?;
}
if close_path == open_path {
Ok(Tag { Ok(Tag {
path: open, path: open_path,
attributes: attrs, attributes: attrs,
body body: children,
}) })
} else {
Err(input.error("open and close paths shoud match"))
} }
} }
impl Synom for Tag {
named!(parse -> Self, do_parse!(
t: alt!(
do_parse!(
punct!(<) >>
open: syn!(TypePath) >>
attrs: many0!(syn!(Attribute)) >>
punct!(>) >>
body: many0!(syn!(Node)) >>
punct!(<) >> punct!(/) >>
close: syn!(TypePath) >>
punct!(>) >>
(match Tag::new(open, Some(close), attrs, body) {
Ok(v) => v,
Err(e) => panic!("{:?}", e)
})
) => {|x|x}
|
do_parse!(
punct!(<) >>
open: syn!(TypePath) >>
attrs: many0!(syn!(Attribute)) >>
punct!(/) >>
punct!(>) >>
(Tag::new(open, None, attrs, vec![]).unwrap())
) => {|x|x}
) >> (t)
));
} }