Return compile errors
This commit is contained in:
parent
2b149f5bdf
commit
ed9488629d
|
@ -0,0 +1,39 @@
|
||||||
|
use proc_macro2::{TokenStream, Span};
|
||||||
|
use quote::{quote_spanned, ToTokens};
|
||||||
|
|
||||||
|
macro_rules! err_span {
|
||||||
|
($span:expr, $($msg:tt)*) => (
|
||||||
|
$crate::error::CompileError::new_spanned(&$span, format!($($msg)*))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CompileError {
|
||||||
|
msg: String,
|
||||||
|
span: Option<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompileError {
|
||||||
|
pub fn new_spanned(span: &Span, msg: String) -> Self {
|
||||||
|
CompileError {
|
||||||
|
span: Some(*span),
|
||||||
|
msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(msg: String) -> Self {
|
||||||
|
CompileError {
|
||||||
|
span: None,
|
||||||
|
msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for CompileError {
|
||||||
|
fn to_tokens(&self, dst: &mut TokenStream) {
|
||||||
|
let msg = &self.msg;
|
||||||
|
let span = self.span.unwrap_or_else(|| Span::call_site());
|
||||||
|
(quote_spanned! { span=>
|
||||||
|
compile_error!(#msg);
|
||||||
|
}).to_tokens(dst);
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,8 @@
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod error;
|
||||||
mod codegen;
|
mod codegen;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
|
@ -53,8 +55,13 @@ use proc_macro::TokenStream;
|
||||||
pub fn derive_externals(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn derive_externals(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let mut input: proc_macro2::TokenStream = input.into();
|
let mut input: proc_macro2::TokenStream = input.into();
|
||||||
|
|
||||||
let ext_def = parser::parse(input.clone()).unwrap();
|
match parser::parse(input.clone()) {
|
||||||
codegen::codegen(&ext_def, &mut input);
|
Ok(ext_def) => {
|
||||||
|
codegen::codegen(&ext_def, &mut input);
|
||||||
input.into()
|
input.into()
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
(quote::quote! { #err }).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use syn::{spanned::Spanned, Ident, ImplItem, ImplItemMethod, ReturnType};
|
use crate::error::CompileError;
|
||||||
|
use syn::{spanned::Spanned, FnArg, Ident, ImplItem, ImplItemMethod, ReturnType};
|
||||||
|
|
||||||
/// A parameter.
|
/// A parameter. This doesn't used for modeling `&self` or `&mut self` parameters.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Param {
|
pub struct Param {
|
||||||
/// A generated identifier used to name temporary variables
|
/// A generated identifier used to name temporary variables
|
||||||
|
@ -15,6 +16,7 @@ pub struct FuncDef {
|
||||||
/// Assigned index of this function.
|
/// Assigned index of this function.
|
||||||
pub index: u32,
|
pub index: u32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
/// The parameter of this function. This excludes the `&self` or `&mut self`.
|
||||||
pub params: Vec<Param>,
|
pub params: Vec<Param>,
|
||||||
pub return_ty: Option<proc_macro2::Span>,
|
pub return_ty: Option<proc_macro2::Span>,
|
||||||
}
|
}
|
||||||
|
@ -34,8 +36,8 @@ pub struct ImplBlockDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an incoming stream of tokens into externalities definition.
|
/// Parse an incoming stream of tokens into externalities definition.
|
||||||
pub fn parse(input: proc_macro2::TokenStream) -> Result<ImplBlockDef, ()> {
|
pub fn parse(input: proc_macro2::TokenStream) -> Result<ImplBlockDef, CompileError> {
|
||||||
let item_impl = syn::parse2::<syn::ItemImpl>(input).map_err(|_| ())?;
|
let item_impl = syn::parse2::<syn::ItemImpl>(input).map_err(|_| CompileError::new("failed to parse".to_string()))?;
|
||||||
|
|
||||||
let mut funcs = vec![];
|
let mut funcs = vec![];
|
||||||
|
|
||||||
|
@ -44,19 +46,28 @@ pub fn parse(input: proc_macro2::TokenStream) -> Result<ImplBlockDef, ()> {
|
||||||
ImplItem::Method(ImplItemMethod { sig, .. }) => {
|
ImplItem::Method(ImplItemMethod { sig, .. }) => {
|
||||||
let index = funcs.len() as u32;
|
let index = funcs.len() as u32;
|
||||||
|
|
||||||
// self TODO: handle this properly
|
|
||||||
let params = sig
|
let params = sig
|
||||||
.decl
|
.decl
|
||||||
.inputs
|
.inputs
|
||||||
.iter()
|
.iter()
|
||||||
.skip(1)
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, input)| {
|
.filter_map(|(idx, input)| {
|
||||||
|
// The first parameter should be either &self or &mut self.
|
||||||
|
// This makes code generation simpler.
|
||||||
|
if idx == 0 {
|
||||||
|
match input {
|
||||||
|
FnArg::SelfRef(_) => return None,
|
||||||
|
_ => return Some(
|
||||||
|
Err(err_span!(input.span(), "only &self and &mut self supported as first argument"))
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let param_name = format!("arg{}", idx);
|
let param_name = format!("arg{}", idx);
|
||||||
let ident = Ident::new(¶m_name, input.span());
|
let ident = Ident::new(¶m_name, input.span());
|
||||||
Param { ident }
|
Some(Ok(Param { ident }))
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Result<Vec<Param>, CompileError>>()?;
|
||||||
|
|
||||||
let return_ty = match sig.decl.output {
|
let return_ty = match sig.decl.output {
|
||||||
ReturnType::Default => None,
|
ReturnType::Default => None,
|
||||||
|
|
Loading…
Reference in New Issue