Merge branch 'dimenus-c-field-expr'
commit
8d5c4a67a7
|
@ -120,6 +120,7 @@ static void begin_token(CTokenize *ctok, CTokId id) {
|
|||
case CTokIdLParen:
|
||||
case CTokIdRParen:
|
||||
case CTokIdEOF:
|
||||
case CTokIdDot:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -216,9 +217,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
|
|||
buf_append_char(&ctok->buf, '0');
|
||||
break;
|
||||
case '.':
|
||||
begin_token(ctok, CTokIdNumLitFloat);
|
||||
ctok->state = CTokStateFloat;
|
||||
buf_init_from_str(&ctok->buf, "0.");
|
||||
begin_token(ctok, CTokIdDot);
|
||||
end_token(ctok);
|
||||
break;
|
||||
case '(':
|
||||
begin_token(ctok, CTokIdLParen);
|
||||
|
@ -238,6 +238,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
|
|||
break;
|
||||
case CTokStateFloat:
|
||||
switch (*c) {
|
||||
case '.':
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
buf_append_char(&ctok->buf, 'e');
|
||||
|
|
|
@ -21,6 +21,7 @@ enum CTokId {
|
|||
CTokIdLParen,
|
||||
CTokIdRParen,
|
||||
CTokIdEOF,
|
||||
CTokIdDot,
|
||||
};
|
||||
|
||||
enum CNumLitSuffix {
|
||||
|
|
|
@ -6302,8 +6302,9 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char
|
|||
buf_appendf(name, ")");
|
||||
return name;
|
||||
} else {
|
||||
//Note: C-imports do not have valid location information
|
||||
return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,
|
||||
buf_ptr(source_node->owner->path), source_node->line + 1, source_node->column + 1);
|
||||
(source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,6 @@
|
|||
|
||||
using namespace clang;
|
||||
|
||||
struct MacroSymbol {
|
||||
Buf *name;
|
||||
Buf *value;
|
||||
};
|
||||
|
||||
struct Alias {
|
||||
Buf *new_name;
|
||||
Buf *canon_name;
|
||||
|
@ -44,7 +39,6 @@ struct Context {
|
|||
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> global_table;
|
||||
SourceManager *source_manager;
|
||||
ZigList<Alias> aliases;
|
||||
ZigList<MacroSymbol> macro_symbols;
|
||||
AstNode *source_node;
|
||||
bool warnings_on;
|
||||
|
||||
|
@ -351,8 +345,7 @@ static AstNode *trans_create_node_var_decl_local(Context *c, bool is_const, Buf
|
|||
return trans_create_node_var_decl(c, VisibModPrivate, is_const, var_name, type_node, init_node);
|
||||
}
|
||||
|
||||
|
||||
static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_name, AstNode *src_proto_node) {
|
||||
static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *ref_node, AstNode *src_proto_node) {
|
||||
AstNode *fn_def = trans_create_node(c, NodeTypeFnDef);
|
||||
AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto);
|
||||
fn_proto->data.fn_proto.visib_mod = c->visib_mod;
|
||||
|
@ -363,7 +356,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_n
|
|||
fn_def->data.fn_def.fn_proto = fn_proto;
|
||||
fn_proto->data.fn_proto.fn_def_node = fn_def;
|
||||
|
||||
AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, trans_create_node_symbol(c, var_name));
|
||||
AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, ref_node);
|
||||
AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr);
|
||||
fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node;
|
||||
|
||||
|
@ -3517,7 +3510,6 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
|
|||
}
|
||||
|
||||
const char *raw_name = decl_name(record_decl);
|
||||
|
||||
const char *container_kind_name;
|
||||
ContainerKind container_kind;
|
||||
if (record_decl->isUnion()) {
|
||||
|
@ -3809,6 +3801,83 @@ static void render_aliases(Context *c) {
|
|||
}
|
||||
}
|
||||
|
||||
static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node);
|
||||
|
||||
static AstNode *trans_lookup_ast_container(Context *c, AstNode *type_node) {
|
||||
if (type_node == nullptr) {
|
||||
return nullptr;
|
||||
} else if (type_node->type == NodeTypeContainerDecl) {
|
||||
return type_node;
|
||||
} else if (type_node->type == NodeTypePrefixOpExpr) {
|
||||
return type_node;
|
||||
} else if (type_node->type == NodeTypeSymbol) {
|
||||
AstNode *existing_node = get_global(c, type_node->data.symbol_expr.symbol);
|
||||
if (existing_node == nullptr)
|
||||
return nullptr;
|
||||
if (existing_node->type != NodeTypeVariableDeclaration)
|
||||
return nullptr;
|
||||
return trans_lookup_ast_container(c, existing_node->data.variable_declaration.expr);
|
||||
} else if (type_node->type == NodeTypeFieldAccessExpr) {
|
||||
AstNode *container_node = trans_lookup_ast_container_typeof(c, type_node->data.field_access_expr.struct_expr);
|
||||
if (container_node == nullptr)
|
||||
return nullptr;
|
||||
if (container_node->type != NodeTypeContainerDecl)
|
||||
return container_node;
|
||||
|
||||
for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) {
|
||||
AstNode *field_node = container_node->data.container_decl.fields.items[i];
|
||||
if (buf_eql_buf(field_node->data.struct_field.name, type_node->data.field_access_expr.field_name)) {
|
||||
return trans_lookup_ast_container(c, field_node->data.struct_field.type);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node) {
|
||||
if (ref_node->type == NodeTypeSymbol) {
|
||||
AstNode *existing_node = get_global(c, ref_node->data.symbol_expr.symbol);
|
||||
if (existing_node == nullptr)
|
||||
return nullptr;
|
||||
if (existing_node->type != NodeTypeVariableDeclaration)
|
||||
return nullptr;
|
||||
return trans_lookup_ast_container(c, existing_node->data.variable_declaration.type);
|
||||
} else if (ref_node->type == NodeTypeFieldAccessExpr) {
|
||||
AstNode *container_node = trans_lookup_ast_container_typeof(c, ref_node->data.field_access_expr.struct_expr);
|
||||
if (container_node == nullptr)
|
||||
return nullptr;
|
||||
if (container_node->type != NodeTypeContainerDecl)
|
||||
return container_node;
|
||||
for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) {
|
||||
AstNode *field_node = container_node->data.container_decl.fields.items[i];
|
||||
if (buf_eql_buf(field_node->data.struct_field.name, ref_node->data.field_access_expr.field_name)) {
|
||||
return trans_lookup_ast_container(c, field_node->data.struct_field.type);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static AstNode *trans_lookup_ast_maybe_fn(Context *c, AstNode *ref_node) {
|
||||
AstNode *prefix_node = trans_lookup_ast_container_typeof(c, ref_node);
|
||||
if (prefix_node == nullptr)
|
||||
return nullptr;
|
||||
if (prefix_node->type != NodeTypePrefixOpExpr)
|
||||
return nullptr;
|
||||
if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpMaybe)
|
||||
return nullptr;
|
||||
|
||||
AstNode *fn_proto_node = prefix_node->data.prefix_op_expr.primary_expr;
|
||||
if (fn_proto_node->type != NodeTypeFnProto)
|
||||
return nullptr;
|
||||
|
||||
return fn_proto_node;
|
||||
}
|
||||
|
||||
static void render_macros(Context *c) {
|
||||
auto it = c->macro_table.entry_iterator();
|
||||
for (;;) {
|
||||
|
@ -3816,9 +3885,16 @@ static void render_macros(Context *c) {
|
|||
if (!entry)
|
||||
break;
|
||||
|
||||
AstNode *proto_node;
|
||||
AstNode *value_node = entry->value;
|
||||
if (value_node->type == NodeTypeFnDef) {
|
||||
add_top_level_decl(c, value_node->data.fn_def.fn_proto->data.fn_proto.name, value_node);
|
||||
} else if ((proto_node = trans_lookup_ast_maybe_fn(c, value_node))) {
|
||||
// If a macro aliases a global variable which is a function pointer, we conclude that
|
||||
// the macro is intended to represent a function that assumes the function pointer
|
||||
// variable is non-null and calls it.
|
||||
AstNode *inline_fn_node = trans_create_node_inline_fn(c, entry->key, value_node, proto_node);
|
||||
add_top_level_decl(c, entry->key, inline_fn_node);
|
||||
} else {
|
||||
add_global_var(c, entry->key, value_node);
|
||||
}
|
||||
|
@ -3869,9 +3945,33 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {
|
|||
return parse_ctok_num_lit(c, ctok, tok_i, false);
|
||||
case CTokIdSymbol:
|
||||
{
|
||||
*tok_i += 1;
|
||||
bool need_symbol = false;
|
||||
CTokId curr_id = CTokIdSymbol;
|
||||
Buf *symbol_name = buf_create_from_buf(&tok->data.symbol);
|
||||
return trans_create_node_symbol(c, symbol_name);
|
||||
AstNode *curr_node = trans_create_node_symbol(c, symbol_name);
|
||||
AstNode *parent_node = curr_node;
|
||||
do {
|
||||
*tok_i += 1;
|
||||
CTok* curr_tok = &ctok->tokens.at(*tok_i);
|
||||
if (need_symbol) {
|
||||
if (curr_tok->id == CTokIdSymbol) {
|
||||
symbol_name = buf_create_from_buf(&curr_tok->data.symbol);
|
||||
curr_node = trans_create_node_field_access(c, parent_node, buf_create_from_buf(symbol_name));
|
||||
parent_node = curr_node;
|
||||
need_symbol = false;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
if (curr_tok->id == CTokIdDot) {
|
||||
need_symbol = true;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (curr_id != CTokIdEOF);
|
||||
return curr_node;
|
||||
}
|
||||
case CTokIdLParen:
|
||||
{
|
||||
|
@ -3885,6 +3985,7 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {
|
|||
*tok_i += 1;
|
||||
return inner_node;
|
||||
}
|
||||
case CTokIdDot:
|
||||
case CTokIdEOF:
|
||||
case CTokIdRParen:
|
||||
// not able to make sense of this
|
||||
|
@ -3920,40 +4021,8 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch
|
|||
if (buf_eql_buf(name, symbol_name)) {
|
||||
return;
|
||||
}
|
||||
c->macro_symbols.append({name, symbol_name});
|
||||
} else {
|
||||
c->macro_table.put(name, result_node);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_symbol_macros(Context *c) {
|
||||
for (size_t i = 0; i < c->macro_symbols.length; i += 1) {
|
||||
MacroSymbol ms = c->macro_symbols.at(i);
|
||||
|
||||
// Check if this macro aliases another top level declaration
|
||||
AstNode *existing_node = get_global(c, ms.value);
|
||||
if (!existing_node || name_exists_global(c, ms.name))
|
||||
continue;
|
||||
|
||||
// If a macro aliases a global variable which is a function pointer, we conclude that
|
||||
// the macro is intended to represent a function that assumes the function pointer
|
||||
// variable is non-null and calls it.
|
||||
if (existing_node->type == NodeTypeVariableDeclaration) {
|
||||
AstNode *var_type = existing_node->data.variable_declaration.type;
|
||||
if (var_type != nullptr && var_type->type == NodeTypePrefixOpExpr &&
|
||||
var_type->data.prefix_op_expr.prefix_op == PrefixOpMaybe)
|
||||
{
|
||||
AstNode *fn_proto_node = var_type->data.prefix_op_expr.primary_expr;
|
||||
if (fn_proto_node->type == NodeTypeFnProto) {
|
||||
AstNode *inline_fn_node = trans_create_node_inline_fn(c, ms.name, ms.value, fn_proto_node);
|
||||
c->macro_table.put(ms.name, inline_fn_node);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_global_var(c, ms.name, trans_create_node_symbol(c, ms.value));
|
||||
}
|
||||
c->macro_table.put(name, result_node);
|
||||
}
|
||||
|
||||
static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
|
||||
|
@ -4170,7 +4239,6 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
|
|||
|
||||
process_preprocessor_entities(c, *ast_unit);
|
||||
|
||||
process_symbol_macros(c);
|
||||
render_macros(c);
|
||||
render_aliases(c);
|
||||
|
||||
|
|
|
@ -1046,6 +1046,44 @@ pub fn addCases(cases: &tests.TranslateCContext) {
|
|||
\\ return x + 13;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("macros with field targets",
|
||||
\\typedef unsigned int GLbitfield;
|
||||
\\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
|
||||
\\typedef void(*OpenGLProc)(void);
|
||||
\\union OpenGLProcs {
|
||||
\\ OpenGLProc ptr[1];
|
||||
\\ struct {
|
||||
\\ PFNGLCLEARPROC Clear;
|
||||
\\ } gl;
|
||||
\\};
|
||||
\\extern union OpenGLProcs glProcs;
|
||||
\\#define glClearUnion glProcs.gl.Clear
|
||||
\\#define glClearPFN PFNGLCLEARPROC
|
||||
,
|
||||
\\pub const GLbitfield = c_uint;
|
||||
,
|
||||
\\pub const PFNGLCLEARPROC = ?extern fn(GLbitfield);
|
||||
,
|
||||
\\pub const OpenGLProc = ?extern fn();
|
||||
,
|
||||
\\pub const union_OpenGLProcs = extern union {
|
||||
\\ ptr: [1]OpenGLProc,
|
||||
\\ gl: extern struct {
|
||||
\\ Clear: PFNGLCLEARPROC,
|
||||
\\ },
|
||||
\\};
|
||||
,
|
||||
\\pub extern var glProcs: union_OpenGLProcs;
|
||||
,
|
||||
\\pub const glClearPFN = PFNGLCLEARPROC;
|
||||
,
|
||||
\\pub inline fn glClearUnion(arg0: GLbitfield) {
|
||||
\\ (??glProcs.gl.Clear)(arg0)
|
||||
\\}
|
||||
,
|
||||
\\pub const OpenGLProcs = union_OpenGLProcs;
|
||||
);
|
||||
|
||||
cases.add("switch statement with no default",
|
||||
\\int foo(int x) {
|
||||
|
|
Loading…
Reference in New Issue