@@ -28,6 +28,7 @@ import csetjmp local;
28
28
import stdarg local;
29
29
import stdio local;
30
30
import string;
31
+ import stdlib;
31
32
32
33
type Kind enum u8 {
33
34
// global
@@ -47,6 +48,8 @@ type Kind enum u8 {
47
48
Export,
48
49
Use,
49
50
AsmFile,
51
+ Set,
52
+ SetUse,
50
53
Eof,
51
54
}
52
55
@@ -67,6 +70,8 @@ const char*[] kind_names = {
67
70
"$export",
68
71
"$use",
69
72
"$asm",
73
+ "set",
74
+ "(set)",
70
75
"eof",
71
76
}
72
77
@@ -82,6 +87,53 @@ fn void Token.init(Token* t) {
82
87
string.memset(t, 0, sizeof(Token));
83
88
}
84
89
90
+
91
+ type Set struct {
92
+ u32 name_idx; // into aux pool
93
+ SrcLoc loc;
94
+
95
+ build_target.File* files;
96
+ u32 num_files;
97
+ u32 max_files;
98
+
99
+ Set* next;
100
+ }
101
+
102
+ fn Set* Set.create(u32 name, SrcLoc loc, Set* next) {
103
+ Set* s = stdlib.calloc(1, sizeof(Set));
104
+ s.name_idx = name;
105
+ s.loc = loc;
106
+ s.next = next;
107
+
108
+ s.max_files = 8;
109
+ s.files = stdlib.malloc(8*sizeof(build_target.File));
110
+ return s;
111
+ }
112
+
113
+ fn void Set.free(Set* s) {
114
+ stdlib.free(s.files);
115
+ stdlib.free(s);
116
+ }
117
+
118
+ fn bool Set.addFile(Set* s, u32 filename, SrcLoc loc) {
119
+ for (u32 i=0; i<s.num_files; i++) {
120
+ if (s.files[i].name == filename) return false;
121
+ }
122
+
123
+ if (s.num_files == s.max_files) {
124
+ s.max_files *= 2;
125
+ build_target.File* files2 = stdlib.malloc(s.max_files * sizeof(build_target.File));
126
+ string.memcpy(files2, s.files, s.num_files * sizeof(build_target.File));
127
+ stdlib.free(s.files);
128
+ s.files = files2;
129
+ }
130
+
131
+ s.files[s.num_files].name = filename;
132
+ s.files[s.num_files].loc = loc;
133
+ s.num_files++;
134
+ return true;
135
+ }
136
+
85
137
type Parser struct {
86
138
Recipe* recipe;
87
139
string_pool.Pool* pool;
@@ -96,6 +148,17 @@ type Parser struct {
96
148
bool new_line;
97
149
bool targets_started;
98
150
build_target.Target* target;
151
+ Set* sets; // Note: will point to current set
152
+ }
153
+
154
+ fn void Parser.free(Parser* p) {
155
+ p.global_configs.free();
156
+ Set* s = p.sets;
157
+ while (s) {
158
+ Set* next = s.next;
159
+ s.free();
160
+ s = next;
161
+ }
99
162
}
100
163
101
164
fn bool Parser.parse(Recipe* recipe, string_pool.Pool* pool, source_mgr.SourceMgr* sm, i32 file_id) {
@@ -117,7 +180,7 @@ fn bool Parser.parse(Recipe* recipe, string_pool.Pool* pool, source_mgr.SourceMg
117
180
p.consumeToken();
118
181
p.parseTop();
119
182
}
120
- p.global_configs. free();
183
+ p.free();
121
184
return res == 0;
122
185
}
123
186
@@ -197,6 +260,10 @@ fn void Parser.lex(Parser* p, Token* result) {
197
260
p.lex_option(result);
198
261
p.new_line = false;
199
262
return;
263
+ case '(':
264
+ p.lex_set_use(result);
265
+ p.new_line = false;
266
+ return;
200
267
case '/':
201
268
// filename
202
269
// lex until whitespace
@@ -247,6 +314,12 @@ fn void Parser.lex(Parser* p, Token* result) {
247
314
p.new_line = false;
248
315
return;
249
316
}
317
+ if (equals(p.cur, "set ", 4)) {
318
+ result.kind = Kind.Set;
319
+ p.cur += 4;
320
+ p.new_line = false;
321
+ return;
322
+ }
250
323
251
324
// lex until whitespace
252
325
const char* start = p.cur;
@@ -286,8 +359,38 @@ fn void Parser.lex_plugin_options(Parser* p, Token* result) {
286
359
}
287
360
}
288
361
289
- fn void Parser.lex_option(Parser* p, Token* result) {
362
+ fn bool is_name(char c) {
363
+ if (c >= 'a' && c <= 'z') return true;
364
+ if (c >= 'A' && c <= 'Z') return true;
365
+ if (c >= '0' && c <= '9') return true;
366
+ if (c == '_') return true;
367
+ return false;
368
+ }
369
+
370
+ fn void Parser.lex_set_use(Parser* p, Token* result) {
371
+ p.cur++; // skip (
372
+
373
+ result.loc = p.loc_start + cast<SrcLoc>(p.cur - p.input_start);
374
+
375
+ const char* start = p.cur;
376
+ while (is_name(*p.cur)) p.cur++;
377
+
378
+ result.kind = Kind.SetUse;
379
+ u32 len = cast<u32>(p.cur - start);
380
+ if (len == 0) p.error("expected set name");
381
+
382
+ result.value = p.pool.add(start, len, true);
383
+
384
+ if (*p.cur != ')') {
385
+ result.loc = p.loc_start + cast<SrcLoc>(p.cur - p.input_start);
386
+ p.error("expected ')'");
387
+ }
290
388
p.cur++;
389
+ }
390
+
391
+
392
+ fn void Parser.lex_option(Parser* p, Token* result) {
393
+ p.cur++; // skip $
291
394
292
395
result.loc = p.loc_start + cast<SrcLoc>(p.cur - p.input_start);
293
396
@@ -387,6 +490,12 @@ fn void Parser.parseTop(Parser* p) {
387
490
case AsmFile:
388
491
p.error("must be inside target");
389
492
break;
493
+ case Set:
494
+ p.parseSet();
495
+ break;
496
+ case SetUse:
497
+ p.error("syntax error");
498
+ break;
390
499
case Eof:
391
500
return;
392
501
}
@@ -419,7 +528,8 @@ fn void Parser.parseWarnings(Parser* p) {
419
528
// TODO no need to store in string pool
420
529
while (p.is(Kind.Text)) {
421
530
const char* option = p.pool.idx2str(p.token.value);
422
- if (string.strcmp(option, "no-unused") == 0) {
531
+ switch (option) {
532
+ case "no-unused":
423
533
warnings.no_unused = true;
424
534
warnings.no_unused_variable = true;
425
535
warnings.no_unused_function = true;
@@ -430,28 +540,40 @@ fn void Parser.parseWarnings(Parser* p) {
430
540
warnings.no_unused_public = true;
431
541
warnings.no_unused_label = true;
432
542
warnings.no_unused_enum_constant = true;
433
- } else if (string.strcmp(option, "no-unused-variable") == 0) {
543
+ break;
544
+ case "no-unused-variable":
434
545
warnings.no_unused_variable = true;
435
- } else if (string.strcmp(option, "no-unused-function") == 0) {
546
+ break;
547
+ case "no-unused-function":
436
548
warnings.no_unused_function = true;
437
- } else if (string.strcmp(option, "no-unused-parameter") == 0) {
549
+ break;
550
+ case "no-unused-parameter":
438
551
warnings.no_unused_parameter = true;
439
- } else if (string.strcmp(option, "no-unused-type") == 0) {
552
+ break;
553
+ case "no-unused-type":
440
554
warnings.no_unused_type = true;
441
- } else if (string.strcmp(option, "no-unused-module") == 0) {
555
+ break;
556
+ case "no-unused-module":
442
557
warnings.no_unused_module = true;
443
- } else if (string.strcmp(option, "no-unused-import") == 0) {
558
+ break;
559
+ case "no-unused-import":
444
560
warnings.no_unused_import = true;
445
- } else if (string.strcmp(option, "no-unused-public") == 0) {
561
+ break;
562
+ case "no-unused-public":
446
563
warnings.no_unused_public = true;
447
- } else if (string.strcmp(option, "no-unused-label") == 0) {
564
+ break;
565
+ case "no-unused-label":
448
566
warnings.no_unused_label = true;
449
- } else if (string.strcmp(option, "no-unused-enum-constant") == 0) {
567
+ break;
568
+ case "no-unused-enum-constant":
450
569
warnings.no_unused_enum_constant = true;
451
- } else if (string.strcmp(option, "promote-to-error") == 0) {
570
+ break;
571
+ case "promote-to-error":
452
572
warnings.are_errors = true;
453
- } else {
573
+ break;
574
+ default:
454
575
p.error("unknown warning '%s'", option);
576
+ break;
455
577
}
456
578
p.consumeToken();
457
579
}
@@ -475,6 +597,44 @@ fn void Parser.parseImage(Parser* p) {
475
597
p.parseTarget();
476
598
}
477
599
600
+ fn void Parser.parseSet(Parser* p) {
601
+ p.consumeToken();
602
+ p.expect(Kind.Text, "expect set name");
603
+
604
+ Set* old = p.findSet(p.token.value);
605
+ if (old) {
606
+ p.error("duplicate set '%s'", p.pool.idx2str(p.token.value));
607
+ }
608
+ p.sets = Set.create(p.token.value, p.token.loc, p.sets);
609
+ p.consumeToken();
610
+
611
+ while (1) {
612
+ switch (p.token.kind) {
613
+ case File:
614
+ if (!p.sets.addFile(p.token.value, p.token.loc)) {
615
+ p.error("duplicate file '%s' in set '%s'", p.pool.idx2str(p.token.value), p.pool.idx2str(p.sets.name_idx));
616
+ }
617
+ p.consumeToken();
618
+ break;
619
+ case End:
620
+ p.consumeToken();
621
+ return;
622
+ default:
623
+ p.error("syntax error");
624
+ break;
625
+ }
626
+ }
627
+ }
628
+
629
+ fn Set* Parser.findSet(Parser* p, u32 name_idx) {
630
+ Set* s = p.sets;
631
+ while (s) {
632
+ if (s.name_idx == name_idx) return s;
633
+ s = s.next;
634
+ }
635
+ return nil;
636
+ }
637
+
478
638
fn void Parser.parseLibrary(Parser* p) {
479
639
p.consumeToken();
480
640
p.expect(Kind.Text, "expect target name");
@@ -609,6 +769,21 @@ fn void Parser.parseTarget(Parser* p) {
609
769
}
610
770
p.consumeToken();
611
771
break;
772
+ case Set:
773
+ p.error("cannot define a set here");
774
+ break;
775
+ case SetUse:
776
+ Set* s = p.findSet(p.token.value);
777
+ if (!s) p.error("unknown set '%s'", p.pool.idx2str(p.token.value));
778
+ p.consumeToken();
779
+ files_started = true;
780
+ for (u32 i=0; i<s.num_files; i++) {
781
+ const build_target.File* f = &s.files[i];
782
+ if (!p.target.addFile(f.name, f.loc)) {
783
+ p.error("duplicate file '%s' from set '%s'", p.pool.idx2str(f.name), p.pool.idx2str(s.name_idx));
784
+ }
785
+ }
786
+ break;
612
787
case Eof:
613
788
p.error("un-terminated target");
614
789
return;
0 commit comments