diff options
| author | Miquel Sabaté Solà <mikisabate@gmail.com> | 2024-12-23 15:45:49 +0100 |
|---|---|---|
| committer | Miquel Sabaté Solà <mikisabate@gmail.com> | 2024-12-23 15:45:49 +0100 |
| commit | 31ac0e214d43da3bb705c8f345f5afcb922cefac (patch) | |
| tree | 23234809c26a0e0bce208436328ca5f991576047 /lib/xixanta/src/assembler.rs | |
| parent | 4115d83eb537ffbd81e2fd8d12790a8fad769199 (diff) | |
| download | tools.nes-31ac0e214d43da3bb705c8f345f5afcb922cefac.tar.gz tools.nes-31ac0e214d43da3bb705c8f345f5afcb922cefac.zip | |
Make more explicit segment/macros are only global
Force .segment and .macro statements to be on the global scope since
this is how they are meant. Hence, if the programmer tries to do this,
just error out.
Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
Diffstat (limited to 'lib/xixanta/src/assembler.rs')
| -rw-r--r-- | lib/xixanta/src/assembler.rs | 61 |
1 files changed, 40 insertions, 21 deletions
diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs index d24a555..42842a7 100644 --- a/lib/xixanta/src/assembler.rs +++ b/lib/xixanta/src/assembler.rs @@ -1,4 +1,4 @@ -use crate::errors::{ContextError, Error, EvalError}; +use crate::errors::{ContextError, ContextErrorReason, Error, EvalError}; use crate::mapping::Mapping; use crate::node::{ControlType, NodeType, OperationType, PNode, PString}; use crate::object::{Bundle, Context, Object, ObjectType}; @@ -44,7 +44,7 @@ pub enum Stage { } #[derive(Clone, Debug)] -pub struct Macro { +pub struct CodeBlock { nodes: Range<usize>, args: Vec<PString>, } @@ -63,7 +63,7 @@ pub struct Assembler { context: Context, literal_mode: Option<LiteralMode>, stage: Stage, - macros: HashMap<String, Macro>, + macros: HashMap<String, CodeBlock>, can_bundle: bool, mappings: Vec<Mapping>, current_mapping: usize, @@ -207,21 +207,29 @@ impl Assembler { } } NodeType::Control(control_type) => { + if !self.context.is_global() && control_type.must_be_global() { + errors.push(Error::Context(ContextError { + message: format!("{} must be on the global scope", control_type), + line: node.value.line, + global: false, + reason: ContextErrorReason::BadScope, + })); + 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 => { - // TODO: macros are only on the global scope. - // // TODO: boy this is ugly. In fact, this stupid shit if // current_macro might not be relevant anymore. current_macro = Some(&node.left.as_ref().unwrap().value); // TODO: watch out for weird shit on the name of arguments. self.macros .entry(node.left.as_ref().unwrap().value.value.clone()) - .or_insert(Macro { + .or_insert(CodeBlock { nodes: Range { start: idx + 1, end: idx + 1, @@ -1239,19 +1247,6 @@ impl Assembler { }); } - // You cannot change the segment if you are not in the global context. - if !self.context.is_global() { - return Err(EvalError { - line: node.value.line, - message: format!( - "cannot switch to segment '{}' if we are still inside of a scope ('{}')", - name, - self.context.name() - ), - global: false, - }); - } - // Find the segment being referenced and update the // `self.current_segment` accordingly. let mut found = false; @@ -2917,6 +2912,31 @@ WRITE_PPU_DATA $20B9, $04 assert_eq!(res[6].bytes[2], 0x20); } + #[test] + fn start_macro_inside_of_scope() { + 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#".scope Some +.macro WRITE_PPU_DATA + bit $2002 +.endmacro +.endscope +"# + .as_bytes(), + ) + .unwrap_err(); + + assert_eq!( + res.first().unwrap().to_string(), + ".macro must be on the global scope (line 2)" + ); + } + // Segments #[test] @@ -3153,8 +3173,7 @@ code: assert_eq!( res.first().unwrap().to_string(), - "cannot switch to segment 'CODE' \ - if we are still inside of a scope ('Vars') (line 3)" + ".segment must be on the global scope (line 3)" ); } |
