| ... | ... | @@ -5226,6 +5226,7 @@ const MacroCtx = struct { |
| 5226 | 5226 | loc: clang.SourceLocation, |
| 5227 | 5227 | name: []const u8, |
| 5228 | 5228 | refs_var_decl: bool = false, |
| 5229 | fn_params: ?[]const ast.Payload.Param = null, |
| 5229 | 5230 | |
| 5230 | 5231 | fn peek(self: *MacroCtx) ?CToken.Id { |
| 5231 | 5232 | if (self.i >= self.list.len) return null; |
| ... | ... | @@ -5298,6 +5299,15 @@ const MacroCtx = struct { |
| 5298 | 5299 | } |
| 5299 | 5300 | return null; |
| 5300 | 5301 | } |
| 5302 | |
| 5303 | fn checkFnParam(self: *MacroCtx, str: []const u8) bool { |
| 5304 | if (self.fn_params == null) return false; |
| 5305 | |
| 5306 | for (self.fn_params.?) |param| { |
| 5307 | if (mem.eql(u8, param.name.?, str)) return true; |
| 5308 | } |
| 5309 | return false; |
| 5310 | } |
| 5301 | 5311 | }; |
| 5302 | 5312 | |
| 5303 | 5313 | fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) ![]const u8 { |
| ... | ... | @@ -5474,10 +5484,9 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5474 | 5484 | defer fn_params.deinit(); |
| 5475 | 5485 | |
| 5476 | 5486 | while (true) { |
| 5477 | | switch (m.peek().?) { |
| 5478 | | .identifier, .extended_identifier => _ = m.next(), |
| 5479 | | else => break, |
| 5480 | | } |
| 5487 | if (!m.peek().?.isMacroIdentifier()) break; |
| 5488 | |
| 5489 | _ = m.next(); |
| 5481 | 5490 | |
| 5482 | 5491 | const mangled_name = try block_scope.makeMangledName(c, m.slice()); |
| 5483 | 5492 | try fn_params.append(.{ |
| ... | ... | @@ -5490,6 +5499,8 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5490 | 5499 | _ = m.next(); |
| 5491 | 5500 | } |
| 5492 | 5501 | |
| 5502 | m.fn_params = fn_params.items; |
| 5503 | |
| 5493 | 5504 | try m.skip(c, .r_paren); |
| 5494 | 5505 | |
| 5495 | 5506 | if (m.checkTranslatableMacro(scope, fn_params.items)) |err| switch (err) { |
| ... | ... | @@ -5905,38 +5916,41 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5905 | 5916 | .pp_num => { |
| 5906 | 5917 | return parseCNumLit(c, m); |
| 5907 | 5918 | }, |
| 5908 | | .identifier, .extended_identifier => { |
| 5909 | | if (c.global_scope.blank_macros.contains(slice)) { |
| 5910 | | return parseCPrimaryExpr(c, m, scope); |
| 5911 | | } |
| 5912 | | const mangled_name = scope.getAlias(slice); |
| 5913 | | if (builtin_typedef_map.get(mangled_name)) |ty| return Tag.type.create(c.arena, ty); |
| 5914 | | const identifier = try Tag.identifier.create(c.arena, mangled_name); |
| 5915 | | scope.skipVariableDiscard(identifier.castTag(.identifier).?.data); |
| 5916 | | refs_var: { |
| 5917 | | const ident_node = c.global_scope.sym_table.get(slice) orelse break :refs_var; |
| 5918 | | const var_decl_node = ident_node.castTag(.var_decl) orelse break :refs_var; |
| 5919 | | if (!var_decl_node.data.is_const) m.refs_var_decl = true; |
| 5920 | | } |
| 5921 | | return identifier; |
| 5922 | | }, |
| 5923 | 5919 | .l_paren => { |
| 5924 | 5920 | const inner_node = try parseCExpr(c, m, scope); |
| 5925 | 5921 | |
| 5926 | 5922 | try m.skip(c, .r_paren); |
| 5927 | 5923 | return inner_node; |
| 5928 | 5924 | }, |
| 5929 | | else => { |
| 5930 | | // for handling type macros (EVIL) |
| 5931 | | // TODO maybe detect and treat type macros as typedefs in parseCSpecifierQualifierList? |
| 5932 | | m.i -= 1; |
| 5933 | | if (try parseCTypeName(c, m, scope, true)) |type_name| { |
| 5934 | | return type_name; |
| 5935 | | } |
| 5936 | | try m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{tok.symbol()}); |
| 5937 | | return error.ParseError; |
| 5938 | | }, |
| 5925 | else => {}, |
| 5926 | } |
| 5927 | |
| 5928 | // The C preprocessor has no knowledge of C, so C keywords aren't special in macros. |
| 5929 | // Thus the current token should be treated like an identifier if its name matches a parameter. |
| 5930 | if (tok == .identifier or tok == .extended_identifier or m.checkFnParam(slice)) { |
| 5931 | if (c.global_scope.blank_macros.contains(slice)) { |
| 5932 | return parseCPrimaryExpr(c, m, scope); |
| 5933 | } |
| 5934 | const mangled_name = scope.getAlias(slice); |
| 5935 | if (builtin_typedef_map.get(mangled_name)) |ty| return Tag.type.create(c.arena, ty); |
| 5936 | const identifier = try Tag.identifier.create(c.arena, mangled_name); |
| 5937 | scope.skipVariableDiscard(identifier.castTag(.identifier).?.data); |
| 5938 | refs_var: { |
| 5939 | const ident_node = c.global_scope.sym_table.get(slice) orelse break :refs_var; |
| 5940 | const var_decl_node = ident_node.castTag(.var_decl) orelse break :refs_var; |
| 5941 | if (!var_decl_node.data.is_const) m.refs_var_decl = true; |
| 5942 | } |
| 5943 | return identifier; |
| 5944 | } |
| 5945 | |
| 5946 | // for handling type macros (EVIL) |
| 5947 | // TODO maybe detect and treat type macros as typedefs in parseCSpecifierQualifierList? |
| 5948 | m.i -= 1; |
| 5949 | if (try parseCTypeName(c, m, scope, true)) |type_name| { |
| 5950 | return type_name; |
| 5939 | 5951 | } |
| 5952 | try m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{tok.symbol()}); |
| 5953 | return error.ParseError; |
| 5940 | 5954 | } |
| 5941 | 5955 | |
| 5942 | 5956 | fn macroIntFromBool(c: *Context, node: Node) !Node { |
| ... | ... | @@ -6199,41 +6213,50 @@ fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) Pa |
| 6199 | 6213 | |
| 6200 | 6214 | fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node { |
| 6201 | 6215 | const tok = m.next().?; |
| 6202 | | switch (tok) { |
| 6203 | | .identifier, .extended_identifier => { |
| 6204 | | if (c.global_scope.blank_macros.contains(m.slice())) { |
| 6205 | | return try parseCSpecifierQualifierList(c, m, scope, allow_fail); |
| 6206 | | } |
| 6207 | | const mangled_name = scope.getAlias(m.slice()); |
| 6208 | | if (!allow_fail or c.typedefs.contains(mangled_name)) { |
| 6209 | | if (builtin_typedef_map.get(mangled_name)) |ty| return try Tag.type.create(c.arena, ty); |
| 6210 | | return try Tag.identifier.create(c.arena, mangled_name); |
| 6211 | | } |
| 6212 | | }, |
| 6213 | | .keyword_void => return try Tag.type.create(c.arena, "anyopaque"), |
| 6214 | | .keyword_bool => return try Tag.type.create(c.arena, "bool"), |
| 6215 | | .keyword_char, |
| 6216 | | .keyword_int, |
| 6217 | | .keyword_short, |
| 6218 | | .keyword_long, |
| 6219 | | .keyword_float, |
| 6220 | | .keyword_double, |
| 6221 | | .keyword_signed, |
| 6222 | | .keyword_unsigned, |
| 6223 | | .keyword_complex, |
| 6224 | | => { |
| 6225 | | m.i -= 1; |
| 6226 | | return try parseCNumericType(c, m); |
| 6227 | | }, |
| 6228 | | .keyword_enum, .keyword_struct, .keyword_union => { |
| 6229 | | // struct Foo will be declared as struct_Foo by transRecordDecl |
| 6230 | | const slice = m.slice(); |
| 6231 | | try m.skip(c, .identifier); |
| 6216 | const slice = m.slice(); |
| 6217 | const mangled_name = scope.getAlias(slice); |
| 6218 | if (!m.checkFnParam(mangled_name)) { |
| 6219 | switch (tok) { |
| 6220 | .identifier, .extended_identifier => { |
| 6221 | if (c.global_scope.blank_macros.contains(m.slice())) { |
| 6222 | return try parseCSpecifierQualifierList(c, m, scope, allow_fail); |
| 6223 | } |
| 6224 | if (!allow_fail or c.typedefs.contains(mangled_name)) { |
| 6225 | if (builtin_typedef_map.get(mangled_name)) |ty| return try Tag.type.create(c.arena, ty); |
| 6226 | return try Tag.identifier.create(c.arena, mangled_name); |
| 6227 | } |
| 6228 | }, |
| 6229 | .keyword_void => return try Tag.type.create(c.arena, "anyopaque"), |
| 6230 | .keyword_bool => return try Tag.type.create(c.arena, "bool"), |
| 6231 | .keyword_char, |
| 6232 | .keyword_int, |
| 6233 | .keyword_short, |
| 6234 | .keyword_long, |
| 6235 | .keyword_float, |
| 6236 | .keyword_double, |
| 6237 | .keyword_signed, |
| 6238 | .keyword_unsigned, |
| 6239 | .keyword_complex, |
| 6240 | => { |
| 6241 | m.i -= 1; |
| 6242 | return try parseCNumericType(c, m); |
| 6243 | }, |
| 6244 | .keyword_enum, .keyword_struct, .keyword_union => { |
| 6245 | // struct Foo will be declared as struct_Foo by transRecordDecl |
| 6246 | try m.skip(c, .identifier); |
| 6232 | 6247 | |
| 6233 | | const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() }); |
| 6234 | | return try Tag.identifier.create(c.arena, name); |
| 6235 | | }, |
| 6236 | | else => {}, |
| 6248 | const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() }); |
| 6249 | return try Tag.identifier.create(c.arena, name); |
| 6250 | }, |
| 6251 | else => {}, |
| 6252 | } |
| 6253 | } else { |
| 6254 | if (allow_fail) { |
| 6255 | m.i -= 1; |
| 6256 | return null; |
| 6257 | } else { |
| 6258 | return try Tag.identifier.create(c.arena, mangled_name); |
| 6259 | } |
| 6237 | 6260 | } |
| 6238 | 6261 | |
| 6239 | 6262 | if (allow_fail) { |
| ... | ... | @@ -6511,7 +6534,7 @@ fn parseCPostfixExprInner(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ? |
| 6511 | 6534 | } |
| 6512 | 6535 | |
| 6513 | 6536 | fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6514 | | switch (m.next().?) { |
| 6537 | sw: switch (m.next().?) { |
| 6515 | 6538 | .bang => { |
| 6516 | 6539 | const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope)); |
| 6517 | 6540 | return Tag.not.create(c.arena, operand); |
| ... | ... | @@ -6534,6 +6557,9 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6534 | 6557 | return Tag.address_of.create(c.arena, operand); |
| 6535 | 6558 | }, |
| 6536 | 6559 | .keyword_sizeof => { |
| 6560 | // 'sizeof' could be used as a parameter to a macro function. |
| 6561 | if (m.checkFnParam(m.slice())) break :sw; |
| 6562 | |
| 6537 | 6563 | const operand = if (m.peek().? == .l_paren) blk: { |
| 6538 | 6564 | _ = m.next(); |
| 6539 | 6565 | const inner = (try parseCTypeName(c, m, scope, false)).?; |
| ... | ... | @@ -6544,6 +6570,9 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6544 | 6570 | return Tag.helpers_sizeof.create(c.arena, operand); |
| 6545 | 6571 | }, |
| 6546 | 6572 | .keyword_alignof => { |
| 6573 | // 'alignof' could be used as a parameter to a macro function. |
| 6574 | if (m.checkFnParam(m.slice())) break :sw; |
| 6575 | |
| 6547 | 6576 | // TODO this won't work if using <stdalign.h>'s |
| 6548 | 6577 | // #define alignof _Alignof |
| 6549 | 6578 | try m.skip(c, .l_paren); |
| ... | ... | @@ -6556,11 +6585,11 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6556 | 6585 | try m.fail(c, "TODO unary inc/dec expr", .{}); |
| 6557 | 6586 | return error.ParseError; |
| 6558 | 6587 | }, |
| 6559 | | else => { |
| 6560 | | m.i -= 1; |
| 6561 | | return try parseCPostfixExpr(c, m, scope, null); |
| 6562 | | }, |
| 6588 | else => {}, |
| 6563 | 6589 | } |
| 6590 | |
| 6591 | m.i -= 1; |
| 6592 | return try parseCPostfixExpr(c, m, scope, null); |
| 6564 | 6593 | } |
| 6565 | 6594 | |
| 6566 | 6595 | fn getContainer(c: *Context, node: Node) ?Node { |