github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/internal/compiler/analyzer/semver.go (about)

     1  package analyzer
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/Masterminds/semver/v3"
     7  
     8  	"github.com/nevalang/neva/internal/compiler"
     9  	src "github.com/nevalang/neva/internal/compiler/sourcecode"
    10  )
    11  
    12  // semverCheck ensures that module is compatible with existing compiler
    13  // by checking it's version against semver. It uses minor as major.
    14  func (a Analyzer) semverCheck(mod src.Module, modRef src.ModuleRef) *compiler.Error {
    15  	moduleVersion, semverErr := semver.NewVersion(mod.Manifest.LanguageVersion)
    16  	if semverErr != nil {
    17  		return &compiler.Error{
    18  			Err: fmt.Errorf("%w: %v", ErrCompilerVersion, semverErr),
    19  		}
    20  	}
    21  
    22  	compilerVersion, semverErr := semver.NewVersion(a.compilerVersion)
    23  	if semverErr != nil {
    24  		return &compiler.Error{
    25  			Err: fmt.Errorf("%w: %v", ErrCompilerVersion, semverErr),
    26  		}
    27  	}
    28  
    29  	// major versions should be strictly equal
    30  	// if got major more than ours, then compatibility in that program is broken
    31  	// and vice versa if got major less than ours
    32  	if moduleVersion.Major() != compilerVersion.Major() {
    33  		return &compiler.Error{
    34  			Err: fmt.Errorf(
    35  				"%w: different majors: module %v wants %v while current is %v",
    36  				ErrCompilerVersion,
    37  				modRef, mod.Manifest.LanguageVersion, a.compilerVersion,
    38  			),
    39  		}
    40  	}
    41  
    42  	// if majors are equal, then minor should be less or equal
    43  	// so we make sure module don't want any features we don't have
    44  	if moduleVersion.Minor() > compilerVersion.Minor() {
    45  		return &compiler.Error{
    46  			Err: fmt.Errorf(
    47  				"%w: incompatible minors: module %v wants %v while current is %v",
    48  				ErrCompilerVersion,
    49  				modRef, mod.Manifest.LanguageVersion, a.compilerVersion,
    50  			),
    51  		}
    52  	}
    53  
    54  	// at this point we sure we have same majors and got.Minor >= want.Minor
    55  
    56  	// if module's minor is less than ours then we don't care about patches
    57  	// because with newer minor we sure have all the patches of the previous one
    58  	if moduleVersion.Minor() < compilerVersion.Minor() {
    59  		// note that we don't fix previous minors and instead force to update
    60  		return nil
    61  	}
    62  
    63  	// if we here then we sure than minors are equal (as well as majors)
    64  	// this is the only case where we actually care about patches
    65  
    66  	// it's ok if we have some patches that module doesn't rely on
    67  	// but it's not ok if module a wants some patch we don't really have
    68  	if moduleVersion.Patch() > compilerVersion.Patch() {
    69  		return &compiler.Error{
    70  			Err: fmt.Errorf(
    71  				"%w: incompatible patch: module %v wants %v while current is %v",
    72  				ErrCompilerVersion,
    73  				modRef, mod.Manifest.LanguageVersion, a.compilerVersion,
    74  			),
    75  		}
    76  	}
    77  
    78  	// versions are strictly equal
    79  	return nil
    80  }