Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A good chunk of stable patterns for marker #68

Merged
merged 8 commits into from Jan 6, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions marker_api/src/ast/common/id.rs
Expand Up @@ -64,6 +64,26 @@ new_id! {
pub BodyId: u64
}

new_id! {
/// This ID uniquely identifies a variable during linting.
///
/// A variable can have several declaration spots. This can happen if they
/// originate from an or binding. Like this:
/// ```
/// # #[allow(dead_code)]
/// # enum Helper {
/// # One(&'static str),
/// # Two(&'static str),
/// # Three(&'static str),
/// # }
/// # let source = Helper::Three("duck");
/// if let Helper::One(msg) | Helper::Two(msg) = source {
/// println!("{msg}");
/// }
/// ```
pub VarId: u64
}

new_id! {
/// **Unstable**
///
Expand Down
1 change: 1 addition & 0 deletions marker_api/src/ast/mod.rs
Expand Up @@ -7,6 +7,7 @@ use self::item::ItemKind;

pub mod generic;
pub mod item;
pub mod pat;
pub mod ty;

#[derive(Debug)]
Expand Down
108 changes: 108 additions & 0 deletions marker_api/src/ast/pat.rs
@@ -0,0 +1,108 @@
use super::{Span, SpanId};

use std::{fmt::Debug, marker::PhantomData};

mod ident_pat;
pub use ident_pat::*;
mod wildcard_pat;
pub use wildcard_pat::*;
mod rest_pat;
pub use rest_pat::*;
mod ref_pat;
pub use ref_pat::*;
mod struct_pat;
pub use struct_pat::*;
mod tuple_pat;
pub use tuple_pat::*;
mod slice_pat;
pub use slice_pat::*;
mod or_pat;
pub use or_pat::*;

pub trait PatData<'ast>: Debug {
/// Returns the span of this pattern.
fn span(&self) -> &Span<'ast>;

fn as_pat(&'ast self) -> PatKind<'ast>;
}

#[repr(C)]
#[non_exhaustive]
#[derive(Debug, Clone, Copy)]
pub enum PatKind<'ast> {
Ident(&'ast IdentPat<'ast>),
Wildcard(&'ast WildcardPat<'ast>),
Rest(&'ast RestPat<'ast>),
Ref(&'ast RefPat<'ast>),
Struct(&'ast StructPat<'ast>),
Tuple(&'ast TuplePat<'ast>),
Slice(&'ast SlicePat<'ast>),
Or(&'ast OrPat<'ast>),
}

impl<'ast> PatKind<'ast> {
impl_pat_data_fn!(span() -> &Span<'ast>);
}

macro_rules! impl_pat_data_fn {
($method:ident () -> $return_ty:ty) => {
impl_pat_data_fn!(
$method() -> $return_ty,
Ident, Wildcard, Rest, Ref, Struct, Tuple, Slice, Or
);
};
($method:ident () -> $return_ty:ty $(, $item:ident)+) => {
pub fn $method(&self) -> $return_ty {
match self {
$(PatKind::$item(data) => data.$method(),)*
}
}
};
}

use impl_pat_data_fn;

#[repr(C)]
#[derive(Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "driver-api", visibility::make(pub))]
struct CommonPatData<'ast> {
/// The lifetime is not needed right now, but it's safer to include it for
/// future additions. Having it in this struct makes it easier for all
/// pattern structs, as they will have a valid use for `'ast` even if they
/// don't need it. Otherwise, we might need to declare this field in each
/// pattern.
_lifetime: PhantomData<&'ast ()>,
span: SpanId,
}

#[cfg(feature = "driver-api")]
impl<'ast> CommonPatData<'ast> {
pub fn new(span: SpanId) -> Self {
Self {
_lifetime: PhantomData,
span,
}
}
}

macro_rules! impl_pat_data {
($self_ty:ty, $enum_name:ident) => {
impl<'ast> super::PatData<'ast> for $self_ty {
fn span(&self) -> &crate::ast::Span<'ast> {
$crate::context::with_cx(self, |cx| cx.get_span(self.data.span))
}

fn as_pat(&'ast self) -> crate::ast::pat::PatKind<'ast> {
$crate::ast::pat::PatKind::$enum_name(self)
}
}

impl<'ast> From<&'ast $self_ty> for $crate::ast::pat::PatKind<'ast> {
fn from(from: &'ast $self_ty) -> Self {
$crate::ast::pat::PatKind::$enum_name(from)
}
}
};
}

use impl_pat_data;
75 changes: 75 additions & 0 deletions marker_api/src/ast/pat/ident_pat.rs
@@ -0,0 +1,75 @@
use crate::{
ast::{SymbolId, VarId},
context::with_cx,
ffi::FfiOption,
};

use super::{CommonPatData, PatKind};

