summaryrefslogtreecommitdiff
path: root/src/stages/intermediate_tokens.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/stages/intermediate_tokens.rs')
-rw-r--r--src/stages/intermediate_tokens.rs149
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})"),
+ }
+ }
+ }
+ }
+}