aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta/src/assembler.rs
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2024-12-23 16:30:38 +0100
committerMiquel Sabaté Solà <mikisabate@gmail.com>2024-12-23 16:30:38 +0100
commitbbf91bf3abaff31231763352af405a2c22061c90 (patch)
tree0aaa781f6009580cf102c2b09334e67acb2c545c /lib/xixanta/src/assembler.rs
parent2f40bc30185027a125f782e52b65bc65f1c37b9b (diff)
downloadtools.nes-bbf91bf3abaff31231763352af405a2c22061c90.tar.gz
tools.nes-bbf91bf3abaff31231763352af405a2c22061c90.zip
Prevent missplaced start for procs and scopes
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
Diffstat (limited to 'lib/xixanta/src/assembler.rs')
-rw-r--r--lib/xixanta/src/assembler.rs89
1 files changed, 85 insertions, 4 deletions
diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs
index 000f809..ba06abe 100644
--- a/lib/xixanta/src/assembler.rs
+++ b/lib/xixanta/src/assembler.rs
@@ -219,10 +219,6 @@ impl Assembler {
continue;
}
- // TODO: prevent nesting of control statements depending on
- // a definition (e.g. .macro's cannot be nested inside of
- // another control statement, but .if yes).
-
match control_type {
ControlType::StartMacro => {
macro_seen += 1;
@@ -255,6 +251,7 @@ impl Assembler {
global: false,
reason: ContextErrorReason::BadEnd,
}));
+ continue;
}
macro_seen -= 1;
@@ -267,6 +264,16 @@ impl Assembler {
}
// Same as NodeType::Label.
ControlType::StartProc => {
+ if macro_seen > 0 || proc_seen > 0 {
+ errors.push(Error::Context(ContextError {
+ message: "you cannot call '.proc' in this context".to_string(),
+ line: node.value.line,
+ global: false,
+ reason: ContextErrorReason::BadStart,
+ }));
+ continue;
+ }
+
proc_seen += 1;
let proc_name = &node.left.as_ref().unwrap().value;
if let Err(err) = self.define_variable(proc_name) {
@@ -281,10 +288,20 @@ impl Assembler {
global: false,
reason: ContextErrorReason::BadEnd,
}));
+ continue;
}
proc_seen -= 1;
}
ControlType::StartScope => {
+ if macro_seen > 0 || proc_seen > 0 {
+ errors.push(Error::Context(ContextError {
+ message: "you cannot call '.scope' in this context".to_string(),
+ line: node.value.line,
+ global: false,
+ reason: ContextErrorReason::BadStart,
+ }));
+ continue;
+ }
scope_seen += 1;
}
ControlType::EndScope => {
@@ -3032,6 +3049,70 @@ WRITE_PPU_DATA $20B9, $04
);
}
+ #[test]
+ fn bad_scope_definition_inside_of_stuff() {
+ let mut asm = Assembler::new(empty());
+ asm.mappings[0].segments[0].bundles = minimal_header();
+ asm.mappings[0].offset = 6;
+ asm.current_mapping = 1;
+ let res = &asm
+ .assemble(
+ std::env::current_dir().unwrap().to_path_buf(),
+ r#".proc Hey
+.scope Something
+.endscope
+.endproc
+.macro HAHA
+.scope Something_else
+.endscope
+.endmacro
+"#
+ .as_bytes(),
+ )
+ .unwrap_err();
+
+ assert_eq!(
+ res[0].to_string(),
+ "you cannot call '.scope' in this context (line 2)"
+ );
+ assert_eq!(
+ res[3].to_string(),
+ "you cannot call '.scope' in this context (line 6)"
+ );
+ }
+
+ #[test]
+ fn bad_proc_definition_inside_of_stuff() {
+ let mut asm = Assembler::new(empty());
+ asm.mappings[0].segments[0].bundles = minimal_header();
+ asm.mappings[0].offset = 6;
+ asm.current_mapping = 1;
+ let res = &asm
+ .assemble(
+ std::env::current_dir().unwrap().to_path_buf(),
+ r#".proc Hey
+.proc Something
+.endproc
+.endproc
+.macro HAHA
+.proc Something_else
+.endproc
+.endmacro
+"#
+ .as_bytes(),
+ )
+ .unwrap_err();
+
+ assert_eq!(
+ res[0].to_string(),
+ "you cannot call '.proc' in this context (line 2)"
+ );
+ assert_eq!(
+ res[2].to_string(),
+ "you cannot call '.proc' in this context (line 6)"
+ );
+ }
+
// Segments
#[test]