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
use super::*;

use std::sync::Arc;

#[derive(Debug, Clone)]
pub enum BitsyError {
    ExtHasNonPort(Span, Name),
    DuplicateComponent(Arc<Component>),
    MultipleDrivers(Span, Name),
    NoDrivers(Arc<Component>),
    NoDriversPort(Arc<Component>, Arc<Component>),
    WrongWireType(Span, Name, WireType),
    IncomingPortDriven(Span, Name),
    NoSuchComponent(Span, String),
    TypeError(TypeError),
    ParseError(Span, String),
    Unknown(Option<Span>, String),
}

#[derive(Clone, Debug)]
pub enum TypeError {
    UndefinedReference(Arc<Expr>),
    NotExpectedType(Type, Type, Arc<Expr>),
    InvalidWord(Arc<Expr>),
    CantInferType(Arc<Expr>),
    Other(Arc<Expr>, String),
}

impl HasSpan for TypeError {
    fn span(&self) -> Span {
        match self {
            TypeError::UndefinedReference(e) => e.span(),
            TypeError::NotExpectedType(_type_expected, _type_actual, e) => e.span(),
            TypeError::InvalidWord(e) => e.span(),
            TypeError::CantInferType(e) => e.span(),
            TypeError::Other(e, _msg) => e.span(),
        }
    }
}

impl std::fmt::Display for TypeError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
        match self {
            TypeError::UndefinedReference(expr) => write!(f, "Undefiend reference: {expr:?}"),
            TypeError::NotExpectedType(type_expected, type_actual, _expr) => write!(f, "Not expected type: has type {type_actual:?} but expected {type_expected:?}."),
            TypeError::InvalidWord(expr) => write!(f, "Invalid literal: {expr:?}"),
            TypeError::CantInferType(expr) => write!(f, "Can't infer type: {expr:?}"),
            TypeError::Other(_expr, message) => write!(f, "{message}"),
        }
    }
}

impl std::fmt::Display for BitsyError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            BitsyError::ExtHasNonPort(_span, name) => write!(f, "Ext declares a component other than an incoming or outgoing: {name}"),
            BitsyError::DuplicateComponent(component) => write!(f, "Duplicate component: {}", component.name()),
            BitsyError::MultipleDrivers(_span, name) => write!(f, "Component has multiple drivers: {name}."),
            BitsyError::NoDrivers(component) => write!(f, "Component is not driven: {}", component.name()),
            BitsyError::NoDriversPort(component, port) => write!(f, "Port is not driven: {}.{}", component.name(), port.name()),
            BitsyError::WrongWireType(_span, name, wire_type) => {
                let symbol = match wire_type {
                    WireType::Dom    => "$=",
                    WireType::Direct => ":=",
                    WireType::Latch  => "<=",
                    WireType::Proc   => "<=!",
                };
                write!(f, "Wrong wire type: {name} does not support {symbol}")
            },
            BitsyError::IncomingPortDriven(_span, name) => write!(f, "Incoming port is being driven from inside a mod, but shouldn't be: {name}"),
            BitsyError::NoSuchComponent(_span, s) => write!(f, "No such component: {s}"),
            BitsyError::TypeError(type_error) => write!(f, "Type Error: {type_error}"),
            BitsyError::ParseError(_span, error) => write!(f, "{error}"),
            BitsyError::Unknown(_span, message) => write!(f, "{message}"),
        }
    }
}

impl HasSpan for BitsyError {
    fn span(&self) -> Span {
        match self {
            BitsyError::ExtHasNonPort(span, _name) => span.clone(),
            BitsyError::DuplicateComponent(component) => component.span(),
            BitsyError::MultipleDrivers(span, _name) => span.clone(),
            BitsyError::NoDrivers(component) => component.span(),
            BitsyError::NoDriversPort(component, _port) => component.span(),
            BitsyError::WrongWireType(span, _name, _wire_type) => span.clone(),
            BitsyError::IncomingPortDriven(span, _name) => span.clone(),
            BitsyError::NoSuchComponent(span, _name) => span.clone(),
            BitsyError::TypeError(type_error) => type_error.span(),
            BitsyError::ParseError(span, _error) => span.clone(),
            BitsyError::Unknown(span, _string) => span.clone().unwrap_or_else(|| Span::unknown()),
        }
    }
}