summaryrefslogblamecommitdiff
path: root/src/semantic_token.rs
blob: 265db9189bb0138e444ab57c806dc05674ff302a (plain) (tree)
1
2
3
4
5
6
7
8
9







                                     

                      
                    
                              






                                            
                                     
 
                    

                                                          
                                                     
                                                      

                                                                      
                            

























                                                                                                                                    



                                                                                                    












                                                                                                
                                                                                   
                                                  
                                                                     
             
                

     




                                                    




                                                       




                                                    



                                                                    
 
use crate::*;

pub enum SemanticTokenType {
    LabelReference(usize),
    MacroReference(usize),

    LabelDefinition(LabelDefinition),
    MacroDefinition(MacroDefinition),

    Padding(u16),
    ByteLiteral(u8),
    ShortLiteral(u16),
    Instruction(u8),

    MacroDefinitionTerminator,
    Comment,
    Error(SyntacticTokenType, Error),
}

pub struct SemanticToken {
    pub r#type: SemanticTokenType,
    pub source_location: SourceLocation,
    pub bytecode_location: BytecodeLocation,
    pub parent_label: Option<String>,
}

impl SemanticToken {
    /// Returns true if an error was printed.
    pub fn print_error(&self, source_code: &str) -> bool {
        let mut is_error = false;
        macro_rules! red {()=>{eprint!("\x1b[31m")};}
        macro_rules! dim {()=>{eprint!("\x1b[0;2m")};}
        macro_rules! normal {()=>{eprint!("\x1b[0m")};}

        if let SemanticTokenType::Error(token, error) = &self.r#type {
            is_error = true;

            red!(); eprint!("[ERROR] "); normal!();
            let source = &self.source_location.source;
            match error {
                Error::UnresolvedReference => {
                    eprintln!("Unresolved reference, no label or macro has been defined with the name '{source}'") }
                Error::DuplicateDefinition => {
                    eprintln!("Duplicate definition, a label or macro has already been defined with the name '{source}'") }
                Error::OrphanedMacroDefinitionTerminator => {
                    eprintln!("Unmatched macro definition terminator, no macro definition is in progress") }
                Error::InvalidPaddingValue => {
                    eprintln!("Invalid value for padding, the value must be at least one and at most four hexadecimal characters") }
                Error::CyclicMacroReference => {
                    eprintln!("Cyclic macro reference, this macro reference contains a reference to the macro being defined") }
                Error::InvalidTypeInMacroDefinition => {
                    let name = match token {
                        SyntacticTokenType::Reference(_) => "references",
                        SyntacticTokenType::LabelDefinition(_) => "label definitions",
                        SyntacticTokenType::MacroDefinition(_) => "macro definitions",
                        SyntacticTokenType::MacroDefinitionTerminator => "macro definition terminators",
                        SyntacticTokenType::Padding(_) => "padding",
                        SyntacticTokenType::ByteLiteral(_) => "byte literals",
                        SyntacticTokenType::ShortLiteral(_) => "short literals",
                        SyntacticTokenType::Instruction(_) => "instructions",
                        SyntacticTokenType::Comment => "comments",
                    };
                    eprintln!("Invalid token in macro definition, macro definitions are not allowed to contain {name}") }
            }

            if let Some(label) = &self.parent_label {
                eprint!("  ... "); red!(); eprint!("| "); dim!(); eprintln!("@{label} "); normal!();
            }

            let line = source_code.split('\n').nth(self.source_location.start.line).unwrap();
            eprint!("{:>5} ", self.source_location.start.line+1);
            red!(); eprint!("| "); normal!();
            for (i, c) in line.chars().enumerate() {
                if i == self.source_location.start.column { red!() }
                eprint!("{c}");
                if i == self.source_location.end.column { normal!() }
            }
            eprintln!(); red!(); eprint!("      | ");
            for i in 0..=self.source_location.end.column {
                if i < self.source_location.start.column { eprint!(" ") } else { eprint!("^") };
            }
            normal!(); eprintln!();
        }
        else if let SemanticTokenType::MacroDefinition(definition) = &self.r#type {
            for token in &definition.body_tokens {
                if token.print_error(source_code) { is_error = true }
            }
        }
        is_error
    }
}

pub struct LabelDefinition {
    pub name: String,
    pub address: u16,
    /// A list of pointers to label reference tokens
    pub references: Vec<usize>,
}
impl LabelDefinition {
    pub fn new(name: String) -> Self {
        Self { name, address:0, references:Vec::new() }
    }
}

pub struct MacroDefinition {
    pub name: String,
    pub body_tokens: Vec<SemanticToken>,
    /// A list of pointers to macro reference tokens
    pub references: Vec<usize>,
}
impl MacroDefinition {
    pub fn new(name: String) -> Self {
        Self { name, body_tokens:Vec::new(), references:Vec::new() }
    }
}