summaryrefslogtreecommitdiff
path: root/src/stages
diff options
context:
space:
mode:
Diffstat (limited to 'src/stages')
-rw-r--r--src/stages/bytecode.rs6
-rw-r--r--src/stages/intermediate.rs45
-rw-r--r--src/stages/syntactic.rs6
-rw-r--r--src/stages/syntactic_tokens.rs3
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);