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
//! Type annotation parsing.
use super::Parser;
use crate::ast::ty::TypeExpr;
pub struct TypeParserEngine;
impl TypeParserEngine {
/// Reads raw string type annotation tokens until the next statement delimiter.
pub fn read_type_annotation(parser: &mut Parser) -> String {
let mut parts = Vec::new();
let mut braces = 0usize;
let mut brackets = 0usize;
let mut parens = 0usize;
let mut last_line = None;
while !parser.is_eof() {
let token = parser.peek().clone();
if token.kind == "eof" {
break;
}
if braces == 0
&& brackets == 0
&& parens == 0
&& last_line.is_some_and(|line| line != token.line)
{
break;
}
// Types never put two names side by side, so a name right after a
// complete type starts the body: `function f(): () x = 1 end`.
if braces == 0
&& brackets == 0
&& parens == 0
&& token.kind == "name"
&& parts.last().is_some_and(|prev: &String| {
prev == ")"
|| prev == "}"
|| prev == "]"
|| prev == "?"
|| prev.starts_with(|c: char| c.is_alphanumeric() || c == '_')
})
{
break;
}
last_line = Some(token.line);
if token.kind == "symbol" {
if braces == 0
&& brackets == 0
&& parens == 0
&& matches!(token.value.as_str(), "=" | "," | ")" | ";")
{
break;
}
match token.value.as_str() {
"{" => braces += 1,
"}" if braces > 0 => braces -= 1,
"[" => brackets += 1,
"]" if brackets > 0 => brackets -= 1,
"(" => parens += 1,
")" if parens > 0 => parens -= 1,
_ => {}
}
}
if token.kind == "keyword"
&& braces == 0
&& brackets == 0
&& parens == 0
&& matches!(
token.value.as_str(),
"end"
| "do"
| "then"
| "else"
| "elseif"
| "until"
| "return"
| "local"
| "const"
| "global"
| "if"
| "for"
| "while"
| "repeat"
)
{
break;
}
parts.push(parser.advance_token().value);
}
parts.join(" ")
}
/// Parses a structured `TypeExpr` from the current token stream.
pub fn parse_type_expr(parser: &mut Parser) -> Result<TypeExpr, String> {
let raw = Self::read_type_annotation(parser);
if raw.trim().is_empty() {
return Ok(TypeExpr::Any);
}
Ok(TypeExpr::parse(&raw))
}
}
pub fn read_type_annotation(parser: &mut Parser) -> String {
TypeParserEngine::read_type_annotation(parser)
}
pub fn parse_type_expr(parser: &mut Parser) -> Result<TypeExpr, String> {
TypeParserEngine::parse_type_expr(parser)
}