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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
//! # Summary
//!
//! `VB6Parse` is a library for parsing Visual Basic 6 (VB6) code. It is a
//! foundational library for tools and utilities that parse / analyse / convert
//! VB6 code. It is designed to be used as a base library for other tools and utilities.
//!
//! ## Design Goals
//!
//! `VB6Parse` is designed to be a fast and efficient library for parsing VB6 code.
//! Despite focusing on speed, ease of use has a high priority. While it should
//! be possible for the library to be used to create things like real-time syntax
//! highlighting, a language server, an interpreter, or a high speed compiler,
//! the primary goal is focused around offline analysis, legacy utilities,
//! and tools that convert VB6 code to more modern languages.
//!
//! ## Project File Parsing
//!
//! To load a VB6 project file, you can use the `Project::parse` method.
//! This method takes a `SourceFile` as input, and returns a
//! `Project` struct that contains the parsed information.
//!
//! ```rust
//! use vb6parse::*;
//! use vb6parse::files::project::properties::CompileTargetType;
//!
//! let input = r#"Type=Exe
//! Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\Windows\System32\stdole2.tlb#OLE Automation
//! Object={00020430-0000-0000-C000-000000000046}#2.0#0; stdole2.tlb
//! Module=Module1; Module1.bas
//! Class=Class1; Class1.cls
//! Form=Form1.frm
//! Form=Form2.frm
//! UserControl=UserControl1.ctl
//! UserDocument=UserDocument1.uds
//! ExeName32="Project1.exe"
//! Command32=""
//! Path32=""
//! Name="Project1"
//! HelpContextID="0"
//! CompatibleMode="0"
//! MajorVer=1
//! MinorVer=0
//! RevisionVer=0
//! AutoIncrementVer=0
//! StartMode=0
//! Unattended=0
//! Retained=0
//! ThreadPerObject=0
//! MaxNumberOfThreads=1
//! DebugStartupOption=0
//! NoControlUpgrade=0
//! ServerSupportFiles=0
//! VersionCompanyName="Company Name"
//! VersionFileDescription="File Description"
//! VersionLegalCopyright="Copyright"
//! VersionLegalTrademarks="Trademark"
//! VersionProductName="Product Name"
//! VersionComments="Comments"
//! CompilationType=0
//! OptimizationType=0
//! FavorPentiumPro(tm)=0
//! CodeViewDebugInfo=0
//! NoAliasing=0
//! BoundsCheck=0
//! OverflowCheck=0
//! FlPointCheck=0
//! FDIVCheck=0
//! UnroundedFP=0
//! CondComp=""
//! ResFile32=""
//! IconForm=""
//! Startup="Form1"
//! HelpFile=""
//! Title="Project1"
//!
//! [MS Transaction Server]
//! AutoRefresh=1
//! "#;
//!
//!
//! let project_source_file = match SourceFile::decode_with_replacement("project1.vbp", input.as_bytes()) {
//! Ok(source_file) => source_file,
//! Err(e) => {
//! e.print();
//! panic!("failed to decode project source code.");
//! }
//! };
//!
//! let result = ProjectFile::parse(&project_source_file);
//!
//! let (Some(project), failures) = result.unpack() else {
//! panic!("Project parse had no result");
//! };
//!
//! if !failures.is_empty() {
//! for failure in failures {
//! failure.print();
//! }
//! panic!("Project parse had failures");
//! }
//!
//!
//! assert_eq!(project.project_type, CompileTargetType::Exe);
//! assert_eq!(project.references().collect::<Vec<_>>().len(), 1);
//! assert_eq!(project.objects().collect::<Vec<_>>().len(), 1);
//! assert_eq!(project.modules().collect::<Vec<_>>().len(), 1);
//! assert_eq!(project.classes().collect::<Vec<_>>().len(), 1);
//! assert_eq!(project.designers().collect::<Vec<_>>().len(), 0);
//! assert_eq!(project.forms().collect::<Vec<_>>().len(), 2);
//! assert_eq!(project.user_controls().collect::<Vec<_>>().len(), 1);
//! assert_eq!(project.user_documents().collect::<Vec<_>>().len(), 1);
//! assert_eq!(project.properties.startup, "Form1");
//! assert_eq!(project.properties.title, "Project1");
//! assert_eq!(project.properties.exe_32_file_name, "Project1.exe");
//! ```
//!
//! Note that in the example above, the `ProjectFile::parse` method is used to parse
//! the project file. The `ProjectFile` struct contains the parsed information
//! about the project, including the project type, references, objects, modules,
//! classes, forms, user controls, etc. These references are not actually loaded
//! or parsed. This makes it possible to read a project file in parts or to
//! read a project file without having to load all the files in the project.
//!
//! ## Form File Parsing
//!
//! To load a VB6 form file, you can use the `FormFile::parse` method. This
//! pattern is very similar to the `ProjectFile::parse` method and this pattern is
//! repeated throughout the library.
//!
//! ```rust
//! use vb6parse::FormFile;
//!
//! let input = b"VERSION 5.00\r
//! Begin VB.Form frmExampleForm\r
//! BackColor = &H80000005&\r
//! Caption = \"example form\"\r
//! ClientHeight = 6210\r
//! ClientLeft = 60\r
//! ClientTop = 645\r
//! ClientWidth = 9900\r
//! BeginProperty Font\r
//! Name = \"Arial\"\r
//! Size = 8.25\r
//! Charset = 0\r
//! Weight = 400\r
//! Underline = 0 'False\r
//! Italic = 0 'False\r
//! Strikethrough = 0 'False\r
//! EndProperty\r
//! LinkTopic = \"Form1\"\r
//! ScaleHeight = 414\r
//! ScaleMode = 3 'Pixel\r
//! ScaleWidth = 660\r
//! StartUpPosition = 2 'CenterScreen\r
//! Begin VB.Menu mnuFile\r
//! Caption = \"&File\"\r
//! Begin VB.Menu mnuOpenImage\r
//! Caption = \"&Open image\"\r
//! End\r
//! End\r
//! End\r
//! Attribute VB_Name = \"frmExampleForm\"\r
//! ";
//!
//! let source = vb6parse::SourceFile::decode("frmExampleForm.frm", input).expect("Failed to decode source file");
//! let result = FormFile::parse(&source);
//!
//! let (Some(project), failures) = result.unpack() else {
//! panic!("Project parse had no result");
//! };
//!
//! if !failures.is_empty() {
//! for failure in failures {
//! failure.print();
//! }
//! panic!("Project parse had failures");
//! }
//!
//! assert_eq!(project.attributes.name, "frmExampleForm");
//! ```
// =============================================================================
// Layer modules (for advanced users who need full access)
// =============================================================================
// wasm module for playground use.
// =============================================================================
// Top-level re-exports for common use cases
// =============================================================================
// I/O Layer - Decoding and character stream access
pub use crate;
// Lexer Layer - Tokenization
pub use crate;
// File Parsers - Main entry points for parsing VB6 files
pub use crate;
// Syntax Parsers - CST parsing and tree types
pub use crate;
// Error Types - New unified error handling (Phase 4)
pub use crate;