aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mssola@mssola.com>2026-02-03 10:49:33 +0100
committerMiquel Sabaté Solà <mssola@mssola.com>2026-02-03 10:49:33 +0100
commit8b38c88ae55a6edf1028a5aa57b93afdbc4001d6 (patch)
treedd7f8a8c369000d6579a8dd20497ab20d93f1c9c /lib
parent948ad7f2bda3495faebf39d1bb903f863e9ad596 (diff)
downloadtools.nes-8b38c88ae55a6edf1028a5aa57b93afdbc4001d6.tar.gz
tools.nes-8b38c88ae55a6edf1028a5aa57b93afdbc4001d6.zip
Avoid invalid identifiers in proc/macro/scope
This was apparently neglected and you were able to pick invalid identifiers to identify procs, macros and scopes. Ensure this does not happen again and provide tests for it. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/xixanta/src/assembler.rs65
1 files changed, 58 insertions, 7 deletions
diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs
index cb992d4..136d416 100644
--- a/lib/xixanta/src/assembler.rs
+++ b/lib/xixanta/src/assembler.rs
@@ -588,12 +588,25 @@ impl<'a> Assembler<'a> {
// illegal definitions.
self.macros_seen += 1;
- // Insert a reference to this node so it can be
- // unrolled whenever we have to perform a macro
- // call.
- self.macros
- .entry(node.left.as_ref().unwrap().value.value.clone())
- .or_insert(node);
+ let name = &node.left.as_ref().unwrap().value;
+ if let Err(e) = name.is_valid_identifier(false) {
+ errors.push(Error {
+ message: format!(
+ "'{}' is not a valid macro name: {e}",
+ name.value
+ ),
+ line: node.value.line,
+ global: false,
+ expanded_from: self.macro_context.clone(),
+ source: self.source_for(node),
+ });
+ continue;
+ } else {
+ // Insert a reference to this node so it can be
+ // unrolled whenever we have to perform a macro
+ // call.
+ self.macros.entry(name.value.clone()).or_insert(node);
+ }
}
ControlType::EndMacro => {
if self.macros_seen > 0 {
@@ -616,7 +629,19 @@ impl<'a> Assembler<'a> {
self.procs_seen += 1;
let proc_name = &node.left.as_ref().unwrap();
- if let Err(err) = self.define_variable(proc_name) {
+ if let Err(err) = proc_name.value.is_valid_identifier(false) {
+ errors.push(Error {
+ message: format!(
+ "'{}' is not a valid proc name: {err}",
+ proc_name.value.value,
+ ),
+ line: node.value.line,
+ global: false,
+ expanded_from: self.macro_context.clone(),
+ source: self.source_for(node),
+ });
+ continue;
+ } else if let Err(err) = self.define_variable(proc_name) {
errors.push(err);
}
}
@@ -638,6 +663,20 @@ impl<'a> Assembler<'a> {
});
continue;
}
+ let scope_name = &node.left.as_ref().unwrap();
+ if let Err(err) = scope_name.value.is_valid_identifier(false) {
+ errors.push(Error {
+ message: format!(
+ "'{}' is not a valid scope name: {err}",
+ scope_name.value.value,
+ ),
+ line: node.value.line,
+ global: false,
+ expanded_from: self.macro_context.clone(),
+ source: self.source_for(node),
+ });
+ continue;
+ }
}
ControlType::StartRepeat => {
self.repeats_seen += 1;
@@ -4758,6 +4797,18 @@ MACRO Var1
}
#[test]
+ fn bad_macro_name() {
+ assert_error(
+ r#".macro __fallthrough__ arg
+ .endmacro
+ "#,
+ 1,
+ false,
+ "'__fallthrough__' is not a valid macro name: cannot use reserved name '__fallthrough__'",
+ );
+ }
+
+ #[test]
fn bad_scope_definition_inside_of_proc() {
assert_error(
r#".proc Hey