diff --git a/crates/mabo-compiler/src/resolve/mod.rs b/crates/mabo-compiler/src/resolve/mod.rs index c30756a..50ca7bd 100644 --- a/crates/mabo-compiler/src/resolve/mod.rs +++ b/crates/mabo-compiler/src/resolve/mod.rs @@ -2,8 +2,9 @@ //! correct. use mabo_parser::{ - punctuated::Punctuated, DataType, Definition, ExternalType, Fields, Generics, Import, Name, - Schema, Spanned, Type, + punctuated::Punctuated, + token::{self, Punctuation}, + DataType, Definition, ExternalType, Fields, Generics, Import, Name, Schema, Spanned, Type, }; use miette::NamedSource; use rustc_hash::FxHashMap; @@ -133,7 +134,7 @@ impl Module<'_> { let module = if ty.path.is_empty() { self } else { - ty.path.iter().try_fold(self, |module, name| { + ty.path.iter().try_fold(self, |module, (name, _)| { module.modules.get(name.get()).ok_or_else(|| MissingModule { name: name.get().to_owned(), path: module.path_to_string(), @@ -232,11 +233,11 @@ impl Module<'_> { let module = if ty .path .first() - .is_some_and(|first| first.get() == self.name) + .is_some_and(|(first, _)| first.get() == self.name) { self } else { - ty.path.iter().try_fold(self, |module, name| { + ty.path.iter().try_fold(self, |module, (name, _)| { module.modules.get(name.get()).ok_or_else(|| MissingModule { name: name.get().to_owned(), path: module.path_to_string(), @@ -528,7 +529,7 @@ pub(crate) fn resolve_type_remotely( ) -> Result<(), ResolveError> { if imports.is_empty() { return Err(ty.error.into()); - } else if let Some(name) = ty.external.path.first() { + } else if let Some((name, _)) = ty.external.path.first() { let module = imports.iter().find_map(|import| match import { ResolvedImport::Module(module) => (module.name == name.get()).then_some(module), ResolvedImport::Type { .. } => None, @@ -543,9 +544,9 @@ pub(crate) fn resolve_type_remotely( ty.external .path .iter() - .fold(String::new(), |mut acc, part| { + .fold(String::new(), |mut acc, (part, _)| { acc.push_str(part.get()); - acc.push_str("::"); + acc.push_str(token::DoubleColon::VALUE); acc }), ty.external.name diff --git a/crates/mabo-compiler/src/simplify.rs b/crates/mabo-compiler/src/simplify.rs index 7b8050e..2972623 100644 --- a/crates/mabo-compiler/src/simplify.rs +++ b/crates/mabo-compiler/src/simplify.rs @@ -457,7 +457,7 @@ fn simplify_type<'a>(item: &'a mabo_parser::Type<'_>) -> Type<'a> { 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(), + path: ty.path.iter().map(|(segment, _)| segment.get()).collect(), name: ty.name.get(), generics: ty.generics.as_ref().map_or(Vec::default(), |g| { g.values().map(|ty| simplify_type(ty)).collect() diff --git a/crates/mabo-lsp/src/handlers/semantic_tokens.rs b/crates/mabo-lsp/src/handlers/semantic_tokens.rs index dacc5af..b05fc44 100644 --- a/crates/mabo-lsp/src/handlers/semantic_tokens.rs +++ b/crates/mabo-lsp/src/handlers/semantic_tokens.rs @@ -418,8 +418,9 @@ impl<'a> Visitor<'a> { angle, generics, }) => { - for name in path { + for (name, token) in path { self.add_span(name, &types::NAMESPACE, &[])?; + self.add_span(token, &types::DOUBLE_COLON, &[])?; } self.add_span(name, &types::TYPE, &[])?; if let Some(angle) = angle { diff --git a/crates/mabo-parser/src/lib.rs b/crates/mabo-parser/src/lib.rs index 3c95aca..86a74ac 100644 --- a/crates/mabo-parser/src/lib.rs +++ b/crates/mabo-parser/src/lib.rs @@ -1026,7 +1026,7 @@ impl Display for DataType<'_> { #[derive(Clone, Debug, Eq, PartialEq)] pub struct ExternalType<'a> { /// Optional path, if the type wasn't fully imported with a `use` statement. - pub path: Vec>, + pub path: Vec<(Name<'a>, token::DoubleColon)>, /// Unique name of the type within the current scope (or the module if prefixed with a path). pub name: Name<'a>, /// Angles `<`...`>` to delimit the generic type parameters. @@ -1044,8 +1044,8 @@ impl Display for ExternalType<'_> { .. } = self; - for segment in path { - write!(f, "{segment}::")?; + for (segment, token) in path { + write!(f, "{segment}{token}")?; } name.fmt(f)?; if let Some(generics) = generics { diff --git a/crates/mabo-parser/src/parser/types.rs b/crates/mabo-parser/src/parser/types.rs index 0971013..d05cdb7 100644 --- a/crates/mabo-parser/src/parser/types.rs +++ b/crates/mabo-parser/src/parser/types.rs @@ -3,7 +3,7 @@ use std::ops::Range; use mabo_derive::{ParserError, ParserErrorCause}; use winnow::{ ascii::{dec_uint, space0}, - combinator::{alt, cut_err, empty, fail, opt, preceded, separated, terminated}, + combinator::{alt, cut_err, empty, fail, opt, preceded, repeat}, dispatch, error::ErrorKind, stream::Location, @@ -221,13 +221,13 @@ fn parse_array<'i>(input: &mut Input<'i>) -> Result, Cause> { fn parse_external<'i>(input: &mut Input<'i>) -> Result, Cause> { ( - opt(terminated( - separated( - 1.., + opt(repeat( + 1.., + ( imports::parse_segment.map_err(Cause::from), - token::DoubleColon::VALUE, - ), - token::DoubleColon::VALUE, + token::DoubleColon::VALUE.span(), + ) + .map(|(segment, token)| (segment, token.into())), )) .map(Option::unwrap_or_default), parse_external_name, diff --git a/crates/mabo-parser/tests/snapshots/parser__parse@mixed.mabo.snap b/crates/mabo-parser/tests/snapshots/parser__parse@mixed.mabo.snap index bd921ed..c0abf8f 100644 --- a/crates/mabo-parser/tests/snapshots/parser__parse@mixed.mabo.snap +++ b/crates/mabo-parser/tests/snapshots/parser__parse@mixed.mabo.snap @@ -147,9 +147,12 @@ Schema { value: External( ExternalType { path: [ - Name { - value: "birthday", - }, + ( + Name { + value: "birthday", + }, + DoubleColon, + ), ], name: Name { value: "DayOfBirth", diff --git a/crates/mabo-parser/tests/snapshots/parser__parse@module_basic.mabo.snap b/crates/mabo-parser/tests/snapshots/parser__parse@module_basic.mabo.snap index 0b842d6..f434bfd 100644 --- a/crates/mabo-parser/tests/snapshots/parser__parse@module_basic.mabo.snap +++ b/crates/mabo-parser/tests/snapshots/parser__parse@module_basic.mabo.snap @@ -130,9 +130,12 @@ Schema { value: External( ExternalType { path: [ - Name { - value: "b", - }, + ( + Name { + value: "b", + }, + DoubleColon, + ), ], name: Name { value: "Sample",