Source file src/cmd/compile/internal/types/goversion.go

     1  // Copyright 2009 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  
     5  package types
     6  
     7  import (
     8  	"fmt"
     9  	"internal/goversion"
    10  	"log"
    11  	"regexp"
    12  	"strconv"
    13  
    14  	"cmd/compile/internal/base"
    15  )
    16  
    17  // A lang is a language version broken into major and minor numbers.
    18  type lang struct {
    19  	major, minor int
    20  }
    21  
    22  // langWant is the desired language version set by the -lang flag.
    23  // If the -lang flag is not set, this is the zero value, meaning that
    24  // any language version is supported.
    25  var langWant lang
    26  
    27  // AllowsGoVersion reports whether a particular package
    28  // is allowed to use Go version major.minor.
    29  // We assume the imported packages have all been checked,
    30  // so we only have to check the local package against the -lang flag.
    31  func AllowsGoVersion(pkg *Pkg, major, minor int) bool {
    32  	if pkg == nil {
    33  		// TODO(mdempsky): Set Pkg for local types earlier.
    34  		pkg = LocalPkg
    35  	}
    36  	if pkg != LocalPkg {
    37  		// Assume imported packages passed type-checking.
    38  		return true
    39  	}
    40  	if langWant.major == 0 && langWant.minor == 0 {
    41  		return true
    42  	}
    43  	return langWant.major > major || (langWant.major == major && langWant.minor >= minor)
    44  }
    45  
    46  // ParseLangFlag verifies that the -lang flag holds a valid value, and
    47  // exits if not. It initializes data used by langSupported.
    48  func ParseLangFlag() {
    49  	if base.Flag.Lang == "" {
    50  		return
    51  	}
    52  
    53  	var err error
    54  	langWant, err = parseLang(base.Flag.Lang)
    55  	if err != nil {
    56  		log.Fatalf("invalid value %q for -lang: %v", base.Flag.Lang, err)
    57  	}
    58  
    59  	if def := currentLang(); base.Flag.Lang != def {
    60  		defVers, err := parseLang(def)
    61  		if err != nil {
    62  			log.Fatalf("internal error parsing default lang %q: %v", def, err)
    63  		}
    64  		if langWant.major > defVers.major || (langWant.major == defVers.major && langWant.minor > defVers.minor) {
    65  			log.Fatalf("invalid value %q for -lang: max known version is %q", base.Flag.Lang, def)
    66  		}
    67  	}
    68  }
    69  
    70  // parseLang parses a -lang option into a langVer.
    71  func parseLang(s string) (lang, error) {
    72  	matches := goVersionRE.FindStringSubmatch(s)
    73  	if matches == nil {
    74  		return lang{}, fmt.Errorf(`should be something like "go1.12"`)
    75  	}
    76  	major, err := strconv.Atoi(matches[1])
    77  	if err != nil {
    78  		return lang{}, err
    79  	}
    80  	minor, err := strconv.Atoi(matches[2])
    81  	if err != nil {
    82  		return lang{}, err
    83  	}
    84  	return lang{major: major, minor: minor}, nil
    85  }
    86  
    87  // currentLang returns the current language version.
    88  func currentLang() string {
    89  	return fmt.Sprintf("go1.%d", goversion.Version)
    90  }
    91  
    92  // goVersionRE is a regular expression that matches the valid
    93  // arguments to the -lang flag.
    94  var goVersionRE = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
    95  

View as plain text