summaryrefslogtreecommitdiff
path: root/src/stages/semantic_tokens.rs
blob: fe49c26a00e60a537eb5e49b02607945f7c1edbc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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);
                    }
                }
            }
        }
    }
}