3
3
4
4
const std = @import ("std" );
5
5
const builtin = @import ("builtin" );
6
+ const assert = std .debug .assert ;
6
7
const ast = std .zig .ast ;
7
8
const Token = std .zig .Token ;
8
9
use @import ("clang.zig" );
@@ -21,6 +22,10 @@ pub const Error = error{
21
22
OutOfMemory ,
22
23
UnsupportedType ,
23
24
};
25
+ pub const TransError = error {
26
+ OutOfMemory ,
27
+ UnsupportedTranslation ,
28
+ };
24
29
25
30
const DeclTable = std .HashMap (usize , void , addrHash , addrEql );
26
31
@@ -61,6 +66,27 @@ const Scope = struct {
61
66
62
67
const Block = struct {
63
68
base : Scope ,
69
+ block_node : * ast.Node.Block ,
70
+
71
+ /// Don't forget to set rbrace token later
72
+ fn create (c : * Context , parent : * Scope , lbrace_tok : ast.TokenIndex ) ! * Block {
73
+ const block = try c .a ().create (Block );
74
+ block .* = Block {
75
+ .base = Scope {
76
+ .id = Id .Block ,
77
+ .parent = parent ,
78
+ },
79
+ .block_node = try c .a ().create (ast .Node .Block ),
80
+ };
81
+ block .block_node .* = ast.Node.Block {
82
+ .base = ast.Node { .id = ast .Node .Id .Block },
83
+ .label = null ,
84
+ .lbrace = lbrace_tok ,
85
+ .statements = ast .Node .Block .StatementList .init (c .a ()),
86
+ .rbrace = undefined ,
87
+ };
88
+ return block ;
89
+ }
64
90
};
65
91
66
92
const Root = struct {
@@ -72,6 +98,12 @@ const Scope = struct {
72
98
};
73
99
};
74
100
101
+ const TransResult = struct {
102
+ node : * ast.Node ,
103
+ node_scope : * Scope ,
104
+ child_scope : * Scope ,
105
+ };
106
+
75
107
const Context = struct {
76
108
tree : * ast.Tree ,
77
109
source_buffer : * std.Buffer ,
@@ -170,6 +202,14 @@ pub fn translate(
170
202
171
203
_ = try appendToken (& context , .Eof , "" );
172
204
tree .source = source_buffer .toOwnedSlice ();
205
+ if (false ) {
206
+ std .debug .warn ("debug source:\n {}\n ==EOF==\n tokens:\n " , tree .source );
207
+ var i : usize = 0 ;
208
+ while (i < tree .tokens .len ) : (i += 1 ) {
209
+ const token = tree .tokens .at (i );
210
+ std .debug .warn ("{}\n " , token );
211
+ }
212
+ }
173
213
return tree ;
174
214
}
175
215
@@ -213,29 +253,107 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
213
253
const fn_decl_loc = ZigClangFunctionDecl_getLocation (fn_decl );
214
254
const fn_qt = ZigClangFunctionDecl_getType (fn_decl );
215
255
const fn_type = ZigClangQualType_getTypePtr (fn_qt );
256
+ var scope = & c .global_scope .base ;
257
+ const decl_ctx = FnDeclContext {
258
+ .fn_name = fn_name ,
259
+ .has_body = ZigClangFunctionDecl_hasBody (fn_decl ),
260
+ .storage_class = ZigClangFunctionDecl_getStorageClass (fn_decl ),
261
+ .scope = & scope ,
262
+ };
216
263
const proto_node = switch (ZigClangType_getTypeClass (fn_type )) {
217
- .FunctionProto = > transFnProto (
218
- rp ,
219
- @ptrCast (* const ZigClangFunctionProtoType , fn_type ),
220
- fn_decl_loc ,
221
- fn_decl ,
222
- fn_name ,
223
- ) catch | err | switch (err ) {
224
- error .UnsupportedType = > {
225
- return failDecl (c , fn_decl_loc , fn_name , "unable to resolve prototype of function" );
226
- },
227
- else = > return err ,
264
+ .FunctionProto = > blk : {
265
+ const fn_proto_type = @ptrCast (* const ZigClangFunctionProtoType , fn_type );
266
+ break :blk transFnProto (rp , fn_proto_type , fn_decl_loc , decl_ctx ) catch | err | switch (err ) {
267
+ error .UnsupportedType = > {
268
+ return failDecl (c , fn_decl_loc , fn_name , "unable to resolve prototype of function" );
269
+ },
270
+ error .OutOfMemory = > return error .OutOfMemory ,
271
+ };
228
272
},
229
273
.FunctionNoProto = > return failDecl (c , fn_decl_loc , fn_name , "TODO support functions with no prototype" ),
230
274
else = > unreachable ,
231
275
};
232
276
233
- if (! ZigClangFunctionDecl_hasBody ( fn_decl ) ) {
277
+ if (! decl_ctx . has_body ) {
234
278
const semi_tok = try appendToken (c , .Semicolon , ";" );
235
279
return addTopLevelDecl (c , fn_name , & proto_node .base );
236
280
}
237
281
238
- try emitWarning (c , fn_decl_loc , "TODO implement function body translation" );
282
+ // actual function definition with body
283
+ const body_stmt = ZigClangFunctionDecl_getBody (fn_decl );
284
+ const result = transStmt (rp , scope , body_stmt , .unused , .r_value ) catch | err | switch (err ) {
285
+ error .OutOfMemory = > return error .OutOfMemory ,
286
+ error .UnsupportedTranslation = > return failDecl (c , fn_decl_loc , fn_name , "unable to translate function" ),
287
+ };
288
+ assert (result .node .id == ast .Node .Id .Block );
289
+ proto_node .body_node = result .node ;
290
+
291
+ return addTopLevelDecl (c , fn_name , & proto_node .base );
292
+ }
293
+
294
+ const ResultUsed = enum {
295
+ used ,
296
+ unused ,
297
+ };
298
+
299
+ const LRValue = enum {
300
+ l_value ,
301
+ r_value ,
302
+ };
303
+
304
+ fn transStmt (
305
+ rp : RestorePoint ,
306
+ scope : * Scope ,
307
+ stmt : * const ZigClangStmt ,
308
+ result_used : ResultUsed ,
309
+ lrvalue : LRValue ,
310
+ ) ! TransResult {
311
+ const sc = ZigClangStmt_getStmtClass (stmt );
312
+ switch (sc ) {
313
+ .CompoundStmtClass = > return transCompoundStmt (rp , scope , @ptrCast (* const ZigClangCompoundStmt , stmt )),
314
+ else = > {
315
+ return revertAndWarn (
316
+ rp ,
317
+ error .UnsupportedTranslation ,
318
+ ZigClangStmt_getBeginLoc (stmt ),
319
+ "TODO implement translation of stmt class {}" ,
320
+ @tagName (sc ),
321
+ );
322
+ },
323
+ }
324
+ }
325
+
326
+ fn transCompoundStmtInline (
327
+ rp : RestorePoint ,
328
+ parent_scope : * Scope ,
329
+ stmt : * const ZigClangCompoundStmt ,
330
+ block_node : * ast.Node.Block ,
331
+ ) TransError ! TransResult {
332
+ var it = ZigClangCompoundStmt_body_begin (stmt );
333
+ const end_it = ZigClangCompoundStmt_body_end (stmt );
334
+ var scope = parent_scope ;
335
+ while (it != end_it ) : (it += 1 ) {
336
+ const result = try transStmt (rp , scope , it .* , .unused , .r_value );
337
+ scope = result .child_scope ;
338
+ try block_node .statements .push (result .node );
339
+ }
340
+ return TransResult {
341
+ .node = & block_node .base ,
342
+ .child_scope = scope ,
343
+ .node_scope = scope ,
344
+ };
345
+ }
346
+
347
+ fn transCompoundStmt (rp : RestorePoint , scope : * Scope , stmt : * const ZigClangCompoundStmt ) ! TransResult {
348
+ const lbrace_tok = try appendToken (rp .c , .LBrace , "{" );
349
+ const block_scope = try Scope .Block .create (rp .c , scope , lbrace_tok );
350
+ const inline_result = try transCompoundStmtInline (rp , & block_scope .base , stmt , block_scope .block_node );
351
+ block_scope .block_node .rbrace = try appendToken (rp .c , .RBrace , "}" );
352
+ return TransResult {
353
+ .node = & block_scope .block_node .base ,
354
+ .node_scope = inline_result .node_scope ,
355
+ .child_scope = inline_result .child_scope ,
356
+ };
239
357
}
240
358
241
359
fn addTopLevelDecl (c : * Context , name : []const u8 , decl_node : * ast.Node ) ! void {
@@ -299,7 +417,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
299
417
},
300
418
.FunctionProto = > {
301
419
const fn_proto_ty = @ptrCast (* const ZigClangFunctionProtoType , ty );
302
- const fn_proto = try transFnProto (rp , fn_proto_ty , source_loc , null , null );
420
+ const fn_proto = try transFnProto (rp , fn_proto_ty , source_loc , null );
303
421
return & fn_proto .base ;
304
422
},
305
423
else = > {
@@ -309,12 +427,18 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
309
427
}
310
428
}
311
429
430
+ const FnDeclContext = struct {
431
+ fn_name : []const u8 ,
432
+ has_body : bool ,
433
+ storage_class : ZigClangStorageClass ,
434
+ scope : ** Scope ,
435
+ };
436
+
312
437
fn transFnProto (
313
438
rp : RestorePoint ,
314
439
fn_proto_ty : * const ZigClangFunctionProtoType ,
315
440
source_loc : ZigClangSourceLocation ,
316
- opt_fn_decl : ? * const ZigClangFunctionDecl ,
317
- fn_name : ? []const u8 ,
441
+ fn_decl_context : ? FnDeclContext ,
318
442
) ! * ast.Node.FnProto {
319
443
const fn_ty = @ptrCast (* const ZigClangFunctionType , fn_proto_ty );
320
444
const cc = switch (ZigClangFunctionType_getCallConv (fn_ty )) {
@@ -351,13 +475,11 @@ fn transFnProto(
351
475
const pub_tok = try appendToken (rp .c , .Keyword_pub , "pub" );
352
476
const cc_tok = if (cc == .Stdcall ) try appendToken (rp .c , .Keyword_stdcallcc , "stdcallcc" ) else null ;
353
477
const is_export = exp : {
354
- const fn_decl = opt_fn_decl orelse break :exp false ;
355
- const has_body = ZigClangFunctionDecl_hasBody (fn_decl );
356
- const storage_class = ZigClangFunctionDecl_getStorageClass (fn_decl );
357
- break :exp switch (storage_class ) {
478
+ const decl_ctx = fn_decl_context orelse break :exp false ;
479
+ break :exp switch (decl_ctx .storage_class ) {
358
480
.None = > switch (rp .c .mode ) {
359
481
.import = > false ,
360
- .translate = > has_body ,
482
+ .translate = > decl_ctx . has_body ,
361
483
},
362
484
.Extern , .Static = > false ,
363
485
.PrivateExtern = > return revertAndWarn (rp , error .UnsupportedType , source_loc , "unsupported storage class: private extern" ),
@@ -372,7 +494,7 @@ fn transFnProto(
372
494
else
373
495
null ;
374
496
const fn_tok = try appendToken (rp .c , .Keyword_fn , "fn" );
375
- const name_tok = if (fn_name ) | n | try appendToken (rp .c , .Identifier , "{}" , n ) else null ;
497
+ const name_tok = if (fn_decl_context ) | ctx | try appendToken (rp .c , .Identifier , ctx . fn_name ) else null ;
376
498
const lparen_tok = try appendToken (rp .c , .LParen , "(" );
377
499
const var_args_tok = if (is_var_args ) try appendToken (rp .c , .Ellipsis3 , "..." ) else null ;
378
500
const rparen_tok = try appendToken (rp .c , .RParen , ")" );
@@ -390,7 +512,7 @@ fn transFnProto(
390
512
try emitWarning (rp .c , source_loc , "unsupported function proto return type" );
391
513
return err ;
392
514
},
393
- else = > return err ,
515
+ error . OutOfMemory = > return error . OutOfMemory ,
394
516
};
395
517
}
396
518
}
@@ -430,17 +552,17 @@ fn revertAndWarn(
430
552
}
431
553
432
554
fn emitWarning (c : * Context , loc : ZigClangSourceLocation , comptime format : []const u8 , args : ... ) ! void {
433
- _ = try appendToken (c , .LineComment , "// {}: warning: " ++ format , c .locStr (loc ), args );
555
+ _ = try appendTokenFmt (c , .LineComment , "// {}: warning: " ++ format , c .locStr (loc ), args );
434
556
}
435
557
436
558
fn failDecl (c : * Context , loc : ZigClangSourceLocation , name : []const u8 , comptime format : []const u8 , args : ... ) ! void {
437
559
// const name = @compileError(msg);
438
560
const const_tok = try appendToken (c , .Keyword_const , "const" );
439
- const name_tok = try appendToken (c , .Identifier , "{}" , name );
561
+ const name_tok = try appendToken (c , .Identifier , name );
440
562
const eq_tok = try appendToken (c , .Equal , "=" );
441
563
const builtin_tok = try appendToken (c , .Builtin , "@compileError" );
442
564
const lparen_tok = try appendToken (c , .LParen , "(" );
443
- const msg_tok = try appendToken (c , .StringLiteral , "\" " ++ format ++ "\" " , args );
565
+ const msg_tok = try appendTokenFmt (c , .StringLiteral , "\" " ++ format ++ "\" " , args );
444
566
const rparen_tok = try appendToken (c , .RParen , ")" );
445
567
const semi_tok = try appendToken (c , .Semicolon , ";" );
446
568
@@ -480,16 +602,20 @@ fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime
480
602
try c .tree .root_node .decls .push (& var_decl_node .base );
481
603
}
482
604
483
- fn appendToken (c : * Context , token_id : Token.Id , comptime format : []const u8 , args : ... ) ! ast.TokenIndex {
605
+ fn appendToken (c : * Context , token_id : Token.Id , bytes : []const u8 ) ! ast.TokenIndex {
606
+ return appendTokenFmt (c , token_id , "{}" , bytes );
607
+ }
608
+
609
+ fn appendTokenFmt (c : * Context , token_id : Token.Id , comptime format : []const u8 , args : ... ) ! ast.TokenIndex {
484
610
const S = struct {
485
- fn callback (context : * Context , bytes : []const u8 ) Error ! void {
611
+ fn callback (context : * Context , bytes : []const u8 ) error { OutOfMemory } ! void {
486
612
return context .source_buffer .append (bytes );
487
613
}
488
614
};
489
615
const start_index = c .source_buffer .len ();
490
616
errdefer c .source_buffer .shrink (start_index );
491
617
492
- try std .fmt .format (c , Error , S .callback , format , args );
618
+ try std .fmt .format (c , error { OutOfMemory } , S .callback , format , args );
493
619
const end_index = c .source_buffer .len ();
494
620
const token_index = c .tree .tokens .len ;
495
621
const new_token = try c .tree .tokens .addOne ();
@@ -506,7 +632,7 @@ fn appendToken(c: *Context, token_id: Token.Id, comptime format: []const u8, arg
506
632
}
507
633
508
634
fn appendIdentifier (c : * Context , name : []const u8 ) ! * ast.Node {
509
- const token_index = try appendToken (c , .Identifier , "{}" , name );
635
+ const token_index = try appendToken (c , .Identifier , name );
510
636
const identifier = try c .a ().create (ast .Node .Identifier );
511
637
identifier .* = ast.Node.Identifier {
512
638
.base = ast.Node { .id = ast .Node .Id .Identifier },
0 commit comments