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:
parent
6465af3ae2
commit
0838d48f7c
|
@ -3,8 +3,11 @@ use std::{fmt, ops::Range, sync::Arc};
|
||||||
use crate::{
|
use crate::{
|
||||||
builtins::{self, bool},
|
builtins::{self, bool},
|
||||||
expr::{TypedExpr, UntypedExpr},
|
expr::{TypedExpr, UntypedExpr},
|
||||||
|
parser::token::Token,
|
||||||
tipo::{PatternConstructor, Type, TypeInfo},
|
tipo::{PatternConstructor, Type, TypeInfo},
|
||||||
};
|
};
|
||||||
|
use miette::Diagnostic;
|
||||||
|
use owo_colors::OwoColorize;
|
||||||
|
|
||||||
pub const ASSERT_VARIABLE: &str = "_try";
|
pub const ASSERT_VARIABLE: &str = "_try";
|
||||||
pub const CAPTURE_VARIABLE: &str = "_capture";
|
pub const CAPTURE_VARIABLE: &str = "_capture";
|
||||||
|
@ -72,6 +75,51 @@ impl TypedModule {
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|definition| definition.find_node(byte_index))
|
.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>;
|
pub type TypedFunction = Function<Arc<Type>, TypedExpr>;
|
||||||
|
@ -1137,3 +1185,29 @@ impl chumsky::Span for Span {
|
||||||
self.end
|
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,
|
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(
|
#[error(
|
||||||
"I discovered an attempt to access the {} element of a {}-tuple.\n",
|
"I discovered an attempt to access the {} element of a {}-tuple.\n",
|
||||||
Ordinal(*index + 1).to_string().purple(),
|
Ordinal(*index + 1).to_string().purple(),
|
||||||
|
|
|
@ -8,7 +8,6 @@ use crate::{
|
||||||
},
|
},
|
||||||
builtins,
|
builtins,
|
||||||
builtins::function,
|
builtins::function,
|
||||||
parser::token::Token,
|
|
||||||
IdGenerator,
|
IdGenerator,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,8 +35,6 @@ impl UntypedModule {
|
||||||
let docs = std::mem::take(&mut self.docs);
|
let docs = std::mem::take(&mut self.docs);
|
||||||
let mut environment = Environment::new(id_gen.clone(), &name, modules, warnings);
|
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 type_names = HashMap::with_capacity(self.definitions.len());
|
||||||
let mut value_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());
|
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -277,7 +277,7 @@ impl Annotated<Schema> {
|
||||||
Ok(Annotated {
|
Ok(Annotated {
|
||||||
title: Some("Tuple".to_owned()),
|
title: Some("Tuple".to_owned()),
|
||||||
description: None,
|
description: None,
|
||||||
annotated: Schema::Data(Some(Data::List(Items::Many(elems)))).into(),
|
annotated: Schema::Data(Some(Data::List(Items::Many(elems)))),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
script::EvalHint,
|
script::EvalHint,
|
||||||
};
|
};
|
||||||
use aiken_lang::{
|
use aiken_lang::{
|
||||||
ast::{BinOp, Span},
|
ast::{self, BinOp, Span},
|
||||||
parser::error::ParseError,
|
parser::error::ParseError,
|
||||||
tipo,
|
tipo,
|
||||||
};
|
};
|
||||||
|
@ -54,6 +54,9 @@ pub enum Error {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Json(#[from] serde_json::Error),
|
Json(#[from] serde_json::Error),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
Module(#[from] ast::Error),
|
||||||
|
|
||||||
#[error("{help}")]
|
#[error("{help}")]
|
||||||
TomlLoading {
|
TomlLoading {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
@ -189,6 +192,7 @@ impl GetSource for Error {
|
||||||
Error::MalformedStakeAddress { .. } => None,
|
Error::MalformedStakeAddress { .. } => None,
|
||||||
Error::NoValidatorNotFound { .. } => None,
|
Error::NoValidatorNotFound { .. } => None,
|
||||||
Error::MoreThanOneValidatorFound { .. } => None,
|
Error::MoreThanOneValidatorFound { .. } => None,
|
||||||
|
Error::Module { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,6 +217,7 @@ impl GetSource for Error {
|
||||||
Error::MalformedStakeAddress { .. } => None,
|
Error::MalformedStakeAddress { .. } => None,
|
||||||
Error::NoValidatorNotFound { .. } => None,
|
Error::NoValidatorNotFound { .. } => None,
|
||||||
Error::MoreThanOneValidatorFound { .. } => None,
|
Error::MoreThanOneValidatorFound { .. } => None,
|
||||||
|
Error::Module { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,6 +251,7 @@ impl Diagnostic for Error {
|
||||||
Error::MalformedStakeAddress { .. } => None,
|
Error::MalformedStakeAddress { .. } => None,
|
||||||
Error::NoValidatorNotFound { .. } => None,
|
Error::NoValidatorNotFound { .. } => None,
|
||||||
Error::MoreThanOneValidatorFound { .. } => None,
|
Error::MoreThanOneValidatorFound { .. } => None,
|
||||||
|
Error::Module(e) => e.code(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,6 +323,7 @@ impl Diagnostic for Error {
|
||||||
known_validators.iter().map(|title| format!("→ {title}", title = title.purple().bold())).collect::<Vec<String>>().join("\n")
|
known_validators.iter().map(|title| format!("→ {title}", title = title.purple().bold())).collect::<Vec<String>>().join("\n")
|
||||||
)))
|
)))
|
||||||
},
|
},
|
||||||
|
Error::Module(e) => e.help(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,6 +356,7 @@ impl Diagnostic for Error {
|
||||||
Error::MalformedStakeAddress { .. } => None,
|
Error::MalformedStakeAddress { .. } => None,
|
||||||
Error::NoValidatorNotFound { .. } => None,
|
Error::NoValidatorNotFound { .. } => None,
|
||||||
Error::MoreThanOneValidatorFound { .. } => None,
|
Error::MoreThanOneValidatorFound { .. } => None,
|
||||||
|
Error::Module(e) => e.labels(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,6 +381,7 @@ impl Diagnostic for Error {
|
||||||
Error::MalformedStakeAddress { .. } => None,
|
Error::MalformedStakeAddress { .. } => None,
|
||||||
Error::NoValidatorNotFound { .. } => None,
|
Error::NoValidatorNotFound { .. } => None,
|
||||||
Error::MoreThanOneValidatorFound { .. } => None,
|
Error::MoreThanOneValidatorFound { .. } => None,
|
||||||
|
Error::Module(e) => e.source_code(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,6 +406,7 @@ impl Diagnostic for Error {
|
||||||
Error::MalformedStakeAddress { .. } => None,
|
Error::MalformedStakeAddress { .. } => None,
|
||||||
Error::NoValidatorNotFound { .. } => None,
|
Error::NoValidatorNotFound { .. } => None,
|
||||||
Error::MoreThanOneValidatorFound { .. } => None,
|
Error::MoreThanOneValidatorFound { .. } => None,
|
||||||
|
Error::Module(e) => e.url(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,6 +431,7 @@ impl Diagnostic for Error {
|
||||||
Error::MalformedStakeAddress { .. } => None,
|
Error::MalformedStakeAddress { .. } => None,
|
||||||
Error::NoValidatorNotFound { .. } => None,
|
Error::NoValidatorNotFound { .. } => None,
|
||||||
Error::MoreThanOneValidatorFound { .. } => None,
|
Error::MoreThanOneValidatorFound { .. } => None,
|
||||||
|
Error::Module(e) => e.related(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,7 @@ where
|
||||||
|
|
||||||
let parsed_modules = self.parse_sources(self.config.name.clone())?;
|
let parsed_modules = self.parse_sources(self.config.name.clone())?;
|
||||||
|
|
||||||
self.type_check(parsed_modules, Tracing::NoTraces)?;
|
self.type_check(parsed_modules, Tracing::NoTraces, false)?;
|
||||||
|
|
||||||
self.event_listener.handle_event(Event::GeneratingDocFiles {
|
self.event_listener.handle_event(Event::GeneratingDocFiles {
|
||||||
output_path: destination.clone(),
|
output_path: destination.clone(),
|
||||||
|
@ -247,7 +247,7 @@ where
|
||||||
|
|
||||||
let parsed_modules = self.parse_sources(self.config.name.clone())?;
|
let parsed_modules = self.parse_sources(self.config.name.clone())?;
|
||||||
|
|
||||||
self.type_check(parsed_modules, options.tracing)?;
|
self.type_check(parsed_modules, options.tracing, true)?;
|
||||||
|
|
||||||
match options.code_gen_mode {
|
match options.code_gen_mode {
|
||||||
CodeGenMode::Build(uplc_dump) => {
|
CodeGenMode::Build(uplc_dump) => {
|
||||||
|
@ -432,7 +432,7 @@ where
|
||||||
|
|
||||||
let parsed_modules = self.parse_sources(package.name)?;
|
let parsed_modules = self.parse_sources(package.name)?;
|
||||||
|
|
||||||
self.type_check(parsed_modules, Tracing::NoTraces)?;
|
self.type_check(parsed_modules, Tracing::NoTraces, true)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -518,6 +518,7 @@ where
|
||||||
&mut self,
|
&mut self,
|
||||||
mut parsed_modules: ParsedModules,
|
mut parsed_modules: ParsedModules,
|
||||||
tracing: Tracing,
|
tracing: Tracing,
|
||||||
|
validate_module_name: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let processing_sequence = parsed_modules.sequence()?;
|
let processing_sequence = parsed_modules.sequence()?;
|
||||||
|
|
||||||
|
@ -550,6 +551,10 @@ where
|
||||||
error,
|
error,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
if validate_module_name {
|
||||||
|
ast.validate_module_name()?;
|
||||||
|
}
|
||||||
|
|
||||||
// Register any warnings emitted as type warnings
|
// Register any warnings emitted as type warnings
|
||||||
let type_warnings = type_warnings
|
let type_warnings = type_warnings
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
Loading…
Reference in New Issue