فهرست منبع

Fix name clash with reserved identifiers

The following bug was found using fuzzing:

    unit _
    _/_
    _!

The underlying problem (a unit named '_') is fixed by this change.
David Peter 2 سال پیش
والد
کامیت
2d0c8153ed

+ 1 - 0
examples/name_resolution_error/reserved_identifier_1.nbt

@@ -0,0 +1 @@
+unit _

+ 1 - 0
examples/name_resolution_error/reserved_identifier_2.nbt

@@ -0,0 +1 @@
+unit ans

+ 1 - 0
examples/name_resolution_error/reserved_identifier_3.nbt

@@ -0,0 +1 @@
+let _ = 1

+ 1 - 0
examples/name_resolution_error/reserved_identifier_4.nbt

@@ -0,0 +1 @@
+let ans = 1

+ 2 - 1
numbat-cli/src/main.rs

@@ -374,7 +374,8 @@ impl Cli {
                 execution_mode.exit_status_in_case_of_error()
             }
             Err(NumbatError::NameResolutionError(
-                e @ NameResolutionError::IdentifierClash { .. },
+                e @ (NameResolutionError::IdentifierClash { .. }
+                | NameResolutionError::ReservedIdentifier(_)),
             )) => {
                 self.print_diagnostic(e);
                 execution_mode.exit_status_in_case_of_error()

+ 5 - 0
numbat/src/diagnostic.rs

@@ -52,6 +52,11 @@ impl ErrorDiagnostic for NameResolutionError {
                         .diagnostic_label(LabelStyle::Primary)
                         .with_message("identifier is already in use"),
                 ]),
+            NameResolutionError::ReservedIdentifier(span) => Diagnostic::error()
+                .with_message("reserved identifier may not be used")
+                .with_labels(vec![span
+                    .diagnostic_label(LabelStyle::Primary)
+                    .with_message("reserved identifier")]),
         }
     }
 }

+ 3 - 0
numbat/src/name_resolution.rs

@@ -12,4 +12,7 @@ pub enum NameResolutionError {
         conflict_span: Span,
         original_span: Span,
     },
+
+    #[error("Reserved identifier")]
+    ReservedIdentifier(Span),
 }

+ 7 - 0
numbat/src/prefix_parser.rs

@@ -69,6 +69,8 @@ pub struct PrefixParser {
     units_vec: Vec<(String, UnitInfo)>,
 
     other_identifiers: HashMap<String, Span>,
+
+    reserved_identifiers: &'static [&'static str],
 }
 
 impl PrefixParser {
@@ -77,6 +79,7 @@ impl PrefixParser {
             units: HashMap::new(),
             units_vec: Vec::new(),
             other_identifiers: HashMap::new(),
+            reserved_identifiers: &["_", "ans"],
         }
     }
 
@@ -138,6 +141,10 @@ impl PrefixParser {
     }
 
     fn ensure_name_is_available(&self, name: &str, conflict_span: Span) -> Result<()> {
+        if self.reserved_identifiers.contains(&name) {
+            return Err(NameResolutionError::ReservedIdentifier(conflict_span));
+        }
+
         if let Some(original_span) = self.other_identifiers.get(name) {
             return Err(self.identifier_clash_error(name, conflict_span, *original_span));
         }