diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-01-04 16:57:22 -0700 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-01-04 16:57:22 -0700 |
| commit | 4514661cfef1cd0090ba9888b69037af3ef9805a (patch) | |
| tree | a298e8c90440837a9cbf7ec83d9c6408ca59c768 /src | |
| parent | fcacc85b4e7f0a60ae11bbefcdae620665426297 (diff) | |
| download | zig-4514661cfef1cd0090ba9888b69037af3ef9805a.tar.gz zig-4514661cfef1cd0090ba9888b69037af3ef9805a.zip | |
add member functions
Diffstat (limited to 'src')
| -rw-r--r-- | src/analyze.cpp | 435 | ||||
| -rw-r--r-- | src/analyze.hpp | 2 | ||||
| -rw-r--r-- | src/codegen.cpp | 31 | ||||
| -rw-r--r-- | src/parser.cpp | 36 | ||||
| -rw-r--r-- | src/parser.hpp | 2 |
5 files changed, 306 insertions, 200 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index 8a30968376..acf921f35a 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -106,6 +106,11 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { TypeTableEntry *entry = allocate<TypeTableEntry>(1); entry->arrays_by_size.init(2); entry->id = id; + + if (id == TypeTableEntryIdStruct) { + entry->data.structure.fn_table.init(8); + } + return entry; } @@ -461,6 +466,68 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE struct_type->di_type = replacement_di_type; } +static void preview_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node, TypeTableEntry *struct_type) { + assert(node->type == NodeTypeFnDef); + AstNode *proto_node = node->data.fn_def.fn_proto; + assert(proto_node->type == NodeTypeFnProto); + Buf *proto_name = &proto_node->data.fn_proto.name; + + auto fn_table = struct_type ? &struct_type->data.structure.fn_table : &import->fn_table; + + auto entry = fn_table->maybe_get(proto_name); + bool skip = false; + bool is_internal = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport); + bool is_pub = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModPrivate); + if (entry) { + add_node_error(g, node, + buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); + alloc_codegen_node(node); + node->codegen_node->data.fn_def_node.skip = true; + skip = true; + } else if (is_pub) { + auto entry = fn_table->maybe_get(proto_name); + if (entry) { + add_node_error(g, node, + buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); + alloc_codegen_node(node); + node->codegen_node->data.fn_def_node.skip = true; + skip = true; + } + } + if (proto_node->data.fn_proto.is_var_args) { + add_node_error(g, node, + buf_sprintf("variadic arguments only allowed in extern functions")); + } + if (!skip) { + FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); + fn_table_entry->import_entry = import; + fn_table_entry->proto_node = proto_node; + fn_table_entry->fn_def_node = node; + fn_table_entry->internal_linkage = is_internal; + fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv; + fn_table_entry->label_table.init(8); + + g->fn_protos.append(fn_table_entry); + g->fn_defs.append(fn_table_entry); + + fn_table->put(proto_name, fn_table_entry); + + if (!struct_type && + g->bootstrap_import && + import == g->root_import && buf_eql_str(proto_name, "main")) + { + g->bootstrap_import->fn_table.put(proto_name, fn_table_entry); + } + + resolve_function_proto(g, proto_node, fn_table_entry, import); + + + alloc_codegen_node(proto_node); + proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry; + + preview_function_labels(g, node->data.fn_def.body, fn_table_entry); + } +} static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) { switch (node->type) { @@ -500,61 +567,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, } break; case NodeTypeFnDef: - { - AstNode *proto_node = node->data.fn_def.fn_proto; - assert(proto_node->type == NodeTypeFnProto); - Buf *proto_name = &proto_node->data.fn_proto.name; - auto entry = import->fn_table.maybe_get(proto_name); - bool skip = false; - bool is_internal = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport); - bool is_pub = (proto_node->data.fn_proto.visib_mod != FnProtoVisibModPrivate); - if (entry) { - add_node_error(g, node, - buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); - alloc_codegen_node(node); - node->codegen_node->data.fn_def_node.skip = true; - skip = true; - } else if (is_pub) { - auto entry = import->fn_table.maybe_get(proto_name); - if (entry) { - add_node_error(g, node, - buf_sprintf("redefinition of '%s'", buf_ptr(proto_name))); - alloc_codegen_node(node); - node->codegen_node->data.fn_def_node.skip = true; - skip = true; - } - } - if (proto_node->data.fn_proto.is_var_args) { - add_node_error(g, node, - buf_sprintf("variadic arguments only allowed in extern functions")); - } - if (!skip) { - FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); - fn_table_entry->import_entry = import; - fn_table_entry->proto_node = proto_node; - fn_table_entry->fn_def_node = node; - fn_table_entry->internal_linkage = is_internal; - fn_table_entry->calling_convention = is_internal ? LLVMFastCallConv : LLVMCCallConv; - fn_table_entry->label_table.init(8); - - g->fn_protos.append(fn_table_entry); - g->fn_defs.append(fn_table_entry); - - import->fn_table.put(proto_name, fn_table_entry); - - if (g->bootstrap_import && import == g->root_import && buf_eql_str(proto_name, "main")) { - g->bootstrap_import->fn_table.put(proto_name, fn_table_entry); - } - - resolve_function_proto(g, proto_node, fn_table_entry, import); - - - alloc_codegen_node(proto_node); - proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry; - - preview_function_labels(g, node->data.fn_def.body, fn_table_entry); - } - } + preview_fn_def(g, import, node, nullptr); break; case NodeTypeRootExportDecl: if (import == g->root_import) { @@ -605,6 +618,11 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, TypeTableEntry *type_entry = struct_codegen->type_entry; resolve_struct_type(g, import, type_entry); + + for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) { + AstNode *fn_def_node = node->data.struct_decl.fns.at(i); + preview_fn_def(g, import, fn_def_node, type_entry); + } break; } case NodeTypeUse: @@ -1624,6 +1642,94 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im } } +static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, + TypeTableEntry *expected_type, AstNode *node) +{ + AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; + TypeTableEntry *struct_type = nullptr; + HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> *fn_table = &import->fn_table; + AstNode *first_param_expr = nullptr; + Buf *name; + + if (fn_ref_expr->type == NodeTypeFieldAccessExpr) { + first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr; + struct_type = analyze_expression(g, import, context, nullptr, first_param_expr); + name = &fn_ref_expr->data.field_access_expr.field_name; + if (struct_type->id == TypeTableEntryIdStruct) { + fn_table = &struct_type->data.structure.fn_table; + } else if (struct_type->id == TypeTableEntryIdInvalid) { + return struct_type; + } else { + add_node_error(g, fn_ref_expr->data.field_access_expr.struct_expr, + buf_sprintf("member reference base type not struct or enum")); + return g->builtin_types.entry_invalid; + } + } else if (fn_ref_expr->type == NodeTypeSymbol) { + name = &fn_ref_expr->data.symbol; + } else { + add_node_error(g, node, + buf_sprintf("function pointers not yet supported")); + return g->builtin_types.entry_invalid; + } + + auto entry = fn_table->maybe_get(name); + + if (!entry) { + add_node_error(g, fn_ref_expr, + buf_sprintf("undefined function: '%s'", buf_ptr(name))); + // still analyze the parameters, even though we don't know what to expect + for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { + AstNode *child = node->data.fn_call_expr.params.at(i); + analyze_expression(g, import, context, nullptr, child); + } + + return g->builtin_types.entry_invalid; + } else { + FnTableEntry *fn_table_entry = entry->value; + assert(fn_table_entry->proto_node->type == NodeTypeFnProto); + AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; + + // count parameters + int expected_param_count = fn_proto->params.length; + int actual_param_count = node->data.fn_call_expr.params.length; + + if (struct_type) { + actual_param_count += 1; + } + + if (fn_proto->is_var_args) { + if (actual_param_count < expected_param_count) { + add_node_error(g, node, + buf_sprintf("wrong number of arguments. Expected at least %d, got %d.", + expected_param_count, actual_param_count)); + } + } else if (expected_param_count != actual_param_count) { + add_node_error(g, node, + buf_sprintf("wrong number of arguments. Expected %d, got %d.", + expected_param_count, actual_param_count)); + } + + // analyze each parameter. in the case of a method, we already analyzed the + // first parameter in order to figure out which struct we were calling a method on. + for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { + AstNode *child = node->data.fn_call_expr.params.at(i); + // determine the expected type for each parameter + TypeTableEntry *expected_param_type = nullptr; + int fn_proto_i = i + (struct_type ? 1 : 0); + if (fn_proto_i < fn_proto->params.length) { + AstNode *param_decl_node = fn_proto->params.at(fn_proto_i); + assert(param_decl_node->type == NodeTypeParamDecl); + AstNode *param_type_node = param_decl_node->data.param_decl.type; + if (param_type_node->codegen_node) + expected_param_type = param_type_node->codegen_node->data.type_node.entry; + } + analyze_expression(g, import, context, expected_param_type, child); + } + + return fn_proto->return_type->codegen_node->data.type_node.entry; + } +} + static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { @@ -1739,67 +1845,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, break; case NodeTypeFnCallExpr: - { - AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; - if (fn_ref_expr->type != NodeTypeSymbol) { - add_node_error(g, node, - buf_sprintf("function pointers not allowed")); - break; - } - - Buf *name = &fn_ref_expr->data.symbol; - - auto entry = import->fn_table.maybe_get(name); - - if (!entry) { - add_node_error(g, fn_ref_expr, - buf_sprintf("undefined function: '%s'", buf_ptr(name))); - // still analyze the parameters, even though we don't know what to expect - for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { - AstNode *child = node->data.fn_call_expr.params.at(i); - analyze_expression(g, import, context, nullptr, child); - } - - return_type = g->builtin_types.entry_invalid; - } else { - FnTableEntry *fn_table_entry = entry->value; - assert(fn_table_entry->proto_node->type == NodeTypeFnProto); - AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; - - // count parameters - int expected_param_count = fn_proto->params.length; - int actual_param_count = node->data.fn_call_expr.params.length; - if (fn_proto->is_var_args) { - if (actual_param_count < expected_param_count) { - add_node_error(g, node, - buf_sprintf("wrong number of arguments. Expected at least %d, got %d.", - expected_param_count, actual_param_count)); - } - } else if (expected_param_count != actual_param_count) { - add_node_error(g, node, - buf_sprintf("wrong number of arguments. Expected %d, got %d.", - expected_param_count, actual_param_count)); - } - - // analyze each parameter - for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { - AstNode *child = node->data.fn_call_expr.params.at(i); - // determine the expected type for each parameter - TypeTableEntry *expected_param_type = nullptr; - if (i < fn_proto->params.length) { - AstNode *param_decl_node = fn_proto->params.at(i); - assert(param_decl_node->type == NodeTypeParamDecl); - AstNode *param_type_node = param_decl_node->data.param_decl.type; - if (param_type_node->codegen_node) - expected_param_type = param_type_node->codegen_node->data.type_node.entry; - } - analyze_expression(g, import, context, expected_param_type, child); - } - - return_type = fn_proto->return_type->codegen_node->data.type_node.entry; - } - break; - } + return_type = analyze_fn_call_expr(g, import, context, expected_type, node); + break; case NodeTypeArrayAccessExpr: // for reading array access; assignment handled elsewhere @@ -1924,89 +1971,92 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, return return_type; } -static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, AstNode *node) { - switch (node->type) { - case NodeTypeFnDef: - { - if (node->codegen_node && node->codegen_node->data.fn_def_node.skip) { - // we detected an error with this function definition which prevents us - // from further analyzing it. - break; - } +static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) { + assert(node->type == NodeTypeFnDef); - AstNode *fn_proto_node = node->data.fn_def.fn_proto; - assert(fn_proto_node->type == NodeTypeFnProto); + if (node->codegen_node && node->codegen_node->data.fn_def_node.skip) { + // we detected an error with this function definition which prevents us + // from further analyzing it. + return; + } - alloc_codegen_node(node); - BlockContext *context = new_block_context(node, import->block_context); - node->codegen_node->data.fn_def_node.block_context = context; - - AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; - bool is_exported = (fn_proto->visib_mod == FnProtoVisibModExport); - for (int i = 0; i < fn_proto->params.length; i += 1) { - AstNode *param_decl_node = fn_proto->params.at(i); - assert(param_decl_node->type == NodeTypeParamDecl); - - // define local variables for parameters - AstNodeParamDecl *param_decl = ¶m_decl_node->data.param_decl; - assert(param_decl->type->type == NodeTypeType); - TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry; - - if (is_exported && type->id == TypeTableEntryIdStruct) { - add_node_error(g, param_decl_node, - buf_sprintf("byvalue struct parameters not yet supported on exported functions")); - } + AstNode *fn_proto_node = node->data.fn_def.fn_proto; + assert(fn_proto_node->type == NodeTypeFnProto); - VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); - buf_init_from_buf(&variable_entry->name, ¶m_decl->name); - variable_entry->type = type; - variable_entry->is_const = true; - variable_entry->decl_node = param_decl_node; - variable_entry->arg_index = i; + alloc_codegen_node(node); + BlockContext *context = new_block_context(node, import->block_context); + node->codegen_node->data.fn_def_node.block_context = context; + + AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto; + bool is_exported = (fn_proto->visib_mod == FnProtoVisibModExport); + for (int i = 0; i < fn_proto->params.length; i += 1) { + AstNode *param_decl_node = fn_proto->params.at(i); + assert(param_decl_node->type == NodeTypeParamDecl); + + // define local variables for parameters + AstNodeParamDecl *param_decl = ¶m_decl_node->data.param_decl; + assert(param_decl->type->type == NodeTypeType); + TypeTableEntry *type = param_decl->type->codegen_node->data.type_node.entry; + + if (is_exported && type->id == TypeTableEntryIdStruct) { + add_node_error(g, param_decl_node, + buf_sprintf("byvalue struct parameters not yet supported on exported functions")); + } - alloc_codegen_node(param_decl_node); - param_decl_node->codegen_node->data.param_decl_node.variable = variable_entry; + VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); + buf_init_from_buf(&variable_entry->name, ¶m_decl->name); + variable_entry->type = type; + variable_entry->is_const = true; + variable_entry->decl_node = param_decl_node; + variable_entry->arg_index = i; - VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); - if (!existing_entry) { - // unique definition - context->variable_table.put(&variable_entry->name, variable_entry); - } else { - add_node_error(g, node, - buf_sprintf("redeclaration of parameter '%s'.", buf_ptr(&existing_entry->name))); - if (existing_entry->type == variable_entry->type) { - // types agree, so the type is probably good enough for the rest of analysis - } else { - // types disagree. don't trust either one of them. - existing_entry->type = g->builtin_types.entry_invalid;; - } - } - } + alloc_codegen_node(param_decl_node); + param_decl_node->codegen_node->data.param_decl_node.variable = variable_entry; - TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry; - TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body); + VariableTableEntry *existing_entry = find_local_variable(context, &variable_entry->name); + if (!existing_entry) { + // unique definition + context->variable_table.put(&variable_entry->name, variable_entry); + } else { + add_node_error(g, node, + buf_sprintf("redeclaration of parameter '%s'.", buf_ptr(&existing_entry->name))); + if (existing_entry->type == variable_entry->type) { + // types agree, so the type is probably good enough for the rest of analysis + } else { + // types disagree. don't trust either one of them. + existing_entry->type = g->builtin_types.entry_invalid;; + } + } + } - node->codegen_node->data.fn_def_node.implicit_return_type = block_return_type; + TypeTableEntry *expected_type = fn_proto->return_type->codegen_node->data.type_node.entry; + TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body); - { - FnTableEntry *fn_table_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; - auto it = fn_table_entry->label_table.entry_iterator(); - for (;;) { - auto *entry = it.next(); - if (!entry) - break; + node->codegen_node->data.fn_def_node.implicit_return_type = block_return_type; - LabelTableEntry *label_entry = entry->value; - if (!label_entry->used) { - add_node_error(g, label_entry->label_node, - buf_sprintf("label '%s' defined but not used", - buf_ptr(&label_entry->label_node->data.label.name))); - } - } - } + { + FnTableEntry *fn_table_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry; + auto it = fn_table_entry->label_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + LabelTableEntry *label_entry = entry->value; + if (!label_entry->used) { + add_node_error(g, label_entry->label_node, + buf_sprintf("label '%s' defined but not used", + buf_ptr(&label_entry->label_node->data.label.name))); } - break; + } + } +} +static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, AstNode *node) { + switch (node->type) { + case NodeTypeFnDef: + analyze_top_level_fn_def(g, import, node); + break; case NodeTypeRootExportDecl: case NodeTypeExternBlock: // already looked at these in the preview pass @@ -2048,8 +2098,13 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, break; } case NodeTypeStructDecl: - // nothing to do - break; + { + for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) { + AstNode *fn_def_node = node->data.struct_decl.fns.at(i); + analyze_top_level_fn_def(g, import, fn_def_node); + } + break; + } case NodeTypeVariableDeclaration: { VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context, diff --git a/src/analyze.hpp b/src/analyze.hpp index 85b5a73ba0..e71261eb58 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -45,6 +45,8 @@ struct TypeTableEntryStruct { int field_count; TypeStructField *fields; uint64_t size_bytes; + // reminder: hash tables must be initialized before use + HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; // set this flag temporarily to detect infinite loops bool embedded_in_current; diff --git a/src/codegen.cpp b/src/codegen.cpp index 4fe1373f92..0a784f8071 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -142,15 +142,31 @@ static TypeTableEntry *get_expr_type(AstNode *node) { static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeFnCallExpr); - Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr); + FnTableEntry *fn_table_entry; + AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; + TypeTableEntry *struct_type; + AstNode *first_param_expr; + if (fn_ref_expr->type == NodeTypeFieldAccessExpr) { + Buf *name = &fn_ref_expr->data.field_access_expr.field_name; + first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr; + struct_type = get_expr_type(first_param_expr); + fn_table_entry = struct_type->data.structure.fn_table.get(name); + } else if (fn_ref_expr->type == NodeTypeSymbol) { + Buf *name = hack_get_fn_call_name(g, fn_ref_expr); + struct_type = nullptr; + first_param_expr = nullptr; + fn_table_entry = g->cur_fn->import_entry->fn_table.get(name); + } else { + zig_unreachable(); + } - FnTableEntry *fn_table_entry = g->cur_fn->import_entry->fn_table.get(name); assert(fn_table_entry->proto_node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto_data = &fn_table_entry->proto_node->data.fn_proto; int expected_param_count = fn_proto_data->params.length; - int actual_param_count = node->data.fn_call_expr.params.length; + int fn_call_param_count = node->data.fn_call_expr.params.length; + int actual_param_count = fn_call_param_count + (struct_type ? 1 : 0); bool is_var_args = fn_proto_data->is_var_args; assert((is_var_args && actual_param_count >= expected_param_count) || actual_param_count == expected_param_count); @@ -164,10 +180,13 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { } LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(gen_param_count); - int loop_end = max(gen_param_count, actual_param_count); - int gen_param_index = 0; - for (int i = 0; i < loop_end; i += 1) { + if (struct_type) { + gen_param_values[gen_param_index] = gen_expr(g, first_param_expr); + gen_param_index += 1; + } + + for (int i = 0; i < fn_call_param_count; i += 1) { AstNode *expr_node = node->data.fn_call_expr.params.at(i); LLVMValueRef param_value = gen_expr(g, expr_node); if (is_var_args || diff --git a/src/parser.cpp b/src/parser.cpp index bddd8a4229..1fc4f538d4 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -395,6 +395,14 @@ void ast_print(AstNode *node, int indent) { case NodeTypeStructDecl: fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_decl.name)); + for (int i = 0; i < node->data.struct_decl.fields.length; i += 1) { + AstNode *child = node->data.struct_decl.fields.at(i); + ast_print(child, indent + 2); + } + for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) { + AstNode *child = node->data.struct_decl.fns.at(i); + ast_print(child, indent + 2); + } break; case NodeTypeStructField: fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_field.name)); @@ -2572,7 +2580,8 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index) { } /* -StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructField) token(RBrace) +StructDecl : many(Directive) token(Struct) token(Symbol) token(LBrace) many(StructMember) token(RBrace) +StructMember: StructField | FnDecl StructField : token(Symbol) token(Colon) Type token(Comma) */ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) { @@ -2590,16 +2599,38 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) { ast_eat_token(pc, token_index, TokenIdLBrace); + node->data.struct_decl.directives = pc->directive_list; + pc->directive_list = nullptr; + for (;;) { + assert(!pc->directive_list); + pc->directive_list = allocate<ZigList<AstNode*>>(1); + Token *directive_token = &pc->tokens->at(*token_index); + ast_parse_directives(pc, token_index, pc->directive_list); + + AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false); + if (fn_def_node) { + node->data.struct_decl.fns.append(fn_def_node); + continue; + } + Token *token = &pc->tokens->at(*token_index); if (token->id == TokenIdRBrace) { + if (pc->directive_list->length > 0) { + ast_error(pc, directive_token, "invalid directive"); + } + pc->directive_list = nullptr; + *token_index += 1; break; } else if (token->id == TokenIdSymbol) { AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token); *token_index += 1; + field_node->data.struct_field.directives = pc->directive_list; + pc->directive_list = nullptr; + ast_buf_from_token(pc, token, &field_node->data.struct_field.name); ast_eat_token(pc, token_index, TokenIdColon); @@ -2615,9 +2646,6 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) { } - node->data.struct_decl.directives = pc->directive_list; - pc->directive_list = nullptr; - return node; } diff --git a/src/parser.hpp b/src/parser.hpp index 407acac6a6..f889a1ff27 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -281,12 +281,14 @@ struct AstNodeAsmExpr { struct AstNodeStructDecl { Buf name; ZigList<AstNode *> fields; + ZigList<AstNode *> fns; ZigList<AstNode *> *directives; }; struct AstNodeStructField { Buf name; AstNode *type; + ZigList<AstNode *> *directives; }; struct AstNodeStringLiteral { |
