diff options
Diffstat (limited to 'src/stages')
-rw-r--r-- | src/stages/bytecode.rs | 6 | ||||
-rw-r--r-- | src/stages/intermediate.rs | 45 | ||||
-rw-r--r-- | src/stages/syntactic.rs | 6 | ||||
-rw-r--r-- | src/stages/syntactic_tokens.rs | 3 |
4 files changed, 36 insertions, 24 deletions
diff --git a/src/stages/bytecode.rs b/src/stages/bytecode.rs index e4464a1..1d27b28 100644 --- a/src/stages/bytecode.rs +++ b/src/stages/bytecode.rs @@ -162,11 +162,7 @@ impl BytecodeParser { *value } }; - let value_width = match field_value.cmp(&0) { - std::cmp::Ordering::Less => (-field_value).ilog2() + 2, - std::cmp::Ordering::Equal => 0, - std::cmp::Ordering::Greater => field_value.ilog2() + 1, - }; + let value_width = width(field_value); if field.width < value_width { let error = BytecodeError::ValueTooWide(field.width, value_width); self.errors.push(Tracked::from(error, field_source.clone())); 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) => { diff --git a/src/stages/syntactic.rs b/src/stages/syntactic.rs index 45d5e60..a1ba833 100644 --- a/src/stages/syntactic.rs +++ b/src/stages/syntactic.rs @@ -184,6 +184,12 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser) -> Result<Vec<Tracked<Syntac Ok(value) => SyntacticToken::IntegerLiteral(value), Err(_) => err!(SyntacticError::InvalidBinaryLiteral(binary_string)), } + } else if let Some(octal_string) = stripped.strip_prefix("0o") { + let octal_string = octal_string.to_string(); + match parse_integer_literal(&octal_string, 8, neg) { + Ok(value) => SyntacticToken::IntegerLiteral(value), + Err(_) => err!(SyntacticError::InvalidOctalLiteral(octal_string)), + } } else { let decimal_string = stripped.to_string(); match parse_integer_literal(&decimal_string, 10, neg) { diff --git a/src/stages/syntactic_tokens.rs b/src/stages/syntactic_tokens.rs index 041c568..5bfa0be 100644 --- a/src/stages/syntactic_tokens.rs +++ b/src/stages/syntactic_tokens.rs @@ -70,6 +70,7 @@ pub enum SyntacticError { InvalidDecimalLiteral(String), InvalidHexadecimalLiteral(String), InvalidBinaryLiteral(String), + InvalidOctalLiteral(String), } @@ -118,6 +119,8 @@ fn report_syntactic_error(error: &Tracked<SyntacticError>, source_code: &str) { &format!("The string '{string}' is not a valid hexadecimal literal"), SyntacticError::InvalidBinaryLiteral(string) => &format!("The string '{string}' is not a valid binary literal"), + SyntacticError::InvalidOctalLiteral(string) => + &format!("The string '{string}' is not a valid octal literal"), }; report_source_issue(LogLevel::Error, &context, message); |