diff options
Diffstat (limited to 'src/stages/semantic_tokens.rs')
-rw-r--r-- | src/stages/semantic_tokens.rs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/stages/semantic_tokens.rs b/src/stages/semantic_tokens.rs new file mode 100644 index 0000000..fe49c26 --- /dev/null +++ b/src/stages/semantic_tokens.rs @@ -0,0 +1,94 @@ +use crate::*; + +use std::collections::HashMap; + + +pub struct Program { + pub definitions: HashMap<String, Tracked<Definition>>, + pub tokens: Vec<Tracked<SemanticToken>>, +} + +pub struct Definition { + pub variant: DefinitionVariant, + /// Index of definition token. + pub definition: usize, + /// Indices of symbols referencing this definition. + pub references: Vec<usize>, + /// 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<Tracked<SemanticToken>>), +} + +pub enum SemanticToken { + Literal(Value), + Pad(Value), + String(Vec<u8>), + Comment(String), + BlockOpen(usize), // index to matching block-close + BlockClose(usize), // index to matching block-open + Symbol(String), + Instruction(Instruction), + LabelDefinition(String), + MacroDefinition(Tracked<String>), +} + +pub enum SemanticError { + InvocationBeforeDefinition, +} + + +pub fn report_semantic_errors(errors: &[Tracked<SemanticError>], source_code: &str) { + for error in errors { + report_semantic_error(error, source_code); + } +} + + +fn report_semantic_error(error: &Tracked<SemanticError>, 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<String, Tracked<Definition>>) { + 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); + } + } + } + } + } +} |