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.rs626
1 files changed, 307 insertions, 319 deletions
diff --git a/src/stages/intermediate.rs b/src/stages/intermediate.rs
index cfe33b7..7523baf 100644
--- a/src/stages/intermediate.rs
+++ b/src/stages/intermediate.rs
@@ -1,163 +1,170 @@
use crate::*;
-use assembler::{DefinitionType, SourceLocation, SourcePosition, SymbolRole};
-
use indexmap::{IndexSet, IndexMap};
-static mut ID: usize = 0;
-macro_rules! next_id { () => { unsafe { let id = ID; ID += 1; id }}; }
+static mut ENVIRONMENT_ID: usize = 0;
+macro_rules! next_id {
+ () => {
+ unsafe {
+ let id = ENVIRONMENT_ID;
+ ENVIRONMENT_ID += 1;
+ id
+ }
+ };
+}
+
+pub struct LabelAddress {
+ pub previous: usize,
+ pub current: usize,
+ pub touched: bool,
+}
+
+#[derive(Eq, Hash, PartialEq, Clone)]
+pub struct SymbolSignature {
+ pub name: String,
+ pub arg_count: usize,
+}
+
+impl std::fmt::Display for SymbolSignature {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+ write!(f, "{}::{}", self.name, self.arg_count)
+ }
+}
+
+struct Environment {
+ arguments: IndexMap<String, Tracked<IntermediateValue>>,
+ id: usize,
+}
+
pub fn parse_intermediate(semantic: Vec<Tracked<SemanticToken>>) -> Result<Vec<Tracked<IntermediateToken>>, Vec<Tracked<IntermediateError>>> {
IntermediateParser::new(semantic).parse()
}
-
struct IntermediateParser {
semantic: Vec<Tracked<SemanticToken>>,
- label_names: IndexSet<Tracked<String>>,
- macro_names: IndexSet<Tracked<String>>,
- macro_definitions: IndexMap<String, MacroDefinition>,
+ label_names: IndexSet<Tracked<SymbolSignature>>,
+ label_addresses: IndexMap<Tracked<String>, LabelAddress>,
+ macro_definitions: IndexMap<SymbolSignature, Tracked<MacroDefinition>>,
+ environment_stack: Vec<Environment>,
+ address: usize,
intermediate: Vec<Tracked<IntermediateToken>>,
errors: Vec<Tracked<IntermediateError>>,
}
impl IntermediateParser {
- pub fn new(semantic: Vec<Tracked<SemanticToken>>) -> Self {
+ /// Initialise a new parser.
+ pub fn new(mut semantic: Vec<Tracked<SemanticToken>>) -> Self {
+ // Collect all label and macro definitions ahead of time.
let mut label_names = IndexSet::new();
- let mut macro_names = IndexSet::new();
+ let mut macro_definitions = IndexMap::new();
+ // Get the signatures of all defined labels.
for symbol in SymbolParser::new().parse(&semantic) {
- match symbol.role {
- SymbolRole::Definition(DefinitionType::MustPrecedeReference) => {
- // Only consider macro definitions, not macro argument definitions.
- if symbol.namespace.is_empty() {
- if !macro_names.insert(Tracked::from(symbol.name.clone(), symbol.source)) {
- unreachable!("Uncaught duplicate macro definition '{}'", symbol.name);
- }
- }
- }
- SymbolRole::Definition(DefinitionType::CanFollowReference) => {
- if !label_names.insert(Tracked::from(symbol.name.clone(), symbol.source)) {
- unreachable!("Uncaught duplicate label definition '{}'", symbol.name);
- }
+ if let SymbolRoleDetailed::LabelDefinition = symbol.role {
+ let signature = SymbolSignature { name: symbol.name.clone(), arg_count: symbol.arg_count };
+ if !label_names.insert(Tracked::from(signature.clone(), symbol.source)) {
+ unreachable!("Uncaught duplicate label definition '{signature}'");
}
- SymbolRole::Reference => (),
}
}
-
+ // Strip all semantic macro definitions from the semantic tokens.
+ let definitions = semantic.extract_if(..,
+ |t| if let SemanticToken::MacroDefinition(_) = t.value { true } else { false });
+ for definition in definitions {
+ let source = definition.source;
+ let SemanticToken::MacroDefinition(definition) = definition.value else { unreachable!() };
+ let name = definition.name.value.clone();
+ let arg_count = definition.arguments.len();
+ let signature = SymbolSignature { name, arg_count };
+ if macro_definitions.insert(signature.clone(), Tracked::from(definition, source)).is_some() {
+ unreachable!("Uncaught duplicate macro definition '{signature}'")
+ }
+ }
Self {
semantic,
label_names,
- macro_names,
- macro_definitions: IndexMap::new(),
+ label_addresses: IndexMap::new(),
+ macro_definitions,
+ environment_stack: Vec::new(),
+ address: 0,
intermediate: Vec::new(),
errors: Vec::new(),
}
}
pub fn parse(mut self) -> Result<Vec<Tracked<IntermediateToken>>, Vec<Tracked<IntermediateError>>> {
- for token in self.semantic {
- let source = &token.source;
- match token.value {
- SemanticToken::MacroDefinition(definition) => {
- // Invoke the body to see if it contains undefined macros.
- let error_count = self.errors.len();
- let mut arguments = IndexMap::new();
- // Prepare dummy argument values.
- let null = SourceSpan {
- string: String::new(),
- in_merged: SourceLocation {
- path: None,
- start: SourcePosition::ZERO,
- end: SourcePosition::ZERO,
- },
- in_source: None,
- child: None,
- };
- for argument in &definition.arguments {
- let value = match argument.variant {
- ArgumentType::Integer => {
- let integer = IntermediateInteger::Integer(0);
- let tracked = Tracked::from(integer, null.clone());
- IntermediateValue::Integer(tracked)
- }
- ArgumentType::Block => {
- IntermediateValue::Block(Vec::new())
- }
- ArgumentType::String => {
- let string = String::new();
- let chars = Vec::new();
- let literal = StringLiteral { string, chars };
- let tracked = Tracked::from(literal, null.clone());
- IntermediateValue::String(tracked)
- }
- };
- 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,
- macro_definitions: &self.macro_definitions,
- arguments,
- errors: &mut self.errors,
- id: next_id!(),
- };
- env.parse_macro_definition_body(&definition.body, source);
- if self.errors.len() != error_count {
- break;
- }
- // 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) => {
- let mut env = Environment {
- label_names: &self.label_names,
- macro_names: &self.macro_names,
- macro_definitions: &self.macro_definitions,
- arguments: IndexMap::new(),
- errors: &mut self.errors,
- id: next_id!(),
- };
- let mut tokens = env.parse_block_token(&block_token, source);
- self.intermediate.append(&mut tokens);
- }
+ let semantic = std::mem::take(&mut self.semantic);
+
+ for i in 0..MAX_ITERATIONS_TO_STABILISE {
+ info!("Attempting iteration {} of intermediate assembly stage", i+1);
+ // Erase the previous parse attempt.
+ self.address = 0;
+ self.intermediate.clear();
+ self.errors.clear();
+ self.environment_stack.clear();
+ unsafe { ENVIRONMENT_ID = 0; }
+ // Update label addresses.
+ for (_, address) in &mut self.label_addresses {
+ address.previous = address.current;
+ address.touched = false;
}
+ // Attempt to parse the program (which is now all block tokens).
+ for token in &semantic {
+ let source = &token.source;
+ let SemanticToken::BlockToken(ref block_token) = token.value else { unreachable!() };
+ let env = Environment { arguments: IndexMap::new(), id: next_id!() };
+ self.environment_stack.push(env);
+ let mut tokens = self.parse_block_token(&block_token, source);
+ self.intermediate.append(&mut tokens);
+ }
+ // Return unrecoverable errors.
+ if !self.errors.is_empty() {
+ return Err(self.errors);
+ }
+ // Check label stability
+ if self.check_for_instability(false) {
+ continue;
+ }
+ // Program is stable, return.
+ info!("Stabilised in iteration {} of intermediate assembly stage", i+1);
+ return Ok(self.intermediate);
}
- match self.errors.is_empty() {
- true => Ok(self.intermediate),
- false => Err(self.errors),
- }
+
+ self.check_for_instability(true);
+ return Err(self.errors);
}
-}
+ /// Check if any label is still stabilising.
+ fn check_for_instability(&mut self, create_error: bool) -> bool {
+ for (name, address) in &self.label_addresses {
+ if address.touched && address.current != address.previous {
+ info!("Label '{name}' was unstable, moving from address 0x{:04x} to 0x{:04x}",
+ address.previous, address.current);
+ if create_error {
+ let error = IntermediateError::LabelNeverStabilised(name.to_string());
+ self.errors.push(Tracked::from(error, name.source.clone()));
+ }
+ return true;
+ }
+ }
+ return false;
+ }
-struct Environment<'a> {
- label_names: &'a IndexSet<Tracked<String>>,
- macro_names: &'a IndexSet<Tracked<String>>,
- macro_definitions: &'a IndexMap<String, MacroDefinition>,
- arguments: IndexMap<String, Tracked<IntermediateValue>>,
- errors: &'a mut Vec<Tracked<IntermediateError>>,
- id: usize,
-}
+ /// Get the current environment (the environment at the top of the stack).
+ fn env(&self) -> &Environment {
+ self.environment_stack.last().unwrap_or_else(||
+ unreachable!("No environment on the stack"))
+ }
-impl<'a> Environment<'a> {
- // Attach the invocation ID to every macro label name
+ // Attach the environment ID to a local label name.
fn tag_name(&self, name: &str) -> String {
+ // If a local label belongs to a macro, the name of that macro
+ // has been prefixed with the local label name in the
+ // resolve_label_name method during the semantic parsing stage,
+ // using a ':' character as a separator.
match name.contains(':') {
- true => format!("{name}:{}", self.id),
+ true => format!("{name}:{}", self.env().id),
false => name.to_string(),
}
}
@@ -166,7 +173,7 @@ impl<'a> Environment<'a> {
match &body {
MacroDefinitionBody::Integer(integer) => {
let token = self.parse_integer_token(&integer, &source)?;
- let integer = IntermediateValue::Integer(token);
+ let integer = IntermediateValue::Integer(token.value);
Some(Tracked::from(integer, source.clone()))
}
MacroDefinitionBody::Invocation(invocation) => {
@@ -180,9 +187,9 @@ impl<'a> Environment<'a> {
let value = IntermediateValue::Block(tokens);
Some(Tracked::from(value, source.clone()))
}
- MacroDefinitionBody::String(string) => {
- let string = self.parse_string_token(string, &source)?;
- let integer = IntermediateValue::String(string);
+ MacroDefinitionBody::List(list) => {
+ let list = self.parse_list_token(list, &source)?;
+ let integer = IntermediateValue::List(list.value);
Some(Tracked::from(integer, source.clone()))
}
}
@@ -192,60 +199,77 @@ impl<'a> Environment<'a> {
let mut intermediate = Vec::new();
match block {
BlockToken::LabelDefinition(name) => {
- let token = IntermediateToken::LabelDefinition(self.tag_name(name));
- intermediate.push(Tracked::from(token, source.clone()));
+ let signature = SymbolSignature { name: name.to_string(), arg_count: 0 };
+ if !self.label_names.contains(&signature) {
+ unreachable!("Unrecognised name for label definition");
+ }
+ let tagged_name = self.tag_name(name);
+ let tracked = Tracked::from(tagged_name.clone(), source.clone());
+ self.label_addresses.entry(tracked)
+ .and_modify(|a| {
+ if a.touched { unreachable!("Label '{tagged_name}' was already touched during this cycle.") }
+ a.previous = a.current;
+ a.current = self.address;
+ a.touched = true;
+ })
+ .or_insert(LabelAddress {
+ previous: 0,
+ current: self.address,
+ touched: true,
+ });
}
- BlockToken::PinnedAddress(address) => {
- if let Some(integer) = self.parse_integer_token(address, &address.source) {
- let token = IntermediateToken::PinnedAddress(integer);
+ BlockToken::PinnedAddress(integer) => {
+ if let Some(pinned) = self.parse_integer_token(integer, &integer.source) {
+ let pinned = **pinned as usize;
+ if pinned < self.address {
+ let error = IntermediateError::PinnedAddressBacktrack(pinned, self.address);
+ self.errors.push(Tracked::from(error, source.clone()));
+ }
+ self.address = pinned;
+ let token = IntermediateToken::PinnedAddress(pinned);
intermediate.push(Tracked::from(token, source.clone()));
}
}
BlockToken::ConditionalBlock(cond) => {
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));
- } else {
- match evaluate_integer(&predicate, &cond.predicate.source) {
- 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),
+ if **predicate != 0 {
+ if let Some(label_source) = block_contains_label_definition(&cond.body, &cond.body.source) {
+ let error = IntermediateError::LabelDefinitionInConditionBody;
+ let new_source = cond.body.source.clone().wrap(label_source);
+ self.errors.push(Tracked::from(error, new_source));
+ } else {
+ let mut body = self.parse_block_token(&cond.body, &cond.body.source);
+ intermediate.append(&mut body);
}
- };
+ }
}
}
BlockToken::WordTemplate(word_template) => {
- let mut fields = Vec::new();
- for bit_field in &word_template.fields {
- let name = bit_field.name.to_string();
- let source = &bit_field.source;
+ let word_width = word_template.width;
+ let mut word_value = word_template.value;
+ for field in &word_template.fields {
+ let name = field.name.to_string();
+ let field_source = &field.source;
let invocation = Invocation { name, arguments: Vec::new() };
- if let Some(value) = self.parse_integer_invocation(&invocation, source) {
- let field = IntermediateField {
- width: bit_field.width,
- shift: bit_field.shift,
- value,
- };
- fields.push(Tracked::from(field, bit_field.source.clone()));
+ if let Some(result) = self.parse_integer_invocation(&invocation, field_source) {
+ let field_value = **result;
+ // Inject field value into real value.
+ let value_width = width(field_value);
+ if field.width < value_width {
+ let error = IntermediateError::ValueTooWide(field.width, value_width);
+ let new_source = field_source.wrap(result.source);
+ self.errors.push(Tracked::from(error, new_source));
+ } else {
+ let mask = 2_usize.pow(field.width as u32) - 1;
+ let clamped_value = (field_value as usize) & mask;
+ word_value |= (clamped_value << field.shift) as usize;
+ }
}
}
- let word = IntermediateWord {
- value: word_template.value,
- width: word_template.width,
- fields,
- };
+ let word = IntermediateWord { width: word_width, value: word_value };
let token = IntermediateToken::Word(word);
intermediate.push(Tracked::from(token, source.clone()));
+ self.address += 1;
}
BlockToken::Block(blocks) => {
for block in blocks {
@@ -259,15 +283,14 @@ impl<'a> Environment<'a> {
}
}
}
-
return intermediate;
}
fn parse_integer_token(&mut self, integer: &IntegerToken, source: &SourceSpan) -> Option<Tracked<IntermediateInteger>> {
match integer {
IntegerToken::IntegerLiteral(value) => {
- let integer = IntermediateInteger::Integer(*value);
- Some(Tracked::from(integer, source.clone()))
+ let tracked = Tracked::from(*value, source.clone());
+ Some(Tracked::from(tracked, source.clone()))
}
IntegerToken::Expression(expression) => {
self.parse_expression(expression, source)
@@ -278,45 +301,61 @@ impl<'a> Environment<'a> {
}
}
- fn parse_string_token(&mut self, string: &StringToken, source: &SourceSpan) -> Option<Tracked<StringLiteral>> {
- match string {
- StringToken::StringLiteral(literal) => {
- Some(Tracked::from(literal.clone(), source.clone()))
+ fn parse_list_token(&mut self, list: &ListToken, source: &SourceSpan) -> Option<Tracked<IntermediateList>> {
+ match list {
+ ListToken::StringLiteral(literal) => {
+ Some(Tracked::from(literal.chars.clone(), source.clone()))
}
- StringToken::Invocation(invocation) => {
- self.parse_string_invocation(&invocation, source)
+ ListToken::ListLiteral(literal) => {
+ let mut integers = Vec::new();
+ for token in literal {
+ let integer = self.parse_integer_token(&token.value, &token.source)?;
+ integers.push(integer.value);
+ }
+ Some(Tracked::from(integers, source.clone()))
+ }
+ ListToken::Invocation(invocation) => {
+ self.parse_list_invocation(&invocation, source)
}
}
}
fn parse_integer_invocation(&mut self, invocation: &Invocation, source: &SourceSpan) -> Option<Tracked<IntermediateInteger>> {
- match self.parse_invocation(invocation, source)?.value {
- IntermediateValue::Integer(integer) => Some(integer),
- IntermediateValue::Block(_) | IntermediateValue::String(_) => {
+ let result = self.parse_invocation(invocation, source)?;
+ match result.value {
+ IntermediateValue::Integer(integer) => {
+ let source = integer.source.clone();
+ Some(Tracked::from(integer, source))
+ }
+ IntermediateValue::Block(_) | IntermediateValue::List(_) => {
let error = IntermediateError::ExpectedInteger;
- self.errors.push(Tracked::from(error, source.clone()));
+ self.errors.push(Tracked::from(error, result.source));
None
}
}
}
fn parse_block_invocation(&mut self, invocation: &Invocation, source: &SourceSpan) -> Option<Vec<Tracked<IntermediateToken>>> {
- match self.parse_invocation(invocation, source)?.value {
+ let result = self.parse_invocation(invocation, source)?;
+ let source = result.source;
+ match result.value {
IntermediateValue::Block(tokens) => Some(tokens),
- IntermediateValue::Integer(_) | IntermediateValue::String(_) => {
+ IntermediateValue::Integer(_) | IntermediateValue::List(_) => {
let error = IntermediateError::ExpectedBlock;
- self.errors.push(Tracked::from(error, source.clone()));
+ self.errors.push(Tracked::from(error, source));
None
}
}
}
- fn parse_string_invocation(&mut self, invocation: &Invocation, source: &SourceSpan) -> Option<Tracked<StringLiteral>> {
- match self.parse_invocation(invocation, source)?.value {
- IntermediateValue::String(literal) => Some(literal),
+ fn parse_list_invocation(&mut self, invocation: &Invocation, source: &SourceSpan) -> Option<Tracked<IntermediateList>> {
+ let result = self.parse_invocation(invocation, source)?;
+ let source = result.source;
+ match result.value {
+ IntermediateValue::List(literal) => Some(Tracked::from(literal, source)),
IntermediateValue::Integer(_) | IntermediateValue::Block(_) => {
- let error = IntermediateError::ExpectedString;
- self.errors.push(Tracked::from(error, source.clone()));
+ let error = IntermediateError::ExpectedList;
+ self.errors.push(Tracked::from(error, source));
None
}
}
@@ -324,8 +363,13 @@ impl<'a> Environment<'a> {
fn parse_invocation(&mut self, invocation: &Invocation, source: &SourceSpan) -> Option<Tracked<IntermediateValue>> {
let received_count = invocation.arguments.len();
- if let Some(argument) = self.arguments.get(&invocation.name) {
- // This invocation is a macro argument
+ let signature = SymbolSignature {
+ name: invocation.name.clone(),
+ arg_count: invocation.arguments.len(),
+ };
+ if let Some(argument) = self.env().arguments.get(&invocation.name) {
+ // This invocation is a macro argument.
+ // Check that no arguments were provided.
if received_count != 0 {
let error = IntermediateError::IncorrectArgumentCount(0, received_count);
self.errors.push(Tracked::from(error, source.clone()));
@@ -333,21 +377,24 @@ impl<'a> Environment<'a> {
} else {
Some(argument.clone())
}
- } else if let Some(label_name) = self.label_names.get(&invocation.name) {
- // This invocation is a label reference
+ } else if let Some(label) = self.label_names.get(&signature) {
+ // This invocation is a label reference.
+ // Check that no arguments were provided.
if received_count != 0 {
let error = IntermediateError::IncorrectArgumentCount(0, received_count);
self.errors.push(Tracked::from(error, source.clone()));
None
} else {
- let name = self.tag_name(label_name);
- let tracked = Tracked::from(name, label_name.source.clone());
- let integer = IntermediateInteger::LabelReference(tracked);
- let tracked = Tracked::from(integer, source.clone());
- let value = IntermediateValue::Integer(tracked);
- Some(Tracked::from(value, source.clone()))
+ let tagged_name = self.tag_name(&signature.name);
+ let address = self.label_addresses.get(&tagged_name)
+ .and_then(|a| Some(a.current)).or(Some(0)).unwrap();
+ let tracked = Tracked::from(address as isize, label.source.clone());
+ let integer = IntermediateValue::Integer(tracked);
+ Some(Tracked::from(integer, source.clone()))
}
- } else if let Some(definition) = self.macro_definitions.get(&invocation.name) {
+ } else if let Some(definition) = self.macro_definitions.get(&signature) {
+ // This invocation is a macro reference.
+ let definition = definition.clone();
// Check that the correct number of arguments were provided.
let expected_count = definition.arguments.len();
if received_count != expected_count {
@@ -363,9 +410,9 @@ impl<'a> Environment<'a> {
arguments.push(received_value);
}
// Invoke the invocation multiple times.
- let repetitions = arguments.iter().map(|a| a.len()).max().unwrap_or(1);
+ let invocations = arguments.iter().map(|a| a.len()).max().unwrap_or(1);
let mut values = Vec::new();
- for i in 0..repetitions {
+ for i in 0..invocations {
// Construct an argument map for this invocation.
let mut argument_map = IndexMap::new();
for (a, argument) in arguments.iter().enumerate() {
@@ -392,16 +439,11 @@ impl<'a> Environment<'a> {
};
}
// Invoke the macro once.
- let mut env = Environment {
- label_names: &self.label_names,
- macro_names: &self.macro_names,
- macro_definitions: &self.macro_definitions,
- arguments: argument_map,
- errors: &mut self.errors,
- id: next_id!(),
- };
- // Save the result of this macro invocation.
- values.push(env.parse_macro_definition_body(&definition.body, source)?);
+ let env = Environment { arguments: argument_map, id: next_id!() };
+ self.environment_stack.push(env);
+ let result = self.parse_macro_definition_body(&definition.body, source);
+ self.environment_stack.pop().unwrap();
+ values.push(result?);
}
if values.len() == 1 {
// If the macro was invoked once, return the value.
@@ -412,7 +454,7 @@ impl<'a> Environment<'a> {
let mut block = Vec::new();
for value in values {
match value.value {
- IntermediateValue::Integer(_) | IntermediateValue::String(_) => {
+ IntermediateValue::Integer(_) | IntermediateValue::List(_) => {
let error = IntermediateError::ExpectedBlock;
self.errors.push(Tracked::from(error, value.source));
return None;
@@ -425,26 +467,21 @@ impl<'a> Environment<'a> {
Some(Tracked::from(IntermediateValue::Block(block), source.clone()))
}
}
- } else if let Some(macro_name) = self.macro_names.get(&invocation.name) {
- let error = IntermediateError::InvocationBeforeDefinition;
- let source = source.clone().wrap(macro_name.source.clone());
- self.errors.push(Tracked::from(error, source));
- None
} else {
- unreachable!("Uncaught unresolved reference '{}'", invocation.name);
+ unreachable!("Uncaught unresolved reference '{signature}'");
}
}
fn parse_invocation_argument(&mut self, argument: &Tracked<InvocationArgument>, expected_type: ArgumentType) -> Option<RepeatedArgument> {
let source = &argument.source;
let (received_value, received_type) = match &argument.value {
- InvocationArgument::StringToken(string) => {
- let string = self.parse_string_token(string, source)?;
- self.parse_invocation_string_argument(string, expected_type)?
+ InvocationArgument::ListToken(list) => {
+ let list = self.parse_list_token(list, source)?;
+ self.parse_invocation_list_argument(list, expected_type)?
}
InvocationArgument::IntegerToken(integer) => {
let tracked = self.parse_integer_token(&integer, &argument.source)?;
- let value = IntermediateValue::Integer(tracked);
+ let value = IntermediateValue::Integer(tracked.value);
(RepeatedArgument::Loop(value), ArgumentType::Integer)
}
InvocationArgument::BlockToken(block) => {
@@ -459,8 +496,8 @@ impl<'a> Environment<'a> {
(RepeatedArgument::Loop(value.value), ArgumentType::Integer),
IntermediateValue::Block(_) =>
(RepeatedArgument::Loop(value.value), ArgumentType::Block),
- IntermediateValue::String(string) =>
- self.parse_invocation_string_argument(string, expected_type)?
+ IntermediateValue::List(list) =>
+ self.parse_invocation_list_argument(Tracked::from(list, value.source), expected_type)?
}
}
};
@@ -472,100 +509,93 @@ impl<'a> Environment<'a> {
return Some(received_value);
}
- fn parse_invocation_string_argument(&mut self, string: Tracked<StringLiteral>, expected_type: ArgumentType) -> Option<(RepeatedArgument, ArgumentType)> {
+ fn parse_invocation_list_argument(&mut self, list: Tracked<IntermediateList>, expected_type: ArgumentType) -> Option<(RepeatedArgument, ArgumentType)> {
if let ArgumentType::Integer = expected_type {
let mut values = Vec::new();
- for c in &string.chars {
- let integer = IntermediateInteger::Integer(**c);
- let tracked = Tracked::from(integer, c.source.clone());
- values.push(IntermediateValue::Integer(tracked));
+ for value in &list.value {
+ values.push(IntermediateValue::Integer(value.clone()));
}
Some((RepeatedArgument::List(values), ArgumentType::Integer))
} else {
- let value = IntermediateValue::String(string);
- Some((RepeatedArgument::Loop(value), ArgumentType::String))
+ let value = IntermediateValue::List(list.value);
+ Some((RepeatedArgument::Loop(value), ArgumentType::List))
}
}
fn parse_expression(&mut self, expression: &Expression, source: &SourceSpan) -> Option<Tracked<IntermediateInteger>> {
- let mut intermediate = Vec::new();
- let mut error = false;
-
+ let mut stack = ExpressionStack::new();
for token in &expression.tokens {
let source = &token.source;
match &token.value {
- ExpressionToken::IntegerToken(integer) => {
- let Some(integer) = self.parse_integer_token(integer, source) else {
- error = true; continue;
- };
- let token = IntermediateExpressionToken::Integer(integer.value);
- intermediate.push(Tracked::from(token, integer.source));
+ ExpressionToken::IntegerToken(token) => {
+ let integer = self.parse_integer_token(token, source)?;
+ stack.push(IntermediateValue::Integer(integer.value));
}
- ExpressionToken::Operator(operator) => {
- let token = IntermediateExpressionToken::Operator(*operator);
- intermediate.push(Tracked::from(token, source.clone()));
+ ExpressionToken::ListToken(token) => {
+ let list = self.parse_list_token(token, source)?;
+ stack.push(IntermediateValue::List(list.value));
}
ExpressionToken::Invocation(invocation) => {
- let Some(integer) = self.parse_integer_invocation(invocation, source) else {
- error = true; continue;
- };
- let token = IntermediateExpressionToken::Integer(integer.value);
- intermediate.push(Tracked::from(token, integer.source));
+ if let Some(value) = self.parse_invocation(invocation, source) {
+ if let IntermediateValue::Block(_) = &value.value {
+ let error = IntermediateError::InvalidBlockInExpression;
+ let new_source = source.clone().wrap(value.source.clone());
+ self.errors.push(Tracked::from(error, new_source));
+ return None;
+ }
+ stack.push(value.value);
+ }
+ }
+ ExpressionToken::Operator(operator) => {
+ if let Err(expr_error) = stack.apply(*operator, source) {
+ let error = IntermediateError::ExpressionError(expr_error);
+ self.errors.push(Tracked::from(error, source.clone()));
+ return None;
+ }
}
}
}
-
- if error { return None; }
- let expression = IntermediateExpression { tokens: intermediate };
- let integer = IntermediateInteger::Expression(expression);
- Some(Tracked::from(integer, source.clone()))
+ match stack.pull_result() {
+ Ok(value) => {
+ let tracked = Tracked::from(value, source.clone());
+ Some(Tracked::from(tracked, source.clone()))
+ }
+ Err(expr_error) => {
+ let tracked = Tracked::from(expr_error, source.clone());
+ let error = IntermediateError::ExpressionError(tracked);
+ self.errors.push(Tracked::from(error, source.clone()));
+ None
+ }
+ }
}
}
+
macro_rules! return_some {
($option:expr) => {
if $option.is_some() { return $option; }
};
}
-fn integer_contains_label_reference(integer: &IntermediateInteger) -> Option<SourceSpan> {
- match integer {
- IntermediateInteger::Integer(_) => None,
- IntermediateInteger::LabelReference(label) => Some(label.source.clone()),
- IntermediateInteger::Expression(expr) => expression_contains_label_reference(expr),
- }
-}
-
-fn expression_contains_label_reference(expression: &IntermediateExpression) -> Option<SourceSpan> {
- for token in &expression.tokens {
- if let IntermediateExpressionToken::Integer(integer) = &token.value {
- if let Some(child) = integer_contains_label_reference(&integer) {
- return Some(token.source.clone().wrap(child));
- }
- }
- }
- return None;
-}
+// Check if a block token contains a label definition.
fn block_contains_label_definition(block: &BlockToken, source: &SourceSpan) -> Option<SourceSpan> {
match &block {
- BlockToken::LabelDefinition(_) => {
- return Some(source.clone());
- }
- BlockToken::Invocation(invocation) => {
- return_some!(invocation_contains_label_definition(invocation))
- }
- BlockToken::Block(blocks) => {
+ BlockToken::LabelDefinition(_) =>
+ return Some(source.clone()),
+ BlockToken::Invocation(invocation) =>
+ return_some!(invocation_contains_label_definition(invocation)),
+ BlockToken::Block(blocks) =>
for block in blocks {
return_some!(block_contains_label_definition(block, &block.source))
- }
- }
+ },
_ => (),
}
return None;
}
+// Check if the arguments passed to an invocation contain a label definition.
fn invocation_contains_label_definition(invocation: &Invocation) -> Option<SourceSpan> {
for argument in &invocation.arguments {
match &argument.value {
@@ -580,45 +610,3 @@ fn invocation_contains_label_definition(invocation: &Invocation) -> Option<Sourc
}
return None;
}
-
-fn evaluate_integer(integer: &IntermediateInteger, source: &SourceSpan) -> Result<isize, Tracked<IntermediateError>> {
- match integer {
- IntermediateInteger::Integer(value) => Ok(*value),
- IntermediateInteger::LabelReference(name) =>
- unreachable!("Uncaught label reference '{name}' in condition predicate or pinned address value"),
- IntermediateInteger::Expression(expr) => evaluate_expression(expr, source),
- }
-}
-
-fn evaluate_expression(expression: &IntermediateExpression, source: &SourceSpan) -> Result<isize, Tracked<IntermediateError>> {
- let mut stack = ExpressionStack::new();
- for token in &expression.tokens {
- let source = &token.source;
- match &token.value {
- IntermediateExpressionToken::Integer(integer) => match integer {
- IntermediateInteger::Integer(value) => {
- stack.push(*value);
- }
- IntermediateInteger::Expression(expression) => {
- stack.push(evaluate_expression(&expression, source)?);
- }
- IntermediateInteger::LabelReference(name) => {
- unreachable!("Uncaught label reference '{name}' in condition predicate");
- }
- }
- IntermediateExpressionToken::Operator(operator) => {
- if let Err(stack_error) = stack.apply(*operator, source) {
- let error = IntermediateError::StackError(stack_error);
- return Err(Tracked::from(error, token.source.clone()));
- }
- }
- }
- }
- match stack.pull_result() {
- Ok(value) => Ok(value),
- Err(err) => {
- let error = Tracked::from(err, source.clone());
- Err(Tracked::from(IntermediateError::StackError(error), source.clone()))
- }
- }
-}