Skip to content

Commit 86b55cd

Browse files
author
Randall C. O'Reilly
committed
gopy, gogi flags, generates class __init__ with SetTags properly for gogi mode. strings., copy() -> method calls
1 parent ee6b89f commit 86b55cd

File tree

6 files changed

+140
-39
lines changed

6 files changed

+140
-39
lines changed

README.md

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,17 @@ It is based on the Go `gofmt` command source code and the go `printer` package,
66

77
We have modified the `printer` code in the `pyprint` package to instead print out Python code.
88

9-
# TODO
10-
11-
* add gopy flag
12-
13-
* strings.Fields(x) -> x.split()
9+
The `-gopy` flag generates [GoPy](https:://github.com/go-python/gopy) specific Python code, including:
1410

15-
* class comments -> """
11+
* `nil` -> `go.nil`
12+
* `[]string{...}` -> `go.Slice_string([...])` etc for int, float64, float32
1613

17-
* switch -> ifs.. -- grab switch expr and put into each if
14+
The `-gogi` flag generates [GoGi](https:://github.com/goki/gi) specific Python code, including:
1815

19-
# gopy specific mode
16+
* struct tags generate: `self.SetTags()` call, for the `pygiv.ClassViewObj` class, which then provides an automatic GUI view with tag-based formatting of struct fields.
2017

21-
* replace []string() -> go.Slice_string etc
18+
# TODO
2219

23-
# Check
20+
* switch -> ifs.. -- grab switch expr and put into each if
2421

2522

format.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func format(
3636
if err != nil {
3737
return nil, err
3838
}
39-
pyfix := pyEdits(buf.Bytes(), true)
39+
pyfix := pyEdits(buf.Bytes())
4040
return pyfix, nil
4141
// return buf.Bytes(), nil
4242
}
@@ -82,7 +82,7 @@ func format(
8282
return nil, err
8383
}
8484

85-
pyfix := pyEdits(buf.Bytes(), true)
85+
pyfix := pyEdits(buf.Bytes())
8686

8787
out := sourceAdj(pyfix, cfg.Indent)
8888

gotopy.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,17 @@ var (
3838
simplifyAST = flag.Bool("s", false, "simplify code")
3939
doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
4040
allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)")
41+
gopyMode = flag.Bool("gopy", false, "support GoPy-specific Python code generation")
42+
gogiMode = flag.Bool("gogi", false, "support GoGi-specific Python code generation (implies gopy)")
4143

4244
// debugging
4345
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
4446
)
4547

4648
// Keep these in sync with go/format/format.go.
4749
const (
48-
tabWidth = 8
49-
printerMode = pyprint.UseSpaces | pyprint.TabIndent | printerNormalizeNumbers
50+
tabWidth = 8
51+
printerModeDef = pyprint.UseSpaces | pyprint.TabIndent | printerNormalizeNumbers
5052

5153
// printerNormalizeNumbers means to canonicalize number literal prefixes
5254
// and exponents while printing. See https://golang.org/doc/go1.13#gofmt.
@@ -56,10 +58,11 @@ const (
5658
)
5759

5860
var (
59-
fileSet = token.NewFileSet() // per process FileSet
60-
exitCode = 0
61-
rewrite func(*ast.File) *ast.File
62-
parserMode parser.Mode
61+
fileSet = token.NewFileSet() // per process FileSet
62+
exitCode = 0
63+
rewrite func(*ast.File) *ast.File
64+
parserMode parser.Mode
65+
printerMode = printerModeDef
6366
)
6467

6568
func report(err error) {
@@ -224,6 +227,14 @@ func gofmtMain() {
224227
return
225228
}
226229

230+
if *gopyMode {
231+
printerMode |= pyprint.GoPy
232+
}
233+
234+
if *gogiMode {
235+
printerMode |= pyprint.GoGi | pyprint.GoPy
236+
}
237+
227238
for i := 0; i < flag.NArg(); i++ {
228239
path := flag.Arg(i)
229240
switch dir, err := os.Stat(path); {

pyedits.go

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ package main
66

77
import (
88
"bytes"
9+
"fmt"
910
"strings"
11+
12+
"github.com/goki/gotopy/pyprint"
1013
)
1114

1215
// moveLines moves the st,ed region to 'to' line
@@ -26,11 +29,10 @@ func moveLines(lines *[][]byte, to, st, ed int) {
2629
// * moves python segments around, e.g., methods
2730
// into their proper classes
2831
// * fixes printf, slice other common code
29-
func pyEdits(src []byte, gopy bool) []byte {
32+
func pyEdits(src []byte) []byte {
3033
type sted struct {
3134
st, ed int
3235
}
33-
3436
classes := map[string]sted{}
3537

3638
nl := []byte("\n")
@@ -41,10 +43,14 @@ func pyEdits(src []byte, gopy bool) []byte {
4143
fmtSprintf := []byte("fmt.Sprintf(")
4244
prints := []byte("print")
4345
eqappend := []byte("= append(")
46+
elseif := []byte("else if")
47+
elif := []byte("elif")
4448
itoa := []byte("strconv.Itoa")
4549
float64p := []byte("float64(")
4650
float32p := []byte("float32(")
4751
floatp := []byte("float(")
52+
stringp := []byte("string(")
53+
strp := []byte("str(")
4854
slicestr := []byte("[]string(")
4955
sliceint := []byte("[]int(")
5056
slicefloat64 := []byte("[]float64(")
@@ -53,6 +59,8 @@ func pyEdits(src []byte, gopy bool) []byte {
5359
gosliceint := []byte("go.Slice_int([")
5460
goslicefloat64 := []byte("go.Slice_float64([")
5561
goslicefloat32 := []byte("go.Slice_float32([")
62+
stringsdot := []byte("strings.")
63+
copyp := []byte("copy(")
5664

5765
endclass := "EndClass: "
5866
method := "Method: "
@@ -66,6 +74,9 @@ func pyEdits(src []byte, gopy bool) []byte {
6674
lastComSt := -1
6775
lastComEd := -1
6876

77+
gopy := (printerMode&pyprint.GoPy != 0)
78+
// gogi := (printerMode&pyprint.GoGi != 0)
79+
6980
li := 0
7081
for {
7182
if li >= len(lines) {
@@ -86,6 +97,7 @@ func pyEdits(src []byte, gopy bool) []byte {
8697

8798
ln = bytes.Replace(ln, float64p, floatp, -1)
8899
ln = bytes.Replace(ln, float32p, floatp, -1)
100+
ln = bytes.Replace(ln, stringp, strp, -1)
89101
lines[li] = ln
90102

91103
switch {
@@ -154,25 +166,66 @@ func pyEdits(src []byte, gopy bool) []byte {
154166
nln = append(nln, []byte(".append(")...)
155167
nln = append(nln, ln[idx+len(eqappend)+comi+1:]...)
156168
lines[li] = nln
157-
case bytes.Contains(ln, slicestr):
169+
case bytes.Contains(ln, stringsdot):
170+
idx := bytes.Index(ln, stringsdot)
171+
pi := idx + len(stringsdot) + bytes.Index(ln[idx+len(stringsdot):], []byte("("))
172+
comi := bytes.Index(ln[pi:], []byte(","))
173+
nln := make([]byte, idx)
174+
copy(nln, ln[:idx])
175+
if comi < 0 {
176+
comi = bytes.Index(ln[pi:], []byte(")"))
177+
nln = append(nln, ln[pi+1:pi+comi]...)
178+
nln = append(nln, '.')
179+
meth := bytes.ToLower(ln[idx+len(stringsdot) : pi+1])
180+
fmt.Println(string(meth))
181+
if bytes.Equal(meth, []byte("fields(")) {
182+
meth = []byte("split(")
183+
}
184+
nln = append(nln, meth...)
185+
nln = append(nln, ln[pi+comi:]...)
186+
} else {
187+
nln = append(nln, ln[pi+1:pi+comi]...)
188+
nln = append(nln, '.')
189+
meth := bytes.ToLower(ln[idx+len(stringsdot) : pi+1])
190+
nln = append(nln, meth...)
191+
nln = append(nln, ln[pi+comi+1:]...)
192+
}
193+
lines[li] = nln
194+
case bytes.Contains(ln, copyp):
195+
idx := bytes.Index(ln, copyp)
196+
pi := idx + len(copyp) + bytes.Index(ln[idx+len(stringsdot):], []byte("("))
197+
comi := bytes.Index(ln[pi:], []byte(","))
198+
nln := make([]byte, idx)
199+
copy(nln, ln[:idx])
200+
nln = append(nln, ln[pi+1:pi+comi]...)
201+
nln = append(nln, '.')
202+
nln = append(nln, copyp...)
203+
nln = append(nln, ln[pi+comi+1:]...)
204+
lines[li] = nln
205+
case bytes.Contains(ln, itoa):
206+
ln = bytes.Replace(ln, itoa, []byte(`str`), -1)
207+
lines[li] = ln
208+
case bytes.Contains(ln, elseif):
209+
ln = bytes.Replace(ln, elseif, elif, -1)
210+
lines[li] = ln
211+
212+
// gopy cases
213+
case gopy && bytes.Contains(ln, slicestr):
158214
ln = bytes.Replace(ln, slicestr, goslicestr, -1)
159215
ln = bytes.Replace(ln, []byte(")"), []byte("])"), 1)
160216
lines[li] = ln
161-
case bytes.Contains(ln, sliceint):
217+
case gopy && bytes.Contains(ln, sliceint):
162218
ln = bytes.Replace(ln, sliceint, gosliceint, -1)
163219
ln = bytes.Replace(ln, []byte(")"), []byte("])"), 1)
164220
lines[li] = ln
165-
case bytes.Contains(ln, slicefloat64):
221+
case gopy && bytes.Contains(ln, slicefloat64):
166222
ln = bytes.Replace(ln, slicefloat64, goslicefloat64, -1)
167223
ln = bytes.Replace(ln, []byte(")"), []byte("])"), 1)
168224
lines[li] = ln
169-
case bytes.Contains(ln, slicefloat32):
225+
case gopy && bytes.Contains(ln, slicefloat32):
170226
ln = bytes.Replace(ln, slicefloat32, goslicefloat32, -1)
171227
ln = bytes.Replace(ln, []byte(")"), []byte("])"), 1)
172228
lines[li] = ln
173-
case bytes.Contains(ln, itoa):
174-
ln = bytes.Replace(ln, itoa, []byte(`str`), -1)
175-
lines[li] = ln
176229
}
177230
li++
178231
}

pyprint/nodes.go

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,17 @@ func (p *printer) setLineComment(text string) {
443443
p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
444444
}
445445

446+
func (p *printer) printFieldInit(fi ast.Expr) {
447+
switch fi.(type) {
448+
case *ast.Ident, *ast.SelectorExpr:
449+
p.expr(fi)
450+
p.print(token.LPAREN, token.RPAREN)
451+
default:
452+
p.expr(fi)
453+
// fmt.Printf("%T\n", fi)
454+
}
455+
}
456+
446457
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
447458
lbrace := fields.Opening
448459
list := fields.List
@@ -496,6 +507,9 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
496507

497508
if isStruct {
498509
p.print("def __init__(self):", newline, indent)
510+
if p.Mode&GoGi != 0 {
511+
p.print("super(Sim, self).__init__()", newline)
512+
}
499513
sep := vtab
500514
if len(list) == 1 {
501515
sep = blank
@@ -512,8 +526,12 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
512526
if len(f.Names) > 0 {
513527
// named fields
514528
p.identList(f.Names, false)
515-
p.print(sep)
516-
p.expr(f.Type)
529+
p.print(sep, token.ASSIGN, sep)
530+
if se, ok := f.Type.(*ast.StarExpr); ok {
531+
p.printFieldInit(se.X)
532+
} else {
533+
p.printFieldInit(f.Type)
534+
}
517535
extraTabs = 1
518536
} else {
519537
// anonymous field
@@ -525,8 +543,16 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
525543
p.print(sep)
526544
}
527545
p.print(sep)
528-
p.print("# ")
529-
p.expr(f.Tag)
546+
if p.Mode&GoGi != 0 {
547+
p.print(newline, `self.SetTags("`+f.Names[0].Name+`", '`)
548+
tg := f.Tag.Value
549+
tg = strings.Replace(tg, "'", `\'`, -1)
550+
p.print(tg[1 : len(tg)-1]) // cut out ` `
551+
p.print(`')`)
552+
} else {
553+
p.print("# ")
554+
p.expr(f.Tag)
555+
}
530556
extraTabs = 0
531557
}
532558
if f.Comment != nil {
@@ -986,10 +1012,11 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
9861012
p.fieldList(x.Methods, false, x.Incomplete)
9871013

9881014
case *ast.MapType:
989-
p.print(token.MAP, token.LBRACK)
990-
p.expr(x.Key)
991-
p.print(token.RBRACK)
992-
p.expr(x.Value)
1015+
p.print(token.LBRACE, token.RBRACE)
1016+
// p.print(token.MAP, token.LBRACK)
1017+
// p.expr(x.Key)
1018+
// p.print(token.RBRACK)
1019+
// p.expr(x.Value)
9931020

9941021
case *ast.ChanType:
9951022
switch x.Dir {
@@ -1658,6 +1685,9 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
16581685
p.flush(p.pos, token.TYPE) // get rid of any comments
16591686
p.print("class", blank)
16601687
p.expr(s.Name)
1688+
if p.Mode&GoGi != 0 {
1689+
p.print("(pygiv.ClassViewObj):", newline)
1690+
}
16611691
// if n == 1 {
16621692
// p.print(blank)
16631693
// } else {
@@ -1666,8 +1696,10 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
16661696
if s.Assign.IsValid() {
16671697
p.print(token.ASSIGN, blank)
16681698
}
1669-
p.pyFuncComments(s.Doc) // neither s.Doc nor s.Comment work here
1699+
doc := p.comments[p.cindex-1]
1700+
p.pyFuncComments(doc) // neither s.Doc nor s.Comment work here
16701701
p.expr(s.Type)
1702+
p.print(newline)
16711703
p.print("<<<<EndClass: ")
16721704
p.expr(s.Name)
16731705
p.print(">>>>", newline)
@@ -1859,19 +1891,24 @@ func (p *printer) pyFuncComments(com *ast.CommentGroup) {
18591891
if com == nil || len(com.List) == 0 {
18601892
return
18611893
}
1894+
p.print("\t")
18621895
p.print(`"""`, newline)
18631896
for _, c := range com.List {
1897+
p.print("\t")
18641898
if len(c.Text) < 3 {
18651899
p.print(c.Text)
18661900
} else {
18671901
if c.Text[1] == '/' {
18681902
p.print(c.Text[3:])
1903+
} else if c.Text[0] == '#' {
1904+
p.print(c.Text[2:])
18691905
} else {
18701906
p.print(c.Text)
18711907
}
18721908
}
18731909
p.print(newline)
18741910
}
1911+
p.print("\t")
18751912
p.print(`"""`, newline)
18761913
}
18771914

@@ -1904,9 +1941,8 @@ func (p *printer) funcDecl(d *ast.FuncDecl) {
19041941
}
19051942
p.signature(d.Type.Params, d.Type.Results)
19061943
p.print(token.RPAREN)
1907-
p.print(token.COLON, newline, indent)
1944+
p.print(token.COLON, newline)
19081945
p.pyFuncComments(d.Doc)
1909-
p.print(unindent)
19101946
p.funcBody(p.distanceFrom(d.Pos(), startCol), vtab, d.Body)
19111947
if d.Recv != nil {
19121948
p.print(unindent)

pyprint/printer.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,9 @@ func (p *printer) print(args ...interface{}) {
10191019
case "false":
10201020
data = "False"
10211021
case "nil":
1022-
data = "go.nil" // todo: gopy mode
1022+
if p.Config.Mode&GoPy != 0 {
1023+
data = "go.nil"
1024+
}
10231025
}
10241026

10251027
p.writeString(next, data, isLit)
@@ -1293,6 +1295,8 @@ const (
12931295
TabIndent // use tabs for indentation independent of UseSpaces
12941296
UseSpaces // use spaces instead of tabs for alignment
12951297
SourcePos // emit //line directives to preserve original source positions
1298+
GoPy // support GoPy-specific Python code generation
1299+
GoGi // support GoGi-specific Python code generation
12961300
)
12971301

12981302
// The mode below is not included in printer's public API because

0 commit comments

Comments
 (0)