use crate::*; #[derive(Clone)] pub enum IntermediateToken { Word(IntermediateWord), PinnedAddress(Tracked), LabelDefinition(String), } #[derive(Clone)] pub struct IntermediateWord { pub value: usize, /// Width of the word in bits. pub width: u32, pub fields: Vec>, } #[derive(Clone)] pub struct IntermediateField { pub value: Tracked, /// Width of the field in bits. pub width: u32, /// Number of bits to the right of the field in the word. pub shift: u32, } #[derive(Clone)] pub enum IntermediateInteger { Integer(isize), Expression(IntermediateExpression), LabelReference(Tracked), } #[derive(Clone)] pub struct IntermediateExpression { pub tokens: Vec>, } #[derive(Clone)] pub enum IntermediateExpressionToken { Integer(IntermediateInteger), Operator(Operator), } #[derive(Clone)] pub enum IntermediateValue { Integer(Tracked), Block(Vec>), } pub enum RepeatedArgument { Loop(IntermediateValue), List(Vec), } impl RepeatedArgument { pub fn len(&self) -> usize { match self { Self::Loop(_) => 1, Self::List(list) => list.len(), } } } pub enum IntermediateError { ExpectedInteger, ExpectedBlock, ListExhausted, LabelReferenceInConditionPredicate, LabelDefinitionInConditionBody, LabelReferenceInPinnedAddress, StackError(Tracked), InvocationBeforeDefinition, /// expected, received IncorrectArgumentCount(usize, usize), /// expected, received IncorrectArgumentType(ArgumentType, ArgumentType), } pub fn report_intermediate_errors(errors: &[Tracked], source_code: &str) { for error in errors { report_intermediate_error(error, source_code); } } fn report_intermediate_error(error: &Tracked, source_code: &str) { let context = Context { source_code: &source_code, source: &error.source }; let message = match &error.value { IntermediateError::ExpectedInteger => "An integer value was expected here", IntermediateError::ExpectedBlock => "A block value was expected here", IntermediateError::ListExhausted => "This string is shorter than another string passed to the same invocation", IntermediateError::LabelReferenceInConditionPredicate => "The predicate of a conditional block cannot contain a label reference", IntermediateError::LabelDefinitionInConditionBody => "The body of a conditional block cannot contain a label definition", IntermediateError::LabelReferenceInPinnedAddress => "The value of a pinned address cannot contain a label reference", IntermediateError::StackError(stack_error) => { report_stack_error(stack_error, source_code); return; }, IntermediateError::InvocationBeforeDefinition => &format!("Macro cannot be invoked before it has been defined"), IntermediateError::IncorrectArgumentCount(expected, received) => &format!("Expected {expected} arguments, but received {received} instead"), IntermediateError::IncorrectArgumentType(expected, received) => &format!("Expected {expected} value but received {received} value instead"), }; report_source_issue(LogLevel::Error, &context, message); } pub fn print_intermediate_token(i: usize, token: &IntermediateToken) { match token { IntermediateToken::Word(word) => { indent!(i, "Word({:>0w$b})", word.value, w = word.width as usize); for field in &word.fields { print_intermediate_integer(i+1, &field.value.value); } } IntermediateToken::PinnedAddress(address) => indent!(i, "PinnedAddress({address})"), IntermediateToken::LabelDefinition(name) => indent!(i, "LabelDefinition({name})"), } } fn print_intermediate_integer(i: usize, integer: &IntermediateInteger) { match integer { IntermediateInteger::Integer(value) => indent!(i, "Integer({value})"), IntermediateInteger::LabelReference(name) => indent!(i, "LabelReference({name})"), IntermediateInteger::Expression(expression) => { indent!(i, "Expression"); for token in &expression.tokens { match &token.value { IntermediateExpressionToken::Integer(integer) => print_intermediate_integer(i+1, integer), IntermediateExpressionToken::Operator(operator) => indent!(i+1, "Operator({operator})"), } } } } }