Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
compiler_lexer_test.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
37# include <gtest/gtest.h>
38
39# include <Compiler_Lexer.H>
40
41# include <vector>
42
43using namespace Aleph;
44
45
46namespace
47{
48 std::vector<Compiler_Token_Kind>
50 {
51 std::vector<Compiler_Token_Kind> kinds;
52 while (true)
53 {
54 const auto tok = lexer.next();
55 kinds.push_back(tok.kind);
56 if (tok.is_eof() or tok.is_invalid())
57 break;
58 }
59 return kinds;
60 }
61}
62
63
65{
67 const auto id = sm.add_virtual_file("main.aw",
68 "fn add(x, y) { return x + 42; }\n");
70 Compiler_Lexer lexer(sm, id, &dx);
71
72 const auto t0 = lexer.next();
73 const auto t1 = lexer.next();
74 const auto t2 = lexer.next();
75 const auto t3 = lexer.next();
76 const auto t4 = lexer.next();
77 const auto t5 = lexer.next();
78 const auto t6 = lexer.next();
79 const auto t7 = lexer.next();
80 const auto t8 = lexer.next();
81 const auto t9 = lexer.next();
82 const auto t10 = lexer.next();
83 const auto t11 = lexer.next();
84 const auto t12 = lexer.next();
85 const auto t13 = lexer.next();
86 const auto t14 = lexer.next();
87
88 EXPECT_EQ(t0.kind, Compiler_Token_Kind::Kw_Fn);
89 EXPECT_EQ(t1.kind, Compiler_Token_Kind::Identifier);
90 EXPECT_EQ(t1.lexeme, "add");
91 EXPECT_EQ(t1.span.begin, 3u);
92 EXPECT_EQ(t1.span.end, 6u);
93 EXPECT_EQ(t2.kind, Compiler_Token_Kind::LParen);
94 EXPECT_EQ(t3.kind, Compiler_Token_Kind::Identifier);
95 EXPECT_EQ(t3.lexeme, "x");
96 EXPECT_EQ(t4.kind, Compiler_Token_Kind::Comma);
97 EXPECT_EQ(t5.kind, Compiler_Token_Kind::Identifier);
98 EXPECT_EQ(t5.lexeme, "y");
99 EXPECT_EQ(t6.kind, Compiler_Token_Kind::RParen);
100 EXPECT_EQ(t7.kind, Compiler_Token_Kind::LBrace);
101 EXPECT_EQ(t8.kind, Compiler_Token_Kind::Kw_Return);
102 EXPECT_EQ(t9.kind, Compiler_Token_Kind::Identifier);
103 EXPECT_EQ(t10.kind, Compiler_Token_Kind::Plus);
104 EXPECT_EQ(t11.kind, Compiler_Token_Kind::Integer_Literal);
105 EXPECT_EQ(t11.lexeme, "42");
106 EXPECT_EQ(t11.span.begin, 26u);
107 EXPECT_EQ(t11.span.end, 28u);
108 EXPECT_EQ(t12.kind, Compiler_Token_Kind::Semicolon);
109 EXPECT_EQ(t13.kind, Compiler_Token_Kind::RBrace);
110 EXPECT_TRUE(t14.is_eof());
111
113}
114
115
117{
119 const auto id = sm.add_virtual_file("types.aw", "struct Point {} enum Color {} type UserId = Int;");
120 Compiler_Lexer lexer(sm, id);
121
122 const auto t0 = lexer.next();
123 const auto t1 = lexer.next();
124 const auto t2 = lexer.next();
125 const auto t3 = lexer.next();
126 const auto t4 = lexer.next();
127 const auto t5 = lexer.next();
128 const auto t6 = lexer.next();
129 const auto t7 = lexer.next();
130 const auto t8 = lexer.next();
131 const auto t9 = lexer.next();
132 const auto t10 = lexer.next();
133 const auto t11 = lexer.next();
134 const auto t12 = lexer.next();
135
136 EXPECT_EQ(t0.kind, Compiler_Token_Kind::Kw_Struct);
137 EXPECT_EQ(t1.kind, Compiler_Token_Kind::Identifier);
138 EXPECT_EQ(t4.kind, Compiler_Token_Kind::Kw_Enum);
139 EXPECT_EQ(t5.kind, Compiler_Token_Kind::Identifier);
140 EXPECT_EQ(t8.kind, Compiler_Token_Kind::Kw_Type);
141 EXPECT_EQ(t9.kind, Compiler_Token_Kind::Identifier);
142 EXPECT_EQ(t10.kind, Compiler_Token_Kind::Assign);
143 EXPECT_EQ(t11.kind, Compiler_Token_Kind::Identifier);
144 EXPECT_EQ(t12.kind, Compiler_Token_Kind::Semicolon);
145}
146
147
149{
151 const auto id = sm.add_virtual_file("main.aw", "let value");
152 Compiler_Lexer lexer(sm, id);
153
154 const auto look1 = lexer.peek();
155 const auto look2 = lexer.peek();
156 const auto next = lexer.next();
157 const auto ident = lexer.next();
158
159 EXPECT_EQ(look1.kind, Compiler_Token_Kind::Kw_Let);
160 EXPECT_EQ(look1.lexeme, "let");
161 EXPECT_EQ(look2.kind, Compiler_Token_Kind::Kw_Let);
162 EXPECT_EQ(next.kind, Compiler_Token_Kind::Kw_Let);
163 EXPECT_EQ(ident.kind, Compiler_Token_Kind::Identifier);
164 EXPECT_EQ(ident.lexeme, "value");
165}
166
167
169{
171 const auto id = sm.add_virtual_file("main.aw",
172 "let x = 1; // note\n/* block */ return x;");
174 Compiler_Lexer lexer(sm, id, &dx);
175
176 const auto kinds = collect_kinds(lexer);
177 const std::vector<Compiler_Token_Kind> expected = {
178 Compiler_Token_Kind::Kw_Let,
179 Compiler_Token_Kind::Identifier,
180 Compiler_Token_Kind::Assign,
181 Compiler_Token_Kind::Integer_Literal,
182 Compiler_Token_Kind::Semicolon,
183 Compiler_Token_Kind::Kw_Return,
184 Compiler_Token_Kind::Identifier,
185 Compiler_Token_Kind::Semicolon,
186 Compiler_Token_Kind::End_Of_File
187 };
188
191}
192
193
195{
197 const auto id = sm.add_virtual_file("main.aw", "// note\n/* block */");
199 opts.keep_comments = true;
200 Compiler_Lexer lexer(sm, id, nullptr, opts);
201
202 const auto t0 = lexer.next();
203 const auto t1 = lexer.next();
204 const auto t2 = lexer.next();
205
206 EXPECT_EQ(t0.kind, Compiler_Token_Kind::Line_Comment);
207 EXPECT_EQ(t0.lexeme, "// note");
208 EXPECT_EQ(t1.kind, Compiler_Token_Kind::Block_Comment);
209 EXPECT_EQ(t1.lexeme, "/* block */");
210 EXPECT_TRUE(t2.is_eof());
211}
212
213
215{
217 const auto id = sm.add_virtual_file("main.aw", "/*x*/");
220 Compiler_Lexer lexer(sm, id, nullptr, opts);
221
222 const auto kinds = collect_kinds(lexer);
223 const std::vector<Compiler_Token_Kind> expected = {
224 Compiler_Token_Kind::Slash,
225 Compiler_Token_Kind::Star,
226 Compiler_Token_Kind::Identifier,
227 Compiler_Token_Kind::Star,
228 Compiler_Token_Kind::Slash,
229 Compiler_Token_Kind::End_Of_File
230 };
231
233}
234
235
237{
239 const auto id = sm.add_virtual_file("main.aw", "'a' \"hi\\n\" += == && ->");
241 Compiler_Lexer lexer(sm, id, &dx);
242
243 const auto t0 = lexer.next();
244 const auto t1 = lexer.next();
245 const auto t2 = lexer.next();
246 const auto t3 = lexer.next();
247 const auto t4 = lexer.next();
248 const auto t5 = lexer.next();
249 const auto t6 = lexer.next();
250
251 EXPECT_EQ(t0.kind, Compiler_Token_Kind::Char_Literal);
252 EXPECT_EQ(t0.lexeme, "'a'");
253 EXPECT_EQ(t1.kind, Compiler_Token_Kind::String_Literal);
254 EXPECT_EQ(t1.lexeme, "\"hi\\n\"");
255 EXPECT_EQ(t2.kind, Compiler_Token_Kind::PlusEq);
256 EXPECT_EQ(t3.kind, Compiler_Token_Kind::EqEq);
257 EXPECT_EQ(t4.kind, Compiler_Token_Kind::AndAnd);
258 EXPECT_EQ(t5.kind, Compiler_Token_Kind::Arrow);
259 EXPECT_TRUE(t6.is_eof());
260
262}
263
264
266{
268 const auto id = sm.add_virtual_file("main.aw", "@");
270 Compiler_Lexer lexer(sm, id, &dx);
271
272 const auto tok = lexer.next();
273
274 EXPECT_TRUE(tok.is_invalid());
275 EXPECT_EQ(tok.lexeme, "@");
276 ASSERT_EQ(dx.size(), 1u);
277 EXPECT_EQ(dx.get(0).code, "LEX001");
278 EXPECT_EQ(dx.get(0).message, "unexpected character '@'");
279}
280
281
283{
285 const auto id = sm.add_virtual_file("main.aw", "\"abc");
287 Compiler_Lexer lexer(sm, id, &dx);
288
289 const auto tok = lexer.next();
290
291 EXPECT_TRUE(tok.is_invalid());
292 EXPECT_EQ(tok.lexeme, "\"abc");
293 ASSERT_EQ(dx.size(), 1u);
294 EXPECT_EQ(dx.get(0).code, "LEX002");
295 EXPECT_EQ(dx.get(0).message, "unterminated string literal");
296}
297
298
300{
302 const auto id = sm.add_virtual_file("main.aw", "/* block");
304 Compiler_Lexer lexer(sm, id, &dx);
305
306 const auto tok = lexer.next();
307
308 EXPECT_TRUE(tok.is_invalid());
309 EXPECT_EQ(tok.lexeme, "/* block");
310 ASSERT_EQ(dx.size(), 1u);
311 EXPECT_EQ(dx.get(0).code, "LEX004");
312 EXPECT_EQ(dx.get(0).message, "unterminated block comment");
313}
314
315
317{
319 const auto id = sm.add_virtual_file("main.aw", "'ab'");
321 Compiler_Lexer lexer(sm, id, &dx);
322
323 const auto tok = lexer.next();
324
325 EXPECT_TRUE(tok.is_invalid());
326 ASSERT_EQ(dx.size(), 1u);
327 EXPECT_EQ(dx.get(0).code, "LEX003");
328 EXPECT_EQ(dx.get(0).message, "malformed character literal");
329}
330
331
333{
335 const auto id = sm.add_virtual_file("empty.aw", "");
337 Compiler_Lexer lexer(sm, id, &dx);
338
339 // Empty input should report EOF immediately
340 EXPECT_TRUE(lexer.eof());
341 const auto tok = lexer.next();
342 EXPECT_TRUE(tok.is_eof());
343}
344
345
347{
349 // "fn x" is 4 bytes (fn=0..1, space=2, x=3)
350 const auto id = sm.add_virtual_file("api.aw", "fn x");
352 Compiler_Lexer lexer(sm, id, &dx);
353
354 // source_file_id() must match the file we registered
355 EXPECT_EQ(lexer.source_file_id(), id);
356
357 // At start, cursor is at 0
358 EXPECT_EQ(lexer.current_offset(), 0u);
359 EXPECT_FALSE(lexer.eof());
360
361 // Consume "fn" token; offset should advance
362 const auto tok_fn = lexer.next();
363 EXPECT_EQ(tok_fn.kind, Compiler_Token_Kind::Kw_Fn);
364 EXPECT_GT(lexer.current_offset(), 0u);
365
366 // Consume "x" identifier
367 const auto tok_x = lexer.next();
368 EXPECT_EQ(tok_x.kind, Compiler_Token_Kind::Identifier);
369
370 // Next token is EOF
371 EXPECT_TRUE(lexer.eof());
372 const auto tok_eof = lexer.next();
373 EXPECT_TRUE(tok_eof.is_eof());
374
375 // reset(0) restores cursor and lets us re-lex from the start
376 lexer.reset(0);
377 EXPECT_EQ(lexer.current_offset(), 0u);
378 EXPECT_FALSE(lexer.eof());
379 const auto tok_fn2 = lexer.next();
380 EXPECT_EQ(tok_fn2.kind, Compiler_Token_Kind::Kw_Fn);
381
382 // reset(offset) past end of file must throw
383 const Source_Offset past_end = sm.file_text(id).size() + 1;
384 EXPECT_THROW(lexer.reset(past_end), std::out_of_range);
385}
Lexical analyzer (Lexer) based on Source_Manager.
Token generator for a single source file.
Source_Offset current_offset() const noexcept
Returns the current byte offset in the file.
Compiler_Token next()
Consumes and returns the next token from the stream.
bool eof()
Indicates whether the end of the file has been reached.
const Compiler_Token & peek()
Peeks at the next token without advancing the cursor.
Source_File_Id source_file_id() const noexcept
Returns the file ID currently being analyzed.
void reset(const Source_Offset offset=0)
Repositions the reading cursor.
Diagnostic accumulator and renderer.
bool has_errors() const noexcept
Returns whether any error or fatal diagnostic was emitted.
const Diagnostic & get(const size_t i) const
Returns diagnostic i.
size_t size() const noexcept
Returns the number of stored diagnostics.
Stores source files and resolves offsets into human-readable data.
Definition ah-source.H:184
Source_File_Id add_virtual_file(const std::string &name, const std::string &text)
Registers an in-memory source file.
Definition ah-source.H:258
Minimal std::expected-style result type for C++20.
#define TEST(name)
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:171
size_t Source_Offset
Definition ah-source.H:62
Configuration options for lexer behavior.
bool allow_block_comments
If false, /* is treated as / followed by *.
bool keep_comments
If true, comments are returned as tokens.
std::string code
Optional stable code such as E001.
std::string message
Main headline message.