message/pipeline: prepare for multi-stage extraction
most notably ssa and callgraph analysis
just restructuring now to keep diffs better later
Change-Id: I7e24053fe014430603a4daa282c87a97ad753433
Reviewed-on: https://go-review.googlesource.com/102715
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ross Light <light@google.com>
diff --git a/message/pipeline/extract.go b/message/pipeline/extract.go
index 379cc6d..9be2bac 100644
--- a/message/pipeline/extract.go
+++ b/message/pipeline/extract.go
@@ -34,22 +34,50 @@
// Extract extracts all strings form the package defined in Config.
func Extract(c *Config) (*State, error) {
- conf := loader.Config{}
- prog, err := loadPackages(&conf, c.Packages)
+ x, err := newExtracter(c)
if err != nil {
return nil, wrap(err, "")
}
+ x.extractMessages()
+
+ return &State{
+ Config: *c,
+ program: x.iprog,
+ Extracted: Messages{
+ Language: c.SourceLanguage,
+ Messages: x.messages,
+ },
+ }, nil
+}
+
+type extracter struct {
+ conf loader.Config
+ iprog *loader.Program
+ messages []Message
+}
+
+func newExtracter(c *Config) (x *extracter, err error) {
+ x = &extracter{
+ conf: loader.Config{},
+ }
+
+ x.iprog, err = loadPackages(&x.conf, c.Packages)
+ if err != nil {
+ return nil, wrap(err, "")
+ }
+ return x, nil
+}
+
+func (x *extracter) extractMessages() {
// print returns Go syntax for the specified node.
print := func(n ast.Node) string {
var buf bytes.Buffer
- format.Node(&buf, conf.Fset, n)
+ format.Node(&buf, x.conf.Fset, n)
return buf.String()
}
-
- var messages []Message
-
- for _, info := range prog.AllPackages {
+ prog := x.iprog
+ for _, info := range x.iprog.AllPackages {
for _, f := range info.Files {
// Associate comments with nodes.
cmap := ast.NewCommentMap(prog.Fset, f, f.Comments)
@@ -135,80 +163,76 @@
Expr: expr,
Value: val,
Comment: getComment(arg),
- Position: posString(conf, info, arg.Pos()),
+ Position: posString(&x.conf, info.Pkg, arg.Pos()),
// TODO report whether it implements
// interfaces plural.Interface,
// gender.Interface.
})
}
- msg := ""
- ph := placeholders{index: map[string]string{}}
+ formats := []string{fmtMsg}
+ for _, c := range formats {
+ fmtMsg = c
+ msg := ""
- trimmed, _, _ := trimWS(fmtMsg)
+ ph := placeholders{index: map[string]string{}}
- p := fmtparser.Parser{}
- p.Reset(simArgs)
- for p.SetFormat(trimmed); p.Scan(); {
- switch p.Status {
- case fmtparser.StatusText:
- msg += p.Text()
- case fmtparser.StatusSubstitution,
- fmtparser.StatusBadWidthSubstitution,
- fmtparser.StatusBadPrecSubstitution:
- arguments[p.ArgNum-1].used = true
- arg := arguments[p.ArgNum-1]
- sub := p.Text()
- if !p.HasIndex {
- r, sz := utf8.DecodeLastRuneInString(sub)
- sub = fmt.Sprintf("%s[%d]%c", sub[:len(sub)-sz], p.ArgNum, r)
+ trimmed, _, _ := trimWS(fmtMsg)
+
+ p := fmtparser.Parser{}
+ p.Reset(simArgs)
+ for p.SetFormat(trimmed); p.Scan(); {
+ switch p.Status {
+ case fmtparser.StatusText:
+ msg += p.Text()
+ case fmtparser.StatusSubstitution,
+ fmtparser.StatusBadWidthSubstitution,
+ fmtparser.StatusBadPrecSubstitution:
+ arguments[p.ArgNum-1].used = true
+ arg := arguments[p.ArgNum-1]
+ sub := p.Text()
+ if !p.HasIndex {
+ r, sz := utf8.DecodeLastRuneInString(sub)
+ sub = fmt.Sprintf("%s[%d]%c", sub[:len(sub)-sz], p.ArgNum, r)
+ }
+ msg += fmt.Sprintf("{%s}", ph.addArg(&arg, sub))
}
- msg += fmt.Sprintf("{%s}", ph.addArg(&arg, sub))
}
- }
- key = append(key, msg)
+ key = append(key, msg)
- // Add additional Placeholders that can be used in translations
- // that are not present in the string.
- for _, arg := range arguments {
- if arg.used {
- continue
+ // Add additional Placeholders that can be used in translations
+ // that are not present in the string.
+ for _, arg := range arguments {
+ if arg.used {
+ continue
+ }
+ ph.addArg(&arg, fmt.Sprintf("%%[%d]v", arg.ArgNum))
}
- ph.addArg(&arg, fmt.Sprintf("%%[%d]v", arg.ArgNum))
- }
- if c := getComment(call.Args[0]); c != "" {
- comment = c
- }
+ if c := getComment(call.Args[0]); c != "" {
+ comment = c
+ }
- messages = append(messages, Message{
- ID: key,
- Key: fmtMsg,
- Message: Text{Msg: msg},
- // TODO(fix): this doesn't get the before comment.
- Comment: comment,
- Placeholders: ph.slice,
- Position: posString(conf, info, call.Lparen),
- })
+ x.messages = append(x.messages, Message{
+ ID: key,
+ Key: fmtMsg,
+ Message: Text{Msg: msg},
+ // TODO(fix): this doesn't get the before comment.
+ Comment: comment,
+ Placeholders: ph.slice,
+ Position: posString(&x.conf, info.Pkg, call.Lparen),
+ })
+ }
return true
})
}
}
-
- return &State{
- Config: *c,
- program: prog,
- Extracted: Messages{
- Language: c.SourceLanguage,
- Messages: messages,
- },
- }, nil
}
-func posString(conf loader.Config, info *loader.PackageInfo, pos token.Pos) string {
+func posString(conf *loader.Config, pkg *types.Package, pos token.Pos) string {
p := conf.Fset.Position(pos)
file := fmt.Sprintf("%s:%d:%d", filepath.Base(p.Filename), p.Line, p.Column)
- return filepath.Join(info.Pkg.Path(), file)
+ return filepath.Join(pkg.Path(), file)
}
// extractFuncs indicates the types and methods for which to extract strings,