use crate::*; use std::collections::HashMap; pub struct Program { pub definitions: HashMap>, pub tokens: Vec>, } pub struct Definition { pub kind: DefinitionKind, pub definition: usize, pub references: Vec, pub deep_references: Vec<(usize, usize)>, } impl Definition { pub fn new(i: usize, kind: DefinitionKind) -> Self { Self { kind, definition: i, references: Vec::new(), deep_references: Vec::new(), } } } pub enum DefinitionKind { MacroDefinition(Vec>), LabelDefinition, } pub enum SemanticToken { Comment(String), LabelDefinition(String), MacroDefinition(Tracked), RawValue(Value), Instruction(Instruction), Invocation(String), Padding(Value), String(Vec), BlockOpen(usize), BlockClose(usize), } 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::Comment(_) => indent!(i, "Comment"), 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 DefinitionKind::MacroDefinition(body) = &definition.kind { for token in body { print_semantic_token(i+1, token, definitions); } } } } SemanticToken::RawValue(value) => indent!(i, "RawValue({value})"), SemanticToken::Instruction(instruction) => indent!(i, "Instruction({instruction})"), SemanticToken::Invocation(name) => indent!(i, "Invocation({name})"), SemanticToken::Padding(value) => indent!(i, "Padding({value})"), SemanticToken::String(bytes) => indent!(i, "String({})", String::from_utf8_lossy(bytes)), SemanticToken::BlockOpen(pointer) => indent!(i, "BlockOpen(*{pointer})"), SemanticToken::BlockClose(pointer) => indent!(i, "BlockOpen(*{pointer})"), } }