#[repr(C)]
#[derive(Debug)]
pub struct IdentPat<'ast> {
data: CommonPatData<'ast>,
name: SymbolId,
var: VarId,
is_mut: bool,
is_ref: bool,
binding_pat: FfiOption<PatKind<'ast>>,
}

impl<'ast> IdentPat<'ast> {
pub fn name(&self) -> String {
with_cx(self, |cx| cx.symbol_str(self.name))
}

pub fn var_id(&self) -> VarId {
self.var
}

pub fn is_mut(&self) -> bool {
self.is_mut
}

pub fn is_ref(&self) -> bool {
self.is_ref
}

/// The pattern, if the variable originates from a binding to a pattern.
/// ```
/// # let expr = 10;
/// match expr {
/// x @ 0.. => println!("{x} is positive"),
/// // ^ ^^^
/// // | +-- The pattern, that the variable is bound to
/// // |
/// // +-------- The variable which is bound
xFrednet marked this conversation as resolved.
Show resolved Hide resolved
/// _ => println!("x is most likely negative"),
/// }
/// ```
pub fn binding_pat(&self) -> Option<PatKind<'ast>> {
self.binding_pat.copy()
}
}

super::impl_pat_data!(IdentPat<'ast>, Ident);

#[cfg(feature = "driver-api")]
impl<'ast> IdentPat<'ast> {
pub fn new(
data: CommonPatData<'ast>,
name: SymbolId,
var: VarId,
is_mut: bool,
is_ref: bool,
binding_pat: Option<PatKind<'ast>>,
) -> Self {
Self {
data,
name,
var,
is_mut,
is_ref,
binding_pat: binding_pat.into(),
}
}
}
28 changes: 28 additions & 0 deletions marker_api/src/ast/pat/or_pat.rs
@@ -0,0 +1,28 @@
use crate::ffi::FfiSlice;

use super::{CommonPatData, PatKind};

#[repr(C)]
#[derive(Debug)]
pub struct OrPat<'ast> {
data: CommonPatData<'ast>,
patterns: FfiSlice<'ast, PatKind<'ast>>,
}

impl<'ast> OrPat<'ast> {
pub fn patterns(&self) -> &[PatKind<'ast>] {
(&self.patterns).into()
}
}

super::impl_pat_data!(OrPat<'ast>, Or);

#[cfg(feature = "driver-api")]
impl<'ast> OrPat<'ast> {
pub fn new(data: CommonPatData<'ast>, patterns: &'ast [PatKind<'ast>]) -> Self {
Self {
data,
patterns: patterns.into(),
}
}
}
24 changes: 24 additions & 0 deletions marker_api/src/ast/pat/ref_pat.rs
@@ -0,0 +1,24 @@
use super::{CommonPatData, PatKind};

#[repr(C)]
#[derive(Debug)]
pub struct RefPat<'ast> {
data: CommonPatData<'ast>,
pattern: PatKind<'ast>,
}

impl<'ast> RefPat<'ast> {
/// Returns the pattern, that is behind this reference pattern.
pub fn pattern(&self) -> PatKind<'ast> {
self.pattern
}
}

super::impl_pat_data!(RefPat<'ast>, Ref);

#[cfg(feature = "driver-api")]
impl<'ast> RefPat<'ast> {
pub fn new(data: CommonPatData<'ast>, pattern: PatKind<'ast>) -> Self {
Self { data, pattern }
}
}
16 changes: 16 additions & 0 deletions marker_api/src/ast/pat/rest_pat.rs
@@ -0,0 +1,16 @@
use super::CommonPatData;

#[repr(C)]
#[derive(Debug)]
pub struct RestPat<'ast> {
data: CommonPatData<'ast>,
}

super::impl_pat_data!(RestPat<'ast>, Rest);

#[cfg(feature = "driver-api")]
impl<'ast> RestPat<'ast> {
pub fn new(data: CommonPatData<'ast>) -> Self {
Self { data }
}
}
28 changes: 28 additions & 0 deletions marker_api/src/ast/pat/slice_pat.rs
@@ -0,0 +1,28 @@
use crate::ffi::FfiSlice;

use super::{CommonPatData, PatKind};

#[repr(C)]
#[derive(Debug)]
pub struct SlicePat<'ast> {
data: CommonPatData<'ast>,
elements: FfiSlice<'ast, PatKind<'ast>>,
}

impl<'ast> SlicePat<'ast> {
pub fn elements(&self) -> &[PatKind<'ast>] {
(&self.elements).into()
}
}

super::impl_pat_data!(SlicePat<'ast>, Slice);

#[cfg(feature = "driver-api")]
impl<'ast> SlicePat<'ast> {
pub fn new(data: CommonPatData<'ast>, elements: &'ast [PatKind<'ast>]) -> Self {
Self {
data,
elements: elements.into(),
}
}
}