Move module name validation outside of type-checking
And disable it for documentation generation. This way, we can generate documentation for aiken/builtins and aiken (prelude)
This commit is contained in:
@@ -3,8 +3,11 @@ use std::{fmt, ops::Range, sync::Arc};
|
||||
use crate::{
|
||||
builtins::{self, bool},
|
||||
expr::{TypedExpr, UntypedExpr},
|
||||
parser::token::Token,
|
||||
tipo::{PatternConstructor, Type, TypeInfo},
|
||||
};
|
||||
use miette::Diagnostic;
|
||||
use owo_colors::OwoColorize;
|
||||
|
||||
pub const ASSERT_VARIABLE: &str = "_try";
|
||||
pub const CAPTURE_VARIABLE: &str = "_capture";
|
||||
@@ -72,6 +75,51 @@ impl TypedModule {
|
||||
.iter()
|
||||
.find_map(|definition| definition.find_node(byte_index))
|
||||
}
|
||||
|
||||
pub fn validate_module_name(&self) -> Result<(), Error> {
|
||||
if self.name == "aiken" || self.name == "aiken/builtin" {
|
||||
return Err(Error::ReservedModuleName {
|
||||
name: self.name.to_string(),
|
||||
});
|
||||
};
|
||||
|
||||
for segment in self.name.split('/') {
|
||||
if str_to_keyword(segment).is_some() {
|
||||
return Err(Error::KeywordInModuleName {
|
||||
name: self.name.to_string(),
|
||||
keyword: segment.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn str_to_keyword(word: &str) -> Option<Token> {
|
||||
// Alphabetical keywords:
|
||||
match word {
|
||||
"assert" => Some(Token::Expect),
|
||||
"expect" => Some(Token::Expect),
|
||||
"else" => Some(Token::Else),
|
||||
"is" => Some(Token::Is),
|
||||
"as" => Some(Token::As),
|
||||
"when" => Some(Token::When),
|
||||
"const" => Some(Token::Const),
|
||||
"fn" => Some(Token::Fn),
|
||||
"if" => Some(Token::If),
|
||||
"use" => Some(Token::Use),
|
||||
"let" => Some(Token::Let),
|
||||
"opaque" => Some(Token::Opaque),
|
||||
"pub" => Some(Token::Pub),
|
||||
"todo" => Some(Token::Todo),
|
||||
"type" => Some(Token::Type),
|
||||
"trace" => Some(Token::Trace),
|
||||
"test" => Some(Token::Test),
|
||||
"error" => Some(Token::ErrorTerm),
|
||||
"validator" => Some(Token::Validator),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub type TypedFunction = Function<Arc<Type>, TypedExpr>;
|
||||
@@ -1137,3 +1185,29 @@ impl chumsky::Span for Span {
|
||||
self.end
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error, Diagnostic)]
|
||||
pub enum Error {
|
||||
#[error(
|
||||
"I realized the module '{}' contains the keyword '{}', which is forbidden.\n",
|
||||
name.purple(),
|
||||
keyword.purple()
|
||||
)]
|
||||
#[diagnostic(url("https://aiken-lang.org/language-tour/modules"))]
|
||||
#[diagnostic(code("illegal::module_name"))]
|
||||
#[diagnostic(help(r#"You cannot use keywords as part of a module path name. As a quick reminder, here's a list of all the keywords (and thus, of invalid module path names):
|
||||
|
||||
as, expect, check, const, else, fn, if, is, let, opaque, pub, test, todo, trace, type, use, when"#))]
|
||||
KeywordInModuleName { name: String, keyword: String },
|
||||
|
||||
#[error("I realized you used '{}' as a module name, which is reserved (and not available).\n", name.purple())]
|
||||
#[diagnostic(code("illegal::module_name"))]
|
||||
#[diagnostic(help(r#"Some module names are reserved for internal use. This the case of:
|
||||
|
||||
- aiken: where the prelude is located;
|
||||
- aiken/builtin: where I store low-level Plutus builtins.
|
||||
|
||||
Note that 'aiken' is also imported by default; but you can refer to it explicitly to disambiguate with a local value that would clash with one from that module."#
|
||||
))]
|
||||
ReservedModuleName { name: String },
|
||||
}
|
||||
|
||||
@@ -521,17 +521,6 @@ You can help me by providing a type-annotation for 'x', as such:
|
||||
location: Span,
|
||||
},
|
||||
|
||||
#[error("I realized you used '{}' as a module name, which is reserved (and not available).\n", name.purple())]
|
||||
#[diagnostic(code("illegal::module_name"))]
|
||||
#[diagnostic(help(r#"Some module names are reserved for internal use. This the case of:
|
||||
|
||||
- aiken: where the prelude is located;
|
||||
- aiken/builtin: where I store low-level Plutus builtins.
|
||||
|
||||
Note that 'aiken' is also imported by default; but you can refer to it explicitly to disambiguate with a local value that would clash with one from that module."#
|
||||
))]
|
||||
ReservedModuleName { name: String },
|
||||
|
||||
#[error(
|
||||
"I discovered an attempt to access the {} element of a {}-tuple.\n",
|
||||
Ordinal(*index + 1).to_string().purple(),
|
||||
|
||||
@@ -8,7 +8,6 @@ use crate::{
|
||||
},
|
||||
builtins,
|
||||
builtins::function,
|
||||
parser::token::Token,
|
||||
IdGenerator,
|
||||
};
|
||||
|
||||
@@ -36,8 +35,6 @@ impl UntypedModule {
|
||||
let docs = std::mem::take(&mut self.docs);
|
||||
let mut environment = Environment::new(id_gen.clone(), &name, modules, warnings);
|
||||
|
||||
validate_module_name(&name)?;
|
||||
|
||||
let mut type_names = HashMap::with_capacity(self.definitions.len());
|
||||
let mut value_names = HashMap::with_capacity(self.definitions.len());
|
||||
let mut hydrators = HashMap::with_capacity(self.definitions.len());
|
||||
@@ -549,48 +546,3 @@ fn infer_definition(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_module_name(name: &str) -> Result<(), Error> {
|
||||
if name == "aiken" || name == "aiken/builtin" {
|
||||
return Err(Error::ReservedModuleName {
|
||||
name: name.to_string(),
|
||||
});
|
||||
};
|
||||
|
||||
for segment in name.split('/') {
|
||||
if str_to_keyword(segment).is_some() {
|
||||
return Err(Error::KeywordInModuleName {
|
||||
name: name.to_string(),
|
||||
keyword: segment.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn str_to_keyword(word: &str) -> Option<Token> {
|
||||
// Alphabetical keywords:
|
||||
match word {
|
||||
"assert" => Some(Token::Expect),
|
||||
"expect" => Some(Token::Expect),
|
||||
"else" => Some(Token::Else),
|
||||
"is" => Some(Token::Is),
|
||||
"as" => Some(Token::As),
|
||||
"when" => Some(Token::When),
|
||||
"const" => Some(Token::Const),
|
||||
"fn" => Some(Token::Fn),
|
||||
"if" => Some(Token::If),
|
||||
"use" => Some(Token::Use),
|
||||
"let" => Some(Token::Let),
|
||||
"opaque" => Some(Token::Opaque),
|
||||
"pub" => Some(Token::Pub),
|
||||
"todo" => Some(Token::Todo),
|
||||
"type" => Some(Token::Type),
|
||||
"trace" => Some(Token::Trace),
|
||||
"test" => Some(Token::Test),
|
||||
"error" => Some(Token::ErrorTerm),
|
||||
"validator" => Some(Token::Validator),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user