1#![allow(clippy::single_match)]
2
3mod expression;
4mod function;
5mod imports;
6mod statement;
7pub mod types;
8pub mod wit;
9
10use ast::{FunctionId, GlobalId};
11use claw_ast as ast;
12use claw_common::Source;
13
14use std::collections::HashMap;
15use wit::{ResolvedWit, WitError};
16
17use miette::{Diagnostic, SourceSpan};
18use thiserror::Error;
19
20pub use function::*;
21pub use imports::*;
22pub use types::*;
23
24pub struct ResolvedComponent {
25 pub src: Source,
26 pub component: ast::Component,
27 pub wit: ResolvedWit,
28 pub global_vals: HashMap<GlobalId, ast::Literal>,
29 pub imports: ImportResolver,
30 pub funcs: HashMap<FunctionId, ResolvedFunction>,
31}
32
33#[derive(Clone, Copy, Debug)]
34pub enum ItemId {
35 ImportFunc(ImportFuncId),
36 Type(ResolvedType),
37 Global(GlobalId),
38 Param(ParamId),
39 Local(LocalId),
40 Function(FunctionId),
41}
42
43#[derive(Error, Debug, Diagnostic)]
44pub enum ResolverError {
45 #[error("Failed to resolve")]
46 Base {
47 #[source_code]
48 src: Source,
49 #[label("This bit")]
50 span: SourceSpan,
51 },
52 #[error("Conflicting types inferred for expression {type_a} != {type_b}")]
53 TypeConflict {
54 #[source_code]
55 src: Source,
56 #[label("This bit")]
57 span: SourceSpan,
58
59 type_a: ResolvedType,
60 type_b: ResolvedType,
61 },
62 #[error("Failed to resolve name \"{ident}\"")]
63 NameError {
64 #[source_code]
65 src: Source,
66 #[label("Name referenced here")]
67 span: SourceSpan,
68 ident: String,
69 },
70 #[error("Function call with wrong number of arguments \"{ident}\"")]
71 CallArgumentsMismatch {
72 #[source_code]
73 src: Source,
74 #[label("Here")]
75 span: SourceSpan,
76 ident: String,
77 },
78 #[error("{0} is not yet supported")]
79 NotYetSupported(String),
80
81 #[error(transparent)]
82 #[diagnostic(transparent)]
83 Wit(#[from] WitError),
84}
85
86pub fn resolve(
87 src: Source,
88 comp: ast::Component,
89 wit: wit::ResolvedWit,
90) -> Result<ResolvedComponent, ResolverError> {
91 let mut mappings: HashMap<String, ItemId> = Default::default();
92
93 let mut imports = ImportResolver::default();
94 imports.resolve_imports(&comp, &wit)?;
95 for (name, import) in imports.mapping.iter() {
96 match import {
97 ImportItemId::Type(rtype) => {
98 mappings.insert(name.to_owned(), ItemId::Type(*rtype));
99 }
100 ImportItemId::Func(func) => {
101 mappings.insert(name.to_owned(), ItemId::ImportFunc(*func));
102 }
103 }
104 }
105
106 for (id, global) in comp.globals.iter() {
107 let name = comp.get_name(global.ident);
108 mappings.insert(name.to_owned(), ItemId::Global(id));
109 }
110 for (id, function) in comp.functions.iter() {
111 let name = comp.get_name(function.ident);
112 mappings.insert(name.to_owned(), ItemId::Function(id));
113 }
114
115 let mut global_vals: HashMap<GlobalId, ast::Literal> = HashMap::new();
116
117 for (id, global) in comp.globals.iter() {
118 let global_val = match comp.expr().get_exp(global.init_value) {
119 ast::Expression::Literal(literal) => literal.clone(),
120 _ => panic!("Only literal expressions allowed in global initializer"),
121 };
122 global_vals.insert(id, global_val);
123 }
124
125 let mut funcs: HashMap<FunctionId, ResolvedFunction> = HashMap::new();
126
127 for (id, function) in comp.functions.iter() {
128 let resolver = FunctionResolver::new(src.clone(), &comp, &imports, function, &mappings);
129 funcs.insert(id, resolver.resolve()?);
130 }
131
132 Ok(ResolvedComponent {
133 src,
134 component: comp,
135 wit,
136 global_vals,
137 imports,
138 funcs,
139 })
140}