package interp

import (
	
	
	
	
	
	
	
)

// buildOk returns true if a file or script matches build constraints
// as specified in https://golang.org/pkg/go/build/#hdr-Build_Constraints.
// An error from parser is returned as well.
func ( *Interpreter) ( *build.Context, ,  string) (bool, error) {
	// Extract comments before the first clause
	,  := parser.ParseFile(.fset, , , parser.PackageClauseOnly|parser.ParseComments)
	if  != nil {
		return false, 
	}
	for ,  := range .Comments {
		// in file, evaluate the AND of multiple line build constraints
		for ,  := range strings.Split(strings.TrimSpace(.Text()), "\n") {
			if !buildLineOk(, ) {
				return false, nil
			}
		}
	}
	setYaegiTags(, .Comments)
	return true, nil
}

// buildLineOk returns true if line is not a build constraint or
// if build constraint is satisfied.
func buildLineOk( *build.Context,  string) ( bool) {
	if len() < 7 || [:7] != "+build " {
		return true
	}
	// In line, evaluate the OR of space-separated options
	 := strings.Split(strings.TrimSpace([6:]), " ")
	for ,  := range  {
		if  = buildOptionOk(, );  {
			break
		}
	}
	return 
}

// buildOptionOk return true if all comma separated tags match, false otherwise.
func buildOptionOk( *build.Context,  string) bool {
	// in option, evaluate the AND of individual tags
	for ,  := range strings.Split(, ",") {
		if !buildTagOk(, ) {
			return false
		}
	}
	return true
}

// buildTagOk returns true if a build tag matches, false otherwise
// if first character is !, result is negated.
func buildTagOk( *build.Context,  string) ( bool) {
	 := [0] == '!'
	if  {
		 = [1:]
	}
	switch {
	case contains(.BuildTags, ):
		 = true
	case  == .GOOS:
		 = true
	case  == .GOARCH:
		 = true
	case len() > 4 && [:4] == "go1.":
		if ,  := strconv.Atoi([4:]);  != nil {
			 = false
		} else {
			 = goMinorVersion() >= 
		}
	}
	if  {
		 = !
	}
	return
}

// setYaegiTags scans a comment group for "yaegi:tags tag1 tag2 ..." lines
// and adds the corresponding tags to the interpreter build tags.
func setYaegiTags( *build.Context,  []*ast.CommentGroup) {
	for ,  := range  {
		for ,  := range strings.Split(strings.TrimSpace(.Text()), "\n") {
			if len() < 11 || [:11] != "yaegi:tags " {
				continue
			}

			 := strings.Split(strings.TrimSpace([10:]), " ")
			for ,  := range  {
				if !contains(.BuildTags, ) {
					.BuildTags = append(.BuildTags, )
				}
			}
		}
	}
}

func contains( []string,  string) bool {
	for ,  := range  {
		if  ==  {
			return true
		}
	}
	return false
}

// goMinorVersion returns the go minor version number.
func goMinorVersion( *build.Context) int {
	 := .ReleaseTags[len(.ReleaseTags)-1]

	 := strings.Split(, ".")
	if len() < 2 {
		panic("unsupported Go version: " + )
	}

	,  := strconv.Atoi([1])
	if  != nil {
		panic("unsupported Go version: " + )
	}
	return 
}

// skipFile returns true if file should be skipped.
func skipFile( *build.Context,  string,  bool) bool {
	if !strings.HasSuffix(, ".go") {
		return true
	}
	 = strings.TrimSuffix(path.Base(), ".go")
	if  := filepath.Base(); strings.HasPrefix(, "_") || strings.HasPrefix(, ".") {
		return true
	}
	if  && strings.HasSuffix(, "_test") {
		return true
	}
	 := strings.Index(, "_")
	if  < 0 {
		return false
	}
	 := strings.Split([+1:], "_")
	 := len() - 1
	if -1 >= 0 {
		switch ,  := [-1], []; {
		case  == .GOOS:
			if knownArch[] {
				return  != .GOARCH
			}
			return false
		case knownOs[] && knownArch[]:
			return true
		case knownArch[] &&  != .GOARCH:
			return true
		default:
			return false
		}
	}
	if  := []; knownOs[] &&  != .GOOS || knownArch[] &&  != .GOARCH {
		return true
	}
	return false
}

var knownOs = map[string]bool{
	"aix":       true,
	"android":   true,
	"darwin":    true,
	"dragonfly": true,
	"freebsd":   true,
	"illumos":   true,
	"ios":       true,
	"js":        true,
	"linux":     true,
	"netbsd":    true,
	"openbsd":   true,
	"plan9":     true,
	"solaris":   true,
	"wasip1":    true,
	"windows":   true,
}

var knownArch = map[string]bool{
	"386":      true,
	"amd64":    true,
	"arm":      true,
	"arm64":    true,
	"loong64":  true,
	"mips":     true,
	"mips64":   true,
	"mips64le": true,
	"mipsle":   true,
	"ppc64":    true,
	"ppc64le":  true,
	"s390x":    true,
	"wasm":     true,
}