use crate::*; pub enum SyntacticToken { LabelDefinition(ScopedSymbol), MacroDefinition(SyntacticMacroDefinition), IntegerLiteral(isize), StringLiteral(StringLiteral), WordTemplate(WordTemplate), BlockLiteral(Vec>), Expression(Vec>), Symbol(ScopedSymbol), Separator, Condition, Pin, } pub struct SyntacticMacroDefinition { pub name: Tracked, pub body: Vec>, } pub struct StringLiteral { pub string: String, pub chars: Vec>, } impl std::fmt::Display for StringLiteral { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { self.string.fmt(f) } } pub enum ScopedSymbol { Local(String), Global(String), } impl std::fmt::Display for ScopedSymbol { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { match self { ScopedSymbol::Local(name) => write!(f, "~{name}"), ScopedSymbol::Global(name) => write!(f, "{name}"), } } } pub enum SyntacticError { UnterminatedBlock, UnterminatedExpression, UnterminatedComment, UnterminatedCharacterLiteral, UnterminatedStringLiteral, UnterminatedMacroDefinition(String), UnmatchedBlockTerminator, UnmatchedExpressionTerminator, UnmatchedCommentTerminator, UnmatchedMacroTerminator, ExpectedSingleCharacter, DuplicateFieldNameInWord(char), InvalidCharacterInWord(char), InvalidDecimalLiteral(String), InvalidHexadecimalLiteral(String), InvalidBinaryLiteral(String), InvalidOctalLiteral(String), } 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::UnterminatedExpression => "Expression was not terminated, add a ']' character to terminate", SyntacticError::UnterminatedComment => "Comment was not terminated, add a ')' character to terminate", SyntacticError::UnterminatedCharacterLiteral => "Character was not terminated, add a ' character to terminate", SyntacticError::UnterminatedStringLiteral => "String was not terminated, add a '\"' character to terminate", SyntacticError::UnterminatedMacroDefinition(name) => &format!("The '{name}' macro definition was not terminated, add a ';' character to terminate"), SyntacticError::UnmatchedBlockTerminator => "Attempted to terminate a block, but no block was in progress", SyntacticError::UnmatchedExpressionTerminator => "Attempted to terminate an expression, but no expression 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::ExpectedSingleCharacter => "A character literal must contain exactly one character", SyntacticError::DuplicateFieldNameInWord(name) => &format!("The field '{name}' has already been used in this word"), SyntacticError::InvalidCharacterInWord(c) => &format!("The character '{c}' cannot be used in a word"), SyntacticError::InvalidDecimalLiteral(string) => &format!("The string '{string}' is not a valid decimal literal"), SyntacticError::InvalidHexadecimalLiteral(string) => &format!("The string '{string}' is not a valid hexadecimal literal"), SyntacticError::InvalidBinaryLiteral(string) => &format!("The string '{string}' is not a valid binary literal"), SyntacticError::InvalidOctalLiteral(string) => &format!("The string '{string}' is not a valid octal literal"), }; report_source_issue(LogLevel::Error, &context, message); } pub fn print_syntactic_token(i: usize, token: &SyntacticToken) { match token { SyntacticToken::LabelDefinition(symbol) => indent!(i, "LabelDefinition({symbol})"), SyntacticToken::MacroDefinition(definition) => { indent!(i, "MacroDefinition({})", definition.name); for token in &definition.body { print_syntactic_token(i+1, token); } } SyntacticToken::IntegerLiteral(value) => indent!(i, "IntegerLiteral({value})"), SyntacticToken::StringLiteral(literal) => indent!(i, "StringLiteral({literal})"), SyntacticToken::WordTemplate(template) => indent!(i, "WordTemplate({template})"), SyntacticToken::BlockLiteral(tokens) => { indent!(i, "BlockLiteral"); for token in tokens { print_syntactic_token(i+1, token); } } SyntacticToken::Expression(tokens) => { indent!(i, "Expression"); for token in tokens { print_syntactic_token(i+1, token); } } SyntacticToken::Symbol(symbol) => indent!(i, "Symbol({symbol})"), SyntacticToken::Separator => indent!(i, "Separator"), SyntacticToken::Condition => indent!(i, "Condition"), SyntacticToken::Pin => indent!(i, "Pin"), } }