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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//! Enum statement parsing for VB6 CST.
//!
//! This module handles parsing of VB6 Enum (enumeration) statements.
//!
//! Enum statement syntax:
//!
//! \[ Public | Private \] Enum name
//! membername \[= constantexpression\]
//! membername \[= constantexpression\]
//! ...
//! End Enum
//!
//! Enumerations provide a convenient way to work with sets of related constants
//! and to associate constant values with names.
//!
//! [Reference](https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/enum-statement)
use crate::language::Token;
use crate::parsers::SyntaxKind;
use super::Parser;
impl Parser<'_> {
/// Parse a Visual Basic 6 Enum statement with syntax:
///
/// \[ Public | Private \] Enum name
/// membername \[= constantexpression\]
/// membername \[= constantexpression\]
/// ...
/// End Enum
///
/// The Enum statement syntax has these parts:
///
/// | Part | Optional / Required | Description |
/// |-------------|---------------------|-------------|
/// | Public | Optional | Indicates that the Enum type is accessible to all other procedures in all modules. If used in a module that contains an Option Private statement, the Enum is not available outside the project. |
/// | Private | Optional | Indicates that the Enum type is accessible only to other procedures in the module where it is declared. |
/// | name | Required | Name of the Enum type; follows standard variable naming conventions. |
/// | membername | Required | Name of the enumeration member; follows standard variable naming conventions. |
/// | constantexpression | Optional | Value to be assigned to the member (evaluates to a Long). If no constantexpression is specified, the value assigned is either zero (if it is the first membername), or 1 greater than the value of the immediately preceding membername. |
///
/// Remarks:
/// - Enumeration variables are variables declared with an Enum type.
/// - Both variables and properties can be declared with an Enum type.
/// - The values of Enum members are initialized to constant values within the Enum statement.
/// - Values can't be modified at run time.
/// - Enum values are Long integers.
/// - By default, the first member is initialized to 0, and subsequent members are initialized to 1 more than the previous member.
/// - You can assign specific values to members using the = operator.
///
/// Examples:
/// ```vb
/// Public Enum SecurityLevel
/// IllegalEntry = -1
/// SecurityLevel1 = 0
/// SecurityLevel2 = 1
/// End Enum
/// ```
///
/// [Reference](https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/enum-statement)
pub(crate) fn parse_enum_statement(&mut self) {
// if we are now parsing an enum statement, we are no longer in the header.
self.parsing_header = false;
self.builder.start_node(SyntaxKind::EnumStatement.to_raw());
// Consume any leading whitespace
self.consume_whitespace();
// Consume optional Public/Private keyword
if self.at_token(Token::PublicKeyword) || self.at_token(Token::PrivateKeyword) {
self.consume_token();
// Consume any whitespace after visibility modifier
self.consume_whitespace();
}
// Consume "Enum" keyword
self.consume_token();
// Consume any whitespace after "Enum"
self.consume_whitespace();
// Consume enum name (keywords can be used as enum names in VB6)
if self.at_token(Token::Identifier) {
self.consume_token();
} else if self.at_keyword() {
self.consume_token_as_identifier();
}
// Consume everything until newline (preserving all tokens)
self.consume_until_after(Token::Newline);
// Wrap body in StatementList for formatter indent tracking
self.builder.start_node(SyntaxKind::StatementList.to_raw());
// Parse enum members until "End Enum"
while !self.is_at_end() {
// Check if we've reached "End Enum"
if self.at_token(Token::EndKeyword)
&& self.peek_next_keyword() == Some(Token::EnumKeyword)
{
break;
}
// Consume enum member lines (identifier [= expression])
// This includes whitespace, comments, identifiers, operators, and newlines
// Also includes square brackets for VB6 attributes like [Description("...")]
match self.current_token() {
Some(
Token::Whitespace
| Token::Newline
| Token::EndOfLineComment
| Token::RemComment
| Token::Identifier
| Token::EqualityOperator
| Token::IntegerLiteral
| Token::LongLiteral
| Token::SingleLiteral
| Token::DoubleLiteral
| Token::SubtractionOperator
| Token::AdditionOperator
| Token::MultiplicationOperator
| Token::DivisionOperator
| Token::ExponentiationOperator
| Token::LeftParenthesis
| Token::RightParenthesis
| Token::Ampersand
| Token::Underscore
| Token::Comma
| Token::LeftSquareBracket
| Token::RightSquareBracket,
) => {
self.consume_token();
}
_ if self.at_keyword() => {
// Keywords can appear inside square brackets as escaped identifiers
self.consume_token();
}
_ => {
self.consume_error(vec!["enum member name".to_string()]);
}
}
}
self.builder.finish_node(); // StatementList
// Consume "End Enum" and trailing tokens
if self.at_token(Token::EndKeyword) {
// Consume "End"
self.consume_token();
// Consume any whitespace between "End" and "Enum"
self.consume_whitespace();
// Consume "Enum"
self.consume_token();
// Consume until newline (including it)
self.consume_until_after(Token::Newline);
}
self.builder.finish_node(); // EnumStatement
}
}