summaryrefslogtreecommitdiff
path: root/src/stages/intermediate.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/stages/intermediate.rs')
-rw-r--r--src/stages/intermediate.rs45
1 files changed, 26 insertions, 19 deletions
diff --git a/src/stages/intermediate.rs b/src/stages/intermediate.rs
index 6853f62..c28426c 100644
--- a/src/stages/intermediate.rs
+++ b/src/stages/intermediate.rs
@@ -88,6 +88,16 @@ impl IntermediateParser {
let tracked = Tracked::from(value, null.clone());
arguments.insert(argument.name.clone(), tracked);
}
+ // Register macro definition with empty body so that macro can invoke itself.
+ let name = definition.name.to_string();
+ let dummy_definition = MacroDefinition {
+ name: definition.name,
+ arguments: definition.arguments,
+ body: MacroDefinitionBody::Block(Vec::new()),
+ };
+ if self.macro_definitions.insert(name.clone(), dummy_definition).is_some() {
+ unreachable!("Uncaught duplicate macro definition '{}'", name);
+ }
let mut env = Environment {
label_names: &self.label_names,
macro_names: &self.macro_names,
@@ -100,10 +110,9 @@ impl IntermediateParser {
if self.errors.len() != error_count {
break;
}
-
- let name = definition.name.to_string();
- if self.macro_definitions.insert(name.clone(), definition).is_some() {
- unreachable!("Uncaught duplicate macro definition '{}'", name);
+ // Replace dummy macro body with original macro body.
+ if let Some(registered) = self.macro_definitions.get_mut(&name) {
+ registered.body = definition.body;
}
}
SemanticToken::BlockToken(block_token) => {
@@ -194,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) => {