1use tl_ast::TypeExpr;
5
6use crate::{Type, TypeEnv};
7
8pub fn convert_type_expr(texpr: &TypeExpr) -> Type {
10 convert_type_expr_with_params(texpr, &[])
11}
12
13pub fn convert_type_expr_with_env(texpr: &TypeExpr, env: &TypeEnv) -> Type {
15 convert_type_expr_impl(texpr, &[], Some(env))
16}
17
18pub fn convert_type_expr_with_params(texpr: &TypeExpr, type_params: &[String]) -> Type {
20 convert_type_expr_impl(texpr, type_params, None)
21}
22
23fn convert_type_expr_impl(texpr: &TypeExpr, type_params: &[String], env: Option<&TypeEnv>) -> Type {
24 match texpr {
25 TypeExpr::Named(name) => {
26 if type_params.contains(name) {
27 Type::TypeParam(name.clone())
28 } else if let Some(env) = env {
29 if env.is_resolving_alias(name) {
31 return Type::Error; }
33 if let Some((alias_params, alias_value)) = env.lookup_type_alias(name)
34 && alias_params.is_empty()
35 {
36 return convert_type_expr_impl(alias_value, type_params, Some(env));
37 }
38 convert_named(name)
39 } else {
40 convert_named(name)
41 }
42 }
43 TypeExpr::Generic { name, args } => {
44 if let Some(env) = env
46 && let Some((alias_params, alias_value)) = env.lookup_type_alias(name).cloned()
47 && !alias_params.is_empty()
48 && alias_params.len() == args.len()
49 {
50 return convert_type_expr_impl(&alias_value, type_params, Some(env));
52 }
53 convert_generic_impl(name, args, type_params, env)
54 }
55 TypeExpr::Optional(inner) => {
56 Type::Option(Box::new(convert_type_expr_impl(inner, type_params, env)))
57 }
58 TypeExpr::Function {
59 params,
60 return_type,
61 } => Type::Function {
62 params: params
63 .iter()
64 .map(|p| convert_type_expr_impl(p, type_params, env))
65 .collect(),
66 ret: Box::new(convert_type_expr_impl(return_type, type_params, env)),
67 },
68 }
69}
70
71fn convert_named(name: &str) -> Type {
72 match name {
73 "int" | "int64" => Type::Int,
74 "float" | "float64" => Type::Float,
75 "string" => Type::String,
76 "bool" => Type::Bool,
77 "none" => Type::None,
78 "any" => Type::Any,
79 "unit" | "void" => Type::Unit,
80 "table" => Type::Table {
81 name: None,
82 columns: None,
83 },
84 "tensor" => Type::Tensor,
85 "pipeline" => Type::Pipeline,
86 "decimal" => Type::Decimal,
87 other => {
88 Type::Struct(other.to_string())
91 }
92 }
93}
94
95#[allow(dead_code)]
96fn convert_generic(name: &str, args: &[TypeExpr]) -> Type {
97 convert_generic_with_params(name, args, &[])
98}
99
100fn convert_generic_with_params(name: &str, args: &[TypeExpr], type_params: &[String]) -> Type {
101 convert_generic_impl(name, args, type_params, None)
102}
103
104fn convert_generic_impl(
105 name: &str,
106 args: &[TypeExpr],
107 type_params: &[String],
108 env: Option<&TypeEnv>,
109) -> Type {
110 match name {
111 "list" if args.len() == 1 => {
112 Type::List(Box::new(convert_type_expr_impl(&args[0], type_params, env)))
113 }
114 "map" if args.len() == 1 => {
115 Type::Map(Box::new(convert_type_expr_impl(&args[0], type_params, env)))
116 }
117 "set" if args.len() == 1 => {
118 Type::Set(Box::new(convert_type_expr_impl(&args[0], type_params, env)))
119 }
120 "option" if args.len() == 1 => {
121 Type::Option(Box::new(convert_type_expr_impl(&args[0], type_params, env)))
122 }
123 "result" if args.len() == 2 => Type::Result(
124 Box::new(convert_type_expr_impl(&args[0], type_params, env)),
125 Box::new(convert_type_expr_impl(&args[1], type_params, env)),
126 ),
127 "generator" if args.len() == 1 => {
128 Type::Generator(Box::new(convert_type_expr_impl(&args[0], type_params, env)))
129 }
130 "task" if args.len() == 1 => {
131 Type::Task(Box::new(convert_type_expr_impl(&args[0], type_params, env)))
132 }
133 "channel" if args.len() == 1 => {
134 Type::Channel(Box::new(convert_type_expr_impl(&args[0], type_params, env)))
135 }
136 "stream" if args.len() == 1 => {
137 Type::Stream(Box::new(convert_type_expr_impl(&args[0], type_params, env)))
138 }
139 "table" if args.len() == 1 => {
140 if let TypeExpr::Named(schema) = &args[0] {
141 Type::Table {
142 name: Some(schema.clone()),
143 columns: None,
144 }
145 } else {
146 Type::Table {
147 name: None,
148 columns: None,
149 }
150 }
151 }
152 _ => {
153 Type::Struct(name.to_string())
155 }
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 use tl_ast::TypeExpr;
163
164 #[test]
165 fn test_convert_primitives() {
166 assert_eq!(convert_type_expr(&TypeExpr::Named("int".into())), Type::Int);
167 assert_eq!(
168 convert_type_expr(&TypeExpr::Named("float".into())),
169 Type::Float
170 );
171 assert_eq!(
172 convert_type_expr(&TypeExpr::Named("string".into())),
173 Type::String
174 );
175 assert_eq!(
176 convert_type_expr(&TypeExpr::Named("bool".into())),
177 Type::Bool
178 );
179 }
180
181 #[test]
182 fn test_convert_optional() {
183 let texpr = TypeExpr::Optional(Box::new(TypeExpr::Named("int".into())));
184 assert_eq!(convert_type_expr(&texpr), Type::Option(Box::new(Type::Int)));
185 }
186
187 #[test]
188 fn test_convert_generic_list() {
189 let texpr = TypeExpr::Generic {
190 name: "list".into(),
191 args: vec![TypeExpr::Named("int".into())],
192 };
193 assert_eq!(convert_type_expr(&texpr), Type::List(Box::new(Type::Int)));
194 }
195
196 #[test]
197 fn test_convert_result() {
198 let texpr = TypeExpr::Generic {
199 name: "result".into(),
200 args: vec![
201 TypeExpr::Named("int".into()),
202 TypeExpr::Named("string".into()),
203 ],
204 };
205 assert_eq!(
206 convert_type_expr(&texpr),
207 Type::Result(Box::new(Type::Int), Box::new(Type::String))
208 );
209 }
210
211 #[test]
212 fn test_convert_function_type() {
213 let texpr = TypeExpr::Function {
214 params: vec![TypeExpr::Named("int".into())],
215 return_type: Box::new(TypeExpr::Named("string".into())),
216 };
217 assert_eq!(
218 convert_type_expr(&texpr),
219 Type::Function {
220 params: vec![Type::Int],
221 ret: Box::new(Type::String),
222 }
223 );
224 }
225}