From 75018f1ec69162a0695e603030f5e1a5cc105af0 Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Fri, 18 Apr 2025 20:47:47 +1200 Subject: Allow a macro to invoke itself safely A macro can now invoke itself if the invocation is inside a conditional block that will eventually return false. The assembler stack can still overflow if the macro recurses too deeply, or if a macro calls itself without a conditional block. --- src/stages/intermediate.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/stages/intermediate.rs b/src/stages/intermediate.rs index ca17aa0..c28426c 100644 --- a/src/stages/intermediate.rs +++ b/src/stages/intermediate.rs @@ -203,28 +203,26 @@ impl<'a> Environment<'a> { } } BlockToken::ConditionalBlock(cond) => { - let predicate = self.parse_integer_token(&cond.predicate, &cond.predicate.source); - let mut body = self.parse_block_token(&cond.body, &cond.body.source); - if let Some(predicate) = predicate { - let mut found_error = false; + if let Some(predicate) = self.parse_integer_token(&cond.predicate, &cond.predicate.source) { if let Some(source) = integer_contains_label_reference(&predicate) { let error = IntermediateError::LabelReferenceInConditionPredicate; let new_source = cond.predicate.source.clone().wrap(source); self.errors.push(Tracked::from(error, new_source)); - found_error = true; - }; - if let Some(source) = block_contains_label_definition(&cond.body, &cond.body.source) { - let error = IntermediateError::LabelDefinitionInConditionBody; - let new_source = cond.body.source.clone().wrap(source); - self.errors.push(Tracked::from(error, new_source)); - found_error = true; - } - if !found_error { + } else { match evaluate_integer(&predicate, &cond.predicate.source) { - Ok(value) => if value != 0 { intermediate.append(&mut body) }, + Ok(value) => if value != 0 { + let mut body = self.parse_block_token(&cond.body, &cond.body.source); + if let Some(source) = block_contains_label_definition(&cond.body, &cond.body.source) { + let error = IntermediateError::LabelDefinitionInConditionBody; + let new_source = cond.body.source.clone().wrap(source); + self.errors.push(Tracked::from(error, new_source)); + } else { + intermediate.append(&mut body); + } + }, Err(error) => self.errors.push(error), } - } + }; } } BlockToken::WordTemplate(word_template) => { -- cgit v1.2.3-70-g09d2