Compare commits
2 commits
5835b995a9
...
2c1afd1cd6
Author | SHA1 | Date | |
---|---|---|---|
Jacob Lifshay | 2c1afd1cd6 | ||
Jacob Lifshay | 76ea7f82c3 |
|
@ -5,14 +5,14 @@ use std::{collections::HashMap, fmt, mem};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
parse_quote, parse_quote_spanned,
|
parse_quote, parse_quote_spanned,
|
||||||
punctuated::Punctuated,
|
punctuated::{Pair, Punctuated},
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
token::{Brace, Bracket, Paren},
|
token::{Brace, Bracket, Paren},
|
||||||
AngleBracketedGenericArguments, Attribute, ConstParam, Expr, ExprIndex, ExprPath, ExprTuple,
|
AngleBracketedGenericArguments, Attribute, ConstParam, Expr, ExprIndex, ExprPath, ExprTuple,
|
||||||
Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, GenericArgument, GenericParam,
|
Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, GenericArgument, GenericParam,
|
||||||
Generics, Ident, ImplGenerics, Index, ItemStruct, Path, PathArguments, PathSegment,
|
Generics, Ident, ImplGenerics, Index, ItemStruct, Path, PathArguments, PathSegment,
|
||||||
PredicateType, Token, Turbofish, Type, TypeGenerics, TypeGroup, TypeParam, TypeParen, TypePath,
|
PredicateType, QSelf, Token, Turbofish, Type, TypeGenerics, TypeGroup, TypeParam, TypeParen,
|
||||||
TypeTuple, Visibility, WhereClause, WherePredicate,
|
TypePath, TypeTuple, Visibility, WhereClause, WherePredicate,
|
||||||
};
|
};
|
||||||
|
|
||||||
crate::options! {
|
crate::options! {
|
||||||
|
@ -239,7 +239,34 @@ impl ParseTypes<GenericArgument> for ParsedGenericArgument {
|
||||||
parser: &mut TypesParser<'_>,
|
parser: &mut TypesParser<'_>,
|
||||||
) -> Result<Self, ParseFailed> {
|
) -> Result<Self, ParseFailed> {
|
||||||
match arg {
|
match arg {
|
||||||
GenericArgument::Type(ty) => Ok(Self::Type(parser.parse(ty)?)),
|
GenericArgument::Type(ty) => {
|
||||||
|
{
|
||||||
|
let mut ty = &*ty;
|
||||||
|
while let Type::Group(TypeGroup { elem, .. }) = ty {
|
||||||
|
ty = &**elem;
|
||||||
|
}
|
||||||
|
if let Type::Path(TypePath { qself: None, path }) = ty {
|
||||||
|
if let Some(ident) = path.get_ident() {
|
||||||
|
if let Some(¶m_index) =
|
||||||
|
parser.generics.param_name_to_index_map.get(ident)
|
||||||
|
{
|
||||||
|
match parser.generics.params[param_index] {
|
||||||
|
ParsedGenericParam::Type(_)
|
||||||
|
| ParsedGenericParam::SizeType(_) => {}
|
||||||
|
ParsedGenericParam::Const(_) => {
|
||||||
|
return Ok(Self::Const(Expr::Path(ExprPath {
|
||||||
|
attrs: vec![],
|
||||||
|
qself: None,
|
||||||
|
path: path.clone(),
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Self::Type(parser.parse(ty)?))
|
||||||
|
}
|
||||||
GenericArgument::Const(expr) => Ok(Self::Const(expr.clone())),
|
GenericArgument::Const(expr) => Ok(Self::Const(expr.clone())),
|
||||||
_ => parse_failed!(parser, arg, "expected type or const generic argument"),
|
_ => parse_failed!(parser, arg, "expected type or const generic argument"),
|
||||||
}
|
}
|
||||||
|
@ -1205,6 +1232,12 @@ impl ParseTypes<Path> for ParsedType {
|
||||||
param_index,
|
param_index,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ParsedGenericParam::Const(ParsedConstParam { ref ident, .. }) => {
|
||||||
|
parser
|
||||||
|
.errors
|
||||||
|
.error(ident, "constant provided when a type was expected");
|
||||||
|
return Err(ParseFailed);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -1291,6 +1324,120 @@ impl ParseTypes<Type> for ParsedType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) enum ParsedConstGenericType {
|
||||||
|
Usize(known_items::usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_fold! {
|
||||||
|
enum ParsedConstGenericType<> {
|
||||||
|
Usize(known_items::usize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParsedConstGenericType> for Type {
|
||||||
|
fn from(value: ParsedConstGenericType) -> Self {
|
||||||
|
match value {
|
||||||
|
ParsedConstGenericType::Usize(v) => parse_quote! { #v },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MaybeParsed<ParsedConstGenericType, Type>> for Type {
|
||||||
|
fn from(value: MaybeParsed<ParsedConstGenericType, Type>) -> Self {
|
||||||
|
match value {
|
||||||
|
MaybeParsed::Unrecognized(value) => value,
|
||||||
|
MaybeParsed::Parsed(value) => value.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<ParsedConstGenericType>> for Type {
|
||||||
|
fn from(value: Box<ParsedConstGenericType>) -> Self {
|
||||||
|
(*value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ParsedConstGenericType {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
match self {
|
||||||
|
ParsedConstGenericType::Usize(ty) => ty.to_tokens(tokens),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParseTypes<Path> for ParsedConstGenericType {
|
||||||
|
fn parse_types(path: &mut Path, parser: &mut TypesParser<'_>) -> Result<Self, ParseFailed> {
|
||||||
|
let Path {
|
||||||
|
leading_colon,
|
||||||
|
ref mut segments,
|
||||||
|
} = *path;
|
||||||
|
if segments.is_empty() {
|
||||||
|
parse_failed!(parser, path, "path must not be empty");
|
||||||
|
}
|
||||||
|
let mut args = None;
|
||||||
|
let segments = Punctuated::from_iter(segments.pairs_mut().map_pair_value_mut(|segment| {
|
||||||
|
let PathSegment { ident, arguments } = segment;
|
||||||
|
if let Some(_) = args {
|
||||||
|
parser
|
||||||
|
.errors()
|
||||||
|
.error(&ident, "associated types/consts are not yet implemented");
|
||||||
|
}
|
||||||
|
args = match arguments {
|
||||||
|
PathArguments::None => None,
|
||||||
|
PathArguments::AngleBracketed(args) => parser.parse(args).ok(),
|
||||||
|
PathArguments::Parenthesized(_) => {
|
||||||
|
parser
|
||||||
|
.errors()
|
||||||
|
.error(&segment, "function traits are not allowed");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
PathSegment::from(segment.ident.clone())
|
||||||
|
}));
|
||||||
|
let named = ParsedTypeNamed {
|
||||||
|
path: Path {
|
||||||
|
leading_colon,
|
||||||
|
segments,
|
||||||
|
},
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
let named = match known_items::usize::try_from_named(named, parser)? {
|
||||||
|
Ok(v) => return Ok(Self::Usize(v)),
|
||||||
|
Err(named) => named,
|
||||||
|
};
|
||||||
|
parser.errors.error(
|
||||||
|
named,
|
||||||
|
"const parameter types other than `usize` are not yet implemented",
|
||||||
|
);
|
||||||
|
Err(ParseFailed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParseTypes<TypePath> for ParsedConstGenericType {
|
||||||
|
fn parse_types(ty: &mut TypePath, parser: &mut TypesParser<'_>) -> Result<Self, ParseFailed> {
|
||||||
|
let TypePath { qself, path } = ty;
|
||||||
|
if let Some(_qself) = qself {
|
||||||
|
parse_failed!(
|
||||||
|
parser,
|
||||||
|
ty,
|
||||||
|
"associated types/consts are not yet implemented"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
parser.parse(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParseTypes<Type> for ParsedConstGenericType {
|
||||||
|
fn parse_types(ty: &mut Type, parser: &mut TypesParser<'_>) -> Result<Self, ParseFailed> {
|
||||||
|
Ok(match ty {
|
||||||
|
Type::Path(ty) => parser.parse(ty)?,
|
||||||
|
_ => parse_failed!(parser, ty, "unsupported const generic type"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct ParseFailed;
|
pub(crate) struct ParseFailed;
|
||||||
|
|
||||||
impl fmt::Display for ParseFailed {
|
impl fmt::Display for ParseFailed {
|
||||||
|
@ -1376,6 +1523,16 @@ pub(crate) enum UnparsedGenericParam {
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
colon_token: Token![:],
|
colon_token: Token![:],
|
||||||
bounds: ParsedBounds,
|
bounds: ParsedBounds,
|
||||||
|
mask_type_bounds: ParsedTypeBounds,
|
||||||
|
},
|
||||||
|
Const {
|
||||||
|
attrs: Vec<Attribute>,
|
||||||
|
options: HdlAttr<ConstParamOptions>,
|
||||||
|
const_token: Token![const],
|
||||||
|
ident: Ident,
|
||||||
|
colon_token: Token![:],
|
||||||
|
ty: ParsedConstGenericType,
|
||||||
|
bounds: Option<ParsedConstParamWhereBounds>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1390,7 +1547,7 @@ pub(crate) mod known_items {
|
||||||
macro_rules! impl_known_item_body {
|
macro_rules! impl_known_item_body {
|
||||||
($known_item:ident) => {
|
($known_item:ident) => {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code, non_camel_case_types)]
|
||||||
pub(crate) struct $known_item {
|
pub(crate) struct $known_item {
|
||||||
pub(crate) path: Path,
|
pub(crate) path: Path,
|
||||||
pub(crate) span: Span,
|
pub(crate) span: Span,
|
||||||
|
@ -1439,6 +1596,20 @@ pub(crate) mod known_items {
|
||||||
Err(path)
|
Err(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn parse_path_with_arguments(mut path: Path) -> Result<(Self, PathArguments), Path> {
|
||||||
|
let Some(last_segment) = path.segments.last_mut() else {
|
||||||
|
return Err(path);
|
||||||
|
};
|
||||||
|
let arguments = std::mem::replace(&mut last_segment.arguments, PathArguments::None);
|
||||||
|
match Self::parse_path(path) {
|
||||||
|
Ok(retval) => Ok((retval, arguments)),
|
||||||
|
Err(mut path) => {
|
||||||
|
path.segments.last_mut().unwrap().arguments = arguments;
|
||||||
|
Err(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for $known_item {
|
impl Parse for $known_item {
|
||||||
|
@ -1508,7 +1679,9 @@ pub(crate) mod known_items {
|
||||||
impl_known_item!(::fayalite::ty::CanonicalType);
|
impl_known_item!(::fayalite::ty::CanonicalType);
|
||||||
impl_known_item!(::fayalite::ty::StaticType);
|
impl_known_item!(::fayalite::ty::StaticType);
|
||||||
impl_known_item!(::fayalite::ty::Type);
|
impl_known_item!(::fayalite::ty::Type);
|
||||||
|
impl_known_item!(::fayalite::ty::Type::MaskType);
|
||||||
impl_known_item!(::fayalite::util::ConstUsize);
|
impl_known_item!(::fayalite::util::ConstUsize);
|
||||||
|
impl_known_item!(::fayalite::__std::primitive::usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_bounds {
|
macro_rules! impl_bounds {
|
||||||
|
@ -1665,6 +1838,19 @@ macro_rules! impl_bounds {
|
||||||
Ok(retval)
|
Ok(retval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl $struct_type {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
$vis fn add_implied_bounds(&mut self) {
|
||||||
|
let orig_bounds = self.clone();
|
||||||
|
self.extend(
|
||||||
|
self.clone()
|
||||||
|
.into_iter()
|
||||||
|
.map($enum_type::implied_bounds),
|
||||||
|
);
|
||||||
|
self.extend([orig_bounds]); // keep spans of explicitly provided bounds
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1692,6 +1878,64 @@ impl_bounds! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ParsedTypeBound> for ParsedBound {
|
||||||
|
fn from(value: ParsedTypeBound) -> Self {
|
||||||
|
match value {
|
||||||
|
ParsedTypeBound::BundleType(v) => ParsedBound::BundleType(v),
|
||||||
|
ParsedTypeBound::EnumType(v) => ParsedBound::EnumType(v),
|
||||||
|
ParsedTypeBound::IntType(v) => ParsedBound::IntType(v),
|
||||||
|
ParsedTypeBound::StaticType(v) => ParsedBound::StaticType(v),
|
||||||
|
ParsedTypeBound::Type(v) => ParsedBound::Type(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParsedTypeBounds> for ParsedBounds {
|
||||||
|
fn from(value: ParsedTypeBounds) -> Self {
|
||||||
|
let ParsedTypeBounds {
|
||||||
|
BundleType,
|
||||||
|
EnumType,
|
||||||
|
IntType,
|
||||||
|
StaticType,
|
||||||
|
Type,
|
||||||
|
} = value;
|
||||||
|
Self {
|
||||||
|
BundleType,
|
||||||
|
EnumType,
|
||||||
|
IntType,
|
||||||
|
KnownSize: None,
|
||||||
|
Size: None,
|
||||||
|
StaticType,
|
||||||
|
Type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParsedTypeBound {
|
||||||
|
fn implied_bounds(self) -> ParsedTypeBounds {
|
||||||
|
let span = self.span();
|
||||||
|
match self {
|
||||||
|
Self::BundleType(v) => ParsedTypeBounds::from_iter([
|
||||||
|
ParsedTypeBound::from(v),
|
||||||
|
ParsedTypeBound::Type(known_items::Type(span)),
|
||||||
|
]),
|
||||||
|
Self::EnumType(v) => ParsedTypeBounds::from_iter([
|
||||||
|
ParsedTypeBound::from(v),
|
||||||
|
ParsedTypeBound::Type(known_items::Type(span)),
|
||||||
|
]),
|
||||||
|
Self::IntType(v) => ParsedTypeBounds::from_iter([
|
||||||
|
ParsedTypeBound::from(v),
|
||||||
|
ParsedTypeBound::Type(known_items::Type(span)),
|
||||||
|
]),
|
||||||
|
Self::StaticType(v) => ParsedTypeBounds::from_iter([
|
||||||
|
ParsedTypeBound::from(v),
|
||||||
|
ParsedTypeBound::Type(known_items::Type(span)),
|
||||||
|
]),
|
||||||
|
Self::Type(v) => ParsedTypeBounds::from_iter([ParsedTypeBound::from(v)]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl_bounds! {
|
impl_bounds! {
|
||||||
#[struct = ParsedSizeTypeBounds]
|
#[struct = ParsedSizeTypeBounds]
|
||||||
pub(crate) enum ParsedSizeTypeBound {
|
pub(crate) enum ParsedSizeTypeBound {
|
||||||
|
@ -1700,6 +1944,43 @@ impl_bounds! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ParsedSizeTypeBound> for ParsedBound {
|
||||||
|
fn from(value: ParsedSizeTypeBound) -> Self {
|
||||||
|
match value {
|
||||||
|
ParsedSizeTypeBound::KnownSize(v) => ParsedBound::KnownSize(v),
|
||||||
|
ParsedSizeTypeBound::Size(v) => ParsedBound::Size(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParsedSizeTypeBounds> for ParsedBounds {
|
||||||
|
fn from(value: ParsedSizeTypeBounds) -> Self {
|
||||||
|
let ParsedSizeTypeBounds { KnownSize, Size } = value;
|
||||||
|
Self {
|
||||||
|
BundleType: None,
|
||||||
|
EnumType: None,
|
||||||
|
IntType: None,
|
||||||
|
KnownSize,
|
||||||
|
Size,
|
||||||
|
StaticType: None,
|
||||||
|
Type: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParsedSizeTypeBound {
|
||||||
|
fn implied_bounds(self) -> ParsedSizeTypeBounds {
|
||||||
|
let span = self.span();
|
||||||
|
match self {
|
||||||
|
Self::KnownSize(v) => ParsedSizeTypeBounds::from_iter([
|
||||||
|
ParsedSizeTypeBound::from(v),
|
||||||
|
ParsedSizeTypeBound::Size(known_items::Size(span)),
|
||||||
|
]),
|
||||||
|
Self::Size(v) => ParsedSizeTypeBounds::from_iter([ParsedSizeTypeBound::from(v)]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) enum ParsedBoundsCategory {
|
pub(crate) enum ParsedBoundsCategory {
|
||||||
Type(ParsedTypeBounds),
|
Type(ParsedTypeBounds),
|
||||||
|
@ -1761,42 +2042,13 @@ impl ParsedBound {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn implied_bounds(self) -> ParsedBounds {
|
fn implied_bounds(self) -> ParsedBounds {
|
||||||
let span = self.span();
|
match self.categorize() {
|
||||||
match self {
|
ParsedBoundCategory::Type(v) => v.implied_bounds().into(),
|
||||||
Self::BundleType(v) => ParsedBounds::from_iter([
|
ParsedBoundCategory::SizeType(v) => v.implied_bounds().into(),
|
||||||
ParsedBound::from(v),
|
|
||||||
ParsedBound::Type(known_items::Type(span)),
|
|
||||||
]),
|
|
||||||
Self::EnumType(v) => ParsedBounds::from_iter([
|
|
||||||
ParsedBound::from(v),
|
|
||||||
ParsedBound::Type(known_items::Type(span)),
|
|
||||||
]),
|
|
||||||
Self::IntType(v) => ParsedBounds::from_iter([
|
|
||||||
ParsedBound::from(v),
|
|
||||||
ParsedBound::Type(known_items::Type(span)),
|
|
||||||
]),
|
|
||||||
Self::KnownSize(v) => ParsedBounds::from_iter([
|
|
||||||
ParsedBound::from(v),
|
|
||||||
ParsedBound::Size(known_items::Size(span)),
|
|
||||||
]),
|
|
||||||
Self::Size(v) => ParsedBounds::from_iter([ParsedBound::from(v)]),
|
|
||||||
Self::StaticType(v) => ParsedBounds::from_iter([
|
|
||||||
ParsedBound::from(v),
|
|
||||||
ParsedBound::Type(known_items::Type(span)),
|
|
||||||
]),
|
|
||||||
Self::Type(v) => ParsedBounds::from_iter([ParsedBound::from(v)]),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParsedBounds {
|
|
||||||
fn add_implied_bounds(&mut self) {
|
|
||||||
let orig_bounds = self.clone();
|
|
||||||
self.extend(self.clone().into_iter().map(ParsedBound::implied_bounds));
|
|
||||||
self.extend([orig_bounds]); // keep spans of explicitly provided bounds
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct ParsedTypeParam {
|
pub(crate) struct ParsedTypeParam {
|
||||||
pub(crate) attrs: Vec<Attribute>,
|
pub(crate) attrs: Vec<Attribute>,
|
||||||
|
@ -1865,10 +2117,54 @@ impl ToTokens for ParsedSizeTypeParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct ParsedConstParamWhereBounds {
|
||||||
|
pub(crate) const_usize: known_items::ConstUsize,
|
||||||
|
pub(crate) lt_token: Token![<],
|
||||||
|
pub(crate) ident: Ident,
|
||||||
|
pub(crate) gt_token: Token![>],
|
||||||
|
pub(crate) colon_token: Token![:],
|
||||||
|
pub(crate) bounds: ParsedSizeTypeBounds,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct ParsedConstParam {
|
||||||
|
pub(crate) attrs: Vec<Attribute>,
|
||||||
|
pub(crate) options: HdlAttr<ConstParamOptions>,
|
||||||
|
pub(crate) const_token: Token![const],
|
||||||
|
pub(crate) ident: Ident,
|
||||||
|
pub(crate) colon_token: Token![:],
|
||||||
|
pub(crate) ty: ParsedConstGenericType,
|
||||||
|
pub(crate) bounds: ParsedConstParamWhereBounds,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ParsedConstParam {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let Self {
|
||||||
|
attrs,
|
||||||
|
options,
|
||||||
|
const_token,
|
||||||
|
ident,
|
||||||
|
colon_token,
|
||||||
|
ty,
|
||||||
|
bounds: _,
|
||||||
|
} = self;
|
||||||
|
let ConstParamOptions {} = options.body;
|
||||||
|
for attr in attrs {
|
||||||
|
attr.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
const_token.to_tokens(tokens);
|
||||||
|
ident.to_tokens(tokens);
|
||||||
|
colon_token.to_tokens(tokens);
|
||||||
|
ty.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) enum ParsedGenericParam {
|
pub(crate) enum ParsedGenericParam {
|
||||||
Type(ParsedTypeParam),
|
Type(ParsedTypeParam),
|
||||||
SizeType(ParsedSizeTypeParam),
|
SizeType(ParsedSizeTypeParam),
|
||||||
|
Const(ParsedConstParam),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokens for ParsedGenericParam {
|
impl ToTokens for ParsedGenericParam {
|
||||||
|
@ -1876,6 +2172,7 @@ impl ToTokens for ParsedGenericParam {
|
||||||
match self {
|
match self {
|
||||||
ParsedGenericParam::Type(v) => v.to_tokens(tokens),
|
ParsedGenericParam::Type(v) => v.to_tokens(tokens),
|
||||||
ParsedGenericParam::SizeType(v) => v.to_tokens(tokens),
|
ParsedGenericParam::SizeType(v) => v.to_tokens(tokens),
|
||||||
|
ParsedGenericParam::Const(v) => v.to_tokens(tokens),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1885,6 +2182,7 @@ impl ParsedGenericParam {
|
||||||
match self {
|
match self {
|
||||||
ParsedGenericParam::Type(v) => &v.ident,
|
ParsedGenericParam::Type(v) => &v.ident,
|
||||||
ParsedGenericParam::SizeType(v) => &v.ident,
|
ParsedGenericParam::SizeType(v) => &v.ident,
|
||||||
|
ParsedGenericParam::Const(v) => &v.ident,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1911,6 +2209,12 @@ impl ParsedGenerics {
|
||||||
.KnownSize
|
.KnownSize
|
||||||
.get_or_insert_with(|| known_items::KnownSize(ident.span()));
|
.get_or_insert_with(|| known_items::KnownSize(ident.span()));
|
||||||
}
|
}
|
||||||
|
ParsedGenericParam::Const(ParsedConstParam { ident, bounds, .. }) => {
|
||||||
|
bounds
|
||||||
|
.bounds
|
||||||
|
.KnownSize
|
||||||
|
.get_or_insert_with(|| known_items::KnownSize(ident.span()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
|
@ -1982,6 +2286,13 @@ impl ParsedGenerics {
|
||||||
<#ident as ::fayalite::int::Size>::SizeType
|
<#ident as ::fayalite::int::Size>::SizeType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ParsedGenericParam::Const(param) => {
|
||||||
|
let ident = ¶m.ident;
|
||||||
|
parse_quote_spanned! {span=>
|
||||||
|
<::fayalite::util::ConstUsize<#ident>
|
||||||
|
as ::fayalite::int::Size>::SizeType
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
|
@ -2254,28 +2565,35 @@ impl ParsedGenerics {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ParsedGenericParam::Const(_) => todo!(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(crate) fn parse(generics: &mut Generics) -> syn::Result<Self> {
|
pub(crate) fn parse<'a>(generics: &'a mut Generics) -> syn::Result<Self> {
|
||||||
let Generics {
|
let Generics {
|
||||||
lt_token,
|
lt_token,
|
||||||
params,
|
params: input_params,
|
||||||
gt_token,
|
gt_token,
|
||||||
where_clause,
|
where_clause,
|
||||||
} = generics;
|
} = generics;
|
||||||
let mut errors = Errors::new();
|
let mut errors = Errors::new();
|
||||||
let mut predicates: Vec<WherePredicate> = Vec::with_capacity(params.len());
|
let mut predicates: Vec<WherePredicate> = Vec::with_capacity(input_params.len());
|
||||||
let mut defaults = Vec::with_capacity(params.len());
|
struct LateParsedParam<'a> {
|
||||||
let mut params = Punctuated::<UnparsedGenericParam, _>::from_iter(
|
default: Option<(Token![=], &'a mut Type)>,
|
||||||
params.pairs_mut().filter_map_pair_value_mut(|param| {
|
const_param_type: Option<&'a mut Type>,
|
||||||
let (param, default) = match param {
|
}
|
||||||
|
let mut late_parsed_params: Vec<LateParsedParam<'a>> =
|
||||||
|
Vec::with_capacity(input_params.len());
|
||||||
|
let mut unparsed_params: Punctuated<UnparsedGenericParam, _> = Punctuated::new();
|
||||||
|
for input_param in input_params.pairs_mut() {
|
||||||
|
let (input_param, punct) = input_param.into_tuple();
|
||||||
|
let (unparsed_param, late_parsed_param) = match input_param {
|
||||||
GenericParam::Lifetime(param) => {
|
GenericParam::Lifetime(param) => {
|
||||||
errors.unwrap_or_default(
|
errors.unwrap_or_default(HdlAttr::<LifetimeParamOptions>::parse_and_take_attr(
|
||||||
HdlAttr::<LifetimeParamOptions>::parse_and_take_attr(&mut param.attrs),
|
&mut param.attrs,
|
||||||
);
|
));
|
||||||
errors.error(param, "lifetime generics are not supported by #[hdl]");
|
errors.error(param, "lifetime generics are not supported by #[hdl]");
|
||||||
return None;
|
continue;
|
||||||
}
|
}
|
||||||
GenericParam::Type(TypeParam {
|
GenericParam::Type(TypeParam {
|
||||||
attrs,
|
attrs,
|
||||||
|
@ -2287,9 +2605,7 @@ impl ParsedGenerics {
|
||||||
}) => {
|
}) => {
|
||||||
let span = ident.span();
|
let span = ident.span();
|
||||||
let options = errors
|
let options = errors
|
||||||
.unwrap_or_default(HdlAttr::<TypeParamOptions>::parse_and_take_attr(
|
.unwrap_or_default(HdlAttr::<TypeParamOptions>::parse_and_take_attr(attrs))
|
||||||
attrs,
|
|
||||||
))
|
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let colon_token = colon_token.unwrap_or_else(|| Token![:](span));
|
let colon_token = colon_token.unwrap_or_else(|| Token![:](span));
|
||||||
if !bounds.is_empty() {
|
if !bounds.is_empty() {
|
||||||
|
@ -2307,10 +2623,14 @@ impl ParsedGenerics {
|
||||||
ident: ident.clone(),
|
ident: ident.clone(),
|
||||||
colon_token,
|
colon_token,
|
||||||
bounds: ParsedBounds::default(),
|
bounds: ParsedBounds::default(),
|
||||||
|
mask_type_bounds: ParsedTypeBounds::default(),
|
||||||
},
|
},
|
||||||
default
|
LateParsedParam {
|
||||||
.clone()
|
default: default
|
||||||
|
.as_mut()
|
||||||
.map(|v| (eq_token.unwrap_or_else(|| Token![=](span)), v)),
|
.map(|v| (eq_token.unwrap_or_else(|| Token![=](span)), v)),
|
||||||
|
const_param_type: None,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
GenericParam::Const(ConstParam {
|
GenericParam::Const(ConstParam {
|
||||||
|
@ -2323,29 +2643,41 @@ impl ParsedGenerics {
|
||||||
default,
|
default,
|
||||||
}) => {
|
}) => {
|
||||||
let options = errors
|
let options = errors
|
||||||
.unwrap_or_default(HdlAttr::<ConstParamOptions>::parse_and_take_attr(
|
.unwrap_or_default(HdlAttr::<ConstParamOptions>::parse_and_take_attr(attrs))
|
||||||
attrs,
|
|
||||||
))
|
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let _ = const_token;
|
if let Some(default) = default {
|
||||||
let _ = ident;
|
|
||||||
let _ = colon_token;
|
|
||||||
let _ = ty;
|
|
||||||
let _ = eq_token;
|
let _ = eq_token;
|
||||||
let _ = default;
|
errors.error(
|
||||||
let _ = options;
|
default,
|
||||||
todo!()
|
"const generics' default values are not yet implemented",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(
|
||||||
|
UnparsedGenericParam::Const {
|
||||||
|
attrs: attrs.clone(),
|
||||||
|
options,
|
||||||
|
const_token: *const_token,
|
||||||
|
ident: ident.clone(),
|
||||||
|
colon_token: *colon_token,
|
||||||
|
ty: ParsedConstGenericType::Usize(known_items::usize(ident.span())),
|
||||||
|
bounds: None,
|
||||||
|
},
|
||||||
|
LateParsedParam {
|
||||||
|
default: None,
|
||||||
|
const_param_type: Some(ty),
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
defaults.push(default);
|
late_parsed_params.push(late_parsed_param);
|
||||||
Some(param)
|
unparsed_params.extend([Pair::new(unparsed_param, punct.cloned())]);
|
||||||
}),
|
}
|
||||||
);
|
let param_name_to_index_map: HashMap<Ident, usize> = unparsed_params
|
||||||
let param_name_to_index_map: HashMap<Ident, usize> = params
|
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, param)| {
|
.map(|(index, param)| {
|
||||||
let UnparsedGenericParam::Type { ident, .. } = param;
|
let (UnparsedGenericParam::Type { ident, .. }
|
||||||
|
| UnparsedGenericParam::Const { ident, .. }) = param;
|
||||||
(ident.clone(), index)
|
(ident.clone(), index)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -2357,43 +2689,193 @@ impl ParsedGenerics {
|
||||||
lifetimes: None,
|
lifetimes: None,
|
||||||
bounded_ty:
|
bounded_ty:
|
||||||
Type::Path(TypePath {
|
Type::Path(TypePath {
|
||||||
qself: None,
|
qself,
|
||||||
path: bounded_ty,
|
path: bounded_ty,
|
||||||
}),
|
}),
|
||||||
colon_token: _,
|
colon_token,
|
||||||
bounds: unparsed_bounds,
|
bounds: unparsed_bounds,
|
||||||
}) = predicate
|
}) = predicate
|
||||||
else {
|
else {
|
||||||
errors.error(predicate, "unsupported where predicate kind");
|
errors.error(predicate, "unsupported where predicate kind");
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
if let Some(qself) = &qself {
|
||||||
|
if let QSelf {
|
||||||
|
lt_token: _,
|
||||||
|
ty: base_ty,
|
||||||
|
position: 3,
|
||||||
|
as_token: Some(_),
|
||||||
|
gt_token: _,
|
||||||
|
} = qself
|
||||||
|
{
|
||||||
|
if bounded_ty.segments.len() == 4 && unparsed_bounds.len() == 1 {
|
||||||
|
if let (
|
||||||
|
Ok(_),
|
||||||
|
Type::Path(TypePath {
|
||||||
|
qself: None,
|
||||||
|
path: base_ty,
|
||||||
|
}),
|
||||||
|
) = (
|
||||||
|
known_items::MaskType::parse_path(bounded_ty.clone()),
|
||||||
|
&**base_ty,
|
||||||
|
) {
|
||||||
|
let Some(&index) = base_ty
|
||||||
|
.get_ident()
|
||||||
|
.and_then(|base_ty| param_name_to_index_map.get(base_ty))
|
||||||
|
else {
|
||||||
|
errors.error(
|
||||||
|
TypePath {
|
||||||
|
qself: Some(qself.clone()),
|
||||||
|
path: bounded_ty,
|
||||||
|
},
|
||||||
|
"unsupported where predicate kind",
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let parsed_bounds = match &mut unparsed_params[index] {
|
||||||
|
UnparsedGenericParam::Type {
|
||||||
|
mask_type_bounds, ..
|
||||||
|
} => mask_type_bounds,
|
||||||
|
UnparsedGenericParam::Const { ident, .. } => {
|
||||||
|
errors.error(
|
||||||
|
bounded_ty,
|
||||||
|
format_args!(
|
||||||
|
"expected type, found const parameter `{ident}`"
|
||||||
|
),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
parsed_bounds.extend(errors.ok(syn::parse2::<ParsedTypeBounds>(
|
||||||
|
unparsed_bounds.to_token_stream(),
|
||||||
|
)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errors.error(
|
||||||
|
TypePath {
|
||||||
|
qself: Some(qself.clone()),
|
||||||
|
path: bounded_ty,
|
||||||
|
},
|
||||||
|
"unsupported where predicate kind",
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Ok((
|
||||||
|
const_usize,
|
||||||
|
PathArguments::AngleBracketed(AngleBracketedGenericArguments {
|
||||||
|
colon2_token: _,
|
||||||
|
lt_token,
|
||||||
|
args,
|
||||||
|
gt_token,
|
||||||
|
}),
|
||||||
|
)) = known_items::ConstUsize::parse_path_with_arguments(bounded_ty.clone())
|
||||||
|
{
|
||||||
|
if args.len() != 1 {
|
||||||
|
errors.error(const_usize, "ConstUsize must have one argument");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let GenericArgument::Type(Type::Path(TypePath {
|
||||||
|
qself: None,
|
||||||
|
path: arg,
|
||||||
|
})) = &args[0]
|
||||||
|
else {
|
||||||
|
errors.error(
|
||||||
|
const_usize,
|
||||||
|
"the only supported ConstUsize argument is a const generic parameter",
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let arg = arg.get_ident();
|
||||||
|
let Some((arg, &index)) =
|
||||||
|
arg.and_then(|arg| Some((arg, param_name_to_index_map.get(arg)?)))
|
||||||
|
else {
|
||||||
|
errors.error(
|
||||||
|
const_usize,
|
||||||
|
"the only supported ConstUsize argument is a const generic parameter",
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let parsed_bounds = match &mut unparsed_params[index] {
|
||||||
|
UnparsedGenericParam::Const { bounds, .. } => bounds,
|
||||||
|
UnparsedGenericParam::Type { ident, .. } => {
|
||||||
|
errors.error(
|
||||||
|
bounded_ty,
|
||||||
|
format_args!("expected const generic parameter, found type `{ident}`"),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
parsed_bounds
|
||||||
|
.get_or_insert_with(|| ParsedConstParamWhereBounds {
|
||||||
|
const_usize,
|
||||||
|
lt_token,
|
||||||
|
ident: arg.clone(),
|
||||||
|
gt_token,
|
||||||
|
colon_token,
|
||||||
|
bounds: ParsedSizeTypeBounds::default(),
|
||||||
|
})
|
||||||
|
.bounds
|
||||||
|
.extend(errors.ok(syn::parse2::<ParsedSizeTypeBounds>(
|
||||||
|
unparsed_bounds.to_token_stream(),
|
||||||
|
)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let Some(&index) = bounded_ty
|
let Some(&index) = bounded_ty
|
||||||
.get_ident()
|
.get_ident()
|
||||||
.and_then(|bounded_ty| param_name_to_index_map.get(bounded_ty))
|
.and_then(|bounded_ty| param_name_to_index_map.get(bounded_ty))
|
||||||
else {
|
else {
|
||||||
errors.error(
|
errors.error(
|
||||||
bounded_ty,
|
bounded_ty,
|
||||||
"where predicate bounded type must be one of the generic parameters",
|
"where predicate bounded type must be one of the generic type \
|
||||||
|
parameters or `ConstUsize<A_CONST_PARAM>`",
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let UnparsedGenericParam::Type {
|
let parsed_bounds = match &mut unparsed_params[index] {
|
||||||
bounds: parsed_bounds,
|
UnparsedGenericParam::Type { bounds, .. } => bounds,
|
||||||
..
|
UnparsedGenericParam::Const { ident, .. } => {
|
||||||
} = &mut params[index];
|
errors.error(
|
||||||
|
bounded_ty,
|
||||||
|
format_args!("expected type, found const parameter `{ident}`"),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
parsed_bounds.extend(errors.ok(syn::parse2::<ParsedBounds>(
|
parsed_bounds.extend(errors.ok(syn::parse2::<ParsedBounds>(
|
||||||
unparsed_bounds.to_token_stream(),
|
unparsed_bounds.to_token_stream(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let params =
|
let params =
|
||||||
Punctuated::from_iter(params.into_pairs().map_pair_value(|param| match param {
|
Punctuated::from_iter(unparsed_params.into_pairs().map_pair_value(
|
||||||
|
|param| match param {
|
||||||
UnparsedGenericParam::Type {
|
UnparsedGenericParam::Type {
|
||||||
attrs,
|
attrs,
|
||||||
options,
|
options,
|
||||||
ident,
|
ident,
|
||||||
colon_token,
|
colon_token,
|
||||||
mut bounds,
|
mut bounds,
|
||||||
|
mask_type_bounds,
|
||||||
} => {
|
} => {
|
||||||
|
for bound in mask_type_bounds {
|
||||||
|
bounds
|
||||||
|
.Type
|
||||||
|
.get_or_insert_with(|| known_items::Type(bound.span()));
|
||||||
|
match bound {
|
||||||
|
ParsedTypeBound::BundleType(_)
|
||||||
|
| ParsedTypeBound::EnumType(_)
|
||||||
|
| ParsedTypeBound::IntType(_) => {
|
||||||
|
errors.error(bound, "bound on mask type not implemented");
|
||||||
|
}
|
||||||
|
ParsedTypeBound::StaticType(bound) => {
|
||||||
|
if bounds.StaticType.is_none() {
|
||||||
|
errors.error(bound, "StaticType bound on mask type without corresponding StaticType bound on original type is not implemented");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ParsedTypeBound::Type(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
bounds.add_implied_bounds();
|
bounds.add_implied_bounds();
|
||||||
match bounds.categorize(&mut errors, ident.span()) {
|
match bounds.categorize(&mut errors, ident.span()) {
|
||||||
ParsedBoundsCategory::Type(bounds) => {
|
ParsedBoundsCategory::Type(bounds) => {
|
||||||
|
@ -2418,29 +2900,85 @@ impl ParsedGenerics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
UnparsedGenericParam::Const {
|
||||||
|
attrs,
|
||||||
|
options,
|
||||||
|
const_token,
|
||||||
|
ident,
|
||||||
|
colon_token,
|
||||||
|
ty,
|
||||||
|
bounds,
|
||||||
|
} => {
|
||||||
|
let span = ident.span();
|
||||||
|
let mut bounds = bounds.unwrap_or_else(|| ParsedConstParamWhereBounds {
|
||||||
|
const_usize: known_items::ConstUsize(span),
|
||||||
|
lt_token: Token![<](span),
|
||||||
|
ident: ident.clone(),
|
||||||
|
gt_token: Token![>](span),
|
||||||
|
colon_token: Token![:](span),
|
||||||
|
bounds: ParsedSizeTypeBounds {
|
||||||
|
KnownSize: None,
|
||||||
|
Size: Some(known_items::Size(span)),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
bounds
|
||||||
|
.bounds
|
||||||
|
.Size
|
||||||
|
.get_or_insert_with(|| known_items::Size(span));
|
||||||
|
bounds.bounds.add_implied_bounds();
|
||||||
|
ParsedGenericParam::Const(ParsedConstParam {
|
||||||
|
bounds,
|
||||||
|
attrs,
|
||||||
|
options,
|
||||||
|
const_token,
|
||||||
|
ident,
|
||||||
|
colon_token,
|
||||||
|
ty,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
));
|
||||||
let mut retval = Self {
|
let mut retval = Self {
|
||||||
lt_token: *lt_token,
|
lt_token: *lt_token,
|
||||||
params,
|
params,
|
||||||
gt_token: *gt_token,
|
gt_token: *gt_token,
|
||||||
param_name_to_index_map,
|
param_name_to_index_map,
|
||||||
};
|
};
|
||||||
for (cur_param_index, default) in defaults.into_iter().enumerate() {
|
for (
|
||||||
let Some((eq, mut ty)) = default else {
|
cur_param_index,
|
||||||
continue;
|
LateParsedParam {
|
||||||
};
|
default,
|
||||||
let Ok(ty) = TypesParser {
|
const_param_type,
|
||||||
|
},
|
||||||
|
) in late_parsed_params.into_iter().enumerate()
|
||||||
|
{
|
||||||
|
let mut parser = TypesParser {
|
||||||
generics: &retval,
|
generics: &retval,
|
||||||
cur_param_index: Some(cur_param_index),
|
cur_param_index: Some(cur_param_index),
|
||||||
errors: &mut errors,
|
errors: &mut errors,
|
||||||
}
|
|
||||||
.parse(&mut ty) else {
|
|
||||||
continue;
|
|
||||||
};
|
};
|
||||||
|
let parsed_default = default.and_then(|(eq, ty)| {
|
||||||
|
let ty = parser.parse(ty).ok()?;
|
||||||
|
Some((eq, ty))
|
||||||
|
});
|
||||||
|
let parsed_const_param_type = const_param_type.and_then(|ty| parser.parse(ty).ok());
|
||||||
match &mut retval.params[cur_param_index] {
|
match &mut retval.params[cur_param_index] {
|
||||||
ParsedGenericParam::Type(ParsedTypeParam { default, .. })
|
ParsedGenericParam::Type(ParsedTypeParam { default, .. })
|
||||||
| ParsedGenericParam::SizeType(ParsedSizeTypeParam { default, .. }) => {
|
| ParsedGenericParam::SizeType(ParsedSizeTypeParam { default, .. }) => {
|
||||||
*default = Some((eq, ty))
|
*default = parsed_default;
|
||||||
|
}
|
||||||
|
ParsedGenericParam::Const(ParsedConstParam {
|
||||||
|
attrs: _,
|
||||||
|
options: _,
|
||||||
|
const_token: _,
|
||||||
|
ident: _,
|
||||||
|
colon_token: _,
|
||||||
|
ty,
|
||||||
|
bounds: _,
|
||||||
|
}) => {
|
||||||
|
if let Some(parsed_const_param_type) = parsed_const_param_type {
|
||||||
|
*ty = parsed_const_param_type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2517,6 +3055,21 @@ impl ToTokens for ParsedGenericsImplGenerics<'_> {
|
||||||
colon_token.to_tokens(tokens);
|
colon_token.to_tokens(tokens);
|
||||||
bounds.to_tokens(tokens);
|
bounds.to_tokens(tokens);
|
||||||
}
|
}
|
||||||
|
ParsedGenericParam::Const(ParsedConstParam {
|
||||||
|
attrs: _,
|
||||||
|
options,
|
||||||
|
const_token,
|
||||||
|
ident,
|
||||||
|
colon_token,
|
||||||
|
ty,
|
||||||
|
bounds: _,
|
||||||
|
}) => {
|
||||||
|
let ConstParamOptions {} = options.body;
|
||||||
|
const_token.to_tokens(tokens);
|
||||||
|
ident.to_tokens(tokens);
|
||||||
|
colon_token.to_tokens(tokens);
|
||||||
|
ty.to_tokens(tokens);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
punct.to_tokens(tokens);
|
punct.to_tokens(tokens);
|
||||||
}
|
}
|
||||||
|
@ -2609,6 +3162,27 @@ impl ToTokens for ParsedGenericsWhereClause<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParsedGenericParam::SizeType(_) => {}
|
ParsedGenericParam::SizeType(_) => {}
|
||||||
|
ParsedGenericParam::Const(ParsedConstParam {
|
||||||
|
ident: _,
|
||||||
|
bounds:
|
||||||
|
ParsedConstParamWhereBounds {
|
||||||
|
const_usize,
|
||||||
|
lt_token,
|
||||||
|
ident,
|
||||||
|
gt_token,
|
||||||
|
colon_token,
|
||||||
|
bounds,
|
||||||
|
},
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
where_token(ident.span()).to_tokens(tokens);
|
||||||
|
const_usize.to_tokens(tokens);
|
||||||
|
lt_token.to_tokens(tokens);
|
||||||
|
ident.to_tokens(tokens);
|
||||||
|
gt_token.to_tokens(tokens);
|
||||||
|
colon_token.to_tokens(tokens);
|
||||||
|
bounds.to_tokens(tokens);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,8 +66,8 @@ pub(crate) struct ModuleFn {
|
||||||
vis: Visibility,
|
vis: Visibility,
|
||||||
sig: Signature,
|
sig: Signature,
|
||||||
block: Box<Block>,
|
block: Box<Block>,
|
||||||
io: Vec<ModuleIO>,
|
|
||||||
struct_generics: ParsedGenerics,
|
struct_generics: ParsedGenerics,
|
||||||
|
the_struct: TokenStream,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
|
@ -224,6 +224,41 @@ impl Parse for ModuleFn {
|
||||||
errors.finish()?;
|
errors.finish()?;
|
||||||
let struct_generics = struct_generics.unwrap();
|
let struct_generics = struct_generics.unwrap();
|
||||||
let (block, io) = body_results.unwrap();
|
let (block, io) = body_results.unwrap();
|
||||||
|
let (_struct_impl_generics, _struct_type_generics, struct_where_clause) =
|
||||||
|
struct_generics.split_for_impl();
|
||||||
|
let struct_where_clause: Option<WhereClause> = parse_quote! { #struct_where_clause };
|
||||||
|
if let Some(struct_where_clause) = &struct_where_clause {
|
||||||
|
sig.generics
|
||||||
|
.where_clause
|
||||||
|
.get_or_insert_with(|| WhereClause {
|
||||||
|
where_token: struct_where_clause.where_token,
|
||||||
|
predicates: Default::default(),
|
||||||
|
})
|
||||||
|
.predicates
|
||||||
|
.extend(struct_where_clause.predicates.clone());
|
||||||
|
}
|
||||||
|
let fn_name = &sig.ident;
|
||||||
|
let io_flips = io
|
||||||
|
.iter()
|
||||||
|
.map(|io| match io.kind.kind {
|
||||||
|
ModuleIOKind::Input((input,)) => quote_spanned! {input.span=>
|
||||||
|
#[hdl(flip)]
|
||||||
|
},
|
||||||
|
ModuleIOKind::Output(_) => quote! {},
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let io_types = io.iter().map(|io| &io.kind.ty).collect::<Vec<_>>();
|
||||||
|
let io_names = io.iter().map(|io| &io.name).collect::<Vec<_>>();
|
||||||
|
let the_struct: ItemStruct = parse_quote! {
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[hdl(no_runtime_generics, no_static)]
|
||||||
|
#vis struct #fn_name #struct_generics #struct_where_clause {
|
||||||
|
#(
|
||||||
|
#io_flips
|
||||||
|
#vis #io_names: #io_types,)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let the_struct = crate::hdl_bundle::hdl_bundle(the_struct)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
attrs,
|
attrs,
|
||||||
config_options,
|
config_options,
|
||||||
|
@ -231,8 +266,8 @@ impl Parse for ModuleFn {
|
||||||
vis,
|
vis,
|
||||||
sig,
|
sig,
|
||||||
block,
|
block,
|
||||||
io,
|
|
||||||
struct_generics,
|
struct_generics,
|
||||||
|
the_struct,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,8 +281,8 @@ impl ModuleFn {
|
||||||
vis,
|
vis,
|
||||||
sig,
|
sig,
|
||||||
block,
|
block,
|
||||||
io,
|
|
||||||
struct_generics,
|
struct_generics,
|
||||||
|
the_struct,
|
||||||
} = self;
|
} = self;
|
||||||
let ConfigOptions {
|
let ConfigOptions {
|
||||||
outline_generated: _,
|
outline_generated: _,
|
||||||
|
@ -279,7 +314,7 @@ impl ModuleFn {
|
||||||
ModuleKind::Normal => quote! { ::fayalite::module::ModuleKind::Normal },
|
ModuleKind::Normal => quote! { ::fayalite::module::ModuleKind::Normal },
|
||||||
};
|
};
|
||||||
let fn_name = &outer_sig.ident;
|
let fn_name = &outer_sig.ident;
|
||||||
let (_struct_impl_generics, struct_type_generics, struct_where_clause) =
|
let (_struct_impl_generics, struct_type_generics, _struct_where_clause) =
|
||||||
struct_generics.split_for_impl();
|
struct_generics.split_for_impl();
|
||||||
let struct_ty = quote! {#fn_name #struct_type_generics};
|
let struct_ty = quote! {#fn_name #struct_type_generics};
|
||||||
body_sig.ident = parse_quote! {__body};
|
body_sig.ident = parse_quote! {__body};
|
||||||
|
@ -294,17 +329,6 @@ impl ModuleFn {
|
||||||
};
|
};
|
||||||
outer_sig.output =
|
outer_sig.output =
|
||||||
parse_quote! {-> ::fayalite::intern::Interned<::fayalite::module::Module<#struct_ty>>};
|
parse_quote! {-> ::fayalite::intern::Interned<::fayalite::module::Module<#struct_ty>>};
|
||||||
let io_flips = io
|
|
||||||
.iter()
|
|
||||||
.map(|io| match io.kind.kind {
|
|
||||||
ModuleIOKind::Input((input,)) => quote_spanned! {input.span=>
|
|
||||||
#[hdl(flip)]
|
|
||||||
},
|
|
||||||
ModuleIOKind::Output(_) => quote! {},
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let io_types = io.iter().map(|io| &io.kind.ty).collect::<Vec<_>>();
|
|
||||||
let io_names = io.iter().map(|io| &io.name).collect::<Vec<_>>();
|
|
||||||
let fn_name_str = fn_name.to_string();
|
let fn_name_str = fn_name.to_string();
|
||||||
let (_, body_type_generics, _) = body_fn.sig.generics.split_for_impl();
|
let (_, body_type_generics, _) = body_fn.sig.generics.split_for_impl();
|
||||||
let body_turbofish_type_generics = body_type_generics.as_turbofish();
|
let body_turbofish_type_generics = body_type_generics.as_turbofish();
|
||||||
|
@ -316,15 +340,6 @@ impl ModuleFn {
|
||||||
|m| __body #body_turbofish_type_generics(m, #(#param_names,)*),
|
|m| __body #body_turbofish_type_generics(m, #(#param_names,)*),
|
||||||
)
|
)
|
||||||
}};
|
}};
|
||||||
let the_struct: ItemStruct = parse_quote! {
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[hdl(no_runtime_generics, no_static)]
|
|
||||||
#vis struct #fn_name #struct_generics #struct_where_clause {
|
|
||||||
#(
|
|
||||||
#io_flips
|
|
||||||
#vis #io_names: #io_types,)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let outer_fn = ItemFn {
|
let outer_fn = ItemFn {
|
||||||
attrs,
|
attrs,
|
||||||
vis,
|
vis,
|
||||||
|
@ -332,7 +347,7 @@ impl ModuleFn {
|
||||||
block,
|
block,
|
||||||
};
|
};
|
||||||
let mut retval = outer_fn.into_token_stream();
|
let mut retval = outer_fn.into_token_stream();
|
||||||
retval.extend(crate::hdl_bundle::hdl_bundle(the_struct).unwrap());
|
retval.extend(the_struct);
|
||||||
retval
|
retval
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use fayalite::{
|
||||||
intern::Intern,
|
intern::Intern,
|
||||||
module::transform::simplify_enums::{simplify_enums, SimplifyEnumsKind},
|
module::transform::simplify_enums::{simplify_enums, SimplifyEnumsKind},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
ty::StaticType,
|
||||||
};
|
};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
|
@ -133,9 +134,11 @@ circuit my_module:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(todo)]
|
|
||||||
#[hdl_module(outline_generated)]
|
#[hdl_module(outline_generated)]
|
||||||
pub fn check_array_repeat<const N: usize>() {
|
pub fn check_array_repeat<const N: usize>()
|
||||||
|
where
|
||||||
|
ConstUsize<N>: KnownSize,
|
||||||
|
{
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let i: UInt<8> = m.input();
|
let i: UInt<8> = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
@ -147,7 +150,6 @@ pub fn check_array_repeat<const N: usize>() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(todo)]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_array_repeat() {
|
fn test_array_repeat() {
|
||||||
let _n = SourceLocation::normalize_files_for_tests();
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
@ -188,21 +190,21 @@ circuit check_array_repeat_1:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(todo)]
|
|
||||||
#[hdl_module(outline_generated)]
|
#[hdl_module(outline_generated)]
|
||||||
pub fn check_skipped_generics<T, #[hdl(skip)] U, const N: usize, #[hdl(skip)] const M: usize>(v: U)
|
pub fn check_skipped_generics<T, #[hdl(skip)] U, const N: usize, #[hdl(skip)] const M: usize>(v: U)
|
||||||
where
|
where
|
||||||
T: StaticValue,
|
T: StaticType,
|
||||||
|
ConstUsize<N>: KnownSize,
|
||||||
U: std::fmt::Display,
|
U: std::fmt::Display,
|
||||||
{
|
{
|
||||||
dbg!(M);
|
dbg!(M);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let i: T = m.input();
|
let i: T = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let o: Array<[T; N]> = m.output();
|
let o: Array<T, N> = m.output();
|
||||||
let bytes = v.to_string().as_bytes().to_expr();
|
let bytes = v.to_string().as_bytes().to_expr();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let o2: Array<[UInt<8>]> = m.output(bytes.ty());
|
let o2: Array<UInt<8>> = m.output(Expr::ty(bytes));
|
||||||
connect(
|
connect(
|
||||||
o,
|
o,
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
@ -211,7 +213,6 @@ where
|
||||||
connect(o2, bytes);
|
connect(o2, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(todo)]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_skipped_generics() {
|
fn test_skipped_generics() {
|
||||||
let _n = SourceLocation::normalize_files_for_tests();
|
let _n = SourceLocation::normalize_files_for_tests();
|
||||||
|
|
Loading…
Reference in a new issue