diff options
author | Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> | 2023-08-28 17:20:28 +0200 |
---|---|---|
committer | Arthur Cohen <arthur.cohen@embecosm.com> | 2024-01-16 19:04:32 +0100 |
commit | b1c722d1411448e00d45bb4da0aca2421dcd54e0 (patch) | |
tree | b11715e039833ce6ebc83a6ff284a2b69ae5296b /libgrust/libproc_macro | |
parent | fd73cf8c31611dd8ddbf7835ce246e56771618ef (diff) | |
download | gcc-b1c722d1411448e00d45bb4da0aca2421dcd54e0.zip gcc-b1c722d1411448e00d45bb4da0aca2421dcd54e0.tar.gz gcc-b1c722d1411448e00d45bb4da0aca2421dcd54e0.tar.bz2 |
gccrs: libproc_macro: Split c++ and rust
Move the rust interface to the libproc_macro directory.
libgrust/ChangeLog:
* libproc_macro_internal/rust/bridge.rs: Moved to...
* libproc_macro/bridge.rs: ...here.
* libproc_macro_internal/rust/bridge/ffistring.rs: Moved to...
* libproc_macro/bridge/ffistring.rs: ...here.
* libproc_macro_internal/rust/bridge/group.rs: Moved to...
* libproc_macro/bridge/group.rs: ...here.
* libproc_macro_internal/rust/bridge/ident.rs: Moved to...
* libproc_macro/bridge/ident.rs: ...here.
* libproc_macro_internal/rust/bridge/literal.rs: Moved to...
* libproc_macro/bridge/literal.rs: ...here.
* libproc_macro_internal/rust/bridge/punct.rs: Moved to...
* libproc_macro/bridge/punct.rs: ...here.
* libproc_macro_internal/rust/bridge/span.rs: Moved to...
* libproc_macro/bridge/span.rs: ...here.
* libproc_macro_internal/rust/bridge/token_stream.rs: Moved to...
* libproc_macro/bridge/token_stream.rs: ...here.
* libproc_macro_internal/rust/group.rs: Moved to...
* libproc_macro/group.rs: ...here.
* libproc_macro_internal/rust/ident.rs: Moved to...
* libproc_macro/ident.rs: ...here.
* libproc_macro_internal/rust/lib.rs: Moved to...
* libproc_macro/lib.rs: ...here.
* libproc_macro_internal/rust/literal.rs: Moved to...
* libproc_macro/literal.rs: ...here.
* libproc_macro_internal/rust/punct.rs: Moved to...
* libproc_macro/punct.rs: ...here.
* libproc_macro_internal/rust/span.rs: Moved to...
* libproc_macro/span.rs: ...here.
* libproc_macro_internal/rust/token_stream.rs: Moved to...
* libproc_macro/token_stream.rs: ...here.
Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
Diffstat (limited to 'libgrust/libproc_macro')
-rw-r--r-- | libgrust/libproc_macro/bridge.rs | 15 | ||||
-rw-r--r-- | libgrust/libproc_macro/bridge/ffistring.rs | 51 | ||||
-rw-r--r-- | libgrust/libproc_macro/bridge/group.rs | 60 | ||||
-rw-r--r-- | libgrust/libproc_macro/bridge/ident.rs | 58 | ||||
-rw-r--r-- | libgrust/libproc_macro/bridge/literal.rs | 241 | ||||
-rw-r--r-- | libgrust/libproc_macro/bridge/punct.rs | 39 | ||||
-rw-r--r-- | libgrust/libproc_macro/bridge/span.rs | 40 | ||||
-rw-r--r-- | libgrust/libproc_macro/bridge/token_stream.rs | 156 | ||||
-rw-r--r-- | libgrust/libproc_macro/group.rs | 88 | ||||
-rw-r--r-- | libgrust/libproc_macro/ident.rs | 67 | ||||
-rw-r--r-- | libgrust/libproc_macro/lib.rs | 198 | ||||
-rw-r--r-- | libgrust/libproc_macro/literal.rs | 189 | ||||
-rw-r--r-- | libgrust/libproc_macro/punct.rs | 92 | ||||
-rw-r--r-- | libgrust/libproc_macro/span.rs | 52 | ||||
-rw-r--r-- | libgrust/libproc_macro/token_stream.rs | 52 |
15 files changed, 1398 insertions, 0 deletions
diff --git a/libgrust/libproc_macro/bridge.rs b/libgrust/libproc_macro/bridge.rs new file mode 100644 index 0000000..3900ae1 --- /dev/null +++ b/libgrust/libproc_macro/bridge.rs @@ -0,0 +1,15 @@ +pub mod ffistring; +pub mod group; +pub mod ident; +pub mod literal; +pub mod punct; +pub mod span; +pub mod token_stream; + +extern "C" { + fn bridge__is_available() -> bool; +} + +pub fn is_available() -> bool { + unsafe { bridge__is_available() } +} diff --git a/libgrust/libproc_macro/bridge/ffistring.rs b/libgrust/libproc_macro/bridge/ffistring.rs new file mode 100644 index 0000000..73162e9 --- /dev/null +++ b/libgrust/libproc_macro/bridge/ffistring.rs @@ -0,0 +1,51 @@ +use std::convert::TryInto; +use std::ffi::c_uchar; +use std::fmt; +use std::slice::from_raw_parts; +use std::str::from_utf8; + +extern "C" { + fn FFIString__new(data: *const c_uchar, len: u64) -> FFIString; + fn FFIString__drop(string: *mut FFIString); +} + +#[repr(C)] +#[derive(Debug)] +pub struct FFIString { + data: *const c_uchar, + len: u64, +} + +impl<S> From<S> for FFIString +where + S: AsRef<str>, +{ + fn from(s: S) -> Self { + unsafe { FFIString__new(s.as_ref().as_ptr(), s.as_ref().len() as u64) } + } +} + +impl Clone for FFIString { + fn clone(&self) -> Self { + FFIString::from(&self.to_string()) + } +} + +impl Drop for FFIString { + fn drop(&mut self) { + unsafe { + FFIString__drop(self as *mut FFIString); + } + } +} + +impl fmt::Display for FFIString { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str( + from_utf8(unsafe { + from_raw_parts(self.data, self.len.try_into().map_err(|_| fmt::Error)?) + }) + .map_err(|_| fmt::Error)?, + ) + } +} diff --git a/libgrust/libproc_macro/bridge/group.rs b/libgrust/libproc_macro/bridge/group.rs new file mode 100644 index 0000000..254a3db --- /dev/null +++ b/libgrust/libproc_macro/bridge/group.rs @@ -0,0 +1,60 @@ +use bridge::span::Span; +use bridge::token_stream::TokenStream; +use std::fmt; +use Delimiter; + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct Group { + delimiter: Delimiter, + stream: TokenStream, + span: Span, +} + +impl Group { + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Self { + Group { + delimiter, + stream, + span: Span::default(), + } + } + + pub fn delimiter(&self) -> Delimiter { + self.delimiter + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + let _ = span; + } + + pub fn stream(&self) -> TokenStream { + self.stream.clone() + } +} + +impl fmt::Display for Group { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.delimiter { + Delimiter::Parenthesis => f.write_str("(")?, + Delimiter::Brace => f.write_str("{")?, + Delimiter::Bracket => f.write_str("[")?, + Delimiter::None => (), + } + + self.stream.fmt(f)?; + + match self.delimiter { + Delimiter::Parenthesis => f.write_str(")")?, + Delimiter::Brace => f.write_str("}")?, + Delimiter::Bracket => f.write_str("]")?, + Delimiter::None => (), + } + + Ok(()) + } +} diff --git a/libgrust/libproc_macro/bridge/ident.rs b/libgrust/libproc_macro/bridge/ident.rs new file mode 100644 index 0000000..d58896d --- /dev/null +++ b/libgrust/libproc_macro/bridge/ident.rs @@ -0,0 +1,58 @@ +use bridge::ffistring::FFIString; +use bridge::span::Span; +use std::fmt; + +extern "C" { + fn Ident__new(str: FFIString, span: Span) -> Ident; + fn Ident__new_raw(str: FFIString, span: Span) -> Ident; + fn Ident__drop(ident: *mut Ident); + fn Ident__clone(ident: *const Ident) -> Ident; +} + +#[repr(C)] +#[derive(Debug)] +pub struct Ident { + pub(crate) is_raw: bool, + value: FFIString, + span: Span, +} + +impl Ident { + pub fn new(string: &str, span: Span) -> Self { + unsafe { Ident__new(string.into(), span) } + } + + pub fn new_raw(string: &str, span: Span) -> Self { + unsafe { Ident__new_raw(string.into(), span) } + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +impl Drop for Ident { + fn drop(&mut self) { + unsafe { Ident__drop(self as *mut Ident) } + } +} + +impl fmt::Display for Ident { + /// Display as lossless converted string. + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.is_raw { + f.write_str("r#")?; + } + self.value.fmt(f) + } +} + +impl Clone for Ident { + fn clone(&self) -> Self { + unsafe { Ident__clone(self as *const Ident) } + } +} diff --git a/libgrust/libproc_macro/bridge/literal.rs b/libgrust/libproc_macro/bridge/literal.rs new file mode 100644 index 0000000..5982504 --- /dev/null +++ b/libgrust/libproc_macro/bridge/literal.rs @@ -0,0 +1,241 @@ +use bridge::{ffistring::FFIString, span::Span}; +use std::fmt; +use std::str::FromStr; +use LexError; + +extern "C" { + fn Literal__from_string(str: FFIString, lit: *mut Literal) -> bool; +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub enum LitKind { + Byte, + Char, + Integer, + Float, + Str, + StrRaw(u8), + ByteStr, + ByteStrRaw(u8), + Err, +} + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct Literal { + kind: LitKind, + text: FFIString, + suffix: FFIString, + span: Span, +} + +macro_rules! suffixed_int_literals { + ($($name: ident => $kind: ident,)*) => ($( + pub fn $name(n : $kind) -> Literal { + Literal { + kind : LitKind::Integer, + text: FFIString::from(&n.to_string()), + suffix: FFIString::from(stringify!($kind)), + span: Span::default(), + } + } + )*) +} + +macro_rules! unsuffixed_int_literals { + ($($name: ident => $kind: ident,)*) => ($( + pub fn $name(n : $kind) -> Literal { + Literal { + kind : LitKind::Integer, + text: FFIString::from(&n.to_string()), + suffix: FFIString::from(""), + span: Span::default(), + } + } + )*) +} + +impl Literal { + suffixed_int_literals! { + u8_suffixed => u8, + u16_suffixed => u16, + u32_suffixed => u32, + u64_suffixed => u64, + u128_suffixed => u128, + usize_suffixed => usize, + i8_suffixed => i8, + i16_suffixed => i16, + i32_suffixed => i32, + i64_suffixed => i64, + i128_suffixed => i128, + isize_suffixed => isize, + } + + unsuffixed_int_literals! { + u8_unsuffixed => u8, + u16_unsuffixed => u16, + u32_unsuffixed => u32, + u64_unsuffixed => u64, + u128_unsuffixed => u128, + usize_unsuffixed => usize, + i8_unsuffixed => i8, + i16_unsuffixed => i16, + i32_unsuffixed => i32, + i64_unsuffixed => i64, + i128_unsuffixed => i128, + isize_unsuffixed => isize, + } + + pub fn f32_unsuffixed(n: f32) -> Self { + let mut repr = n.to_string(); + if !repr.contains('.') { + repr.push_str(".0"); + } + + Literal { + kind: LitKind::Float, + text: FFIString::from(&repr), + suffix: FFIString::from(""), + span: Span::default(), + } + } + + pub fn f32_suffixed(n: f32) -> Self { + Literal { + kind: LitKind::Float, + text: FFIString::from(&n.to_string()), + suffix: FFIString::from("f32"), + span: Span::default(), + } + } + + pub fn f64_unsuffixed(n: f64) -> Self { + let mut repr = n.to_string(); + if !repr.contains('.') { + repr.push_str(".0"); + } + + Literal { + kind: LitKind::Float, + text: FFIString::from(&repr), + suffix: FFIString::from(""), + span: Span::default(), + } + } + + pub fn f64_suffixed(n: f64) -> Self { + Literal { + kind: LitKind::Float, + text: FFIString::from(&n.to_string()), + suffix: FFIString::from("f64"), + span: Span::default(), + } + } + + pub fn string(string: &str) -> Self { + Literal { + kind: LitKind::Str, + text: FFIString::from(string), + suffix: FFIString::from(""), + span: Span::default(), + } + } + + pub fn character(c: char) -> Self { + Literal { + kind: LitKind::Char, + text: FFIString::from(&c.to_string()), + suffix: FFIString::from(""), + span: Span::default(), + } + } + + pub fn byte_string(bytes: &[u8]) -> Self { + Literal { + kind: LitKind::ByteStr, + text: FFIString::from(&bytes.escape_ascii().to_string()), + suffix: FFIString::from(""), + span: Span::default(), + } + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let text = &self.text.to_string(); + match self.kind { + LitKind::Byte => { + f.write_str("b'")?; + f.write_str(text)?; + f.write_str("'")?; + } + LitKind::Char => { + f.write_str("'")?; + f.write_str(text)?; + f.write_str("'")?; + } + LitKind::Str => { + f.write_str("\"")?; + f.write_str(text)?; + f.write_str("\"")?; + } + LitKind::StrRaw(n) => { + f.write_str("r")?; + for _ in 0..n { + f.write_str("#")?; + } + f.write_str("\"")?; + f.write_str(text)?; + f.write_str("\"")?; + } + LitKind::ByteStr => { + f.write_str("b\"")?; + f.write_str(text)?; + f.write_str("\"")?; + } + LitKind::ByteStrRaw(n) => { + f.write_str("br")?; + for _ in 0..n { + f.write_str("#")?; + } + f.write_str("\"")?; + f.write_str(text)?; + f.write_str("\"")?; + } + _ => f.write_str(text)?, + } + + f.write_str(&self.suffix.to_string())?; + Ok(()) + } +} + +impl FromStr for Literal { + type Err = LexError; + + fn from_str(string: &str) -> Result<Self, LexError> { + // Structure that will be filled in by the cpp + let mut lit = Literal { + kind: LitKind::Err, + text: FFIString::from(""), + suffix: FFIString::from(""), + span: Span::default(), + }; + // TODO: We might want to pass a LexError by reference to retrieve + // error information + if unsafe { Literal__from_string(string.into(), &mut lit as *mut Literal) } { + Err(LexError) + } else { + Ok(lit) + } + } +} diff --git a/libgrust/libproc_macro/bridge/punct.rs b/libgrust/libproc_macro/bridge/punct.rs new file mode 100644 index 0000000..e835472 --- /dev/null +++ b/libgrust/libproc_macro/bridge/punct.rs @@ -0,0 +1,39 @@ +use bridge::span::Span; +use std::convert::TryFrom; +use std::fmt; +use Spacing; + +#[repr(C)] +#[derive(Clone, Debug)] +pub struct Punct { + pub(crate) ch: u32, + pub(crate) spacing: Spacing, + span: Span, +} + +impl Punct { + pub fn new(ch: char, spacing: Spacing) -> Self { + Punct { + ch: ch.into(), + spacing, + span: Span::default(), + } + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + let _ = span; + } +} + +impl fmt::Display for Punct { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Spacing::Alone = self.spacing { + f.write_str(" ")?; + } + char::try_from(self.ch).unwrap().fmt(f) + } +} diff --git a/libgrust/libproc_macro/bridge/span.rs b/libgrust/libproc_macro/bridge/span.rs new file mode 100644 index 0000000..06537c9 --- /dev/null +++ b/libgrust/libproc_macro/bridge/span.rs @@ -0,0 +1,40 @@ +//! Bridge internal span representation and functions +//! +//! # Note +//! +//! All methods accessing source location in rust are unstable, hence this +//! implementation with an empty structure. + +/// # Note: Gcc does not have a span interner, a span will not contain an index +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Span { + location: u32, +} + +impl Span { + pub fn call_site() -> Self { + // FIXME: implement this function properly + Span::default() + } + + pub fn mixed_site() -> Self { + // FIXME: implement this function properly + Span::default() + } + + pub fn resolved_at(&self, _other: Span) -> Self { + // FIXME: implement this function properly + Span::default() + } + + pub fn located_at(&self, _other: Span) -> Self { + // FIXME: implement this function properly + Span::default() + } + + pub fn source_text(&self) -> Option<String> { + // FIXME: implement this function properly + None + } +} diff --git a/libgrust/libproc_macro/bridge/token_stream.rs b/libgrust/libproc_macro/bridge/token_stream.rs new file mode 100644 index 0000000..094f91f --- /dev/null +++ b/libgrust/libproc_macro/bridge/token_stream.rs @@ -0,0 +1,156 @@ +use bridge::{ffistring::FFIString, group::Group, ident::Ident, literal::Literal, punct::Punct}; +use std::convert::TryInto; +use std::fmt; +use std::slice; +use std::str::FromStr; +use LexError; + +type ExternalTokenTree = crate::TokenTree; +type ExternalTokenStream = crate::TokenStream; + +extern "C" { + fn TokenStream__new() -> TokenStream; + fn TokenStream__with_capacity(capacity: u64) -> TokenStream; + fn TokenStream__push(stream: *mut TokenStream, tree: TokenTree); + fn TokenStream__from_string(str: FFIString, ts: *mut TokenStream) -> bool; + fn TokenStream__clone(ts: *const TokenStream) -> TokenStream; + fn TokenStream__drop(stream: *mut TokenStream); +} + +#[repr(C)] +#[derive(Clone)] +pub enum TokenTree { + Group(Group), + Ident(Ident), + Punct(Punct), + Literal(Literal), +} + +impl fmt::Display for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TokenTree::Group(group) => group.fmt(f), + TokenTree::Ident(ident) => ident.fmt(f), + TokenTree::Punct(punct) => punct.fmt(f), + TokenTree::Literal(literal) => literal.fmt(f), + } + } +} + +impl From<ExternalTokenTree> for TokenTree { + fn from(value: ExternalTokenTree) -> Self { + match value { + ExternalTokenTree::Group(g) => TokenTree::Group(g.0), + ExternalTokenTree::Ident(i) => TokenTree::Ident(i.0), + ExternalTokenTree::Punct(p) => TokenTree::Punct(p.0), + ExternalTokenTree::Literal(l) => TokenTree::Literal(l.0), + } + } +} + +#[repr(C)] +#[derive(Debug)] +pub struct TokenStream { + pub(crate) data: *const TokenTree, + pub(crate) size: u64, + capacity: u64, +} + +impl TokenStream { + pub fn new() -> Self { + unsafe { TokenStream__new() } + } + + fn with_capacity(capacity: u64) -> Self { + unsafe { TokenStream__with_capacity(capacity) } + } + + fn push(&mut self, tree: TokenTree) { + unsafe { TokenStream__push(self as *mut TokenStream, tree) } + } + + pub fn is_empty(&self) -> bool { + 0 == self.size + } + + pub fn from_iterator<I>(it: I) -> Self + where + I: IntoIterator<Item = ExternalTokenStream>, + { + let it = it.into_iter(); + let mut result = TokenStream::with_capacity(it.size_hint().0.try_into().unwrap()); + for stream in it { + for item in stream.into_iter() { + result.push(item.into()); + } + } + result + } + + pub fn from_tree_iterator<I>(it: I) -> Self + where + I: IntoIterator<Item = ExternalTokenTree>, + { + let it = it.into_iter(); + let mut result = TokenStream::with_capacity(it.size_hint().0.try_into().unwrap()); + for item in it { + result.push(item.into()); + } + result + } +} + +impl Extend<ExternalTokenTree> for TokenStream { + fn extend<I: IntoIterator<Item = ExternalTokenTree>>(&mut self, trees: I) { + for tt in trees { + self.push(tt.into()) + } + } +} + +impl Extend<ExternalTokenStream> for TokenStream { + fn extend<I: IntoIterator<Item = ExternalTokenStream>>(&mut self, streams: I) { + for stream in streams { + for tt in stream { + self.push(tt.into()); + } + } + } +} + +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for i in unsafe { slice::from_raw_parts(self.data, self.size.try_into().unwrap()) } { + i.fmt(f)?; + match i { + TokenTree::Punct(_) => (), + _ => f.write_str(" ")?, + } + } + Ok(()) + } +} + +impl FromStr for TokenStream { + type Err = LexError; + fn from_str(string: &str) -> Result<Self, LexError> { + let mut ts = TokenStream::new(); + if unsafe { TokenStream__from_string(string.into(), &mut ts as *mut TokenStream) } { + Err(LexError) + } else { + Ok(ts) + } + } +} + +impl Clone for TokenStream { + fn clone(&self) -> Self { + unsafe { TokenStream__clone(self as *const TokenStream) } + } +} + +impl Drop for TokenStream { + fn drop(&mut self) { + unsafe { TokenStream__drop(self as *mut TokenStream) } + } +} diff --git a/libgrust/libproc_macro/group.rs b/libgrust/libproc_macro/group.rs new file mode 100644 index 0000000..29bfb9d --- /dev/null +++ b/libgrust/libproc_macro/group.rs @@ -0,0 +1,88 @@ +use bridge; +use std::fmt; +use Span; +use TokenStream; + +/// Describes how a sequence of token trees is delimited. +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Delimiter { + /// The sequence is delimited by a parenthesis `(...)`. + Parenthesis, + /// The sequence is delimited by a brace `{...}`. + Brace, + /// The sequence is delimited by a bracket `[...]`. + Bracket, + /// Invisible delimiter to preserve operator priority. + None, +} + +/// A delimited token stream. +#[derive(Clone)] +pub struct Group(pub(crate) bridge::group::Group); + +impl Group { + /// Creates a new `Group`. + /// + /// # Arguments + /// + /// * `delimiter` - The delimiter surrounding the inner [`TokenStream`]. + /// * `stream` - The tokenstream for this `Group`. + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Self { + Group(bridge::group::Group::new(delimiter, stream.0)) + } + + /// Get the delimiter of the `Group`. + pub fn delimiter(&self) -> Delimiter { + self.0.delimiter() + } + + /// Get the stream of the `Group`. + /// + /// # Note + /// + /// The returned stream does not include the delimiters of this group. + pub fn stream(&self) -> TokenStream { + TokenStream(self.0.stream()) + } + + /// Get the span for the delimiters of this token stream, spanning the + /// entire group. + pub fn span(&self) -> Span { + Span(self.0.span()) + } + + /// Get the span pointing to the opening delimiter of this `Group`. + pub fn span_open(&self) -> Span { + Span(self.0.span()) + } + + /// Get the span pointing to the closing delimiter of this `Group`. + pub fn span_close(&self) -> Span { + Span(self.0.span()) + } + + /// Change the span for this `Group`'s delimiters, but not its internal + /// tokens. + /// + /// # Note + /// + /// This method will **not** set the span of all the internal tokens spanned + /// by this group, but rather it will only set the span of the delimiter + /// tokens at the level of the `Group`. + pub fn set_span(&mut self, span: Span) { + self.0.set_span(span.0) + } +} + +impl fmt::Display for Group { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Debug for Group { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} diff --git a/libgrust/libproc_macro/ident.rs b/libgrust/libproc_macro/ident.rs new file mode 100644 index 0000000..809c993 --- /dev/null +++ b/libgrust/libproc_macro/ident.rs @@ -0,0 +1,67 @@ +use bridge; +use std::fmt; +use Span; + +/// An identifier. +#[derive(Clone)] +pub struct Ident(pub(crate) bridge::ident::Ident); + +impl Ident { + /// Creates a new identifier. + /// + /// # Arguments + /// + /// * `string` - A valid identifier. + /// * `span` - The span of the identifier. + /// + /// # Panics + /// + /// The `string` argument must be a valid identifier permitted by the + /// language, otherwise the function will panic. + pub fn new(string: &str, span: Span) -> Self { + Ident(bridge::ident::Ident::new(string, span.0)) + } + + /// Creates a new raw identifier. + /// + /// # Arguments + /// + /// * `string` - A valid identifier. + /// * `span` - The span of the identifier. + /// + /// # Panics + /// + /// The `string` argument must be a valid identifier permitted by the + /// language. Furthermore, it should not be a keyword used in path + /// segments, otherwise this function will panic. + pub fn new_raw(string: &str, span: Span) -> Self { + Ident(bridge::ident::Ident::new_raw(string, span.0)) + } + + /// Return the span of the identifier + pub fn span(&self) -> Span { + Span(self.0.span()) + } + + /// Change the span of the identifier. + /// + /// # Arguments + /// + /// * `span` - The new span value. + pub fn set_span(&mut self, span: Span) { + self.0.set_span(span.0); + } +} + +impl fmt::Display for Ident { + /// Display as lossless converted string. + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} diff --git a/libgrust/libproc_macro/lib.rs b/libgrust/libproc_macro/lib.rs new file mode 100644 index 0000000..a1be0ac --- /dev/null +++ b/libgrust/libproc_macro/lib.rs @@ -0,0 +1,198 @@ +pub use group::{Delimiter, Group}; +pub use ident::Ident; +pub use literal::Literal; +pub use punct::{Punct, Spacing}; +pub use span::Span; +use std::error; +use std::{fmt, iter, str::FromStr}; + +mod bridge; +mod group; +mod ident; +mod literal; +mod punct; +mod span; +pub mod token_stream; + +/// Determines whether proc_macro has been made accessible to the currently +/// running program. +/// +/// # Note +/// +/// This function provide a non panicking way to detect whether the API is +/// invoked from inside of a procedural macro. +pub fn is_available() -> bool { + bridge::is_available() +} + +/// A single token or a delimited sequence of token trees. +#[derive(Clone)] +pub enum TokenTree { + Group(Group), + Ident(Ident), + Punct(Punct), + Literal(Literal), +} + +type InternalTokenTree = bridge::token_stream::TokenTree; + +impl From<InternalTokenTree> for TokenTree { + fn from(value: InternalTokenTree) -> Self { + match value { + InternalTokenTree::Group(g) => TokenTree::Group(Group(g)), + InternalTokenTree::Ident(i) => TokenTree::Ident(Ident(i)), + InternalTokenTree::Punct(p) => TokenTree::Punct(Punct(p)), + InternalTokenTree::Literal(l) => TokenTree::Literal(Literal(l)), + } + } +} + +impl TokenTree { + /// Get the [`Span`] for this TokenTree. + pub fn span(&self) -> Span { + match self { + TokenTree::Group(group) => group.span(), + TokenTree::Ident(ident) => ident.span(), + TokenTree::Punct(punct) => punct.span(), + TokenTree::Literal(literal) => literal.span(), + } + } + + /// Set the span for this TokenTree. + /// + /// # Arguments + /// + /// * `span` - The new span value. + pub fn set_span(&mut self, span: Span) { + match self { + TokenTree::Group(group) => group.set_span(span), + TokenTree::Ident(ident) => ident.set_span(span), + TokenTree::Punct(punct) => punct.set_span(span), + TokenTree::Literal(literal) => literal.set_span(span), + } + } +} + +impl fmt::Debug for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TokenTree::Group(group) => group.fmt(f), + TokenTree::Ident(ident) => ident.fmt(f), + TokenTree::Punct(punct) => punct.fmt(f), + TokenTree::Literal(literal) => literal.fmt(f), + } + } +} + +impl fmt::Display for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TokenTree::Group(group) => group.fmt(f), + TokenTree::Ident(ident) => ident.fmt(f), + TokenTree::Punct(punct) => punct.fmt(f), + TokenTree::Literal(literal) => literal.fmt(f), + } + } +} + +impl From<Group> for TokenTree { + fn from(g: Group) -> Self { + TokenTree::Group(g) + } +} + +impl From<Ident> for TokenTree { + fn from(i: Ident) -> Self { + TokenTree::Ident(i) + } +} + +impl From<Punct> for TokenTree { + fn from(p: Punct) -> Self { + TokenTree::Punct(p) + } +} + +impl From<Literal> for TokenTree { + fn from(l: Literal) -> Self { + TokenTree::Literal(l) + } +} + +/// Error returned from `from_str` functions. +#[derive(Debug)] +pub struct LexError; + +impl fmt::Display for LexError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("cannot parse string into token stream") + } +} + +impl error::Error for LexError {} + +/// An abstract sequence of token trees. +/// +/// This type provides interfaces for iterating over those token trees. This +/// is both the input and the output of `#[proc_macro]`, +/// `#[proc_macro_attribute]` and `#[proc_macro_derive]` definitions. +#[derive(Clone)] +pub struct TokenStream(bridge::token_stream::TokenStream); + +impl TokenStream { + // TODO: Add experimental API functions for this type + + /// Creates an empty `TokenStream` containing no token trees. + pub fn new() -> Self { + TokenStream(bridge::token_stream::TokenStream::new()) + } + + /// Checks if this `TokenStream` is empty. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result<Self, LexError> { + bridge::token_stream::TokenStream::from_str(src).map(TokenStream) + } +} + +impl iter::FromIterator<TokenTree> for TokenStream { + fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self { + TokenStream(bridge::token_stream::TokenStream::from_tree_iterator(trees)) + } +} + +impl iter::FromIterator<TokenStream> for TokenStream { + fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self { + TokenStream(bridge::token_stream::TokenStream::from_iterator(streams)) + } +} + +impl Extend<TokenTree> for TokenStream { + fn extend<I: IntoIterator<Item = TokenTree>>(&mut self, trees: I) { + self.0.extend(trees); + } +} + +impl Extend<TokenStream> for TokenStream { + fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) { + self.0.extend(streams) + } +} diff --git a/libgrust/libproc_macro/literal.rs b/libgrust/libproc_macro/literal.rs new file mode 100644 index 0000000..171ca56 --- /dev/null +++ b/libgrust/libproc_macro/literal.rs @@ -0,0 +1,189 @@ +use bridge; +use std::fmt; +use std::str::FromStr; +use LexError; +use Span; + +/// A type representing a literal value except `true` and `false`. +/// +/// This could be one of the following: +/// * literal string (`"hello"`) +/// * byte string (`b"hello"`) +/// * character (`'a'`) +/// * byte character (`b'a'`) +/// * unsuffixed integer (`42`) +/// * suffixed integer (`42u8`) +/// * unsuffixed floating point number (`1.618`) +/// * suffixed floating point number (`1.618f32`) +/// +/// # Note +/// +/// Boolean literals like `true` and `false` are `Ident`s and do not belong +/// here. +#[derive(Clone)] +pub struct Literal(pub(crate) bridge::literal::Literal); + +impl Literal { + // TODO: Add experimental API functions for this type + // TODO: Generate those constructor with 1/2 macros instead + + pub fn u8_suffixed(n: u8) -> Self { + Literal(bridge::literal::Literal::u8_suffixed(n)) + } + + pub fn u16_suffixed(n: u16) -> Self { + Literal(bridge::literal::Literal::u16_suffixed(n)) + } + + pub fn u32_suffixed(n: u32) -> Self { + Literal(bridge::literal::Literal::u32_suffixed(n)) + } + + pub fn u64_suffixed(n: u64) -> Self { + Literal(bridge::literal::Literal::u64_suffixed(n)) + } + + pub fn u128_suffixed(n: u128) -> Self { + Literal(bridge::literal::Literal::u128_suffixed(n)) + } + + pub fn usize_suffixed(n: usize) -> Self { + Literal(bridge::literal::Literal::usize_suffixed(n)) + } + + pub fn i8_suffixed(n: i8) -> Self { + Literal(bridge::literal::Literal::i8_suffixed(n)) + } + + pub fn i16_suffixed(n: i16) -> Self { + Literal(bridge::literal::Literal::i16_suffixed(n)) + } + + pub fn i32_suffixed(n: i32) -> Self { + Literal(bridge::literal::Literal::i32_suffixed(n)) + } + + pub fn i64_suffixed(n: i64) -> Self { + Literal(bridge::literal::Literal::i64_suffixed(n)) + } + + pub fn i128_suffixed(n: i128) -> Self { + Literal(bridge::literal::Literal::i128_suffixed(n)) + } + + pub fn isize_suffixed(n: isize) -> Self { + Literal(bridge::literal::Literal::isize_suffixed(n)) + } + + // Unsuffixed + + pub fn u8_unsuffixed(n: u8) -> Self { + Literal(bridge::literal::Literal::u8_unsuffixed(n)) + } + + pub fn u16_unsuffixed(n: u16) -> Self { + Literal(bridge::literal::Literal::u16_unsuffixed(n)) + } + + pub fn u32_unsuffixed(n: u32) -> Self { + Literal(bridge::literal::Literal::u32_unsuffixed(n)) + } + + pub fn u64_unsuffixed(n: u64) -> Self { + Literal(bridge::literal::Literal::u64_unsuffixed(n)) + } + + pub fn u128_unsuffixed(n: u128) -> Self { + Literal(bridge::literal::Literal::u128_unsuffixed(n)) + } + + pub fn usize_unsuffixed(n: usize) -> Self { + Literal(bridge::literal::Literal::usize_unsuffixed(n)) + } + + pub fn i8_unsuffixed(n: i8) -> Self { + Literal(bridge::literal::Literal::i8_unsuffixed(n)) + } + + pub fn i16_unsuffixed(n: i16) -> Self { + Literal(bridge::literal::Literal::i16_unsuffixed(n)) + } + + pub fn i32_unsuffixed(n: i32) -> Self { + Literal(bridge::literal::Literal::i32_unsuffixed(n)) + } + + pub fn i64_unsuffixed(n: i64) -> Self { + Literal(bridge::literal::Literal::i64_unsuffixed(n)) + } + + pub fn i128_unsuffixed(n: i128) -> Self { + Literal(bridge::literal::Literal::i128_unsuffixed(n)) + } + + pub fn isize_unsuffixed(n: isize) -> Self { + Literal(bridge::literal::Literal::isize_unsuffixed(n)) + } + + pub fn f32_unsuffixed(n: f32) -> Self { + Literal(bridge::literal::Literal::f32_unsuffixed(n)) + } + + pub fn f32_suffixed(n: f32) -> Self { + Literal(bridge::literal::Literal::f32_suffixed(n)) + } + + pub fn f64_unsuffixed(n: f64) -> Self { + Literal(bridge::literal::Literal::f64_unsuffixed(n)) + } + + pub fn f64_suffixed(n: f64) -> Self { + Literal(bridge::literal::Literal::f64_suffixed(n)) + } + + pub fn string(string: &str) -> Self { + Literal(bridge::literal::Literal::string(string)) + } + + pub fn character(c: char) -> Self { + Literal(bridge::literal::Literal::character(c)) + } + + pub fn byte_string(bytes: &[u8]) -> Self { + Literal(bridge::literal::Literal::byte_string(bytes)) + } + + /// Get the [`Span`] for this literal. + pub fn span(&self) -> Span { + Span(self.0.span()) + } + + /// Set the span for this literal. + /// + /// # Arguments + /// + /// * `span` - The new span value. + pub fn set_span(&mut self, span: Span) { + self.0.set_span(span.0); + } +} + +impl fmt::Debug for Literal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl FromStr for Literal { + type Err = LexError; + + fn from_str(src: &str) -> Result<Self, LexError> { + bridge::literal::Literal::from_str(src).map(Literal) + } +} diff --git a/libgrust/libproc_macro/punct.rs b/libgrust/libproc_macro/punct.rs new file mode 100644 index 0000000..0f7830e --- /dev/null +++ b/libgrust/libproc_macro/punct.rs @@ -0,0 +1,92 @@ +use bridge; +use std::convert::TryInto; +use std::fmt; +use Span; + +/// Describes the context of a [`Punct`] relatively to the next token. +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Spacing { + /// A [`Punct`] is not immediately followed by another `Punct`. + Alone, + /// A [`Punct`] is immediately followed by another `Punct` and can be + /// combined into a multi-character operator. + Joint, +} + +/// Single punctuation character such as `+`, `-` or `#`. +/// +/// Multi-character operators like `+=` are represented as two instances of +/// `Punct` with different forms of `Spacing` returned. +#[derive(Clone)] +pub struct Punct(pub(crate) bridge::punct::Punct); + +impl Punct { + /// Creates a new `Punct` from a given character and spacing. + /// + /// # Arguments + /// + /// * `ch` - The punctuation character. + /// * `spacing` - The link between this character and the next one. + /// + /// # Panics + /// + /// This function will panic if the `ch` argument is not a valid + /// punctuation character allowed by the language. + pub fn new(ch: char, spacing: Spacing) -> Self { + Punct(bridge::punct::Punct::new(ch, spacing)) + } + + /// Get the value for this punctuation character as `char`. + pub fn as_char(&self) -> char { + self.0 + .ch + .try_into() + .expect("Cannot convert from u32 to char") + } + + /// Get the [`Spacing`] of this punctuation character, indicating whether + /// the following character can be combined into a multi-character operator + /// or not. + pub fn spacing(&self) -> Spacing { + self.0.spacing + } + + /// Get the [`Span`] for this punctuation character. + pub fn span(&self) -> Span { + Span(self.0.span()) + } + + /// Set the span for this punctuation character. + /// + /// # Arguments + /// + /// * `span` - The new span value. + pub fn set_span(&mut self, span: Span) { + self.0.set_span(span.0); + } +} + +impl fmt::Display for Punct { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Debug for Punct { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl PartialEq<char> for Punct { + fn eq(&self, rhs: &char) -> bool { + self.as_char() == *rhs + } +} + +impl PartialEq<Punct> for char { + fn eq(&self, rhs: &Punct) -> bool { + *self == rhs.as_char() + } +} diff --git a/libgrust/libproc_macro/span.rs b/libgrust/libproc_macro/span.rs new file mode 100644 index 0000000..b5d573c --- /dev/null +++ b/libgrust/libproc_macro/span.rs @@ -0,0 +1,52 @@ +use bridge; +use std::fmt; + +/// A region of source code along with macro expansion information. +#[derive(Copy, Clone)] +pub struct Span(pub(crate) bridge::span::Span); + +impl Span { + // TODO: Add experimental API functions for this type + + /// Creates a new span that resolves at the macro call location. + pub fn call_site() -> Self { + Span(bridge::span::Span::call_site()) + } + + /// Creates a new span that resolved sometimes at macro call site, and + /// sometimes at macro definition site. + pub fn mixed_site() -> Self { + Span(bridge::span::Span::mixed_site()) + } + + /// Creates a new span with the same line/column informations but that + /// resolve symbols as though it were at `other`. + /// + /// # Arguments + /// + /// * `other` - Other span to resolve at. + pub fn resolved_at(&self, other: Span) -> Self { + Span(self.0.resolved_at(other.0)) + } + + /// Creates a new span with the same name resolution behavior as self, but + /// with the line/column information of `other`. + /// + /// # Arguments + /// + /// * `other` - Other span containing the line/column informations to use. + pub fn located_at(&self, other: Span) -> Self { + Span(self.0.located_at(other.0)) + } + + /// Return the source text behind a span. + pub fn source_text(&self) -> Option<String> { + self.0.source_text() + } +} + +impl fmt::Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} diff --git a/libgrust/libproc_macro/token_stream.rs b/libgrust/libproc_macro/token_stream.rs new file mode 100644 index 0000000..9333e3e --- /dev/null +++ b/libgrust/libproc_macro/token_stream.rs @@ -0,0 +1,52 @@ +//! Public implementation details for the `TokenStream` type, such as iterators. +use bridge; +use std::convert::TryInto; + +use TokenStream; +use TokenTree; + +/// An iterator over [`TokenStream`]'s [`TokenTree`]s. +#[derive(Clone)] +pub struct IntoIter { + current: *const bridge::token_stream::TokenTree, + end: *const bridge::token_stream::TokenTree, +} + +impl Iterator for IntoIter { + type Item = TokenTree; + + fn next(&mut self) -> Option<TokenTree> { + if self.current == self.end { + None + } else { + let result = self.current; + self.current = unsafe { self.current.add(1) }; + Some(unsafe { std::ptr::read(result) }.into()) + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + // TODO: I'm not a fan of those casts, once #![feature(ptr_sub_ptr)] + // is implemented we may replace this line by the following: + // self.end.sub_ptr(self.current) + let remaining = self.end as usize - self.current as usize; + (remaining, Some(remaining)) + } + + fn count(self) -> usize { + self.end as usize - self.current as usize + } +} + +impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + let capacity = self.0.size.try_into().unwrap(); + IntoIter { + current: self.0.data, + end: unsafe { self.0.data.add(capacity) }, + } + } +} |