summaryrefslogtreecommitdiff
path: root/src/parsers/assembler.rs
diff options
context:
space:
mode:
authorBen Bridle <ben@derelict.engineering>2025-03-06 20:33:27 +1300
committerBen Bridle <ben@derelict.engineering>2025-03-11 16:59:26 +1300
commit1ecee352f5844b0809d7ae66df52e34f42b44c8e (patch)
tree472b6fd57ff7f64ac3f8cd676cbe7a113ba01f05 /src/parsers/assembler.rs
parentf2ed89083f5326a7a6f0a1720033d3388aa431fb (diff)
downloadtorque-asm-1ecee352f5844b0809d7ae66df52e34f42b44c8e.zip
Rewrite entire assembler
The language is now more general, the code is better structured, error reporting is more detailed, and many new language features have been implemented: - conditional blocks - first-class strings - more expression operators - binary literals - negative values - invocations in constant expressions
Diffstat (limited to 'src/parsers/assembler.rs')
-rw-r--r--src/parsers/assembler.rs290
1 files changed, 0 insertions, 290 deletions
diff --git a/src/parsers/assembler.rs b/src/parsers/assembler.rs
deleted file mode 100644
index 61e1a84..0000000
--- a/src/parsers/assembler.rs
+++ /dev/null
@@ -1,290 +0,0 @@
-use crate::*;
-use AssemblerErrorVariant as ErrVar;
-
-use indexmap::IndexMap;
-
-
-static mut ID: usize = 0;
-macro_rules! new_id {
- () => { unsafe {
- let id = ID;
- ID += 1;
- id
- }};
-}
-
-
-impl SemanticProgram {
- pub fn assemble(&self) -> Vec<AssembledToken> {
- let environment = Environment {
- macro_definitions: &self.macro_definitions,
- label_definitions: &self.label_definitions,
- arguments: &IndexMap::new(),
- id: new_id!(),
- };
- let mut assembled_tokens = Vec::new();
- for token in &self.body {
- let tokens = environment.reify_semantic_token(token);
- assembled_tokens.extend(tokens);
- }
- return assembled_tokens;
- }
-}
-
-
-pub struct Environment<'a> {
- pub macro_definitions: &'a IndexMap<String, MacroDefinition>,
- pub label_definitions: &'a IndexMap<String, LabelDefinition>,
- pub arguments: &'a IndexMap<String, Argument>,
- pub id: usize,
-}
-
-impl<'a> Environment<'a> {
- // This is only ever called for the highest level body tokens, never for invocations.
- fn reify_semantic_token(&self, token: &SemanticToken) -> Vec<AssembledToken> {
- let mut assembled_tokens = Vec::new();
- match token {
- SemanticToken::Word(pbl) => {
- let word = self.reify_packed_binary_literal(pbl);
- assembled_tokens.push(AssembledToken::Word(word));
- }
- SemanticToken::Invocation(invocation) => {
- match self.reify_invocation(invocation) {
- Ok(argument) => match argument {
- Argument::Block(block) => assembled_tokens.extend(block),
- Argument::Integer(_) => {
- let variant = AssemblerErrorVariant::NotABlock;
- let source = invocation.source.clone();
- let error = AssemblerError { source, variant };
- assembled_tokens.push(AssembledToken::Error(error))
- }
- }
- Err(error) => assembled_tokens.push(AssembledToken::Error(error)),
- }
- }
- SemanticToken::LabelDefinition(definition) => {
- assembled_tokens.push(AssembledToken::LabelDefinition(definition.clone()));
- }
- SemanticToken::PinnedAddress(address) => {
- assembled_tokens.push(AssembledToken::PinnedAddress(address.clone()));
- }
- SemanticToken::Error(_) => (),
- }
- return assembled_tokens;
- }
-
- fn reify_packed_binary_literal(&self, pbl: &PackedBinaryLiteral) -> AssembledWord {
- let mut assembled_fields = Vec::new();
- let mut errors = Vec::new();
- for field in &pbl.fields {
- let name = field.name.to_string();
- match self.reify_integer_reference(&name, &field.source) {
- Ok(value) => assembled_fields.push(
- AssembledField {
- source: field.source.clone(),
- value,
- bits: field.bits,
- shift: field.shift,
- }
- ),
- Err(error) => errors.push(error),
- };
- }
- let source = pbl.source.clone();
- let value = pbl.value;
- let bits = pbl.bits;
- AssembledWord { source, bits, fields: assembled_fields, value, errors }
- }
-
- fn reify_integer_reference(&self, name: &str, source: &SourceSpan) -> Result<IntegerArgument, AssemblerError> {
- match self.reify_reference(name, source)? {
- Argument::Integer(integer) => Ok(integer),
- Argument::Block(_) => Err(
- AssemblerError {
- source: source.clone(),
- variant: ErrVar::NotAnInteger,
- }
- ),
- }
- }
-
- fn reify_reference(&self, name: &str, source: &SourceSpan) -> Result<Argument, AssemblerError> {
- let source = source.clone();
- if let Some(argument) = self.arguments.get(name) {
- Ok(argument.clone())
- } else if let Some(definition) = self.macro_definitions.get(name) {
- self.reify_value(&definition.value)
- } else if let Some(label) = self.label_definitions.get(name) {
- let name = Tracked::from(self.tag_label_name(&label.name), source);
- Ok(Argument::Integer(IntegerArgument::LabelReference(name)))
- } else {
- let variant = ErrVar::DefinitionNotFound(name.to_string());
- Err(AssemblerError { source, variant })
- }
- }
-
- fn tag_label_name(&self, name: &str) -> String {
- match name.contains(':') {
- true => format!("{name}:{}", self.id),
- false => name.to_string(),
- }
- }
-
- fn reify_value(&self, value: &Value) -> Result<Argument, AssemblerError> {
- match value {
- Value::Integer(integer) => {
- let value = match &integer {
- Integer::Literal(integer) => {
- IntegerArgument::Integer(integer.clone())
- }
- Integer::Expression(expr) => {
- let expr = self.reify_constant_expression(expr)?;
- IntegerArgument::Expression(expr)
- }
- Integer::LabelReference(name) => {
- let name = Tracked::from(self.tag_label_name(name), name.source.clone());
- IntegerArgument::LabelReference(name)
- }
- Integer::String(string) => {
- IntegerArgument::String(string.clone())
- }
- };
- Ok(Argument::Integer(value))
- }
- Value::Block(block) => {
- let mut assembled_tokens = Vec::new();
- for token in block {
- match &token {
- SemanticToken::Word(pbl) => {
- let word = self.reify_packed_binary_literal(pbl);
- assembled_tokens.push(AssembledToken::Word(word));
- }
- SemanticToken::Invocation(invocation) => {
- match self.reify_invocation(invocation)? {
- Argument::Block(block) => assembled_tokens.extend(block),
- Argument::Integer(_) => {
- let source = invocation.source.clone();
- let variant = AssemblerErrorVariant::IntegerInBlock;
- return Err(AssemblerError { source, variant});
- }
- }
- }
- SemanticToken::LabelDefinition(definition) => {
- let mut definition = definition.clone();
- definition.name.push_str(&format!(":{}", self.id));
- let token = AssembledToken::LabelDefinition(definition);
- assembled_tokens.push(token);
- }
- SemanticToken::PinnedAddress(address) => {
- let token = AssembledToken::PinnedAddress(address.to_owned());
- assembled_tokens.push(token);
- }
- SemanticToken::Error(_) => (),
- }
- }
- Ok(Argument::Block(assembled_tokens))
- }
- Value::Invocation(invocation) => {
- self.reify_invocation(invocation)
- }
- }
- }
-
- fn reify_invocation(&self, invocation: &Invocation) -> Result<Argument, AssemblerError> {
- macro_rules! err {
- ($variant:expr) => { Err(AssemblerError {
- source: invocation.source.clone(), variant: $variant
- }) };
- }
- if let Some(argument) = self.arguments.get(&invocation.name) {
- let expected = 0;
- let received = invocation.arguments.len();
- if received != expected {
- return err!(ErrVar::IncorrectArgumentCount(expected, received));
- }
- Ok(argument.clone())
- } else if let Some(definition) = self.macro_definitions.get(&invocation.name) {
- // Check that the correct number of arguments were provided.
- let received = invocation.arguments.len();
- let expected = definition.arguments.len();
- if received != expected {
- return err!(ErrVar::IncorrectArgumentCount(expected, received));
- }
- let mut arguments = IndexMap::new();
- for (i, argument) in invocation.arguments.iter().enumerate() {
- // Check that the correct types of arguments were provided.
- let arg_invocation = self.reify_value(&argument.value)?;
- let arg_invocation_type = match &arg_invocation {
- Argument::Integer(_) => ArgumentVariant::Integer,
- Argument::Block(_) => ArgumentVariant::Block,
- };
- let arg_definition_type = definition.arguments[i].variant;
- if arg_invocation_type != arg_definition_type {
- let variant = ErrVar::IncorrectArgumentType(
- arg_definition_type, arg_invocation_type
- );
- return Err(AssemblerError { source: argument.source.clone(), variant });
- }
- let name = definition.arguments[i].name.clone();
- arguments.insert(name, arg_invocation);
- }
- let environment = Environment {
- macro_definitions: &self.macro_definitions,
- label_definitions: &self.label_definitions,
- arguments: &arguments,
- id: new_id!(),
- };
- environment.reify_value(&definition.value)
- } else if let Some(label) = self.label_definitions.get(&invocation.name) {
- let expected = 0;
- let received = invocation.arguments.len();
- if received != expected {
- return err!(ErrVar::IncorrectArgumentCount(expected, received));
- }
- let name = Tracked::from(self.tag_label_name(&label.name), label.source.clone());
- Ok(Argument::Integer(IntegerArgument::LabelReference(name)))
- } else {
- err!(ErrVar::DefinitionNotFound(invocation.name.to_string()))
- }
- }
-
- fn reify_constant_expression(&self, expr: &Expression) -> Result<AssembledExpression, AssemblerError> {
- use ExpressionTokenVariant as ExprVar;
-
- let mut assembled_tokens = Vec::new();
- for token in &expr.tokens {
- let assembled_token = match &token.variant {
- ExprVar::Literal(value) => {
- let source = token.source.clone();
- let integer = TrackedInteger { source, value: *value };
- AssembledExpressionToken::Integer(integer)
- }
- ExprVar::Operator(operator) => {
- AssembledExpressionToken::Operator(*operator)
- }
- ExprVar::Invocation(name) => {
- match self.reify_integer_reference(&name, &token.source)? {
- IntegerArgument::LabelReference(name) => {
- AssembledExpressionToken::LabelReference(name)
- }
- IntegerArgument::Integer(integer) => {
- AssembledExpressionToken::Integer(integer)
- }
- IntegerArgument::Expression(expr) => {
- AssembledExpressionToken::Expression(Box::new(expr))
- },
- IntegerArgument::String(string) => {
- let source = string.source.clone();
- let variant = AssemblerErrorVariant::StringInExpression;
- return Err(AssemblerError { source, variant })
- }
- }
- }
- ExprVar::Error(_) => continue,
- };
- assembled_tokens.push(assembled_token);
- }
- Ok(AssembledExpression { source: expr.source.clone(), tokens: assembled_tokens })
- }
-}
-