diff options
Diffstat (limited to 'src/stages/intermediate_tokens.rs')
| -rw-r--r-- | src/stages/intermediate_tokens.rs | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/src/stages/intermediate_tokens.rs b/src/stages/intermediate_tokens.rs new file mode 100644 index 0000000..a09581e --- /dev/null +++ b/src/stages/intermediate_tokens.rs @@ -0,0 +1,149 @@ +use crate::*; + + +#[derive(Clone)] +pub enum IntermediateToken { + Word(IntermediateWord), + PinnedAddress(Tracked<usize>), + LabelDefinition(String), +} + +#[derive(Clone)] +pub struct IntermediateWord { + pub value: usize, + /// Width of the word in bits. + pub width: u32, + pub fields: Vec<Tracked<IntermediateField>>, +} + +#[derive(Clone)] +pub struct IntermediateField { + pub value: Tracked<IntermediateInteger>, + /// 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<String>), +} + +#[derive(Clone)] +pub struct IntermediateExpression { + pub tokens: Vec<Tracked<IntermediateExpressionToken>>, +} + +#[derive(Clone)] +pub enum IntermediateExpressionToken { + Integer(IntermediateInteger), + Operator(Operator), +} + +#[derive(Clone)] +pub enum IntermediateValue { + Integer(Tracked<IntermediateInteger>), + Block(Vec<Tracked<IntermediateToken>>), +} + +pub enum RepeatedArgument { + Loop(IntermediateValue), + List(Vec<IntermediateValue>), +} + +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<StackError>), + InvocationBeforeDefinition, + /// expected, received + IncorrectArgumentCount(usize, usize), + /// expected, received + IncorrectArgumentType(ArgumentType, ArgumentType), +} + +pub fn report_intermediate_errors(errors: &[Tracked<IntermediateError>], source_code: &str) { + for error in errors { + report_intermediate_error(error, source_code); + } +} + +fn report_intermediate_error(error: &Tracked<IntermediateError>, 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})"), + } + } + } + } +} |
