authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-07 22:28:41+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-16 16:37:08+02:00
log7514c0ad0d327d2427009c26e5930540297e396e
tree1c696f87661d4139cd40b65fdba2f3deab2a3304
parentf5041caa2e9d1e891bd93aa2721a4a283123f0d9
signature Commit is signed but in an unrecognized format.

translate-c: unary operator, integers and misc


2 files changed, 138 insertions(+), 176 deletions(-)

src/translate_c.zig+108-171
......@@ -8,7 +8,6 @@ const ctok = std.c.tokenizer;
88const CToken = std.c.Token;
99const mem = std.mem;
1010const math = std.math;
11const Type = @import("type.zig").Type;
1211const ast = @import("translate_c/ast.zig");
1312const Node = ast.Node;
1413
......@@ -20,7 +19,7 @@ pub const Error = error{OutOfMemory};
2019const TypeError = Error || error{UnsupportedType};
2120const TransError = TypeError || error{UnsupportedTranslation};
2221
23const SymbolTable = std.StringArrayHashMap(*ast.Node);
22const SymbolTable = std.StringArrayHashMap(Node);
2423const AliasList = std.ArrayList(struct {
2524 alias: []const u8,
2625 name: []const u8,
......@@ -38,13 +37,13 @@ const Scope = struct {
3837 Loop,
3938 };
4039
41 /// Represents an in-progress ast.Node.Switch. This struct is stack-allocated.
42 /// When it is deinitialized, it produces an ast.Node.Switch which is allocated
40 /// Represents an in-progress Node.Switch. This struct is stack-allocated.
41 /// When it is deinitialized, it produces an Node.Switch which is allocated
4342 /// into the main arena.
4443 const Switch = struct {
4544 base: Scope,
4645 pending_block: Block,
47 cases: []*ast.Node,
46 cases: []Node,
4847 case_index: usize,
4948 switch_label: ?[]const u8,
5049 default_label: ?[]const u8,
......@@ -156,6 +155,7 @@ const Scope = struct {
156155 sym_table: SymbolTable,
157156 macro_table: SymbolTable,
158157 context: *Context,
158 nodes: std.ArrayList(Node),
159159
160160 fn init(c: *Context) Root {
161161 return .{
......@@ -163,12 +163,19 @@ const Scope = struct {
163163 .id = .Root,
164164 .parent = null,
165165 },
166 .sym_table = SymbolTable.init(c.arena),
167 .macro_table = SymbolTable.init(c.arena),
166 .sym_table = SymbolTable.init(c.gpa),
167 .macro_table = SymbolTable.init(c.gpa),
168168 .context = c,
169 .nodes = std.ArrayList(Node).init(c.gpa),
169170 };
170171 }
171172
173 fn deinit(scope: *Root) void {
174 scope.sym_table.deinit();
175 scope.macro_table.deinit();
176 scope.nodes.deinit();
177 }
178
172179 /// Check if the global scope contains this name, without looking into the "future", e.g.
173180 /// ignore the preprocessed decl and macro names.
174181 fn containsNow(scope: *Root, name: []const u8) bool {
......@@ -195,11 +202,11 @@ const Scope = struct {
195202 }
196203 }
197204
198 fn findBlockReturnType(inner: *Scope, c: *Context) ?clang.QualType {
205 fn findBlockReturnType(inner: *Scope, c: *Context) clang.QualType {
199206 var scope = inner;
200207 while (true) {
201208 switch (scope.id) {
202 .Root => return null,
209 .Root => unreachable,
203210 .Block => {
204211 const block = @fieldParentPtr(Block, "base", scope);
205212 if (block.return_type) |qt| return qt;
......@@ -248,23 +255,35 @@ const Scope = struct {
248255 }
249256 }
250257 }
258
259 /// Appends a node to the first block scope if inside a function, or to the root tree if not.
260 fn appendNode(scope: *Scope, node: Node) !void {
261 var scope = inner;
262 while (true) {
263 switch (scope.id) {
264 .Root => {
265 const root = @fieldParentPtr(Root, "base", scope).contains(name);
266 return root.nodes.append(node);
267 },
268 .Block => {
269 const block = @fieldParentPtr(Block, "base", scope).contains(name);
270 return block.statements.append(node);
271 },
272 else => scope = scope.parent.?,
273 }
274 }
275 }
251276};
252277
253278pub const Context = struct {
254279 gpa: *mem.Allocator,
255280 arena: *mem.Allocator,
256 token_ids: std.ArrayListUnmanaged(Token.Id) = .{},
257 token_locs: std.ArrayListUnmanaged(Token.Loc) = .{},
258 errors: std.ArrayListUnmanaged(ast.Error) = .{},
259 source_buffer: *std.ArrayList(u8),
260 err: Error,
261281 source_manager: *clang.SourceManager,
262282 decl_table: std.AutoArrayHashMapUnmanaged(usize, []const u8) = .{},
263283 alias_list: AliasList,
264284 global_scope: *Scope.Root,
265285 clang_context: *clang.ASTContext,
266286 mangle_count: u32 = 0,
267 root_decls: std.ArrayListUnmanaged(*ast.Node) = .{},
268287 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},
269288
270289 /// This one is different than the root scope's name table. This contains
......@@ -293,40 +312,6 @@ pub const Context = struct {
293312 const column = c.source_manager.getSpellingColumnNumber(spelling_loc);
294313 return std.fmt.allocPrint(c.arena, "{s}:{d}:{d}", .{ filename, line, column });
295314 }
296
297 fn createCall(c: *Context, fn_expr: *ast.Node, params_len: ast.NodeIndex) !*ast.Node.Call {
298 _ = try appendToken(c, .LParen, "(");
299 const node = try ast.Node.Call.alloc(c.arena, params_len);
300 node.* = .{
301 .lhs = fn_expr,
302 .params_len = params_len,
303 .async_token = null,
304 .rtoken = undefined, // set after appending args
305 };
306 return node;
307 }
308
309 fn createBuiltinCall(c: *Context, name: []const u8, params_len: ast.NodeIndex) !*ast.Node.BuiltinCall {
310 const builtin_token = try appendToken(c, .Builtin, name);
311 _ = try appendToken(c, .LParen, "(");
312 const node = try ast.Node.BuiltinCall.alloc(c.arena, params_len);
313 node.* = .{
314 .builtin_token = builtin_token,
315 .params_len = params_len,
316 .rparen_token = undefined, // set after appending args
317 };
318 return node;
319 }
320
321 fn createBlock(c: *Context, statements_len: ast.NodeIndex) !*ast.Node.Block {
322 const block_node = try ast.Node.Block.alloc(c.arena, statements_len);
323 block_node.* = .{
324 .lbrace = try appendToken(c, .LBrace, "{"),
325 .statements_len = statements_len,
326 .rbrace = undefined,
327 };
328 return block_node;
329 }
330315};
331316
332317pub fn translate(
......@@ -348,9 +333,6 @@ pub fn translate(
348333 };
349334 defer ast_unit.delete();
350335
351 var source_buffer = std.ArrayList(u8).init(gpa);
352 defer source_buffer.deinit();
353
354336 // For memory that has the same lifetime as the Tree that we return
355337 // from this function.
356338 var arena = std.heap.ArenaAllocator.init(gpa);
......@@ -367,9 +349,7 @@ pub fn translate(
367349 var context = Context{
368350 .gpa = gpa,
369351 .arena = &arena.allocator,
370 .source_buffer = &source_buffer,
371352 .source_manager = ast_unit.getSourceManager(),
372 .err = undefined,
373353 .alias_list = AliasList.init(gpa),
374354 .global_scope = try arena.allocator.create(Scope.Root),
375355 .clang_context = ast_unit.getASTContext(),
......@@ -378,15 +358,12 @@ pub fn translate(
378358 defer {
379359 context.decl_table.deinit(gpa);
380360 context.alias_list.deinit();
381 context.token_ids.deinit(gpa);
382 context.token_locs.deinit(gpa);
383 context.errors.deinit(gpa);
384361 context.global_names.deinit(gpa);
385 context.root_decls.deinit(gpa);
386362 context.opaque_demotes.deinit(gpa);
363 context.global_scope.deini();
387364 }
388365
389 _ = try Node.usingnamespace_builtins.init();
366 try context.global_scope.nodes.append(try Node.usingnamespace_builtins.init());
390367
391368 try prepopulateGlobalNameTable(ast_unit, &context);
392369
......@@ -403,29 +380,7 @@ pub fn translate(
403380 }
404381 }
405382
406 const eof_token = try appendToken(&context, .Eof, "");
407 const root_node = try ast.Node.Root.create(&arena.allocator, context.root_decls.items.len, eof_token);
408 mem.copy(*ast.Node, root_node.decls(), context.root_decls.items);
409
410 if (false) {
411 std.debug.warn("debug source:\n{s}\n==EOF==\ntokens:\n", .{source_buffer.items});
412 for (context.token_ids.items) |token| {
413 std.debug.warn("{}\n", .{token});
414 }
415 }
416
417 const tree = try arena.allocator.create(ast.Tree);
418 tree.* = .{
419 .gpa = gpa,
420 .source = try arena.allocator.dupe(u8, source_buffer.items),
421 .token_ids = context.token_ids.toOwnedSlice(gpa),
422 .token_locs = context.token_locs.toOwnedSlice(gpa),
423 .errors = context.errors.toOwnedSlice(gpa),
424 .root_node = root_node,
425 .arena = arena.state,
426 .generated = true,
427 };
428 return tree;
383 return ast.render(context.global_scope.nodes.items);
429384}
430385
431386fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
......@@ -498,7 +453,7 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
498453 },
499454 else => {
500455 const decl_name = try c.str(decl.getDeclKindName());
501 try emitWarning(c, decl.getLocation(), "ignoring {s} declaration", .{decl_name});
456 try warn(c, decl.getLocation(), "ignoring {s} declaration", .{decl_name});
502457 },
503458 }
504459}
......@@ -1880,21 +1835,21 @@ const SuppressCast = enum {
18801835 no_as,
18811836};
18821837fn transIntegerLiteral(
1883 rp: RestorePoint,
1838 c: *Context,
18841839 scope: *Scope,
18851840 expr: *const clang.IntegerLiteral,
18861841 result_used: ResultUsed,
18871842 suppress_as: SuppressCast,
1888) TransError!*ast.Node {
1843) TransError!Node {
18891844 var eval_result: clang.ExprEvalResult = undefined;
1890 if (!expr.EvaluateAsInt(&eval_result, rp.c.clang_context)) {
1845 if (!expr.EvaluateAsInt(&eval_result, c.clang_context)) {
18911846 const loc = expr.getBeginLoc();
1892 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
1847 return revertAndWarn(c, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
18931848 }
18941849
18951850 if (suppress_as == .no_as) {
1896 const int_lit_node = try transCreateNodeAPInt(rp.c, eval_result.Val.getInt());
1897 return maybeSuppressResult(rp, scope, result_used, int_lit_node);
1851 const int_lit_node = try transCreateNodeAPInt(c, eval_result.Val.getInt());
1852 return maybeSuppressResult(c, scope, result_used, int_lit_node);
18981853 }
18991854
19001855 // Integer literals in C have types, and this can matter for several reasons.
......@@ -1908,51 +1863,26 @@ fn transIntegerLiteral(
19081863 // But the first step is to be correct, and the next step is to make the output more elegant.
19091864
19101865 // @as(T, x)
1911 const expr_base = @ptrCast(*const clang.Expr, expr);
1912 const as_node = try rp.c.createBuiltinCall("@as", 2);
1913 const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc());
1914 as_node.params()[0] = ty_node;
1915 _ = try appendToken(rp.c, .Comma, ",");
1916 as_node.params()[1] = try transCreateNodeAPInt(rp.c, eval_result.Val.getInt());
1917
1918 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1919 return maybeSuppressResult(rp, scope, result_used, &as_node.base);
1920}
1921
1922/// In C if a function has return type `int` and the return value is a boolean
1923/// expression, there is no implicit cast. So the translated Zig will need to
1924/// call @boolToInt
1925fn zigShouldCastBooleanReturnToInt(node: ?*ast.Node, qt: ?clang.QualType) bool {
1926 if (node == null or qt == null) return false;
1927 return isBoolRes(node.?) and cIsNativeInt(qt.?);
1866 const ty_node = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc());
1867 const rhs = try transCreateNodeAPInt(c, eval_result.Val.getInt());
1868 const as = try Node.as.create(c.arena, .{ .lhs = ty_node, .rhs = rhs });
1869 return maybeSuppressResult(c, scope, result_used, as);
19281870}
19291871
19301872fn transReturnStmt(
1931 rp: RestorePoint,
1873 c: *Context,
19321874 scope: *Scope,
19331875 expr: *const clang.ReturnStmt,
19341876) TransError!*ast.Node {
1935 const return_kw = try appendToken(rp.c, .Keyword_return, "return");
1936 var rhs: ?*ast.Node = if (expr.getRetValue()) |val_expr|
1937 try transExprCoercing(rp, scope, val_expr, .used, .r_value)
1938 else
1939 null;
1940 const return_qt = scope.findBlockReturnType(rp.c);
1941 if (zigShouldCastBooleanReturnToInt(rhs, return_qt)) {
1942 const bool_to_int_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1943 bool_to_int_node.params()[0] = rhs.?;
1944 bool_to_int_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1877 const val_expr = expr.getRetValue() orelse
1878 return Node.return_void.init();
19451879
1946 rhs = &bool_to_int_node.base;
1880 var rhs = try transExprCoercing(c, scope, val_expr, .used, .r_value);
1881 const return_qt = scope.findBlockReturnType(c);
1882 if (isBoolRes(rhs) and !qualTypeIsBoolean(return_qt)) {
1883 rhs = try Node.bool_to_int.create(c.arena, rhs);
19471884 }
1948 const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{
1949 .ltoken = return_kw,
1950 .tag = .Return,
1951 }, .{
1952 .rhs = rhs,
1953 });
1954 _ = try appendToken(rp.c, .Semicolon, ";");
1955 return &return_expr.base;
1885 return Node.@"return".create(c.arena, rhs);
19561886}
19571887
19581888fn transStringLiteral(
......@@ -2251,6 +2181,33 @@ fn transExpr(
22512181 return transStmt(c, scope, @ptrCast(*const clang.Stmt, expr), used, lrvalue);
22522182}
22532183
2184/// Same as `transExpr` but with the knowledge that the operand will be type coerced, and therefore
2185/// an `@as` would be redundant. This is used to prevent redundant `@as` in integer literals.
2186fn transExprCoercing(
2187 c: *Context,
2188 scope: *Scope,
2189 expr: *const clang.Expr,
2190 used: ResultUsed,
2191 lrvalue: LRValue,
2192) TransError!Node {
2193 switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) {
2194 .IntegerLiteralClass => {
2195 return transIntegerLiteral(c, scope, @ptrCast(*const clang.IntegerLiteral, expr), .used, .no_as);
2196 },
2197 .CharacterLiteralClass => {
2198 return transCharLiteral(c, scope, @ptrCast(*const clang.CharacterLiteral, expr), .used, .no_as);
2199 },
2200 .UnaryOperatorClass => {
2201 const un_expr = @ptrCast(*const clang.UnaryOperator, expr);
2202 if (un_expr.getOpcode() == .Extension) {
2203 return transExprCoercing(c, scope, un_expr.getSubExpr(), used, lrvalue);
2204 }
2205 },
2206 else => {},
2207 }
2208 return transExpr(c, scope, expr, .used, .r_value);
2209}
2210
22542211fn transInitListExprRecord(
22552212 rp: RestorePoint,
22562213 scope: *Scope,
......@@ -3257,71 +3214,59 @@ fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {
32573214 }
32583215}
32593216
3260fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.UnaryOperator, used: ResultUsed) TransError!*ast.Node {
3217fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperator, used: ResultUsed) TransError!Node {
32613218 const op_expr = stmt.getSubExpr();
32623219 switch (stmt.getOpcode()) {
32633220 .PostInc => if (qualTypeHasWrappingOverflow(stmt.getType()))
3264 return transCreatePostCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
3221 return transCreatePostCrement(c, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
32653222 else
3266 return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
3223 return transCreatePostCrement(c, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
32673224 .PostDec => if (qualTypeHasWrappingOverflow(stmt.getType()))
3268 return transCreatePostCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
3225 return transCreatePostCrement(c, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
32693226 else
3270 return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
3227 return transCreatePostCrement(c, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
32713228 .PreInc => if (qualTypeHasWrappingOverflow(stmt.getType()))
3272 return transCreatePreCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
3229 return transCreatePreCrement(c, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
32733230 else
3274 return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
3231 return transCreatePreCrement(c, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
32753232 .PreDec => if (qualTypeHasWrappingOverflow(stmt.getType()))
3276 return transCreatePreCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
3233 return transCreatePreCrement(c, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
32773234 else
3278 return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
3235 return transCreatePreCrement(c, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
32793236 .AddrOf => {
32803237 if (cIsFunctionDeclRef(op_expr)) {
32813238 return transExpr(rp, scope, op_expr, used, .r_value);
32823239 }
3283 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3284 op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
3285 return &op_node.base;
3240 return Node.address_of.create(c.arena, try transExpr(c, scope, op_expr, used, .r_value));
32863241 },
32873242 .Deref => {
3288 const value_node = try transExpr(rp, scope, op_expr, used, .r_value);
3243 const node = try transExpr(c, scope, op_expr, used, .r_value);
32893244 var is_ptr = false;
32903245 const fn_ty = qualTypeGetFnProto(op_expr.getType(), &is_ptr);
32913246 if (fn_ty != null and is_ptr)
3292 return value_node;
3293 const unwrapped = try transCreateNodeUnwrapNull(rp.c, value_node);
3294 return transCreateNodePtrDeref(rp.c, unwrapped);
3247 return node;
3248 return Node.unwrap_deref.create(c.arena, node);
32953249 },
3296 .Plus => return transExpr(rp, scope, op_expr, used, .r_value),
3250 .Plus => return transExpr(c, scope, op_expr, used, .r_value),
32973251 .Minus => {
32983252 if (!qualTypeHasWrappingOverflow(op_expr.getType())) {
3299 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .Negation, .Minus, "-");
3300 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3301 return &op_node.base;
3253 return Node.negate.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value));
33023254 } else if (cIsUnsignedInteger(op_expr.getType())) {
3303 // we gotta emit 0 -% x
3304 const zero = try transCreateNodeInt(rp.c, 0);
3305 const token = try appendToken(rp.c, .MinusPercent, "-%");
3306 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
3307 return transCreateNodeInfixOp(rp, scope, zero, .SubWrap, token, expr, used, true);
3255 // use -% x for unsigned integers
3256 return Node.negate_wrap.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value));
33083257 } else
3309 return revertAndWarn(rp, error.UnsupportedTranslation, stmt.getBeginLoc(), "C negation with non float non integer", .{});
3258 return revertAndWarn(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "C negation with non float non integer", .{});
33103259 },
33113260 .Not => {
3312 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BitNot, .Tilde, "~");
3313 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3314 return &op_node.base;
3261 return Node.bit_not.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value));
33153262 },
33163263 .LNot => {
3317 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");
3318 op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
3319 return &op_node.base;
3264 return Node.not.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value));
33203265 },
33213266 .Extension => {
3322 return transExpr(rp, scope, stmt.getSubExpr(), used, .l_value);
3267 return transExpr(c, scope, stmt.getSubExpr(), used, .l_value);
33233268 },
3324 else => return revertAndWarn(rp, error.UnsupportedTranslation, stmt.getBeginLoc(), "unsupported C translation {}", .{stmt.getOpcode()}),
3269 else => return revertAndWarn(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "unsupported C translation {}", .{stmt.getOpcode()}),
33253270 }
33263271}
33273272
......@@ -3910,8 +3855,7 @@ fn maybeSuppressResult(
39103855 return &op_node.base;
39113856}
39123857
3913fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
3914 try c.root_decls.append(c.gpa, decl_node);
3858fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
39153859 _ = try c.global_scope.sym_table.put(name, decl_node);
39163860}
39173861
......@@ -4356,7 +4300,7 @@ fn transCreateNodePtrType(
43564300 return node;
43574301}
43584302
4359fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node {
4303fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {
43604304 const num_limbs = math.cast(usize, int.getNumWords()) catch |err| switch (err) {
43614305 error.Overflow => return error.OutOfMemory,
43624306 };
......@@ -4396,14 +4340,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node {
43964340 const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) {
43974341 error.OutOfMemory => return error.OutOfMemory,
43984342 };
4399 defer c.arena.free(str);
4400 const token = try appendToken(c, .IntegerLiteral, str);
4401 const node = try c.arena.create(ast.Node.OneToken);
4402 node.* = .{
4403 .base = .{ .tag = .IntegerLiteral },
4404 .token = token,
4405 };
4406 return &node.base;
4343 return Node.int_literal.create(c.arena, str);
44074344}
44084345
44094346fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
src/translate_c/ast.zig+30-5
......@@ -109,11 +109,16 @@ pub const Node = extern union {
109109 div_trunc,
110110 /// @boolToInt(lhs, rhs)
111111 bool_to_int,
112 /// @as(lhs, rhs)
113 as,
112114
113115 negate,
114116 negate_wrap,
115117 bit_not,
116118 not,
119 address_of,
120 // operand.?.*
121 unwrap_deref,
117122
118123 block,
119124 @"break",
......@@ -151,9 +156,8 @@ pub const Node = extern union {
151156 .bit_not,
152157 .not,
153158 .optional_type,
154 .c_pointer,
155 .single_pointer,
156 .array_type,
159 .address_of,
160 .unwrap_deref,
157161 => Payload.UnOp,
158162
159163 .add,
......@@ -208,6 +212,7 @@ pub const Node = extern union {
208212 .rem,
209213 .int_cast,
210214 .bool_to_int,
215 .as,
211216 => Payload.BinOp,
212217
213218 .int,
......@@ -236,6 +241,9 @@ pub const Node = extern union {
236241 .container_init => Payload.ContainerInit,
237242 .std_meta_cast => Payload.Infix,
238243 .block => Payload.Block,
244 .c_pointer => Payload.Pointer,
245 .single_pointer => Payload.Pointer,
246 .array_type => Payload.Array,
239247 };
240248 }
241249
......@@ -424,9 +432,26 @@ pub const Payload = struct {
424432 base: Node = .{ .tag = .@"break" },
425433 data: *Block
426434 };
435
436 pub const Array = struct {
437 base: Node,
438 data: struct {
439 elem_type: Node,
440 len: Node,
441 },
442 };
443
444 pub const Pointer = struct {
445 base: Node,
446 data: struct {
447 elem_type: Node,
448 is_const: bool,
449 is_volatile: bool,
450 },
451 };
427452};
428453
429/// Converts the nodes into a Zig ast and then renders it.
430pub fn render(allocator: *Allocator, nodes: []const Node) !void {
454/// Converts the nodes into a Zig ast.
455pub fn render(allocator: *Allocator, nodes: []const Node) !*ast.Tree {
431456 @panic("TODO");
432457}