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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#![allow(clippy::single_match)]

mod expression;
mod function;
mod imports;
mod statement;
pub mod types;
pub mod wit;

use ast::{FunctionId, GlobalId};
use claw_ast as ast;
use claw_common::Source;

use std::collections::HashMap;
use wit::{ResolvedWit, WitError};

use miette::{Diagnostic, SourceSpan};
use thiserror::Error;

pub use function::*;
pub use imports::*;
pub use types::*;

pub struct ResolvedComponent {
    pub src: Source,
    pub component: ast::Component,
    pub wit: ResolvedWit,
    pub global_vals: HashMap<GlobalId, ast::Literal>,
    pub imports: ImportResolver,
    pub funcs: HashMap<FunctionId, ResolvedFunction>,
}

#[derive(Clone, Copy, Debug)]
pub enum ItemId {
    ImportFunc(ImportFuncId),
    Type(ResolvedType),
    Global(GlobalId),
    Param(ParamId),
    Local(LocalId),
    Function(FunctionId),
}

#[derive(Error, Debug, Diagnostic)]
pub enum ResolverError {
    #[error("Failed to resolve")]
    Base {
        #[source_code]
        src: Source,
        #[label("This bit")]
        span: SourceSpan,
    },
    #[error("Conflicting types inferred for expression {type_a} != {type_b}")]
    TypeConflict {
        #[source_code]
        src: Source,
        #[label("This bit")]
        span: SourceSpan,

        type_a: ResolvedType,
        type_b: ResolvedType,
    },
    #[error("Failed to resolve name \"{ident}\"")]
    NameError {
        #[source_code]
        src: Source,
        #[label("Name referenced here")]
        span: SourceSpan,
        ident: String,
    },
    #[error("Function call with wrong number of arguments \"{ident}\"")]
    CallArgumentsMismatch {
        #[source_code]
        src: Source,
        #[label("Here")]
        span: SourceSpan,
        ident: String,
    },
    #[error("{0} is not yet supported")]
    NotYetSupported(String),

    #[error(transparent)]
    #[diagnostic(transparent)]
    Wit(#[from] WitError),
}

pub fn resolve(
    src: Source,
    comp: ast::Component,
    wit: wit::ResolvedWit,
) -> Result<ResolvedComponent, ResolverError> {
    let mut mappings: HashMap<String, ItemId> = Default::default();

    let mut imports = ImportResolver::default();
    imports.resolve_imports(&comp, &wit)?;
    for (name, import) in imports.mapping.iter() {
        match import {
            ImportItemId::Type(rtype) => {
                dbg!(name, import);
                mappings.insert(name.to_owned(), ItemId::Type(*rtype));
            }
            ImportItemId::Func(func) => {
                dbg!(name, import);
                mappings.insert(name.to_owned(), ItemId::ImportFunc(*func));
            }
        }
    }

    for (id, global) in comp.globals.iter() {
        let name = comp.get_name(global.ident);
        mappings.insert(name.to_owned(), ItemId::Global(id));
    }
    for (id, function) in comp.functions.iter() {
        let name = comp.get_name(function.ident);
        mappings.insert(name.to_owned(), ItemId::Function(id));
    }

    let mut global_vals: HashMap<GlobalId, ast::Literal> = HashMap::new();

    for (id, global) in comp.globals.iter() {
        let global_val = match comp.expr().get_exp(global.init_value) {
            ast::Expression::Literal(literal) => literal.clone(),
            _ => panic!("Only literal expressions allowed in global initializer"),
        };
        global_vals.insert(id, global_val);
    }

    let mut funcs: HashMap<FunctionId, ResolvedFunction> = HashMap::new();

    for (id, function) in comp.functions.iter() {
        let resolver = FunctionResolver::new(src.clone(), &comp, &imports, function, &mappings);
        funcs.insert(id, resolver.resolve()?);
    }

    Ok(ResolvedComponent {
        src,
        component: comp,
        wit,
        global_vals,
        imports,
        funcs,
    })
}