summaryrefslogtreecommitdiff
path: root/src/stages/syntactic_tokens.rs
blob: 4c258c650d87c17f70b469d500c2746d6f26743e (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
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::*;

pub enum SyntacticToken {
    Comment(String),

    LabelDefinition(String),
    MacroDefinition(SyntacticMacroDefinition),

    RawValue(Value),
    Instruction(Instruction),
    Invocation(String),

    Padding(Value),
    String(Vec<u8>),

    BlockOpen,
    BlockClose,
}

pub struct SyntacticMacroDefinition {
    pub name: Tracked<String>,
    pub body: Vec<Tracked<SyntacticToken>>,
}

pub enum SyntacticError {
    UnterminatedBlock,
    UnterminatedComment,
    UnterminatedRawString,
    UnterminatedNullString,
    UnterminatedMacroDefinition,

    UnmatchedBlockTerminator,
    UnmatchedCommentTerminator,
    UnmatchedMacroTerminator,

    InvalidPaddingValue,

    MacroDefinitionInMacroDefinition,
    LabelDefinitionInMacroDefinition,
}


pub fn report_syntactic_errors(errors: &[Tracked<SyntacticError>], source_code: &str) {
    for error in errors {
        report_syntactic_error(error, source_code);
    }
}

fn report_syntactic_error(error: &Tracked<SyntacticError>, 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 =>
            "Raw string was not terminated, add a ' character to terminate",
        SyntacticError::UnterminatedNullString =>
            "Null-terminated 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::InvalidPaddingValue =>
            "The padding value must be either two or four hexadecimal digits",

        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::Comment(_) =>
            indent!(i, "Comment"),

        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);
            }
        }

        SyntacticToken::RawValue(value) => indent!(i, "RawValue({value})"),
        SyntacticToken::Instruction(instruction) => indent!(i, "Instruction({instruction})"),
        SyntacticToken::Invocation(name) => indent!(i, "Invocation({name})"),

        SyntacticToken::Padding(value) => indent!(i, "Padding({value})"),
        SyntacticToken::String(bytes) => indent!(i, "String({})", String::from_utf8_lossy(bytes)),

        SyntacticToken::BlockOpen => indent!(i, "BlockOpen"),
        SyntacticToken::BlockClose => indent!(i, "BlockOpen"),
    }
}