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