diff options
Diffstat (limited to 'src/cmd/gc/go.y')
-rw-r--r-- | src/cmd/gc/go.y | 448 |
1 files changed, 276 insertions, 172 deletions
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 4c7fe6068..f95058721 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -18,7 +18,9 @@ */ %{ +#include <u.h> #include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */ +#include <libc.h> #include "go.h" static void fixlbrace(int); @@ -29,13 +31,13 @@ static void fixlbrace(int); Type* type; Sym* sym; struct Val val; - int lint; + int i; } // |sed 's/.* //' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx /' %token <val> LLITERAL -%token <lint> LASOP +%token <i> LASOP %token <sym> LBREAK LCASE LCHAN LCOLAS LCONST LCONTINUE LDDD %token <sym> LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO %token <sym> LIF LIMPORT LINTERFACE LMAP LNAME @@ -45,7 +47,7 @@ static void fixlbrace(int); %token LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT %token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH -%type <lint> lbrace import_here +%type <i> lbrace import_here %type <sym> sym packname %type <val> oliteral @@ -54,8 +56,8 @@ static void fixlbrace(int); %type <node> case caseblock %type <node> compound_stmt dotname embed expr complitexpr %type <node> expr_or_type -%type <node> fndcl fnliteral -%type <node> for_body for_header for_stmt if_header if_stmt non_dcl_stmt +%type <node> fndcl hidden_fndcl fnliteral +%type <node> for_body for_header for_stmt if_header if_stmt else non_dcl_stmt %type <node> interfacedcl keyval labelname name %type <node> name_or_type non_expr_type %type <node> new_name dcl_name oexpr typedclname @@ -64,7 +66,7 @@ static void fixlbrace(int); %type <node> pseudocall range_stmt select_stmt %type <node> simple_stmt %type <node> switch_stmt uexpr -%type <node> xfndcl typedcl +%type <node> xfndcl typedcl start_complit %type <list> xdcl fnbody fnres loop_body dcl_name_list %type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list @@ -76,12 +78,10 @@ static void fixlbrace(int); %type <node> indcl interfacetype structtype ptrtype %type <node> recvchantype non_recvchantype othertype fnret_type fntype -%type <val> hidden_tag - %type <sym> hidden_importsym hidden_pkg_importsym -%type <node> hidden_constant hidden_literal hidden_dcl -%type <node> hidden_interfacedcl hidden_structdcl hidden_opt_sym +%type <node> hidden_constant hidden_literal hidden_funarg +%type <node> hidden_interfacedcl hidden_structdcl %type <list> hidden_funres %type <list> ohidden_funres @@ -205,7 +205,15 @@ import_stmt: my->lastlineno = $1; my->block = 1; // at top level } - +| import_here import_there + { + // When an invalid import path is passed to importfile, + // it calls yyerror and then sets up a fake import with + // no package statement. This allows us to test more + // than one invalid import statement in a single file. + if(nerrors == 0) + fatal("phase error in import"); + } import_stmt_list: import_stmt @@ -235,17 +243,17 @@ import_here: } import_package: - LPACKAGE sym import_safety ';' + LPACKAGE LNAME import_safety ';' { if(importpkg->name == nil) { importpkg->name = $2->name; pkglookup($2->name, nil)->npkg++; } else if(strcmp(importpkg->name, $2->name) != 0) - yyerror("conflicting names %s and %s for package %Z", importpkg->name, $2->name, importpkg->path); + yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, $2->name, importpkg->path); importpkg->direct = 1; if(safemode && !curio.importsafe) - yyerror("cannot import unsafe package %Z", importpkg->path); + yyerror("cannot import unsafe package \"%Z\"", importpkg->path); } import_safety: @@ -418,18 +426,15 @@ simple_stmt: | expr_list LCOLAS expr_list { if($3->n->op == OTYPESW) { - Node *n; - - n = N; + $$ = nod(OTYPESW, N, $3->n->right); if($3->next != nil) yyerror("expr.(type) must be alone in list"); if($1->next != nil) yyerror("argument count mismatch: %d = %d", count($1), 1); - else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME) - yyerror("invalid variable name %#N in type switch", $1->n); + else if(($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME) || isblank($1->n)) + yyerror("invalid variable name %N in type switch", $1->n); else - n = $1->n; - $$ = nod(OTYPESW, n, $3->n->right); + $$->left = dclname($1->n->sym); // it's a colas, so must not re-use an oldname. break; } $$ = colas($1, $3); @@ -448,7 +453,7 @@ simple_stmt: case: LCASE expr_or_type_list ':' { - Node *n; + Node *n, *nn; // will be converted to OCASE // right will point to next case @@ -458,12 +463,13 @@ case: $$->list = $2; if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { // type switch - declare variable - n = newname(n->sym); - n->used = 1; // TODO(rsc): better job here - declare(n, dclcontext); - $$->nname = n; + nn = newname(n->sym); + declare(nn, dclcontext); + $$->nname = nn; + + // keep track of the instances for reporting unused + nn->defn = typesw->right; } - break; } | LCASE expr_or_type_list '=' expr ':' { @@ -494,16 +500,18 @@ case: } | LDEFAULT ':' { - Node *n; + Node *n, *nn; markdcl(); $$ = nod(OXCASE, N, N); if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { // type switch - declare variable - n = newname(n->sym); - n->used = 1; // TODO(rsc): better job here - declare(n, dclcontext); - $$->nname = n; + nn = newname(n->sym); + declare(nn, dclcontext); + $$->nname = nn; + + // keep track of the instances for reporting unused + nn->defn = typesw->right; } } @@ -638,6 +646,7 @@ if_header: $$->ntest = $3; } +/* IF cond body (ELSE IF cond body)* (ELSE block)? */ if_stmt: LIF { @@ -650,9 +659,27 @@ if_stmt: } loop_body { + $3->nbody = $5; + } + else + { + popdcl(); $$ = $3; - $$->nbody = $5; - // no popdcl; maybe there's an LELSE + if($7 != N) + $$->nelse = list1($7); + } + +else: + { + $$ = N; + } +| LELSE if_stmt + { + $$ = $2; + } +| LELSE compound_stmt + { + $$ = $2; } switch_stmt: @@ -785,7 +812,14 @@ uexpr: } | '&' uexpr { - $$ = nod(OADDR, $2, N); + if($2->op == OCOMPLIT) { + // Special case for &T{...}: turn into (*T){...}. + $$ = $2; + $$->right = nod(OIND, $$->right, N); + $$->right->implicit = 1; + } else { + $$ = nod(OADDR, $2, N); + } } | '+' uexpr { @@ -874,29 +908,35 @@ pexpr_no_paren: $$ = nod(OCALL, $1, N); $$->list = list1($3); } -| comptype lbrace braced_keyval_list '}' +| comptype lbrace start_complit braced_keyval_list '}' { - // composite expression - $$ = nod(OCOMPLIT, N, $1); - $$->list = $3; - + $$ = $3; + $$->right = $1; + $$->list = $4; fixlbrace($2); } -| pexpr_no_paren '{' braced_keyval_list '}' +| pexpr_no_paren '{' start_complit braced_keyval_list '}' { - // composite expression - $$ = nod(OCOMPLIT, N, $1); - $$->list = $3; + $$ = $3; + $$->right = $1; + $$->list = $4; } -| '(' expr_or_type ')' '{' braced_keyval_list '}' +| '(' expr_or_type ')' '{' start_complit braced_keyval_list '}' { yyerror("cannot parenthesize type in composite literal"); - // composite expression - $$ = nod(OCOMPLIT, N, $2); - $$->list = $5; + $$ = $5; + $$->right = $2; + $$->list = $6; } | fnliteral +start_complit: + { + // composite expression. + // make node early so we get the right line number. + $$ = nod(OCOMPLIT, N, N); + } + keyval: expr ':' complitexpr { @@ -905,10 +945,10 @@ keyval: complitexpr: expr -| '{' braced_keyval_list '}' +| '{' start_complit braced_keyval_list '}' { - $$ = nod(OCOMPLIT, N, N); - $$->list = $2; + $$ = $2; + $$->list = $3; } pexpr: @@ -955,7 +995,10 @@ lbrace: new_name: sym { - $$ = newname($1); + if($1 == S) + $$ = N; + else + $$ = newname($1); } dcl_name: @@ -972,6 +1015,26 @@ onew_name: sym: LNAME + { + $$ = $1; + // during imports, unqualified non-exported identifiers are from builtinpkg + if(importpkg != nil && !exportname($1->name)) + $$ = pkglookup($1->name, builtinpkg); + } +| hidden_importsym +| '?' + { + $$ = S; + } + +hidden_importsym: + '@' LLITERAL '.' LNAME + { + if($2.u.sval->len == 0) + $$ = pkglookup($4->name, importpkg); + else + $$ = pkglookup($4->name, mkpkg($2.u.sval)); + } name: sym %prec NotParen @@ -1144,38 +1207,43 @@ xfndcl: } fndcl: - dcl_name '(' oarg_type_list_ocomma ')' fnres + sym '(' oarg_type_list_ocomma ')' fnres { - Node *n; + Node *t; + $$ = N; $3 = checkarglist($3, 1); - $$ = nod(ODCLFUNC, N, N); - $$->nname = $1; - n = nod(OTFUNC, N, N); - n->list = $3; - n->rlist = $5; - if(strcmp($1->sym->name, "init") == 0) { - $$->nname = renameinit($1); + + if(strcmp($1->name, "init") == 0) { + $1 = renameinit(); if($3 != nil || $5 != nil) yyerror("func init must have no arguments and no return values"); } - if(strcmp(localpkg->name, "main") == 0 && strcmp($1->sym->name, "main") == 0) { + if(strcmp(localpkg->name, "main") == 0 && strcmp($1->name, "main") == 0) { if($3 != nil || $5 != nil) yyerror("func main must have no arguments and no return values"); } - // TODO: check if nname already has an ntype - $$->nname->ntype = n; + + t = nod(OTFUNC, N, N); + t->list = $3; + t->rlist = $5; + + $$ = nod(ODCLFUNC, N, N); + $$->nname = newname($1); + $$->nname->defn = $$; + $$->nname->ntype = t; // TODO: check if nname already has an ntype + declare($$->nname, PFUNC); + funchdr($$); } | '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres { Node *rcvr, *t; - Node *name; - - name = newname($4); + + $$ = N; $2 = checkarglist($2, 0); $6 = checkarglist($6, 1); - $$ = N; + if($2 == nil) { yyerror("method has no receiver"); break; @@ -1192,16 +1260,60 @@ fndcl: if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN)) yyerror("cannot parenthesize receiver type"); - $$ = nod(ODCLFUNC, N, N); - $$->nname = methodname1(name, rcvr->right); t = nod(OTFUNC, rcvr, N); t->list = $6; t->rlist = $8; + + $$ = nod(ODCLFUNC, N, N); + $$->shortname = newname($4); + $$->nname = methodname1($$->shortname, rcvr->right); + $$->nname->defn = $$; $$->nname->ntype = t; - $$->shortname = name; + declare($$->nname, PFUNC); + funchdr($$); } +hidden_fndcl: + hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres + { + Sym *s; + Type *t; + + $$ = N; + + s = $1; + t = functype(N, $3, $5); + + importsym(s, ONAME); + if(s->def != N && s->def->op == ONAME) { + if(eqtype(t, s->def->type)) + break; + yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t); + } + + $$ = newname(s); + $$->type = t; + declare($$, PFUNC); + + funchdr($$); + } +| '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres + { + $$ = methodname1(newname($4), $2->n->right); + $$->type = functype($2->n, $6, $8); + + checkwidth($$->type); + addmethod($4, $$->type, 0); + funchdr($$); + + // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as + // (dotmeth's type)->nname->inl, and dotmeth's type has been pulled + // out by typecheck's lookdot as this $$->ttype. So by providing + // this back link here we avoid special casing there. + $$->type->nname = $$; + } + fntype: LFUNC '(' oarg_type_list_ocomma ')' fnres { @@ -1317,6 +1429,20 @@ structdcl: { NodeList *l; + Node *n; + l = $1; + if(l != nil && l->next == nil && l->n == nil) { + // ? symbol, during import + n = $2; + if(n->op == OIND) + n = n->left; + n = embedded(n->sym); + n->right = $2; + n->val = $3; + $$ = list1(n); + break; + } + for(l=$1; l; l=l->next) { l->n = nod(ODCLFIELD, l->n, $2); l->n->val = $3; @@ -1472,19 +1598,6 @@ non_dcl_stmt: | switch_stmt | select_stmt | if_stmt - { - popdcl(); - $$ = $1; - } -| if_stmt LELSE stmt - { - if($3->op != OIF && $3->op != OBLOCK) - yyerror("missing { } after else"); - - popdcl(); - $$ = $1; - $$->nelse = list1($3); - } | labelname ':' { $1 = nod(OLABEL, $1, N); @@ -1494,7 +1607,7 @@ non_dcl_stmt: { NodeList *l; - $1->right = $4; + $1->defn = $4; l = list1($1); if($4) l = list(l, $4); @@ -1530,6 +1643,18 @@ non_dcl_stmt: { $$ = nod(ORETURN, N, N); $$->list = $2; + if($$->list == nil && curfn != N) { + NodeList *l; + + for(l=curfn->dcl; l; l=l->next) { + if(l->n->class == PPARAM) + continue; + if(l->n->class != PPARAMOUT) + break; + if(l->n->sym->def != l->n) + yyerror("%s is shadowed during return", l->n->sym->name); + } + } } stmt_list: @@ -1668,27 +1793,16 @@ oliteral: | LLITERAL /* - * import syntax from header of - * an output package + * import syntax from package header */ hidden_import: - LIMPORT sym LLITERAL ';' + LIMPORT LNAME LLITERAL ';' { - // Informational: record package name - // associated with import path, for use in - // human-readable messages. - Pkg *p; - - p = mkpkg($3.u.sval); - if(p->name == nil) { - p->name = $2->name; - pkglookup($2->name, nil)->npkg++; - } else if(strcmp(p->name, $2->name) != 0) - yyerror("conflicting names %s and %s for package %Z", p->name, $2->name, p->path); + importimport($2, $3.u.sval); } | LVAR hidden_pkg_importsym hidden_type ';' { - importvar($2, $3, PEXTERN); + importvar($2, $3); } | LCONST hidden_pkg_importsym '=' hidden_constant ';' { @@ -1702,17 +1816,28 @@ hidden_import: { importtype($2, $3); } -| LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres ';' +| LFUNC hidden_fndcl fnbody ';' { - importvar($2, functype(N, $4, $6), PFUNC); + if($2 == N) + break; + + $2->inl = $3; + + funcbody($2); + importlist = list(importlist, $2); + + if(debug['E']) { + print("import [%Z] func %lN \n", importpkg->path, $2); + if(debug['l'] > 2 && $2->inl) + print("inl body:%+H\n", $2->inl); + } } -| LFUNC '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres ';' + +hidden_pkg_importsym: + hidden_importsym { - if($3->next != nil || $3->n->op != ODCLFIELD) { - yyerror("bad receiver in method"); - YYERROR; - } - importmethod($5, functype($3->n, $7, $9)); + $$ = $1; + structpkg = $$->pkg; } hidden_pkgtype: @@ -1722,6 +1847,10 @@ hidden_pkgtype: importsym($1, OTYPE); } +/* + * importing types + */ + hidden_type: hidden_type_misc | hidden_type_recv_chan @@ -1760,11 +1889,11 @@ hidden_type_misc: } | LSTRUCT '{' ohidden_structdcl_list '}' { - $$ = dostruct($3, TSTRUCT); + $$ = tostruct($3); } | LINTERFACE '{' ohidden_interfacedcl_list '}' { - $$ = dostruct($3, TINTER); + $$ = tointerface($3); } | '*' hidden_type { @@ -1803,61 +1932,45 @@ hidden_type_func: $$ = functype(nil, $3, $5); } -hidden_opt_sym: - sym - { - $$ = newname($1); - } -| '?' - { - $$ = N; - } - -hidden_dcl: - hidden_opt_sym hidden_type hidden_tag +hidden_funarg: + sym hidden_type oliteral { - $$ = nod(ODCLFIELD, $1, typenod($2)); + $$ = nod(ODCLFIELD, N, typenod($2)); + if($1) + $$->left = newname($1); $$->val = $3; } -| hidden_opt_sym LDDD hidden_type hidden_tag +| sym LDDD hidden_type oliteral { Type *t; - + t = typ(TARRAY); t->bound = -1; t->type = $3; - $$ = nod(ODCLFIELD, $1, typenod(t)); + + $$ = nod(ODCLFIELD, N, typenod(t)); + if($1) + $$->left = newname($1); $$->isddd = 1; $$->val = $4; } hidden_structdcl: - sym hidden_type hidden_tag - { - $$ = nod(ODCLFIELD, newname($1), typenod($2)); - $$->val = $3; - } -| '?' hidden_type hidden_tag + sym hidden_type oliteral { Sym *s; - s = $2->sym; - if(s == S && isptr[$2->etype]) - s = $2->type->sym; - if(s && s->pkg == builtinpkg) - s = lookup(s->name); - $$ = embedded(s); - $$->right = typenod($2); - $$->val = $3; - } - -hidden_tag: - { - $$.ctype = CTxxx; - } -| ':' LLITERAL // extra colon avoids conflict with "" looking like beginning of "".typename - { - $$ = $2; + if($1 != S) { + $$ = nod(ODCLFIELD, newname($1), typenod($2)); + $$->val = $3; + } else { + s = $2->sym; + if(s == S && isptr[$2->etype]) + s = $2->type->sym; + $$ = embedded(s); + $$->right = typenod($2); + $$->val = $3; + } } hidden_interfacedcl: @@ -1865,9 +1978,9 @@ hidden_interfacedcl: { $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5))); } -| hidden_importsym '(' ohidden_funarg_list ')' ohidden_funres +| hidden_type { - $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5))); + $$ = nod(ODCLFIELD, N, typenod($1)); } ohidden_funres: @@ -1886,6 +1999,10 @@ hidden_funres: $$ = list1(nod(ODCLFIELD, N, typenod($1))); } +/* + * importing constants + */ + hidden_literal: LLITERAL { @@ -1896,6 +2013,7 @@ hidden_literal: $$ = nodlit($2); switch($$->val.ctype){ case CTINT: + case CTRUNE: mpnegfix($$->val.u.xval); break; case CTFLT: @@ -1916,37 +2034,23 @@ hidden_constant: hidden_literal | '(' hidden_literal '+' hidden_literal ')' { + if($2->val.ctype == CTRUNE && $4->val.ctype == CTINT) { + $$ = $2; + mpaddfixfix($2->val.u.xval, $4->val.u.xval, 0); + break; + } $$ = nodcplxlit($2->val, $4->val); } -hidden_importsym: - LLITERAL '.' sym - { - Pkg *p; - - if($1.u.sval->len == 0) - p = importpkg; - else - p = mkpkg($1.u.sval); - $$ = pkglookup($3->name, p); - } - -hidden_pkg_importsym: - hidden_importsym - { - $$ = $1; - structpkg = $$->pkg; - } - hidden_import_list: | hidden_import_list hidden_import hidden_funarg_list: - hidden_dcl + hidden_funarg { $$ = list1($1); } -| hidden_funarg_list ',' hidden_dcl +| hidden_funarg_list ',' hidden_funarg { $$ = list($1, $3); } |