diff --git a/crates/analyzer/src/analyzer_error.rs b/crates/analyzer/src/analyzer_error.rs index 84cbc41e..d3d64f17 100644 --- a/crates/analyzer/src/analyzer_error.rs +++ b/crates/analyzer/src/analyzer_error.rs @@ -565,6 +565,23 @@ pub enum AnalyzerError { #[label("Uncovered")] uncovered: SourceSpan, }, + + #[diagnostic( + severity(Error), + code(reserved_identifier), + help("prefix `__` can't be used"), + url( + "https://doc.veryl-lang.org/book/06_appendix/02_semantic_error.html#reserved_identifier" + ) + )] + #[error("{identifier} is reverved for compiler usage")] + ReservedIdentifier { + identifier: String, + #[source_code] + input: NamedSource, + #[label("Error location")] + error_location: SourceSpan, + }, } impl AnalyzerError { @@ -906,4 +923,12 @@ impl AnalyzerError { uncovered: uncovered.into(), } } + + pub fn reserved_identifier(identifier: &str, source: &str, token: &Token) -> Self { + AnalyzerError::ReservedIdentifier { + identifier: identifier.to_string(), + input: AnalyzerError::named_source(source, token), + error_location: token.into(), + } + } } diff --git a/crates/analyzer/src/handlers/check_identifier.rs b/crates/analyzer/src/handlers/check_identifier.rs index 5d39d71d..9fd1ce04 100644 --- a/crates/analyzer/src/handlers/check_identifier.rs +++ b/crates/analyzer/src/handlers/check_identifier.rs @@ -130,6 +130,15 @@ impl<'a> CheckIdentifier<'a> { }; let identifier = token.to_string(); + + if identifier.starts_with("__") { + self.errors.push(AnalyzerError::reserved_identifier( + &identifier, + self.text, + token, + )); + } + if let Some(prefix) = prefix { if !identifier.starts_with(prefix) { self.errors.push(AnalyzerError::invalid_identifier( diff --git a/crates/analyzer/src/tests.rs b/crates/analyzer/src/tests.rs index 8e07e83d..1652dcac 100644 --- a/crates/analyzer/src/tests.rs +++ b/crates/analyzer/src/tests.rs @@ -600,3 +600,17 @@ fn uncovered_branch() { let errors = analyze(code); assert!(matches!(errors[0], AnalyzerError::UncoveredBranch { .. })); } + +#[test] +fn reserved_identifier() { + let code = r#" + module __ModuleA { + } + "#; + + let errors = analyze(code); + assert!(matches!( + errors[0], + AnalyzerError::ReservedIdentifier { .. } + )); +}