diff --git a/examples/unstable/Cargo.toml b/examples/unstable/Cargo.toml new file mode 100644 index 0000000000..472d860cf8 --- /dev/null +++ b/examples/unstable/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "unstable" +version = "0.1.0" +authors = ["Sergio Benitez "] +publish = false + +[lib] +proc-macro = true + +[dependencies] +syn = { path = "../../", features = ["full"] } +proc-macro2 = { version = "0.4", features = ["nightly"] } diff --git a/examples/unstable/src/lib.rs b/examples/unstable/src/lib.rs new file mode 100644 index 0000000000..2ded6b1e1b --- /dev/null +++ b/examples/unstable/src/lib.rs @@ -0,0 +1,92 @@ +#![feature(core_intrinsics, proc_macro_diagnostic)] + +extern crate proc_macro; +extern crate syn; + +use proc_macro::{Diagnostic, Span, TokenStream}; +use syn::buffer::{Cursor, TokenBuffer}; +use syn::spanned::Spanned; +use syn::synom::Synom; +use syn::{token, ExprTuple}; + +struct Parser { + cursor: Cursor<'static>, + + #[allow(dead_code)] + buffer: Box, +} + +impl Parser { + fn new(tokens: TokenStream) -> Parser { + let buffer = Box::new(TokenBuffer::new(tokens)); + let cursor = unsafe { + let buffer: *const TokenBuffer = &*buffer; + let buffer: &'static TokenBuffer = &*buffer; + buffer.begin() + }; + + Parser { cursor, buffer } + } + + fn current_span(&self) -> Span { + self.cursor.span().unstable() + } + + fn parse(&mut self) -> Result { + let (val, cursor) = T::parse(self.cursor).map_err(|e| { + let expected = match T::description() { + Some(desc) => desc, + None => unsafe { std::intrinsics::type_name::() }, + }; + + self.current_span() + .error(format!("{}: expected {}", e, expected)) + })?; + + self.cursor = cursor; + Ok(val) + } + + fn eof(&mut self) -> Result<(), Diagnostic> { + if !self.cursor.eof() { + return Err(self + .current_span() + .error("trailing characters; expected eof")); + } + + Ok(()) + } +} + +fn eval(input: TokenStream) -> Result { + let mut parser = Parser::new(input); + + let a = parser.parse::()?; + parser.parse::()?; + let b = parser.parse::()?; + parser.eof()?; + + let (a_len, b_len) = (a.elems.len(), b.elems.len()); + if a_len != b_len { + let diag = b + .span() + .unstable() + .error(format!("expected {} element(s), got {}", a_len, b_len)) + .span_note(a.span().unstable(), "because of this"); + + return Err(diag); + } + + Ok("println!(\"All good!\")".parse().unwrap()) +} + +#[proc_macro] +pub fn demo(input: TokenStream) -> TokenStream { + match eval(input) { + Ok(val) => val, + Err(diag) => { + diag.emit(); + "".parse().unwrap() + } + } +} diff --git a/examples/unstable/src/main.rs b/examples/unstable/src/main.rs new file mode 100644 index 0000000000..6b48e4641c --- /dev/null +++ b/examples/unstable/src/main.rs @@ -0,0 +1,13 @@ +#![feature(proc_macro_non_items)] + +#[macro_use] +extern crate unstable; + +pub fn main() { + demo!((a, b) = (1, 2, 3)); + demo!((a, b, c) = (1, 2, 3)); + demo!((c) = (1, 2, 3)); + demo!((c) ? (1, 2, 3)); + demo!(c = (1, 2, 3)); + demo!((a, b, c) = (1, 2, 3) hi); +}