From: Matthew Dempsky Date: Tue, 25 Oct 2016 18:50:13 +0000 (-0700) Subject: cmd/compile: remove old lexer and parser X-Git-Tag: go1.8beta1~617 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=57df2f802f0417f08100ff8002f3b062e695e148;p=gostls13.git cmd/compile: remove old lexer and parser Change-Id: I7306d28930dc4538a3bee31ff5d22f3f40681ec5 Reviewed-on: https://go-review.googlesource.com/32020 Run-TryBot: Matthew Dempsky Reviewed-by: Robert Griesemer TryBot-Result: Gobot Gobot --- diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index d95e8dbd44..b16c9433ee 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -487,23 +487,6 @@ func colasdefn(left []*Node, defn *Node) { } } -func colas(left, right []*Node, lno int32) *Node { - n := nod(OAS, nil, nil) // assume common case - n.Colas = true - n.Lineno = lno // set before calling colasdefn for correct error line - colasdefn(left, n) // modifies left, call before using left[0] in common case - if len(left) == 1 && len(right) == 1 { - // common case - n.Left = left[0] - n.Right = right[0] - } else { - n.Op = OAS2 - n.List.Set(left) - n.Rlist.Set(right) - } - return n -} - // declare the arguments in an // interface field declaration. func ifacedcl(n *Node) { diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index df9790955f..87f9bf27cc 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -5,21 +5,10 @@ package gc import ( - "bufio" - "bytes" "cmd/compile/internal/syntax" "cmd/internal/obj" "fmt" - "io" - "strconv" "strings" - "unicode" - "unicode/utf8" -) - -const ( - EOF = -1 - BOM = 0xFEFF ) // lexlineno is the line number _after_ the most recently read rune. @@ -29,22 +18,10 @@ var lexlineno int32 // lineno is the line number at the start of the most recently lexed token. var lineno int32 -var lexbuf bytes.Buffer -var strbuf bytes.Buffer -var litbuf string // LLITERAL value for use in syntax error messages - func isSpace(c rune) bool { return c == ' ' || c == '\t' || c == '\n' || c == '\r' } -func isLetter(c rune) bool { - return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' -} - -func isDigit(c rune) bool { - return '0' <= c && c <= '9' -} - func isQuoted(s string) bool { return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' } @@ -139,764 +116,6 @@ func pragmaValue(verb string) Pragma { return 0 } -type lexer struct { - // source - bin *bufio.Reader - prevlineno int32 // line no. of most recently read character - - nlsemi bool // if set, '\n' and EOF translate to ';' - - // pragma flags - // accumulated by lexer; reset by parser - pragma Pragma - - // current token - tok int32 - sym_ *Sym // valid if tok == LNAME - val Val // valid if tok == LLITERAL - op Op // valid if tok == LOPER, LASOP, or LINCOP, or prec > 0 - prec OpPrec // operator precedence; 0 if not a binary operator -} - -type OpPrec int - -const ( - // Precedences of binary operators (must be > 0). - PCOMM OpPrec = 1 + iota - POROR - PANDAND - PCMP - PADD - PMUL -) - -const ( - // The value of single-char tokens is just their character's Unicode value. - // They are all below utf8.RuneSelf. Shift other tokens up to avoid conflicts. - - // names and literals - LNAME = utf8.RuneSelf + iota - LLITERAL - - // operator-based operations - LOPER - LASOP - LINCOP - - // miscellaneous - LCOLAS - LCOMM - LDDD - - // keywords - LBREAK - LCASE - LCHAN - LCONST - LCONTINUE - LDEFAULT - LDEFER - LELSE - LFALL - LFOR - LFUNC - LGO - LGOTO - LIF - LIMPORT - LINTERFACE - LMAP - LPACKAGE - LRANGE - LRETURN - LSELECT - LSTRUCT - LSWITCH - LTYPE - LVAR - - LIGNORE -) - -var lexn = map[rune]string{ - LNAME: "NAME", - LLITERAL: "LITERAL", - - LOPER: "OPER", - LASOP: "ASOP", - LINCOP: "INCOP", - - LCOLAS: "COLAS", - LCOMM: "COMM", - LDDD: "DDD", - - LBREAK: "BREAK", - LCASE: "CASE", - LCHAN: "CHAN", - LCONST: "CONST", - LCONTINUE: "CONTINUE", - LDEFAULT: "DEFAULT", - LDEFER: "DEFER", - LELSE: "ELSE", - LFALL: "FALL", - LFOR: "FOR", - LFUNC: "FUNC", - LGO: "GO", - LGOTO: "GOTO", - LIF: "IF", - LIMPORT: "IMPORT", - LINTERFACE: "INTERFACE", - LMAP: "MAP", - LPACKAGE: "PACKAGE", - LRANGE: "RANGE", - LRETURN: "RETURN", - LSELECT: "SELECT", - LSTRUCT: "STRUCT", - LSWITCH: "SWITCH", - LTYPE: "TYPE", - LVAR: "VAR", - - // LIGNORE is never escaping lexer.next -} - -func lexname(lex rune) string { - if s, ok := lexn[lex]; ok { - return s - } - return fmt.Sprintf("LEX-%d", lex) -} - -func (l *lexer) next() { - nlsemi := l.nlsemi - l.nlsemi = false - l.prec = 0 - -l0: - // skip white space - c := l.getr() - for isSpace(c) { - if c == '\n' && nlsemi { - if Debug['x'] != 0 { - fmt.Printf("lex: implicit semi\n") - } - // Insert implicit semicolon on previous line, - // before the newline character. - lineno = lexlineno - 1 - l.tok = ';' - return - } - c = l.getr() - } - - // start of token - lineno = lexlineno - - // identifiers and keywords - // (for better error messages consume all chars >= utf8.RuneSelf for identifiers) - if isLetter(c) || c >= utf8.RuneSelf { - l.ident(c) - if l.tok == LIGNORE { - goto l0 - } - return - } - // c < utf8.RuneSelf - - var c1 rune - var op Op - var prec OpPrec - - switch c { - case EOF: - l.ungetr() - // Treat EOF as "end of line" for the purposes - // of inserting a semicolon. - if nlsemi { - if Debug['x'] != 0 { - fmt.Printf("lex: implicit semi\n") - } - l.tok = ';' - return - } - l.tok = -1 - return - - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - l.number(c) - return - - case '.': - c1 = l.getr() - if isDigit(c1) { - l.ungetr() - l.number('.') - return - } - - if c1 == '.' { - p, err := l.bin.Peek(1) - if err == nil && p[0] == '.' { - l.getr() - c = LDDD - goto lx - } - - l.ungetr() - c1 = '.' - } - - case '"': - l.stdString() - return - - case '`': - l.rawString() - return - - case '\'': - l.rune() - return - - case '/': - c1 = l.getr() - if c1 == '*' { - c = l.getr() - for { - if c == '*' { - c = l.getr() - if c == '/' { - break - } - continue - } - if c == EOF { - yyerror("eof in comment") - errorexit() - } - c = l.getr() - } - - // A comment containing newlines acts like a newline. - if lexlineno > lineno && nlsemi { - if Debug['x'] != 0 { - fmt.Printf("lex: implicit semi\n") - } - l.tok = ';' - return - } - goto l0 - } - - if c1 == '/' { - c = l.getlinepragma() - for { - if c == '\n' || c == EOF { - l.ungetr() - goto l0 - } - - c = l.getr() - } - } - - op = ODIV - prec = PMUL - goto binop1 - - case ':': - c1 = l.getr() - if c1 == '=' { - c = LCOLAS - goto lx - } - - case '*': - op = OMUL - prec = PMUL - goto binop - - case '%': - op = OMOD - prec = PMUL - goto binop - - case '+': - op = OADD - goto incop - - case '-': - op = OSUB - goto incop - - case '>': - c = LOPER - c1 = l.getr() - if c1 == '>' { - op = ORSH - prec = PMUL - goto binop - } - - l.prec = PCMP - if c1 == '=' { - l.op = OGE - goto lx - } - l.op = OGT - - case '<': - c = LOPER - c1 = l.getr() - if c1 == '<' { - op = OLSH - prec = PMUL - goto binop - } - - if c1 == '-' { - c = LCOMM - // Not a binary operator, but parsed as one - // so we can give a good error message when used - // in an expression context. - l.prec = PCOMM - l.op = OSEND - goto lx - } - - l.prec = PCMP - if c1 == '=' { - l.op = OLE - goto lx - } - l.op = OLT - - case '=': - c1 = l.getr() - if c1 == '=' { - c = LOPER - l.prec = PCMP - l.op = OEQ - goto lx - } - - case '!': - c1 = l.getr() - if c1 == '=' { - c = LOPER - l.prec = PCMP - l.op = ONE - goto lx - } - - case '&': - c1 = l.getr() - if c1 == '&' { - c = LOPER - l.prec = PANDAND - l.op = OANDAND - goto lx - } - - if c1 == '^' { - c = LOPER - op = OANDNOT - prec = PMUL - goto binop - } - - op = OAND - prec = PMUL - goto binop1 - - case '|': - c1 = l.getr() - if c1 == '|' { - c = LOPER - l.prec = POROR - l.op = OOROR - goto lx - } - - op = OOR - prec = PADD - goto binop1 - - case '^': - op = OXOR - prec = PADD - goto binop - - case '(', '[', '{', ',', ';': - goto lx - - case ')', ']', '}': - l.nlsemi = true - goto lx - - default: - // anything else is illegal - yyerror("syntax error: illegal character %#U", c) - goto l0 - } - - l.ungetr() - -lx: - if Debug['x'] != 0 { - if c >= utf8.RuneSelf { - fmt.Printf("%v lex: TOKEN %s\n", linestr(lineno), lexname(c)) - } else { - fmt.Printf("%v lex: TOKEN '%c'\n", linestr(lineno), c) - } - } - - l.tok = c - return - -incop: - c1 = l.getr() - if c1 == c { - l.nlsemi = true - l.op = op - c = LINCOP - goto lx - } - prec = PADD - goto binop1 - -binop: - c1 = l.getr() -binop1: - if c1 != '=' { - l.ungetr() - l.op = op - l.prec = prec - goto lx - } - - l.op = op - if Debug['x'] != 0 { - fmt.Printf("lex: TOKEN ASOP %s=\n", goopnames[op]) - } - l.tok = LASOP -} - -func (l *lexer) ident(c rune) { - cp := &lexbuf - cp.Reset() - - // accelerate common case (7bit ASCII) - for isLetter(c) || isDigit(c) { - cp.WriteByte(byte(c)) - c = l.getr() - } - - // general case - for { - if c >= utf8.RuneSelf { - if unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) { - if cp.Len() == 0 && unicode.IsDigit(c) { - yyerror("identifier cannot begin with digit %#U", c) - } - } else { - yyerror("invalid identifier character %#U", c) - } - cp.WriteRune(c) - } else if isLetter(c) || isDigit(c) { - cp.WriteByte(byte(c)) - } else { - break - } - c = l.getr() - } - - cp = nil - l.ungetr() - - name := lexbuf.Bytes() - - if len(name) >= 2 { - if tok, ok := keywords[string(name)]; ok { - if Debug['x'] != 0 { - fmt.Printf("lex: %s\n", lexname(tok)) - } - switch tok { - case LBREAK, LCONTINUE, LFALL, LRETURN: - l.nlsemi = true - } - l.tok = tok - return - } - } - - s := lookupBytes(name) - if Debug['x'] != 0 { - fmt.Printf("lex: ident %v\n", s) - } - l.sym_ = s - l.nlsemi = true - l.tok = LNAME -} - -var keywords = map[string]int32{ - "break": LBREAK, - "case": LCASE, - "chan": LCHAN, - "const": LCONST, - "continue": LCONTINUE, - "default": LDEFAULT, - "defer": LDEFER, - "else": LELSE, - "fallthrough": LFALL, - "for": LFOR, - "func": LFUNC, - "go": LGO, - "goto": LGOTO, - "if": LIF, - "import": LIMPORT, - "interface": LINTERFACE, - "map": LMAP, - "package": LPACKAGE, - "range": LRANGE, - "return": LRETURN, - "select": LSELECT, - "struct": LSTRUCT, - "switch": LSWITCH, - "type": LTYPE, - "var": LVAR, - - // 💩 - "notwithstanding": LIGNORE, - "thetruthofthematter": LIGNORE, - "despiteallobjections": LIGNORE, - "whereas": LIGNORE, - "insofaras": LIGNORE, -} - -func (l *lexer) number(c rune) { - cp := &lexbuf - cp.Reset() - - // parse mantissa before decimal point or exponent - isInt := false - malformedOctal := false - if c != '.' { - if c != '0' { - // decimal or float - for isDigit(c) { - cp.WriteByte(byte(c)) - c = l.getr() - } - - } else { - // c == 0 - cp.WriteByte('0') - c = l.getr() - if c == 'x' || c == 'X' { - isInt = true // must be int - cp.WriteByte(byte(c)) - c = l.getr() - for isDigit(c) || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { - cp.WriteByte(byte(c)) - c = l.getr() - } - if lexbuf.Len() == 2 { - yyerror("malformed hex constant") - } - } else { - // decimal 0, octal, or float - for isDigit(c) { - if c > '7' { - malformedOctal = true - } - cp.WriteByte(byte(c)) - c = l.getr() - } - } - } - } - - // unless we have a hex number, parse fractional part or exponent, if any - var str string - if !isInt { - isInt = true // assume int unless proven otherwise - - // fraction - if c == '.' { - isInt = false - cp.WriteByte('.') - c = l.getr() - for isDigit(c) { - cp.WriteByte(byte(c)) - c = l.getr() - } - } - - // exponent - if c == 'e' || c == 'E' { - isInt = false - cp.WriteByte(byte(c)) - c = l.getr() - if c == '+' || c == '-' { - cp.WriteByte(byte(c)) - c = l.getr() - } - if !isDigit(c) { - yyerror("malformed floating point constant exponent") - } - for isDigit(c) { - cp.WriteByte(byte(c)) - c = l.getr() - } - } - - // imaginary constant - if c == 'i' { - str = lexbuf.String() - x := new(Mpcplx) - x.Real.SetFloat64(0.0) - x.Imag.SetString(str) - if x.Imag.Val.IsInf() { - yyerror("overflow in imaginary constant") - x.Imag.SetFloat64(0.0) - } - l.val.U = x - - if Debug['x'] != 0 { - fmt.Printf("lex: imaginary literal\n") - } - goto done - } - } - - l.ungetr() - - if isInt { - if malformedOctal { - yyerror("malformed octal constant") - } - - str = lexbuf.String() - x := new(Mpint) - x.SetString(str) - if x.Ovf { - yyerror("overflow in constant") - x.SetInt64(0) - } - l.val.U = x - - if Debug['x'] != 0 { - fmt.Printf("lex: integer literal\n") - } - - } else { // float - - str = lexbuf.String() - x := newMpflt() - x.SetString(str) - if x.Val.IsInf() { - yyerror("overflow in float constant") - x.SetFloat64(0.0) - } - l.val.U = x - - if Debug['x'] != 0 { - fmt.Printf("lex: floating literal\n") - } - } - -done: - litbuf = "" // lazily initialized in (*parser).syntax_error - l.nlsemi = true - l.tok = LLITERAL -} - -func (l *lexer) stdString() { - lexbuf.Reset() - lexbuf.WriteString(`""`) - - cp := &strbuf - cp.Reset() - - for { - r, b, ok := l.onechar('"') - if !ok { - break - } - if r == 0 { - cp.WriteByte(b) - } else { - cp.WriteRune(r) - } - } - - l.val.U = internString(cp.Bytes()) - if Debug['x'] != 0 { - fmt.Printf("lex: string literal\n") - } - litbuf = "string literal" - l.nlsemi = true - l.tok = LLITERAL -} - -func (l *lexer) rawString() { - lexbuf.Reset() - lexbuf.WriteString("``") - - cp := &strbuf - cp.Reset() - - for { - c := l.getr() - if c == '\r' { - continue - } - if c == EOF { - yyerror("eof in string") - break - } - if c == '`' { - break - } - cp.WriteRune(c) - } - - l.val.U = internString(cp.Bytes()) - if Debug['x'] != 0 { - fmt.Printf("lex: string literal\n") - } - litbuf = "string literal" - l.nlsemi = true - l.tok = LLITERAL -} - -func (l *lexer) rune() { - r, b, ok := l.onechar('\'') - if !ok { - yyerror("empty character literal or unescaped ' in character literal") - r = '\'' - } - if r == 0 { - r = rune(b) - } - - if c := l.getr(); c != '\'' { - yyerror("missing '") - l.ungetr() - } - - x := new(Mpint) - l.val.U = x - x.SetInt64(int64(r)) - x.Rune = true - if Debug['x'] != 0 { - fmt.Printf("lex: codepoint literal\n") - } - litbuf = "rune literal" - l.nlsemi = true - l.tok = LLITERAL -} - var internedStrings = map[string]string{} func internString(b []byte) string { @@ -908,108 +127,6 @@ func internString(b []byte) string { return s } -// read and interpret syntax that looks like -// //line parse.y:15 -// as a discontinuity in sequential line numbers. -// the next line of input comes from parse.y:15 -func (l *lexer) getlinepragma() rune { - c := l.getr() - if c == 'g' { // check for //go: directive - cp := &lexbuf - cp.Reset() - cp.WriteByte('g') // already read - for { - c = l.getr() - if c == EOF || c >= utf8.RuneSelf { - return c - } - if c == '\n' { - break - } - cp.WriteByte(byte(c)) - } - cp = nil - - text := strings.TrimSuffix(lexbuf.String(), "\r") - - if strings.HasPrefix(text, "go:cgo_") { - pragcgobuf += pragcgo(text) - } - - verb := text - if i := strings.Index(text, " "); i >= 0 { - verb = verb[:i] - } - - switch verb { - case "go:linkname": - if !imported_unsafe { - yyerror("//go:linkname only allowed in Go files that import \"unsafe\"") - } - f := strings.Fields(text) - if len(f) != 3 { - yyerror("usage: //go:linkname localname linkname") - break - } - lookup(f[1]).Linkname = f[2] - default: - l.pragma |= pragmaValue(verb) - } - return c - } - - // check for //line directive - if c != 'l' { - return c - } - for i := 1; i < 5; i++ { - c = l.getr() - if c != rune("line "[i]) { - return c - } - } - - cp := &lexbuf - cp.Reset() - linep := 0 - for { - c = l.getr() - if c == EOF { - return c - } - if c == '\n' { - break - } - if c == ' ' { - continue - } - if c == ':' { - linep = cp.Len() + 1 - } - cp.WriteByte(byte(c)) - } - cp = nil - - if linep == 0 { - return c - } - text := strings.TrimSuffix(lexbuf.String(), "\r") - n, err := strconv.Atoi(text[linep:]) - if err != nil { - return c // todo: make this an error instead? it is almost certainly a bug. - } - if n > 1e8 { - yyerror("line number out of range") - errorexit() - } - if n <= 0 { - return c - } - - linehistupdate(text[:linep-1], n) - return c -} - func pragcgo(text string) string { f := pragmaFields(text) @@ -1119,148 +236,3 @@ func pragmaFields(s string) []string { } return a } - -func (l *lexer) getr() rune { -redo: - l.prevlineno = lexlineno - r, w, err := l.bin.ReadRune() - if err != nil { - if err != io.EOF { - Fatalf("io error: %v", err) - } - return -1 - } - switch r { - case 0: - yyerrorl(lexlineno, "illegal NUL byte") - case '\n': - lexlineno++ - case utf8.RuneError: - if w == 1 { - yyerrorl(lexlineno, "illegal UTF-8 sequence") - } - case BOM: - yyerrorl(lexlineno, "Unicode (UTF-8) BOM in middle of file") - goto redo - } - - return r -} - -func (l *lexer) ungetr() { - l.bin.UnreadRune() - lexlineno = l.prevlineno -} - -// onechar lexes a single character within a rune or interpreted string literal, -// handling escape sequences as necessary. -func (l *lexer) onechar(quote rune) (r rune, b byte, ok bool) { - c := l.getr() - switch c { - case EOF: - yyerror("eof in string") - l.ungetr() - return - - case '\n': - yyerror("newline in string") - l.ungetr() - return - - case '\\': - break - - case quote: - return - - default: - return c, 0, true - } - - c = l.getr() - switch c { - case 'x': - return 0, byte(l.hexchar(2)), true - - case 'u': - return l.unichar(4), 0, true - - case 'U': - return l.unichar(8), 0, true - - case '0', '1', '2', '3', '4', '5', '6', '7': - x := c - '0' - for i := 2; i > 0; i-- { - c = l.getr() - if c >= '0' && c <= '7' { - x = x*8 + c - '0' - continue - } - - yyerror("non-octal character in escape sequence: %c", c) - l.ungetr() - } - - if x > 255 { - yyerror("octal escape value > 255: %d", x) - } - - return 0, byte(x), true - - case 'a': - c = '\a' - case 'b': - c = '\b' - case 'f': - c = '\f' - case 'n': - c = '\n' - case 'r': - c = '\r' - case 't': - c = '\t' - case 'v': - c = '\v' - case '\\': - c = '\\' - - default: - if c != quote { - yyerror("unknown escape sequence: %c", c) - } - } - - return c, 0, true -} - -func (l *lexer) unichar(n int) rune { - x := l.hexchar(n) - if x > utf8.MaxRune || 0xd800 <= x && x < 0xe000 { - yyerror("invalid Unicode code point in escape sequence: %#x", x) - x = utf8.RuneError - } - return rune(x) -} - -func (l *lexer) hexchar(n int) uint32 { - var x uint32 - - for ; n > 0; n-- { - var d uint32 - switch c := l.getr(); { - case isDigit(c): - d = uint32(c - '0') - case 'a' <= c && c <= 'f': - d = uint32(c - 'a' + 10) - case 'A' <= c && c <= 'F': - d = uint32(c - 'A' + 10) - default: - yyerror("non-hex character in escape sequence: %c", c) - l.ungetr() - return x - } - x = x*16 + d - } - - return x -} diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index db7c76231a..a990c0896f 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -27,8 +27,6 @@ var imported_unsafe bool var ( buildid string - - flag_newparser bool ) var ( @@ -181,7 +179,6 @@ func Main() { obj.Flagcount("live", "debug liveness analysis", &debuglive) obj.Flagcount("m", "print optimization decisions", &Debug['m']) flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer") - flag.BoolVar(&flag_newparser, "newparser", true, "use new parser") flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports") flag.StringVar(&outfile, "o", "", "write output to `file`") flag.StringVar(&myimportpath, "p", "", "set expected package import `path`") @@ -320,11 +317,7 @@ func Main() { block = 1 iota_ = -1000000 imported_unsafe = false - if flag_newparser { - parseFile(infile) - } else { - oldParseFile(infile) - } + parseFile(infile) if nsyntaxerrors != 0 { errorexit() } diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index b81724daee..641dcb65d0 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -12,1548 +12,7 @@ package gc // Semicolons are inserted by the lexer. The parser uses one-token look-ahead // to handle optional commas and semicolons before a closing ) or } . -import ( - "bufio" - "fmt" - "os" - "strconv" - "strings" -) - -const trace = false // if set, parse tracing can be enabled with -x - -// oldParseFile parses a single Go source file. -func oldParseFile(infile string) { - f, err := os.Open(infile) - if err != nil { - fmt.Printf("open %s: %v\n", infile, err) - errorexit() - } - defer f.Close() - bin := bufio.NewReader(f) - - // Skip initial BOM if present. - if r, _, _ := bin.ReadRune(); r != BOM { - bin.UnreadRune() - } - newparser(bin, nil).file() -} - -type parser struct { - lexer - fnest int // function nesting level (for error handling) - xnest int // expression nesting level (for complit ambiguity resolution) - indent []byte // tracing support -} - -// newparser returns a new parser ready to parse from src. -// indent is the initial indentation for tracing output. -func newparser(src *bufio.Reader, indent []byte) *parser { - var p parser - p.bin = src - p.indent = indent - p.next() - return &p -} - -func (p *parser) got(tok int32) bool { - if p.tok == tok { - p.next() - return true - } - return false -} - -func (p *parser) want(tok int32) { - if !p.got(tok) { - p.syntax_error("expecting " + tokstring(tok)) - p.advance() - } -} - -// ---------------------------------------------------------------------------- -// Syntax error handling - -func (p *parser) syntax_error(msg string) { - if trace && Debug['x'] != 0 { - defer p.trace("syntax_error (" + msg + ")")() - } - - if p.tok == EOF && nerrors > 0 { - return // avoid meaningless follow-up errors - } - - // add punctuation etc. as needed to msg - switch { - case msg == "": - // nothing to do - case strings.HasPrefix(msg, "in"), strings.HasPrefix(msg, "at"), strings.HasPrefix(msg, "after"): - msg = " " + msg - case strings.HasPrefix(msg, "expecting"): - msg = ", " + msg - default: - // plain error - we don't care about current token - yyerror("syntax error: %s", msg) - return - } - - // determine token string - var tok string - switch p.tok { - case LNAME: - if p.sym_ != nil && p.sym_.Name != "" { - tok = p.sym_.Name - } else { - tok = "name" - } - case LLITERAL: - if litbuf == "" { - litbuf = "literal " + lexbuf.String() - } - tok = litbuf - case LOPER: - tok = goopnames[p.op] - case LASOP: - tok = goopnames[p.op] + "=" - case LINCOP: - tok = goopnames[p.op] + goopnames[p.op] - default: - tok = tokstring(p.tok) - } - - yyerror("syntax error: unexpected %s", tok+msg) -} - -// Like syntax_error, but reports error at given line rather than current lexer line. -func (p *parser) syntax_error_at(lno int32, msg string) { - defer func(lno int32) { - lineno = lno - }(lineno) - lineno = lno - p.syntax_error(msg) -} - -// The stoplist contains keywords that start a statement. -// They are good synchronization points in case of syntax -// errors and (usually) shouldn't be skipped over. -var stoplist = map[int32]bool{ - LBREAK: true, - LCONST: true, - LCONTINUE: true, - LDEFER: true, - LFALL: true, - LFOR: true, - LFUNC: true, - LGO: true, - LGOTO: true, - LIF: true, - LRETURN: true, - LSELECT: true, - LSWITCH: true, - LTYPE: true, - LVAR: true, -} - -// Advance consumes tokens until it finds a token of the stop- or followlist. -// The stoplist is only considered if we are inside a function (p.fnest > 0). -// The followlist is the list of valid tokens that can follow a production; -// if it is empty, exactly one token is consumed to ensure progress. -func (p *parser) advance(followlist ...int32) { - if len(followlist) == 0 { - p.next() - return - } - for p.tok != EOF { - if p.fnest > 0 && stoplist[p.tok] { - return - } - for _, follow := range followlist { - if p.tok == follow { - return - } - } - p.next() - } -} - -func tokstring(tok int32) string { - switch tok { - case EOF: - return "EOF" - case ',': - return "comma" - case ';': - return "semicolon or newline" - } - if 0 <= tok && tok < 128 { - // get invisibles properly backslashed - s := strconv.QuoteRune(tok) - if n := len(s); n > 0 && s[0] == '\'' && s[n-1] == '\'' { - s = s[1 : n-1] - } - return s - } - if s := tokstrings[tok]; s != "" { - return s - } - // catchall - return fmt.Sprintf("tok-%v", tok) -} - -var tokstrings = map[int32]string{ - LNAME: "NAME", - LLITERAL: "LITERAL", - - LOPER: "op", - LASOP: "op=", - LINCOP: "opop", - - LCOLAS: ":=", - LCOMM: "<-", - LDDD: "...", - - LBREAK: "break", - LCASE: "case", - LCHAN: "chan", - LCONST: "const", - LCONTINUE: "continue", - LDEFAULT: "default", - LDEFER: "defer", - LELSE: "else", - LFALL: "fallthrough", - LFOR: "for", - LFUNC: "func", - LGO: "go", - LGOTO: "goto", - LIF: "if", - LIMPORT: "import", - LINTERFACE: "interface", - LMAP: "map", - LPACKAGE: "package", - LRANGE: "range", - LRETURN: "return", - LSELECT: "select", - LSTRUCT: "struct", - LSWITCH: "switch", - LTYPE: "type", - LVAR: "var", -} - -// usage: defer p.trace(msg)() -func (p *parser) trace(msg string) func() { - fmt.Printf("%5d: %s%s (\n", lineno, p.indent, msg) - const tab = ". " - p.indent = append(p.indent, tab...) - return func() { - p.indent = p.indent[:len(p.indent)-len(tab)] - if x := recover(); x != nil { - panic(x) // skip print_trace - } - fmt.Printf("%5d: %s)\n", lineno, p.indent) - } -} - -// ---------------------------------------------------------------------------- -// Parsing package files -// -// Parse methods are annotated with matching Go productions as appropriate. -// The annotations are intended as guidelines only since a single Go grammar -// rule may be covered by multiple parse methods and vice versa. - -// SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } . -func (p *parser) file() { - if trace && Debug['x'] != 0 { - defer p.trace("file")() - } - - p.package_() - p.want(';') - - for p.tok == LIMPORT { - p.import_() - p.want(';') - } - - xtop = append(xtop, p.xdcl_list()...) - - p.want(EOF) -} - -// PackageClause = "package" PackageName . -// PackageName = identifier . -func (p *parser) package_() { - if trace && Debug['x'] != 0 { - defer p.trace("package_")() - } - - if !p.got(LPACKAGE) { - p.syntax_error("package statement must be first") - errorexit() - } - mkpackage(p.sym().Name) -} - -// ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) . -func (p *parser) import_() { - if trace && Debug['x'] != 0 { - defer p.trace("import_")() - } - - p.want(LIMPORT) - if p.got('(') { - for p.tok != EOF && p.tok != ')' { - p.importdcl() - if !p.osemi(')') { - break - } - } - p.want(')') - } else { - p.importdcl() - } -} - -// ImportSpec = [ "." | PackageName ] ImportPath . -// ImportPath = string_lit . -func (p *parser) importdcl() { - if trace && Debug['x'] != 0 { - defer p.trace("importdcl")() - } - - var my *Sym - switch p.tok { - case LNAME: - // import with given name - my = p.sym() - - case '.': - // import into my name space - my = lookup(".") - p.next() - } - - if p.tok != LLITERAL { - p.syntax_error("missing import path; require quoted string") - p.advance(';', ')') - return - } - - line := lineno - - // We need to clear importpkg before calling p.next(), - // otherwise it will affect lexlineno. - // TODO(mdempsky): Fix this clumsy API. - importfile(&p.val, p.indent) - ipkg := importpkg - importpkg = nil - - p.next() - if ipkg == nil { - if nerrors == 0 { - Fatalf("phase error in import") - } - return - } - - ipkg.Direct = true - - if my == nil { - my = lookup(ipkg.Name) - } - - pack := nod(OPACK, nil, nil) - pack.Sym = my - pack.Name.Pkg = ipkg - pack.Lineno = line - - if strings.HasPrefix(my.Name, ".") { - importdot(ipkg, pack) - return - } - if my.Name == "init" { - lineno = line - yyerror("cannot import package as init - init must be a func") - return - } - if my.Name == "_" { - return - } - if my.Def != nil { - lineno = line - redeclare(my, "as imported package name") - } - my.Def = pack - my.Lastlineno = line - my.Block = 1 // at top level -} - -// Declaration = ConstDecl | TypeDecl | VarDecl . -// ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) . -// TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) . -// VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) . -func (p *parser) common_dcl() []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("common_dcl")() - } - - var dcl func() []*Node - switch p.tok { - case LVAR: - dcl = p.vardcl - - case LCONST: - iota_ = 0 - dcl = p.constdcl - - case LTYPE: - dcl = p.typedcl - - default: - panic("unreachable") - } - - p.next() - var s []*Node - if p.got('(') { - for p.tok != EOF && p.tok != ')' { - s = append(s, dcl()...) - if !p.osemi(')') { - break - } - } - p.want(')') - } else { - s = dcl() - } - - iota_ = -100000 - lastconst = nil - - return s -} - -// VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) . -func (p *parser) vardcl() []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("vardcl")() - } - - names := p.dcl_name_list() - var typ *Node - var exprs []*Node - if p.got('=') { - exprs = p.expr_list() - } else { - typ = p.ntype() - if p.got('=') { - exprs = p.expr_list() - } - } - - return variter(names, typ, exprs) -} - -// ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] . -func (p *parser) constdcl() []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("constdcl")() - } - - names := p.dcl_name_list() - var typ *Node - var exprs []*Node - if p.tok != EOF && p.tok != ';' && p.tok != ')' { - typ = p.try_ntype() - if p.got('=') { - exprs = p.expr_list() - } - } - - return constiter(names, typ, exprs) -} - -// TypeSpec = identifier Type . -func (p *parser) typedcl() []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("typedcl")() - } - - name := typedcl0(p.sym()) - name.Name.Param.Pragma = p.pragma - - typ := p.try_ntype() - // handle case where type is missing - if typ == nil { - p.syntax_error("in type declaration") - p.advance(';', ')') - } - - return []*Node{typedcl1(name, typ, true)} -} - -// SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl . -// -// simple_stmt may return missing_stmt if labelOk is set. -func (p *parser) simple_stmt(labelOk, rangeOk bool) *Node { - if trace && Debug['x'] != 0 { - defer p.trace("simple_stmt")() - } - - if rangeOk && p.got(LRANGE) { - // LRANGE expr - r := nod(ORANGE, nil, p.expr()) - r.Etype = 0 // := flag - return r - } - - lhs := p.expr_list() - - if len(lhs) == 1 && p.tok != '=' && p.tok != LCOLAS && p.tok != LRANGE { - // expr - lhs := lhs[0] - switch p.tok { - case LASOP: - // expr LASOP expr - op := p.op - p.next() - rhs := p.expr() - - stmt := nod(OASOP, lhs, rhs) - stmt.Etype = EType(op) // rathole to pass opcode - return stmt - - case LINCOP: - // expr LINCOP - p.next() - - stmt := nod(OASOP, lhs, nodintconst(1)) - stmt.Implicit = true - stmt.Etype = EType(p.op) - return stmt - - case ':': - // labelname ':' stmt - if labelOk { - // If we have a labelname, it was parsed by operand - // (calling p.name()) and given an ONAME, ONONAME, OTYPE, OPACK, or OLITERAL node. - // We only have a labelname if there is a symbol (was issue 14006). - switch lhs.Op { - case ONAME, ONONAME, OTYPE, OPACK, OLITERAL: - if lhs.Sym != nil { - lhs = newname(lhs.Sym) - break - } - fallthrough - default: - p.syntax_error("expecting semicolon or newline or }") - // we already progressed, no need to advance - } - lhs := nod(OLABEL, lhs, nil) - lhs.Sym = dclstack // context, for goto restrictions - p.next() // consume ':' after making label node for correct lineno - return p.labeled_stmt(lhs) - } - fallthrough - - default: - // expr - // Since a bare name used as an expression is an error, - // introduce a wrapper node where necessary to give the - // correct line. - return wrapname(lhs) - } - } - - // expr_list - switch p.tok { - case '=': - p.next() - if rangeOk && p.got(LRANGE) { - // expr_list '=' LRANGE expr - r := nod(ORANGE, nil, p.expr()) - r.List.Set(lhs) - r.Etype = 0 // := flag - return r - } - - // expr_list '=' expr_list - rhs := p.expr_list() - - if len(lhs) == 1 && len(rhs) == 1 { - // simple - return nod(OAS, lhs[0], rhs[0]) - } - // multiple - stmt := nod(OAS2, nil, nil) - stmt.List.Set(lhs) - stmt.Rlist.Set(rhs) - return stmt - - case LCOLAS: - lno := lineno - p.next() - - if rangeOk && p.got(LRANGE) { - // expr_list LCOLAS LRANGE expr - r := nod(ORANGE, nil, p.expr()) - r.List.Set(lhs) - r.Colas = true - colasdefn(lhs, r) - return r - } - - // expr_list LCOLAS expr_list - rhs := p.expr_list() - - if rhs[0].Op == OTYPESW { - ts := nod(OTYPESW, nil, rhs[0].Right) - if len(rhs) > 1 { - yyerror("expr.(type) must be alone in list") - } - if len(lhs) > 1 { - yyerror("argument count mismatch: %d = %d", len(lhs), 1) - } else if (lhs[0].Op != ONAME && lhs[0].Op != OTYPE && lhs[0].Op != ONONAME && (lhs[0].Op != OLITERAL || lhs[0].Name == nil)) || isblank(lhs[0]) { - yyerror("invalid variable name %v in type switch", lhs[0]) - } else { - ts.Left = dclname(lhs[0].Sym) - } // it's a colas, so must not re-use an oldname - return ts - } - return colas(lhs, rhs, lno) - - default: - p.syntax_error("expecting := or = or comma") - p.advance(';', '}') - return nil - } -} - -// LabeledStmt = Label ":" Statement . -// Label = identifier . -func (p *parser) labeled_stmt(label *Node) *Node { - if trace && Debug['x'] != 0 { - defer p.trace("labeled_stmt")() - } - - var ls *Node // labeled statement - if p.tok != '}' && p.tok != EOF { - ls = p.stmt() - if ls == missing_stmt { - // report error at line of ':' token - p.syntax_error_at(label.Lineno, "missing statement after label") - // we are already at the end of the labeled statement - no need to advance - return missing_stmt - } - } - - label.Name.Defn = ls - l := []*Node{label} - if ls != nil { - if ls.Op == OBLOCK && ls.Ninit.Len() == 0 { - l = append(l, ls.List.Slice()...) - } else { - l = append(l, ls) - } - } - return liststmt(l) -} - -// case_ parses a superset of switch and select statement cases. -// Later checks restrict the syntax to valid forms. -// -// ExprSwitchCase = "case" ExpressionList | "default" . -// TypeSwitchCase = "case" TypeList | "default" . -// TypeList = Type { "," Type } . -// CommCase = "case" ( SendStmt | RecvStmt ) | "default" . -// RecvStmt = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr . -// RecvExpr = Expression . -func (p *parser) case_(tswitch *Node) *Node { - if trace && Debug['x'] != 0 { - defer p.trace("case_")() - } - - switch p.tok { - case LCASE: - p.next() - cases := p.expr_list() // expr_or_type_list - switch p.tok { - case ':': - // LCASE expr_or_type_list ':' - - // will be converted to OCASE - // right will point to next case - // done in casebody() - markdcl() // matching popdcl in caseblock - stmt := nod(OXCASE, nil, nil) - stmt.List.Set(cases) - if tswitch != nil { - if n := tswitch.Left; n != nil { - // type switch - declare variable - nn := newname(n.Sym) - declare(nn, dclcontext) - stmt.Rlist.Set1(nn) - - // keep track of the instances for reporting unused - nn.Name.Defn = tswitch - } - } - - p.next() // consume ':' after declaring type switch var for correct lineno - return stmt - - case '=': - // LCASE expr_or_type_list '=' expr ':' - p.next() - rhs := p.expr() - - // will be converted to OCASE - // right will point to next case - // done in casebody() - markdcl() // matching popdcl in caseblock - stmt := nod(OXCASE, nil, nil) - var n *Node - if len(cases) == 1 { - n = nod(OAS, cases[0], rhs) - } else { - n = nod(OAS2, nil, nil) - n.List.Set(cases) - n.Rlist.Set1(rhs) - } - stmt.List.Set1(n) - - p.want(':') // consume ':' after declaring select cases for correct lineno - return stmt - - case LCOLAS: - // LCASE expr_or_type_list LCOLAS expr ':' - lno := lineno - p.next() - rhs := p.expr() - - // will be converted to OCASE - // right will point to next case - // done in casebody() - markdcl() // matching popdcl in caseblock - stmt := nod(OXCASE, nil, nil) - stmt.List.Set1(colas(cases, []*Node{rhs}, lno)) - - p.want(':') // consume ':' after declaring select cases for correct lineno - return stmt - - default: - markdcl() // for matching popdcl in caseblock - stmt := nod(OXCASE, nil, nil) // don't return nil - p.syntax_error("expecting := or = or : or comma") - p.advance(LCASE, LDEFAULT, '}') - return stmt - } - - case LDEFAULT: - // LDEFAULT ':' - p.next() - - markdcl() // matching popdcl in caseblock - stmt := nod(OXCASE, nil, nil) - if tswitch != nil { - if n := tswitch.Left; n != nil { - // type switch - declare variable - nn := newname(n.Sym) - declare(nn, dclcontext) - stmt.Rlist.Set1(nn) - - // keep track of the instances for reporting unused - nn.Name.Defn = tswitch - } - } - - p.want(':') // consume ':' after declaring type switch var for correct lineno - return stmt - - default: - markdcl() // matching popdcl in caseblock - stmt := nod(OXCASE, nil, nil) // don't return nil - p.syntax_error("expecting case or default or }") - p.advance(LCASE, LDEFAULT, '}') - return stmt - } -} - -// Block = "{" StatementList "}" . -// StatementList = { Statement ";" } . -func (p *parser) compound_stmt() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("compound_stmt")() - } - - markdcl() - p.want('{') - l := p.stmt_list() - p.want('}') - popdcl() - - if len(l) == 0 { - return nod(OEMPTY, nil, nil) - } - return liststmt(l) -} - -// caseblock parses a superset of switch and select clauses. -// -// ExprCaseClause = ExprSwitchCase ":" StatementList . -// TypeCaseClause = TypeSwitchCase ":" StatementList . -// CommClause = CommCase ":" StatementList . -func (p *parser) caseblock(tswitch *Node) *Node { - if trace && Debug['x'] != 0 { - defer p.trace("caseblock")() - } - - stmt := p.case_(tswitch) // does markdcl - stmt.Xoffset = int64(block) - stmt.Nbody.Set(p.stmt_list()) - - popdcl() - - return stmt -} - -// caseblock_list parses a superset of switch and select clause lists. -func (p *parser) caseblock_list(tswitch *Node) (l []*Node) { - if trace && Debug['x'] != 0 { - defer p.trace("caseblock_list")() - } - - if !p.got('{') { - p.syntax_error("missing { after switch clause") - p.advance(LCASE, LDEFAULT, '}') - } - - for p.tok != EOF && p.tok != '}' { - l = append(l, p.caseblock(tswitch)) - } - p.want('}') - return -} - -// loop_body parses if and for statement bodies. -func (p *parser) loop_body(context string) []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("loop_body")() - } - - markdcl() - if !p.got('{') { - p.syntax_error("missing { after " + context) - p.advance(LNAME, '}') - } - - body := p.stmt_list() - popdcl() - p.want('}') - - return body -} - -// for_header parses the header portion of a for statement. -// -// ForStmt = "for" [ Condition | ForClause | RangeClause ] Block . -// Condition = Expression . -func (p *parser) for_header() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("for_header")() - } - - init, cond, post := p.header(true) - - if init != nil || post != nil { - // init ; test ; incr - if post != nil && post.Colas { - yyerror("cannot declare in the for-increment") - } - h := nod(OFOR, nil, nil) - if init != nil { - h.Ninit.Set1(init) - } - h.Left = cond - h.Right = post - return h - } - - if cond != nil && cond.Op == ORANGE { - // range_stmt - handled by pexpr - return cond - } - - // normal test - h := nod(OFOR, nil, nil) - h.Left = cond - return h -} - -func (p *parser) for_body() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("for_body")() - } - - stmt := p.for_header() - body := p.loop_body("for clause") - - stmt.Nbody.Append(body...) - return stmt -} - -// ForStmt = "for" [ Condition | ForClause | RangeClause ] Block . -func (p *parser) for_stmt() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("for_stmt")() - } - - p.want(LFOR) - markdcl() - body := p.for_body() - popdcl() - - return body -} - -// header parses a combination of if, switch, and for statement headers: -// -// Header = [ InitStmt ";" ] [ Expression ] . -// Header = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] . // for_stmt only -// InitStmt = SimpleStmt . -// PostStmt = SimpleStmt . -func (p *parser) header(for_stmt bool) (init, cond, post *Node) { - if p.tok == '{' { - return - } - - outer := p.xnest - p.xnest = -1 - - if p.tok != ';' { - // accept potential vardcl but complain - // (for test/syntax/forvar.go) - if for_stmt && p.tok == LVAR { - yyerror("var declaration not allowed in for initializer") - p.next() - } - init = p.simple_stmt(false, for_stmt) - // If we have a range clause, we are done. - if for_stmt && init.Op == ORANGE { - cond = init - init = nil - - p.xnest = outer - return - } - } - if p.got(';') { - if for_stmt { - if p.tok != ';' { - cond = p.simple_stmt(false, false) - } - p.want(';') - if p.tok != '{' { - post = p.simple_stmt(false, false) - } - } else if p.tok != '{' { - cond = p.simple_stmt(false, false) - } - } else { - cond = init - init = nil - } - - p.xnest = outer - return -} - -func (p *parser) if_header() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("if_header")() - } - - init, cond, _ := p.header(false) - h := nod(OIF, nil, nil) - if init != nil { - h.Ninit.Set1(init) - } - h.Left = cond - return h -} - -// IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] . -func (p *parser) if_stmt() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("if_stmt")() - } - - p.want(LIF) - - markdcl() - - stmt := p.if_header() - if stmt.Left == nil { - yyerror("missing condition in if statement") - } - - stmt.Nbody.Set(p.loop_body("if clause")) - - if p.got(LELSE) { - switch p.tok { - case LIF: - stmt.Rlist.Set1(p.if_stmt()) - case '{': - cs := p.compound_stmt() - if cs.Op == OBLOCK && cs.Ninit.Len() == 0 { - stmt.Rlist.Set(cs.List.Slice()) - } else { - stmt.Rlist.Set1(cs) - } - default: - p.syntax_error("else must be followed by if or statement block") - p.advance(LNAME, '}') - } - } - - popdcl() - return stmt -} - -// switch_stmt parses both expression and type switch statements. -// -// SwitchStmt = ExprSwitchStmt | TypeSwitchStmt . -// ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" . -// TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" . -func (p *parser) switch_stmt() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("switch_stmt")() - } - - p.want(LSWITCH) - markdcl() - - hdr := p.if_header() - hdr.Op = OSWITCH - - tswitch := hdr.Left - if tswitch != nil && tswitch.Op != OTYPESW { - tswitch = nil - } - - hdr.List.Set(p.caseblock_list(tswitch)) - popdcl() - - return hdr -} - -// SelectStmt = "select" "{" { CommClause } "}" . -func (p *parser) select_stmt() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("select_stmt")() - } - - p.want(LSELECT) - hdr := nod(OSELECT, nil, nil) - hdr.List.Set(p.caseblock_list(nil)) - return hdr -} - -// Expression = UnaryExpr | Expression binary_op Expression . -func (p *parser) bexpr(prec OpPrec) *Node { - // don't trace bexpr - only leads to overly nested trace output - - // prec is precedence of the prior/enclosing binary operator (if any), - // so we only want to parse tokens of greater precedence. - - x := p.uexpr() - for p.prec > prec { - op, prec1 := p.op, p.prec - p.next() - x = nod(op, x, p.bexpr(prec1)) - } - return x -} - -func (p *parser) expr() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("expr")() - } - - return p.bexpr(0) -} - -func unparen(x *Node) *Node { - for x.Op == OPAREN { - x = x.Left - } - return x -} - -// UnaryExpr = PrimaryExpr | unary_op UnaryExpr . -func (p *parser) uexpr() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("uexpr")() - } - - var op Op - switch p.tok { - case '*': - op = OIND - - case '&': - p.next() - // uexpr may have returned a parenthesized composite literal - // (see comment in operand) - remove parentheses if any - x := unparen(p.uexpr()) - if x.Op == OCOMPLIT { - // Special case for &T{...}: turn into (*T){...}. - x.Right = nod(OIND, x.Right, nil) - x.Right.Implicit = true - } else { - x = nod(OADDR, x, nil) - } - return x - - case '+': - op = OPLUS - - case '-': - op = OMINUS - - case '!': - op = ONOT - - case '^': - op = OCOM - - case LCOMM: - // receive op (<-x) or receive-only channel (<-chan E) - p.next() - - // If the next token is LCHAN we still don't know if it is - // a channel (<-chan int) or a receive op (<-chan int(ch)). - // We only know once we have found the end of the uexpr. - - x := p.uexpr() - - // There are two cases: - // - // <-chan... => <-x is a channel type - // <-x => <-x is a receive operation - // - // In the first case, <- must be re-associated with - // the channel type parsed already: - // - // <-(chan E) => (<-chan E) - // <-(chan<-E) => (<-chan (<-E)) - - if x.Op == OTCHAN { - // x is a channel type => re-associate <- - dir := Csend - t := x - for ; t.Op == OTCHAN && dir == Csend; t = t.Left { - dir = ChanDir(t.Etype) - if dir == Crecv { - // t is type <-chan E but <-<-chan E is not permitted - // (report same error as for "type _ <-<-chan E") - p.syntax_error("unexpected <-, expecting chan") - // already progressed, no need to advance - } - t.Etype = EType(Crecv) - } - if dir == Csend { - // channel dir is <- but channel element E is not a channel - // (report same error as for "type _ <-chan<-E") - p.syntax_error(fmt.Sprintf("unexpected %v, expecting chan", t)) - // already progressed, no need to advance - } - return x - } - - // x is not a channel type => we have a receive op - return nod(ORECV, x, nil) - - default: - return p.pexpr(false) - } - - // simple uexpr - p.next() - return nod(op, p.uexpr(), nil) -} - -// pseudocall parses call-like statements that can be preceded by 'defer' and 'go'. -func (p *parser) pseudocall() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("pseudocall")() - } - - x := p.pexpr(p.tok == '(') // keep_parens so we can report error below - switch x.Op { - case OCALL: - return x - case OPAREN: - yyerror("expression in go/defer must not be parenthesized") - // already progressed, no need to advance - default: - yyerror("expression in go/defer must be function call") - // already progressed, no need to advance - } - return nil -} - -// Operand = Literal | OperandName | MethodExpr | "(" Expression ")" . -// Literal = BasicLit | CompositeLit | FunctionLit . -// BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit . -// OperandName = identifier | QualifiedIdent. -func (p *parser) operand(keep_parens bool) *Node { - if trace && Debug['x'] != 0 { - defer p.trace("operand")() - } - - switch p.tok { - case LLITERAL: - x := nodlit(p.val) - p.next() - return x - - case LNAME: - return p.name() - - case '(': - p.next() - p.xnest++ - x := p.expr() // expr_or_type - p.xnest-- - p.want(')') - - // Optimization: Record presence of ()'s only where needed - // for error reporting. Don't bother in other cases; it is - // just a waste of memory and time. - - // Parentheses are not permitted on lhs of := . - switch x.Op { - case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW: - keep_parens = true - } - - // Parentheses are not permitted around T in a composite - // literal T{}. If the next token is a {, assume x is a - // composite literal type T (it may not be, { could be - // the opening brace of a block, but we don't know yet). - if p.tok == '{' { - keep_parens = true - } - - // Parentheses are also not permitted around the expression - // in a go/defer statement. In that case, operand is called - // with keep_parens set. - if keep_parens { - x = nod(OPAREN, x, nil) - } - return x - - case LFUNC: - t := p.ntype() // fntype - if p.tok == '{' { - // fnlitdcl - closurehdr(t) - // fnliteral - p.next() // consume '{' - p.fnest++ - p.xnest++ - body := p.stmt_list() - p.xnest-- - p.fnest-- - p.want('}') - return closurebody(body) - } - return t - - case '[', LCHAN, LMAP, LSTRUCT, LINTERFACE: - return p.ntype() // othertype - - case '{': - // common case: p.header is missing simple_stmt before { in if, for, switch - p.syntax_error("missing operand") - // '{' will be consumed in pexpr - no need to consume it here - return nil - - default: - p.syntax_error("expecting expression") - p.advance() - return nil - } - - // Syntactically, composite literals are operands. Because a complit - // type may be a qualified identifier which is handled by pexpr - // (together with selector expressions), complits are parsed there - // as well (operand is only called from pexpr). -} - -// PrimaryExpr = -// Operand | -// Conversion | -// PrimaryExpr Selector | -// PrimaryExpr Index | -// PrimaryExpr Slice | -// PrimaryExpr TypeAssertion | -// PrimaryExpr Arguments . -// -// Selector = "." identifier . -// Index = "[" Expression "]" . -// Slice = "[" ( [ Expression ] ":" [ Expression ] ) | -// ( [ Expression ] ":" Expression ":" Expression ) -// "]" . -// TypeAssertion = "." "(" Type ")" . -// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" . -func (p *parser) pexpr(keep_parens bool) *Node { - if trace && Debug['x'] != 0 { - defer p.trace("pexpr")() - } - - x := p.operand(keep_parens) - -loop: - for { - switch p.tok { - case '.': - p.next() - switch p.tok { - case LNAME: - // pexpr '.' sym - x = p.new_dotname(x) - - case '(': - p.next() - switch p.tok { - default: - // pexpr '.' '(' expr_or_type ')' - t := p.expr() // expr_or_type - p.want(')') - x = nod(ODOTTYPE, x, t) - - case LTYPE: - // pexpr '.' '(' LTYPE ')' - p.next() - p.want(')') - x = nod(OTYPESW, nil, x) - } - - default: - p.syntax_error("expecting name or (") - p.advance(';', '}') - } - - case '[': - p.next() - p.xnest++ - var index [3]*Node - if p.tok != ':' { - index[0] = p.expr() - } - ncol := 0 - for ncol < len(index)-1 && p.got(':') { - ncol++ - if p.tok != EOF && p.tok != ':' && p.tok != ']' { - index[ncol] = p.expr() - } - } - p.xnest-- - p.want(']') - - switch ncol { - case 0: - i := index[0] - if i == nil { - yyerror("missing index in index expression") - } - x = nod(OINDEX, x, i) - case 1: - x = nod(OSLICE, x, nil) - x.SetSliceBounds(index[0], index[1], nil) - case 2: - if index[1] == nil { - yyerror("middle index required in 3-index slice") - } - if index[2] == nil { - yyerror("final index required in 3-index slice") - } - x = nod(OSLICE3, x, nil) - x.SetSliceBounds(index[0], index[1], index[2]) - - default: - panic("unreachable") - } - - case '(': - // convtype '(' expr ocomma ')' - args, ddd := p.arg_list() - - // call or conversion - x = nod(OCALL, x, nil) - x.List.Set(args) - x.Isddd = ddd - - case '{': - // operand may have returned a parenthesized complit - // type; accept it but complain if we have a complit - t := unparen(x) - // determine if '{' belongs to a complit or a compound_stmt - complit_ok := false - switch t.Op { - case ONAME, ONONAME, OTYPE, OPACK, OXDOT, ODOT: - if p.xnest >= 0 { - // x is considered a comptype - complit_ok = true - } - case OTARRAY, OTSTRUCT, OTMAP: - // x is a comptype - complit_ok = true - } - if !complit_ok { - break loop - } - if t != x { - p.syntax_error("cannot parenthesize type in composite literal") - // already progressed, no need to advance - } - n := p.complitexpr() - n.Right = x - x = n - - default: - break loop - } - } - - return x -} - -// KeyedElement = [ Key ":" ] Element . -func (p *parser) keyval() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("keyval")() - } - - // A composite literal commonly spans several lines, - // so the line number on errors may be misleading. - // Wrap values (but not keys!) that don't carry line - // numbers. - - x := p.bare_complitexpr() - - if p.got(':') { - // key ':' value - return nod(OKEY, x, wrapname(p.bare_complitexpr())) - } - - // value - return wrapname(x) -} - -func wrapname(x *Node) *Node { - // These nodes do not carry line numbers. - // Introduce a wrapper node to give the correct line. - switch x.Op { - case ONAME, ONONAME, OTYPE, OPACK, OLITERAL: - x = nod(OPAREN, x, nil) - x.Implicit = true - } - return x -} - -// Element = Expression | LiteralValue . -func (p *parser) bare_complitexpr() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("bare_complitexpr")() - } - - if p.tok == '{' { - // '{' start_complit braced_keyval_list '}' - return p.complitexpr() - } - - return p.expr() -} - -// LiteralValue = "{" [ ElementList [ "," ] ] "}" . -func (p *parser) complitexpr() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("complitexpr")() - } - - // make node early so we get the right line number - n := nod(OCOMPLIT, nil, nil) - - p.want('{') - p.xnest++ - - var l []*Node - for p.tok != EOF && p.tok != '}' { - l = append(l, p.keyval()) - if !p.ocomma('}') { - break - } - } - - p.xnest-- - p.want('}') - - n.List.Set(l) - return n -} - -// names and types -// newname is used before declared -// oldname is used after declared -func (p *parser) new_name(sym *Sym) *Node { - if trace && Debug['x'] != 0 { - defer p.trace("new_name")() - } - - if sym != nil { - return newname(sym) - } - return nil -} - -func (p *parser) dcl_name() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("dcl_name")() - } - - symlineno := lineno - sym := p.sym() - if sym == nil { - yyerrorl(symlineno, "invalid declaration") - return nil - } - return dclname(sym) -} - -func (p *parser) onew_name() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("onew_name")() - } - - if p.tok == LNAME { - return p.new_name(p.sym()) - } - return nil -} - -func (p *parser) sym() *Sym { - if p.tok == LNAME { - s := p.sym_ // from localpkg - p.next() - return s - } - - p.syntax_error("expecting name") - p.advance() - return new(Sym) -} +const trace = false // if set, parse tracing can be enabled with -x func mkname(sym *Sym) *Node { n := oldname(sym) @@ -1563,1011 +22,9 @@ func mkname(sym *Sym) *Node { return n } -func (p *parser) name() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("name")() - } - - return mkname(p.sym()) -} - -// [ "..." ] Type -func (p *parser) dotdotdot() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("dotdotdot")() - } - - p.want(LDDD) - if typ := p.try_ntype(); typ != nil { - return nod(ODDD, typ, nil) - } - - yyerror("final argument in variadic function missing type") - return nod(ODDD, typenod(typ(TINTER)), nil) -} - -func (p *parser) ntype() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("ntype")() - } - - if typ := p.try_ntype(); typ != nil { - return typ - } - - p.syntax_error("") - p.advance() - return nil -} - -// signature parses a function signature and returns an OTFUNC node. -// -// Signature = Parameters [ Result ] . -func (p *parser) signature(recv *Node) *Node { - if trace && Debug['x'] != 0 { - defer p.trace("signature")() - } - - params := p.param_list(true) - - var result []*Node - if p.tok == '(' { - result = p.param_list(false) - } else if t := p.try_ntype(); t != nil { - result = []*Node{nod(ODCLFIELD, nil, t)} - } - - typ := nod(OTFUNC, recv, nil) - typ.List.Set(params) - typ.Rlist.Set(result) - - return typ -} - -// try_ntype is like ntype but it returns nil if there was no type -// instead of reporting an error. -// -// Type = TypeName | TypeLit | "(" Type ")" . -// TypeName = identifier | QualifiedIdent . -// TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType | -// SliceType | MapType | ChannelType . -func (p *parser) try_ntype() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("try_ntype")() - } - - switch p.tok { - case LCOMM: - // recvchantype - p.next() - p.want(LCHAN) - t := nod(OTCHAN, p.chan_elem(), nil) - t.Etype = EType(Crecv) - return t - - case LFUNC: - // fntype - p.next() - return p.signature(nil) - - case '[': - // '[' oexpr ']' ntype - // '[' LDDD ']' ntype - p.next() - p.xnest++ - var len *Node - if p.tok != ']' { - if p.got(LDDD) { - len = nod(ODDD, nil, nil) - } else { - len = p.expr() - } - } - p.xnest-- - p.want(']') - return nod(OTARRAY, len, p.ntype()) - - case LCHAN: - // LCHAN non_recvchantype - // LCHAN LCOMM ntype - p.next() - var dir = EType(Cboth) - if p.got(LCOMM) { - dir = EType(Csend) - } - t := nod(OTCHAN, p.chan_elem(), nil) - t.Etype = dir - return t - - case LMAP: - // LMAP '[' ntype ']' ntype - p.next() - p.want('[') - key := p.ntype() - p.want(']') - val := p.ntype() - return nod(OTMAP, key, val) - - case LSTRUCT: - return p.structtype() - - case LINTERFACE: - return p.interfacetype() - - case '*': - // ptrtype - p.next() - return nod(OIND, p.ntype(), nil) - - case LNAME: - return p.dotname() - - case '(': - p.next() - t := p.ntype() - p.want(')') - return t - - default: - return nil - } -} - -func (p *parser) chan_elem() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("chan_elem")() - } - - if typ := p.try_ntype(); typ != nil { - return typ - } - - p.syntax_error("missing channel element type") - // assume element type is simply absent - don't advance - return nil -} - -func (p *parser) new_dotname(obj *Node) *Node { - if trace && Debug['x'] != 0 { - defer p.trace("new_dotname")() - } - - sel := p.sym() - if obj.Op == OPACK { - s := restrictlookup(sel.Name, obj.Name.Pkg) - obj.Used = true - return oldname(s) - } - return nodSym(OXDOT, obj, sel) -} - -func (p *parser) dotname() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("dotname")() - } - - name := p.name() - if p.got('.') { - return p.new_dotname(name) - } - return name -} - -// StructType = "struct" "{" { FieldDecl ";" } "}" . -func (p *parser) structtype() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("structtype")() - } - - p.want(LSTRUCT) - p.want('{') - var l []*Node - for p.tok != EOF && p.tok != '}' { - l = append(l, p.structdcl()...) - if !p.osemi('}') { - break - } - } - p.want('}') - - t := nod(OTSTRUCT, nil, nil) - t.List.Set(l) - return t -} - -// InterfaceType = "interface" "{" { MethodSpec ";" } "}" . -func (p *parser) interfacetype() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("interfacetype")() - } - - p.want(LINTERFACE) - p.want('{') - var l []*Node - for p.tok != EOF && p.tok != '}' { - l = append(l, p.interfacedcl()) - if !p.osemi('}') { - break - } - } - p.want('}') - - t := nod(OTINTER, nil, nil) - t.List.Set(l) - return t -} - -// Function stuff. -// All in one place to show how crappy it all is. - -func (p *parser) xfndcl() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("xfndcl")() - } - - p.want(LFUNC) - f := p.fndcl() - body := p.fnbody() - - if f == nil { - return nil - } - - f.Nbody.Set(body) - f.Noescape = p.pragma&Noescape != 0 - if f.Noescape && len(body) != 0 { - yyerror("can only use //go:noescape with external func implementations") - } - f.Func.Pragma = p.pragma - f.Func.Endlineno = lineno - - funcbody(f) - - return f -} - -// FunctionDecl = "func" FunctionName ( Function | Signature ) . -// FunctionName = identifier . -// Function = Signature FunctionBody . -// MethodDecl = "func" Receiver MethodName ( Function | Signature ) . -// Receiver = Parameters . -func (p *parser) fndcl() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("fndcl")() - } - - switch p.tok { - case LNAME: - // FunctionName Signature - name := p.sym() - t := p.signature(nil) - - if name.Name == "init" { - name = renameinit() - if t.List.Len() > 0 || t.Rlist.Len() > 0 { - yyerror("func init must have no arguments and no return values") - } - } - - if localpkg.Name == "main" && name.Name == "main" { - if t.List.Len() > 0 || t.Rlist.Len() > 0 { - yyerror("func main must have no arguments and no return values") - } - } - - f := nod(ODCLFUNC, nil, nil) - f.Func.Nname = newfuncname(name) - f.Func.Nname.Name.Defn = f - f.Func.Nname.Name.Param.Ntype = t // TODO: check if nname already has an ntype - declare(f.Func.Nname, PFUNC) - - funchdr(f) - return f - - case '(': - // Receiver MethodName Signature - rparam := p.param_list(false) - var recv *Node - if len(rparam) > 0 { - recv = rparam[0] - } - name := p.sym() - t := p.signature(recv) - - // check after parsing header for fault-tolerance - if recv == nil { - yyerror("method has no receiver") - return nil - } - - if len(rparam) > 1 { - yyerror("method has multiple receivers") - return nil - } - - if recv.Op != ODCLFIELD { - yyerror("bad receiver in method") - return nil - } - - f := nod(ODCLFUNC, nil, nil) - f.Func.Shortname = newfuncname(name) - f.Func.Nname = methodname(f.Func.Shortname, recv.Right) - f.Func.Nname.Name.Defn = f - f.Func.Nname.Name.Param.Ntype = t - declare(f.Func.Nname, PFUNC) - - funchdr(f) - return f - - default: - p.syntax_error("expecting name or (") - p.advance('{', ';') - return nil - } -} - -// FunctionBody = Block . -func (p *parser) fnbody() []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("fnbody")() - } - - if p.got('{') { - p.fnest++ - body := p.stmt_list() - p.fnest-- - p.want('}') - if body == nil { - body = []*Node{nod(OEMPTY, nil, nil)} - } - return body - } - - return nil -} - -// Declaration = ConstDecl | TypeDecl | VarDecl . -// TopLevelDecl = Declaration | FunctionDecl | MethodDecl . -func (p *parser) xdcl_list() (l []*Node) { - if trace && Debug['x'] != 0 { - defer p.trace("xdcl_list")() - } - - for p.tok != EOF { - switch p.tok { - case LVAR, LCONST, LTYPE: - l = append(l, p.common_dcl()...) - - case LFUNC: - l = append(l, p.xfndcl()) - - default: - if p.tok == '{' && len(l) != 0 && l[len(l)-1].Op == ODCLFUNC && l[len(l)-1].Nbody.Len() == 0 { - // opening { of function declaration on next line - p.syntax_error("unexpected semicolon or newline before {") - } else { - p.syntax_error("non-declaration statement outside function body") - } - p.advance(LVAR, LCONST, LTYPE, LFUNC) - continue - } - - // Reset p.pragma BEFORE advancing to the next token (consuming ';') - // since comments before may set pragmas for the next function decl. - p.pragma = 0 - - if p.tok != EOF && !p.got(';') { - p.syntax_error("after top level declaration") - p.advance(LVAR, LCONST, LTYPE, LFUNC) - } - } - - if nsyntaxerrors == 0 { - testdclstack() - } - return -} - -// FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] . -// AnonymousField = [ "*" ] TypeName . -// Tag = string_lit . -func (p *parser) structdcl() []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("structdcl")() - } - - var sym *Sym - switch p.tok { - case LNAME: - sym = p.sym_ - p.next() - if sym == nil { - panic("unreachable") // we must have a sym for LNAME - } - if p.tok == '.' || p.tok == LLITERAL || p.tok == ';' || p.tok == '}' { - // embed oliteral - field := p.embed(sym) - tag := p.oliteral() - - field.SetVal(tag) - return []*Node{field} - } - - // new_name_list ntype oliteral - fields := p.new_name_list(sym) - typ := p.ntype() - tag := p.oliteral() - - if len(fields) == 0 || fields[0].Sym.Name == "?" { - // ? symbol, during import - n := typ - if n.Op == OIND { - n = n.Left - } - n = embedded(n.Sym, importpkg) - n.Right = typ - n.SetVal(tag) - return []*Node{n} - } - - for i, n := range fields { - fields[i] = nod(ODCLFIELD, n, typ) - fields[i].SetVal(tag) - } - return fields - - case '(': - p.next() - if p.got('*') { - // '(' '*' embed ')' oliteral - field := p.embed(nil) - p.want(')') - tag := p.oliteral() - - field.Right = nod(OIND, field.Right, nil) - field.SetVal(tag) - yyerror("cannot parenthesize embedded type") - return []*Node{field} - - } else { - // '(' embed ')' oliteral - field := p.embed(nil) - p.want(')') - tag := p.oliteral() - - field.SetVal(tag) - yyerror("cannot parenthesize embedded type") - return []*Node{field} - } - - case '*': - p.next() - if p.got('(') { - // '*' '(' embed ')' oliteral - field := p.embed(nil) - p.want(')') - tag := p.oliteral() - - field.Right = nod(OIND, field.Right, nil) - field.SetVal(tag) - yyerror("cannot parenthesize embedded type") - return []*Node{field} - - } else { - // '*' embed oliteral - field := p.embed(nil) - tag := p.oliteral() - - field.Right = nod(OIND, field.Right, nil) - field.SetVal(tag) - return []*Node{field} - } - - default: - p.syntax_error("expecting field name or embedded type") - p.advance(';', '}') - return nil - } -} - -func (p *parser) oliteral() (v Val) { - if p.tok == LLITERAL { - v = p.val - p.next() - } - return -} - -func (p *parser) packname(name *Sym) *Sym { - if trace && Debug['x'] != 0 { - defer p.trace("embed")() - } - - if name != nil { - // LNAME was already consumed and is coming in as name - } else if p.tok == LNAME { - name = p.sym_ - p.next() - } else { - p.syntax_error("expecting name") - p.advance('.', ';', '}') - name = new(Sym) - } - - if p.got('.') { - // LNAME '.' sym - s := p.sym() - - var pkg *Pkg - if name.Def == nil || name.Def.Op != OPACK { - yyerror("%v is not a package", name) - pkg = localpkg - } else { - name.Def.Used = true - pkg = name.Def.Name.Pkg - } - return restrictlookup(s.Name, pkg) - } - - // LNAME - if n := oldname(name); n.Name != nil && n.Name.Pack != nil { - n.Name.Pack.Used = true - } - return name -} - -func (p *parser) embed(sym *Sym) *Node { - if trace && Debug['x'] != 0 { - defer p.trace("embed")() - } - - pkgname := p.packname(sym) - return embedded(pkgname, localpkg) -} - -// MethodSpec = MethodName Signature | InterfaceTypeName . -// MethodName = identifier . -// InterfaceTypeName = TypeName . -func (p *parser) interfacedcl() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("interfacedcl")() - } - - switch p.tok { - case LNAME: - sym := p.sym_ - p.next() - - // accept potential name list but complain - hasNameList := false - for p.got(',') { - p.sym() - hasNameList = true - } - if hasNameList { - p.syntax_error("name list not allowed in interface type") - // already progressed, no need to advance - } - - if p.tok != '(' { - // packname - pname := p.packname(sym) - return nod(ODCLFIELD, nil, oldname(pname)) - } - - // MethodName Signature - mname := newname(sym) - sig := p.signature(fakethis()) - - meth := nod(ODCLFIELD, mname, sig) - ifacedcl(meth) - return meth - - case '(': - p.next() - pname := p.packname(nil) - p.want(')') - n := nod(ODCLFIELD, nil, oldname(pname)) - yyerror("cannot parenthesize embedded type") - return n - - default: - p.syntax_error("") - p.advance(';', '}') - return nil - } -} - -// param parses and returns a function parameter list entry which may be -// a parameter name and type pair (name, typ), a single type (nil, typ), -// or a single name (name, nil). In the last case, the name may still be -// a type name. The result is (nil, nil) in case of a syntax error. -// -// [ParameterName] Type -func (p *parser) param() (name *Sym, typ *Node) { - if trace && Debug['x'] != 0 { - defer p.trace("param")() - } - - switch p.tok { - case LNAME: - name = p.sym() - switch p.tok { - case LCOMM, LFUNC, '[', LCHAN, LMAP, LSTRUCT, LINTERFACE, '*', LNAME, '(': - // sym name_or_type - typ = p.ntype() - - case LDDD: - // sym dotdotdot - typ = p.dotdotdot() - - default: - // name_or_type - if p.got('.') { - // a qualified name cannot be a parameter name - typ = p.new_dotname(mkname(name)) - name = nil - } - } - - case LDDD: - // dotdotdot - typ = p.dotdotdot() - - case LCOMM, LFUNC, '[', LCHAN, LMAP, LSTRUCT, LINTERFACE, '*', '(': - // name_or_type - typ = p.ntype() - - default: - p.syntax_error("expecting )") - p.advance(',', ')') - } - - return -} - -// Parameters = "(" [ ParameterList [ "," ] ] ")" . -// ParameterList = ParameterDecl { "," ParameterDecl } . -// ParameterDecl = [ IdentifierList ] [ "..." ] Type . -func (p *parser) param_list(dddOk bool) []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("param_list")() - } - - type param struct { - name *Sym - typ *Node - } - var params []param - var named int // number of parameters that have a name and type - - p.want('(') - for p.tok != EOF && p.tok != ')' { - name, typ := p.param() - params = append(params, param{name, typ}) - if name != nil && typ != nil { - named++ - } - if !p.ocomma(')') { - break - } - } - p.want(')') - // 0 <= named <= len(params) - - // There are 3 cases: - // - // 1) named == 0: - // No parameter list entry has both a name and a type; i.e. there are only - // unnamed parameters. Any name must be a type name; they are "converted" - // to types when creating the final parameter list. - // In case of a syntax error, there is neither a name nor a type. - // Nil checks take care of this. - // - // 2) named == len(names): - // All parameter list entries have both a name and a type. - // - // 3) Otherwise: - if named != 0 && named != len(params) { - // Some parameter list entries have both a name and a type: - // Distribute types backwards and check that there are no - // mixed named and unnamed parameters. - var T *Node // type T in a parameter sequence: a, b, c T - for i := len(params) - 1; i >= 0; i-- { - p := ¶ms[i] - if t := p.typ; t != nil { - // explicit type: use type for earlier parameters - T = t - // an explicitly typed entry must have a name - if p.name == nil { - T = nil // error - } - } else { - // no explicit type: use type of next parameter - p.typ = T - } - if T == nil { - yyerror("mixed named and unnamed function parameters") - break - } - } - // Unless there was an error, now all parameter entries have a type. - } - - // create final parameter list - list := make([]*Node, len(params)) - for i, p := range params { - // create dcl node - var name, typ *Node - if p.typ != nil { - typ = p.typ - if p.name != nil { - // name must be a parameter name - name = newname(p.name) - } - } else if p.name != nil { - // p.name must be a type name (or nil in case of syntax error) - typ = mkname(p.name) - } - n := nod(ODCLFIELD, name, typ) - - // rewrite ...T parameter - if typ != nil && typ.Op == ODDD { - if !dddOk { - yyerror("cannot use ... in receiver or result parameter list") - } else if i+1 < len(params) { - yyerror("can only use ... with final parameter in list") - } - typ.Op = OTARRAY - typ.Right = typ.Left - typ.Left = nil - n.Isddd = true - if n.Left != nil { - n.Left.Isddd = true - } - } - - list[i] = n - } - - return list -} - -var missing_stmt = nod(OXXX, nil, nil) - -// Statement = -// Declaration | LabeledStmt | SimpleStmt | -// GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt | -// FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt | -// DeferStmt . -// -// stmt may return missing_stmt. -func (p *parser) stmt() *Node { - if trace && Debug['x'] != 0 { - defer p.trace("stmt")() - } - - switch p.tok { - case '{': - return p.compound_stmt() - - case LVAR, LCONST, LTYPE: - return liststmt(p.common_dcl()) - - case LNAME, LLITERAL, LFUNC, '(', // operands - '[', LSTRUCT, LMAP, LCHAN, LINTERFACE, // composite types - '+', '-', '*', '&', '^', LCOMM, '!': // unary operators - return p.simple_stmt(true, false) - - case LFOR: - return p.for_stmt() - - case LSWITCH: - return p.switch_stmt() - - case LSELECT: - return p.select_stmt() - - case LIF: - return p.if_stmt() - - case LFALL: - p.next() - // will be converted to OFALL - stmt := nod(OXFALL, nil, nil) - stmt.Xoffset = int64(block) - return stmt - - case LBREAK: - p.next() - return nod(OBREAK, p.onew_name(), nil) - - case LCONTINUE: - p.next() - return nod(OCONTINUE, p.onew_name(), nil) - - case LGO: - p.next() - return nod(OPROC, p.pseudocall(), nil) - - case LDEFER: - p.next() - return nod(ODEFER, p.pseudocall(), nil) - - case LGOTO: - p.next() - stmt := nod(OGOTO, p.new_name(p.sym()), nil) - stmt.Sym = dclstack // context, for goto restrictions - return stmt - - case LRETURN: - p.next() - var results []*Node - if p.tok != ';' && p.tok != '}' { - results = p.expr_list() - } - - stmt := nod(ORETURN, nil, nil) - stmt.List.Set(results) - if stmt.List.Len() == 0 && Curfn != nil { - for _, ln := range Curfn.Func.Dcl { - if ln.Class == PPARAM { - continue - } - if ln.Class != PPARAMOUT { - break - } - if ln.Sym.Def != ln { - yyerror("%s is shadowed during return", ln.Sym.Name) - } - } - } - - return stmt - - case ';': - return nil - - default: - return missing_stmt - } -} - -// StatementList = { Statement ";" } . -func (p *parser) stmt_list() (l []*Node) { - if trace && Debug['x'] != 0 { - defer p.trace("stmt_list")() - } - - for p.tok != EOF && p.tok != '}' && p.tok != LCASE && p.tok != LDEFAULT { - s := p.stmt() - if s == missing_stmt { - break - } - if s == nil { - } else if s.Op == OBLOCK && s.Ninit.Len() == 0 { - l = append(l, s.List.Slice()...) - } else { - l = append(l, s) - } - // customized version of osemi: - // ';' is optional before a closing ')' or '}' - if p.tok == ')' || p.tok == '}' { - continue - } - if !p.got(';') { - p.syntax_error("at end of statement") - p.advance(';', '}') - } - } - return -} - -// IdentifierList = identifier { "," identifier } . -// -// If first != nil we have the first symbol already. -func (p *parser) new_name_list(first *Sym) []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("new_name_list")() - } - - if first == nil { - first = p.sym() // may still be nil - } - var l []*Node - n := p.new_name(first) - if n != nil { - l = append(l, n) - } - for p.got(',') { - n = p.new_name(p.sym()) - if n != nil { - l = append(l, n) - } - } - return l -} - -// IdentifierList = identifier { "," identifier } . -func (p *parser) dcl_name_list() []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("dcl_name_list")() - } - - s := []*Node{p.dcl_name()} - for p.got(',') { - s = append(s, p.dcl_name()) - } - return s -} - -// ExpressionList = Expression { "," Expression } . -func (p *parser) expr_list() []*Node { - if trace && Debug['x'] != 0 { - defer p.trace("expr_list")() - } - - l := []*Node{p.expr()} - for p.got(',') { - l = append(l, p.expr()) - } - return l -} - -// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" . -func (p *parser) arg_list() (l []*Node, ddd bool) { - if trace && Debug['x'] != 0 { - defer p.trace("arg_list")() - } - - p.want('(') - p.xnest++ - - for p.tok != EOF && p.tok != ')' && !ddd { - l = append(l, p.expr()) // expr_or_type - ddd = p.got(LDDD) - if !p.ocomma(')') { - break - } - } - - p.xnest-- - p.want(')') - - return -} - -// osemi parses an optional semicolon. -func (p *parser) osemi(follow int32) bool { - switch p.tok { - case ';': - p.next() - return true - - case ')', '}': - // semicolon is optional before ) or } - return true - } - - p.syntax_error("expecting semicolon, newline, or " + tokstring(follow)) - p.advance(follow) - return false -} - -// ocomma parses an optional comma. -func (p *parser) ocomma(follow int32) bool { - switch p.tok { - case ',': - p.next() - return true - - case ')', '}': - // comma is optional before ) or } - return true +func unparen(x *Node) *Node { + for x.Op == OPAREN { + x = x.Left } - - p.syntax_error("expecting comma or " + tokstring(follow)) - p.advance(follow) - return false + return x }