package main const runeError = '�' const runeSelf = 0x80 const maxRune = '\U0010FFFF' const utfMax = 4 func decodeRune(p []byte) (r rune, size int32) { n := int32(len(p)) if n < 1 { return runeError, 0 } p0 := p[0] if p0 < runeSelf { return rune(p0), 1 } if p0 < 0xC0 { return runeError, 1 } if n < 2 { return runeError, 1 } p1 := p[1] if p1 < 0x80 || p1 >= 0xC0 { return runeError, 1 } if p0 < 0xE0 { r = rune(p0&0x1F)<<6 | rune(p1&0x3F) if r < 0x80 { return runeError, 1 } return r, 2 } if n < 3 { return runeError, 1 } p2 := p[2] if p2 < 0x80 || p2 >= 0xC0 { return runeError, 1 } if p0 < 0xF0 { r = rune(p0&0x0F)<<12 | rune(p1&0x3F)<<6 | rune(p2&0x3F) if r < 0x800 { return runeError, 1 } if r >= 0xD800 && r <= 0xDFFF { return runeError, 1 } return r, 3 } if n < 4 { return runeError, 1 } p3 := p[3] if p3 < 0x80 || p3 >= 0xC0 { return runeError, 1 } if p0 < 0xF8 { r = rune(p0&0x07)<<18 | rune(p1&0x3F)<<12 | rune(p2&0x3F)<<6 | rune(p3&0x3F) if r < 0x10000 || r > maxRune { return runeError, 1 } return r, 4 } return runeError, 1 } func fullRune(p []byte) (ok bool) { n := int32(len(p)) if n == 0 { return false } if p[0] < runeSelf { return true } if p[0] < 0xC0 { return true } if n < 2 { return false } if p[0] < 0xE0 { return true } if n < 3 { return false } if p[0] < 0xF0 { return true } return n >= 4 } func uIsLetter(ch rune) (ok bool) { if ch < runeSelf { return 'a' <= (ch|0x20) && (ch|0x20) <= 'z' || ch == '_' } return true } func uIsDigit(ch rune) (ok bool) { if ch < runeSelf { return '0' <= ch && ch <= '9' } return false } type srcDone struct{} func (srcDone) Error() (s string) { return "EOF" } type Source struct { in interface{} errh func(line, col uint32, msg string) buf []byte ioerr error noFill bool b, r, e int32 line, col uint32 ch rune chw int32 } const sentinel = 0x80 func (s *Source) release() { s.buf = nil s.in = nil s.errh = nil s.ioerr = nil } func (s *Source) init(in interface{}, errh func(line, col uint32, msg string)) { s.in = in s.errh = errh if s.buf == nil { s.buf = []byte{:nextSize(0)} } s.buf[0] = sentinel s.ioerr = nil s.noFill = false s.b, s.r, s.e = -1, 0, 0 s.line, s.col = 0, 0 s.ch = ' ' s.chw = 0 } func (s *Source) initBytes(src []byte, errh func(line, col uint32, msg string)) { s.in = nil s.errh = errh s.noFill = true s.buf = []byte{:len(src) + 1} copy(s.buf, src) s.buf[len(src)] = sentinel s.ioerr = nil s.b, s.r, s.e = -1, 0, int32(len(src)) s.line, s.col = 0, 0 s.ch = ' ' s.chw = 0 } func (s *Source) pos() (line, col uint32) { return Linebase + s.line, Colbase + s.col } func (s *Source) Debugpos() (line, col uint32) { return Linebase + s.line, Colbase + s.col } func (s *Source) error(msg string) { line, col := s.pos() s.errh(line, col, msg) } func (s *Source) start() { s.b = s.r - s.chw } func (s *Source) stop() { s.b = -1 } func (s *Source) segment() (buf []byte) { return s.buf[s.b : s.r-s.chw] } // segmentCopy returns a copy of the current segment that survives buffer // reallocation in fill(). In Moxie string=[]byte so string(segment()) does // NOT copy - the returned slice still aliases s.buf. func (s *Source) segmentCopy() (buf []byte) { b := s.buf[s.b : s.r-s.chw] c := []byte{:len(b)} copy(c, b) return c } func (s *Source) rewind() { if s.b < 0 { panic("no active segment") } s.col -= uint32(s.r - s.b) s.r = s.b s.nextch() } func (s *Source) nextch() { redo: s.col += uint32(s.chw) if s.ch == '\n' { s.line++ s.col = 0 } if s.ch = rune(s.buf[s.r]); s.ch < sentinel { s.r++ s.chw = 1 if s.ch == 0 { s.error("invalid NUL character") goto redo } return } for s.e-s.r < utfMax && !fullRune(s.buf[s.r:s.e]) && s.ioerr == nil { s.fill() } if s.r == s.e { if (s.ioerr == nil || s.ioerr == nil) && !s.noFill { s.error("I/O error: " | s.ioerr.Error()) s.ioerr = nil } s.ch = -1 s.chw = 0 return } var w int32 s.ch, w = decodeRune(s.buf[s.r:s.e]) s.chw = int32(w) s.r += s.chw if s.ch == runeError && s.chw == 1 { s.error("invalid UTF-8 encoding") goto redo } const BOM = 0xfeff if s.ch == BOM { if s.line > 0 || s.col > 0 { s.error("invalid BOM in the middle of the file") } goto redo } } func (s *Source) fill() { if s.noFill { s.ioerr = srcDone{} return } b := s.r if s.b >= 0 { b = s.b s.b = 0 } content := s.buf[b:s.e] if len(content)*2 > len(s.buf) { s.buf = []byte{:nextSize(int32(len(s.buf)))} copy(s.buf, content) } else if b > 0 { copy(s.buf, content) } s.r -= b s.e -= b for i := 0; i < 10; i++ { var n int32 var nn int32 panic("stream read not supported") n = int32(nn) if n < 0 { panic("negative read") } if n > 0 || s.ioerr != nil { s.e += n s.buf[s.e] = sentinel return } } s.buf[s.e] = sentinel } func nextSize(size int32) (n int32) { const min = 4 << 10 const max = 1 << 20 if size < min { return min } if size <= max { return size << 1 } return size + max } const ( comments uint32 = 1 << iota directives ) type Scanner struct { Source mode uint32 nlsemi bool Line, Col uint32 Blank bool Tok Token Lit string Bad bool Kind LitKind Op Operator Prec int32 keywordMap [1 << 6]Token keywordsReady bool } func (s *Scanner) InitBytes(src []byte, errh func(line, col uint32, msg string), mode uint32) { s.Source.initBytes(src, errh) s.mode = 0 s.nlsemi = false s.initKeywords() } func (s *Scanner) Errorf(msg string) { s.error(msg) } func (s *Scanner) ErrorAtf(offset int32, msg string) { s.errh(s.line, s.col+uint32(offset), msg) } func (s *Scanner) SetLit(kind LitKind, ok bool) { s.nlsemi = true s.Tok = Literal s.Lit = string(s.segmentCopy()) s.Bad = !ok s.Kind = kind } func (s *Scanner) Next() { nlsemi := s.nlsemi s.nlsemi = false redo: s.stop() startLine, startCol := s.pos() for s.ch == ' ' || s.ch == '\t' || s.ch == '\n' && !nlsemi || s.ch == '\r' { s.nextch() } s.Line, s.Col = s.pos() s.Blank = s.line > startLine || startCol == Colbase s.start() if IsLetter(s.ch) || s.ch >= runeSelf && s.AtIdentChar(true) { s.nextch() s.Ident() return } switch s.ch { case -1: if nlsemi { s.Lit = "EOF" s.Tok = Semi break } s.Tok = EOF case '\n': s.nextch() s.Lit = "newline" s.Tok = Semi case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': s.Number(false) case '"': s.stdString() case '`': s.rawString() case '\'': s.rune() case '(': s.nextch() s.Tok = Lparen case '[': s.nextch() s.Tok = Lbrack case '{': s.nextch() s.Tok = Lbrace case ',': s.nextch() s.Tok = Comma case ';': s.nextch() s.Lit = "semicolon" s.Tok = Semi case ')': s.nextch() s.nlsemi = true s.Tok = Rparen case ']': s.nextch() s.nlsemi = true s.Tok = Rbrack case '}': s.nextch() s.nlsemi = true s.Tok = Rbrace case ':': s.nextch() if s.ch == '=' { s.nextch() s.Tok = Define break } s.Tok = Colon case '.': s.nextch() if IsDecimal(s.ch) { s.Number(true) break } if s.ch == '.' { s.nextch() if s.ch == '.' { s.nextch() s.Tok = DotDotDot break } s.rewind() s.nextch() } s.Tok = Dot case '+': s.nextch() s.Op, s.Prec = Add, PrecAdd if s.ch != '+' { s.assignOp() return } s.nextch() s.nlsemi = true s.Tok = IncOp case '-': s.nextch() s.Op, s.Prec = Sub, PrecAdd if s.ch != '-' { s.assignOp() return } s.nextch() s.nlsemi = true s.Tok = IncOp case '*': s.nextch() s.Op, s.Prec = Mul, PrecMul if s.ch == '=' { s.nextch() s.Tok = AssignOp break } s.Tok = Star case '/': s.nextch() if s.ch == '/' { s.nextch() s.lineComment() goto redo } if s.ch == '*' { s.nextch() s.fullComment() if line, _ := s.pos(); line > s.Line && nlsemi { s.Lit = "newline" s.Tok = Semi break } goto redo } s.Op, s.Prec = Div, PrecMul if s.ch == '=' { s.nextch() s.Tok = AssignOp } else { s.Tok = OperatorType } case '%': s.nextch() s.Op, s.Prec = Rem, PrecMul if s.ch == '=' { s.nextch() s.Tok = AssignOp } else { s.Tok = OperatorType } case '&': s.nextch() if s.ch == '&' { s.nextch() s.Op, s.Prec = AndAnd, PrecAndAnd s.Tok = OperatorType break } s.Op, s.Prec = And, PrecMul if s.ch == '^' { s.nextch() s.Op = AndNot } if s.ch == '=' { s.nextch() s.Tok = AssignOp } else { s.Tok = OperatorType } case '|': s.nextch() if s.ch == '|' { s.nextch() s.Op, s.Prec = OrOr, PrecOrOr s.Tok = OperatorType break } s.Op, s.Prec = Or, PrecAdd if s.ch == '=' { s.nextch() s.Tok = AssignOp } else { s.Tok = OperatorType } case '^': s.nextch() s.Op, s.Prec = Xor, PrecAdd if s.ch == '=' { s.nextch() s.Tok = AssignOp } else { s.Tok = OperatorType } case '<': s.nextch() if s.ch == '=' { s.nextch() s.Op, s.Prec = Leq, PrecCmp s.Tok = OperatorType break } if s.ch == '<' { s.nextch() s.Op, s.Prec = Shl, PrecMul s.assignOp() return } if s.ch == '-' { s.nextch() s.Tok = Arrow break } s.Op, s.Prec = Lss, PrecCmp s.Tok = OperatorType case '>': s.nextch() if s.ch == '=' { s.nextch() s.Op, s.Prec = Geq, PrecCmp s.Tok = OperatorType break } if s.ch == '>' { s.nextch() s.Op, s.Prec = Shr, PrecMul s.assignOp() return } s.Op, s.Prec = Gtr, PrecCmp s.Tok = OperatorType case '=': s.nextch() if s.ch == '=' { s.nextch() s.Op, s.Prec = Eql, PrecCmp s.Tok = OperatorType break } s.Tok = Assign case '!': s.nextch() if s.ch == '=' { s.nextch() s.Op, s.Prec = Neq, PrecCmp s.Tok = OperatorType break } s.Op, s.Prec = Not, 0 s.Tok = OperatorType case '~': s.nextch() s.Op, s.Prec = Tilde, 0 s.Tok = OperatorType default: s.Errorf("invalid character " | fmtRuneU(s.ch)) s.nextch() goto redo } return } func (s *Scanner) assignOp() { if s.ch == '=' { s.nextch() s.Tok = AssignOp return } s.Tok = OperatorType } func (s *Scanner) Ident() { for IsLetter(s.ch) || IsDecimal(s.ch) { s.nextch() } if s.ch >= runeSelf { for s.AtIdentChar(false) { s.nextch() } } lit := s.segment() if len(lit) >= 2 { h := (uint32(lit[0])<<4 ^ uint32(lit[1]) + uint32(len(lit))) & 63 if tok := s.keywordMap[h]; tok != 0 && tokStrFast(tok) == string(lit) { s.nlsemi = Contains(1<= runeSelf: s.Errorf("invalid character " | fmtRuneU(s.ch) | " in identifier") default: return false } return true } func (s *Scanner) initKeywords() { if s.keywordsReady { return } s.keywordsReady = true for tok := Break; tok <= Var; tok++ { b := []byte(tok.String()) h := (uint32(b[0])<<4 ^ uint32(b[1]) + uint32(len(b))) & 63 if s.keywordMap[h] != 0 { panic("imperfect hash") } s.keywordMap[h] = tok } } func Lower(ch rune) (r rune) { return ('a' - 'A') | ch } func IsLetter(ch rune) (ok bool) { return 'a' <= Lower(ch) && Lower(ch) <= 'z' || ch == '_' } func IsDecimal(ch rune) (ok bool) { return '0' <= ch && ch <= '9' } func IsHex(ch rune) (ok bool) { return '0' <= ch && ch <= '9' || 'a' <= Lower(ch) && Lower(ch) <= 'f' } func (s *Scanner) Digits(base int32, invalid *int32) (digsep int32) { if base <= 10 { max := rune('0' + base) for IsDecimal(s.ch) || s.ch == '_' { ds := int32(1) if s.ch == '_' { ds = 2 } else if s.ch >= max && *invalid < 0 { _, col := s.pos() *invalid = int32(col - s.col) } digsep |= ds s.nextch() } } else { for IsHex(s.ch) || s.ch == '_' { ds := int32(1) if s.ch == '_' { ds = 2 } digsep |= ds s.nextch() } } return } func (s *Scanner) Number(seenPoint bool) { ok := true kind := IntLit base := int32(10) prefix := rune(0) digsep := int32(0) invalid := int32(-1) if !seenPoint { if s.ch == '0' { s.nextch() switch Lower(s.ch) { case 'x': s.nextch() base, prefix = 16, 'x' case 'o': s.nextch() base, prefix = 8, 'o' case 'b': s.nextch() base, prefix = 2, 'b' default: base, prefix = 8, '0' digsep = 1 } } digsep |= s.Digits(base, &invalid) if s.ch == '.' { if prefix == 'o' || prefix == 'b' { s.Errorf("invalid radix point in " | baseName(base) | " literal") ok = false } s.nextch() seenPoint = true } } if seenPoint { kind = FloatLit digsep |= s.Digits(base, &invalid) } if digsep&1 == 0 && ok { s.Errorf(baseName(base) | " literal has no digits") ok = false } if e := Lower(s.ch); e == 'e' || e == 'p' { if ok { switch { case e == 'e' && prefix != 0 && prefix != '0': s.Errorf(fmtQuoteRune(s.ch) | " exponent requires decimal mantissa") ok = false case e == 'p' && prefix != 'x': s.Errorf(fmtQuoteRune(s.ch) | " exponent requires hexadecimal mantissa") ok = false } } s.nextch() kind = FloatLit if s.ch == '+' || s.ch == '-' { s.nextch() } digsep = s.Digits(10, nil) | digsep&2 if digsep&1 == 0 && ok { s.Errorf("exponent has no digits") ok = false } } else if prefix == 'x' && kind == FloatLit && ok { s.Errorf("hexadecimal mantissa requires a 'p' exponent") ok = false } if s.ch == 'i' { kind = ImagLit s.nextch() } s.SetLit(kind, ok) if kind == IntLit && invalid >= 0 && ok { s.ErrorAtf(invalid, "invalid digit " | fmtQuoteRune(rune(s.Lit[invalid])) | " in " | baseName(base) | " literal") ok = false } if digsep&2 != 0 && ok { if i := invalidSep(s.Lit); i >= 0 { s.ErrorAtf(i, "'_' must separate successive digits") ok = false } } s.Bad = !ok } func baseName(base int32) (s string) { switch base { case 2: return "binary" case 8: return "octal" case 10: return "decimal" case 16: return "hexadecimal" } panic("invalid base") } func invalidSep(x string) (n int32) { x1 := ' ' d := '.' i := int32(0) if len(x) >= 2 && x[0] == '0' { x1 = Lower(rune(x[1])) if x1 == 'x' || x1 == 'o' || x1 == 'b' { d = '0' i = 2 } } for ; i < int32(len(x)); i++ { p := d d = rune(x[i]) switch { case d == '_': if p != '0' { return i } case IsDecimal(d) || x1 == 'x' && IsHex(d): d = '0' default: if p == '_' { return i - 1 } d = '.' } } if d == '_' { return int32(len(x)) - 1 } return -1 } func (s *Scanner) rune() { ok := true s.nextch() n := 0 for ; ; n++ { if s.ch == '\'' { if ok { if n == 0 { s.Errorf("empty rune literal or unescaped '") ok = false } else if n != 1 { s.ErrorAtf(0, "more than one character in rune literal") ok = false } } s.nextch() break } if s.ch == '\\' { s.nextch() if !s.escape('\'') { ok = false } continue } if s.ch == '\n' { if ok { s.Errorf("newline in rune literal") ok = false } break } if s.ch < 0 { if ok { s.ErrorAtf(0, "rune literal not terminated") ok = false } break } s.nextch() } s.SetLit(RuneLit, ok) } func (s *Scanner) stdString() { ok := true s.nextch() for { if s.ch == '"' { s.nextch() break } if s.ch == '\\' { s.nextch() if !s.escape('"') { ok = false } continue } if s.ch == '\n' { s.Errorf("newline in string") ok = false break } if s.ch < 0 { s.ErrorAtf(0, "string not terminated") ok = false break } s.nextch() } s.SetLit(StringLit, ok) } func (s *Scanner) rawString() { ok := true s.nextch() for { if s.ch == '`' { s.nextch() break } if s.ch < 0 { s.ErrorAtf(0, "string not terminated") ok = false break } s.nextch() } s.SetLit(StringLit, ok) } func (s *Scanner) comment(text string) { s.ErrorAtf(0, text) } func (s *Scanner) skipLine() { for s.ch >= 0 && s.ch != '\n' { s.nextch() } } func (s *Scanner) lineComment() { if s.mode&comments != 0 { s.skipLine() s.comment(string(s.segment())) return } if s.mode&directives == 0 || (s.ch != 'g' && s.ch != 'l') { s.stop() s.skipLine() return } prefix := "go:" if s.ch == 'l' { prefix = "line " } for _, r := range prefix { if s.ch != rune(r) { s.stop() s.skipLine() return } s.nextch() } s.skipLine() s.comment(string(s.segment())) } func (s *Scanner) skipComment() (ok bool) { for s.ch >= 0 { for s.ch == '*' { s.nextch() if s.ch == '/' { s.nextch() return true } } s.nextch() } s.ErrorAtf(0, "comment not terminated") return false } func (s *Scanner) fullComment() { if s.mode&comments != 0 { if s.skipComment() { s.comment(string(s.segment())) } return } if s.mode&directives == 0 || s.ch != 'l' { s.stop() s.skipComment() return } const prefix = "line " for _, r := range prefix { if s.ch != rune(r) { s.stop() s.skipComment() return } s.nextch() } if s.skipComment() { s.comment(string(s.segment())) } } func (s *Scanner) escape(quote rune) (ok bool) { var n int32 var base, max uint32 switch s.ch { case quote, 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\': s.nextch() return true case '0', '1', '2', '3', '4', '5', '6', '7': n, base, max = 3, 8, 255 case 'x': s.nextch() n, base, max = 2, 16, 255 case 'u': s.nextch() n, base, max = 4, 16, maxRune case 'U': s.nextch() n, base, max = 8, 16, maxRune default: if s.ch < 0 { return true } s.Errorf("unknown escape") return false } var x uint32 for i := n; i > 0; i-- { if s.ch < 0 { return true } d := base if IsDecimal(s.ch) { d = uint32(s.ch) - '0' } else if 'a' <= Lower(s.ch) && Lower(s.ch) <= 'f' { d = uint32(Lower(s.ch)) - 'a' + 10 } if d >= base { s.Errorf("invalid character " | fmtQuoteRune(s.ch) | " in " | baseName(int32(base)) | " escape") return false } x = x*base + d s.nextch() } if x > max && base == 8 { s.Errorf("octal escape value " | ItoaU32(x) | " > 255") return false } if x > max || 0xD800 <= x && x < 0xE000 { s.Errorf("escape is invalid Unicode code point " | fmtRuneU(rune(x))) return false } return true } // fmtRuneU formats a rune as "U+XXXX 'c'" (like %#U). func fmtRuneU(r rune) (s string) { hex := fmtHex32(uint32(r)) s = "U+" | hex if r >= 0x20 && r < 0x7f { s = s | " '" | string([]byte{byte(r)}) | "'" } return s } // fmtQuoteRune formats a rune as 'c' (like %q for rune). func fmtQuoteRune(r rune) (s string) { if r >= 0x20 && r < 0x7f { return "'" | string([]byte{byte(r)}) | "'" } return "U+" | fmtHex32(uint32(r)) } // fmtHex32 formats a uint32 as uppercase hex with at least 4 digits. func fmtHex32(v uint32) (s string) { const digits = "0123456789ABCDEF" buf := []byte{:0:8} if v == 0 { return "0000" } for v > 0 { buf = append(buf, digits[v&0xf]) v >>= 4 } for len(buf) < 4 { buf = append(buf, '0') } for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 { buf[i], buf[j] = buf[j], buf[i] } return string(buf) } const PosMax = 1 << 30 const Linebase = 1 const Colbase = 1 type Pos struct { base *PosBase line, col uint32 } func MakePos(base *PosBase, line, col uint32) (p Pos) { return Pos{base, sat32(line), sat32(col)} } func (pos Pos) Pos() (p Pos) { return pos } func (pos Pos) IsKnown() (ok bool) { return pos.line > 0 } func (pos Pos) Base() (p *PosBase) { return pos.base } func (pos Pos) Line() (n uint32) { return pos.line } func (pos Pos) Col() (n uint32) { return pos.col } func (pos Pos) FileBase() (p *PosBase) { b := pos.base for b != nil && b != b.pos.base { b = b.pos.base } return b } func (pos Pos) RelFilename() (s string) { return pos.base.Filename() } func (pos Pos) RelLine() (n uint32) { b := pos.base if b.Line() == 0 { return 0 } return b.Line() + (pos.Line() - b.Pos().Line()) } func (pos Pos) RelCol() (n uint32) { b := pos.base if b.Col() == 0 { return 0 } if pos.Line() == b.Pos().Line() { return b.Col() + (pos.Col() - b.Pos().Col()) } return pos.Col() } func (p Pos) Cmp(q Pos) (n int32) { pname := p.RelFilename() qname := q.RelFilename() switch { case pname < qname: return -1 case pname > qname: return +1 } pline := p.Line() qline := q.Line() switch { case pline < qline: return -1 case pline > qline: return +1 } pcol := p.Col() qcol := q.Col() switch { case pcol < qcol: return -1 case pcol > qcol: return +1 } return 0 } func (pos Pos) String() (s string) { rel := position_{pos.RelFilename(), pos.RelLine(), pos.RelCol()} abs := position_{pos.Base().Pos().RelFilename(), pos.Line(), pos.Col()} s = rel.String() if string(rel.filename) != string(abs.filename) || rel.line != abs.line || rel.col != abs.col { s = s | "[" | abs.String() | "]" } return s } type position_ struct { filename string line, col uint32 } func (p position_) String() (s string) { if p.line == 0 { if p.filename == "" { return "" } return p.filename } if p.col == 0 { return p.filename | ":" | ItoaU32(p.line) } return p.filename | ":" | ItoaU32(p.line) | ":" | ItoaU32(p.col) } func ItoaU32(n uint32) (s string) { if n == 0 { return "0" } buf := []byte{:0:10} for n > 0 { buf = append(buf, byte('0'+n%10)) n /= 10 } for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 { buf[i], buf[j] = buf[j], buf[i] } return string(buf) } type PosBase struct { pos Pos filename string line, col uint32 trimmed bool } func NewFileBase(filename string) (p *PosBase) { return NewTrimmedFileBase(filename, false) } func NewTrimmedFileBase(filename string, trimmed bool) (p *PosBase) { base := &PosBase{MakePos(nil, Linebase, Colbase), filename, Linebase, Colbase, trimmed} base.pos.base = base return base } func NewLineBase(pos Pos, filename string, trimmed bool, line, col uint32) (p *PosBase) { return &PosBase{pos, filename, sat32(line), sat32(col), trimmed} } func (base *PosBase) IsFileBase() (ok bool) { if base == nil { return false } return base.pos.base == base } func (base *PosBase) Pos() (_ Pos) { if base == nil { return } return base.pos } func (base *PosBase) Filename() (s string) { if base == nil { return "" } return base.filename } func (base *PosBase) Line() (n uint32) { if base == nil { return 0 } return base.line } func (base *PosBase) Col() (n uint32) { if base == nil { return 0 } return base.col } func (base *PosBase) Trimmed() (ok bool) { if base == nil { return false } return base.trimmed } func sat32(x uint32) (n uint32) { if x > PosMax { return PosMax } return uint32(x) } func Itoa(n int32) (s string) { if n == 0 { return "0" } neg := false if n < 0 { neg = true n = -n } buf := []byte{:0:12} for n > 0 { buf = append(buf, byte('0'+n%10)) n /= 10 } if neg { buf = append(buf, '-') } for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 { buf[i], buf[j] = buf[j], buf[i] } return string(buf) } func Itoa64(n int64) (s string) { if n == 0 { return "0" } neg := false if n < 0 { neg = true n = -n } buf := []byte{:0:20} for n > 0 { buf = append(buf, byte('0'+n%10)) n /= 10 } if neg { buf = append(buf, '-') } for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 { buf[i], buf[j] = buf[j], buf[i] } return string(buf) } func Contains(tokset uint64, tok Token) (ok bool) { var bit uint64 = 1 bit = bit << tok return tokset&bit != 0 } type Token uint32 const ( _ Token = iota EOF NameType Literal OperatorType AssignOp IncOp Assign Define Arrow Star Lparen Lbrack Lbrace Rparen Rbrack Rbrace Comma Semi Colon Dot DotDotDot Break Case Chan Const Continue Default Defer Else Fallthrough For Func Go Goto If Import Interface Map Package Range Return Select Struct Switch TypeType Var tokenCount ) const _ uint64 = 1 << (tokenCount - 1) type LitKind uint8 const ( IntLit LitKind = iota FloatLit ImagLit RuneLit StringLit ) type Operator uint32 const ( _ Operator = iota Def Not Recv Tilde OrOr AndAnd Eql Neq Lss Leq Gtr Geq Add Sub Or Xor Mul Div Rem And AndNot Shl Shr ) const ( _ = iota PrecOrOr PrecAndAnd PrecCmp PrecAdd PrecMul ) const token_name = "EOFnameliteralopop=opop=:=<-*([{)]},;:....breakcasechanconstcontinuedefaultdeferelsefallthroughforfuncgogotoifimportinterfacemappackagerangereturnselectstructswitchtypevar" func (i Token) String() (s string) { idx := [48]uint8{0, 3, 7, 14, 16, 19, 23, 24, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 42, 47, 51, 55, 60, 68, 75, 80, 84, 95, 98, 102, 104, 108, 110, 116, 125, 128, 135, 140, 146, 152, 158, 164, 168, 171, 171} i -= 1 if i >= Token(len(idx)-1) { return "token(" | Itoa64(int64(i+1)) | ")" } return token_name[idx[i]:idx[i+1]] } const _Operator_name = ":!<-~||&&==!=<<=>>=+-|^*/%&&^<<>>" func (i Operator) String() (s string) { idx := [24]uint8{0, 1, 2, 4, 5, 7, 9, 11, 13, 14, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 31, 33} i -= 1 if i >= Operator(len(idx)-1) { return "Operator(" | Itoa64(int64(i+1)) | ")" } return _Operator_name[idx[i]:idx[i+1]] } // --- AST nodes --- type File struct { Pragma Pragma PkgName *Name DeclList []Decl EOF Pos GoVersion string node } type node struct { pos Pos } func (n *node) Pos() (p Pos) { return n.pos } func (n *node) SetPos(pos Pos) { n.pos = pos } func (*node) aNode() {} type Node interface { Pos() Pos aNode() } type Decl interface { Node aDecl() } type decl struct{ node } func (*decl) aDecl() {} type ( ImportDecl struct { Group *Group Pragma Pragma LocalPkgName *Name Path *BasicLit decl } ConstDecl struct { Group *Group Pragma Pragma NameList []*Name Type Expr Values Expr decl } TypeDecl struct { Group *Group Pragma Pragma Name *Name TParamList []*Field Alias bool Type Expr decl } VarDecl struct { Group *Group Pragma Pragma NameList []*Name Type Expr Values Expr decl } FuncDecl struct { Pragma Pragma Recv *Field Name *Name TParamList []*Field Type *FuncType Body *BlockStmt decl } ) type Group struct { _ int32 } func NewName(pos Pos, value string) (n *Name) { n = &Name{} n.pos = pos n.Value = value return n } type Error struct { Pos Pos Msg string } func (err Error) Error() (s string) { return err.Msg } func String(n Node) (s string) { return "node" } func StartPos(n Node) (p Pos) { return n.Pos() } func dbg(s string) { if debug { out(s) } } type ( Expr interface { Node typeInfo aExpr() } BadExpr struct { expr } Name struct { Value string expr } BasicLit struct { Value string Kind LitKind Bad bool expr } CompositeLit struct { Type Expr ElemList []Expr NKeys int32 Rbrace Pos expr } KeyValueExpr struct { Key, Value Expr expr } FuncLit struct { Type *FuncType Body *BlockStmt expr } ParenExpr struct { X Expr expr } SelectorExpr struct { X Expr Sel *Name expr } IndexExpr struct { X Expr Index Expr expr } SliceExpr struct { X Expr Index [3]Expr Full bool expr } AssertExpr struct { X Expr Type Expr expr } TypeSwitchGuard struct { Lhs *Name X Expr expr } Operation struct { Op Operator X, Y Expr expr } CallExpr struct { Fun Expr ArgList []Expr HasDots bool expr } ListExpr struct { ElemList []Expr expr } ArrayType struct { Len Expr Elem Expr expr } SliceType struct { Elem Expr expr } DotsType struct { Elem Expr expr } StructType struct { FieldList []*Field TagList []*BasicLit expr } Field struct { Name *Name Type Expr node } InterfaceType struct { MethodList []*Field expr } FuncType struct { ParamList []*Field ResultList []*Field expr } MapType struct { Key, Value Expr expr } ChanType struct { Dir ChanDir Elem Expr expr } ) type Type interface { Underlying() Type String() string } type typeInfo interface { SetTypeInfo(TypeAndValue) GetTypeInfo() TypeAndValue } type ConstVal interface{ String() string } type TypeAndValue struct { Type Type Value ConstVal exprFlags } type exprFlags uint16 func (f exprFlags) IsVoid() (ok bool) { return f&1 != 0 } func (f exprFlags) IsType() (ok bool) { return f&2 != 0 } func (f exprFlags) IsBuiltin() (ok bool) { return f&4 != 0 } func (f exprFlags) IsValue() (ok bool) { return f&8 != 0 } func (f exprFlags) IsNil() (ok bool) { return f&16 != 0 } func (f exprFlags) Addressable() (ok bool) { return f&32 != 0 } func (f exprFlags) Assignable() (ok bool) { return f&64 != 0 } func (f exprFlags) HasOk() (ok bool) { return f&128 != 0 } func (f exprFlags) IsRuntimeHelper() (ok bool) { return f&256 != 0 } func (f *exprFlags) SetIsVoid() { *f |= 1 } func (f *exprFlags) SetIsType() { *f |= 2 } func (f *exprFlags) SetIsBuiltin() { *f |= 4 } func (f *exprFlags) SetIsValue() { *f |= 8 } func (f *exprFlags) SetIsNil() { *f |= 16 } func (f *exprFlags) SetAddressable() { *f |= 32 } func (f *exprFlags) SetAssignable() { *f |= 64 } func (f *exprFlags) SetHasOk() { *f |= 128 } func (f *exprFlags) SetIsRuntimeHelper() { *f |= 256 } type typeAndValue struct { tv TypeAndValue } func (x *typeAndValue) SetTypeInfo(tv TypeAndValue) { x.tv = tv } func (x *typeAndValue) GetTypeInfo() (t TypeAndValue) { return x.tv } type expr struct { node typeAndValue } func (*expr) aExpr() {} type ChanDir uint32 const ( _ ChanDir = iota SendOnly RecvOnly ) type ( Stmt interface { Node aStmt() } SimpleStmt interface { Stmt aSimpleStmt() } EmptyStmt struct { simpleStmt } LabeledStmt struct { Label *Name Stmt Stmt stmt } BlockStmt struct { List []Stmt Rbrace Pos stmt } ExprStmt struct { X Expr simpleStmt } SendStmt struct { Chan, Value Expr simpleStmt } DeclStmt struct { DeclList []Decl stmt } AssignStmt struct { Op Operator Lhs, Rhs Expr simpleStmt } BranchStmt struct { Tok Token Label *Name Target Stmt stmt } CallStmt struct { Tok Token Call Expr DeferAt Expr stmt } ReturnStmt struct { Results Expr stmt } IfStmt struct { Init SimpleStmt Cond Expr Then *BlockStmt Else Stmt stmt } ForStmt struct { Init SimpleStmt Cond Expr Post SimpleStmt Body *BlockStmt stmt } SwitchStmt struct { Init SimpleStmt Tag Expr Body []*CaseClause Rbrace Pos stmt } SelectStmt struct { Body []*CommClause Rbrace Pos stmt } ) type ( RangeClause struct { Lhs Expr Def bool X Expr simpleStmt } CaseClause struct { Cases Expr Body []Stmt Colon Pos node } CommClause struct { Comm SimpleStmt Body []Stmt Colon Pos node } ) type stmt struct{ node } func (stmt) aStmt() {} type simpleStmt struct { stmt } func (simpleStmt) aSimpleStmt() {} type CommentKind uint32 const ( Above CommentKind = iota Below Left Right ) type Comment struct { Kind CommentKind Text string Next *Comment } // --- parser --- const debug = false const trace = false type ErrorHandler func(err error) type PragmaHandler func(pos Pos, blank bool, text string, current Pragma) type Pragma interface{} type Mode uint32 type Parser struct { File *PosBase Errh ErrorHandler Mode Mode Pragh PragmaHandler Scanner Base *PosBase // current position base First error // first error encountered Errcnt int32 // number of errors encountered Pragma Pragma // pragmas GoVersion string // Go version from //go:build line Top bool // in top of file (before package clause) Fnest int32 // function nesting level (for error handling) Xnest int32 // expression nesting level (for complit ambiguity resolution) Indent []byte // tracing support } func (p *Parser) initBytes(File *PosBase, src []byte, Errh ErrorHandler, Pragh PragmaHandler, Mode Mode) { p.Top = true p.File = File p.Errh = Errh p.Mode = Mode p.Pragh = Pragh p.Scanner.InitBytes( src, func(line, col uint32, msg string) { if msg[0] != '/' { p.errorAt(p.posAt(line, col), msg) return } text := commentText(msg) if (col == Colbase || msg[1] == '*') && bytesHasPrefix(text, "line ") { var pos Pos if msg[1] == '/' { pos = MakePos(p.File, line+1, Colbase) } else { pos = MakePos(p.File, line, col+uint32(len(msg))) } p.updateBase(pos, line, col+2+5, text[5:]) return } if bytesHasPrefix(text, "go:") || bytesHasPrefix(text, ":") { if Pragh != nil { Pragh(p.posAt(line, col+2), p.Scanner.Blank, text, p.Pragma) } } else if bytesHasPrefix(text, "export ") { if Pragh != nil { Pragh(p.posAt(line, col+2), p.Scanner.Blank, text, p.Pragma) } } }, comments, ) p.Base = File p.First = nil p.Errcnt = 0 p.Pragma = nil p.Fnest = 0 p.Xnest = 0 p.Indent = nil } // takePragma returns the current parsed pragmas // and clears them from the parser state. func (p *Parser) takePragma() (pv Pragma) { prag := p.Pragma p.Pragma = nil return prag } // clearPragma is called at the end of a statement or // other Go form that does NOT accept a pragma. // It sends the pragma back to the pragma handler // to be reported as unused. func (p *Parser) clearPragma() { if p.Pragma != nil { p.Pragh(p.pos(), p.Scanner.Blank, "", p.Pragma) p.Pragma = nil } } // updateBase sets the current position base to a new line base at pos. // The base's filename, line, and column values are extracted from text // which is positioned at (tline, tcol) (only needed for error messages). func (p *Parser) updateBase(pos Pos, tline, tcol uint32, text string) { i, n, ok := trailingDigits(text) if i == 0 { return // ignore (not a line directive) } // i > 0 if !ok { // text has a suffix :xxx but xxx is not a number p.errorAt(p.posAt(tline, tcol+i), "invalid line number: " | text[i:]) return } var line, col uint32 i2, n2, ok2 := trailingDigits(text[:i-1]) if ok2 { //line filename:line:col i, i2 = i2, i line, col = n2, n if col == 0 || col > PosMax { p.errorAt(p.posAt(tline, tcol+i2), "invalid column number: " | text[i2:]) return } text = text[:i2-1] // lop off ":col" } else { //line filename:line line = n } if line == 0 || line > PosMax { p.errorAt(p.posAt(tline, tcol+i), "invalid line number: " | text[i:]) return } // If we have a column (//line filename:line:col form), // an empty filename means to use the previous filename. filename := text[:i-1] // lop off ":line" trimmed := false if filename == "" && ok2 { filename = p.Base.Filename() trimmed = p.Base.Trimmed() } p.Base = NewLineBase(pos, filename, trimmed, line, col) } func commentText(s string) (sv string) { if s[:2] == "/*" { return s[2 : len(s)-2] // lop off /* and */ } // line comment (does not include newline) // (on Windows, the line comment may end in \r\n) i := len(s) if s[i-1] == '\r' { i-- } return s[2:i] // lop off //, and \r at end, if any } func trailingDigits(text string) (uint32, uint32, bool) { i := bytesLastIndexByte(text, ':') if i < 0 { return 0, 0, false } s := text[i+1:] if len(s) == 0 { return 0, 0, false } var n uint32 for j := 0; j < len(s); j++ { c := s[j] if c < '0' || c > '9' { return 0, 0, false } n = n*10 + uint32(c-'0') } return uint32(i | 1), n, true } func (p *Parser) got(tok Token) (ok bool) { if p.Tok == tok { p.Next() return true } return false } func (p *Parser) want(tok Token) { if !p.got(tok) { p.syntaxError("expected " | tokstring(tok)) p.advance() } } // gotAssign is like got(_Assign) but it also accepts ":=" // (and reports an error) for better parser error recovery. func (p *Parser) gotAssign() (ok bool) { switch p.Tok { case Define: p.syntaxError("expected =") p.Next() return true case Assign: p.Next() return true } return false } // ---------------------------------------------------------------------------- // Error handling // posAt returns the Pos value for (line, col) and the current position base. func (p *Parser) posAt(line, col uint32) (pv Pos) { return MakePos(p.Base, line, col) } // errorAt reports an error at the given position. func (p *Parser) errorAt(pos Pos, msg string) { if len(msg) == 0 { return } err := Error{pos, msg} if p.First == nil { p.First = err } p.Errcnt++ if p.Errh == nil { panic(p.First) } p.Errh(err) } // syntaxErrorAt reports a syntax error at the given position. func (p *Parser) syntaxErrorAt(pos Pos, msg string) { if trace { p.print("syntax error: " | msg) } if p.Tok == EOF && p.First != nil { return // avoid meaningless follow-up errors } // add punctuation etc. as needed to msg switch { case msg == "": // nothing case bytesHasPrefix(msg, "in "), bytesHasPrefix(msg, "at "), bytesHasPrefix(msg, "after "): msg = " " | msg case bytesHasPrefix(msg, "expected "): msg = ", " | msg default: p.errorAt(pos, "syntax error: " | msg) return } // determine token string var tok string switch p.Tok { case NameType: tok = "name " | p.Lit case Semi: tok = p.Lit case Literal: tok = "literal " | p.Lit case OperatorType: tok = p.Op.String() case AssignOp: tok = p.Op.String() | "=" case IncOp: tok = p.Op.String() tok = tok | tok default: tok = tokstring(p.Tok) } p.errorAt(pos, "syntax error: unexpected " | tok | msg) } // tokstring returns the English word for selected punctuation tokens // for more readable error messages. Use tokstring (not tok.String()) // for user-facing (error) messages; use tok.String() for debugging // output. func tokstring(tok Token) (s string) { switch tok { case Comma: return "comma" case Semi: return "semicolon or newline" } s = tok.String() if Break <= tok && tok <= Var { return "keyword " | s } return s } // Convenience methods using the current token position. func (p *Parser) pos() (pv Pos) { return p.posAt(p.Line-Linebase, p.Col-Colbase) } func (p *Parser) error(msg string) { p.errorAt(p.pos(), msg) } func (p *Parser) syntaxError(msg string) { p.syntaxErrorAt(p.pos(), msg) } // The stopset contains keywords that start a statement. // They are good synchronization points in case of syntax // errors and (usually) shouldn't be skipped over. const stopset uint64 = 1< 0). // The followlist is the list of valid tokens that can follow a production; // if it is empty, exactly one (non-EOF) token is consumed to ensure progress. func (p *Parser) advance(followlist ...Token) { if trace { p.print("advance") } // compute follow set // (not speed critical, advance is only called in error situations) var followset uint64 = 1 << EOF // don't skip over EOF if len(followlist) > 0 { if p.Fnest > 0 { followset |= stopset } for _, tok := range followlist { var bit uint64 = 1 followset |= bit << tok } } for !Contains(followset, p.Tok) { if trace { p.print("skip " | p.Tok.String()) } p.Next() if len(followlist) == 0 { break } } if trace { p.print("next " | p.Tok.String()) } } // usage: defer p.trace(msg)() func (p *Parser) trace(msg string) (fn func()) { p.print(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 } p.print(")") } } func (p *Parser) print(msg string) { // trace is const false; this is dead code but must type-check _ = Itoa(int32(p.line)) | ": " | p.Indent | msg | "\n" } // ---------------------------------------------------------------------------- // 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. // // Excluding methods returning slices, parse methods named xOrNil may return // nil; all others are expected to return a valid non-nil node. // SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } . func (p *Parser) fileOrNil() (f *File) { if trace { defer p.trace("file")() } f = &File{} f.pos = p.pos() // PackageClause f.GoVersion = p.GoVersion p.Top = false if !p.got(Package) { p.syntaxError("package statement must be first") return nil } f.Pragma = p.takePragma() f.PkgName = p.name() p.want(Semi) // don't bother continuing if package clause has errors if p.First != nil { return nil } // Accept import declarations anywhere for error tolerance, but complain. // { ( ImportDecl | TopLevelDecl ) ";" } prev := Import for p.Tok != EOF { if p.Tok == Import && prev != Import { p.syntaxError("imports must appear before other declarations") } prev = p.Tok switch p.Tok { case Import: p.Next() f.DeclList = p.appendGroup(f.DeclList, p.importDecl) case Const: p.Next() f.DeclList = p.appendGroup(f.DeclList, p.constDecl) case TypeType: p.Next() f.DeclList = p.appendGroup(f.DeclList, p.typeDecl) case Var: p.Next() f.DeclList = p.appendGroup(f.DeclList, p.varDecl) case Func: p.Next() fd := &FuncDecl{} fd.pos = p.pos() if p.got(Lparen) { rcvr := p.paramList(nil, nil, Rparen, false, false) if len(rcvr) > 0 { fd.Recv = rcvr[0] } } if p.Tok == NameType { fd.Name = p.name() fd.TParamList, fd.Type = p.funcType("") } if p.Tok == Lbrace { fd.Body = p.funcBody() } f.DeclList = append(f.DeclList, fd) default: if p.Tok == Lbrace && len(f.DeclList) > 0 && isEmptyFuncDecl(f.DeclList[len(f.DeclList)-1]) { // opening { of function declaration on next line p.syntaxError("unexpected semicolon or newline before {") } else { p.syntaxError("non-declaration statement outside function body") } p.advance(Import, Const, TypeType, Var, Func) continue } // Reset p.pragma BEFORE advancing to the next token (consuming ';') // since comments before may set pragmas for the next function decl. p.clearPragma() if p.Tok != EOF && !p.got(Semi) { p.syntaxError("after top level declaration") p.advance(Import, Const, TypeType, Var, Func) } } // p.tok == _EOF p.clearPragma() f.EOF = p.pos() return f } func isEmptyFuncDecl(dcl Decl) (ok bool) { f, ok := dcl.(*FuncDecl) return ok && f.Body == nil } // ---------------------------------------------------------------------------- // Declarations // list parses a possibly empty, sep-separated list of elements, optionally // followed by sep, and closed by close (or EOF). sep must be one of _Comma // or _Semi, and close must be one of _Rparen, _Rbrace, or _Rbrack. // // For each list element, f is called. Specifically, unless we're at close // (or EOF), f is called at least once. After f returns true, no more list // elements are accepted. list returns the position of the closing // // list = [ f { sep f } [sep] ] close . func (p *Parser) list(context string, sep, close Token, f func() bool) (pv Pos) { if debug && (sep != Comma && sep != Semi || close != Rparen && close != Rbrace && close != Rbrack) { panic("invalid sep or close argument for list") } done := false for p.Tok != EOF && p.Tok != close && !done { done = f() // sep is optional before close if !p.got(sep) && p.Tok != close { p.syntaxError("in " | context | "; possibly missing " | tokstring(sep) | " or " | tokstring(close)) p.advance(Rparen, Rbrack, Rbrace) if p.Tok != close { // position could be better but we had an error so we don't care return p.pos() } } } pos := p.pos() p.want(close) return pos } // appendGroup(f) = f + "(" { f ";" } ")" . // ";" is optional before ")" func (p *Parser) appendGroup(list []Decl, f func(*Group) Decl) (ds []Decl) { if p.Tok == Lparen { g := &Group{} p.clearPragma() p.Next() // must consume "(" after calling clearPragma! p.list("grouped declaration", Semi, Rparen, func() bool { if x := f(g); x != nil { list = append(list, x) } return false }) } else { if x := f(nil); x != nil { list = append(list, x) } } return list } // ImportSpec = [ "." + PackageName ] ImportPath . // ImportPath = string_lit . func (p *Parser) importDecl(group *Group) Decl { if trace { defer p.trace("importDecl")() } d := &ImportDecl{} d.pos = p.pos() d.Group = group d.Pragma = p.takePragma() switch p.Tok { case NameType: n := p.name() if n.Value == "_" { p.syntaxErrorAt(n.Pos(), "blank imports are not allowed in Moxie") } d.LocalPkgName = n case Dot: d.LocalPkgName = NewName(p.pos(), ".") p.Next() } d.Path = p.oliteral() if d.Path == nil { p.syntaxError("missing import path") p.advance(Semi, Rparen) return d } if !d.Path.Bad && d.Path.Kind != StringLit { p.syntaxErrorAt(d.Path.Pos(), "import path must be a string") d.Path.Bad = true } // d.Path.Bad || d.Path.Kind == StringLit return d } // ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] . func (p *Parser) constDecl(group *Group) Decl { if trace { defer p.trace("constDecl")() } d := &ConstDecl{} d.pos = p.pos() d.Group = group d.Pragma = p.takePragma() d.NameList = p.nameList(p.name()) if p.Tok != EOF && p.Tok != Semi && p.Tok != Rparen { d.Type = p.typeOrNil() if p.gotAssign() { d.Values = p.exprList() } } return d } // TypeSpec = identifier [ TypeParams ] [ "=" ] Type . func (p *Parser) typeDecl(group *Group) Decl { if trace { defer p.trace("typeDecl")() } d := &TypeDecl{} d.pos = p.pos() d.Group = group d.Pragma = p.takePragma() d.Name = p.name() if p.Tok == Lbrack { // d.Name "[" ... // array/slice type or type parameter list pos := p.pos() p.Next() switch p.Tok { case NameType: // We may have an array type or a type parameter list. // In either case we expect an expression x (which may // just be a name, or a more complex expression) which // we can analyze further. // // A type parameter list may have a type bound starting // with a "[" as in: P []E. In that case, simply parsing // an expression would lead to an error: P[] is invalid. // But since index or slice expressions are never constant // and thus invalid array length expressions, if the name // is followed by "[" it must be the start of an array or // slice constraint. Only if we don't see a "[" do we // need to parse a full expression. Notably, name <- x // is not a concern because name <- x is a statement and // not an expression. var x Expr = p.name() if p.Tok != Lbrack { // To parse the expression starting with name, expand // the call sequence we would get by passing in name // to parser.expr, and pass in name to parser.pexpr. p.Xnest++ x = p.binaryExpr(p.pexpr(x, false), 0) p.Xnest-- } // Analyze expression x. If we can split x into a type parameter // name, possibly followed by a type parameter type, we consider // this the start of a type parameter list, with some caveats: // a single name followed by "]" tilts the decision towards an // array declaration; a type parameter type that could also be // an ordinary expression but which is followed by a comma tilts // the decision towards a type parameter list. if pname, ptype := extractName(x, p.Tok == Comma); pname != nil && (ptype != nil || p.Tok != Rbrack) { // d.Name "[" pname ... // d.Name "[" pname ptype ... // d.Name "[" pname ptype "," ... d.TParamList = p.paramList(pname, ptype, Rbrack, true, false) // ptype may be nil d.Alias = p.gotAssign() d.Type = p.typeOrNil() } else { // d.Name "[" pname "]" ... // d.Name "[" x ... d.Type = p.arrayType(pos, x) } case Rbrack: // d.Name "[" "]" ... p.Next() d.Type = p.sliceType(pos) default: // d.Name "[" ... d.Type = p.arrayType(pos, nil) } } else { d.Alias = p.gotAssign() d.Type = p.typeOrNil() } if d.Type == nil { d.Type = p.badExpr() p.syntaxError("in type declaration") p.advance(Semi, Rparen) } return d } // extractName splits the expression x into (name, expr) if syntactically // x can be written as name expr. The split only happens if expr is a type // element (per the isTypeElem predicate) or if force is set. // If x is just a name, the result is (name, nil). If the split succeeds, // the result is (name, expr). Otherwise the result is (nil, x). // Examples: // // x force name expr // ------------------------------------ // P*[]int32 T/F P *[]int32 // P*E T P *E // P*E F nil P*E // P([]int32) T/F P []int32 // P(E) T P E // P(E) F nil P(E) // P*E|F|~G T/F P *E|F|~G // P*E|F|G T P *E|F|G // P*E|F|G F nil P*E|F|G func extractName(x Expr, force bool) (*Name, Expr) { switch x := x.(type) { case *Name: return x, nil case *Operation: if x.Y == nil { break // unary expr } switch x.Op { case Mul: if name, _ := x.X.(*Name); name != nil && (force || isTypeElem(x.Y)) { // x = name *x.Y op := *x op.X, op.Y = op.Y, nil // change op into unary *op.Y return name, &op } case Or: if name, lhs := extractName(x.X, force || isTypeElem(x.Y)); name != nil && lhs != nil { // x = name lhs|x.Y op := *x op.X = lhs return name, &op } } case *CallExpr: if name, _ := x.Fun.(*Name); name != nil { if len(x.ArgList) == 1 && !x.HasDots && (force || isTypeElem(x.ArgList[0])) { // The parser doesn't keep unnecessary parentheses. // Set the flag below to keep them, for testing // (see go.dev/issues/69206). const keep_parens = false if keep_parens { // x = name (x.ArgList[0]) px := &ParenExpr{} px.pos = x.pos // position of "(" in call px.X = x.ArgList[0] return name, px } else { // x = name x.ArgList[0] return name, Unparen(x.ArgList[0]) } } } } return nil, x } // isTypeElem reports whether x is a (possibly parenthesized) type element expression. // The result is false if x could be a type element OR an ordinary (value) expression. func isTypeElem(x Expr) (ok bool) { switch x := x.(type) { case *ArrayType, *StructType, *FuncType, *InterfaceType, *SliceType, *MapType, *ChanType: return true case *Operation: return isTypeElem(x.X) || (x.Y != nil && isTypeElem(x.Y)) || x.Op == Tilde case *ParenExpr: return isTypeElem(x.X) } return false } // VarSpec = IdentifierList ( Type [ "=" ExpressionList ] + "=" ExpressionList ) . func (p *Parser) varDecl(group *Group) Decl { if trace { defer p.trace("varDecl")() } d := &VarDecl{} d.pos = p.pos() d.Group = group d.Pragma = p.takePragma() d.NameList = p.nameList(p.name()) if p.gotAssign() { d.Values = p.exprList() } else { d.Type = p.type_() if p.gotAssign() { d.Values = p.exprList() } } return d } // FunctionDecl = "func" FunctionName [ TypeParams ] ( Function | Signature ) . // FunctionName = identifier . // Function = Signature FunctionBody . // MethodDecl = "func" Receiver MethodName ( Function | Signature ) . // Receiver = Parameters . func (p *Parser) funcDeclOrNil() (f *FuncDecl) { if trace { defer p.trace("funcDecl")() } f = &FuncDecl{} f.pos = p.pos() f.Pragma = p.takePragma() var context string if p.got(Lparen) { context = "method" rcvr := p.paramList(nil, nil, Rparen, false, false) switch len(rcvr) { case 0: p.error("method has no receiver") default: p.error("method has multiple receivers") f.Recv = rcvr[0] case 1: f.Recv = rcvr[0] } } if p.Tok == NameType { f.Name = p.name() f.TParamList, f.Type = p.funcType(context) } else { dbg("funcDecl: not a name, falling to error\n") f.Name = NewName(p.pos(), "_") f.Type = &FuncType{} f.Type.pos = p.pos() msg := "expected name or (" if context != "" { msg = "expected name" } p.syntaxError(msg) p.advance(Lbrace, Semi) } if p.Tok == Lbrace { f.Body = p.funcBody() } return f } func (p *Parser) funcBody() (b *BlockStmt) { p.Fnest++ body := p.blockStmt("") p.Fnest-- return body } // ---------------------------------------------------------------------------- // Expressions func (p *Parser) expr() (e Expr) { if trace { defer p.trace("expr")() } return p.binaryExpr(nil, 0) } // Expression = UnaryExpr | Expression binary_op Expression . func (p *Parser) binaryExpr(x Expr, prec int32) (e Expr) { // don't trace binaryExpr - only leads to overly nested trace output if x == nil { x = p.unaryExpr() } for (p.Tok == OperatorType || p.Tok == Star) && p.Prec > prec { t := &Operation{} t.pos = p.pos() t.Op = p.Op tprec := p.Prec p.Next() t.X = x t.Y = p.binaryExpr(nil, tprec) x = t } return x } // UnaryExpr = PrimaryExpr | unary_op UnaryExpr . func (p *Parser) unaryExpr() (e Expr) { if trace { defer p.trace("unaryExpr")() } switch p.Tok { case OperatorType, Star: switch p.Op { case Mul, Add, Sub, Not, Xor, Tilde: x := &Operation{} x.pos = p.pos() x.Op = p.Op p.Next() x.X = p.unaryExpr() return x case And: x := &Operation{} x.pos = p.pos() x.Op = And p.Next() // unaryExpr may have returned a parenthesized composite literal // (see comment in operand) - remove parentheses if any x.X = Unparen(p.unaryExpr()) return x } case Arrow: // receive op (<-x) or receive-only channel (<-chan E) pos := p.pos() p.Next() // If the next token is _Chan we still don't know if it is // a channel (<-chan int32) or a receive op (<-chan int32(ch)). // We only know once we have found the end of the unaryExpr. x := p.unaryExpr() // 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 _, ok := x.(*ChanType); ok { // x is a channel type => re-associate <- dir := SendOnly t := x for dir == SendOnly { c, ok := t.(*ChanType) if !ok { break } dir = c.Dir if dir == RecvOnly { // t is type <-chan E but <-<-chan E is not permitted // (report same error as for "type _ <-<-chan E") p.syntaxError("unexpected <-, expected chan") // already progressed, no need to advance } c.Dir = RecvOnly t = c.Elem } if dir == SendOnly { // channel dir is <- but channel element E is not a channel // (report same error as for "type _ <-chan<-E") p.syntaxError("unexpected " | String(t) | ", expected chan") // already progressed, no need to advance } return x } // x is not a channel type => we have a receive op o := &Operation{} o.pos = pos o.Op = Recv o.X = x return o } // TODO(mdempsky): We need parens here so we can report an // error for "(x) := true". It should be possible to detect // and reject that more efficiently though. return p.pexpr(nil, true) } // callStmt parses call-like statements that can be preceded by 'defer' and 'go'. func (p *Parser) callStmt() (c *CallStmt) { if trace { defer p.trace("callStmt")() } s := &CallStmt{} s.pos = p.pos() s.Tok = p.Tok // _Defer or _Go p.Next() x := p.pexpr(nil, p.Tok == Lparen) // keep_parens so we can report error below if t := Unparen(x); t != x { p.errorAt(x.Pos(), "expression in " | s.Tok.String() | " must not be parenthesized") // already progressed, no need to advance x = t } s.Call = x return s } // 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) (e Expr) { if trace { defer p.trace("operand " | p.Tok.String())() } switch p.Tok { case NameType: return p.name() case Literal: return p.oliteral() case Lparen: pos := p.pos() p.Next() p.Xnest++ x := p.expr() p.Xnest-- p.want(Rparen) // 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 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 == Lbrace { 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 { px := &ParenExpr{} px.pos = pos px.X = x x = px } return x case Func: pos := p.pos() p.Next() _, ftyp := p.funcType("function type") if p.Tok == Lbrace { p.Xnest++ f := &FuncLit{} f.pos = pos f.Type = ftyp f.Body = p.funcBody() p.Xnest-- return f } return ftyp case Lbrack, Chan, Map, Struct, Interface: return p.type_() // othertype default: x := p.badExpr() p.syntaxError("expected expression") p.advance(Rparen, Rbrack, Rbrace) return x } // 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). } // pexpr parses a PrimaryExpr. // // 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(x Expr, keep_parens bool) (e Expr) { if trace { defer p.trace("pexpr")() } if x == nil { x = p.operand(keep_parens) } loop: for { pos := p.pos() switch p.Tok { case Dot: p.Next() switch p.Tok { case NameType: // pexpr '.' sym t := &SelectorExpr{} t.pos = pos t.X = x t.Sel = p.name() x = t case Lparen: p.Next() if p.got(TypeType) { t := &TypeSwitchGuard{} // t.Lhs is filled in by parser.simpleStmt t.pos = pos t.X = x x = t } else { t := &AssertExpr{} t.pos = pos t.X = x t.Type = p.type_() x = t } p.want(Rparen) default: p.syntaxError("expected name or (") p.advance(Semi, Rparen) } case Lbrack: p.Next() var i Expr if p.Tok != Colon { var comma bool if p.Tok == Rbrack { // invalid empty instance, slice or index expression; accept but complain p.syntaxError("expected operand") i = p.badExpr() } else { i, comma = p.typeList(false) } if comma || p.Tok == Rbrack { p.want(Rbrack) // x[], x[i,] or x[i, j, ...] t := &IndexExpr{} t.pos = pos t.X = x t.Index = i x = t break } } // x[i:... // For better error message, don't simply use p.want(_Colon) here (go.dev/issue/47704). if !p.got(Colon) { p.syntaxError("expected comma, : or ]") p.advance(Comma, Colon, Rbrack) } p.Xnest++ t := &SliceExpr{} t.pos = pos t.X = x t.Index[0] = i if p.Tok != Colon && p.Tok != Rbrack { // x[i:j... t.Index[1] = p.expr() } if p.Tok == Colon { t.Full = true // x[i:j:...] if t.Index[1] == nil { p.error("middle index required in 3-index slice") t.Index[1] = p.badExpr() } p.Next() if p.Tok != Rbrack { // x[i:j:k... t.Index[2] = p.expr() } else { p.error("final index required in 3-index slice") t.Index[2] = p.badExpr() } } p.Xnest-- p.want(Rbrack) x = t case Lparen: t := &CallExpr{} t.pos = pos p.Next() t.Fun = x t.ArgList, t.HasDots = p.argList() x = t case Lbrace: // 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 composite literal or a block statement complit_ok := false switch t.(type) { case *Name, *SelectorExpr: if p.Xnest >= 0 { // x is possibly a composite literal type complit_ok = true } case *IndexExpr: if p.Xnest >= 0 && !isValue(t) { // x is possibly a composite literal type complit_ok = true } case *ArrayType, *SliceType, *StructType, *MapType: // x is a comptype complit_ok = true } if !complit_ok { break loop } if t != x { p.syntaxError("cannot parenthesize type in composite literal") // already progressed, no need to advance } n := p.complitexpr() n.Type = x x = n default: break loop } } return x } // isValue reports whether x syntactically must be a value (and not a type) expression. func isValue(x Expr) (ok bool) { switch x := x.(type) { case *BasicLit, *CompositeLit, *FuncLit, *SliceExpr, *AssertExpr, *TypeSwitchGuard, *CallExpr: return true case *Operation: return x.Op != Mul || x.Y != nil // *T may be a type case *ParenExpr: return isValue(x.X) case *IndexExpr: return isValue(x.X) || isValue(x.Index) } return false } // Element = Expression | LiteralValue . func (p *Parser) bare_complitexpr() (e Expr) { if trace { defer p.trace("bare_complitexpr")() } if p.Tok == Lbrace { // '{' start_complit braced_keyval_list '}' return p.complitexpr() } return p.expr() } // LiteralValue = "{" [ ElementList [ "," ] ] "}" . func (p *Parser) complitexpr() (c *CompositeLit) { if trace { defer p.trace("complitexpr")() } x := &CompositeLit{} x.pos = p.pos() p.Xnest++ p.want(Lbrace) x.Rbrace = p.list("composite literal", Comma, Rbrace, func() bool { // value e := p.bare_complitexpr() if p.Tok == Colon { // key ':' value l := &KeyValueExpr{} l.pos = p.pos() p.Next() l.Key = e l.Value = p.bare_complitexpr() e = l x.NKeys++ } x.ElemList = append(x.ElemList, e) return false }) p.Xnest-- return x } // ---------------------------------------------------------------------------- // Types func (p *Parser) type_() (e Expr) { if trace { defer p.trace("type_")() } typ := p.typeOrNil() if typ == nil { typ = p.badExpr() p.syntaxError("expected type") p.advance(Comma, Colon, Semi, Rparen, Rbrack, Rbrace) } return typ } func newIndirect(pos Pos, typ Expr) (e Expr) { o := &Operation{} o.pos = pos o.Op = Mul o.X = typ return o } // typeOrNil is like type_ 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 | Channel_Type . func (p *Parser) typeOrNil() (e Expr) { if trace { defer p.trace("typeOrNil")() } pos := p.pos() switch p.Tok { case Star: // ptrtype p.Next() return newIndirect(pos, p.type_()) case Arrow: // recvchantype p.Next() p.want(Chan) t := &ChanType{} t.pos = pos t.Dir = RecvOnly t.Elem = p.chanElem() return t case Func: // fntype p.Next() _, t := p.funcType("function type") return t case Lbrack: // '[' oexpr ']' ntype // '[' _DotDotDot ']' ntype p.Next() if p.got(Rbrack) { return p.sliceType(pos) } return p.arrayType(pos, nil) case Chan: // _Chan non_recvchantype // _Chan _Comm ntype p.Next() t := &ChanType{} t.pos = pos if p.got(Arrow) { t.Dir = SendOnly } t.Elem = p.chanElem() return t case Map: // _Map '[' ntype ']' ntype p.Next() p.want(Lbrack) t := &MapType{} t.pos = pos t.Key = p.type_() p.want(Rbrack) t.Value = p.type_() return t case Struct: return p.structType() case Interface: return p.interfaceType() case NameType: return p.qualifiedName(nil) case Lparen: p.Next() t := p.type_() p.want(Rparen) // The parser doesn't keep unnecessary parentheses. // Set the flag below to keep them, for testing // (see e.g. tests for go.dev/issue/68639). const keep_parens = false if keep_parens { px := &ParenExpr{} px.pos = pos px.X = t t = px } return t } return nil } func (p *Parser) typeInstance(typ Expr) (e Expr) { if trace { defer p.trace("typeInstance")() } pos := p.pos() p.want(Lbrack) x := &IndexExpr{} x.pos = pos x.X = typ if p.Tok == Rbrack { p.syntaxError("expected type argument list") x.Index = p.badExpr() } else { x.Index, _ = p.typeList(true) } p.want(Rbrack) return x } // If context != "", type parameters are not permitted. func (p *Parser) funcType(context string) ([]*Field, *FuncType) { if trace { defer p.trace("funcType")() } typ := &FuncType{} typ.pos = p.pos() var tparamList []*Field if p.got(Lbrack) { if context != "" { // accept but complain p.syntaxErrorAt(typ.pos, context | " must have no type parameters") } if p.Tok == Rbrack { p.syntaxError("empty type parameter list") p.Next() } else { tparamList = p.paramList(nil, nil, Rbrack, true, false) } } p.want(Lparen) typ.ParamList = p.paramList(nil, nil, Rparen, false, true) typ.ResultList = p.funcResult() return tparamList, typ } // "[" has already been consumed, and pos is its position. // If len != nil it is the already consumed array length. func (p *Parser) arrayType(pos Pos, len Expr) (e Expr) { if trace { defer p.trace("arrayType")() } if len == nil && !p.got(DotDotDot) { p.Xnest++ len = p.expr() p.Xnest-- } if p.Tok == Comma { // Trailing commas are accepted in type parameter // lists but not in array type declarations. // Accept for better error handling but complain. p.syntaxError("unexpected comma; expected ]") p.Next() } p.want(Rbrack) t := &ArrayType{} t.pos = pos t.Len = len t.Elem = p.type_() return t } // "[" and "]" have already been consumed, and pos is the position of "[". func (p *Parser) sliceType(pos Pos) (e Expr) { t := &SliceType{} t.pos = pos t.Elem = p.type_() return t } func (p *Parser) chanElem() (e Expr) { if trace { defer p.trace("chanElem")() } typ := p.typeOrNil() if typ == nil { typ = p.badExpr() p.syntaxError("missing channel element type") // assume element type is simply absent - don't advance } return typ } // StructType = "struct" "{" { FieldDecl ";" } "}" . func (p *Parser) structType() (s *StructType) { if trace { defer p.trace("structType")() } typ := &StructType{} typ.pos = p.pos() p.want(Struct) p.want(Lbrace) p.list("struct type", Semi, Rbrace, func() bool { p.fieldDecl(typ) return false }) return typ } // InterfaceType = "interface" "{" { ( MethodDecl | EmbeddedElem ) ";" } "}" . func (p *Parser) interfaceType() (i *InterfaceType) { if trace { defer p.trace("interfaceType")() } typ := &InterfaceType{} typ.pos = p.pos() p.want(Interface) p.want(Lbrace) p.list("interface type", Semi, Rbrace, func() bool { var f *Field if p.Tok == NameType { f = p.methodDecl() } if f == nil || f.Name == nil { f = p.embeddedElem(f) } typ.MethodList = append(typ.MethodList, f) return false }) return typ } // Result = Parameters | Type . func (p *Parser) funcResult() (fs []*Field) { if trace { defer p.trace("funcResult")() } if p.got(Lparen) { return p.paramList(nil, nil, Rparen, false, false) } pos := p.pos() if typ := p.typeOrNil(); typ != nil { f := &Field{} f.pos = pos f.Type = typ return []*Field{f} } return nil } func (p *Parser) addField(styp *StructType, pos Pos, name *Name, typ Expr, tag *BasicLit) { if tag != nil { for i := len(styp.FieldList) - len(styp.TagList); i > 0; i-- { styp.TagList = append(styp.TagList, nil) } styp.TagList = append(styp.TagList, tag) } f := &Field{} f.pos = pos f.Name = name f.Type = typ styp.FieldList = append(styp.FieldList, f) if debug && tag != nil && len(styp.FieldList) != len(styp.TagList) { panic("inconsistent struct field list") } } // FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] . // AnonymousField = [ "*" ] TypeName . // Tag = string_lit . func (p *Parser) fieldDecl(styp *StructType) { if trace { defer p.trace("fieldDecl")() } pos := p.pos() switch p.Tok { case NameType: name := p.name() if p.Tok == Dot || p.Tok == Literal || p.Tok == Semi || p.Tok == Rbrace { // embedded type typ := p.qualifiedName(name) tag := p.oliteral() p.addField(styp, pos, nil, typ, tag) break } // name1, name2, ... Type [ tag ] names := p.nameList(name) var typ Expr // Careful dance: We don't know if we have an embedded instantiated // type T[P1, P2, ...] or a field T of array/slice type [P]E or []E. if len(names) == 1 && p.Tok == Lbrack { typ = p.arrayOrTArgs() if typ, ok := typ.(*IndexExpr); ok { // embedded type T[P1, P2, ...] typ.X = name // name == names[0] tag := p.oliteral() p.addField(styp, pos, nil, typ, tag) break } } else { // T P typ = p.type_() } tag := p.oliteral() for _, name := range names { p.addField(styp, name.Pos(), name, typ, tag) } case Star: p.Next() var typ Expr if p.Tok == Lparen { // *(T) p.syntaxError("cannot parenthesize embedded type") p.Next() typ = p.qualifiedName(nil) p.got(Rparen) // no need to complain if missing } else { // *T typ = p.qualifiedName(nil) } tag := p.oliteral() p.addField(styp, pos, nil, newIndirect(pos, typ), tag) case Lparen: p.syntaxError("cannot parenthesize embedded type") p.Next() var typ Expr if p.Tok == Star { // (*T) pos := p.pos() p.Next() typ = newIndirect(pos, p.qualifiedName(nil)) } else { // (T) typ = p.qualifiedName(nil) } p.got(Rparen) // no need to complain if missing tag := p.oliteral() p.addField(styp, pos, nil, typ, tag) default: p.syntaxError("expected field name or embedded type") p.advance(Semi, Rbrace) } } func (p *Parser) arrayOrTArgs() (e Expr) { if trace { defer p.trace("arrayOrTArgs")() } pos := p.pos() p.want(Lbrack) if p.got(Rbrack) { return p.sliceType(pos) } // x [n]E or x[n,], x[n1, n2], ... n, comma := p.typeList(false) p.want(Rbrack) if !comma { if elem := p.typeOrNil(); elem != nil { // x [n]E t := &ArrayType{} t.pos = pos t.Len = n t.Elem = elem return t } } // x[n,], x[n1, n2], ... t := &IndexExpr{} t.pos = pos // t.X will be filled in by caller t.Index = n return t } func (p *Parser) oliteral() (b *BasicLit) { if p.Tok == Literal { b = &BasicLit{} b.pos = p.pos() b.Value = p.Lit b.Kind = p.Kind b.Bad = p.Bad p.Next() return b } return nil } // MethodSpec = MethodName Signature | InterfaceTypeName . // MethodName = identifier . // InterfaceTypeName = TypeName . func (p *Parser) methodDecl() (f *Field) { if trace { defer p.trace("methodDecl")() } f = &Field{} f.pos = p.pos() name := p.name() const context = "interface method" switch p.Tok { case Lparen: // method f.Name = name _, f.Type = p.funcType(context) case Lbrack: // Careful dance: We don't know if we have a generic method m[T C](x T) // or an embedded instantiated type T[P1, P2] (we accept generic methods // for generality and robustness of parsing but complain with an error). pos := p.pos() p.Next() // Empty type parameter or argument lists are not permitted. // Treat as if [] were absent. if p.Tok == Rbrack { // name[] pos := p.pos() p.Next() if p.Tok == Lparen { // name[]( p.errorAt(pos, "empty type parameter list") f.Name = name _, f.Type = p.funcType(context) } else { p.errorAt(pos, "empty type argument list") f.Type = name } break } // A type argument list looks like a parameter list with only // types. Parse a parameter list and decide afterwards. list := p.paramList(nil, nil, Rbrack, false, false) if len(list) == 0 { // The type parameter list is not [] but we got nothing // due to other errors (reported by paramList). Treat // as if [] were absent. if p.Tok == Lparen { f.Name = name _, f.Type = p.funcType(context) } else { f.Type = name } break } // len(list) > 0 if list[0].Name != nil { // generic method f.Name = name _, f.Type = p.funcType(context) p.errorAt(pos, "interface method must have no type parameters") break } // embedded instantiated type t := &IndexExpr{} t.pos = pos t.X = name if len(list) == 1 { t.Index = list[0].Type } else { // len(list) > 1 l := &ListExpr{} l.pos = list[0].Pos() l.ElemList = []Expr{:len(list)} for i := range list { l.ElemList[i] = list[i].Type } t.Index = l } f.Type = t default: // embedded type f.Type = p.qualifiedName(name) } return f } // EmbeddedElem = MethodSpec | EmbeddedTerm { "|" EmbeddedTerm } . func (p *Parser) embeddedElem(f *Field) (fv *Field) { if trace { defer p.trace("embeddedElem")() } if f == nil { f = &Field{} f.pos = p.pos() f.Type = p.embeddedTerm() } for p.Tok == OperatorType && p.Op == Or { t := &Operation{} t.pos = p.pos() t.Op = Or p.Next() t.X = f.Type t.Y = p.embeddedTerm() f.Type = t } return f } // EmbeddedTerm = [ "~" ] Type . func (p *Parser) embeddedTerm() (e Expr) { if trace { defer p.trace("embeddedTerm")() } if p.Tok == OperatorType && p.Op == Tilde { t := &Operation{} t.pos = p.pos() t.Op = Tilde p.Next() t.X = p.type_() return t } t := p.typeOrNil() if t == nil { t = p.badExpr() p.syntaxError("expected ~ term or type") p.advance(OperatorType, Semi, Rparen, Rbrack, Rbrace) } return t } // ParameterDecl = [ IdentifierList ] [ "..." ] Type . func (p *Parser) paramDeclOrNil(name *Name, follow Token) (f *Field) { if trace { defer p.trace("paramDeclOrNil")() } // type set notation is ok in type parameter lists typeSetsOk := follow == Rbrack pos := p.pos() if name != nil { pos = name.pos } else if typeSetsOk && p.Tok == OperatorType && p.Op == Tilde { // "~" ... return p.embeddedElem(nil) } f = &Field{} f.pos = pos if p.Tok == NameType || name != nil { // name if name == nil { name = p.name() } if p.Tok == Lbrack { // name "[" ... f.Type = p.arrayOrTArgs() if typ, ok := f.Type.(*IndexExpr); ok { // name "[" ... "]" typ.X = name } else { // name "[" n "]" E f.Name = name } if typeSetsOk && p.Tok == OperatorType && p.Op == Or { // name "[" ... "]" "|" ... // name "[" n "]" E "|" ... f = p.embeddedElem(f) } return f } if p.Tok == Dot { // name "." ... f.Type = p.qualifiedName(name) if typeSetsOk && p.Tok == OperatorType && p.Op == Or { // name "." name "|" ... f = p.embeddedElem(f) } return f } if typeSetsOk && p.Tok == OperatorType && p.Op == Or { // name "|" ... f.Type = name return p.embeddedElem(f) } f.Name = name } if p.Tok == DotDotDot { // [name] "..." ... t := &DotsType{} t.pos = p.pos() p.Next() t.Elem = p.typeOrNil() if t.Elem == nil { f.Type = p.badExpr() p.syntaxError("... is missing type") } else { f.Type = t } return f } if typeSetsOk && p.Tok == OperatorType && p.Op == Tilde { // [name] "~" ... f.Type = p.embeddedElem(nil).Type return f } f.Type = p.typeOrNil() if typeSetsOk && p.Tok == OperatorType && p.Op == Or && f.Type != nil { // [name] type "|" f = p.embeddedElem(f) } if f.Name != nil || f.Type != nil { return f } p.syntaxError("expected " | tokstring(follow)) p.advance(Comma, follow) return nil } // Parameters = "(" [ ParameterList [ "," ] ] ")" . // ParameterList = ParameterDecl { "," ParameterDecl } . // "(" or "[" has already been consumed. // If name != nil, it is the first name after "(" or "[". // If typ != nil, name must be != nil, and (name, typ) is the first field in the list. // In the result list, either all fields have a name, or no field has a name. func (p *Parser) paramList(name *Name, typ Expr, close Token, requireNames, dddok bool) (list []*Field) { if trace { defer p.trace("paramList")() } // p.list won't invoke its function argument if we're at the end of the // parameter list. If we have a complete field, handle this case here. if name != nil && typ != nil && p.Tok == close { p.Next() par := &Field{} par.pos = name.pos par.Name = name par.Type = typ return []*Field{par} } var named int32 // number of parameters that have an explicit name and type var typed int32 // number of parameters that have an explicit type end := p.list("parameter list", Comma, close, func() bool { var par *Field if typ != nil { if debug && name == nil { panic("initial type provided without name") } par = &Field{} par.pos = name.pos par.Name = name par.Type = typ } else { par = p.paramDeclOrNil(name, close) } name = nil // 1st name was consumed if present typ = nil // 1st type was consumed if present if par != nil { if debug && par.Name == nil && par.Type == nil { panic("parameter without name or type") } if par.Name != nil && par.Type != nil { named++ } if par.Type != nil { typed++ } list = append(list, par) } return false }) if len(list) == 0 { return } // distribute parameter types (len(list) > 0) if named == 0 && !requireNames { // all unnamed and we're not in a type parameter list => found names are named types for _, par := range list { if typ := par.Name; typ != nil { par.Type = typ par.Name = nil } } } else if named != len(list) { // some named or we're in a type parameter list => all must be named var errPos Pos // left-most error position (or unknown) var typ Expr // current type (from right to left) for i := len(list) - 1; i >= 0; i-- { par := list[i] if par.Type != nil { typ = par.Type if par.Name == nil { errPos = StartPos(typ) par.Name = NewName(errPos, "_") } } else if typ != nil { par.Type = typ } else { // par.Type == nil && typ == nil => we only have a par.Name errPos = par.Name.Pos() t := p.badExpr() t.pos = errPos // correct position par.Type = t } } if errPos.IsKnown() { // Not all parameters are named because named != len(list). // If named == typed, there must be parameters that have no types. // They must be at the end of the parameter list, otherwise types // would have been filled in by the right-to-left sweep above and // there would be no error. // If requireNames is set, the parameter list is a type parameter // list. var msg string if named == typed { errPos = end // position error at closing token ) or ] if requireNames { msg = "missing type constraint" } else { msg = "missing parameter type" } } else { if requireNames { msg = "missing type parameter name" // go.dev/issue/60812 if len(list) == 1 { msg = msg | " or invalid array length" } } else { msg = "missing parameter name" } } p.syntaxErrorAt(errPos, msg) } } // check use of ... - DISABLED for gen1 debugging return } func (p *Parser) badExpr() (b *BadExpr) { b = &BadExpr{} b.pos = p.pos() return b } // ---------------------------------------------------------------------------- // Statements // SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl . func (p *Parser) simpleStmt(lhs Expr, keyword Token) (s SimpleStmt) { if trace { defer p.trace("simpleStmt")() } if keyword == For && p.Tok == Range { // _Range expr if debug && lhs != nil { panic("invalid call of simpleStmt") } return p.newRangeClause(nil, false) } if lhs == nil { lhs = p.exprList() } if _, ok := lhs.(*ListExpr); !ok && p.Tok != Assign && p.Tok != Define { // expr pos := p.pos() switch p.Tok { case AssignOp: // lhs op= rhs op := p.Op p.Next() return p.newAssignStmt(pos, op, lhs, p.expr()) case IncOp: // lhs++ or lhs-- op := p.Op p.Next() return p.newAssignStmt(pos, op, lhs, nil) case Arrow: // lhs <- rhs ss := &SendStmt{} ss.pos = pos p.Next() ss.Chan = lhs ss.Value = p.expr() return ss default: // expr es := &ExprStmt{} es.pos = lhs.Pos() es.X = lhs return es } } // expr_list switch p.Tok { case Assign, Define: pos := p.pos() var op Operator if p.Tok == Define { op = Def } p.Next() if keyword == For && p.Tok == Range { // expr_list op= _Range expr return p.newRangeClause(lhs, op == Def) } // expr_list op= expr_list rhs := p.exprList() if x, ok := rhs.(*TypeSwitchGuard); ok && keyword == Switch && op == Def { if lhs, ok := lhs.(*Name); ok { // switch … lhs := rhs.(type) x.Lhs = lhs es := &ExprStmt{} es.pos = x.Pos() es.X = x return es } } return p.newAssignStmt(pos, op, lhs, rhs) default: p.syntaxError("expected := or = or comma") p.advance(Semi, Rbrace) if x, ok := lhs.(*ListExpr); ok { lhs = x.ElemList[0] } es := &ExprStmt{} es.pos = lhs.Pos() es.X = lhs return es } } func (p *Parser) newRangeClause(lhs Expr, def bool) (r *RangeClause) { r = &RangeClause{} r.pos = p.pos() p.Next() // consume _Range r.Lhs = lhs r.Def = def r.X = p.expr() return r } func (p *Parser) newAssignStmt(pos Pos, op Operator, lhs, rhs Expr) (a *AssignStmt) { a = &AssignStmt{} a.pos = pos a.Op = op a.Lhs = lhs a.Rhs = rhs return a } func (p *Parser) labeledStmtOrNil(label *Name) Stmt { if trace { defer p.trace("labeledStmt")() } s := &LabeledStmt{} s.pos = p.pos() s.Label = label p.want(Colon) if p.Tok == Rbrace { e := &EmptyStmt{} e.pos = p.pos() s.Stmt = e return s } s.Stmt = p.stmtOrNil() if s.Stmt != nil { return s } p.syntaxErrorAt(s.pos, "missing statement after label") return nil } // context must be a non-empty string unless we know that p.tok == _Lbrace. func (p *Parser) blockStmt(context string) (b *BlockStmt) { if trace { defer p.trace("blockStmt")() } s := &BlockStmt{} s.pos = p.pos() // people coming from C may forget that braces are mandatory in Go if !p.got(Lbrace) { p.syntaxError("expected { after " | context) p.advance(NameType, Rbrace) s.Rbrace = p.pos() // in case we found "}" if p.got(Rbrace) { return s } } s.List = p.stmtList() s.Rbrace = p.pos() p.want(Rbrace) return s } func (p *Parser) declStmt(f func(*Group) Decl) (d *DeclStmt) { if trace { defer p.trace("declStmt")() } s := &DeclStmt{} s.pos = p.pos() p.Next() // _Const, _Type, or _Var s.DeclList = p.appendGroup(nil, f) return s } func (p *Parser) forStmt() Stmt { if trace { defer p.trace("forStmt")() } s := &ForStmt{} s.pos = p.pos() s.Init, s.Cond, s.Post = p.header(For) s.Body = p.blockStmt("for clause") return s } func (p *Parser) header(keyword Token) (init SimpleStmt, cond Expr, post SimpleStmt) { p.want(keyword) if p.Tok == Lbrace { if keyword == If { p.syntaxError("missing condition in if statement") cond = p.badExpr() } return } // p.tok != _Lbrace outer := p.Xnest p.Xnest = -1 if p.Tok != Semi { // accept potential varDecl but complain if p.got(Var) { p.syntaxError("var declaration not allowed in " | keyword.String() | " initializer") } init = p.simpleStmt(nil, keyword) // If we have a range clause, we are done (can only happen for keyword == _For). if _, ok := init.(*RangeClause); ok { p.Xnest = outer return } } var condStmt SimpleStmt var semi struct { pos Pos lit string // valid if pos.IsKnown() } if p.Tok != Lbrace { if p.Tok == Semi { semi.pos = p.pos() semi.lit = p.Lit p.Next() } else { // asking for a '{' rather than a ';' here leads to a better error message p.want(Lbrace) if p.Tok != Lbrace { p.advance(Lbrace, Rbrace) // for better synchronization (e.g., go.dev/issue/22581) } } if keyword == For { if p.Tok != Semi { if p.Tok == Lbrace { p.syntaxError("expected for loop condition") goto done } condStmt = p.simpleStmt(nil, 0 /* range not permitted */) } p.want(Semi) if p.Tok != Lbrace { post = p.simpleStmt(nil, 0 /* range not permitted */) if a, _ := post.(*AssignStmt); a != nil && a.Op == Def { p.syntaxErrorAt(a.Pos(), "cannot declare in post statement of for loop") } } } else if p.Tok != Lbrace { condStmt = p.simpleStmt(nil, keyword) } } else { condStmt = init init = nil } done: // unpack condStmt switch s := condStmt.(type) { case nil: if keyword == If && semi.pos.IsKnown() { if semi.lit != "semicolon" { p.syntaxErrorAt(semi.pos, "unexpected " | semi.lit | ", expected { after if clause") } else { p.syntaxErrorAt(semi.pos, "missing condition in if statement") } b := &BadExpr{} b.pos = semi.pos cond = b } case *ExprStmt: cond = s.X default: // A common syntax error is to write '=' instead of '==', // which turns an expression into an assignment. Provide // a more explicit error message in that case to prevent // further confusion. var str string if as, ok := s.(*AssignStmt); ok && as.Op == 0 { // Emphasize complex Lhs and Rhs of assignment with parentheses to highlight '='. str = "assignment " | emphasize(as.Lhs) | " = " | emphasize(as.Rhs) } else { str = String(s) } p.syntaxErrorAt(s.Pos(), "cannot use " | str | " as value") } p.Xnest = outer return } // emphasize returns a string representation of x, with (top-level) // binary expressions emphasized by enclosing them in parentheses. func emphasize(x Expr) (s string) { return "" } func (p *Parser) ifStmt() (i *IfStmt) { if trace { defer p.trace("ifStmt")() } s := &IfStmt{} s.pos = p.pos() s.Init, s.Cond, _ = p.header(If) s.Then = p.blockStmt("if clause") if p.got(Else) { switch p.Tok { case If: s.Else = p.ifStmt() case Lbrace: s.Else = p.blockStmt("") default: p.syntaxError("else must be followed by if or statement block") p.advance(NameType, Rbrace) } } return s } func (p *Parser) switchStmt() (s *SwitchStmt) { if trace { defer p.trace("switchStmt")() } s = &SwitchStmt{} s.pos = p.pos() s.Init, s.Tag, _ = p.header(Switch) if !p.got(Lbrace) { p.syntaxError("missing { after switch clause") p.advance(Case, Default, Rbrace) } for p.Tok != EOF && p.Tok != Rbrace { s.Body = append(s.Body, p.caseClause()) } s.Rbrace = p.pos() p.want(Rbrace) return s } func (p *Parser) selectStmt() (s *SelectStmt) { if trace { defer p.trace("selectStmt")() } s = &SelectStmt{} s.pos = p.pos() p.want(Select) if !p.got(Lbrace) { p.syntaxError("missing { after select clause") p.advance(Case, Default, Rbrace) } for p.Tok != EOF && p.Tok != Rbrace { s.Body = append(s.Body, p.commClause()) } s.Rbrace = p.pos() p.want(Rbrace) return s } func (p *Parser) caseClause() (c *CaseClause) { if trace { defer p.trace("caseClause")() } c = &CaseClause{} c.pos = p.pos() switch p.Tok { case Case: p.Next() c.Cases = p.exprList() case Default: p.Next() default: p.syntaxError("expected case or default or }") p.advance(Colon, Case, Default, Rbrace) } c.Colon = p.pos() p.want(Colon) c.Body = p.stmtList() return c } func (p *Parser) commClause() (c *CommClause) { if trace { defer p.trace("commClause")() } c = &CommClause{} c.pos = p.pos() switch p.Tok { case Case: p.Next() c.Comm = p.simpleStmt(nil, 0) // The syntax restricts the possible simple statements here to: // // lhs <- x (send statement) // <-x // lhs = <-x // lhs := <-x // // All these (and more) are recognized by simpleStmt and invalid // syntax trees are flagged later, during type checking. case Default: p.Next() default: p.syntaxError("expected case or default or }") p.advance(Colon, Case, Default, Rbrace) } c.Colon = p.pos() p.want(Colon) c.Body = p.stmtList() return c } // stmtOrNil parses a statement if one is present, or else returns nil. // // Statement = // Declaration | LabeledStmt | SimpleStmt | // GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt | // FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt | // DeferStmt . func (p *Parser) stmtOrNil() (s Stmt) { if trace { defer p.trace("stmt " | p.Tok.String())() } // Most statements (assignments) start with an identifier; // look for it first before doing anything more expensive. if p.Tok == NameType { p.clearPragma() lhs := p.exprList() if label, ok := lhs.(*Name); ok && p.Tok == Colon { return p.labeledStmtOrNil(label) } return p.simpleStmt(lhs, 0) } switch p.Tok { case Var: return p.declStmt(p.varDecl) case Const: return p.declStmt(p.constDecl) case TypeType: return p.declStmt(p.typeDecl) } p.clearPragma() switch p.Tok { case Lbrace: return p.blockStmt("") case OperatorType, Star: switch p.Op { case Add, Sub, Mul, And, Xor, Not: return p.simpleStmt(nil, 0) // unary operators } case Literal, Func, Lparen, // operands Lbrack, Struct, Map, Chan, Interface, // composite types Arrow: // receive operator return p.simpleStmt(nil, 0) case For: return p.forStmt() case Switch: return p.switchStmt() case Select: return p.selectStmt() case If: return p.ifStmt() case Fallthrough: b := &BranchStmt{} b.pos = p.pos() p.Next() b.Tok = Fallthrough return b case Break, Continue: b := &BranchStmt{} b.pos = p.pos() b.Tok = p.Tok p.Next() if p.Tok == NameType { b.Label = p.name() } return b case Go, Defer: return p.callStmt() case Goto: b := &BranchStmt{} b.pos = p.pos() b.Tok = Goto p.Next() b.Label = p.name() return b case Return: r := &ReturnStmt{} r.pos = p.pos() p.Next() if p.Tok != Semi && p.Tok != Rbrace { r.Results = p.exprList() } return r case Semi: e := &EmptyStmt{} e.pos = p.pos() return e } return nil } // StatementList = { Statement ";" } . func (p *Parser) stmtList() (l []Stmt) { if trace { defer p.trace("stmtList")() } for p.Tok != EOF && p.Tok != Rbrace && p.Tok != Case && p.Tok != Default { s := p.stmtOrNil() p.clearPragma() if s == nil { break } l = append(l, s) // ";" is optional before "}" if !p.got(Semi) && p.Tok != Rbrace { p.syntaxError("at end of statement") p.advance(Semi, Rbrace, Case, Default) p.got(Semi) // avoid spurious empty statement } } return } // argList parses a possibly empty, comma-separated list of arguments, // optionally followed by a comma (if not empty), and closed by ")". // The last argument may be followed by "...". // // argList = [ arg { "," arg } [ "..." ] [ "," ] ] ")" . func (p *Parser) argList() (list []Expr, hasDots bool) { if trace { defer p.trace("argList")() } p.Xnest++ p.list("argument list", Comma, Rparen, func() bool { list = append(list, p.expr()) hasDots = p.got(DotDotDot) return hasDots }) p.Xnest-- return } // ---------------------------------------------------------------------------- // Common productions func (p *Parser) name() (n *Name) { // no tracing to avoid overly verbose output if p.Tok == NameType { n = NewName(p.pos(), p.Lit) p.Next() return n } n = NewName(p.pos(), "_") p.syntaxError("expected name") p.advance() return n } // IdentifierList = identifier { "," identifier } . // The first name must be provided. func (p *Parser) nameList(First *Name) (ns []*Name) { if trace { defer p.trace("nameList")() } if debug && First == nil { panic("first name not provided") } l := []*Name{First} for p.got(Comma) { l = append(l, p.name()) } return l } // The first name may be provided, or nil. func (p *Parser) qualifiedName(name *Name) (e Expr) { if trace { defer p.trace("qualifiedName")() } var x Expr switch { case name != nil: x = name case p.Tok == NameType: x = p.name() default: x = NewName(p.pos(), "_") p.syntaxError("expected name") p.advance(Dot, Semi, Rbrace) } if p.Tok == Dot { s := &SelectorExpr{} s.pos = p.pos() p.Next() s.X = x s.Sel = p.name() x = s } if p.Tok == Lbrack { x = p.typeInstance(x) } return x } // ExpressionList = Expression { "," Expression } . func (p *Parser) exprList() (e Expr) { if trace { defer p.trace("exprList")() } x := p.expr() if p.got(Comma) { list := []Expr{x, p.expr()} for p.got(Comma) { list = append(list, p.expr()) } t := &ListExpr{} t.pos = x.Pos() t.ElemList = list x = t } return x } // typeList parses a non-empty, comma-separated list of types, // optionally followed by a comma. If strict is set to false, // the first element may also be a (non-type) expression. // If there is more than one argument, the result is a *ListExpr. // The comma result indicates whether there was a (separating or // trailing) comma. // // typeList = arg { "," arg } [ "," ] . func (p *Parser) typeList(strict bool) (x Expr, comma bool) { if trace { defer p.trace("typeList")() } p.Xnest++ if strict { x = p.type_() } else { x = p.expr() } if p.got(Comma) { comma = true if t := p.typeOrNil(); t != nil { list := []Expr{x, t} for p.got(Comma) { if t = p.typeOrNil(); t == nil { break } list = append(list, t) } l := &ListExpr{} l.pos = x.Pos() // == list[0].Pos() l.ElemList = list x = l } } p.Xnest-- return } // Unparen returns e with any enclosing parentheses stripped. func Unparen(x Expr) (e Expr) { for { p, ok := x.(*ParenExpr) if !ok { break } x = p.X } return x } // UnpackListExpr unpacks a *ListExpr into a []Expr. func UnpackListExpr(x Expr) (es []Expr) { switch x := x.(type) { case nil: return nil case *ListExpr: return x.ElemList default: return []Expr{x} } } func parseSource(name string, src []byte) (f *File) { errh := func(err error) {} var p Parser p.initBytes(NewFileBase(name), src, errh, nil, 0) p.Next() return p.fileOrNil() } func bytesHasPrefix(s, prefix string) (ok bool) { if len(prefix) > len(s) { return false } return s[:len(prefix)] == prefix } func bytesIndexByte(s string, c byte) (n int32) { for i := int32(0); i < int32(len(s)); i++ { if s[i] == c { return i } } return -1 } func bytesLastIndexByte(s string, c byte) (n int32) { for i := int32(len(s)) - 1; i >= 0; i-- { if s[i] == c { return i } } return -1 }