Skip to main content

brooks_lib/mel/interpreter/
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
18//! MEL interpreter error types
19
20use std::{error::Error, fmt::Display};
21
22use crate::{
23    common::TextLocation,
24    mel::{ast::BinaryInfixOperator, interpreter::interpret::MelInterpContext, types::Type},
25};
26
27#[derive(Debug, Clone)]
28pub enum InterpAssertion {
29    TypeMismatch(Type, Type),
30    SuccessWithoutValue(String, String),
31    UnexpectedOperator(BinaryInfixOperator),
32}
33
34impl Display for InterpAssertion {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        match self {
37            InterpAssertion::SuccessWithoutValue(what, whre) => write!(
38                f,
39                "Successful evaluation of subexpression {what} did not yield a value in {whre}"
40            ),
41            InterpAssertion::UnexpectedOperator(oper) => write!(
42                f,
43                "Unexpected binary infix operator during evaluation: {oper}",
44            ),
45            InterpAssertion::TypeMismatch(expected, actual) => {
46                write!(f, "Expected type {expected}, have type {actual}",)
47            }
48        }
49    }
50}
51
52#[derive(Debug, Clone)]
53pub enum MelInterpPreconditions {}
54
55impl Display for MelInterpPreconditions {
56    fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        Ok(())
58    }
59}
60
61#[derive(Debug, Clone)]
62pub enum InterpError {
63    Assertion(Box<InterpAssertion>),
64    ValueError(Box<TypedValueError>),
65    UnknownIdentifier(String),
66    UnknownField(String),
67    MistypedField(String, Type, Type),
68    BuiltinError(Box<BuiltinInterpError>),
69}
70
71impl Display for InterpError {
72    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73        write!(f, "Mel interpreter error: ")?;
74        match self {
75            InterpError::ValueError(mel_value_error) => {
76                write!(f, "value failure: {}", mel_value_error)
77            }
78            InterpError::Assertion(mel_interp_assertion) => {
79                write!(f, "assertion failure: {}", mel_interp_assertion)
80            }
81            InterpError::UnknownIdentifier(id) => {
82                write!(f, "unknown identifier: {}", id)
83            }
84            InterpError::UnknownField(field) => {
85                write!(f, "unknown field: {}", field)
86            }
87            InterpError::BuiltinError(bi) => {
88                write!(f, "error executing builtin function: {}", bi)
89            }
90            InterpError::MistypedField(field, expected, actual) => {
91                write!(
92                    f,
93                    "error adding field to struct: field {field} has wrong type (expected: {expected}, actual: {actual})",
94                )
95            }
96        }
97    }
98}
99
100impl Error for InterpError {}
101
102#[derive(Debug, Clone)]
103pub enum BuiltinInterpError {
104    ArgumentMiscount(usize, usize),
105    ArgumentMismatch(usize, Type, Type),
106    RuntimeError(String),
107    ArgumentsInvalid,
108}
109
110impl Display for BuiltinInterpError {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        match self {
113            BuiltinInterpError::ArgumentMiscount(expected, actual) => {
114                write!(f, "Expected {expected} arguments but got {actual}")
115            }
116            BuiltinInterpError::ArgumentMismatch(which, expected, actual) => write!(
117                f,
118                "Expected argument {which} to have type {expected} but it has {actual}",
119            ),
120            BuiltinInterpError::ArgumentsInvalid => write!(f, "Invalid arguments"),
121            BuiltinInterpError::RuntimeError(e) => write!(f, "Runtime error: {e}"),
122        }
123    }
124}
125
126#[derive(Debug, Clone)]
127pub enum TypedValueError {
128    ConversionError(String),
129}
130
131impl Display for TypedValueError {
132    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133        match self {
134            TypedValueError::ConversionError(ce) => write!(f, "Conversion error: {ce}"),
135        }
136    }
137}
138#[derive(Debug)]
139pub struct InterpLocatableError {
140    pub error: Box<InterpError>,
141    pub location: TextLocation,
142    pub context: MelInterpContext,
143}
144
145impl Display for InterpLocatableError {
146    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147        write!(f, "{} ({})", self.error, self.location)
148    }
149}
150
151impl std::error::Error for InterpLocatableError {}