diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig index cc862a0e67..2ac3be068e 100644 --- a/src-self-hosted/c_tokenizer.zig +++ b/src-self-hosted/c_tokenizer.zig @@ -31,6 +31,8 @@ pub const CToken = struct { LBrace, RBrace, Pipe, + QuestionMark, + Colon, }; pub const NumLitSuffix = enum { @@ -365,6 +367,14 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { result.id = .Pipe; state = .Done; }, + '?' => { + result.id = .QuestionMark; + state = .Done; + }, + ':' => { + result.id = .Colon; + state = .Done; + }, else => return error.TokenizingFailed, } }, diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index e1d6c9a814..5d73d1b69c 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -4545,6 +4545,18 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc call_node.rtoken = try appendToken(rp.c, .RParen, ")"); node = &call_node.base; }, + .QuestionMark => { + // must come immediately after expr + _ = try appendToken(rp.c, .RParen, ")"); + const if_node = try transCreateNodeIf(rp.c); + if_node.condition = node; + if_node.body = try parseCPrimaryExpr(rp, it, source_loc, scope); + if (it.next().?.id != .Colon) + return error.ParseError; + if_node.@"else" = try transCreateNodeElse(rp.c); + if_node.@"else".?.body = try parseCPrimaryExpr(rp, it, source_loc, scope); + node = &if_node.base; + }, else => { _ = it.prev(); return node; diff --git a/test/translate_c.zig b/test/translate_c.zig index 452898b1be..9994e23d4c 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -2192,6 +2192,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.add_2("macro conditional operator", + \\#define FOO a ? b : c + , &[_][]const u8{ + \\pub const FOO = if (a) b else c; + }); + /////////////// Cases for only stage1 because stage2 behavior is better //////////////// cases.addC("Parameterless function prototypes", \\void foo() {}