feature. See also
. The project being documented here (as the example) is the Zig library itself.
MacroTranslator.parseCPrimaryExpr
fn parseCPrimaryExpr(mt: *MacroTranslator, scope: *Scope) ParseError!ZigNode
File
Code
fn parseCPrimaryExpr(mt: *MacroTranslator, scope: *Scope) ParseError!ZigNode {
const arena = mt.t.arena;
const gpa = mt.t.gpa;
const tok = mt.peek();
switch (tok) {
.char_literal,
.char_literal_utf_8,
.char_literal_utf_16,
.char_literal_utf_32,
.char_literal_wide,
=> {
const slice = mt.tokSlice();
if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
return ZigTag.char_literal.create(arena, try mt.escapeUnprintables());
} else {
mt.i += 1;
const str = try std.fmt.allocPrint(arena, "0x{x}", .{slice[1 .. slice.len - 1]});
return ZigTag.integer_literal.create(arena, str);
}
},
.string_literal,
.string_literal_utf_16,
.string_literal_utf_8,
.string_literal_utf_32,
.string_literal_wide,
=> return ZigTag.string_literal.create(arena, try mt.escapeUnprintables()),
.pp_num => return mt.parseCNumLit(),
.l_paren => {
mt.i += 1;
const inner_node = try mt.parseCExpr(scope);
try mt.expect(.r_paren);
return inner_node;
},
.macro_param, .macro_param_no_expand => {
const param = mt.macro.params[mt.tokens[mt.i].end];
mt.i += 1;
const mangled_name = scope.getAlias(param) orelse param;
return try ZigTag.identifier.create(arena, mangled_name);
},
.identifier, .extended_identifier => {
const slice = mt.tokSlice();
mt.i += 1;
const mangled_name = scope.getAlias(slice) orelse slice;
if (Translator.builtin_typedef_map.get(mangled_name)) |ty| {
return ZigTag.type.create(arena, ty);
}
if (builtins.map.get(mangled_name)) |builtin| {
const builtin_identifier = try ZigTag.identifier.create(arena, "__builtin");
return ZigTag.field_access.create(arena, .{
.lhs = builtin_identifier,
.field_name = builtin.name,
});
}
const identifier = try ZigTag.identifier.create(arena, mangled_name);
scope.skipVariableDiscard(mangled_name);
refs_var: {
const ident_node = mt.t.global_scope.sym_table.get(slice) orelse break :refs_var;
const var_decl_node = ident_node.castTag(.var_decl) orelse break :refs_var;
if (!var_decl_node.data.is_const) mt.refs_var_decl = true;
}
return identifier;
},
.keyword_generic => {
mt.i += 1;
try mt.expect(.l_paren);
const param = try mt.parseCCondExpr(scope);
const typeof_param = try ZigTag.typeof.create(arena, param);
try mt.expect(.comma);
var cases: std.ArrayList(ZigNode) = .empty;
defer cases.deinit(gpa);
var has_default = false;
while (true) {
const case = if (mt.eat(.keyword_default)) blk: {
has_default = true;
try mt.expect(.colon);
const expr = try mt.parseCCondExpr(scope);
break :blk try ZigTag.switch_else.create(arena, expr);
} else blk: {
const case_type = try mt.parseCTypeName(scope) orelse {
try mt.fail("unable to translate C expr: expected type instead got '{s}'", .{mt.peek().symbol()});
return error.ParseError;
};
try mt.expect(.colon);
const expr = try mt.parseCCondExpr(scope);
break :blk try ZigTag.switch_prong.create(arena, .{
.cases = try arena.dupe(ZigNode, &.{case_type}),
.cond = expr,
});
};
try cases.append(gpa, case);
if (!mt.eat(.comma)) break;
}
try mt.expect(.r_paren);
if (!has_default) try cases.append(gpa, try ZigTag.switch_else.create(
arena,
try ZigTag.@"comptime".create(arena, ZigTag.@"unreachable".init()),
));
const sw = try ZigTag.@"switch".create(arena, .{
.cond = typeof_param,
.cases = try arena.dupe(ZigNode, cases.items),
});
return sw;
},
else => {},
}
// TODO maybe detect and treat type macros as typedefs in parseCSpecifierQualifierList?
if (try mt.parseCTypeName(scope)) |type_name| {
return type_name;
}
try mt.fail("unable to translate C expr: unexpected token '{s}'", .{tok.symbol()});
return error.ParseError;
}