@@ -2,6 +2,7 @@ const std = @import("std");
2
2
const os = std .os ;
3
3
const io = std .io ;
4
4
const mem = std .mem ;
5
+ const Allocator = mem .Allocator ;
5
6
const Buffer = std .Buffer ;
6
7
const llvm = @import ("llvm.zig" );
7
8
const c = @import ("c.zig" );
@@ -13,6 +14,7 @@ const ArrayList = std.ArrayList;
13
14
const errmsg = @import ("errmsg.zig" );
14
15
const ast = std .zig .ast ;
15
16
const event = std .event ;
17
+ const assert = std .debug .assert ;
16
18
17
19
pub const Module = struct {
18
20
loop : * event.Loop ,
@@ -81,6 +83,8 @@ pub const Module = struct {
81
83
link_out_file : ? []const u8 ,
82
84
events : * event .Channel (Event ),
83
85
86
+ exported_symbol_names : event .Locked (Decl .Table ),
87
+
84
88
// TODO handle some of these earlier and report them in a way other than error codes
85
89
pub const BuildError = error {
86
90
OutOfMemory ,
@@ -232,6 +236,7 @@ pub const Module = struct {
232
236
.test_name_prefix = null ,
233
237
.emit_file_type = Emit .Binary ,
234
238
.link_out_file = null ,
239
+ .exported_symbol_names = event .Locked (Decl .Table ).init (loop , Decl .Table .init (loop .allocator )),
235
240
});
236
241
}
237
242
@@ -272,38 +277,91 @@ pub const Module = struct {
272
277
return ;
273
278
};
274
279
await (async self .events .put (Event .Ok ) catch unreachable );
280
+ // for now we stop after 1
281
+ return ;
275
282
}
276
283
}
277
284
278
285
async fn addRootSrc (self : * Module ) ! void {
279
286
const root_src_path = self .root_src_path orelse @panic ("TODO handle null root src path" );
287
+ // TODO async/await os.path.real
280
288
const root_src_real_path = os .path .real (self .a (), root_src_path ) catch | err | {
281
289
try printError ("unable to get real path '{}': {}" , root_src_path , err );
282
290
return err ;
283
291
};
284
292
errdefer self .a ().free (root_src_real_path );
285
293
294
+ // TODO async/await readFileAlloc()
286
295
const source_code = io .readFileAlloc (self .a (), root_src_real_path ) catch | err | {
287
296
try printError ("unable to open '{}': {}" , root_src_real_path , err );
288
297
return err ;
289
298
};
290
299
errdefer self .a ().free (source_code );
291
300
292
- var tree = try std .zig .parse (self .a (), source_code );
293
- defer tree .deinit ();
294
-
295
- //var it = tree.root_node.decls.iterator();
296
- //while (it.next()) |decl_ptr| {
297
- // const decl = decl_ptr.*;
298
- // switch (decl.id) {
299
- // ast.Node.Comptime => @panic("TODO"),
300
- // ast.Node.VarDecl => @panic("TODO"),
301
- // ast.Node.UseDecl => @panic("TODO"),
302
- // ast.Node.FnDef => @panic("TODO"),
303
- // ast.Node.TestDecl => @panic("TODO"),
304
- // else => unreachable,
305
- // }
306
- //}
301
+ var parsed_file = ParsedFile {
302
+ .tree = try std .zig .parse (self .a (), source_code ),
303
+ .realpath = root_src_real_path ,
304
+ };
305
+ errdefer parsed_file .tree .deinit ();
306
+
307
+ const tree = & parsed_file .tree ;
308
+
309
+ // create empty struct for it
310
+ const decls = try Scope .Decls .create (self .a (), null );
311
+ errdefer decls .destroy ();
312
+
313
+ var it = tree .root_node .decls .iterator (0 );
314
+ while (it .next ()) | decl_ptr | {
315
+ const decl = decl_ptr .* ;
316
+ switch (decl .id ) {
317
+ ast .Node .Id .Comptime = > @panic ("TODO" ),
318
+ ast .Node .Id .VarDecl = > @panic ("TODO" ),
319
+ ast .Node .Id .FnProto = > {
320
+ const fn_proto = @fieldParentPtr (ast .Node .FnProto , "base" , decl );
321
+
322
+ const name = if (fn_proto .name_token ) | name_token | tree .tokenSlice (name_token ) else {
323
+ @panic ("TODO add compile error" );
324
+ //try self.addCompileError(
325
+ // &parsed_file,
326
+ // fn_proto.fn_token,
327
+ // fn_proto.fn_token + 1,
328
+ // "missing function name",
329
+ //);
330
+ continue ;
331
+ };
332
+
333
+ const fn_decl = try self .a ().create (Decl.Fn {
334
+ .base = Decl {
335
+ .id = Decl .Id .Fn ,
336
+ .name = name ,
337
+ .visib = parseVisibToken (tree , fn_proto .visib_token ),
338
+ .resolution = Decl .Resolution .Unresolved ,
339
+ },
340
+ .value = Decl.Fn.Val { .Unresolved = {} },
341
+ .fn_proto = fn_proto ,
342
+ });
343
+ errdefer self .a ().destroy (fn_decl );
344
+
345
+ // TODO make this parallel
346
+ try await try async self .addTopLevelDecl (tree , & fn_decl .base );
347
+ },
348
+ ast .Node .Id .TestDecl = > @panic ("TODO" ),
349
+ else = > unreachable ,
350
+ }
351
+ }
352
+ }
353
+
354
+ async fn addTopLevelDecl (self : * Module , tree : * ast.Tree , decl : * Decl ) ! void {
355
+ const is_export = decl .isExported (tree );
356
+
357
+ {
358
+ const exported_symbol_names = await try async self .exported_symbol_names .acquire ();
359
+ defer exported_symbol_names .release ();
360
+
361
+ if (try exported_symbol_names .value .put (decl .name , decl )) | other_decl | {
362
+ @panic ("TODO report compile error" );
363
+ }
364
+ }
307
365
}
308
366
309
367
pub fn link (self : * Module , out_file : ? []const u8 ) ! void {
@@ -350,3 +408,172 @@ fn printError(comptime format: []const u8, args: ...) !void {
350
408
const out_stream = & stderr_file_out_stream .stream ;
351
409
try out_stream .print (format , args );
352
410
}
411
+
412
+ fn parseVisibToken (tree : * ast.Tree , optional_token_index : ? ast.TokenIndex ) Visib {
413
+ if (optional_token_index ) | token_index | {
414
+ const token = tree .tokens .at (token_index );
415
+ assert (token .id == Token .Id .Keyword_pub );
416
+ return Visib .Pub ;
417
+ } else {
418
+ return Visib .Private ;
419
+ }
420
+ }
421
+
422
+ pub const Scope = struct {
423
+ id : Id ,
424
+ parent : ? * Scope ,
425
+
426
+ pub const Id = enum {
427
+ Decls ,
428
+ Block ,
429
+ };
430
+
431
+ pub const Decls = struct {
432
+ base : Scope ,
433
+ table : Decl.Table ,
434
+
435
+ pub fn create (a : * Allocator , parent : ? * Scope ) ! * Decls {
436
+ const self = try a .create (Decls {
437
+ .base = Scope {
438
+ .id = Id .Decls ,
439
+ .parent = parent ,
440
+ },
441
+ .table = undefined ,
442
+ });
443
+ errdefer a .destroy (self );
444
+
445
+ self .table = Decl .Table .init (a );
446
+ errdefer self .table .deinit ();
447
+
448
+ return self ;
449
+ }
450
+
451
+ pub fn destroy (self : * Decls ) void {
452
+ self .table .deinit ();
453
+ self .table .allocator .destroy (self );
454
+ self .* = undefined ;
455
+ }
456
+ };
457
+
458
+ pub const Block = struct {
459
+ base : Scope ,
460
+ };
461
+ };
462
+
463
+ pub const Visib = enum {
464
+ Private ,
465
+ Pub ,
466
+ };
467
+
468
+ pub const Decl = struct {
469
+ id : Id ,
470
+ name : []const u8 ,
471
+ visib : Visib ,
472
+ resolution : Resolution ,
473
+
474
+ pub const Table = std .HashMap ([]const u8 , * Decl , mem .hash_slice_u8 , mem .eql_slice_u8 );
475
+
476
+ pub fn isExported (base : * const Decl , tree : * ast.Tree ) bool {
477
+ switch (base .id ) {
478
+ Id .Fn = > {
479
+ const fn_decl = @fieldParentPtr (Fn , "base" , base );
480
+ return fn_decl .isExported (tree );
481
+ },
482
+ else = > return false ,
483
+ }
484
+ }
485
+
486
+ pub const Resolution = enum {
487
+ Unresolved ,
488
+ InProgress ,
489
+ Invalid ,
490
+ Ok ,
491
+ };
492
+
493
+ pub const Id = enum {
494
+ Var ,
495
+ Fn ,
496
+ CompTime ,
497
+ };
498
+
499
+ pub const Var = struct {
500
+ base : Decl ,
501
+ };
502
+
503
+ pub const Fn = struct {
504
+ base : Decl ,
505
+ value : Val ,
506
+ fn_proto : * const ast.Node.FnProto ,
507
+
508
+ // TODO https://github.com/ziglang/zig/issues/683 and then make this anonymous
509
+ pub const Val = union {
510
+ Unresolved : void ,
511
+ Ok : * Value.Fn ,
512
+ };
513
+
514
+ pub fn externLibName (self : Fn , tree : * ast.Tree ) ? []const u8 {
515
+ return if (self .fn_proto .extern_export_inline_token ) | tok_index | x : {
516
+ const token = tree .tokens .at (tok_index );
517
+ break :x switch (token .id ) {
518
+ Token .Id .Extern = > tree .tokenSlicePtr (token ),
519
+ else = > null ,
520
+ };
521
+ } else null ;
522
+ }
523
+
524
+ pub fn isExported (self : Fn , tree : * ast.Tree ) bool {
525
+ if (self .fn_proto .extern_export_inline_token ) | tok_index | {
526
+ const token = tree .tokens .at (tok_index );
527
+ return token .id == Token .Id .Keyword_export ;
528
+ } else {
529
+ return false ;
530
+ }
531
+ }
532
+ };
533
+
534
+ pub const CompTime = struct {
535
+ base : Decl ,
536
+ };
537
+ };
538
+
539
+ pub const Value = struct {
540
+ pub const Fn = struct {};
541
+ };
542
+
543
+ pub const Type = struct {
544
+ id : Id ,
545
+
546
+ pub const Id = enum {
547
+ Type ,
548
+ Void ,
549
+ Bool ,
550
+ NoReturn ,
551
+ Int ,
552
+ Float ,
553
+ Pointer ,
554
+ Array ,
555
+ Struct ,
556
+ ComptimeFloat ,
557
+ ComptimeInt ,
558
+ Undefined ,
559
+ Null ,
560
+ Optional ,
561
+ ErrorUnion ,
562
+ ErrorSet ,
563
+ Enum ,
564
+ Union ,
565
+ Fn ,
566
+ Opaque ,
567
+ Promise ,
568
+ };
569
+
570
+ pub const Struct = struct {
571
+ base : Type ,
572
+ decls : * Scope.Decls ,
573
+ };
574
+ };
575
+
576
+ pub const ParsedFile = struct {
577
+ tree : ast.Tree ,
578
+ realpath : []const u8 ,
579
+ };
0 commit comments