use crate::*; pub enum SyntacticToken { Literal(Value), Pad(Value), String(Vec), Comment(String), BlockOpen, BlockClose, Symbol(String), Instruction(Instruction), LabelDefinition(String), MacroDefinition(SyntacticMacroDefinition), } pub struct SyntacticMacroDefinition { pub name: Tracked, pub body: Vec>, } pub enum SyntacticError { UnterminatedBlock, UnterminatedComment, UnterminatedRawString, UnterminatedNullString, UnterminatedMacroDefinition, UnmatchedBlockTerminator, UnmatchedCommentTerminator, UnmatchedMacroTerminator, InvalidPadValue, InvalidIdentifier(String), MacroDefinitionInMacroDefinition, LabelDefinitionInMacroDefinition, } pub fn report_syntactic_errors(errors: &[Tracked], source_code: &str) { for error in errors { report_syntactic_error(error, source_code); } } fn report_syntactic_error(error: &Tracked, source_code: &str) { let context = Context { source_code: &source_code, source: &error.source }; let message = match &error.value { SyntacticError::UnterminatedBlock => "Block was not terminated, add a '}' character to terminate", SyntacticError::UnterminatedComment => "Comment was not terminated, add a ')' character to terminate", SyntacticError::UnterminatedRawString => "String was not terminated, add a ' character to terminate", SyntacticError::UnterminatedNullString => "String was not terminated, add a '\"' character to terminate", SyntacticError::UnterminatedMacroDefinition => "Macro definition was not terminated, add a ';' character to terminate", SyntacticError::UnmatchedBlockTerminator => "Attempted to terminate a block, but no block was in progress", SyntacticError::UnmatchedCommentTerminator => "Attempted to terminate a comment, but no comment was in progress", SyntacticError::UnmatchedMacroTerminator => "Attempted to terminate a macro definition, but no macro definition was in progress", SyntacticError::InvalidPadValue => "The pad value must be two or four hexadecimal digits", SyntacticError::InvalidIdentifier(name) => &format!("An identifier cannot exceed 63 characters in length: {name}"), SyntacticError::MacroDefinitionInMacroDefinition => "A macro cannot be defined inside another macro", SyntacticError::LabelDefinitionInMacroDefinition => "A label cannot be defined inside a macro", }; report_source_issue(LogLevel::Error, &context, message); } pub fn print_syntactic_token(i: usize, token: &SyntacticToken) { match token { SyntacticToken::Literal(value) => indent!(i, "Literal({value})"), SyntacticToken::Pad(value) => indent!(i, "Pad({value})"), SyntacticToken::String(bytes) => indent!(i, "String({})", String::from_utf8_lossy(bytes)), SyntacticToken::Comment(_) => indent!(i, "Comment"), SyntacticToken::BlockOpen => indent!(i, "BlockOpen"), SyntacticToken::BlockClose => indent!(i, "BlockOpen"), SyntacticToken::Symbol(name) => indent!(i, "Symbol({name})"), SyntacticToken::Instruction(instruction) => indent!(i, "Instruction({instruction})"), SyntacticToken::LabelDefinition(name) => indent!(i, "LabelDefinition({name})"), SyntacticToken::MacroDefinition(definition) => { indent!(i, "MacroDefinition({})", definition.name); for token in &definition.body { print_syntactic_token(i+1, token); } } } }