Skip to content

Commit

Permalink
refactor: introduce a container for punctuation
Browse files Browse the repository at this point in the history
Many elements in Mabo schema files use some form of punctuation to
separate from another. This common logic could be centralized in a
custom container that keeps track of punctuation spans and takes care of
formatting logic.

This adds missing tracking of token spans that haven't be tracked before
yet.
  • Loading branch information
dnaka91 committed Feb 21, 2024
1 parent d0e6ec1 commit 554008d
Show file tree
Hide file tree
Showing 56 changed files with 3,908 additions and 3,195 deletions.
48 changes: 25 additions & 23 deletions crates/mabo-compiler/src/resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
//! correct.

use mabo_parser::{
DataType, Definition, ExternalType, Fields, Generics, Import, Name, Schema, Spanned, Type,
punctuated::Punctuated, DataType, Definition, ExternalType, Fields, Generics, Import, Name,
Schema, Spanned, Type,
};
use miette::NamedSource;
use rustc_hash::FxHashMap;
Expand Down Expand Up @@ -153,11 +154,11 @@ impl Module<'_> {

match definition.kind {
DeclarationKind::Struct { generics } | DeclarationKind::Enum { generics }
if generics != ty.generics.len() =>
if generics != ty.generics.as_ref().map_or(0, Punctuated::len) =>
{
Err(GenericsCount {
definition: generics,
usage: ty.generics.len(),
usage: ty.generics.as_ref().map_or(0, Punctuated::len),
declared: definition.name.span().into(),
used: ty.name.span().into(),
}
Expand Down Expand Up @@ -256,10 +257,10 @@ impl Module<'_> {

match definition.kind {
DeclarationKind::Struct { generics } | DeclarationKind::Enum { generics }
if generics != ty.generics.len() =>
if generics != ty.generics.as_ref().map_or(0, Punctuated::len) =>
{
Err(RemoteGenericsCount {
amount: ty.generics.len(),
amount: ty.generics.as_ref().map_or(0, Punctuated::len),
used: ty.name.span().into(),
declaration: [RemoteGenericsCountDeclaration {
amount: generics,
Expand Down Expand Up @@ -321,19 +322,18 @@ pub(crate) fn resolve_module_types<'a>(
module: &'a Module<'_>,
missing: &mut Vec<LocallyMissingType<'a>>,
) {
fn is_generic(external: &ExternalType<'_>, generics: &Generics<'_>) -> bool {
external.generics.is_empty()
fn is_generic(external: &ExternalType<'_>, generics: &Option<Generics<'_>>) -> bool {
external.generics.is_none()
&& external.path.is_empty()
&& generics
.0
.iter()
.any(|gen| gen.get() == external.name.get())
&& generics.as_ref().map_or(false, |g| {
g.types.values().any(|gen| gen.get() == external.name.get())
})
}

fn resolve<'a>(
missing: &mut Vec<LocallyMissingType<'a>>,
ty: &'a Type<'_>,
generics: &Generics<'_>,
generics: &Option<Generics<'_>>,
module: &'a Module<'_>,
) {
visit_externals(ty, &mut |external| {
Expand All @@ -348,17 +348,17 @@ pub(crate) fn resolve_module_types<'a>(
fn resolve_fields<'a>(
missing: &mut Vec<LocallyMissingType<'a>>,
fields: &'a Fields<'_>,
generics: &Generics<'_>,
generics: &Option<Generics<'_>>,
module: &'a Module<'_>,
) {
match fields {
Fields::Named(_, named) => {
for field in named {
for field in named.values() {
resolve(missing, &field.ty, generics, module);
}
}
Fields::Unnamed(_, unnamed) => {
for field in unnamed {
for field in unnamed.values() {
resolve(missing, &field.ty, generics, module);
}
}
Expand All @@ -370,7 +370,7 @@ pub(crate) fn resolve_module_types<'a>(
match def {
Definition::Struct(s) => resolve_fields(missing, &s.fields, &s.generics, module),
Definition::Enum(e) => {
for variant in &e.variants {
for variant in e.variants.values() {
resolve_fields(missing, &variant.fields, &e.generics, module);
}
}
Expand Down Expand Up @@ -424,13 +424,13 @@ fn visit_module_tree<'a>(
}
Definition::Struct(s) => module.types.push(Declaration {
kind: DeclarationKind::Struct {
generics: s.generics.0.len(),
generics: s.generics.as_ref().map_or(0, |g| g.types.len()),
},
name: s.name.clone(),
}),
Definition::Enum(e) => module.types.push(Declaration {
kind: DeclarationKind::Enum {
generics: e.generics.0.len(),
generics: e.generics.as_ref().map_or(0, |g| g.types.len()),
},
name: e.name.clone(),
}),
Expand Down Expand Up @@ -484,15 +484,17 @@ fn visit_externals<'a>(value: &'a Type<'_>, visit: &mut impl FnMut(&'a ExternalT
visit_externals(value, visit);
}
DataType::Tuple { types, .. } => {
for ty in types {
for ty in types.values() {
visit_externals(ty, visit);
}
}
DataType::External(ty) => {
visit(ty);

for ty in &ty.generics {
visit_externals(ty, visit);
if let Some(generics) = &ty.generics {
for ty in generics.values() {
visit_externals(ty, visit);
}
}
}
}
Expand Down Expand Up @@ -564,12 +566,12 @@ pub(crate) fn resolve_type_remotely(
});

if let Some((schema, name, generics)) = found {
if generics == ty.external.generics.len() {
if generics == ty.external.generics.as_ref().map_or(0, Punctuated::len) {
return Ok(());
}

return Err(ResolveRemote::GenericsCount(RemoteGenericsCount {
amount: ty.external.generics.len(),
amount: ty.external.generics.as_ref().map_or(0, Punctuated::len),
used: ty.external.name.span().into(),
declaration: [RemoteGenericsCountDeclaration {
amount: generics,
Expand Down
18 changes: 11 additions & 7 deletions crates/mabo-compiler/src/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,10 @@ fn comment<'a>(item: &'a mabo_parser::Comment<'_>) -> Box<[&'a str]> {
}

#[inline]
fn generics<'a>(item: &'a mabo_parser::Generics<'_>) -> Box<[&'a str]> {
item.0.iter().map(mabo_parser::Name::get).collect()
fn generics<'a>(item: &'a Option<mabo_parser::Generics<'_>>) -> Box<[&'a str]> {
item.as_ref().map_or(Box::default(), |g| {
g.types.values().map(mabo_parser::Name::get).collect()
})
}

#[inline]
Expand Down Expand Up @@ -360,7 +362,7 @@ fn simplify_enum<'a>(item: &'a mabo_parser::Enum<'_>) -> Enum<'a> {
generics: generics(&item.generics),
variants: item
.variants
.iter()
.values()
.map(|variant| simplify_variant(variant, &mut id_gen))
.collect(),
}
Expand All @@ -386,7 +388,7 @@ fn simplify_fields<'a>(item: &'a mabo_parser::Fields<'_>) -> Fields<'a> {
mabo_parser::Fields::Named(_, named) => Fields {
source: item,
fields: named
.iter()
.values()
.map(|field| Field {
source: ParserField::Named(field),
comment: comment(&field.comment),
Expand All @@ -400,7 +402,7 @@ fn simplify_fields<'a>(item: &'a mabo_parser::Fields<'_>) -> Fields<'a> {
mabo_parser::Fields::Unnamed(_, unnamed) => Fields {
source: item,
fields: unnamed
.iter()
.values()
.enumerate()
.map(|(i, field)| Field {
source: ParserField::Unnamed(field),
Expand Down Expand Up @@ -449,15 +451,17 @@ fn simplify_type<'a>(item: &'a mabo_parser::Type<'_>) -> Type<'a> {
mabo_parser::DataType::BoxString => Type::BoxString,
mabo_parser::DataType::BoxBytes => Type::BoxBytes,
mabo_parser::DataType::Tuple { ref types, .. } => {
Type::Tuple(types.iter().map(|ty| simplify_type(ty)).collect())
Type::Tuple(types.values().map(|ty| simplify_type(ty)).collect())
}
mabo_parser::DataType::Array { ref ty, size, .. } => {
Type::Array(simplify_type(ty).into(), size)
}
mabo_parser::DataType::External(ref ty) => Type::External(ExternalType {
path: ty.path.iter().map(mabo_parser::Name::get).collect(),
name: ty.name.get(),
generics: ty.generics.iter().map(|ty| simplify_type(ty)).collect(),
generics: ty.generics.as_ref().map_or(Vec::default(), |g| {
g.values().map(|ty| simplify_type(ty)).collect()
}),
}),
}
}
Expand Down
50 changes: 29 additions & 21 deletions crates/mabo-compiler/src/validate/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,15 @@ pub struct UnusedGeneric {

/// Ensure all generics in a struct are unique and used.
pub fn validate_struct_generics(value: &Struct<'_>) -> Result<(), InvalidGenericType> {
validate_duplicate_generics(&value.generics)?;
let Some(generics) = &value.generics else {
return Ok(());
};

let mut unvisited = value
.generics
.0
.iter()
validate_duplicate_generics(generics)?;

let mut unvisited = generics
.types
.values()
.map(|gen| (gen.get(), gen.span()))
.collect::<FxHashMap<_, _>>();

Expand All @@ -69,16 +72,19 @@ pub fn validate_struct_generics(value: &Struct<'_>) -> Result<(), InvalidGeneric

/// Ensure all generics in an enum are unique and used.
pub fn validate_enum_generics(value: &Enum<'_>) -> Result<(), InvalidGenericType> {
validate_duplicate_generics(&value.generics)?;
let Some(generics) = &value.generics else {
return Ok(());
};

validate_duplicate_generics(generics)?;

let mut unvisited = value
.generics
.0
.iter()
let mut unvisited = generics
.types
.values()
.map(|gen| (gen.get(), gen.span()))
.collect::<FxHashMap<_, _>>();

for variant in &value.variants {
for variant in value.variants.values() {
validate_field_generics(&variant.fields, &mut unvisited);
}

Expand All @@ -94,10 +100,10 @@ pub fn validate_enum_generics(value: &Enum<'_>) -> Result<(), InvalidGenericType
/// Ensure all generic type arguments are unique within a struct or enum.
fn validate_duplicate_generics(value: &Generics<'_>) -> Result<(), DuplicateGenericName> {
let mut visited =
FxHashMap::with_capacity_and_hasher(value.0.len(), BuildHasherDefault::default());
FxHashMap::with_capacity_and_hasher(value.types.len(), BuildHasherDefault::default());
value
.0
.iter()
.types
.values()
.find_map(|name| {
visited
.insert(name.get(), name.span())
Expand All @@ -115,18 +121,18 @@ fn validate_duplicate_generics(value: &Generics<'_>) -> Result<(), DuplicateGene
fn validate_field_generics(value: &Fields<'_>, unvisited: &mut FxHashMap<&str, Span>) {
match &value {
Fields::Named(_, named) => {
for field in named {
for field in named.values() {
visit_externals(&field.ty, &mut |external| {
if external.path.is_empty() && external.generics.is_empty() {
if external.path.is_empty() && external.generics.is_none() {
unvisited.remove(external.name.get());
}
});
}
}
Fields::Unnamed(_, unnamed) => {
for field in unnamed {
for field in unnamed.values() {
visit_externals(&field.ty, &mut |external| {
if external.path.is_empty() && external.generics.is_empty() {
if external.path.is_empty() && external.generics.is_none() {
unvisited.remove(external.name.get());
}
});
Expand Down Expand Up @@ -169,15 +175,17 @@ fn visit_externals(value: &Type<'_>, visit: &mut impl FnMut(&ExternalType<'_>))
visit_externals(value, visit);
}
DataType::Tuple { types, .. } => {
for ty in types {
for ty in types.values() {
visit_externals(ty, visit);
}
}
DataType::External(ty) => {
visit(ty);

for ty in &ty.generics {
visit_externals(ty, visit);
if let Some(generics) = &ty.generics {
for ty in generics.values() {
visit_externals(ty, visit);
}
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions crates/mabo-compiler/src/validate/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pub(crate) fn validate_enum_ids(value: &Enum<'_>) -> Result<(), DuplicateId> {

value
.variants
.iter()
.values()
.find_map(|variant| {
let id = id_gen.next_with_span(variant.id.as_ref(), || variant.span());

Expand Down Expand Up @@ -138,7 +138,7 @@ fn validate_field_ids(value: &Fields<'_>) -> Result<(), DuplicateFieldId> {
let mut id_gen = IdGenerator::new();

named
.iter()
.values()
.find_map(|field| {
let id = id_gen.next_with_span(field.id.as_ref(), || field.span());

Expand All @@ -160,7 +160,7 @@ fn validate_field_ids(value: &Fields<'_>) -> Result<(), DuplicateFieldId> {
let mut id_gen = IdGenerator::new();

unnamed
.iter()
.values()
.enumerate()
.find_map(|(pos, field)| {
let id = id_gen.next_with_span(field.id.as_ref(), || field.span());
Expand Down
4 changes: 2 additions & 2 deletions crates/mabo-compiler/src/validate/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub(crate) fn validate_enum_names(value: &Enum<'_>) -> Result<(), DuplicateName>
FxHashMap::with_capacity_and_hasher(value.variants.len(), BuildHasherDefault::default());
value
.variants
.iter()
.values()
.find_map(|variant| {
visited
.insert(variant.name.get(), variant.name.span())
Expand Down Expand Up @@ -109,7 +109,7 @@ fn validate_field_names(value: &Fields<'_>) -> Result<(), DuplicateFieldName> {
let mut visited =
FxHashMap::with_capacity_and_hasher(named.len(), BuildHasherDefault::default());
named
.iter()
.values()
.find_map(|field| {
visited
.insert(field.name.get(), field.name.span())
Expand Down
Loading

0 comments on commit 554008d

Please sign in to comment.