1// Copyright 2021 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package types 6 7import ( 8 "fmt" 9 "go/ast" 10 "go/token" 11 "regexp" 12 "strconv" 13 "strings" 14) 15 16// langCompat reports an error if the representation of a numeric 17// literal is not compatible with the current language version. 18func (check *Checker) langCompat(lit *ast.BasicLit) { 19 s := lit.Value 20 if len(s) <= 2 || check.allowVersion(check.pkg, 1, 13) { 21 return 22 } 23 // len(s) > 2 24 if strings.Contains(s, "_") { 25 check.errorf(lit, _InvalidLit, "underscores in numeric literals requires go1.13 or later") 26 return 27 } 28 if s[0] != '0' { 29 return 30 } 31 radix := s[1] 32 if radix == 'b' || radix == 'B' { 33 check.errorf(lit, _InvalidLit, "binary literals requires go1.13 or later") 34 return 35 } 36 if radix == 'o' || radix == 'O' { 37 check.errorf(lit, _InvalidLit, "0o/0O-style octal literals requires go1.13 or later") 38 return 39 } 40 if lit.Kind != token.INT && (radix == 'x' || radix == 'X') { 41 check.errorf(lit, _InvalidLit, "hexadecimal floating-point literals requires go1.13 or later") 42 } 43} 44 45// allowVersion reports whether the given package 46// is allowed to use version major.minor. 47func (check *Checker) allowVersion(pkg *Package, major, minor int) bool { 48 // We assume that imported packages have all been checked, 49 // so we only have to check for the local package. 50 if pkg != check.pkg { 51 return true 52 } 53 ma, mi := check.version.major, check.version.minor 54 return ma == 0 && mi == 0 || ma > major || ma == major && mi >= minor 55} 56 57type version struct { 58 major, minor int 59} 60 61// parseGoVersion parses a Go version string (such as "go1.12") 62// and returns the version, or an error. If s is the empty 63// string, the version is 0.0. 64func parseGoVersion(s string) (v version, err error) { 65 if s == "" { 66 return 67 } 68 matches := goVersionRx.FindStringSubmatch(s) 69 if matches == nil { 70 err = fmt.Errorf(`should be something like "go1.12"`) 71 return 72 } 73 v.major, err = strconv.Atoi(matches[1]) 74 if err != nil { 75 return 76 } 77 v.minor, err = strconv.Atoi(matches[2]) 78 return 79} 80 81// goVersionRx matches a Go version string, e.g. "go1.12". 82var goVersionRx = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`) 83