1use sipha::red::{SyntaxElement, SyntaxNode};
8use sipha::types::{IntoSyntaxKind, Span};
9
10use leekscript_core::syntax::Kind;
11use leekscript_core::Type;
12
13#[derive(Debug)]
15pub enum TypeExprResult {
16 Ok(Type),
17 Err(Span),
18}
19
20#[must_use]
22pub fn parse_type_expr(node: &SyntaxNode) -> TypeExprResult {
23 if node.kind_as::<Kind>() != Some(Kind::NodeTypeExpr) {
24 return TypeExprResult::Err(
25 node.first_token()
26 .map_or_else(|| Span::new(0, 0), |t| t.text_range()),
27 );
28 }
29
30 let mut elements: Vec<TypeExprElement> = Vec::new();
32 for child in node.children() {
33 match child {
34 SyntaxElement::Token(t) => {
35 if t.is_trivia() {
36 continue;
37 }
38 let text = t.text().to_string();
39 if t.kind_as::<Kind>() == Some(Kind::TokOp) {
40 elements.push(TypeExprElement::Op(text, t.text_range()));
41 } else {
42 elements.push(TypeExprElement::Ident(text, t.text_range()));
44 }
45 }
46 SyntaxElement::Node(n) => {
47 if n.kind_as::<Kind>() == Some(Kind::NodeTypeParams) {
48 elements.push(TypeExprElement::TypeParams(n.clone()));
49 }
50 }
51 }
52 }
53
54 if elements.is_empty() {
58 if let Some(first_tok) = node.first_token() {
59 let name = first_tok.text().to_string();
60 let type_params = node
61 .find_all_nodes(Kind::NodeTypeParams.into_syntax_kind())
62 .into_iter()
63 .next();
64 let ty = parse_primary_type(name.as_str(), type_params.as_ref());
65 if let Ok(ty) = ty {
66 return TypeExprResult::Ok(ty);
67 }
68 }
69 return TypeExprResult::Err(
70 node.first_token()
71 .map_or_else(|| Span::new(0, 0), |t| t.text_range()),
72 );
73 }
74
75 let segments = split_by_pipe(&elements);
77 let mut types = Vec::with_capacity(segments.len());
78 for seg in segments {
79 match parse_type_optional_segment(seg) {
80 Ok(ty) => types.push(ty),
81 Err(span) => return TypeExprResult::Err(span),
82 }
83 }
84
85 if types.is_empty() {
86 return TypeExprResult::Err(
87 node.first_token()
88 .map_or_else(|| Span::new(0, 0), |t| t.text_range()),
89 );
90 }
91 if types.len() == 1 {
92 TypeExprResult::Ok(types.into_iter().next().unwrap())
93 } else {
94 TypeExprResult::Ok(Type::compound(types))
95 }
96}
97
98#[derive(Debug)]
99enum TypeExprElement {
100 Ident(String, Span),
101 Op(String, Span),
102 TypeParams(SyntaxNode),
103}
104
105fn split_by_pipe(elements: &[TypeExprElement]) -> Vec<&[TypeExprElement]> {
106 let mut segments = Vec::new();
107 let mut start = 0;
108 for (i, el) in elements.iter().enumerate() {
109 if let TypeExprElement::Op(ref t, _) = el {
110 if t == "|" {
111 segments.push(&elements[start..i]);
112 start = i + 1;
113 }
114 }
115 }
116 segments.push(&elements[start..]);
117 segments
118}
119
120fn parse_type_optional_segment(seg: &[TypeExprElement]) -> Result<Type, Span> {
121 if seg.is_empty() {
122 return Err(Span::new(0, 0));
123 }
124 let optional = seg.last().and_then(|el| {
125 if let TypeExprElement::Op(t, _) = el {
126 if t == "?" {
127 return Some(());
128 }
129 }
130 None
131 });
132 let seg = if optional.is_some() {
133 &seg[..seg.len().saturating_sub(1)]
134 } else {
135 seg
136 };
137 let ty = parse_type_primary_segment(seg)?;
138 if optional.is_some() {
139 Ok(Type::compound2(ty, Type::null()))
140 } else {
141 Ok(ty)
142 }
143}
144
145fn parse_type_primary_segment(seg: &[TypeExprElement]) -> Result<Type, Span> {
146 let first = seg.first().ok_or_else(|| Span::new(0, 0))?;
147 let (name, _span) = match first {
148 TypeExprElement::Ident(n, s) => (n.as_str(), *s),
149 _ => return Err(first_span(first)),
150 };
151
152 let type_params = seg.iter().find_map(|el| {
154 if let TypeExprElement::TypeParams(n) = el {
155 Some(n)
156 } else {
157 None
158 }
159 });
160
161 parse_primary_type(name, type_params)
162}
163
164fn first_span(el: &TypeExprElement) -> Span {
165 match el {
166 TypeExprElement::Ident(_, s) => *s,
167 TypeExprElement::Op(_, s) => *s,
168 TypeExprElement::TypeParams(n) => n
169 .first_token()
170 .map_or_else(|| Span::new(0, 0), |t| t.text_range()),
171 }
172}
173
174fn parse_primary_type(name: &str, type_params: Option<&SyntaxNode>) -> Result<Type, Span> {
175 let err_span = type_params
176 .and_then(|n| n.first_token().map(|t| t.text_range()))
177 .unwrap_or_else(|| Span::new(0, 0));
178
179 match name {
180 "integer" => Ok(Type::int()),
181 "real" => Ok(Type::real()),
182 "string" => Ok(Type::string()),
183 "boolean" => Ok(Type::bool()),
184 "void" => Ok(Type::void()),
185 "any" => Ok(Type::any()),
186 "null" => Ok(Type::null()),
187 "Object" => Ok(Type::object()),
188 "Class" => {
189 let inner = type_params.and_then(parse_class_type_param);
190 Ok(Type::class(inner))
191 }
192 "Array" => {
193 let inner = type_params
194 .and_then(parse_single_type_param)
195 .unwrap_or(Type::any());
196 Ok(Type::array(inner))
197 }
198 "Map" => {
199 let (k, v) = type_params
200 .and_then(parse_map_type_params)
201 .unwrap_or((Type::any(), Type::any()));
202 Ok(Type::map(k, v))
203 }
204 "Set" => {
205 let inner = type_params
206 .and_then(parse_single_type_param)
207 .unwrap_or(Type::any());
208 Ok(Type::set(inner))
209 }
210 "Interval" => {
211 let inner = type_params
212 .and_then(parse_single_type_param)
213 .unwrap_or(Type::any());
214 Ok(Type::interval(inner))
215 }
216 "Function" => {
217 let (args, ret) = type_params
218 .and_then(parse_function_type_params)
219 .unwrap_or((vec![], Type::any()));
220 Ok(Type::function(args, ret))
221 }
222 "var" => {
223 Err(err_span)
225 }
226 _ => {
227 if type_params.is_some() {
229 return Err(err_span);
230 }
231 Ok(Type::instance(name.to_string()))
232 }
233 }
234}
235
236fn parse_class_type_param(node: &SyntaxNode) -> Option<String> {
238 let type_expr = node
239 .child_nodes()
240 .find(|n| n.kind_as::<Kind>() == Some(Kind::NodeTypeExpr))?;
241 let res = parse_type_expr(&type_expr);
242 match res {
243 TypeExprResult::Ok(Type::Class(Some(name)) | Type::Instance(name)) => Some(name),
244 _ => None,
245 }
246}
247
248fn parse_single_type_param(node: &SyntaxNode) -> Option<Type> {
250 let type_expr = node
251 .child_nodes()
252 .find(|n| n.kind_as::<Kind>() == Some(Kind::NodeTypeExpr))?;
253 match parse_type_expr(&type_expr) {
254 TypeExprResult::Ok(t) => Some(t),
255 TypeExprResult::Err(_) => None,
256 }
257}
258
259fn parse_map_type_params(node: &SyntaxNode) -> Option<(Type, Type)> {
261 let type_exprs: Vec<SyntaxNode> = node
262 .child_nodes()
263 .filter(|n| n.kind_as::<Kind>() == Some(Kind::NodeTypeExpr))
264 .collect();
265 if type_exprs.len() >= 2 {
266 let k = match parse_type_expr(&type_exprs[0]) {
267 TypeExprResult::Ok(t) => t,
268 _ => return None,
269 };
270 let v = match parse_type_expr(&type_exprs[1]) {
271 TypeExprResult::Ok(t) => t,
272 _ => return None,
273 };
274 Some((k, v))
275 } else {
276 None
277 }
278}
279
280fn parse_function_type_params(node: &SyntaxNode) -> Option<(Vec<Type>, Type)> {
282 let type_exprs: Vec<SyntaxNode> = node
283 .child_nodes()
284 .filter(|n| n.kind_as::<Kind>() == Some(Kind::NodeTypeExpr))
285 .collect();
286 if type_exprs.is_empty() {
287 return None;
288 }
289 if type_exprs.len() == 1 {
292 let ret = match parse_type_expr(&type_exprs[0]) {
295 TypeExprResult::Ok(t) => t,
296 _ => return None,
297 };
298 return Some((vec![], ret));
299 }
300 let ret = match parse_type_expr(type_exprs.last()?) {
302 TypeExprResult::Ok(t) => t,
303 _ => return None,
304 };
305 let args: Result<Vec<Type>, ()> = type_exprs[..type_exprs.len() - 1]
306 .iter()
307 .map(|n| match parse_type_expr(n) {
308 TypeExprResult::Ok(t) => Ok(t),
309 TypeExprResult::Err(_) => Err(()),
310 })
311 .collect();
312 let args = args.ok()?;
313 Some((args, ret))
314}
315
316#[must_use]
318pub fn find_type_expr_child(parent: &SyntaxNode) -> Option<SyntaxNode> {
319 parent
320 .child_nodes()
321 .find(|n| n.kind_as::<Kind>() == Some(Kind::NodeTypeExpr))
322}
323
324#[must_use]
328pub fn anon_fn_types(node: &SyntaxNode) -> (Vec<Type>, Type) {
329 if node.kind_as::<Kind>() != Some(Kind::NodeAnonFn) {
330 return (Vec::new(), Type::any());
331 }
332 let mut param_nodes: Vec<SyntaxNode> = node.find_all_nodes(Kind::NodeParam.into_syntax_kind());
333 param_nodes.sort_by_key(|p| p.text_range().start);
334 let param_types: Vec<Type> = param_nodes
335 .iter()
336 .map(|p| {
337 find_type_expr_child(p)
338 .and_then(|te| match parse_type_expr(&te) {
339 TypeExprResult::Ok(t) => Some(t),
340 TypeExprResult::Err(_) => None,
341 })
342 .unwrap_or(Type::any())
343 })
344 .collect();
345 (param_types, Type::any())
346}
347
348#[must_use]
353pub fn param_and_return_types(
354 node: &SyntaxNode,
355 param_kind: Kind,
356) -> (Option<Vec<Type>>, Option<Type>) {
357 let param_nodes: Vec<SyntaxNode> = node
358 .child_nodes()
359 .filter(|n| n.kind_as::<Kind>() == Some(param_kind))
360 .collect();
361 let mut param_types = Vec::with_capacity(param_nodes.len());
362 for p in ¶m_nodes {
363 if let Some(te) = find_type_expr_child(p) {
364 if let TypeExprResult::Ok(ty) = parse_type_expr(&te) {
365 param_types.push(ty);
366 } else {
367 return (None, None);
368 }
369 } else {
370 return (None, None);
371 }
372 }
373 let child_nodes: Vec<SyntaxNode> = node.child_nodes().collect();
374 let return_type_node = child_nodes
375 .iter()
376 .rev()
377 .find(|c| c.kind_as::<Kind>() == Some(Kind::NodeTypeExpr));
378 let return_type = return_type_node.and_then(|te| match parse_type_expr(te) {
379 TypeExprResult::Ok(t) => Some(t),
380 TypeExprResult::Err(_) => None,
381 });
382 (Some(param_types), return_type)
383}
384
385#[cfg(test)]
386mod tests {
387 use super::*;
388 use leekscript_core::parse_signatures;
389 use sipha::red::SyntaxElement;
390 use sipha::types::IntoSyntaxKind;
391
392 fn find_first_type_expr(node: &SyntaxNode) -> Option<SyntaxNode> {
393 if node.kind_as::<Kind>() == Some(Kind::NodeTypeExpr) {
394 return Some(node.clone());
395 }
396 for child in node.children() {
397 if let SyntaxElement::Node(n) = child {
398 if let Some(found) = find_first_type_expr(&n) {
399 return Some(found);
400 }
401 }
402 }
403 None
404 }
405
406 #[test]
407 fn parse_type_expr_integer_from_sig() {
408 let root = parse_signatures("global integer FOO\n")
409 .unwrap()
410 .expect("parse");
411 let type_expr_node = find_first_type_expr(&root).expect("NodeTypeExpr");
412 let result = parse_type_expr(&type_expr_node);
413 match &result {
414 TypeExprResult::Ok(t) => assert_eq!(*t, Type::int()),
415 TypeExprResult::Err(_) => panic!("expected Ok(integer), got {:?}", result),
416 }
417 }
418
419 #[test]
420 fn parse_type_expr_real_optional_from_sig() {
421 let root = parse_signatures("global real? FOO\n")
422 .unwrap()
423 .expect("parse");
424 let type_expr_node = find_first_type_expr(&root).expect("NodeTypeExpr");
425 let result = parse_type_expr(&type_expr_node);
426 match &result {
427 TypeExprResult::Ok(t) => {
428 assert_eq!(*t, Type::compound2(Type::real(), Type::null()));
429 }
430 TypeExprResult::Err(_) => panic!("expected Ok(real|null), got {:?}", result),
431 }
432 }
433
434 #[test]
435 fn parse_type_expr_union_from_sig() {
436 let root = parse_signatures("function f(real|integer x) -> real\n")
437 .unwrap()
438 .expect("parse");
439 let type_expr_nodes = root.find_all_nodes(Kind::NodeTypeExpr.into_syntax_kind());
440 assert!(!type_expr_nodes.is_empty());
441 let param_type = parse_type_expr(&type_expr_nodes[0]);
442 match ¶m_type {
443 TypeExprResult::Ok(t) => {
444 assert_eq!(*t, Type::compound2(Type::real(), Type::int()));
445 }
446 TypeExprResult::Err(_) => panic!("expected Ok(real|integer), got {:?}", param_type),
447 }
448 }
449
450 fn find_type_expr_with_name(root: &SyntaxNode, name: &str) -> Option<SyntaxNode> {
452 for node in root.find_all_nodes(Kind::NodeTypeExpr.into_syntax_kind()) {
453 let first = node.first_token()?;
454 if first.text() == name {
455 return Some(node);
456 }
457 }
458 None
459 }
460
461 #[test]
462 fn parse_type_expr_function_two_args_from_program() {
463 use leekscript_core::parse;
464
465 let source = "var f = null as Function<integer, integer => void>;";
466 let root = parse(source).unwrap().expect("parse");
467 let type_expr_node =
468 find_type_expr_with_name(&root, "Function").expect("Function type node");
469 let result = parse_type_expr(&type_expr_node);
470 match &result {
471 TypeExprResult::Ok(ty) => {
472 if let Type::Function { args, return_type } = ty {
473 assert_eq!(args.len(), 2, "expected 2 param types");
474 assert_eq!(args[0], Type::int());
475 assert_eq!(args[1], Type::int());
476 assert_eq!(**return_type, Type::void());
477 } else {
478 panic!("expected Type::Function, got {:?}", ty);
479 }
480 }
481 TypeExprResult::Err(_) => panic!("expected Ok(Function<...>), got {:?}", result),
482 }
483 }
484
485 #[test]
486 fn parse_type_expr_function_zero_params_from_sig() {
487 let source = "function noArg(Function< => boolean> pred) -> void\n";
488 let root = parse_signatures(source).unwrap().expect("parse");
489 let type_expr_node =
490 find_type_expr_with_name(&root, "Function").expect("Function type node");
491 let result = parse_type_expr(&type_expr_node);
492 match &result {
493 TypeExprResult::Ok(ty) => {
494 if let Type::Function { args, return_type } = ty {
495 assert!(args.is_empty(), "expected 0 param types");
496 assert_eq!(**return_type, Type::bool());
497 } else {
498 panic!("expected Type::Function, got {:?}", ty);
499 }
500 }
501 TypeExprResult::Err(_) => {
502 panic!("expected Ok(Function< => boolean>), got {:?}", result)
503 }
504 }
505 }
506
507 #[test]
508 fn parse_type_expr_function_one_param_from_sig() {
509 let source = "function oneArg(Function<integer => void> fn) -> void\n";
510 let root = parse_signatures(source).unwrap().expect("parse");
511 let type_expr_node =
512 find_type_expr_with_name(&root, "Function").expect("Function type node");
513 let result = parse_type_expr(&type_expr_node);
514 match &result {
515 TypeExprResult::Ok(ty) => {
516 if let Type::Function { args, return_type } = ty {
517 assert_eq!(args.len(), 1);
518 assert_eq!(args[0], Type::int());
519 assert_eq!(**return_type, Type::void());
520 } else {
521 panic!("expected Type::Function, got {:?}", ty);
522 }
523 }
524 TypeExprResult::Err(_) => {
525 panic!("expected Ok(Function<integer => void>), got {:?}", result)
526 }
527 }
528 }
529}