authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-28 03:00:13-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-28 03:00:13-05:00
log8d5c4a67a7dfe2e1fc07f84515d59405c4100b5c
tree9e0a7501730d34fd8fe0dafdadb172733008e162
parent1ab84a27d374e666463c606dc1cd1c4972b52a74
parente745544dacc5bda010fc65e5c8b81cb3b5249223

Merge branch 'dimenus-c-field-expr'


5 files changed, 160 insertions(+), 50 deletions(-)

src/c_tokenizer.cpp+5-3
......@@ -120,6 +120,7 @@ static void begin_token(CTokenize *ctok, CTokId id) {
120120 case CTokIdLParen:
121121 case CTokIdRParen:
122122 case CTokIdEOF:
123 case CTokIdDot:
123124 break;
124125 }
125126}
......@@ -216,9 +217,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
216217 buf_append_char(&ctok->buf, '0');
217218 break;
218219 case '.':
219 begin_token(ctok, CTokIdNumLitFloat);
220 ctok->state = CTokStateFloat;
221 buf_init_from_str(&ctok->buf, "0.");
220 begin_token(ctok, CTokIdDot);
221 end_token(ctok);
222222 break;
223223 case '(':
224224 begin_token(ctok, CTokIdLParen);
......@@ -238,6 +238,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
238238 break;
239239 case CTokStateFloat:
240240 switch (*c) {
241 case '.':
242 break;
241243 case 'e':
242244 case 'E':
243245 buf_append_char(&ctok->buf, 'e');
src/c_tokenizer.hpp+1
......@@ -21,6 +21,7 @@ enum CTokId {
2121 CTokIdLParen,
2222 CTokIdRParen,
2323 CTokIdEOF,
24 CTokIdDot,
2425};
2526
2627enum CNumLitSuffix {
src/ir.cpp+2-1
......@@ -6302,8 +6302,9 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char
63026302 buf_appendf(name, ")");
63036303 return name;
63046304 } else {
6305 //Note: C-imports do not have valid location information
63056306 return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,
6306 buf_ptr(source_node->owner->path), source_node->line + 1, source_node->column + 1);
6307 (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1);
63076308 }
63086309 }
63096310}
src/translate_c.cpp+114-46
......@@ -23,11 +23,6 @@
2323
2424using namespace clang;
2525
26struct MacroSymbol {
27 Buf *name;
28 Buf *value;
29};
30
3126struct Alias {
3227 Buf *new_name;
3328 Buf *canon_name;
......@@ -44,7 +39,6 @@ struct Context {
4439 HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> global_table;
4540 SourceManager *source_manager;
4641 ZigList<Alias> aliases;
47 ZigList<MacroSymbol> macro_symbols;
4842 AstNode *source_node;
4943 bool warnings_on;
5044
......@@ -351,8 +345,7 @@ static AstNode *trans_create_node_var_decl_local(Context *c, bool is_const, Buf
351345 return trans_create_node_var_decl(c, VisibModPrivate, is_const, var_name, type_node, init_node);
352346}
353347
354
355static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_name, AstNode *src_proto_node) {
348static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *ref_node, AstNode *src_proto_node) {
356349 AstNode *fn_def = trans_create_node(c, NodeTypeFnDef);
357350 AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto);
358351 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
363356 fn_def->data.fn_def.fn_proto = fn_proto;
364357 fn_proto->data.fn_proto.fn_def_node = fn_def;
365358
366 AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, trans_create_node_symbol(c, var_name));
359 AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, ref_node);
367360 AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr);
368361 fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node;
369362
......@@ -3517,7 +3510,6 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
35173510 }
35183511
35193512 const char *raw_name = decl_name(record_decl);
3520
35213513 const char *container_kind_name;
35223514 ContainerKind container_kind;
35233515 if (record_decl->isUnion()) {
......@@ -3809,6 +3801,83 @@ static void render_aliases(Context *c) {
38093801 }
38103802}
38113803
3804static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node);
3805
3806static AstNode *trans_lookup_ast_container(Context *c, AstNode *type_node) {
3807 if (type_node == nullptr) {
3808 return nullptr;
3809 } else if (type_node->type == NodeTypeContainerDecl) {
3810 return type_node;
3811 } else if (type_node->type == NodeTypePrefixOpExpr) {
3812 return type_node;
3813 } else if (type_node->type == NodeTypeSymbol) {
3814 AstNode *existing_node = get_global(c, type_node->data.symbol_expr.symbol);
3815 if (existing_node == nullptr)
3816 return nullptr;
3817 if (existing_node->type != NodeTypeVariableDeclaration)
3818 return nullptr;
3819 return trans_lookup_ast_container(c, existing_node->data.variable_declaration.expr);
3820 } else if (type_node->type == NodeTypeFieldAccessExpr) {
3821 AstNode *container_node = trans_lookup_ast_container_typeof(c, type_node->data.field_access_expr.struct_expr);
3822 if (container_node == nullptr)
3823 return nullptr;
3824 if (container_node->type != NodeTypeContainerDecl)
3825 return container_node;
3826
3827 for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) {
3828 AstNode *field_node = container_node->data.container_decl.fields.items[i];
3829 if (buf_eql_buf(field_node->data.struct_field.name, type_node->data.field_access_expr.field_name)) {
3830 return trans_lookup_ast_container(c, field_node->data.struct_field.type);
3831 }
3832 }
3833 return nullptr;
3834 } else {
3835 return nullptr;
3836 }
3837}
3838
3839static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node) {
3840 if (ref_node->type == NodeTypeSymbol) {
3841 AstNode *existing_node = get_global(c, ref_node->data.symbol_expr.symbol);
3842 if (existing_node == nullptr)
3843 return nullptr;
3844 if (existing_node->type != NodeTypeVariableDeclaration)
3845 return nullptr;
3846 return trans_lookup_ast_container(c, existing_node->data.variable_declaration.type);
3847 } else if (ref_node->type == NodeTypeFieldAccessExpr) {
3848 AstNode *container_node = trans_lookup_ast_container_typeof(c, ref_node->data.field_access_expr.struct_expr);
3849 if (container_node == nullptr)
3850 return nullptr;
3851 if (container_node->type != NodeTypeContainerDecl)
3852 return container_node;
3853 for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) {
3854 AstNode *field_node = container_node->data.container_decl.fields.items[i];
3855 if (buf_eql_buf(field_node->data.struct_field.name, ref_node->data.field_access_expr.field_name)) {
3856 return trans_lookup_ast_container(c, field_node->data.struct_field.type);
3857 }
3858 }
3859 return nullptr;
3860 } else {
3861 return nullptr;
3862 }
3863}
3864
3865static AstNode *trans_lookup_ast_maybe_fn(Context *c, AstNode *ref_node) {
3866 AstNode *prefix_node = trans_lookup_ast_container_typeof(c, ref_node);
3867 if (prefix_node == nullptr)
3868 return nullptr;
3869 if (prefix_node->type != NodeTypePrefixOpExpr)
3870 return nullptr;
3871 if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpMaybe)
3872 return nullptr;
3873
3874 AstNode *fn_proto_node = prefix_node->data.prefix_op_expr.primary_expr;
3875 if (fn_proto_node->type != NodeTypeFnProto)
3876 return nullptr;
3877
3878 return fn_proto_node;
3879}
3880
38123881static void render_macros(Context *c) {
38133882 auto it = c->macro_table.entry_iterator();
38143883 for (;;) {
......@@ -3816,9 +3885,16 @@ static void render_macros(Context *c) {
38163885 if (!entry)
38173886 break;
38183887
3888 AstNode *proto_node;
38193889 AstNode *value_node = entry->value;
38203890 if (value_node->type == NodeTypeFnDef) {
38213891 add_top_level_decl(c, value_node->data.fn_def.fn_proto->data.fn_proto.name, value_node);
3892 } else if ((proto_node = trans_lookup_ast_maybe_fn(c, value_node))) {
3893 // If a macro aliases a global variable which is a function pointer, we conclude that
3894 // the macro is intended to represent a function that assumes the function pointer
3895 // variable is non-null and calls it.
3896 AstNode *inline_fn_node = trans_create_node_inline_fn(c, entry->key, value_node, proto_node);
3897 add_top_level_decl(c, entry->key, inline_fn_node);
38223898 } else {
38233899 add_global_var(c, entry->key, value_node);
38243900 }
......@@ -3869,9 +3945,33 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {
38693945 return parse_ctok_num_lit(c, ctok, tok_i, false);
38703946 case CTokIdSymbol:
38713947 {
3872 *tok_i += 1;
3948 bool need_symbol = false;
3949 CTokId curr_id = CTokIdSymbol;
38733950 Buf *symbol_name = buf_create_from_buf(&tok->data.symbol);
3874 return trans_create_node_symbol(c, symbol_name);
3951 AstNode *curr_node = trans_create_node_symbol(c, symbol_name);
3952 AstNode *parent_node = curr_node;
3953 do {
3954 *tok_i += 1;
3955 CTok* curr_tok = &ctok->tokens.at(*tok_i);
3956 if (need_symbol) {
3957 if (curr_tok->id == CTokIdSymbol) {
3958 symbol_name = buf_create_from_buf(&curr_tok->data.symbol);
3959 curr_node = trans_create_node_field_access(c, parent_node, buf_create_from_buf(symbol_name));
3960 parent_node = curr_node;
3961 need_symbol = false;
3962 } else {
3963 return nullptr;
3964 }
3965 } else {
3966 if (curr_tok->id == CTokIdDot) {
3967 need_symbol = true;
3968 continue;
3969 } else {
3970 break;
3971 }
3972 }
3973 } while (curr_id != CTokIdEOF);
3974 return curr_node;
38753975 }
38763976 case CTokIdLParen:
38773977 {
......@@ -3885,6 +3985,7 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {
38853985 *tok_i += 1;
38863986 return inner_node;
38873987 }
3988 case CTokIdDot:
38883989 case CTokIdEOF:
38893990 case CTokIdRParen:
38903991 // not able to make sense of this
......@@ -3920,40 +4021,8 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch
39204021 if (buf_eql_buf(name, symbol_name)) {
39214022 return;
39224023 }
3923 c->macro_symbols.append({name, symbol_name});
3924 } else {
3925 c->macro_table.put(name, result_node);
3926 }
3927}
3928
3929static void process_symbol_macros(Context *c) {
3930 for (size_t i = 0; i < c->macro_symbols.length; i += 1) {
3931 MacroSymbol ms = c->macro_symbols.at(i);
3932
3933 // Check if this macro aliases another top level declaration
3934 AstNode *existing_node = get_global(c, ms.value);
3935 if (!existing_node || name_exists_global(c, ms.name))
3936 continue;
3937
3938 // If a macro aliases a global variable which is a function pointer, we conclude that
3939 // the macro is intended to represent a function that assumes the function pointer
3940 // variable is non-null and calls it.
3941 if (existing_node->type == NodeTypeVariableDeclaration) {
3942 AstNode *var_type = existing_node->data.variable_declaration.type;
3943 if (var_type != nullptr && var_type->type == NodeTypePrefixOpExpr &&
3944 var_type->data.prefix_op_expr.prefix_op == PrefixOpMaybe)
3945 {
3946 AstNode *fn_proto_node = var_type->data.prefix_op_expr.primary_expr;
3947 if (fn_proto_node->type == NodeTypeFnProto) {
3948 AstNode *inline_fn_node = trans_create_node_inline_fn(c, ms.name, ms.value, fn_proto_node);
3949 c->macro_table.put(ms.name, inline_fn_node);
3950 continue;
3951 }
3952 }
3953 }
3954
3955 add_global_var(c, ms.name, trans_create_node_symbol(c, ms.value));
39564024 }
4025 c->macro_table.put(name, result_node);
39574026}
39584027
39594028static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
......@@ -4170,7 +4239,6 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
41704239
41714240 process_preprocessor_entities(c, *ast_unit);
41724241
4173 process_symbol_macros(c);
41744242 render_macros(c);
41754243 render_aliases(c);
41764244
test/translate_c.zig+38
......@@ -1046,6 +1046,44 @@ pub fn addCases(cases: &tests.TranslateCContext) {
10461046 \\ return x + 13;
10471047 \\}
10481048 );
1049
1050 cases.add("macros with field targets",
1051 \\typedef unsigned int GLbitfield;
1052 \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
1053 \\typedef void(*OpenGLProc)(void);
1054 \\union OpenGLProcs {
1055 \\ OpenGLProc ptr[1];
1056 \\ struct {
1057 \\ PFNGLCLEARPROC Clear;
1058 \\ } gl;
1059 \\};
1060 \\extern union OpenGLProcs glProcs;
1061 \\#define glClearUnion glProcs.gl.Clear
1062 \\#define glClearPFN PFNGLCLEARPROC
1063 ,
1064 \\pub const GLbitfield = c_uint;
1065 ,
1066 \\pub const PFNGLCLEARPROC = ?extern fn(GLbitfield);
1067 ,
1068 \\pub const OpenGLProc = ?extern fn();
1069 ,
1070 \\pub const union_OpenGLProcs = extern union {
1071 \\ ptr: [1]OpenGLProc,
1072 \\ gl: extern struct {
1073 \\ Clear: PFNGLCLEARPROC,
1074 \\ },
1075 \\};
1076 ,
1077 \\pub extern var glProcs: union_OpenGLProcs;
1078 ,
1079 \\pub const glClearPFN = PFNGLCLEARPROC;
1080 ,
1081 \\pub inline fn glClearUnion(arg0: GLbitfield) {
1082 \\ (??glProcs.gl.Clear)(arg0)
1083 \\}
1084 ,
1085 \\pub const OpenGLProcs = union_OpenGLProcs;
1086 );
10491087
10501088 cases.add("switch statement with no default",
10511089 \\int foo(int x) {