use crate::*; use std::collections::HashMap; pub struct Program { pub definitions: HashMap>, pub tokens: Vec>, } pub struct Definition { pub variant: DefinitionVariant, /// Index of definition token. pub definition: usize, /// Indices of symbols referencing this definition. pub references: Vec, /// Indices of references inside other definitions. pub deep_references: Vec<(usize, usize)>, } impl Definition { pub fn new(i: usize, variant: DefinitionVariant) -> Self { Self { variant, definition: i, references: Vec::new(), deep_references: Vec::new(), } } } pub enum DefinitionVariant { LabelDefinition, MacroDefinition(Vec>), } pub enum SemanticToken { Literal(Value), Pad(Value), String(Vec), Comment(String), BlockOpen(usize), // index to matching block-close BlockClose(usize), // index to matching block-open Symbol(String), Instruction(Instruction), LabelDefinition(String), MacroDefinition(Tracked), } pub enum SemanticError { InvocationBeforeDefinition, } pub fn report_semantic_errors(errors: &[Tracked], source_code: &str) { for error in errors { report_semantic_error(error, source_code); } } fn report_semantic_error(error: &Tracked, source_code: &str) { let context = Context { source_code: &source_code, source: &error.source }; let message = match &error.value { SemanticError::InvocationBeforeDefinition => "Macro cannot be invoked before it has been defined", }; report_source_issue(LogLevel::Error, &context, message); } pub fn print_semantic_token(i: usize, token: &SemanticToken, definitions: &HashMap>) { match token { SemanticToken::Literal(value) => indent!(i, "Literal({value})"), SemanticToken::Pad(value) => indent!(i, "Pad({value})"), SemanticToken::String(bytes) => indent!(i, "String({})", String::from_utf8_lossy(bytes)), SemanticToken::Comment(_) => indent!(i, "Comment"), SemanticToken::BlockOpen(pointer) => indent!(i, "BlockOpen(*{pointer})"), SemanticToken::BlockClose(pointer) => indent!(i, "BlockClose(*{pointer})"), SemanticToken::Symbol(name) => indent!(i, "Symbol({name})"), SemanticToken::Instruction(instruction) => indent!(i, "Instruction({instruction})"), SemanticToken::LabelDefinition(name) => indent!(i, "LabelDefinition({name})"), SemanticToken::MacroDefinition(name) => { indent!(i, "MacroDefinition({name})"); if let Some(definition) = definitions.get(name.as_str()) { if let DefinitionVariant::MacroDefinition(body) = &definition.variant { for token in body { print_semantic_token(i+1, token, definitions); } } } } } }