Skip to main content

brooks_lib/mel/
error.rs

1// brooks, Copyright 2026, Will Hawkins
2//
3// This file is part of brooks.
4
5// This file is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18use std::fmt::Display;
19
20use crate::{
21    common::TextLocation,
22    mel::{compiler::error::CompilerLocatableError, types::Type},
23};
24
25#[derive(Debug, Clone)]
26pub enum AnalysisAssertions {
27    ContextMissing,
28    ContextMissingExpr(String),
29    ContextWrongExprType(String, String, String),
30    ContextMissingParams,
31    InvalidOperator(String, String),
32}
33
34impl Display for AnalysisAssertions {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        match self {
37            AnalysisAssertions::ContextMissing => write!(f, "Missing analysis context"),
38            AnalysisAssertions::ContextWrongExprType(expected, actual, whre) => write!(
39                f,
40                "Wrong expression type in analysis context; expected {} but found {} in {}",
41                expected, actual, whre
42            ),
43            AnalysisAssertions::ContextMissingParams => {
44                write!(f, "Missing parameters in analysis context")
45            }
46            AnalysisAssertions::ContextMissingExpr(s) => {
47                write!(f, "Missing expression in {}", s)
48            }
49            AnalysisAssertions::InvalidOperator(o, l) => {
50                write!(f, "Invalid operator {o} in {l}")
51            }
52        }
53    }
54}
55
56#[derive(Debug, Clone)]
57pub enum AnalysisPreconditions {
58    ContextMissingExpr(String),
59}
60
61impl Display for AnalysisPreconditions {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        match self {
64            AnalysisPreconditions::ContextMissingExpr(s) => {
65                write!(f, "Missing expression in {}", s)
66            }
67        }
68    }
69}
70
71#[derive(Debug, Clone)]
72pub enum AnalysisError {
73    CompilerError(CompilerLocatableError),
74    Mismatch(Type, Type),
75    RegexSame,
76    InvalidType(Vec<Type>, Type),
77    Miscount(usize, usize),
78    InvalidRegex(String),
79    UnknownField(String, String),
80    UnknownIdentifier(String),
81    AssertionFailure(AnalysisAssertions),
82    PreconditionFailure(AnalysisPreconditions),
83    OptimizationNotSupported(String),
84    Incalculable,
85}
86
87impl Display for AnalysisError {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        match self {
90            Self::CompilerError(e) => write!(f, "Compiler error: {:?}", e),
91            Self::Mismatch(expected, found) => {
92                write!(f, "Expected {:?}, found {:?}", expected, found)
93            }
94            Self::Miscount(expected, found) => {
95                write!(f, "Expected {expected} arguments, found {found}")
96            }
97            Self::UnknownIdentifier(i) => write!(f, "Unknown identifier {:?}", i),
98            Self::AssertionFailure(c) => write!(f, "Missing compiler context: {:?}", c),
99            Self::PreconditionFailure(c) => {
100                write!(f, "Precondition not satisfied during analysis: {:?}", c)
101            }
102            Self::UnknownField(strct, member) => write!(f, "No field named {member} in {strct}"),
103            Self::Incalculable => write!(f, "Incalculable expression analysis"),
104            Self::OptimizationNotSupported(o) => write!(f, "Optimization not supported: {o}"),
105            Self::InvalidRegex(i) => write!(f, "Regular expression literal not valid: {i}"),
106            Self::RegexSame => write!(
107                f,
108                "The operands to the regular expression match operator must be a string and a regular expression"
109            ),
110            Self::InvalidType(valids, actual) => write!(
111                f,
112                "{actual} is not one of the expected types ({})",
113                valids
114                    .iter()
115                    .map(|v| v.to_string())
116                    .collect::<Vec<_>>()
117                    .join(",")
118            ),
119        }
120    }
121}
122
123#[derive(Debug, Clone)]
124pub struct AnalysisLocatableError {
125    pub error: Box<AnalysisError>,
126    pub location: TextLocation,
127}
128
129impl Display for AnalysisLocatableError {
130    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131        write!(f, "{} ({})", self.error, self.location)
132    }
133}