diff options
Diffstat (limited to 'gcc/go/gofrontend/parse.cc')
-rw-r--r-- | gcc/go/gofrontend/parse.cc | 99 |
1 files changed, 76 insertions, 23 deletions
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 1664fe3..fd81a85 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -1315,12 +1315,36 @@ Parse::declaration() go_warning_at(token->location(), 0, "ignoring magic comment before non-function"); + std::vector<std::string>* embeds = NULL; + if (this->lex_->has_embeds()) + { + embeds = new(std::vector<std::string>); + this->lex_->get_and_clear_embeds(embeds); + + if (!this->gogo_->is_embed_imported()) + { + go_error_at(token->location(), + "invalid go:embed: missing import %<embed%>"); + delete embeds; + embeds = NULL; + } + if (!token->is_keyword(KEYWORD_VAR)) + { + go_error_at(token->location(), "misplaced go:embed directive"); + if (embeds != NULL) + { + delete embeds; + embeds = NULL; + } + } + } + if (token->is_keyword(KEYWORD_CONST)) this->const_decl(); else if (token->is_keyword(KEYWORD_TYPE)) this->type_decl(pragmas); else if (token->is_keyword(KEYWORD_VAR)) - this->var_decl(); + this->var_decl(embeds); else if (token->is_keyword(KEYWORD_FUNC)) this->function_decl(pragmas); else @@ -1343,8 +1367,8 @@ Parse::declaration_may_start_here() // Decl<P> = P | "(" [ List<P> ] ")" . void -Parse::decl(void (Parse::*pfn)(void*, unsigned int), void* varg, - unsigned int pragmas) +Parse::decl(void (Parse::*pfn)(unsigned int, std::vector<std::string>*), + unsigned int pragmas, std::vector<std::string>* embeds) { if (this->peek_token()->is_eof()) { @@ -1354,15 +1378,18 @@ Parse::decl(void (Parse::*pfn)(void*, unsigned int), void* varg, } if (!this->peek_token()->is_op(OPERATOR_LPAREN)) - (this->*pfn)(varg, pragmas); + (this->*pfn)(pragmas, embeds); else { if (pragmas != 0) go_warning_at(this->location(), 0, "ignoring magic %<//go:...%> comment before group"); + if (embeds != NULL) + go_error_at(this->location(), + "ignoring %<//go:embed%> comment before group"); if (!this->advance_token()->is_op(OPERATOR_RPAREN)) { - this->list(pfn, varg, true); + this->list(pfn, true); if (!this->peek_token()->is_op(OPERATOR_RPAREN)) { go_error_at(this->location(), "missing %<)%>"); @@ -1383,10 +1410,10 @@ Parse::decl(void (Parse::*pfn)(void*, unsigned int), void* varg, // might follow. This is either a '}' or a ')'. void -Parse::list(void (Parse::*pfn)(void*, unsigned int), void* varg, +Parse::list(void (Parse::*pfn)(unsigned int, std::vector<std::string>*), bool follow_is_paren) { - (this->*pfn)(varg, 0); + (this->*pfn)(0, NULL); Operator follow = follow_is_paren ? OPERATOR_RPAREN : OPERATOR_RCURLY; while (this->peek_token()->is_op(OPERATOR_SEMICOLON) || this->peek_token()->is_op(OPERATOR_COMMA)) @@ -1395,7 +1422,7 @@ Parse::list(void (Parse::*pfn)(void*, unsigned int), void* varg, go_error_at(this->location(), "unexpected comma"); if (this->advance_token()->is_op(follow)) break; - (this->*pfn)(varg, 0); + (this->*pfn)(0, NULL); } } @@ -1522,13 +1549,13 @@ Parse::type_decl(unsigned int pragmas) { go_assert(this->peek_token()->is_keyword(KEYWORD_TYPE)); this->advance_token(); - this->decl(&Parse::type_spec, NULL, pragmas); + this->decl(&Parse::type_spec, pragmas, NULL); } // TypeSpec = identifier ["="] Type . void -Parse::type_spec(void*, unsigned int pragmas) +Parse::type_spec(unsigned int pragmas, std::vector<std::string>*) { const Token* token = this->peek_token(); if (!token->is_identifier()) @@ -1622,27 +1649,42 @@ Parse::type_spec(void*, unsigned int pragmas) // VarDecl = "var" Decl<VarSpec> . void -Parse::var_decl() +Parse::var_decl(std::vector<std::string>* embeds) { go_assert(this->peek_token()->is_keyword(KEYWORD_VAR)); this->advance_token(); - this->decl(&Parse::var_spec, NULL, 0); + this->decl(&Parse::var_spec, 0, embeds); } // VarSpec = IdentifierList // ( CompleteType [ "=" ExpressionList ] | "=" ExpressionList ) . void -Parse::var_spec(void*, unsigned int pragmas) +Parse::var_spec(unsigned int pragmas, std::vector<std::string>* embeds) { + Location loc = this->location(); + if (pragmas != 0) - go_warning_at(this->location(), 0, - "ignoring magic %<//go:...%> comment before var"); + go_warning_at(loc, 0, "ignoring magic %<//go:...%> comment before var"); // Get the variable names. Typed_identifier_list til; this->identifier_list(&til); + if (embeds != NULL) + { + if (!this->gogo_->in_global_scope()) + { + go_error_at(loc, "go:embed only permitted at package scope"); + embeds = NULL; + } + if (til.size() > 1) + { + go_error_at(loc, "go:embed cannot apply to multiple vars"); + embeds = NULL; + } + } + Location location = this->location(); Type* type = NULL; @@ -1670,7 +1712,13 @@ Parse::var_spec(void*, unsigned int pragmas) init = this->expression_list(NULL, false, true); } - this->init_vars(&til, type, init, false, location); + if (embeds != NULL && init != NULL) + { + go_error_at(loc, "go:embed cannot apply to var with initializer"); + embeds = NULL; + } + + this->init_vars(&til, type, init, false, embeds, location); if (init != NULL) delete init; @@ -1683,11 +1731,12 @@ Parse::var_spec(void*, unsigned int pragmas) void Parse::init_vars(const Typed_identifier_list* til, Type* type, Expression_list* init, bool is_coloneq, - Location location) + std::vector<std::string>* embeds, Location location) { // Check for an initialization which can yield multiple values. if (init != NULL && init->size() == 1 && til->size() > 1) { + go_assert(embeds == NULL); if (this->init_vars_from_call(til, type, *init->begin(), is_coloneq, location)) return; @@ -1729,8 +1778,12 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type, { if (init != NULL) go_assert(pexpr != init->end()); - this->init_var(*p, type, init == NULL ? NULL : *pexpr, is_coloneq, - false, &any_new, vars, vals); + Named_object* no = this->init_var(*p, type, + init == NULL ? NULL : *pexpr, + is_coloneq, false, &any_new, + vars, vals); + if (embeds != NULL && no->is_variable()) + no->var_value()->set_embeds(embeds); if (init != NULL) ++pexpr; } @@ -2270,7 +2323,7 @@ Parse::simple_var_decl_or_assignment(const std::string& name, } } - this->init_vars(&til, NULL, init, true, location); + this->init_vars(&til, NULL, init, true, NULL, location); } // FunctionDecl = "func" identifier Signature [ Block ] . @@ -5317,7 +5370,7 @@ Parse::for_stat(Label* label) { go_error_at(this->location(), "var declaration not allowed in for initializer"); - this->var_decl(); + this->var_decl(NULL); } if (token->is_op(OPERATOR_SEMICOLON)) @@ -5762,13 +5815,13 @@ Parse::import_decl() { go_assert(this->peek_token()->is_keyword(KEYWORD_IMPORT)); this->advance_token(); - this->decl(&Parse::import_spec, NULL, 0); + this->decl(&Parse::import_spec, 0, NULL); } // ImportSpec = [ "." | PackageName ] PackageFileName . void -Parse::import_spec(void*, unsigned int pragmas) +Parse::import_spec(unsigned int pragmas, std::vector<std::string>*) { if (pragmas != 0) go_warning_at(this->location(), 0, |