...

Source file src/cuelang.org/go/tools/fix/fix.go

Documentation: cuelang.org/go/tools/fix

     1  // Copyright 2019 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package fix contains functionality for writing CUE files with legacy
    16  // syntax to newer ones.
    17  //
    18  // Note: the transformations that are supported in this package will change
    19  // over time.
    20  package fix
    21  
    22  import (
    23  	"strings"
    24  
    25  	"cuelang.org/go/cue/ast"
    26  	"cuelang.org/go/cue/ast/astutil"
    27  	"cuelang.org/go/cue/token"
    28  )
    29  
    30  type Option func(*options)
    31  
    32  type options struct {
    33  	simplify bool
    34  }
    35  
    36  // Simplify enables fixes that simplify the code, but are not strictly
    37  // necessary.
    38  func Simplify() Option {
    39  	return func(o *options) { o.simplify = true }
    40  }
    41  
    42  // File applies fixes to f and returns it. It alters the original f.
    43  func File(f *ast.File, o ...Option) *ast.File {
    44  	var options options
    45  	for _, f := range o {
    46  		f(&options)
    47  	}
    48  
    49  	// Rewrite integer division operations to use builtins.
    50  	f = astutil.Apply(f, func(c astutil.Cursor) bool {
    51  		n := c.Node()
    52  		switch x := n.(type) {
    53  		case *ast.BinaryExpr:
    54  			switch x.Op {
    55  			case token.IDIV, token.IMOD, token.IQUO, token.IREM:
    56  				ast.SetRelPos(x.X, token.NoSpace)
    57  				c.Replace(&ast.CallExpr{
    58  					// Use the __foo version to prevent accidental shadowing.
    59  					Fun:  ast.NewIdent("__" + x.Op.String()),
    60  					Args: []ast.Expr{x.X, x.Y},
    61  				})
    62  			}
    63  		}
    64  		return true
    65  	}, nil).(*ast.File)
    66  
    67  	// Rewrite block comments to regular comments.
    68  	ast.Walk(f, func(n ast.Node) bool {
    69  		switch x := n.(type) {
    70  		case *ast.CommentGroup:
    71  			comments := []*ast.Comment{}
    72  			for _, c := range x.List {
    73  				s := c.Text
    74  				if !strings.HasPrefix(s, "/*") || !strings.HasSuffix(s, "*/") {
    75  					comments = append(comments, c)
    76  					continue
    77  				}
    78  				if x.Position > 0 {
    79  					// Moving to the end doesn't work, as it still
    80  					// may inject at a false line break position.
    81  					x.Position = 0
    82  					x.Doc = true
    83  				}
    84  				s = strings.TrimSpace(s[2 : len(s)-2])
    85  				for _, s := range strings.Split(s, "\n") {
    86  					for i := 0; i < 3; i++ {
    87  						if strings.HasPrefix(s, " ") || strings.HasPrefix(s, "*") {
    88  							s = s[1:]
    89  						}
    90  					}
    91  					comments = append(comments, &ast.Comment{Text: "// " + s})
    92  				}
    93  			}
    94  			x.List = comments
    95  			return false
    96  		}
    97  		return true
    98  	}, nil)
    99  
   100  	// TODO: we are probably reintroducing slices. Disable for now.
   101  	//
   102  	// Rewrite slice expression.
   103  	// f = astutil.Apply(f, func(c astutil.Cursor) bool {
   104  	// 	n := c.Node()
   105  	// 	getVal := func(n ast.Expr) ast.Expr {
   106  	// 		if n == nil {
   107  	// 			return nil
   108  	// 		}
   109  	// 		if id, ok := n.(*ast.Ident); ok && id.Name == "_" {
   110  	// 			return nil
   111  	// 		}
   112  	// 		return n
   113  	// 	}
   114  	// 	switch x := n.(type) {
   115  	// 	case *ast.SliceExpr:
   116  	// 		ast.SetRelPos(x.X, token.NoRelPos)
   117  
   118  	// 		lo := getVal(x.Low)
   119  	// 		hi := getVal(x.High)
   120  	// 		if lo == nil { // a[:j]
   121  	// 			lo = mustParseExpr("0")
   122  	// 			astutil.CopyMeta(lo, x.Low)
   123  	// 		}
   124  	// 		if hi == nil { // a[i:]
   125  	// 			hi = ast.NewCall(ast.NewIdent("len"), x.X)
   126  	// 			astutil.CopyMeta(lo, x.High)
   127  	// 		}
   128  	// 		if pkg := c.Import("list"); pkg != nil {
   129  	// 			c.Replace(ast.NewCall(ast.NewSel(pkg, "Slice"), x.X, lo, hi))
   130  	// 		}
   131  	// 	}
   132  	// 	return true
   133  	// }, nil).(*ast.File)
   134  
   135  	if options.simplify {
   136  		f = simplify(f)
   137  	}
   138  
   139  	return f
   140  }
   141  

View as plain text