-
Notifications
You must be signed in to change notification settings - Fork 160
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1510 from 0xPolygonMiden/bitwalker/annotations
feat: implement procedure annotation syntax
- Loading branch information
Showing
16 changed files
with
1,499 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
mod expr; | ||
mod kv; | ||
mod list; | ||
|
||
use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec}; | ||
use core::fmt; | ||
|
||
pub use self::{expr::MetaExpr, kv::MetaKeyValue, list::MetaList}; | ||
use crate::{ast::Ident, parser::HexEncodedValue, Felt, SourceSpan, Span}; | ||
|
||
/// Represents the metadata provided as arguments to an attribute. | ||
#[derive(Clone, PartialEq, Eq)] | ||
pub enum Meta { | ||
/// Represents empty metadata, e.g. `@foo` | ||
Unit, | ||
/// A list of metadata expressions, e.g. `@foo(a, "some text", 0x01)` | ||
/// | ||
/// The list should always have at least one element, and this is guaranteed by the parser. | ||
List(Vec<MetaExpr>), | ||
/// A set of uniquely-named metadata expressions, e.g. `@foo(letter = a, text = "some text")` | ||
/// | ||
/// The set should always have at least one key-value pair, and this is guaranteed by the | ||
/// parser. | ||
KeyValue(BTreeMap<Ident, MetaExpr>), | ||
} | ||
impl Meta { | ||
/// Borrow the metadata without unwrapping the specific type | ||
/// | ||
/// Returns `None` if there is no meaningful metadata | ||
#[inline] | ||
pub fn borrow(&self) -> Option<BorrowedMeta<'_>> { | ||
match self { | ||
Self::Unit => None, | ||
Self::List(ref list) => Some(BorrowedMeta::List(list)), | ||
Self::KeyValue(ref kv) => Some(BorrowedMeta::KeyValue(kv)), | ||
} | ||
} | ||
} | ||
impl FromIterator<MetaItem> for Meta { | ||
#[inline] | ||
fn from_iter<T: IntoIterator<Item = MetaItem>>(iter: T) -> Self { | ||
let mut iter = iter.into_iter(); | ||
match iter.next() { | ||
None => Self::Unit, | ||
Some(MetaItem::Expr(expr)) => Self::List( | ||
core::iter::once(expr) | ||
.chain(iter.map(|item| match item { | ||
MetaItem::Expr(expr) => expr, | ||
MetaItem::KeyValue(..) => unsafe { core::hint::unreachable_unchecked() }, | ||
})) | ||
.collect(), | ||
), | ||
Some(MetaItem::KeyValue(k, v)) => Self::KeyValue( | ||
core::iter::once((k, v)) | ||
.chain(iter.map(|item| match item { | ||
MetaItem::KeyValue(k, v) => (k, v), | ||
MetaItem::Expr(_) => unsafe { core::hint::unreachable_unchecked() }, | ||
})) | ||
.collect(), | ||
), | ||
} | ||
} | ||
} | ||
|
||
impl FromIterator<MetaExpr> for Meta { | ||
#[inline] | ||
fn from_iter<T: IntoIterator<Item = MetaExpr>>(iter: T) -> Self { | ||
Self::List(iter.into_iter().collect()) | ||
} | ||
} | ||
|
||
impl FromIterator<(Ident, MetaExpr)> for Meta { | ||
#[inline] | ||
fn from_iter<T: IntoIterator<Item = (Ident, MetaExpr)>>(iter: T) -> Self { | ||
Self::KeyValue(iter.into_iter().collect()) | ||
} | ||
} | ||
|
||
impl<'a> FromIterator<(&'a str, MetaExpr)> for Meta { | ||
#[inline] | ||
fn from_iter<T>(iter: T) -> Self | ||
where | ||
T: IntoIterator<Item = (&'a str, MetaExpr)>, | ||
{ | ||
Self::KeyValue( | ||
iter.into_iter() | ||
.map(|(k, v)| { | ||
let k = Ident::new_unchecked(Span::new(SourceSpan::UNKNOWN, Arc::from(k))); | ||
(k, v) | ||
}) | ||
.collect(), | ||
) | ||
} | ||
} | ||
|
||
impl<I, V> From<I> for Meta | ||
where | ||
Meta: FromIterator<V>, | ||
I: IntoIterator<Item = V>, | ||
{ | ||
#[inline] | ||
fn from(iter: I) -> Self { | ||
Self::from_iter(iter) | ||
} | ||
} | ||
|
||
/// Represents a reference to the metadata for an [super::Attribute] | ||
/// | ||
/// See [Meta] for what metadata is represented, and its syntax. | ||
#[derive(Copy, Clone, PartialEq, Eq)] | ||
pub enum BorrowedMeta<'a> { | ||
/// A list of metadata expressions | ||
List(&'a [MetaExpr]), | ||
/// A list of uniquely-named metadata expressions | ||
KeyValue(&'a BTreeMap<Ident, MetaExpr>), | ||
} | ||
impl fmt::Debug for BorrowedMeta<'_> { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
match self { | ||
Self::List(items) => write!(f, "{items:#?}"), | ||
Self::KeyValue(items) => write!(f, "{items:#?}"), | ||
} | ||
} | ||
} | ||
|
||
/// Represents a single metadata item provided as an argument to an attribute. | ||
/// | ||
/// For example, the `foo` attribute in `@foo(bar, baz)` has two metadata items, both of `Expr` | ||
/// type, which compose a ` | ||
#[derive(Clone, PartialEq, Eq)] | ||
pub enum MetaItem { | ||
/// A metadata expression, e.g. `"some text"` in `@foo("some text")` | ||
/// | ||
/// This represents the element type for `Meta::List`-based attributes. | ||
Expr(MetaExpr), | ||
/// A named metadata expression, e.g. `letter = a` in `@foo(letter = a)` | ||
/// | ||
/// This represents the element type for `Meta::KeyValue`-based attributes. | ||
KeyValue(Ident, MetaExpr), | ||
} | ||
|
||
impl MetaItem { | ||
/// Unwrap this item to extract the contained [MetaExpr]. | ||
/// | ||
/// Panics if this item is not the `Expr` variant. | ||
#[inline] | ||
#[track_caller] | ||
pub fn unwrap_expr(self) -> MetaExpr { | ||
match self { | ||
Self::Expr(expr) => expr, | ||
Self::KeyValue(..) => unreachable!("tried to unwrap key-value as expression"), | ||
} | ||
} | ||
|
||
/// Unwrap this item to extract the contained key-value pair. | ||
/// | ||
/// Panics if this item is not the `KeyValue` variant. | ||
#[inline] | ||
#[track_caller] | ||
pub fn unwrap_key_value(self) -> (Ident, MetaExpr) { | ||
match self { | ||
Self::KeyValue(k, v) => (k, v), | ||
Self::Expr(_) => unreachable!("tried to unwrap expression as key-value"), | ||
} | ||
} | ||
} | ||
|
||
impl From<Ident> for MetaItem { | ||
fn from(value: Ident) -> Self { | ||
Self::Expr(MetaExpr::Ident(value)) | ||
} | ||
} | ||
|
||
impl From<&str> for MetaItem { | ||
fn from(value: &str) -> Self { | ||
Self::Expr(MetaExpr::String(Ident::new_unchecked(Span::new( | ||
SourceSpan::UNKNOWN, | ||
Arc::from(value), | ||
)))) | ||
} | ||
} | ||
|
||
impl From<String> for MetaItem { | ||
fn from(value: String) -> Self { | ||
Self::Expr(MetaExpr::String(Ident::new_unchecked(Span::new( | ||
SourceSpan::UNKNOWN, | ||
Arc::from(value.into_boxed_str()), | ||
)))) | ||
} | ||
} | ||
|
||
impl From<u8> for MetaItem { | ||
fn from(value: u8) -> Self { | ||
Self::Expr(MetaExpr::Int(Span::new(SourceSpan::UNKNOWN, HexEncodedValue::U8(value)))) | ||
} | ||
} | ||
|
||
impl From<u16> for MetaItem { | ||
fn from(value: u16) -> Self { | ||
Self::Expr(MetaExpr::Int(Span::new(SourceSpan::UNKNOWN, HexEncodedValue::U16(value)))) | ||
} | ||
} | ||
|
||
impl From<u32> for MetaItem { | ||
fn from(value: u32) -> Self { | ||
Self::Expr(MetaExpr::Int(Span::new(SourceSpan::UNKNOWN, HexEncodedValue::U32(value)))) | ||
} | ||
} | ||
|
||
impl From<Felt> for MetaItem { | ||
fn from(value: Felt) -> Self { | ||
Self::Expr(MetaExpr::Int(Span::new(SourceSpan::UNKNOWN, HexEncodedValue::Felt(value)))) | ||
} | ||
} | ||
|
||
impl From<[Felt; 4]> for MetaItem { | ||
fn from(value: [Felt; 4]) -> Self { | ||
Self::Expr(MetaExpr::Int(Span::new(SourceSpan::UNKNOWN, HexEncodedValue::Word(value)))) | ||
} | ||
} | ||
|
||
impl<V> From<(Ident, V)> for MetaItem | ||
where | ||
V: Into<MetaExpr>, | ||
{ | ||
fn from(entry: (Ident, V)) -> Self { | ||
let (key, value) = entry; | ||
Self::KeyValue(key, value.into()) | ||
} | ||
} | ||
|
||
impl<V> From<(&str, V)> for MetaItem | ||
where | ||
V: Into<MetaExpr>, | ||
{ | ||
fn from(entry: (&str, V)) -> Self { | ||
let (key, value) = entry; | ||
let key = Ident::new_unchecked(Span::new(SourceSpan::UNKNOWN, Arc::from(key))); | ||
Self::KeyValue(key, value.into()) | ||
} | ||
} | ||
|
||
impl<V> From<(String, V)> for MetaItem | ||
where | ||
V: Into<MetaExpr>, | ||
{ | ||
fn from(entry: (String, V)) -> Self { | ||
let (key, value) = entry; | ||
let key = | ||
Ident::new_unchecked(Span::new(SourceSpan::UNKNOWN, Arc::from(key.into_boxed_str()))); | ||
Self::KeyValue(key, value.into()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
use alloc::{string::String, sync::Arc}; | ||
|
||
use crate::{ast::Ident, parser::HexEncodedValue, prettier, Felt, SourceSpan, Span, Spanned}; | ||
|
||
/// Represents a metadata expression of an [crate::ast::Attribute] | ||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
pub enum MetaExpr { | ||
/// An identifier/keyword, e.g. `inline` | ||
Ident(Ident), | ||
/// A decimal or hexadecimal integer value | ||
Int(Span<HexEncodedValue>), | ||
/// A quoted string or identifier | ||
String(Ident), | ||
} | ||
|
||
impl prettier::PrettyPrint for MetaExpr { | ||
fn render(&self) -> prettier::Document { | ||
use prettier::*; | ||
|
||
match self { | ||
Self::Ident(id) => text(id), | ||
Self::Int(value) => text(value), | ||
Self::String(id) => text(format!("\"{}\"", id.as_str().escape_default())), | ||
} | ||
} | ||
} | ||
|
||
impl From<Ident> for MetaExpr { | ||
fn from(value: Ident) -> Self { | ||
Self::Ident(value) | ||
} | ||
} | ||
|
||
impl From<&str> for MetaExpr { | ||
fn from(value: &str) -> Self { | ||
Self::String(Ident::new_unchecked(Span::new(SourceSpan::UNKNOWN, Arc::from(value)))) | ||
} | ||
} | ||
|
||
impl From<String> for MetaExpr { | ||
fn from(value: String) -> Self { | ||
Self::String(Ident::new_unchecked(Span::new( | ||
SourceSpan::UNKNOWN, | ||
Arc::from(value.into_boxed_str()), | ||
))) | ||
} | ||
} | ||
|
||
impl From<u8> for MetaExpr { | ||
fn from(value: u8) -> Self { | ||
Self::Int(Span::new(SourceSpan::UNKNOWN, HexEncodedValue::U8(value))) | ||
} | ||
} | ||
|
||
impl From<u16> for MetaExpr { | ||
fn from(value: u16) -> Self { | ||
Self::Int(Span::new(SourceSpan::UNKNOWN, HexEncodedValue::U16(value))) | ||
} | ||
} | ||
|
||
impl From<u32> for MetaExpr { | ||
fn from(value: u32) -> Self { | ||
Self::Int(Span::new(SourceSpan::UNKNOWN, HexEncodedValue::U32(value))) | ||
} | ||
} | ||
|
||
impl From<Felt> for MetaExpr { | ||
fn from(value: Felt) -> Self { | ||
Self::Int(Span::new(SourceSpan::UNKNOWN, HexEncodedValue::Felt(value))) | ||
} | ||
} | ||
|
||
impl From<[Felt; 4]> for MetaExpr { | ||
fn from(value: [Felt; 4]) -> Self { | ||
Self::Int(Span::new(SourceSpan::UNKNOWN, HexEncodedValue::Word(value))) | ||
} | ||
} | ||
|
||
impl Spanned for MetaExpr { | ||
fn span(&self) -> SourceSpan { | ||
match self { | ||
Self::Ident(spanned) | Self::String(spanned) => spanned.span(), | ||
Self::Int(spanned) => spanned.span(), | ||
} | ||
} | ||
} |
Oops, something went wrong.