├── go.mod ├── parser ├── util.go ├── integration_test.go ├── config_test.go ├── goprogram_test.go ├── typedata_test.go ├── gofunc.go ├── methodmap.go ├── govar.go ├── config.go ├── typedata.go ├── transform.go └── analysis.go ├── .gitignore ├── grammar ├── lexer_test.go ├── strrdr.go ├── yacc_test.go └── jobj.go ├── .vscode └── launch.json ├── testutil └── assert.go ├── main_test.go ├── README.md ├── main.go ├── LICENSE └── dumper └── dump.go /go.mod: -------------------------------------------------------------------------------- 1 | module java2go 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /parser/util.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import "go/ast" 4 | 5 | func makeField(name string, texpr ast.Expr) *ast.Field { 6 | fname := make([]*ast.Ident, 0) 7 | if name != "" { 8 | fname = append(fname, ast.NewIdent(name)) 9 | } 10 | 11 | return &ast.Field{Names: fname, Type: texpr} 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | 25 | # OS X cruft 26 | .DS_Store 27 | -------------------------------------------------------------------------------- /grammar/lexer_test.go: -------------------------------------------------------------------------------- 1 | package grammar 2 | 3 | import ( 4 | "testing" 5 | 6 | "java2go/testutil" 7 | ) 8 | 9 | func Test_FileLexer(t *testing.T) { 10 | pgm := "public class foo{ private int val;" + 11 | " public int getVal() { return val; }" + 12 | " public foo(int val) { this.val = val; } }" 13 | 14 | rdr := NewStringReader(pgm) 15 | 16 | lx := NewLexer(rdr, false) 17 | testutil.AssertNotNil(t, lx, "Lexer should not be nil") 18 | } 19 | -------------------------------------------------------------------------------- /grammar/strrdr.go: -------------------------------------------------------------------------------- 1 | package grammar 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | type StringReader struct { 8 | bytes []byte 9 | pos int 10 | } 11 | 12 | func NewStringReader(str string) *StringReader { 13 | return &StringReader{bytes: []byte(str), pos: 0} 14 | } 15 | 16 | func (rdr *StringReader) ReadByte() (byte, error) { 17 | if rdr.pos >= len(rdr.bytes) { 18 | return 0, io.EOF 19 | } 20 | 21 | c := rdr.bytes[rdr.pos] 22 | rdr.pos += 1 23 | return c, nil 24 | } 25 | -------------------------------------------------------------------------------- /grammar/yacc_test.go: -------------------------------------------------------------------------------- 1 | package grammar 2 | 3 | import ( 4 | "testing" 5 | 6 | "java2go/testutil" 7 | ) 8 | 9 | func Test_Simple(t *testing.T) { 10 | pgm := "public class foo{ private int val;" + 11 | " public int getVal() { return val; }" + 12 | " public foo(int val) { this.val = val; }" + 13 | "}" 14 | 15 | rdr := NewStringReader(pgm) 16 | 17 | lx := NewLexer(rdr, false) 18 | 19 | rtn := JulyParse(lx) 20 | testutil.AssertEqual(t, rtn, 0, "Expected", 0, "not", rtn) 21 | } 22 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Package", 9 | "type": "go", 10 | "request": "launch", 11 | "mode": "auto", 12 | "program": "${workspaceFolder}", 13 | "args": [ 14 | "--", 15 | "path/to/java/File.java" 16 | ] 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /testutil/assert.go: -------------------------------------------------------------------------------- 1 | package testutil 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func AssertEmpty(t *testing.T, val string, args ...interface{}) { 8 | if val != "" { 9 | t.Fatal(args) 10 | } 11 | } 12 | 13 | func AssertEqual(t *testing.T, a interface{}, b interface{}, 14 | args ...interface{}) { 15 | if a != b { 16 | t.Fatal(args) 17 | } 18 | } 19 | 20 | func AssertFalse(t *testing.T, val bool, args ...interface{}) { 21 | if val { 22 | t.Fatal(args) 23 | } 24 | } 25 | 26 | func AssertNil(t *testing.T, val interface{}, args ...interface{}) { 27 | if val != nil { 28 | t.Fatal(args) 29 | } 30 | } 31 | 32 | func AssertNotNil(t *testing.T, val interface{}, args ...interface{}) { 33 | if val == nil { 34 | t.Fatal(args) 35 | } 36 | } 37 | 38 | func AssertTrue(t *testing.T, val bool, args ...interface{}) { 39 | if !val { 40 | t.Fatal(args) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "strings" 7 | "testing" 8 | 9 | "java2go/grammar" 10 | ) 11 | 12 | const pgm = "package main;\npublic class foo\n{\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"hello\");\n\t}\n}\n" 13 | 14 | func TestLexer(t *testing.T) { 15 | //parser.JulyDebug = 9 16 | 17 | l := grammar.NewLexer(bufio.NewReader(strings.NewReader(pgm)), false) 18 | 19 | lval := &grammar.JulySymType{} 20 | 21 | var num int 22 | for { 23 | rtn := l.Lex(lval) 24 | if rtn == 0 { 25 | break 26 | } 27 | 28 | num++ 29 | 30 | var tname string 31 | if rtn >= 57346 { 32 | tname = grammar.JulyToknames[rtn-57346] 33 | } else { 34 | tname = fmt.Sprintf("tok#%d (ch '%c')", rtn, byte(rtn)) 35 | } 36 | 37 | fmt.Printf("#%d: rtn %s\n\t%v\n", num, tname, lval) 38 | } 39 | } 40 | 41 | func TestBoth(t *testing.T) { 42 | //parser.JulyDebug = 9 43 | 44 | l := grammar.NewLexer(bufio.NewReader(strings.NewReader(pgm)), false) 45 | 46 | grammar.JulyParse(l) 47 | //if err != nil { 48 | // fmt.Printf("Error in \"%v\": %v\n", input, err) 49 | //} else { 50 | // fmt.Printf("\"%v\" -> %v<%T>\n", input, st.(java.Val), st) 51 | //} 52 | //fmt.Printf("input \"%v\" -> %d\n", pgm, sym) 53 | } 54 | -------------------------------------------------------------------------------- /parser/integration_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | 8 | "java2go/grammar" 9 | "java2go/testutil" 10 | ) 11 | 12 | func Test_Main(t *testing.T) { 13 | src := "public class foo\n" + 14 | "{\n" + 15 | " private int val;\n" + 16 | " public int getVal() { return val; }\n" + 17 | " public foo(int val) { this.val = val; }\n" + 18 | " public static final void main(String[] args) {\n" + 19 | " for (int i = 0; i < args.length; i++) {\n" + 20 | " System.out.println(\"Arg#\" + i + \"=\" + args[i]);\n" + 21 | " System.err.printf(\"Arg#%d=%s\\n\", i, args[i]);\n" + 22 | " }\n" + 23 | " }\n" + 24 | "}\n" 25 | 26 | rdr := grammar.NewStringReader(src) 27 | 28 | lx := grammar.NewLexer(rdr, false) 29 | 30 | rtn := grammar.JulyParse(lx) 31 | testutil.AssertEqual(t, rtn, 0, "Expected", 0, "not", rtn) 32 | testutil.AssertNotNil(t, lx.JavaProgram(), "Parser did not return Java parse tree") 33 | 34 | pgm := NewGoProgram("", nil, false) 35 | pgm.Analyze(lx.JavaProgram()) 36 | 37 | fmt.Println("========= PARSE TREE =============") 38 | pgm.WriteString(os.Stdout) 39 | fmt.Println() 40 | 41 | for _, rule := range StandardRules { 42 | pgm.RunTransform(rule, pgm, nil, nil) 43 | } 44 | 45 | fmt.Println("========= FINAL PROGRAM =============") 46 | pgm.Dump(os.Stdout) 47 | } 48 | -------------------------------------------------------------------------------- /parser/config_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "io/ioutil" 5 | "strings" 6 | "testing" 7 | 8 | "java2go/testutil" 9 | ) 10 | 11 | func fillFile(t *testing.T) string { 12 | f, err := ioutil.TempFile("", "tstcfg") 13 | if err != nil { 14 | t.Fatal("Cannot create temporary file") 15 | } 16 | 17 | f.WriteString("PACKAGE a.b -> ab\n") 18 | f.WriteString("PACKAGE a.b.c -> abc\n") 19 | f.WriteString("INTERFACE a.b.DEF\n") 20 | f.WriteString("INTERFACE a.b.GHI\n") 21 | f.WriteString("RECEIVER a.b.XXX -> xxx\n") 22 | f.WriteString("RECEIVER a.b.ZZZ -> zzz\n") 23 | f.Close() 24 | return f.Name() 25 | } 26 | 27 | func Test_Config_Empty(t *testing.T) { 28 | cfg := &Config{} 29 | is_iface := cfg.isInterface("foo") 30 | testutil.AssertFalse(t, is_iface, "isInterface() returned true") 31 | pkg := cfg.packageName("foo") 32 | testutil.AssertEmpty(t, pkg, "Package() returned", pkg) 33 | rcvr := cfg.receiver("foo") 34 | testutil.AssertEmpty(t, rcvr, "Receiver() returned", rcvr) 35 | str := cfg.String() 36 | if !strings.HasPrefix(str, "Config[") || !strings.HasSuffix(str, "]") { 37 | t.Fatal("String() returned", str) 38 | } 39 | } 40 | 41 | func Test_Config_Full(t *testing.T) { 42 | name := fillFile(t) 43 | 44 | cfg := ReadConfig(name) 45 | 46 | var pkg string 47 | pkg = cfg.packageName("a.b") 48 | testutil.AssertEqual(t, pkg, "ab") 49 | pkg = cfg.packageName("a.b.c") 50 | testutil.AssertEqual(t, pkg, "abc") 51 | 52 | var is_iface bool 53 | is_iface = cfg.isInterface("a.b.DEF") 54 | testutil.AssertTrue(t, is_iface, "a.b.DEF is not an interface") 55 | is_iface = cfg.isInterface("a.b.GHI") 56 | testutil.AssertTrue(t, is_iface, "a.b.GHI is not an interface") 57 | 58 | var rcvr string 59 | rcvr = cfg.receiver("a.b.XXX") 60 | testutil.AssertEqual(t, rcvr, "xxx") 61 | rcvr = cfg.receiver("a.b.ZZZ") 62 | testutil.AssertEqual(t, rcvr, "zzz") 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | java2go 2 | ======= 3 | 4 | ##### Convert Java code to something like Go 5 | 6 | This has been my free-time hacking project for the last few months. It's in a pre-alpha state, but it can convert around 75% of the Java code on my laptop into something that kind of looks like Go code, and if you're lucky that converted code may even be compilable. 7 | 8 | ##### Basic instructions 9 | 10 | To use it: 11 | 12 | go get github.com/dglo/java2go 13 | 14 | then either: 15 | 16 | go run src/github.com/dglo/java2go/main.go -- path/to/my.java 17 | 18 | or: 19 | 20 | go build github.com/dglo/java2go 21 | ./java2go -- path/to/my.java 22 | 23 | ##### Translating multiple files 24 | 25 | If you specify a directory with `-dir`, it will write the translated file(s) to the corresponding `.go` file: 26 | 27 | go run src/github.com/dglo/java2go/main.go --dir . -- *.java 28 | 29 | ##### Customizing the translation 30 | 31 | You can specify a config file with the `-config` option to specify how to translate Java packages to Go packages. The config file supports three different directives: 32 | 33 | * `PACKAGE a.b.c -> go_a_b_c` maps Java package `a.b.c` to Go package `go_a_b_c` 34 | * `INTERFACE go_a_b_c.FooInterface` says Go object `FooInterface` in Go package `go_a_b_c` is an interface. This is only needed for interfaces which are referenced but not defined in a class. 35 | * `RECEIVER go_a_b_c.BarClass -> bc` uses `bc` as the name of the receiver object for all functions defined on BarClass, rather than the default `rcvr`. 36 | 37 | ##### Tweaking the code to translate your project 38 | 39 | This project does some minor transformations from idiomatic Java into 40 | somewhat idiomatic Go, but doesn't do anything with channels or goroutines. 41 | 42 | If you'd like to add your own Java-to-Go transformation(s), you can check out `java2go/parser/transform.go`. The `-report` option is helpful in determining what should be transformed. 43 | 44 | ##### Bugs 45 | 46 | The most difficult bug to fix is the Lex/Yacc code which chokes on some legal Java, especially the '...' operator. 47 | -------------------------------------------------------------------------------- /parser/goprogram_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "testing" 7 | 8 | "java2go/grammar" 9 | "java2go/testutil" 10 | ) 11 | 12 | func Test_FixName(t *testing.T) { 13 | raw := "NaMe" 14 | 15 | modmap := make(map[string]string) 16 | modmap["public"] = "NaMe" 17 | modmap["protected"] = "NaMe" 18 | modmap["private"] = "naMe" 19 | 20 | for modtype, fixed := range modmap { 21 | jmod := grammar.NewJModifiers(modtype, nil) 22 | nm := fixName(raw, jmod) 23 | testutil.AssertEqual(t, nm, fixed, "For modtype", modtype, "expected", fixed, 24 | "not", nm) 25 | } 26 | } 27 | 28 | func Test_GoProgram_Basic(t *testing.T) { 29 | name := "foo" 30 | gp := NewGoProgram(name, nil, false) 31 | 32 | gp.Analyze(nil) 33 | 34 | rcvr := gp.Receiver("foo") 35 | testutil.AssertEqual(t, rcvr, "rcvr", "Expected rcvr, not", rcvr) 36 | 37 | imap := gp.Imports() 38 | testutil.AssertNotNil(t, imap, "ImportMap() should not return nil") 39 | testutil.AssertEqual(t, len(imap), 0, "Did not expect ImportMap to contain", imap) 40 | 41 | decls := gp.Decls() 42 | testutil.AssertNotNil(t, decls, "Decls() should not return nil") 43 | testutil.AssertEqual(t, len(decls), 0, "Did not expect Decls to contain", decls) 44 | 45 | dout := &bytes.Buffer{} 46 | gp.Dump(dout) 47 | dstr := dout.String() 48 | expDstr := "package main\n" 49 | testutil.AssertEqual(t, dstr, expDstr, "Expected '", expDstr, "' not '", dstr, "'") 50 | 51 | file := gp.File() 52 | testutil.AssertNotNil(t, file, "File() should not return nil") 53 | testutil.AssertNotNil(t, file.Name, "File.Name should not be nil") 54 | testutil.AssertNotNil(t, file.Name.Name, "main", 55 | "File.Name.Name should be", "main", file.Name.Name) 56 | testutil.AssertNotNil(t, file.Decls, "File.Decls() should not return nil") 57 | testutil.AssertEqual(t, len(file.Decls), 0, 58 | "Did not expect File.Decls to contain", file.Decls) 59 | testutil.AssertNotNil(t, file.Imports, "File.Imports() should not return nil") 60 | testutil.AssertEqual(t, len(file.Imports), 0, 61 | "Did not expect File.Imports to contain", file.Imports) 62 | testutil.AssertEqual(t, len(file.Unresolved), 0, 63 | "File.Unresolved should be empty but contains", len(file.Unresolved), 64 | "entries") 65 | testutil.AssertEqual(t, len(file.Comments), 0, 66 | "File.Comments should be empty but contains", len(file.Comments), 67 | "entries") 68 | 69 | fs := gp.FileSet() 70 | fmt.Printf("FileSet -> %v\n", fs) 71 | 72 | sout := &bytes.Buffer{} 73 | gp.WriteString(sout) 74 | fmt.Printf("File -> %v\n", sout.String()) 75 | 76 | } 77 | -------------------------------------------------------------------------------- /parser/typedata_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "testing" 7 | 8 | "java2go/testutil" 9 | ) 10 | 11 | func Test_TypeData_Primitive(t *testing.T) { 12 | allTypes := []string{ 13 | "void", "boolean", "byte", "char", "short", 14 | "int", "long", "float", "double", "string", 15 | } 16 | 17 | for _, str := range allTypes { 18 | for dim := 0; dim < 5; dim++ { 19 | td := NewTypeDataPrimitive(str, dim) 20 | 21 | _, is_nil := td.TypeName() 22 | testutil.AssertEqual(t, dim == 0 && strings.EqualFold(str, "void"), is_nil, 23 | str, "should not be nil", is_nil) 24 | 25 | var expStr string 26 | switch str { 27 | case "boolean": 28 | expStr = "bool" 29 | case "short": 30 | expStr = "int16" 31 | case "long": 32 | expStr = "int64" 33 | case "float": 34 | expStr = "float32" 35 | case "double": 36 | expStr = "float64" 37 | default: 38 | expStr = str 39 | } 40 | for i := 1; i <= dim; i++ { 41 | expStr = "[]" + expStr 42 | } 43 | 44 | testutil.AssertEqual(t, td.String(), expStr, "Expected", expStr, 45 | "not", td.String()) 46 | 47 | testutil.AssertFalse(t, td.isObject(), "Unexpected object", str) 48 | } 49 | } 50 | 51 | defer func() { 52 | if x := recover(); x != nil { 53 | testutil.AssertEqual(t, x, "Unrecognized primitive type xxx") 54 | } 55 | }() 56 | 57 | td := NewTypeDataPrimitive("xxx", 0) 58 | testutil.AssertNotNil(t, td, "Got nil TypeData for bad primitive type") 59 | } 60 | 61 | type FakeDictionary struct { 62 | dict map[string]bool 63 | } 64 | 65 | func (fd *FakeDictionary) ImportedType(typename string) string { 66 | if _, ok := fd.dict[typename]; ok { 67 | return typename 68 | } 69 | 70 | return "" 71 | } 72 | 73 | func (fd *FakeDictionary) IsInterface(typename string) bool { 74 | if val, ok := fd.dict[typename]; ok { 75 | return val 76 | } 77 | 78 | return false 79 | } 80 | 81 | func Test_TypeData_Object(t *testing.T) { 82 | fd := &FakeDictionary{dict: make(map[string]bool)} 83 | fd.dict["abc"] = true 84 | fd.dict["def"] = false 85 | 86 | for _, str := range []string{"abc", "def", "ghi"} { 87 | for dim := 0; dim < 5; dim++ { 88 | td := NewTypeDataObject(fd, str, dim) 89 | validate(t, str, dim, td, fd) 90 | } 91 | } 92 | } 93 | 94 | func validate(t *testing.T, str string, dim int, td *TypeData, 95 | fd *FakeDictionary) { 96 | vt, is_nil := td.TypeName() 97 | testutil.AssertEqual(t, dim == 0 && strings.EqualFold(str, "void"), is_nil, 98 | str, "should not be nil", is_nil) 99 | if !is_nil { 100 | testutil.AssertNotNil(t, vt, str, "dim", dim, "is nil ::", vt) 101 | } 102 | 103 | expName := str 104 | if dim == 0 { 105 | expName = str 106 | } else { 107 | var star string 108 | if fd != nil && !fd.IsInterface(str) { 109 | star = "*" 110 | } 111 | expName = fmt.Sprintf("array_%s%s_dim%d", star, str, dim) 112 | } 113 | testutil.AssertEqual(t, expName, td.Name(), "Expected name", expName, 114 | "not", td.Name()) 115 | 116 | var expStr string 117 | if fd == nil || fd.IsInterface(str) { 118 | expStr = str 119 | } else { 120 | expStr = "*" + str 121 | } 122 | for i := 1; i <= dim; i++ { 123 | expStr = "[]" + expStr 124 | } 125 | 126 | testutil.AssertEqual(t, expStr, td.String(), "Expected string ", expStr, 127 | "not", td.String()) 128 | 129 | if fd != nil { 130 | if dim == 0 { 131 | testutil.AssertTrue(t, td.isObject(), "Expected object", str) 132 | } else { 133 | testutil.AssertFalse(t, td.isObject(), "Unexpected object", str) 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /parser/gofunc.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "go/ast" 5 | "go/token" 6 | 7 | "java2go/grammar" 8 | ) 9 | 10 | type GoFunc interface { 11 | Create() ast.Stmt 12 | //Expr(gs *GoState) *ast.FuncDecl 13 | GoName() string 14 | Receiver() string 15 | } 16 | 17 | type GoFuncData struct { 18 | class string 19 | name string 20 | goname string 21 | func_type methodType 22 | rcvr string 23 | params []*grammar.JFormalParameter 24 | } 25 | 26 | func (gf *GoFuncData) Create() ast.Stmt { 27 | if gf.func_type != mt_constructor { 28 | return nil 29 | } 30 | 31 | // left side of first statement in NewFoo() 32 | // (assign new struct to the receiver) 33 | lhs := make([]ast.Expr, 1) 34 | lhs[0] = ast.NewIdent(gf.rcvr) 35 | 36 | // right side of first statement in NewFoo() 37 | // (create new struct) 38 | rhs := make([]ast.Expr, 1) 39 | rhs[0] = &ast.UnaryExpr{Op: token.AND, 40 | X: &ast.CompositeLit{Type: ast.NewIdent(gf.class)}} 41 | 42 | // build creation statement 43 | return &ast.AssignStmt{Lhs: lhs, Tok: token.DEFINE, Rhs: rhs} 44 | } 45 | 46 | /* 47 | func (gf *GoFuncData) Expr(gs *GoState) *ast.FuncDecl { 48 | mtype := &ast.FuncType{Params: gf.paramList(gs), Results: gf.results()} 49 | 50 | return &ast.FuncDecl{Name: ast.NewIdent(gf.goname), 51 | Recv: gf.recv(), Type: mtype} 52 | } 53 | */ 54 | 55 | func (gf *GoFuncData) GoName() string { 56 | return gf.goname 57 | } 58 | 59 | /* 60 | func (gf *GoFuncData) paramList(gs *GoState) *ast.FieldList { 61 | if gf.func_type == mt_test { 62 | if gf.params != nil && len(gf.params) > 0 { 63 | fmt.Fprintf(os.Stderr, 64 | "//ERR// Test method %s.%s should not have %d params\n", 65 | gf.class, gf.name, len(gf.params)) 66 | } 67 | 68 | selexp := &ast.SelectorExpr{X: ast.NewIdent("testing"), 69 | Sel: ast.NewIdent("T")} 70 | 71 | pfld := makeField("t", &ast.StarExpr{X: selexp}) 72 | 73 | paramList := make([]*ast.Field, 1) 74 | paramList[0] = pfld 75 | 76 | return &ast.FieldList{List: paramList} 77 | } 78 | 79 | if gf.params != nil && len(gf.params) > 0 { 80 | flist := make([]*ast.Field, len(gf.params)) 81 | 82 | for i, fp := range gf.params { 83 | if fp.typespec != nil { 84 | if fp.dims != 0 { 85 | fmt.Fprintf(os.Stderr, 86 | "//ERR// Ignoring %s dims=%d for %s.%s\n", 87 | fp.name, fp.dims, gf.class, gf.name) 88 | } else if fp.dotdotdot { 89 | fmt.Fprintf(os.Stderr, 90 | "//ERR// Ignoring %s dotdotdot=true for %s.%s\n", 91 | fp.name, gf.class, gf.name) 92 | } 93 | 94 | ftype := gs.createTypeData(fp.typespec.name, 95 | fp.typespec.type_args, fp.typespec.dims) 96 | 97 | flist[i] = makeField(fp.name, ftype.Expr()) 98 | } 99 | } 100 | 101 | return &ast.FieldList{List: flist} 102 | } 103 | 104 | return nil 105 | } 106 | */ 107 | 108 | func (gf *GoFuncData) Receiver() string { 109 | return gf.rcvr 110 | } 111 | 112 | func (gf *GoFuncData) recv() *ast.FieldList { 113 | if gf.func_type != mt_method { 114 | // non-methods don't have a receiver 115 | return nil 116 | } 117 | 118 | rlist := make([]*ast.Field, 1) 119 | rlist[0] = makeField(gf.rcvr, &ast.StarExpr{X: ast.NewIdent(gf.class)}) 120 | return &ast.FieldList{List: rlist} 121 | } 122 | 123 | func (gf *GoFuncData) results() *ast.FieldList { 124 | if gf.func_type != mt_constructor { 125 | return nil 126 | } 127 | 128 | // return the receiver 129 | rlist := make([]*ast.Field, 1) 130 | rlist[0] = makeField(gf.rcvr, &ast.StarExpr{X: ast.NewIdent(gf.class)}) 131 | return &ast.FieldList{List: rlist} 132 | } 133 | 134 | type GoFuncRef struct { 135 | gofunc GoFunc 136 | suffix *grammar.JTypeName 137 | } 138 | 139 | func (gfr *GoFuncRef) Create() ast.Stmt { 140 | return gfr.Create() 141 | } 142 | 143 | /* 144 | func (gfr *GoFuncRef) Expr(gs *GoState) *ast.FuncDecl { 145 | return gfr.Expr(gs) 146 | } 147 | */ 148 | 149 | func (gfr *GoFuncRef) GoName() string { 150 | return gfr.GoName() + "." + gfr.suffix.String() 151 | } 152 | 153 | func (gfr *GoFuncRef) Receiver() string { 154 | return gfr.Receiver() 155 | } 156 | -------------------------------------------------------------------------------- /parser/methodmap.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | "sort" 8 | ) 9 | 10 | type methodMapper interface { 11 | FixDuplicate(mlist []GoMethod, newmthd GoMethod) bool 12 | } 13 | 14 | type methodMap struct { 15 | methods map[string][]GoMethod 16 | } 17 | 18 | func (mmap *methodMap) AddMethod(newmthd GoMethod, mapper methodMapper) { 19 | if mmap.methods == nil { 20 | mmap.methods = make(map[string][]GoMethod) 21 | } 22 | if mthd, ok := mmap.methods[newmthd.Name()]; !ok { 23 | mmap.methods[newmthd.Name()] = make([]GoMethod, 1) 24 | mmap.methods[newmthd.Name()][0] = newmthd 25 | } else { 26 | if !mapper.FixDuplicate(mthd, newmthd) { 27 | mmap.methods[newmthd.Name()] = 28 | append(mmap.methods[newmthd.Name()], newmthd) 29 | } 30 | } 31 | } 32 | 33 | func (mmap *methodMap) FindMethod(name string, 34 | args *GoMethodArguments) GoMethod { 35 | for key, mlist := range mmap.methods { 36 | if key == name { 37 | for _, m := range mlist { 38 | if m.HasArguments(args) { 39 | return m 40 | } 41 | } 42 | } 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func (mmap *methodMap) Length() int { 49 | return len(mmap.methods) 50 | } 51 | 52 | func (mmap *methodMap) MethodList(name string) []GoMethod { 53 | if mmap.methods != nil { 54 | if mthd, ok := mmap.methods[name]; ok { 55 | return mthd 56 | } 57 | } 58 | 59 | return nil 60 | } 61 | 62 | func (mmap *methodMap) renumberDuplicateMethods(gp *GoProgram) { 63 | for _, mlist := range mmap.methods { 64 | if len(mlist) > 1 { 65 | n := 0 66 | for _, m := range mlist { 67 | if n > 0 { 68 | m.SetGoName(fmt.Sprintf("%s%d", m.GoName(), n + 1)) 69 | } 70 | n += 1 71 | } 72 | } 73 | } 74 | } 75 | 76 | func (mmap *methodMap) SortedKeys() []string { 77 | if mmap.methods == nil { 78 | return nil 79 | } 80 | 81 | flds := make([]string, len(mmap.methods)) 82 | i := 0 83 | for k, _ := range mmap.methods { 84 | flds[i] = k 85 | i++ 86 | } 87 | 88 | sort.Sort(sort.StringSlice(flds)) 89 | 90 | return flds 91 | } 92 | 93 | func (mmap *methodMap) WriteString(out io.Writer, verbose bool) { 94 | io.WriteString(out, "|") 95 | if !verbose { 96 | io.WriteString(out, fmt.Sprintf("%d methods", len(mmap.methods))) 97 | } else { 98 | no_comma := true 99 | for _, mlist := range mmap.methods { 100 | for _, m := range mlist { 101 | if no_comma { 102 | no_comma = false 103 | } else { 104 | io.WriteString(out, ",") 105 | } 106 | m.WriteString(out) 107 | } 108 | } 109 | } 110 | } 111 | 112 | type classMethodMap struct { 113 | methodMap 114 | } 115 | 116 | // create a map of class names to objects 117 | func NewClassMethodMap() *classMethodMap { 118 | return &classMethodMap{methodMap{}} 119 | } 120 | 121 | func (cmm *classMethodMap) FixDuplicate(mlist []GoMethod, newmthd GoMethod) bool { 122 | fixed := false 123 | if gm, is_gm := newmthd.(*GoClassMethod); !is_gm { 124 | if _, is_ref := newmthd.(*GoMethodReference); !is_ref { 125 | log.Printf("//ERR// Unknown class method type %T\n", newmthd) 126 | } 127 | fixed = true 128 | } else { 129 | for i, m2 := range mlist { 130 | if m2.IsMethod(newmthd) { 131 | if _, m2ok := m2.(*GoMethodReference); m2ok { 132 | m2.SetOriginal(gm) 133 | mlist[i] = gm 134 | fixed = true 135 | } 136 | } 137 | } 138 | } 139 | return fixed 140 | } 141 | 142 | type interfaceMethodMap struct { 143 | methodMap 144 | } 145 | 146 | // create a map of interface names to objects 147 | func NewInterfaceMethodMap() *interfaceMethodMap { 148 | return &interfaceMethodMap{methodMap{}} 149 | } 150 | 151 | func (cmm *interfaceMethodMap) FixDuplicate(mlist []GoMethod, newmthd GoMethod) bool { 152 | fixed := false 153 | if gm, is_gm := newmthd.(*GoIfaceMethod); !is_gm { 154 | if _, is_ref := newmthd.(*GoMethodReference); !is_ref { 155 | log.Printf("//ERR// Unknown interface method type %T\n", newmthd) 156 | } 157 | fixed = true 158 | } else { 159 | for i, m2 := range mlist { 160 | if m2.IsMethod(newmthd) { 161 | if _, m2ok := m2.(*GoMethodReference); m2ok { 162 | //m2.SetOriginal(gm) 163 | log.Printf("//ERR// Not setting original for interface" + 164 | " method %T\n", newmthd) 165 | mlist[i] = gm 166 | fixed = true 167 | } 168 | } 169 | } 170 | } 171 | return fixed 172 | } 173 | -------------------------------------------------------------------------------- /parser/govar.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "go/ast" 7 | ) 8 | 9 | type GoVar interface { 10 | GoObject 11 | Expr() ast.Expr 12 | GoName() string 13 | Equals(govar GoVar) bool 14 | hasVariable(govar GoVar) bool 15 | Ident() *ast.Ident 16 | Init() ast.Stmt 17 | IsClassField() bool 18 | IsFinal() bool 19 | IsStatic() bool 20 | Name() string 21 | Receiver() string 22 | SetGoName(newname string) 23 | String() string 24 | Type() ast.Expr 25 | VarType() *TypeData 26 | } 27 | 28 | type GoVarData struct { 29 | rcvr string 30 | name string 31 | goname string 32 | vartype *TypeData 33 | class_field bool 34 | is_static bool 35 | is_final bool 36 | } 37 | 38 | func (gvd *GoVarData) Expr() ast.Expr { 39 | ident := gvd.Ident() 40 | if gvd.rcvr == "" || gvd.is_static { 41 | return ident 42 | } 43 | 44 | return &ast.SelectorExpr{X: ast.NewIdent(gvd.rcvr), Sel: ident} 45 | } 46 | 47 | func (gvd *GoVarData) GoName() string { 48 | return gvd.goname 49 | } 50 | 51 | func (gvd *GoVarData) Equals(govar GoVar) bool { 52 | if gvd == govar { 53 | return true 54 | } else if gvd == nil || govar == nil { 55 | return false 56 | } 57 | 58 | return gvd.rcvr == govar.Receiver() && gvd.name == govar.Name() 59 | } 60 | 61 | func (gvd *GoVarData) hasVariable(govar GoVar) bool { 62 | return gvd.Equals(govar) 63 | } 64 | 65 | func (gvd *GoVarData) Ident() *ast.Ident { 66 | return ast.NewIdent(gvd.goname) 67 | } 68 | 69 | func (gvd *GoVarData) Init() ast.Stmt { 70 | return nil 71 | } 72 | 73 | func (gvd *GoVarData) IsClassField() bool { 74 | return gvd.class_field 75 | } 76 | 77 | func (gvd *GoVarData) IsFinal() bool { 78 | return gvd.is_final 79 | } 80 | 81 | func (gvd *GoVarData) IsStatic() bool { 82 | return gvd.is_static 83 | } 84 | 85 | func (gvd *GoVarData) Name() string { 86 | return gvd.name 87 | } 88 | 89 | func (gvd *GoVarData) Receiver() string { 90 | return gvd.rcvr 91 | } 92 | 93 | func (gvd *GoVarData) RunTransform(xform TransformFunc, prog *GoProgram, cls GoClass, parent GoObject) (GoObject, bool) { 94 | return xform(parent, prog, cls, gvd) 95 | } 96 | 97 | func (gvd *GoVarData) SetGoName(newname string) { 98 | gvd.goname = newname 99 | } 100 | 101 | func (gvd *GoVarData) String() string { 102 | b := &bytes.Buffer{} 103 | b.WriteString("GoVarData[") 104 | if gvd.rcvr != "" { 105 | b.WriteString(gvd.rcvr) 106 | b.WriteString(".") 107 | } 108 | b.WriteString(gvd.name) 109 | b.WriteString(fmt.Sprintf("<%v>->", gvd.vartype)) 110 | b.WriteString(gvd.goname) 111 | 112 | if gvd.class_field || gvd.is_final || gvd.is_static { 113 | b.WriteString(" (") 114 | 115 | need_sep := false 116 | 117 | if gvd.class_field { 118 | if need_sep { 119 | b.WriteString("|") 120 | } 121 | b.WriteString("clsfld") 122 | need_sep = true 123 | } 124 | 125 | if gvd.is_final { 126 | if need_sep { 127 | b.WriteString("|") 128 | } 129 | b.WriteString("final") 130 | need_sep = true 131 | } 132 | 133 | if gvd.is_static { 134 | if need_sep { 135 | b.WriteString("|") 136 | } 137 | b.WriteString("static") 138 | need_sep = true 139 | } 140 | 141 | b.WriteString(")") 142 | } 143 | b.WriteString("]") 144 | 145 | return b.String() 146 | } 147 | 148 | func (gvd *GoVarData) Type() ast.Expr { 149 | if gvd.vartype == nil { 150 | return nil 151 | } 152 | 153 | return gvd.vartype.Expr() 154 | } 155 | 156 | func (gvd *GoVarData) VarType() *TypeData { 157 | return gvd.vartype 158 | } 159 | 160 | type GoClassAttribute struct { 161 | govar GoVar 162 | suffix string 163 | } 164 | 165 | func (gvr *GoClassAttribute) Equals(govar GoVar) bool { 166 | return gvr.govar.Equals(govar) 167 | } 168 | 169 | func (gvr *GoClassAttribute) Expr() ast.Expr { 170 | return &ast.SelectorExpr{X: gvr.govar.Expr(), 171 | Sel: ast.NewIdent(gvr.suffix)} 172 | } 173 | 174 | func (gvr *GoClassAttribute) hasVariable(govar GoVar) bool { 175 | return gvr.Equals(govar) 176 | } 177 | 178 | func (gvr *GoClassAttribute) GoName() string { 179 | return gvr.govar.GoName() + "." + gvr.suffix 180 | } 181 | 182 | func (gvr *GoClassAttribute) Ident() *ast.Ident { 183 | return gvr.govar.Ident() 184 | } 185 | 186 | func (gvr *GoClassAttribute) Init() ast.Stmt { 187 | return nil 188 | } 189 | 190 | func (gvr *GoClassAttribute) IsClassField() bool { 191 | return gvr.govar.IsClassField() 192 | } 193 | 194 | func (gvr *GoClassAttribute) IsFinal() bool { 195 | return gvr.govar.IsFinal() 196 | } 197 | 198 | func (gvr *GoClassAttribute) IsStatic() bool { 199 | return gvr.govar.IsStatic() 200 | } 201 | 202 | func (gvr *GoClassAttribute) Name() string { 203 | return gvr.govar.Name() + "." + gvr.suffix 204 | } 205 | 206 | func (gvr *GoClassAttribute) Receiver() string { 207 | return gvr.govar.Receiver() 208 | } 209 | 210 | func (gvr *GoClassAttribute) RunTransform(xform TransformFunc, prog *GoProgram, cls GoClass, parent GoObject) (GoObject, bool) { 211 | return xform(parent, prog, cls, gvr) 212 | } 213 | 214 | func (gvr *GoClassAttribute) SetGoName(newname string) { 215 | gvr.govar.SetGoName(newname) 216 | } 217 | 218 | func (gvr *GoClassAttribute) String() string { 219 | return fmt.Sprintf("GoClassAttribute[%s|%s]", gvr.govar.String(), gvr.suffix) 220 | } 221 | 222 | func (gvr *GoClassAttribute) Suffix() string { 223 | return gvr.suffix 224 | } 225 | 226 | func (gvr *GoClassAttribute) Type() ast.Expr { 227 | return gvr.govar.Type() 228 | } 229 | 230 | func (gvr *GoClassAttribute) VarType() *TypeData { 231 | return gvr.govar.VarType() 232 | } 233 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "go/format" 7 | goparser "go/parser" 8 | "go/token" 9 | "io/ioutil" 10 | "log" 11 | "os" 12 | "path" 13 | "runtime/debug" 14 | "strings" 15 | 16 | "java2go/dumper" 17 | "java2go/grammar" 18 | "java2go/parser" 19 | ) 20 | 21 | const sep = "------------" 22 | 23 | func analyze(jp *grammar.JProgramFile, path string, config *parser.Config, 24 | rules []parser.TransformFunc, print_report, verbose bool) *parser.GoProgram { 25 | if print_report { 26 | fmt.Println(sep + " CONVERT " + sep) 27 | log.Printf("/** Convert %s **/\n", path) 28 | } 29 | 30 | gp := parser.NewGoProgram(convertPathToGo(path), config, verbose) 31 | gp.Analyze(jp) 32 | 33 | for _, rule := range rules { 34 | gp.RunTransform(rule, gp, nil, nil) 35 | } 36 | 37 | return gp 38 | } 39 | 40 | func convertPathToGo(path string) string { 41 | i := strings.LastIndex(path, "/") 42 | 43 | var name string 44 | if i < 0 { 45 | name = path 46 | } else { 47 | name = path[i+1:] 48 | } 49 | 50 | if strings.HasSuffix(strings.ToLower(name), ".java") { 51 | name = name[:len(name)-5] 52 | } 53 | 54 | return name + ".go" 55 | } 56 | 57 | func dump(gp *parser.GoProgram) { 58 | } 59 | 60 | func parseDirectory(dir string, cfg *parser.Config, outPath string, 61 | debugLex bool, printReport bool, verbose bool) { 62 | if flist, err := ioutil.ReadDir(dir); err != nil { 63 | log.Printf("Cannot read \"%v\": %v\n", dir, err) 64 | } else { 65 | for _, finfo := range flist { 66 | fullpath := path.Join(dir, finfo.Name()) 67 | if finfo.IsDir() { 68 | parseDirectory(fullpath, cfg, outPath, debugLex, printReport, 69 | verbose) 70 | } else { 71 | parseFile(fullpath, finfo, cfg, outPath, debugLex, printReport, 72 | verbose, false) 73 | } 74 | } 75 | } 76 | } 77 | 78 | func parseFile(path string, finfo os.FileInfo, cfg *parser.Config, 79 | outPath string, debugLex bool, printReport bool, verbose bool, 80 | logUnknownFile bool) { 81 | if strings.HasSuffix(path, ".java") { 82 | parseJava(path, cfg, outPath, debugLex, printReport, verbose) 83 | } else if strings.HasSuffix(path, ".go") { 84 | parseGo(path) 85 | } else if logUnknownFile { 86 | log.Printf("Ignoring unknown file \"%v\"", path) 87 | } 88 | } 89 | 90 | func parseGo(path string) { 91 | fset := token.NewFileSet() // positions are relative to fset 92 | 93 | fmt.Printf("Parsing %s\n", path) 94 | 95 | // Parse the file 96 | f, err := goparser.ParseFile(fset, path, nil, 0) 97 | if err != nil { 98 | fmt.Println(err) 99 | return 100 | } 101 | 102 | dumper.Dump("Parser", f) 103 | 104 | format.Node(os.Stdout, fset, f) 105 | } 106 | 107 | func parseJava(path string, cfg *parser.Config, dirPath string, 108 | debugLex, print_report, verbose bool) { 109 | if verbose { 110 | fmt.Printf("// %s\n", path) 111 | } 112 | l := grammar.NewFileLexer(path, debugLex) 113 | if l != nil { 114 | defer func() { 115 | if r := recover(); r != nil { 116 | err, ok := r.(error) 117 | if !ok { 118 | fmt.Fprintf(os.Stderr, "panic in %v: ??%v??<%T>\n", 119 | path, r, r) 120 | } else { 121 | fmt.Fprintf(os.Stderr, "panic in %v: %v\n", path, err) 122 | } 123 | debug.PrintStack() 124 | } 125 | }() 126 | 127 | prtn := grammar.JulyParse(l) 128 | if prtn != 0 { 129 | fmt.Fprintf(os.Stderr, "parser returned %d\n", prtn) 130 | } 131 | 132 | if l.JavaProgram() == nil { 133 | fmt.Println("No code found") 134 | } else { 135 | rules := parser.StandardRules 136 | 137 | gp := analyze(l.JavaProgram(), path, cfg, rules, print_report, 138 | verbose) 139 | if print_report { 140 | fmt.Println(sep + " GODUMP " + sep) 141 | gp.WriteString(os.Stdout) 142 | fmt.Println() 143 | fmt.Println(sep + " PARSE TREE " + sep) 144 | gp.DumpTree() 145 | fmt.Println(sep + " GO " + sep) 146 | gp.Dump(os.Stdout) 147 | } 148 | if dirPath != "" { 149 | if err := gp.Write(dirPath); err != nil { 150 | fmt.Fprintf(os.Stderr, "Cannot write %v: %v\n", gp.Name(), 151 | err) 152 | } 153 | } else if !print_report { 154 | gp.Dump(os.Stdout) 155 | } 156 | } 157 | 158 | l.Close() 159 | } 160 | } 161 | 162 | func main() { 163 | var configPath string 164 | flag.StringVar(&configPath, "config", "", "Config file") 165 | 166 | var debugFlag bool 167 | flag.BoolVar(&debugFlag, "debug", false, "Enable parser debugging") 168 | 169 | var debugLexFlag bool 170 | flag.BoolVar(&debugLexFlag, "debugLex", false, "Enable lexer debugging") 171 | 172 | var dirPath string 173 | flag.StringVar(&dirPath, "dir", "", "Directory where Go code is written") 174 | 175 | var reportFlag bool 176 | flag.BoolVar(&reportFlag, "report", false, 177 | "Do not print dumps/translations to stdout") 178 | 179 | var verboseFlag bool 180 | flag.BoolVar(&verboseFlag, "verbose", false, "Print more stuff") 181 | 182 | flag.Parse() 183 | 184 | if debugFlag { 185 | grammar.JulyDebug = 9 186 | } 187 | 188 | log.SetFlags(0) 189 | 190 | var cfg *parser.Config 191 | for _, f := range flag.Args() { 192 | finfo, err := os.Stat(f) 193 | if err != nil { 194 | log.Printf("Bad file %v: %v\n", f, err) 195 | continue 196 | } 197 | 198 | if cfg == nil { 199 | if configPath != "" { 200 | cfg = parser.ReadConfig(configPath) 201 | } 202 | if cfg == nil { 203 | cfg = &parser.Config{} 204 | } 205 | } 206 | 207 | if finfo.IsDir() { 208 | parseDirectory(f, cfg, dirPath, debugLexFlag, reportFlag, 209 | verboseFlag) 210 | } else { 211 | parseFile(f, finfo, cfg, dirPath, debugLexFlag, reportFlag, 212 | verboseFlag, true) 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /parser/config.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "log" 8 | "os" 9 | "sort" 10 | "strings" 11 | ) 12 | 13 | // configuration file 14 | type Config struct { 15 | interfaceMap map[string]string 16 | interfaceList []string 17 | packageMap map[string]string 18 | packageList []string 19 | receiverMap map[string]string 20 | receiverList []string 21 | } 22 | 23 | // keyword for defining Java interfaces 24 | const typeInterface = "INTERFACE" 25 | // keyword for mapping Java package names to Go names 26 | const typePackage = "PACKAGE" 27 | // keyword for declaring receiver names for a class 28 | const typeReceiver = "RECEIVER" 29 | 30 | func addEntry(entryMap map[string]string, typeName string, key string, 31 | val string) map[string]string { 32 | if entryMap == nil { 33 | entryMap = make(map[string]string) 34 | } 35 | 36 | if _, ok := entryMap[key]; ok { 37 | log.Printf("Overwriting %s entry %s value %s with %s\n", typeName, 38 | key, entryMap[key], val) 39 | } 40 | 41 | entryMap[key] = val 42 | 43 | return entryMap 44 | } 45 | 46 | func (cfg *Config) addInterface(name string) { 47 | cfg.interfaceMap = addEntry(cfg.interfaceMap, typeInterface, name, name) 48 | cfg.interfaceList = nil 49 | } 50 | 51 | func (cfg *Config) addPackage(name string, value string) { 52 | cfg.packageMap = addEntry(cfg.packageMap, typePackage, name, value) 53 | cfg.packageList = nil 54 | } 55 | 56 | func (cfg *Config) addReceiver(name string, value string) { 57 | cfg.receiverMap = addEntry(cfg.receiverMap, typeReceiver, name, value) 58 | cfg.receiverList = nil 59 | } 60 | 61 | func getValue(entryMap map[string]string, key string) string { 62 | if entryMap != nil { 63 | if val, ok := entryMap[key]; ok { 64 | return val 65 | } 66 | } 67 | 68 | return "" 69 | } 70 | 71 | // read the configuration file 72 | func ReadConfig(name string) *Config { 73 | fd, err := os.Open(name) 74 | if err != nil { 75 | fmt.Fprintf(os.Stderr, "Cannot open config file %s\n", name) 76 | return nil 77 | } 78 | 79 | cfg := &Config{} 80 | 81 | scan := bufio.NewScanner(bufio.NewReader(fd)) 82 | for scan.Scan() { 83 | flds := strings.Fields(scan.Text()) 84 | if len(flds) == 0 || strings.Index(flds[0], "#") == 0 { 85 | // ignore empty lines and comments 86 | continue 87 | } 88 | 89 | switch strings.ToUpper(flds[0]) { 90 | case typeInterface: 91 | if len(flds) != 2 { 92 | log.Printf("Bad config line: %s\n", scan.Text()) 93 | } else { 94 | cfg.addInterface(flds[1]) 95 | } 96 | case typePackage: 97 | if len(flds) != 4 { 98 | log.Printf("Bad config line: %s\n", scan.Text()) 99 | } else { 100 | cfg.addPackage(flds[1], flds[3]) 101 | } 102 | case typeReceiver: 103 | if len(flds) != 4 { 104 | log.Printf("Bad config line: %s\n", scan.Text()) 105 | } else { 106 | cfg.addReceiver(flds[1], flds[3]) 107 | } 108 | } 109 | } 110 | 111 | return cfg 112 | } 113 | 114 | // print the configuration data to the output 115 | func (cfg *Config) Dump(out io.Writer) { 116 | need_nl := false 117 | 118 | if len(cfg.packageMap) > 0 { 119 | if need_nl { fmt.Fprintln(out) } 120 | fmt.Fprintln(out, "# map Java packages to Go packages") 121 | for _, k := range cfg.packageKeys() { 122 | fmt.Fprintf(out, "%v %v -> %v\n", typePackage, k, 123 | cfg.packageName(k)) 124 | } 125 | need_nl = true 126 | } 127 | 128 | if len(cfg.interfaceMap) > 0 { 129 | if need_nl { fmt.Fprintln(out) } 130 | fmt.Fprintln(out, "# names which should be treated as interfaces" + 131 | " rather than structs") 132 | for _, k := range cfg.interfaces() { 133 | fmt.Fprintf(out, "%v %v\n", typeInterface, k) 134 | } 135 | need_nl = true 136 | } 137 | 138 | if len(cfg.receiverMap) > 0 { 139 | if need_nl { fmt.Fprintln(out) } 140 | fmt.Fprintln(out, "# receiver name to use (other than 'rcvr')") 141 | for _, k := range cfg.receiverKeys() { 142 | fmt.Fprintf(out, "%v %v -> %v\n", typeReceiver, k, cfg.receiver(k)) 143 | } 144 | need_nl = true 145 | } 146 | } 147 | 148 | func (cfg *Config) findPackage(str string) string { 149 | var pstr string 150 | var pval string 151 | var pextra string 152 | for k, v := range cfg.packageMap { 153 | idx := strings.Index(str, k) 154 | if idx == 0 { 155 | if len(k) > len(pstr) { 156 | pstr = k 157 | pval = v 158 | if len(str) == len(pstr) { 159 | pextra = "" 160 | break 161 | } 162 | pextra = str[len(pstr):] 163 | } 164 | } 165 | } 166 | 167 | return pval + pextra 168 | } 169 | 170 | func (cfg *Config) interfaces() []string { 171 | if cfg.interfaceList == nil { 172 | cfg.interfaceList = make([]string, len(cfg.interfaceMap)) 173 | var i int 174 | for k := range cfg.interfaceMap { 175 | cfg.interfaceList[i] = k 176 | i += 1 177 | } 178 | 179 | sort.Sort(sort.StringSlice(cfg.interfaceList)) 180 | } 181 | 182 | return cfg.interfaceList 183 | } 184 | 185 | func (cfg *Config) isInterface(name string) bool { 186 | _, ok := cfg.interfaceMap[name] 187 | return ok 188 | } 189 | 190 | func (cfg *Config) packageName(key string) string { 191 | return getValue(cfg.packageMap, key) 192 | } 193 | 194 | func (cfg *Config) packageKeys() []string { 195 | if cfg.packageList == nil { 196 | cfg.packageList = make([]string, len(cfg.packageMap)) 197 | var i int 198 | for k := range cfg.packageMap { 199 | cfg.packageList[i] = k 200 | i += 1 201 | } 202 | 203 | sort.Sort(sort.StringSlice(cfg.packageList)) 204 | } 205 | 206 | return cfg.packageList 207 | } 208 | 209 | func (cfg *Config) receiver(key string) string { 210 | return getValue(cfg.receiverMap, key) 211 | } 212 | 213 | func (cfg *Config) receiverKeys() []string { 214 | if cfg.receiverList == nil { 215 | cfg.receiverList = make([]string, len(cfg.receiverMap)) 216 | 217 | var i int 218 | for k := range cfg.receiverMap { 219 | cfg.receiverList[i] = k 220 | i += 1 221 | } 222 | 223 | sort.Sort(sort.StringSlice(cfg.receiverList)) 224 | } 225 | 226 | return cfg.receiverList 227 | } 228 | 229 | // print a minimal description of the configuration rules 230 | func (cfg *Config) String() string { 231 | return fmt.Sprintf("Config[%d ifaces, %d pkgs, %d rcvrs]", 232 | len(cfg.interfaceMap), len(cfg.packageMap), len(cfg.receiverMap)) 233 | } 234 | -------------------------------------------------------------------------------- /parser/typedata.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "go/ast" 6 | "strings" 7 | ) 8 | 9 | type VarType int 10 | 11 | // bool 12 | // byte rune char 13 | // uint8 uint16 uint32 uint64 14 | // int8 int16 int32 int64 15 | // uintptr 16 | // float32 float64 17 | // complex64 complex128 18 | // string 19 | const ( 20 | VT_ILLEGAL VarType = iota 21 | VT_VOID 22 | VT_BOOL 23 | VT_BYTE 24 | VT_CHAR 25 | VT_INT16 26 | VT_INT 27 | VT_INT64 28 | VT_FLOAT32 29 | VT_FLOAT64 30 | VT_STRING 31 | VT_GENERIC_OBJECT 32 | VT_ARRAY 33 | VT_MAP 34 | VT_INTERFACE 35 | VT_CLASS 36 | ) 37 | 38 | func (vt VarType) String() string { 39 | switch vt { 40 | case VT_VOID: return "void" 41 | case VT_BOOL: return "bool" 42 | case VT_BYTE: return "byte" 43 | case VT_CHAR: return "char" 44 | case VT_INT16: return "int16" 45 | case VT_INT: return "int" 46 | case VT_INT64: return "int64" 47 | case VT_FLOAT32: return "float32" 48 | case VT_FLOAT64: return "float64" 49 | case VT_STRING: return "string" 50 | case VT_GENERIC_OBJECT: return "{}interface" 51 | case VT_ARRAY: return "??array??" 52 | case VT_MAP: return "??map??" 53 | case VT_INTERFACE: return "??interface??" 54 | case VT_CLASS: return "??class??" 55 | } 56 | 57 | return fmt.Sprintf("??VarType#%d??", vt) 58 | } 59 | 60 | type TypeDictionary interface { 61 | ImportedType(string) string 62 | IsInterface(string) bool 63 | } 64 | 65 | type TypeData struct { 66 | vtype VarType 67 | vclass string 68 | array_dims int 69 | type1 *TypeData 70 | type2 *TypeData 71 | } 72 | 73 | var genericObject = &TypeData{vtype: VT_GENERIC_OBJECT} 74 | var voidType = &TypeData{vtype: VT_VOID} 75 | var boolType = &TypeData{vtype: VT_BOOL} 76 | var byteType = &TypeData{vtype: VT_BYTE} 77 | var charType = &TypeData{vtype: VT_CHAR} 78 | var shortType = &TypeData{vtype: VT_INT16} 79 | var intType = &TypeData{vtype: VT_INT} 80 | var longType = &TypeData{vtype: VT_INT64} 81 | var floatType = &TypeData{vtype: VT_FLOAT32} 82 | var doubleType = &TypeData{vtype: VT_FLOAT64} 83 | var stringType = &TypeData{vtype: VT_STRING} 84 | 85 | func NewTypeDataPrimitive(typename string, dims int) *TypeData { 86 | var noDimType *TypeData 87 | switch strings.ToLower(typename) { 88 | case "void": 89 | noDimType = voidType 90 | case "boolean": 91 | noDimType = boolType 92 | case "byte": 93 | noDimType = byteType 94 | case "char": 95 | noDimType = charType 96 | case "short": 97 | noDimType = shortType 98 | case "int": 99 | noDimType = intType 100 | case "long": 101 | noDimType = longType 102 | case "float": 103 | noDimType = floatType 104 | case "double": 105 | noDimType = doubleType 106 | case "string": 107 | noDimType = stringType 108 | default: 109 | panic(fmt.Sprintf("Unrecognized primitive type %v", typename)) 110 | } 111 | 112 | if dims == 0 { 113 | return noDimType 114 | } 115 | 116 | return &TypeData{vtype: VT_ARRAY, type1: noDimType, array_dims: dims} 117 | } 118 | 119 | func NewTypeDataObject(tdict TypeDictionary, typename string, dims int) *TypeData { 120 | var vtype VarType 121 | 122 | imptype := tdict.ImportedType(typename) 123 | if imptype == "" { 124 | imptype = typename 125 | vtype = VT_CLASS 126 | } else if tdict.IsInterface(imptype) { 127 | vtype = VT_INTERFACE 128 | } else { 129 | vtype = VT_CLASS 130 | } 131 | 132 | td := &TypeData{vtype: vtype, vclass: imptype} 133 | if dims > 0 { 134 | return &TypeData{vtype: VT_ARRAY, array_dims: dims, type1: td} 135 | } 136 | 137 | return td 138 | } 139 | 140 | var identBool = ast.NewIdent("bool") 141 | var identByte = ast.NewIdent("byte") 142 | var identChar = ast.NewIdent("char") 143 | var identInt16 = ast.NewIdent("int16") 144 | var identInt = ast.NewIdent("int") 145 | var identInt64 = ast.NewIdent("int64") 146 | var identFloat32 = ast.NewIdent("float32") 147 | var identFloat64 = ast.NewIdent("float64") 148 | var identString = ast.NewIdent("string") 149 | 150 | func (vdata *TypeData) Decl() ast.Expr { 151 | return vdata.Expr() 152 | } 153 | 154 | func (vdata *TypeData) Equals(odata *TypeData) bool { 155 | if vdata == nil || odata == nil { 156 | return false 157 | } 158 | 159 | if vdata.vtype != odata.vtype || vdata.array_dims != odata.array_dims { 160 | return false 161 | } 162 | 163 | if vdata.type1 != nil || odata.type1 != nil { 164 | if (vdata.type1 == nil && odata.type1 != nil) || 165 | (vdata.type1 != nil && odata.type1 == nil) { 166 | return false 167 | } 168 | 169 | if !vdata.type1.Equals(odata.type1) { 170 | return false 171 | } 172 | } 173 | 174 | if vdata.type2 != nil || odata.type2 != nil { 175 | if (vdata.type2 == nil && odata.type2 != nil) || 176 | (vdata.type2 != nil && odata.type2 == nil) { 177 | return false 178 | } 179 | 180 | if !vdata.type2.Equals(odata.type2) { 181 | return false 182 | } 183 | } 184 | 185 | return true 186 | } 187 | 188 | func (vdata *TypeData) Expr() ast.Expr { 189 | if vdata.vtype != VT_ARRAY { 190 | typename, is_nil := vdata.TypeName() 191 | if is_nil { 192 | return nil 193 | } 194 | 195 | expr := typename 196 | for i := 0; i < vdata.array_dims; i++ { 197 | expr = &ast.ArrayType{Elt: typename} 198 | } 199 | 200 | return expr 201 | } 202 | 203 | if vdata.type1 != nil { 204 | return &ast.ArrayType{Elt: vdata.type1.Expr()} 205 | } 206 | 207 | return &ast.ArrayType{Elt: genericObject.Expr()} 208 | } 209 | 210 | func (vdata *TypeData) IsClass(name string) bool { 211 | return vdata.vtype == VT_CLASS && vdata.vclass == name 212 | } 213 | 214 | func (vdata *TypeData) isObject() bool { 215 | return vdata.vtype == VT_INTERFACE || vdata.vtype == VT_CLASS 216 | } 217 | 218 | func (vdata *TypeData) Name() string { 219 | switch vdata.vtype { 220 | case VT_ARRAY: 221 | tstr := "array" 222 | if vdata.type1 == nil { 223 | tstr += "_Object" 224 | } else { 225 | tstr += "_" 226 | tstr += vdata.type1.String() 227 | } 228 | 229 | if vdata.array_dims > 0 { 230 | tstr += fmt.Sprintf("_dim%d", vdata.array_dims) 231 | } 232 | 233 | return tstr 234 | case VT_MAP: 235 | kstr := "map" 236 | if vdata.type1 == nil { 237 | kstr += "_Object" 238 | } else { 239 | kstr += "_" 240 | kstr += vdata.type1.String() 241 | } 242 | 243 | if vdata.type2 == nil { 244 | kstr += "_Object" 245 | } else { 246 | kstr += "_" 247 | kstr += vdata.type2.String() 248 | } 249 | 250 | return kstr 251 | case VT_INTERFACE: 252 | return vdata.vclass 253 | case VT_CLASS: 254 | return vdata.vclass 255 | default: 256 | break 257 | } 258 | 259 | return vdata.vtype.String() 260 | } 261 | 262 | func (vdata *TypeData) String() string { 263 | switch vdata.vtype { 264 | case VT_ARRAY: 265 | var tstr string 266 | if vdata.type1 == nil { 267 | tstr = genericObject.String() 268 | } else { 269 | tstr = vdata.type1.String() 270 | } 271 | 272 | for i := 0; i < vdata.array_dims; i++ { 273 | tstr = "[]" + tstr 274 | } 275 | 276 | return tstr 277 | case VT_MAP: 278 | var kstr string 279 | if vdata.type1 == nil { 280 | kstr = genericObject.String() 281 | } else { 282 | kstr = vdata.type1.String() 283 | } 284 | 285 | var vstr string 286 | if vdata.type2 == nil { 287 | vstr = genericObject.String() 288 | } else { 289 | vstr = vdata.type2.String() 290 | } 291 | 292 | return "map[" + kstr + "]" + vstr 293 | case VT_INTERFACE: 294 | return vdata.vclass 295 | case VT_CLASS: 296 | return "*" + vdata.vclass 297 | default: 298 | break 299 | } 300 | 301 | return vdata.vtype.String() 302 | } 303 | 304 | func (vdata *TypeData) TypeName() (ast.Expr, bool) { 305 | switch vdata.vtype { 306 | case VT_VOID: 307 | return nil, true 308 | case VT_BOOL: 309 | return identBool, false 310 | case VT_BYTE: 311 | return identByte, false 312 | case VT_CHAR: 313 | return identChar, false 314 | case VT_INT16: 315 | return identInt16, false 316 | case VT_INT: 317 | return identInt, false 318 | case VT_INT64: 319 | return identInt64, false 320 | case VT_FLOAT32: 321 | return identFloat32, false 322 | case VT_FLOAT64: 323 | return identFloat64, false 324 | case VT_STRING: 325 | return identString, false 326 | case VT_GENERIC_OBJECT: 327 | return &ast.InterfaceType{Methods: &ast.FieldList{}}, false 328 | case VT_ARRAY: 329 | return ast.NewIdent("<>"), false 330 | case VT_MAP: 331 | return ast.NewIdent("<>"), false 332 | case VT_INTERFACE: 333 | return ast.NewIdent(vdata.vclass), false 334 | case VT_CLASS: 335 | return &ast.StarExpr{X: ast.NewIdent(vdata.vclass)}, false 336 | default: 337 | break 338 | } 339 | 340 | panic(fmt.Sprintf("Unknown VarType %v", vdata.vtype)) 341 | } 342 | -------------------------------------------------------------------------------- /parser/transform.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "go/ast" 6 | "go/token" 7 | "log" 8 | "strings" 9 | 10 | "java2go/grammar" 11 | ) 12 | 13 | // list of Java classes which inherit from AbstractList 14 | var javaListType = []string{"List", "ArrayList", "LinkedList", "Stack", 15 | "Vector"} 16 | 17 | type TransformFunc func(parent GoObject, prog *GoProgram, cls GoClass, 18 | object GoObject) (GoObject, bool) 19 | 20 | type GoObject interface { 21 | RunTransform(xform TransformFunc, gp *GoProgram, cls GoClass, 22 | parent GoObject) (GoObject, bool) 23 | } 24 | 25 | type GoTypedObject interface { 26 | GoObject 27 | VarType() *TypeData 28 | } 29 | 30 | func convertToBlock(obj GoObject) (*GoBlock, error) { 31 | if blk, ok := obj.(*GoBlock); ok { 32 | return blk, nil 33 | } 34 | 35 | return nil, fmt.Errorf("%v<%T> is not a *GoBlock", obj, obj) 36 | } 37 | 38 | func convertToExpr(obj GoObject) (GoExpr, error) { 39 | if expr, ok := obj.(GoExpr); ok { 40 | return expr, nil 41 | } 42 | 43 | return nil, fmt.Errorf("%v<%T> is not a GoExpr", obj, obj) 44 | } 45 | 46 | func convertToMethod(obj GoObject) (GoMethod, error) { 47 | if mthd, ok := obj.(GoMethod); ok { 48 | return mthd, nil 49 | } 50 | 51 | return nil, fmt.Errorf("%v<%T> is not a GoMethod", obj, obj) 52 | } 53 | 54 | func convertToMethodArgs(obj GoObject) (*GoMethodArguments, error) { 55 | if mthd, ok := obj.(*GoMethodArguments); ok { 56 | return mthd, nil 57 | } 58 | 59 | return nil, fmt.Errorf("%v<%T> is not a *GoMethodArguments", obj, obj) 60 | } 61 | 62 | func convertToStmt(obj GoObject) (GoStatement, error) { 63 | if stmt, ok := obj.(GoStatement); ok { 64 | return stmt, nil 65 | } 66 | 67 | return nil, fmt.Errorf("%v<%T> is not a GoStatement", obj, obj) 68 | } 69 | 70 | func convertToVar(obj GoObject) (GoVar, error) { 71 | if govar, ok := obj.(GoVar); ok { 72 | return govar, nil 73 | } 74 | 75 | return nil, fmt.Errorf("%v<%T> is not a GoVar", obj, obj) 76 | } 77 | 78 | func convertToVarInit(obj GoObject) (*GoVarInit, error) { 79 | if vi, ok := obj.(*GoVarInit); ok { 80 | return vi, nil 81 | } 82 | 83 | return nil, fmt.Errorf("%v<%T> is not a *GoVarInit", obj, obj) 84 | } 85 | 86 | func getFmtClass(prog *GoProgram) GoClass { 87 | fmtcls := prog.findClass("fmt") 88 | if fmtcls == nil { 89 | fmtcls = NewGoFakeClass("fmt") 90 | prog.addClass(fmtcls) 91 | 92 | // make sure "fmt" is imported 93 | prog.addImport("fmt", "") 94 | } 95 | 96 | return fmtcls 97 | } 98 | 99 | type GoPkgName struct { 100 | pkg string 101 | name string 102 | } 103 | 104 | func (gpn *GoPkgName) Expr() ast.Expr { 105 | return &ast.SelectorExpr{X: ast.NewIdent(gpn.pkg), 106 | Sel: ast.NewIdent(gpn.name)} 107 | } 108 | 109 | func (gpn *GoPkgName) hasVariable(govar GoVar) bool { 110 | return false 111 | } 112 | 113 | func (gpn *GoPkgName) Init() ast.Stmt { 114 | return nil 115 | } 116 | 117 | func (gpn *GoPkgName) RunTransform(xform TransformFunc, prog *GoProgram, 118 | cls GoClass, parent GoObject) (GoObject, bool) { 119 | return xform(parent, prog, cls, gpn) 120 | } 121 | 122 | func (gpn *GoPkgName) String() string { 123 | return fmt.Sprintf("GoPkgName[%s|%s]", gpn.pkg, gpn.name) 124 | } 125 | 126 | func (gpn *GoPkgName) VarType() *TypeData { 127 | panic("GoPkgName.VarType() unimplemented") 128 | } 129 | 130 | // transform "array.length" to "len(array)" 131 | func TransformArrayLen(parent GoObject, prog *GoProgram, cls GoClass, 132 | object GoObject) (GoObject, bool) { 133 | var ref *GoClassAttribute 134 | var ok bool 135 | if ref, ok = object.(*GoClassAttribute); !ok { 136 | return nil, true 137 | } 138 | 139 | if ref.Suffix() != "length" || ref.VarType().vtype != VT_ARRAY { 140 | return nil, true 141 | } 142 | 143 | fm := NewGoFakeMethod(nil, "len", intType) 144 | args := &GoMethodArguments{args: []GoExpr{ref.govar}} 145 | 146 | return &GoMethodAccess{method: fm, args: args}, false 147 | } 148 | 149 | // transform "System.out.print*(...)" to "fmt.Print*(...)" and 150 | // "System.err.print*(...)" to "fmt.Fprintf(os.Stderr, ...)" 151 | func TransformSysfile(parent GoObject, prog *GoProgram, cls GoClass, 152 | object GoObject) (GoObject, bool) { 153 | var ma *GoMethodAccess 154 | var ok bool 155 | if ma, ok = object.(*GoMethodAccess); !ok { 156 | return nil, true 157 | } 158 | 159 | if ma.method == nil { 160 | return nil, true 161 | } 162 | 163 | mcls := ma.method.Class() 164 | if mcls == nil || mcls.IsNil() { 165 | return nil, true 166 | } 167 | 168 | clsname := mcls.Name() 169 | name := ma.method.Name() 170 | 171 | if !strings.HasPrefix(clsname, "System.") || 172 | !strings.HasPrefix(name, "print") { 173 | return nil, true 174 | } 175 | 176 | fmtcls := getFmtClass(prog) 177 | 178 | var fixed string 179 | var args *GoMethodArguments 180 | if strings.HasSuffix(clsname, ".out") { 181 | fixed = strings.ToUpper(name[:1]) + name[1:] 182 | args = ma.args 183 | } else { 184 | fixed = "F" + name 185 | arglist := make([]GoExpr, 1) 186 | arglist[0] = &GoPkgName{pkg: "os", name: "Stderr"} 187 | arglist = append(arglist, ma.args.args...) 188 | args = &GoMethodArguments{args: arglist} 189 | 190 | // make sure "os" is imported 191 | prog.addImport("os", "") 192 | } 193 | 194 | fm := NewGoFakeMethod(fmtcls, fixed, nil) 195 | 196 | return &GoMethodAccess{method: fm, args: args}, false 197 | } 198 | 199 | // transform "func main(String[] xxx)" to "func main()" and all "xxx" references 200 | // to "os.Args" 201 | func TransformMainArgs(parent GoObject, prog *GoProgram, cls GoClass, 202 | object GoObject) (GoObject, bool) { 203 | var cm *GoClassMethod 204 | var ok bool 205 | if cm, ok = object.(*GoClassMethod); !ok { 206 | return nil, true 207 | } 208 | 209 | if cm.method_type != mt_main { 210 | return nil, true 211 | } 212 | 213 | if cm.params == nil || len(cm.params) != 1 { 214 | return nil, true 215 | } 216 | 217 | arg := cm.params[0] 218 | 219 | if cm.body.hasVariable(arg) { 220 | arg.SetGoName("os.Args") 221 | 222 | // make sure "os" is imported 223 | prog.addImport("os", "") 224 | } 225 | 226 | cm.params = nil 227 | 228 | return nil, true 229 | } 230 | 231 | // transform "foo(this)" to "foo(rcvr)" 232 | func TransformThisArg(parent GoObject, prog *GoProgram, cls GoClass, 233 | object GoObject) (GoObject, bool) { 234 | var mref *GoMethodReference 235 | var ok bool 236 | if mref, ok = object.(*GoMethodReference); !ok { 237 | return nil, true 238 | } 239 | 240 | if mref.args == nil { 241 | return nil, true 242 | } 243 | 244 | for i, arg := range mref.args.args { 245 | var kwd *GoKeyword 246 | if kwd, ok = arg.(*GoKeyword); ok { 247 | if kwd.token == grammar.THIS { 248 | mref.args.args[i] = 249 | NewFakeVar(prog.Receiver(cls.Name()), nil, 0) 250 | } 251 | } 252 | } 253 | 254 | return nil, true 255 | } 256 | 257 | // transform method calls for List variants to appropriate array operations 258 | func TransformListMethods(parent GoObject, prog *GoProgram, cls GoClass, 259 | object GoObject) (GoObject, bool) { 260 | var mref *GoMethodAccessVar 261 | var ok bool 262 | if mref, ok = object.(*GoMethodAccessVar); !ok { 263 | return nil, true 264 | } 265 | 266 | var is_list bool 267 | for _, n := range javaListType { 268 | if mref.govar.VarType().IsClass(n) { 269 | is_list = true 270 | break 271 | } 272 | } 273 | if !is_list { 274 | return nil, true 275 | } 276 | 277 | switch mref.method.Name() { 278 | case "add": 279 | if len(mref.args.args) != 1 { 280 | log.Printf("//ERR// Cannot convert %v add() with %d args\n", 281 | mref.govar.VarType(), len(mref.args.args)) 282 | return nil, true 283 | } 284 | 285 | apnd := NewGoFakeMethod(nil, "append", mref.govar.VarType()) 286 | args := &GoMethodArguments{args: []GoExpr{mref.govar, 287 | mref.args.args[0]}} 288 | 289 | rhs := []GoExpr{&GoMethodAccess{method: apnd, args: args}} 290 | 291 | return &GoAssign{govar: mref.govar, tok: token.ASSIGN, rhs: rhs}, false 292 | case "isEmpty": 293 | if len(mref.args.args) != 0 { 294 | log.Printf("//ERR// Cannot convert %v isEmpty() with %d args\n", 295 | mref.govar.VarType(), len(mref.args.args)) 296 | return nil, true 297 | } 298 | 299 | args := &GoMethodArguments{args: []GoExpr{mref.govar}} 300 | x := &GoMethodAccess{method: NewGoFakeMethod(nil, "len", intType), 301 | args: args} 302 | return &GoBinaryExpr{x: x, op: token.EQL, y: &GoLiteral{text: "0"}}, 303 | false 304 | case "get": 305 | if len(mref.args.args) != 1 { 306 | log.Printf("//ERR// Cannot convert %v get() with %d args\n", 307 | mref.govar.VarType(), len(mref.args.args)) 308 | return nil, true 309 | } 310 | 311 | return &GoArrayReference{govar: mref.govar, index: mref.args.args[0]}, 312 | false 313 | case "size": 314 | fm := NewGoFakeMethod(nil, "len", intType) 315 | args := &GoMethodArguments{args: []GoExpr{mref.govar}} 316 | 317 | return &GoMethodAccess{method: fm, args: args}, false 318 | default: 319 | log.Printf("//ERR// Not converting %v method %v\n", 320 | mref.govar.VarType(), mref.method.Name()) 321 | break 322 | } 323 | 324 | return nil, true 325 | } 326 | 327 | // transform various toString() calls into fmt.Sprintf 328 | func TransformToString(parent GoObject, prog *GoProgram, cls GoClass, 329 | object GoObject) (GoObject, bool) { 330 | 331 | var macc *GoMethodAccess 332 | var ok bool 333 | if macc, ok = object.(*GoMethodAccess); !ok { 334 | return nil, true 335 | } 336 | 337 | if macc.method.Name() != "toString" { 338 | return nil, true 339 | } 340 | 341 | if len(macc.args.args) == 1 { 342 | alist := make([]GoExpr, 2) 343 | alist[0] = NewGoLiteral("\"%v\"") 344 | alist[1] = macc.args.args[0] 345 | 346 | args := &GoMethodArguments{args: alist} 347 | 348 | fmtcls := getFmtClass(prog) 349 | 350 | mthd := fmtcls.FindMethod("Sprintf", args) 351 | if mthd == nil { 352 | mthd = NewGoFakeMethod(fmtcls, "Sprintf", stringType) 353 | fmtcls.AddMethod(mthd) 354 | } 355 | 356 | return &GoMethodAccess{method: mthd, args: args}, false 357 | } 358 | 359 | log.Printf("//ERR// Cannot convert %v toString() with %d args\n", 360 | macc.method, len(macc.args.args)) 361 | return nil, true 362 | } 363 | 364 | // transform String.format method call into fmt.Sprintf 365 | func TransformStringFormat(parent GoObject, prog *GoProgram, cls GoClass, 366 | object GoObject) (GoObject, bool) { 367 | 368 | var mref *GoMethodReference 369 | var ok bool 370 | if mref, ok = object.(*GoMethodReference); !ok { 371 | return nil, true 372 | } 373 | 374 | if mref.name == "format" && !mref.class.IsNil() && 375 | mref.class.Name() == "String" { 376 | fmtcls := getFmtClass(prog) 377 | 378 | return NewGoMethodReference(fmtcls, "Sprintf", mref.args, false), false 379 | } 380 | 381 | return nil, true 382 | } 383 | 384 | // transform string addition into fmt.Sprintf 385 | func TransformStringAddition(parent GoObject, prog *GoProgram, cls GoClass, 386 | object GoObject) (GoObject, bool) { 387 | 388 | var bex *GoBinaryExpr 389 | var ok bool 390 | if bex, ok = object.(*GoBinaryExpr); !ok { 391 | return nil, true 392 | } 393 | 394 | var x GoTypedObject 395 | if x, ok = bex.x.(GoTypedObject); !ok { 396 | return nil, true 397 | } 398 | 399 | if x.VarType() != stringType { 400 | return nil, true 401 | } 402 | 403 | return transformBinaryStringExpression(prog, bex) 404 | } 405 | 406 | func joinStrings(s1 string, s2 string) string { 407 | if s1[0] != '"' || s1[len(s1)-1] != '"' { 408 | panic(fmt.Sprintf("String %v is not quoted", s1)) 409 | } 410 | if s2[0] != '"' || s2[len(s2)-1] != '"' { 411 | panic(fmt.Sprintf("String %v is not quoted", s2)) 412 | } 413 | s := fmt.Sprintf("\"%s%s\"", s1[1:len(s1)-1], s2[1:len(s2)-1]) 414 | return s 415 | } 416 | 417 | func transformBinaryStringExpression(prog *GoProgram, bex *GoBinaryExpr) (GoObject, bool) { 418 | if bex.op != token.ADD { 419 | return nil, true 420 | } 421 | 422 | switch x := bex.x.(type) { 423 | case *GoLiteral: 424 | if !x.isString() { 425 | // ignore non-string addition 426 | return nil, true 427 | } 428 | 429 | if y, ok := bex.y.(*GoLiteral); ok { 430 | if y.isString() { 431 | return NewGoLiteral(joinStrings(x.text, y.text)), false 432 | } 433 | } 434 | case *GoMethodAccess: 435 | if x.method.VarType() != stringType { 436 | return nil, true 437 | } 438 | 439 | if x.method.Name() == "Sprintf" { 440 | if fmtstr, ok := x.args.args[0].(*GoLiteral); !ok { 441 | log.Printf("//ERR// First Sprintf argument should be "+ 442 | " *GoLiteral not %T\n", x.args.args[0]) 443 | return nil, true 444 | } else { 445 | x.args.args[0] = NewGoLiteral(joinStrings("\"%v\"", 446 | fmtstr.text)) 447 | } 448 | x.args.args = append(x.args.args, bex.y) 449 | return x, false 450 | } 451 | } 452 | 453 | fmtcls := getFmtClass(prog) 454 | 455 | fmtstr := NewGoLiteral("\"%v%v\"") 456 | args := &GoMethodArguments{args: []GoExpr{fmtstr, bex.x, bex.y}} 457 | 458 | mthd := fmtcls.FindMethod("Sprintf", args) 459 | if mthd == nil { 460 | mthd = NewGoFakeMethod(fmtcls, "Sprintf", stringType) 461 | fmtcls.AddMethod(mthd) 462 | } 463 | 464 | return &GoMethodAccess{method: mthd, args: args}, false 465 | } 466 | 467 | // list of standard transformation rules 468 | var StandardRules = []TransformFunc{ 469 | TransformArrayLen, 470 | TransformSysfile, 471 | TransformMainArgs, 472 | TransformThisArg, 473 | TransformListMethods, 474 | TransformToString, 475 | TransformStringAddition, 476 | TransformStringFormat, 477 | } 478 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License, version 2.0 2 | 3 | 1. Definitions 4 | 5 | 1.1. "Contributor" 6 | 7 | means each individual or legal entity that creates, contributes to the 8 | creation of, or owns Covered Software. 9 | 10 | 1.2. "Contributor Version" 11 | 12 | means the combination of the Contributions of others (if any) used by a 13 | Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | 17 | means Covered Software of a particular Contributor. 18 | 19 | 1.4. "Covered Software" 20 | 21 | means Source Code Form to which the initial Contributor has attached the 22 | notice in Exhibit A, the Executable Form of such Source Code Form, and 23 | Modifications of such Source Code Form, in each case including portions 24 | thereof. 25 | 26 | 1.5. "Incompatible With Secondary Licenses" 27 | means 28 | 29 | a. that the initial Contributor has attached the notice described in 30 | Exhibit B to the Covered Software; or 31 | 32 | b. that the Covered Software was made available under the terms of 33 | version 1.1 or earlier of the License, but not also under the terms of 34 | a Secondary License. 35 | 36 | 1.6. "Executable Form" 37 | 38 | means any form of the work other than Source Code Form. 39 | 40 | 1.7. "Larger Work" 41 | 42 | means a work that combines Covered Software with other material, in a 43 | separate file or files, that is not Covered Software. 44 | 45 | 1.8. "License" 46 | 47 | means this document. 48 | 49 | 1.9. "Licensable" 50 | 51 | means having the right to grant, to the maximum extent possible, whether 52 | at the time of the initial grant or subsequently, any and all of the 53 | rights conveyed by this License. 54 | 55 | 1.10. "Modifications" 56 | 57 | means any of the following: 58 | 59 | a. any file in Source Code Form that results from an addition to, 60 | deletion from, or modification of the contents of Covered Software; or 61 | 62 | b. any new file in Source Code Form that contains any Covered Software. 63 | 64 | 1.11. "Patent Claims" of a Contributor 65 | 66 | means any patent claim(s), including without limitation, method, 67 | process, and apparatus claims, in any patent Licensable by such 68 | Contributor that would be infringed, but for the grant of the License, 69 | by the making, using, selling, offering for sale, having made, import, 70 | or transfer of either its Contributions or its Contributor Version. 71 | 72 | 1.12. "Secondary License" 73 | 74 | means either the GNU General Public License, Version 2.0, the GNU Lesser 75 | General Public License, Version 2.1, the GNU Affero General Public 76 | License, Version 3.0, or any later versions of those licenses. 77 | 78 | 1.13. "Source Code Form" 79 | 80 | means the form of the work preferred for making modifications. 81 | 82 | 1.14. "You" (or "Your") 83 | 84 | means an individual or a legal entity exercising rights under this 85 | License. For legal entities, "You" includes any entity that controls, is 86 | controlled by, or is under common control with You. For purposes of this 87 | definition, "control" means (a) the power, direct or indirect, to cause 88 | the direction or management of such entity, whether by contract or 89 | otherwise, or (b) ownership of more than fifty percent (50%) of the 90 | outstanding shares or beneficial ownership of such entity. 91 | 92 | 93 | 2. License Grants and Conditions 94 | 95 | 2.1. Grants 96 | 97 | Each Contributor hereby grants You a world-wide, royalty-free, 98 | non-exclusive license: 99 | 100 | a. under intellectual property rights (other than patent or trademark) 101 | Licensable by such Contributor to use, reproduce, make available, 102 | modify, display, perform, distribute, and otherwise exploit its 103 | Contributions, either on an unmodified basis, with Modifications, or 104 | as part of a Larger Work; and 105 | 106 | b. under Patent Claims of such Contributor to make, use, sell, offer for 107 | sale, have made, import, and otherwise transfer either its 108 | Contributions or its Contributor Version. 109 | 110 | 2.2. Effective Date 111 | 112 | The licenses granted in Section 2.1 with respect to any Contribution 113 | become effective for each Contribution on the date the Contributor first 114 | distributes such Contribution. 115 | 116 | 2.3. Limitations on Grant Scope 117 | 118 | The licenses granted in this Section 2 are the only rights granted under 119 | this License. No additional rights or licenses will be implied from the 120 | distribution or licensing of Covered Software under this License. 121 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 122 | Contributor: 123 | 124 | a. for any code that a Contributor has removed from Covered Software; or 125 | 126 | b. for infringements caused by: (i) Your and any other third party's 127 | modifications of Covered Software, or (ii) the combination of its 128 | Contributions with other software (except as part of its Contributor 129 | Version); or 130 | 131 | c. under Patent Claims infringed by Covered Software in the absence of 132 | its Contributions. 133 | 134 | This License does not grant any rights in the trademarks, service marks, 135 | or logos of any Contributor (except as may be necessary to comply with 136 | the notice requirements in Section 3.4). 137 | 138 | 2.4. Subsequent Licenses 139 | 140 | No Contributor makes additional grants as a result of Your choice to 141 | distribute the Covered Software under a subsequent version of this 142 | License (see Section 10.2) or under the terms of a Secondary License (if 143 | permitted under the terms of Section 3.3). 144 | 145 | 2.5. Representation 146 | 147 | Each Contributor represents that the Contributor believes its 148 | Contributions are its original creation(s) or it has sufficient rights to 149 | grant the rights to its Contributions conveyed by this License. 150 | 151 | 2.6. Fair Use 152 | 153 | This License is not intended to limit any rights You have under 154 | applicable copyright doctrines of fair use, fair dealing, or other 155 | equivalents. 156 | 157 | 2.7. Conditions 158 | 159 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 160 | Section 2.1. 161 | 162 | 163 | 3. Responsibilities 164 | 165 | 3.1. Distribution of Source Form 166 | 167 | All distribution of Covered Software in Source Code Form, including any 168 | Modifications that You create or to which You contribute, must be under 169 | the terms of this License. You must inform recipients that the Source 170 | Code Form of the Covered Software is governed by the terms of this 171 | License, and how they can obtain a copy of this License. You may not 172 | attempt to alter or restrict the recipients' rights in the Source Code 173 | Form. 174 | 175 | 3.2. Distribution of Executable Form 176 | 177 | If You distribute Covered Software in Executable Form then: 178 | 179 | a. such Covered Software must also be made available in Source Code Form, 180 | as described in Section 3.1, and You must inform recipients of the 181 | Executable Form how they can obtain a copy of such Source Code Form by 182 | reasonable means in a timely manner, at a charge no more than the cost 183 | of distribution to the recipient; and 184 | 185 | b. You may distribute such Executable Form under the terms of this 186 | License, or sublicense it under different terms, provided that the 187 | license for the Executable Form does not attempt to limit or alter the 188 | recipients' rights in the Source Code Form under this License. 189 | 190 | 3.3. Distribution of a Larger Work 191 | 192 | You may create and distribute a Larger Work under terms of Your choice, 193 | provided that You also comply with the requirements of this License for 194 | the Covered Software. If the Larger Work is a combination of Covered 195 | Software with a work governed by one or more Secondary Licenses, and the 196 | Covered Software is not Incompatible With Secondary Licenses, this 197 | License permits You to additionally distribute such Covered Software 198 | under the terms of such Secondary License(s), so that the recipient of 199 | the Larger Work may, at their option, further distribute the Covered 200 | Software under the terms of either this License or such Secondary 201 | License(s). 202 | 203 | 3.4. Notices 204 | 205 | You may not remove or alter the substance of any license notices 206 | (including copyright notices, patent notices, disclaimers of warranty, or 207 | limitations of liability) contained within the Source Code Form of the 208 | Covered Software, except that You may alter any license notices to the 209 | extent required to remedy known factual inaccuracies. 210 | 211 | 3.5. Application of Additional Terms 212 | 213 | You may choose to offer, and to charge a fee for, warranty, support, 214 | indemnity or liability obligations to one or more recipients of Covered 215 | Software. However, You may do so only on Your own behalf, and not on 216 | behalf of any Contributor. You must make it absolutely clear that any 217 | such warranty, support, indemnity, or liability obligation is offered by 218 | You alone, and You hereby agree to indemnify every Contributor for any 219 | liability incurred by such Contributor as a result of warranty, support, 220 | indemnity or liability terms You offer. You may include additional 221 | disclaimers of warranty and limitations of liability specific to any 222 | jurisdiction. 223 | 224 | 4. Inability to Comply Due to Statute or Regulation 225 | 226 | If it is impossible for You to comply with any of the terms of this License 227 | with respect to some or all of the Covered Software due to statute, 228 | judicial order, or regulation then You must: (a) comply with the terms of 229 | this License to the maximum extent possible; and (b) describe the 230 | limitations and the code they affect. Such description must be placed in a 231 | text file included with all distributions of the Covered Software under 232 | this License. Except to the extent prohibited by statute or regulation, 233 | such description must be sufficiently detailed for a recipient of ordinary 234 | skill to be able to understand it. 235 | 236 | 5. Termination 237 | 238 | 5.1. The rights granted under this License will terminate automatically if You 239 | fail to comply with any of its terms. However, if You become compliant, 240 | then the rights granted under this License from a particular Contributor 241 | are reinstated (a) provisionally, unless and until such Contributor 242 | explicitly and finally terminates Your grants, and (b) on an ongoing 243 | basis, if such Contributor fails to notify You of the non-compliance by 244 | some reasonable means prior to 60 days after You have come back into 245 | compliance. Moreover, Your grants from a particular Contributor are 246 | reinstated on an ongoing basis if such Contributor notifies You of the 247 | non-compliance by some reasonable means, this is the first time You have 248 | received notice of non-compliance with this License from such 249 | Contributor, and You become compliant prior to 30 days after Your receipt 250 | of the notice. 251 | 252 | 5.2. If You initiate litigation against any entity by asserting a patent 253 | infringement claim (excluding declaratory judgment actions, 254 | counter-claims, and cross-claims) alleging that a Contributor Version 255 | directly or indirectly infringes any patent, then the rights granted to 256 | You by any and all Contributors for the Covered Software under Section 257 | 2.1 of this License shall terminate. 258 | 259 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user 260 | license agreements (excluding distributors and resellers) which have been 261 | validly granted by You or Your distributors under this License prior to 262 | termination shall survive termination. 263 | 264 | 6. Disclaimer of Warranty 265 | 266 | Covered Software is provided under this License on an "as is" basis, 267 | without warranty of any kind, either expressed, implied, or statutory, 268 | including, without limitation, warranties that the Covered Software is free 269 | of defects, merchantable, fit for a particular purpose or non-infringing. 270 | The entire risk as to the quality and performance of the Covered Software 271 | is with You. Should any Covered Software prove defective in any respect, 272 | You (not any Contributor) assume the cost of any necessary servicing, 273 | repair, or correction. This disclaimer of warranty constitutes an essential 274 | part of this License. No use of any Covered Software is authorized under 275 | this License except under this disclaimer. 276 | 277 | 7. Limitation of Liability 278 | 279 | Under no circumstances and under no legal theory, whether tort (including 280 | negligence), contract, or otherwise, shall any Contributor, or anyone who 281 | distributes Covered Software as permitted above, be liable to You for any 282 | direct, indirect, special, incidental, or consequential damages of any 283 | character including, without limitation, damages for lost profits, loss of 284 | goodwill, work stoppage, computer failure or malfunction, or any and all 285 | other commercial damages or losses, even if such party shall have been 286 | informed of the possibility of such damages. This limitation of liability 287 | shall not apply to liability for death or personal injury resulting from 288 | such party's negligence to the extent applicable law prohibits such 289 | limitation. Some jurisdictions do not allow the exclusion or limitation of 290 | incidental or consequential damages, so this exclusion and limitation may 291 | not apply to You. 292 | 293 | 8. Litigation 294 | 295 | Any litigation relating to this License may be brought only in the courts 296 | of a jurisdiction where the defendant maintains its principal place of 297 | business and such litigation shall be governed by laws of that 298 | jurisdiction, without reference to its conflict-of-law provisions. Nothing 299 | in this Section shall prevent a party's ability to bring cross-claims or 300 | counter-claims. 301 | 302 | 9. Miscellaneous 303 | 304 | This License represents the complete agreement concerning the subject 305 | matter hereof. If any provision of this License is held to be 306 | unenforceable, such provision shall be reformed only to the extent 307 | necessary to make it enforceable. Any law or regulation which provides that 308 | the language of a contract shall be construed against the drafter shall not 309 | be used to construe this License against a Contributor. 310 | 311 | 312 | 10. Versions of the License 313 | 314 | 10.1. New Versions 315 | 316 | Mozilla Foundation is the license steward. Except as provided in Section 317 | 10.3, no one other than the license steward has the right to modify or 318 | publish new versions of this License. Each version will be given a 319 | distinguishing version number. 320 | 321 | 10.2. Effect of New Versions 322 | 323 | You may distribute the Covered Software under the terms of the version 324 | of the License under which You originally received the Covered Software, 325 | or under the terms of any subsequent version published by the license 326 | steward. 327 | 328 | 10.3. Modified Versions 329 | 330 | If you create software not governed by this License, and you want to 331 | create a new license for such software, you may create and use a 332 | modified version of this License if you rename the license and remove 333 | any references to the name of the license steward (except to note that 334 | such modified license differs from this License). 335 | 336 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 337 | Licenses If You choose to distribute Source Code Form that is 338 | Incompatible With Secondary Licenses under the terms of this version of 339 | the License, the notice described in Exhibit B of this License must be 340 | attached. 341 | 342 | Exhibit A - Source Code Form License Notice 343 | 344 | This Source Code Form is subject to the 345 | terms of the Mozilla Public License, v. 346 | 2.0. If a copy of the MPL was not 347 | distributed with this file, You can 348 | obtain one at 349 | http://mozilla.org/MPL/2.0/. 350 | 351 | If it is not possible or desirable to put the notice in a particular file, 352 | then You may include the notice in a location (such as a LICENSE file in a 353 | relevant directory) where a recipient would be likely to look for such a 354 | notice. 355 | 356 | You may add additional accurate notices of copyright ownership. 357 | 358 | Exhibit B - "Incompatible With Secondary Licenses" Notice 359 | 360 | This Source Code Form is "Incompatible 361 | With Secondary Licenses", as defined by 362 | the Mozilla Public License, v. 2.0. -------------------------------------------------------------------------------- /dumper/dump.go: -------------------------------------------------------------------------------- 1 | package dumper 2 | 3 | import ( 4 | "fmt" 5 | "go/ast" 6 | ) 7 | 8 | func buildIndent(indentNum int) string { 9 | var indent string 10 | for i := 0; i < indentNum; i++ { 11 | indent += " " 12 | } 13 | return indent 14 | } 15 | 16 | func Dump(srcname string, f *ast.File) { 17 | fmt.Printf("%s returned <%T> %v\n---- Scope ----\n", srcname, f, f) 18 | dumpScope(f.Scope, 0) 19 | if f.Imports != nil && len(f.Imports) > 0 { 20 | fmt.Printf("--- Imports ---\n") 21 | for _, spec := range f.Imports { 22 | dumpImportSpec(spec, 0) 23 | } 24 | } 25 | if f.Decls != nil && len(f.Decls) > 0 { 26 | fmt.Printf("---- Decls ----\n") 27 | for _, decl := range f.Decls { 28 | dumpDecl(decl, 0) 29 | } 30 | } 31 | fmt.Printf("---------------\n") 32 | } 33 | 34 | func dumpArrayType(atyp *ast.ArrayType, indentNum int) { 35 | indent := buildIndent(indentNum) 36 | fmt.Printf("%s-- ArrayType\n", indent) 37 | 38 | indent1 := buildIndent(indentNum + 1) 39 | 40 | if atyp.Len != nil { 41 | fmt.Printf("%s-- Len\n", indent1) 42 | dumpExpr(atyp.Len, indentNum + 2) 43 | } 44 | 45 | fmt.Printf("%s-- Elt\n", indent1) 46 | dumpExpr(atyp.Elt, indentNum + 2) 47 | } 48 | 49 | func dumpAssignStmt(asgn *ast.AssignStmt, indentNum int) { 50 | fmt.Printf("%s-- AssignStmt\n", buildIndent(indentNum)) 51 | 52 | indent1 := buildIndent(indentNum + 1) 53 | 54 | if asgn.Lhs == nil || len(asgn.Lhs) == 0 { 55 | fmt.Printf("%s\n", indent1) 56 | } else { 57 | fmt.Printf("%s-- Lhs\n", indent1) 58 | for _, expr := range asgn.Lhs { 59 | dumpExpr(expr, indentNum + 2) 60 | } 61 | } 62 | 63 | fmt.Printf("%s-- Token -> %s\n", indent1, asgn.Tok.String()) 64 | 65 | if asgn.Rhs == nil || len(asgn.Rhs) == 0 { 66 | fmt.Printf("%s\n", indent1) 67 | } else { 68 | fmt.Printf("%s-- Rhs\n", indent1) 69 | for _, expr := range asgn.Rhs { 70 | dumpExpr(expr, indentNum + 2) 71 | } 72 | } 73 | } 74 | 75 | func dumpBinaryExpr(bin *ast.BinaryExpr, indentNum int) { 76 | indent := buildIndent(indentNum) 77 | 78 | if bin == nil { 79 | fmt.Printf("%sBinaryExpr -> \n", indent) 80 | return 81 | } 82 | 83 | fmt.Printf("%s-- BinaryExpr\n", indent) 84 | 85 | indent1 := buildIndent(indentNum + 1) 86 | 87 | if bin.X != nil { 88 | fmt.Printf("%s-- X\n", indent1) 89 | dumpExpr(bin.X, indentNum + 2) 90 | } 91 | 92 | fmt.Printf("%sOp -> \"%s\"\n", indent1, bin.Op.String()) 93 | 94 | if bin.Y != nil { 95 | fmt.Printf("%s-- Y\n", indent1) 96 | dumpExpr(bin.Y, indentNum + 2) 97 | } 98 | } 99 | 100 | func dumpBlockStmt(blk *ast.BlockStmt, indentNum int) { 101 | if blk.List == nil || len(blk.List) == 0 { 102 | fmt.Printf("%s\n", buildIndent(indentNum)) 103 | return 104 | } 105 | 106 | for _, stmt := range blk.List { 107 | dumpStmt(stmt, indentNum) 108 | } 109 | } 110 | 111 | func dumpBranchStmt(bstmt *ast.BranchStmt, indentNum int) { 112 | indent := buildIndent(indentNum) 113 | 114 | if bstmt == nil { 115 | fmt.Printf("%sBranchStmt -> \n", indent) 116 | return 117 | } 118 | 119 | fmt.Printf("%sBranchStmt -> %s\n", indent, bstmt.Tok.String()) 120 | 121 | indent1 := buildIndent(indentNum + 1) 122 | 123 | if bstmt.Label == nil { 124 | fmt.Printf("%s\n", indent1) 125 | } else { 126 | fmt.Printf("%sLabel -> %s\n", indent1, bstmt.Label.Name) 127 | } 128 | } 129 | 130 | func dumpCallExpr(call *ast.CallExpr, indentNum int) { 131 | fmt.Printf("%s-- CallExpr\n", buildIndent(indentNum)) 132 | 133 | dumpExpr(call.Fun, indentNum + 1) 134 | 135 | indent1 := buildIndent(indentNum + 1) 136 | if call.Args == nil || len(call.Args) == 0 { 137 | fmt.Printf("%s\n", indent1) 138 | } else { 139 | fmt.Printf("%s-- Args\n", indent1) 140 | for _, expr := range call.Args { 141 | dumpExpr(expr, indentNum + 2) 142 | } 143 | } 144 | 145 | } 146 | 147 | func dumpCaseClause(cc *ast.CaseClause, indentNum int) { 148 | indent := buildIndent(indentNum) 149 | 150 | if cc == nil { 151 | fmt.Printf("%sCaseClause -> \n", indent) 152 | return 153 | } 154 | 155 | indent1 := buildIndent(indentNum + 1) 156 | 157 | fmt.Printf("%sCaseClause ->\n", indent) 158 | 159 | if cc.List == nil || len(cc.List) == 0 { 160 | fmt.Printf("%s\n", indent1) 161 | } else { 162 | fmt.Printf("%s-- List\n", indent1) 163 | for _, expr := range cc.List { 164 | dumpExpr(expr, indentNum + 2) 165 | } 166 | } 167 | 168 | if cc.Body == nil || len(cc.Body) == 0 { 169 | fmt.Printf("%s\n", indent1) 170 | } else { 171 | fmt.Printf("%s-- Body\n", indent1) 172 | for _, stmt := range cc.Body { 173 | dumpStmt(stmt, indentNum + 2) 174 | } 175 | } 176 | } 177 | 178 | func dumpChanType(ch *ast.ChanType, indentNum int) { 179 | indent := buildIndent(indentNum) 180 | 181 | if ch == nil { 182 | fmt.Printf("%sChanType -> \n", indent) 183 | return 184 | } 185 | 186 | var dstr string 187 | switch ch.Dir { 188 | case ast.SEND: 189 | dstr = "SEND" 190 | case ast.RECV: 191 | dstr = "RECV" 192 | case ast.SEND|ast.RECV: 193 | dstr = "SEND|RECV" 194 | default: 195 | dstr = fmt.Sprintf("??ChanDir#%d??", ch.Dir) 196 | } 197 | 198 | fmt.Printf("%s-- ChanType -> Dir %s\n", indent, dstr) 199 | 200 | indent1 := buildIndent(indentNum + 1) 201 | 202 | if ch.Value != nil { 203 | fmt.Printf("%s-- Value\n", indent1) 204 | dumpExpr(ch.Value, indentNum + 2) 205 | } 206 | } 207 | 208 | func dumpCompositeLit(clit *ast.CompositeLit, indentNum int) { 209 | indent := buildIndent(indentNum) 210 | 211 | if clit == nil { 212 | fmt.Printf("%sCompositeLit -> \n", indent) 213 | return 214 | } 215 | 216 | fmt.Printf("%sCompositeLit\n", indent) 217 | 218 | indent1 := buildIndent(indentNum + 1) 219 | 220 | if clit.Type != nil { 221 | fmt.Printf("%s-- Type\n", indent1) 222 | dumpExpr(clit.Type, indentNum + 2) 223 | } 224 | 225 | if clit.Elts == nil || len(clit.Elts) == 0 { 226 | fmt.Printf("%s\n", indent1) 227 | } else { 228 | fmt.Printf("%s-- Elts\n", indent1) 229 | for _, expr := range clit.Elts { 230 | dumpExpr(expr, indentNum + 2) 231 | } 232 | } 233 | } 234 | 235 | func dumpDecl(decl ast.Decl, indentNum int) { 236 | if decl == nil { 237 | fmt.Printf("%sDecl -> \n", buildIndent(indentNum)) 238 | return 239 | } 240 | 241 | switch d := decl.(type) { 242 | case *ast.GenDecl: 243 | dumpGenDecl(d, indentNum) 244 | case *ast.FuncDecl: 245 | dumpFuncDecl(d, indentNum) 246 | default: 247 | fmt.Printf("%s??Unknown Decl %T??\n", buildIndent(indentNum), decl) 248 | } 249 | } 250 | 251 | func dumpDeferStmt(dstmt *ast.DeferStmt, indentNum int) { 252 | indent := buildIndent(indentNum) 253 | 254 | if dstmt == nil { 255 | fmt.Printf("%sDeferStmt -> \n", indent) 256 | return 257 | } 258 | 259 | fmt.Printf("%sDeferStmt ->\n", indent) 260 | dumpCallExpr(dstmt.Call, indentNum + 1) 261 | } 262 | 263 | func dumpEllipsis(elp *ast.Ellipsis, indentNum int) { 264 | indent := buildIndent(indentNum) 265 | 266 | if elp == nil { 267 | fmt.Printf("%sEllipsis -> \n", indent) 268 | return 269 | } 270 | 271 | fmt.Printf("%sEllipsis\n", indent) 272 | 273 | indent1 := buildIndent(indentNum + 1) 274 | 275 | if elp.Elt != nil { 276 | fmt.Printf("%s-- Elt\n", indent1) 277 | dumpExpr(elp.Elt, indentNum + 2) 278 | } 279 | } 280 | 281 | func dumpExpr(expr ast.Expr, indentNum int) { 282 | if expr == nil { 283 | fmt.Printf("%sExpr -> \n", buildIndent(indentNum)) 284 | return 285 | } 286 | 287 | switch e := expr.(type) { 288 | case *ast.ArrayType: 289 | dumpArrayType(e, indentNum) 290 | case *ast.BasicLit: 291 | fmt.Printf("%sBasicLit -> %s (tok %s)\n", buildIndent(indentNum), 292 | e.Value, e.Kind) 293 | case *ast.BinaryExpr: 294 | dumpBinaryExpr(e, indentNum) 295 | case *ast.CallExpr: 296 | dumpCallExpr(e, indentNum) 297 | case *ast.ChanType: 298 | dumpChanType(e, indentNum) 299 | case *ast.CompositeLit: 300 | dumpCompositeLit(e, indentNum) 301 | case *ast.Ellipsis: 302 | dumpEllipsis(e, indentNum) 303 | case *ast.FuncLit: 304 | dumpFuncLit(e, indentNum) 305 | case *ast.FuncType: 306 | dumpFuncType(e, indentNum) 307 | case *ast.Ident: 308 | fmt.Printf("%sIdent -> %s\n", buildIndent(indentNum), e.Name) 309 | case *ast.IndexExpr: 310 | dumpIndexExpr(e, indentNum) 311 | case *ast.InterfaceType: 312 | dumpInterfaceType(e, indentNum) 313 | case *ast.KeyValueExpr: 314 | dumpKeyValueExpr(e, indentNum) 315 | case *ast.MapType: 316 | fmt.Printf("%sMapType\n", buildIndent(indentNum)) 317 | dumpExpr(e.Key, indentNum + 1) 318 | dumpExpr(e.Value, indentNum + 1) 319 | case *ast.ParenExpr: 320 | dumpParenExpr(e, indentNum) 321 | case *ast.SelectorExpr: 322 | var sstr string 323 | if e.Sel == nil { 324 | sstr = "" 325 | } else { 326 | sstr = e.Sel.Name 327 | } 328 | 329 | fmt.Printf("%sSelectorExpr -> %s\n", buildIndent(indentNum), sstr) 330 | 331 | dumpExpr(e.X, indentNum + 1) 332 | case *ast.SliceExpr: 333 | dumpSliceExpr(e, indentNum) 334 | case *ast.StarExpr: 335 | fmt.Printf("%sStarExpr -> *\n", buildIndent(indentNum)) 336 | dumpExpr(e.X, indentNum + 1) 337 | case *ast.StructType: 338 | dumpStructType(e, indentNum + 1) 339 | case *ast.TypeAssertExpr: 340 | dumpTypeAssertExpr(e, indentNum + 1) 341 | case *ast.UnaryExpr: 342 | dumpUnaryExpr(e, indentNum) 343 | default: 344 | fmt.Printf("%s??Expr -> %T\n", buildIndent(indentNum), expr) 345 | } 346 | } 347 | 348 | func dumpField(fld *ast.Field, indentNum int) { 349 | if fld == nil { 350 | fmt.Printf("%sField -> \n", buildIndent(indentNum)) 351 | return 352 | } 353 | 354 | var names string 355 | if fld.Names == nil || len(fld.Names) == 0 { 356 | names = "" 357 | } else { 358 | for _, name := range fld.Names { 359 | if names != "" { 360 | names += ", " 361 | } 362 | 363 | if name == nil { 364 | names += "" 365 | } else { 366 | names += name.Name 367 | } 368 | } 369 | } 370 | 371 | var tag string 372 | if fld.Tag != nil { 373 | tag = " tag " + fld.Tag.Value 374 | } 375 | 376 | fmt.Printf("%sField -> %s%s\n", buildIndent(indentNum), names, tag) 377 | dumpExpr(fld.Type, indentNum + 1) 378 | } 379 | 380 | func dumpFieldList(list *ast.FieldList, indentNum int) { 381 | if list == nil { 382 | fmt.Printf("%sFieldList -> \n", buildIndent(indentNum)) 383 | return 384 | } 385 | 386 | if list.List == nil || len(list.List) == 0 { 387 | fmt.Printf("%s\n", buildIndent(indentNum)) 388 | return 389 | } 390 | 391 | for _, fld := range list.List { 392 | dumpField(fld, indentNum) 393 | } 394 | } 395 | 396 | func dumpForStmt(fstmt *ast.ForStmt, indentNum int) { 397 | indent := buildIndent(indentNum) 398 | 399 | if fstmt == nil { 400 | fmt.Printf("%sForStmt -> \n", indent) 401 | return 402 | } 403 | 404 | fmt.Printf("%s-- ForStmt\n", indent) 405 | 406 | indent1 := buildIndent(indentNum + 1) 407 | 408 | if fstmt.Init != nil { 409 | fmt.Printf("%s-- Init\n", indent1) 410 | dumpStmt(fstmt.Init, indentNum + 2) 411 | } 412 | if fstmt.Cond != nil { 413 | fmt.Printf("%s-- Cond\n", indent1) 414 | dumpExpr(fstmt.Cond, indentNum + 2) 415 | } 416 | if fstmt.Post != nil { 417 | fmt.Printf("%s-- Post\n", indent1) 418 | dumpStmt(fstmt.Post, indentNum + 2) 419 | } 420 | if fstmt.Body != nil { 421 | fmt.Printf("%s-- Body\n", indent1) 422 | dumpBlockStmt(fstmt.Body, indentNum + 2) 423 | } 424 | } 425 | 426 | func dumpFuncDecl(fun *ast.FuncDecl, indentNum int) { 427 | indent := buildIndent(indentNum) 428 | 429 | if fun == nil { 430 | fmt.Printf("%sFuncDecl -> \n", indent) 431 | return 432 | } 433 | 434 | fmt.Printf("%sFuncDecl %s\n", indent, fun.Name.Name) 435 | 436 | if fun.Recv != nil { 437 | fmt.Printf("%s-- Recv\n", indent) 438 | dumpFieldList(fun.Recv, indentNum + 1) 439 | } 440 | 441 | if fun.Type != nil { 442 | dumpFuncType(fun.Type, indentNum + 1) 443 | } 444 | 445 | if fun.Body != nil { 446 | fmt.Printf("%s-- Body\n", indent) 447 | dumpBlockStmt(fun.Body, indentNum + 1) 448 | } 449 | } 450 | 451 | func dumpFuncType(ftyp *ast.FuncType, indentNum int) { 452 | indent := buildIndent(indentNum) 453 | 454 | if ftyp == nil || (ftyp.Params == nil && ftyp.Results == nil) { 455 | fmt.Printf("%s-- \n", indent) 456 | } else { 457 | if ftyp.Params != nil { 458 | fmt.Printf("%s-- FuncType.Params\n", indent) 459 | dumpFieldList(ftyp.Params, indentNum + 1) 460 | } 461 | if ftyp.Results != nil { 462 | fmt.Printf("%s-- FuncType.Results\n", indent) 463 | dumpFieldList(ftyp.Results, indentNum + 1) 464 | } 465 | } 466 | } 467 | 468 | func dumpFuncLit(flit *ast.FuncLit, indentNum int) { 469 | indent := buildIndent(indentNum) 470 | 471 | if flit == nil { 472 | fmt.Printf("%sFuncLit -> \n", indent) 473 | return 474 | } 475 | 476 | fmt.Printf("%sFuncLit\n", indent) 477 | 478 | if flit.Type != nil { 479 | dumpFuncType(flit.Type, indentNum + 1) 480 | } 481 | 482 | if flit.Body != nil { 483 | fmt.Printf("%s-- Body\n", indent) 484 | dumpBlockStmt(flit.Body, indentNum + 1) 485 | } 486 | } 487 | 488 | func dumpGenDecl(gen *ast.GenDecl, indentNum int) { 489 | fmt.Printf("%sGenDecl -> \"%s\"\n", buildIndent(indentNum), 490 | gen.Tok.String()) 491 | if gen.Specs != nil { 492 | for _, spec := range gen.Specs { 493 | dumpSpec(spec, indentNum + 1) 494 | } 495 | } 496 | } 497 | 498 | func dumpGoStmt(gostmt *ast.GoStmt, indentNum int) { 499 | indent := buildIndent(indentNum) 500 | 501 | if gostmt == nil { 502 | fmt.Printf("%sGoStmt -> \n", indent) 503 | return 504 | } 505 | 506 | fmt.Printf("%sGoStmt ->\n", indent) 507 | dumpCallExpr(gostmt.Call, indentNum + 1) 508 | } 509 | 510 | func dumpIfStmt(ifstmt *ast.IfStmt, indentNum int) { 511 | indent := buildIndent(indentNum) 512 | 513 | if ifstmt == nil { 514 | fmt.Printf("%sIfStmt -> \n", indent) 515 | return 516 | } 517 | 518 | fmt.Printf("%s-- IfStmt\n", indent) 519 | 520 | indent1 := buildIndent(indentNum + 1) 521 | 522 | if ifstmt.Init != nil { 523 | fmt.Printf("%s-- Init\n", indent1) 524 | dumpStmt(ifstmt.Init, indentNum + 2) 525 | } 526 | if ifstmt.Cond != nil { 527 | fmt.Printf("%s-- Cond\n", indent1) 528 | dumpExpr(ifstmt.Cond, indentNum + 2) 529 | } 530 | if ifstmt.Body != nil { 531 | fmt.Printf("%s-- Body\n", indent1) 532 | dumpBlockStmt(ifstmt.Body, indentNum + 2) 533 | } 534 | if ifstmt.Else != nil { 535 | fmt.Printf("%s-- Else\n", indent1) 536 | dumpStmt(ifstmt.Else, indentNum + 2) 537 | } 538 | } 539 | 540 | func dumpImportSpec(spec *ast.ImportSpec, indentNum int) { 541 | if spec == nil { 542 | fmt.Printf("%sImportSpec -> \n", buildIndent(indentNum)) 543 | return 544 | } 545 | 546 | var nstr string 547 | if spec.Name != nil { 548 | nstr = fmt.Sprintf(" name %s", spec.Name.Name) 549 | } 550 | 551 | var pstr string 552 | if spec.Path != nil { 553 | pstr = fmt.Sprintf(" path %s", spec.Path.Value) 554 | } 555 | 556 | fmt.Printf("%sImportSpec ->%s%s\n", buildIndent(indentNum), nstr, pstr) 557 | } 558 | 559 | func dumpIncDecStmt(ids *ast.IncDecStmt, indentNum int) { 560 | indent := buildIndent(indentNum) 561 | 562 | if ids == nil { 563 | fmt.Printf("%sIncDecStmt -> \n", indent) 564 | return 565 | } 566 | 567 | fmt.Printf("%sIncDecStmt -> %s\n", indent, ids.Tok.String()) 568 | 569 | if ids.X != nil { 570 | fmt.Printf("%s-- X\n", buildIndent(indentNum + 1)) 571 | dumpExpr(ids.X, indentNum + 2) 572 | } 573 | } 574 | 575 | func dumpIndexExpr(idx *ast.IndexExpr, indentNum int) { 576 | indent := buildIndent(indentNum) 577 | 578 | if idx == nil { 579 | fmt.Printf("%sIndexExpr -> \n", indent) 580 | return 581 | } 582 | 583 | fmt.Printf("%s-- IndexExpr\n", indent) 584 | 585 | indent1 := buildIndent(indentNum + 1) 586 | 587 | if idx.X != nil { 588 | fmt.Printf("%s-- X\n", indent1) 589 | dumpExpr(idx.X, indentNum + 2) 590 | } 591 | 592 | if idx.Index != nil { 593 | fmt.Printf("%s-- Index\n", indent1) 594 | dumpExpr(idx.Index, indentNum + 2) 595 | } 596 | } 597 | 598 | func dumpInterfaceType(ityp *ast.InterfaceType, indentNum int) { 599 | indent := buildIndent(indentNum) 600 | 601 | if ityp == nil { 602 | fmt.Printf("%sInterfaceType -> \n", indent) 603 | return 604 | } 605 | 606 | var istr string 607 | if ityp.Incomplete { 608 | istr = " Incomplete" 609 | } 610 | 611 | fmt.Printf("%sInterfaceType ->%s\n", indent, istr) 612 | dumpFieldList(ityp.Methods, indentNum + 1) 613 | } 614 | 615 | func dumpKeyValueExpr(kv *ast.KeyValueExpr, indentNum int) { 616 | indent := buildIndent(indentNum) 617 | 618 | if kv == nil { 619 | fmt.Printf("%sKeyValueExpr -> \n", indent) 620 | return 621 | } 622 | 623 | fmt.Printf("%s-- KeyValueExpr\n", indent) 624 | 625 | indent1 := buildIndent(indentNum + 1) 626 | 627 | if kv.Key != nil { 628 | fmt.Printf("%s-- Key\n", indent1) 629 | dumpExpr(kv.Key, indentNum + 2) 630 | } 631 | 632 | if kv.Value != nil { 633 | fmt.Printf("%s-- Value\n", indent1) 634 | dumpExpr(kv.Value, indentNum + 2) 635 | } 636 | } 637 | 638 | func dumpLabeledStmt(lex *ast.LabeledStmt, indentNum int) { 639 | indent := buildIndent(indentNum) 640 | 641 | if lex == nil { 642 | fmt.Printf("%sLabeledExpr -> \n", indent) 643 | return 644 | } 645 | 646 | fmt.Printf("%s-- LabeledExpr\n", indent) 647 | 648 | indent1 := buildIndent(indentNum + 1) 649 | 650 | if lex.Label != nil { 651 | fmt.Printf("%s-- Label -> %v\n", indent1, lex.Label) 652 | } 653 | if lex.Stmt != nil { 654 | fmt.Printf("%s-- Stmt\n", indent1) 655 | dumpStmt(lex.Stmt, indentNum + 2) 656 | } 657 | } 658 | 659 | func dumpParenExpr(prn *ast.ParenExpr, indentNum int) { 660 | indent := buildIndent(indentNum) 661 | 662 | if prn == nil { 663 | fmt.Printf("%sParenExpr -> \n", indent) 664 | return 665 | } 666 | 667 | fmt.Printf("%s-- ParenExpr\n", indent) 668 | 669 | indent1 := buildIndent(indentNum + 1) 670 | 671 | if prn.X != nil { 672 | fmt.Printf("%s-- X\n", indent1) 673 | dumpExpr(prn.X, indentNum + 2) 674 | } 675 | } 676 | 677 | func dumpRangeStmt(rstmt *ast.RangeStmt, indentNum int) { 678 | indent := buildIndent(indentNum) 679 | 680 | if rstmt == nil { 681 | fmt.Printf("%sRangeStmt -> \n", indent) 682 | return 683 | } 684 | 685 | fmt.Printf("%s-- RangeStmt -> %s\n", indent, rstmt.Tok.String()) 686 | 687 | indent1 := buildIndent(indentNum + 1) 688 | 689 | if rstmt.Key != nil { 690 | fmt.Printf("%s-- Key\n", indent1) 691 | dumpExpr(rstmt.Key, indentNum + 2) 692 | } 693 | if rstmt.Value != nil { 694 | fmt.Printf("%s-- Value\n", indent1) 695 | dumpExpr(rstmt.Value, indentNum + 2) 696 | } 697 | if rstmt.X != nil { 698 | fmt.Printf("%s-- X\n", indent1) 699 | dumpExpr(rstmt.X, indentNum + 2) 700 | } 701 | if rstmt.Body != nil { 702 | fmt.Printf("%s-- Body\n", indent1) 703 | dumpBlockStmt(rstmt.Body, indentNum + 2) 704 | } 705 | } 706 | 707 | func dumpReturnStmt(rtn *ast.ReturnStmt, indentNum int) { 708 | indent := buildIndent(indentNum) 709 | 710 | if rtn == nil { 711 | fmt.Printf("%sReturnStmt -> \n", indent) 712 | return 713 | } 714 | 715 | fmt.Printf("%sReturnStmt ->\n", indent) 716 | for _, expr := range rtn.Results { 717 | dumpExpr(expr, indentNum + 1) 718 | } 719 | } 720 | 721 | func dumpScope(scope *ast.Scope, indentNum int) { 722 | indent := buildIndent(indentNum) 723 | 724 | if scope == nil { 725 | fmt.Printf("%s\n", indent) 726 | return 727 | } 728 | 729 | if scope.Objects == nil { 730 | fmt.Printf("%s\n", indent) 731 | } else { 732 | for k, v := range scope.Objects { 733 | fmt.Printf("%s%s: <%T> %v\n", indent, k, v, v) 734 | } 735 | } 736 | 737 | dumpScope(scope.Outer, indentNum + 1) 738 | } 739 | 740 | func dumpSendStmt(ss *ast.SendStmt, indentNum int) { 741 | indent := buildIndent(indentNum) 742 | 743 | if ss == nil { 744 | fmt.Printf("%sSendStmt -> \n", indent) 745 | return 746 | } 747 | 748 | fmt.Printf("%sSendStmt\n", indent) 749 | 750 | indent1 := buildIndent(indentNum + 1) 751 | 752 | if ss.Chan != nil { 753 | fmt.Printf("%s-- Chan\n", indent1) 754 | dumpExpr(ss.Chan, indentNum + 2) 755 | } 756 | if ss.Value != nil { 757 | fmt.Printf("%s-- Value\n", indent1) 758 | dumpExpr(ss.Value, indentNum + 2) 759 | } 760 | } 761 | 762 | func dumpSliceExpr(slc *ast.SliceExpr, indentNum int) { 763 | indent := buildIndent(indentNum) 764 | 765 | if slc == nil { 766 | fmt.Printf("%sSliceExpr -> \n", indent) 767 | return 768 | } 769 | 770 | fmt.Printf("%s-- SliceExpr\n", indent) 771 | 772 | indent1 := buildIndent(indentNum + 1) 773 | 774 | if slc.X != nil { 775 | fmt.Printf("%s-- X\n", indent1) 776 | dumpExpr(slc.X, indentNum + 2) 777 | } 778 | 779 | if slc.Low != nil { 780 | fmt.Printf("%s-- Low\n", indent1) 781 | dumpExpr(slc.Low, indentNum + 2) 782 | } 783 | 784 | if slc.High != nil { 785 | fmt.Printf("%s-- High\n", indent1) 786 | dumpExpr(slc.High, indentNum + 2) 787 | } 788 | 789 | if slc.Max != nil { 790 | fmt.Printf("%s-- Max\n", indent1) 791 | dumpExpr(slc.Max, indentNum + 2) 792 | } 793 | } 794 | 795 | func dumpSpec(spec ast.Spec, indentNum int) { 796 | if spec == nil { 797 | fmt.Printf("%sSpec -> \n", buildIndent(indentNum)) 798 | return 799 | } 800 | 801 | switch s := spec.(type) { 802 | case *ast.ImportSpec: 803 | dumpImportSpec(s, indentNum) 804 | case *ast.TypeSpec: 805 | dumpTypeSpec(s, indentNum) 806 | case *ast.ValueSpec: 807 | dumpValueSpec(s, indentNum) 808 | default: 809 | fmt.Printf("%s??Spec -> %T\n", buildIndent(indentNum), spec) 810 | } 811 | } 812 | 813 | func dumpStmt(stmt ast.Stmt, indentNum int) { 814 | switch s := stmt.(type) { 815 | case *ast.AssignStmt: 816 | dumpAssignStmt(s, indentNum) 817 | case *ast.BlockStmt: 818 | dumpBlockStmt(s, indentNum) 819 | case *ast.BranchStmt: 820 | dumpBranchStmt(s, indentNum) 821 | case *ast.CaseClause: 822 | dumpCaseClause(s, indentNum) 823 | // case *ast.CommClause: 824 | case *ast.DeclStmt: 825 | fmt.Printf("%s-- DeclStmt\n", buildIndent(indentNum)) 826 | dumpDecl(s.Decl, indentNum + 1) 827 | case *ast.DeferStmt: 828 | dumpDeferStmt(s, indentNum) 829 | // case *ast.EmptyStmt: 830 | case *ast.ExprStmt: 831 | fmt.Printf("%s-- ExprStmt\n", buildIndent(indentNum)) 832 | dumpExpr(s.X, indentNum + 1) 833 | case *ast.ForStmt: 834 | dumpForStmt(s, indentNum) 835 | case *ast.GoStmt: 836 | dumpGoStmt(s, indentNum) 837 | case *ast.IfStmt: 838 | dumpIfStmt(s, indentNum) 839 | case *ast.IncDecStmt: 840 | dumpIncDecStmt(s, indentNum) 841 | case *ast.LabeledStmt: 842 | dumpLabeledStmt(s, indentNum) 843 | case *ast.RangeStmt: 844 | dumpRangeStmt(s, indentNum) 845 | case *ast.ReturnStmt: 846 | dumpReturnStmt(s, indentNum) 847 | // case *ast.SelectStmt: 848 | case *ast.SendStmt: 849 | dumpSendStmt(s, indentNum) 850 | case *ast.SwitchStmt: 851 | dumpSwitchStmt(s, indentNum) 852 | case *ast.TypeSwitchStmt: 853 | dumpTypeSwitchStmt(s, indentNum) 854 | default: 855 | fmt.Printf("%s??Stmt -> %T\n", buildIndent(indentNum), stmt) 856 | } 857 | } 858 | 859 | func dumpStructType(styp *ast.StructType, indentNum int) { 860 | indent := buildIndent(indentNum) 861 | 862 | if styp == nil { 863 | fmt.Printf("%sStructType -> \n", indent) 864 | return 865 | } 866 | 867 | var istr string 868 | if styp.Incomplete { 869 | istr = " Incomplete" 870 | } 871 | 872 | fmt.Printf("%sStructType ->%s\n", indent, istr) 873 | dumpFieldList(styp.Fields, indentNum + 1) 874 | } 875 | 876 | func dumpSwitchStmt(ss *ast.SwitchStmt, indentNum int) { 877 | indent := buildIndent(indentNum) 878 | 879 | if ss == nil { 880 | fmt.Printf("%sSwitchStmt -> \n", indent) 881 | return 882 | } 883 | 884 | fmt.Printf("%sSwitchStmt\n", indent) 885 | 886 | indent1 := buildIndent(indentNum + 1) 887 | 888 | if ss.Init != nil { 889 | fmt.Printf("%s-- Init\n", indent1) 890 | dumpStmt(ss.Init, indentNum + 2) 891 | } 892 | if ss.Tag != nil { 893 | fmt.Printf("%s-- Tag\n", indent1) 894 | dumpExpr(ss.Tag, indentNum + 2) 895 | } 896 | if ss.Body != nil { 897 | fmt.Printf("%s-- Body\n", indent1) 898 | dumpBlockStmt(ss.Body, indentNum + 2) 899 | } 900 | } 901 | 902 | func dumpTypeAssertExpr(tae *ast.TypeAssertExpr, indentNum int) { 903 | indent := buildIndent(indentNum) 904 | 905 | if tae == nil { 906 | fmt.Printf("%sTypeAssertExpr -> \n", indent) 907 | return 908 | } 909 | 910 | fmt.Printf("%s-- TypeAssertExpr\n", indent) 911 | 912 | indent1 := buildIndent(indentNum + 1) 913 | 914 | if tae.X != nil { 915 | fmt.Printf("%s-- X\n", indent1) 916 | dumpExpr(tae.X, indentNum + 2) 917 | } 918 | 919 | if tae.Type != nil { 920 | fmt.Printf("%s-- Type\n", indent1) 921 | dumpExpr(tae.Type, indentNum + 2) 922 | } 923 | } 924 | 925 | func dumpTypeSpec(spec *ast.TypeSpec, indentNum int) { 926 | indent := buildIndent(indentNum) 927 | 928 | if spec == nil { 929 | fmt.Printf("%sTypeSpec -> \n", indent) 930 | return 931 | } 932 | 933 | var name string 934 | if spec.Name == nil { 935 | name = "" 936 | } else { 937 | name = spec.Name.Name 938 | } 939 | 940 | fmt.Printf("%sTypeSpec -> name %s\n", indent, name) 941 | 942 | if spec.Type != nil { 943 | fmt.Printf("%s-- Type\n", indent) 944 | dumpExpr(spec.Type, indentNum + 1) 945 | } 946 | } 947 | 948 | func dumpTypeSwitchStmt(tss *ast.TypeSwitchStmt, indentNum int) { 949 | indent := buildIndent(indentNum) 950 | 951 | if tss == nil { 952 | fmt.Printf("%sTypeSwitchStmt -> \n", indent) 953 | return 954 | } 955 | 956 | fmt.Printf("%sTypeSwitchStmt\n", indent) 957 | 958 | indent1 := buildIndent(indentNum + 1) 959 | 960 | if tss.Init != nil { 961 | fmt.Printf("%s-- Init\n", indent1) 962 | dumpStmt(tss.Init, indentNum + 2) 963 | } 964 | if tss.Assign != nil { 965 | fmt.Printf("%s-- Assign\n", indent1) 966 | dumpStmt(tss.Assign, indentNum + 2) 967 | } 968 | if tss.Body != nil { 969 | fmt.Printf("%s-- Body\n", indent1) 970 | dumpBlockStmt(tss.Body, indentNum + 2) 971 | } 972 | } 973 | 974 | func dumpUnaryExpr(unary *ast.UnaryExpr, indentNum int) { 975 | indent := buildIndent(indentNum) 976 | 977 | if unary == nil { 978 | fmt.Printf("%sUnaryExpr -> \n", indent) 979 | return 980 | } 981 | 982 | fmt.Printf("%s-- UnaryExpr\n", indent) 983 | 984 | indent1 := buildIndent(indentNum + 1) 985 | 986 | fmt.Printf("%sOp -> \"%s\"\n", indent1, unary.Op.String()) 987 | 988 | if unary.X != nil { 989 | fmt.Printf("%s-- X\n", indent1) 990 | dumpExpr(unary.X, indentNum + 2) 991 | } 992 | } 993 | 994 | func dumpValueSpec(spec *ast.ValueSpec, indentNum int) { 995 | if spec == nil { 996 | fmt.Printf("%sValueSpec -> \n", buildIndent(indentNum)) 997 | return 998 | } 999 | 1000 | var names string 1001 | if spec.Names == nil || len(spec.Names) == 0 { 1002 | names = "" 1003 | } else { 1004 | for _, name := range spec.Names { 1005 | if names != "" { 1006 | names += ", " 1007 | } 1008 | 1009 | if name == nil { 1010 | names += "" 1011 | } else { 1012 | names += name.Name 1013 | } 1014 | } 1015 | } 1016 | 1017 | indent := buildIndent(indentNum) 1018 | 1019 | fmt.Printf("%sValueSpec -> names %s\n", indent, names) 1020 | 1021 | if spec.Type != nil { 1022 | fmt.Printf("%s-- Type\n", indent) 1023 | dumpExpr(spec.Type, indentNum + 1) 1024 | } 1025 | 1026 | if spec.Values != nil && len(spec.Values) > 0 { 1027 | fmt.Printf("%s-- Values\n", indent) 1028 | for _, val := range spec.Values { 1029 | dumpExpr(val, indentNum + 1) 1030 | } 1031 | } 1032 | } 1033 | -------------------------------------------------------------------------------- /grammar/jobj.go: -------------------------------------------------------------------------------- 1 | package grammar 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "reflect" 8 | //"runtime/debug" // debug.PrintStack() 9 | "strings" 10 | ) 11 | 12 | const indentStep = " " 13 | 14 | func isNil(j JObject) bool { 15 | return j == nil || !reflect.ValueOf(j).Elem().IsValid() 16 | } 17 | 18 | type JObject interface { 19 | } 20 | 21 | type JUnimplemented struct { 22 | TypeStr string 23 | } 24 | 25 | func NewJUnimplemented(typestr string) *JUnimplemented { 26 | return &JUnimplemented{TypeStr: typestr} 27 | } 28 | 29 | type JAnnotation struct { 30 | name *JTypeName 31 | elem []JObject 32 | has_parens bool 33 | } 34 | 35 | func NewJAnnotation(name *JTypeName, elem []JObject, 36 | has_parens bool) *JAnnotation { 37 | if name == nil { 38 | ReportError("Annotation name cannot be nil") 39 | } 40 | 41 | return &JAnnotation{name: name, elem: elem, has_parens: has_parens} 42 | } 43 | 44 | type JArrayAlloc struct { 45 | Typename *JTypeName 46 | Dimexprs []JObject 47 | Dims int 48 | Init []*JVariableInit 49 | } 50 | 51 | func NewJArrayAlloc(typename *JTypeName, dimexprs []JObject, 52 | dims int) *JArrayAlloc { 53 | if typename == nil { 54 | ReportError("ArrayExpr name cannot be nil") 55 | } 56 | 57 | return &JArrayAlloc{Typename: typename, Dimexprs: dimexprs, Dims: dims} 58 | } 59 | 60 | func (j *JArrayAlloc) SetInitializers(init []*JVariableInit) { 61 | j.Init = init 62 | } 63 | 64 | type JArrayReference struct { 65 | Name *JTypeName 66 | Obj JObject 67 | Expr JObject 68 | } 69 | 70 | func NewJArrayReference(name *JTypeName, obj JObject, expr JObject) *JArrayReference { 71 | if name == nil && obj == nil { 72 | ReportError("NewArrayExpr name or obj must be specified") 73 | } else if name != nil && obj != nil { 74 | ReportError("NewArrayExpr name and obj cannot both be specified") 75 | } else if expr == nil { 76 | ReportError("NewArrayExpr expr cannot be nil") 77 | } 78 | 79 | return &JArrayReference{Name: name, Obj: obj, Expr: expr} 80 | } 81 | 82 | type JAssignmentExpr struct { 83 | Left JObject 84 | Op string 85 | Right JObject 86 | } 87 | 88 | func NewJAssignmentExpr(left JObject, op string, right JObject) *JAssignmentExpr { 89 | if left == nil { 90 | ReportError("JAssignmentExpr left expression cannot be nil") 91 | } else if right == nil { 92 | ReportError("JAssignmentExpr right expression cannot be nil") 93 | } 94 | 95 | return &JAssignmentExpr{Left: left, Op: op, Right: right} 96 | } 97 | 98 | type JBinaryExpr struct { 99 | Obj1 JObject 100 | Op string 101 | Obj2 JObject 102 | } 103 | 104 | func NewJBinaryExpr(obj1 JObject, op string, obj2 JObject) *JBinaryExpr { 105 | if obj1 == nil { 106 | ReportError("BinaryExpr object1 cannot be nil") 107 | } else if op == "" { 108 | ReportError("BinaryExpr op cannot be empty") 109 | } else if obj2 == nil { 110 | ReportError("BinaryExpr object2 cannot be nil") 111 | } 112 | 113 | return &JBinaryExpr{Obj1: obj1, Op: op, Obj2: obj2} 114 | } 115 | 116 | type JBlock struct { 117 | static bool 118 | List []JObject 119 | } 120 | 121 | func NewJBlock(list []JObject) *JBlock { 122 | return &JBlock{List: list} 123 | } 124 | 125 | func (j *JBlock) SetStatic() { j.static = true } 126 | 127 | type JCastExpr struct { 128 | Reftype *JReferenceType 129 | Target JObject 130 | } 131 | 132 | func NewJCastExpr(reftype *JReferenceType, target JObject) *JCastExpr { 133 | if reftype == nil { 134 | ReportError("CastExpr reference type cannot be nil") 135 | } else if target == nil { 136 | ReportError("CastExpr target cannot be nil") 137 | } 138 | 139 | return &JCastExpr{Reftype: reftype, Target: target} 140 | } 141 | 142 | type JCatch struct { 143 | Modifiers *JModifiers 144 | TypeList []*JTypeName 145 | Name string 146 | Block *JBlock 147 | } 148 | 149 | func NewJCatch(modifiers *JModifiers, typelist []*JTypeName, name string, 150 | block *JBlock) *JCatch { 151 | if typelist == nil || len(typelist) == 0 { 152 | panic("List of exception types cannot be nil/empty") 153 | } 154 | 155 | return &JCatch{Modifiers: modifiers, TypeList: typelist, Name: name, 156 | Block: block} 157 | } 158 | 159 | type JClassAllocationExpr struct { 160 | Name *JTypeName 161 | TypeArgs []*JTypeArgument 162 | Arglist []JObject 163 | Body []JObject 164 | } 165 | 166 | func NewJClassAllocationExpr(name *JTypeName, obj_args []JObject, 167 | arglist []JObject) *JClassAllocationExpr { 168 | if name == nil { 169 | ReportError("Class name cannot be nil") 170 | } 171 | 172 | var type_args []*JTypeArgument 173 | if obj_args != nil && len(obj_args) > 0 { 174 | type_args = make([]*JTypeArgument, len(obj_args)) 175 | for i, o := range obj_args { 176 | if arg, ok := o.(*JTypeArgument); ok { 177 | type_args[i] = arg 178 | } else { 179 | ReportCastError("JTypeArgument", o) 180 | } 181 | } 182 | } 183 | 184 | return &JClassAllocationExpr{Name: name, TypeArgs: type_args, 185 | Arglist: arglist} 186 | } 187 | 188 | func (j *JClassAllocationExpr) SetBody(body []JObject) { 189 | j.Body = body 190 | } 191 | 192 | type JClassBody struct { 193 | List []JObject 194 | } 195 | 196 | func NewJClassBody(list []JObject) *JClassBody { 197 | if list == nil || len(list) == 0 { 198 | panic("JClassBody list cannot be empty/nil") 199 | } 200 | 201 | return &JClassBody{List: list} 202 | } 203 | 204 | type JClassDecl struct { 205 | modifiers *JModifiers 206 | Name string 207 | type_params []JObject 208 | Extends *JReferenceType 209 | Interfaces []*JTypeName 210 | Body []JObject 211 | } 212 | 213 | func NewJClassDecl(modifiers *JModifiers, name string, type_params []JObject, 214 | extends *JReferenceType, interfaces []*JTypeName, body []JObject) *JClassDecl { 215 | if name == "" { 216 | ReportError("JClassDecl name cannot be empty") 217 | } 218 | 219 | return &JClassDecl{modifiers: modifiers, Name: name, 220 | type_params: type_params, Extends: extends, Interfaces: interfaces, 221 | Body: body} 222 | } 223 | 224 | type JConditionalExpr struct { 225 | CondExpr JObject 226 | IfExpr JObject 227 | ElseExpr JObject 228 | } 229 | 230 | func NewJConditionalExpr(condexpr JObject, ifexpr JObject, elseexpr JObject) *JConditionalExpr { 231 | return &JConditionalExpr{CondExpr: condexpr, IfExpr: ifexpr, 232 | ElseExpr: elseexpr} 233 | } 234 | 235 | type JConstantDecl struct { 236 | modifiers *JModifiers 237 | TypeSpec *JReferenceType 238 | Name string 239 | Dims int 240 | Init *JVariableInit 241 | } 242 | 243 | func NewJConstantDecl(name string, dims int, 244 | init *JVariableInit) *JConstantDecl { 245 | return &JConstantDecl{Name: name, Dims: dims, Init: init} 246 | } 247 | 248 | func (j *JConstantDecl) HasName() bool { 249 | return j.Name != "" 250 | } 251 | 252 | func (j *JConstantDecl) SetModifiers(modifiers *JModifiers) { 253 | j.modifiers = modifiers 254 | } 255 | 256 | func (j *JConstantDecl) SetName(name string) { 257 | if name == "" { 258 | panic("Constant name cannot be empty") 259 | } else if j.Name != "" { 260 | panic(fmt.Sprintf("Cannot overwrite constant name \"%s\" with \"%s\"", 261 | j.Name, name)) 262 | } 263 | 264 | j.Name = name 265 | } 266 | 267 | func (j *JConstantDecl) SetType(typespec *JReferenceType) { 268 | j.TypeSpec = typespec 269 | } 270 | 271 | type JElementValuePair struct { 272 | name string 273 | value JObject 274 | } 275 | 276 | func NewJElementValuePair(name string, value JObject) *JElementValuePair { 277 | if name == "" { 278 | ReportError("ReferenceType name cannot be empty") 279 | } 280 | 281 | return &JElementValuePair{name: name, value: value} 282 | } 283 | 284 | type JEmpty struct { 285 | } 286 | 287 | func NewJEmpty() *JEmpty { 288 | return &JEmpty{} 289 | } 290 | 291 | type JEnumBody struct { 292 | constants []*JEnumConstant 293 | bodydecl []JObject 294 | } 295 | 296 | func NewJEnumBody(clist []JObject, bodydecl []JObject) *JEnumBody { 297 | var constants []*JEnumConstant 298 | if clist != nil && len(clist) > 0 { 299 | constants = make([]*JEnumConstant, len(clist)) 300 | for i, v := range clist { 301 | if jcon, ok := v.(*JEnumConstant); !ok { 302 | ReportCastError("JEnumConstant", v) 303 | } else { 304 | constants[i] = jcon 305 | } 306 | } 307 | } 308 | 309 | return &JEnumBody{constants: constants, bodydecl: bodydecl} 310 | } 311 | 312 | type JEnumConstant struct { 313 | Annotations []*JAnnotation 314 | Name string 315 | ArgList []JObject 316 | Body []JObject 317 | } 318 | 319 | func NewJEnumConstant(alist []JObject, name string, arglist []JObject, 320 | body []JObject) *JEnumConstant { 321 | var annotations []*JAnnotation 322 | if alist != nil && len(alist) > 0 { 323 | annotations := make([]*JAnnotation, len(alist)) 324 | for i, v := range alist { 325 | if jann, ok := v.(*JAnnotation); !ok { 326 | ReportCastError("JAnnotation", v) 327 | } else { 328 | annotations[i] = jann 329 | } 330 | } 331 | } 332 | 333 | return &JEnumConstant{Annotations: annotations, Name: name, 334 | ArgList: arglist, Body: body} 335 | } 336 | 337 | type JEnumDecl struct { 338 | modifiers *JModifiers 339 | Name string 340 | Interfaces []*JTypeName 341 | Constants []*JEnumConstant 342 | BodyDecl []JObject 343 | } 344 | 345 | func NewJEnumDecl(modifiers *JModifiers, name string, interfaces []*JTypeName, 346 | body *JEnumBody) *JEnumDecl { 347 | if name == "" { 348 | ReportError("JEnumDecl name cannot be empty") 349 | } 350 | 351 | var constants []*JEnumConstant 352 | var bodydecl []JObject 353 | if body != nil { 354 | constants = body.constants 355 | bodydecl = body.bodydecl 356 | } 357 | 358 | return &JEnumDecl{modifiers: modifiers, Name: name, Interfaces: interfaces, 359 | Constants: constants, BodyDecl: bodydecl} 360 | } 361 | 362 | type JForColon struct { 363 | VarDecl *JVariableDecl 364 | Expr JObject 365 | Body JObject 366 | } 367 | 368 | func NewJForColon(modifiers *JModifiers, typespec *JReferenceType, 369 | name string, dims int, expr JObject) *JForColon { 370 | if typespec == nil { 371 | panic("JForColon type specifier cannot be nil") 372 | } else if name == "" { 373 | panic("JForColon variable name cannot be empty") 374 | } else if expr == nil { 375 | panic("JForColon expr cannot be nil") 376 | } 377 | 378 | vardecl := NewJVariableDecl(name, dims, nil) 379 | vardecl.SetModifiers(modifiers) 380 | vardecl.SetType(typespec) 381 | 382 | return &JForColon{VarDecl: vardecl, Expr: expr} 383 | } 384 | 385 | func (j *JForColon) SetBody(body JObject) { 386 | j.Body = body 387 | } 388 | 389 | type JForExpr struct { 390 | Init []JObject 391 | Expr JObject 392 | Incr []JObject 393 | Body JObject 394 | } 395 | 396 | func NewJForExpr(init []JObject, expr JObject, incr []JObject) *JForExpr { 397 | return &JForExpr{Init: init, Expr: expr, Incr: incr} 398 | } 399 | 400 | func (j *JForExpr) SetBody(body JObject) { 401 | j.Body = body 402 | } 403 | 404 | type JForVar struct { 405 | VarDecl *JVariableDecl 406 | Decl JObject 407 | Expr JObject 408 | Incr []JObject 409 | Body JObject 410 | } 411 | 412 | func NewJForVar(modifiers *JModifiers, typespec *JReferenceType, 413 | name string, dims int) *JForVar { 414 | if typespec == nil { 415 | panic("JForVar type specifier cannot be nil") 416 | } else if name == "" { 417 | panic("JForVar variable name cannot be empty") 418 | } 419 | 420 | vardecl := NewJVariableDecl(name, dims, nil) 421 | if modifiers != nil { 422 | vardecl.SetModifiers(modifiers) 423 | } 424 | vardecl.SetType(typespec) 425 | 426 | return &JForVar{VarDecl: vardecl} 427 | } 428 | 429 | func (j *JForVar) SetBody(body JObject) { 430 | j.Body = body 431 | } 432 | 433 | func (j *JForVar) SetDecl(decl JObject) { 434 | j.Decl = decl 435 | } 436 | 437 | func (j *JForVar) SetExpr(expr JObject) { 438 | j.Expr = expr 439 | } 440 | 441 | func (j *JForVar) SetIncr(incr []JObject) { 442 | j.Incr = incr 443 | } 444 | 445 | func (j *JForVar) SetInit(init *JVariableInit) { 446 | j.VarDecl.Init = init 447 | } 448 | 449 | type JFormalParameter struct { 450 | Modifiers *JModifiers 451 | TypeSpec *JReferenceType 452 | DotDotDot bool 453 | Name string 454 | Dims int 455 | } 456 | 457 | func NewJFormalParameter(typespec *JReferenceType, dotdotdot bool, 458 | name string, dims int) *JFormalParameter { 459 | if name == "" { 460 | panic("FormalParameter name cannot be empty") 461 | } 462 | 463 | return &JFormalParameter{TypeSpec: typespec, DotDotDot: dotdotdot, 464 | Name: name, Dims: dims} 465 | } 466 | 467 | func (j *JFormalParameter) SetModifiers(modifiers *JModifiers) { 468 | j.Modifiers = modifiers 469 | } 470 | 471 | type JIfElseStmt struct { 472 | Cond JObject 473 | IfBlock JObject 474 | ElseBlock JObject 475 | } 476 | 477 | func NewJIfElseStmt(cond JObject, ifblock JObject, elseblock JObject) *JIfElseStmt { 478 | if cond == nil { 479 | panic("'if' condition cannot be nil") 480 | } else if ifblock == nil { 481 | panic("'if' block cannot be nil") 482 | } 483 | 484 | return &JIfElseStmt{Cond: cond, IfBlock: ifblock, ElseBlock: elseblock} 485 | } 486 | 487 | type JImportStmt struct { 488 | Name *JTypeName 489 | is_wild bool 490 | is_static bool 491 | } 492 | 493 | func NewJImportStmt(name *JTypeName, is_wild bool, is_static bool) *JImportStmt { 494 | return &JImportStmt{Name: name, is_wild: is_wild, is_static: is_static} 495 | } 496 | 497 | type JInstanceOf struct { 498 | Obj JObject 499 | TypeSpec *JReferenceType 500 | } 501 | 502 | func NewJInstanceOf(obj JObject, typespec *JReferenceType) *JInstanceOf { 503 | if obj == nil { 504 | ReportError("Instanceof object cannot be nil") 505 | } else if typespec == nil { 506 | ReportError("TwoObjects type specifier cannot be nil") 507 | } 508 | 509 | return &JInstanceOf{Obj: obj, TypeSpec: typespec} 510 | } 511 | 512 | type JInterfaceDecl struct { 513 | modifiers *JModifiers 514 | Name *JTypeName 515 | type_params []JObject 516 | extends []*JTypeName 517 | Body []JObject 518 | } 519 | 520 | func NewJInterfaceDecl(modifiers *JModifiers, name *JTypeName, 521 | type_params []JObject, extends []*JTypeName, 522 | body []JObject) *JInterfaceDecl { 523 | if name == nil { 524 | ReportError("JInterfaceDecl name cannot be nil") 525 | } 526 | 527 | return &JInterfaceDecl{modifiers: modifiers, Name: name, 528 | type_params: type_params, extends: extends, Body: body} 529 | } 530 | 531 | type JInterfaceMethodDecl struct { 532 | modifiers *JModifiers 533 | type_params []JObject 534 | TypeSpec *JReferenceType 535 | Name string 536 | FormalParams []*JFormalParameter 537 | dims int 538 | throws []*JTypeName 539 | } 540 | 541 | func NewJInterfaceMethodDecl(formal_params []*JFormalParameter, dims int, 542 | throws []*JTypeName) *JInterfaceMethodDecl { 543 | return &JInterfaceMethodDecl{FormalParams: formal_params, dims: dims, 544 | throws: throws} 545 | } 546 | 547 | func (j *JInterfaceMethodDecl) SetModifiers(modifiers *JModifiers) { 548 | j.modifiers = modifiers 549 | } 550 | 551 | func (j *JInterfaceMethodDecl) SetName(name string) { 552 | if name == "" { 553 | panic("Interface name cannot be empty") 554 | } else if j.Name != "" { 555 | panic(fmt.Sprintf("Cannot overwrite interface name \"%s\" with \"%s\"", 556 | j.Name, name)) 557 | } 558 | 559 | j.Name = name 560 | } 561 | 562 | func (j *JInterfaceMethodDecl) SetType(typespec *JReferenceType) { 563 | j.TypeSpec = typespec 564 | } 565 | 566 | func (j *JInterfaceMethodDecl) SetTypeParameters(type_params []JObject) { 567 | j.type_params = type_params 568 | } 569 | 570 | type JJumpToLabel struct { 571 | IsContinue bool 572 | Label string 573 | } 574 | 575 | func NewJJumpToLabel(token int, label string) *JJumpToLabel { 576 | var is_continue bool 577 | if token == CONTINUE { 578 | is_continue = true 579 | } else if token != BREAK { 580 | panic(fmt.Sprintf("JJumpToLabel token #%d is not BREAK(#%d)" + 581 | " or CONTINUE(#%d)", token, BREAK, CONTINUE)) 582 | } 583 | 584 | return &JJumpToLabel{IsContinue: is_continue, Label: label} 585 | } 586 | 587 | type JKeyword struct { 588 | Token int 589 | Name string 590 | } 591 | 592 | func NewJKeyword(token int, name string) *JKeyword { 593 | if name == "" { 594 | ReportError("Keyword name cannot be empty") 595 | } 596 | 597 | return &JKeyword{Token: token, Name: name} 598 | } 599 | 600 | type JLabeledStatement struct { 601 | Label string 602 | Stmt JObject 603 | } 604 | 605 | func NewJLabeledStatement(label string, stmt JObject) *JLabeledStatement { 606 | if label == "" { 607 | ReportError("Label cannot be empty") 608 | } else if stmt == nil { 609 | ReportError("Label object cannot be nil") 610 | } 611 | 612 | return &JLabeledStatement{Label: label, Stmt: stmt} 613 | } 614 | 615 | type JLiteral struct { 616 | Text string 617 | } 618 | 619 | func NewJLiteral(text string) *JLiteral { 620 | if text == "" { 621 | ReportError("Literal text cannot be empty") 622 | } 623 | 624 | return &JLiteral{Text: text} 625 | } 626 | 627 | type JLocalVariableDecl struct { 628 | Modifiers *JModifiers 629 | TypeSpec *JReferenceType 630 | Vars []*JVariableDecl 631 | } 632 | 633 | func NewJLocalVariableDecl(modifiers *JModifiers, typespec *JReferenceType, 634 | vars []*JVariableDecl) *JLocalVariableDecl { 635 | return &JLocalVariableDecl{Modifiers: modifiers, TypeSpec: typespec, 636 | Vars: vars} 637 | } 638 | 639 | type JMethodAccess struct { 640 | NameObj JObject 641 | NameKey *JKeyword 642 | NameType *JTypeName 643 | Method string 644 | ArgList []JObject 645 | } 646 | 647 | func NewJMethodAccessComplex(obj JObject, name string, 648 | arglist []JObject) *JMethodAccess { 649 | if obj == nil { 650 | panic("Method object cannot be nil") 651 | } else if name == "" { 652 | panic("Method name cannot be empty") 653 | } 654 | 655 | return &JMethodAccess{NameObj: obj, Method: name, ArgList: arglist} 656 | } 657 | 658 | func NewJMethodAccessKeyword(token int, name string, arglist []JObject) *JMethodAccess { 659 | return &JMethodAccess{NameKey: NewJKeyword(token, name), ArgList: arglist} 660 | } 661 | 662 | func NewJMethodAccessName(nametyp *JTypeName, 663 | arglist []JObject) *JMethodAccess { 664 | if nametyp == nil { 665 | panic("Method name cannot be nil") 666 | } 667 | 668 | name := nametyp.LastType() 669 | if name == "" { 670 | panic("Method name cannot be empty") 671 | } 672 | 673 | var class *JTypeName 674 | if nametyp.IsDotted() { 675 | class = nametyp.NotLast() 676 | } 677 | 678 | return &JMethodAccess{NameType: class, Method: name, ArgList: arglist} 679 | } 680 | 681 | type JMethodDecl struct { 682 | Modifiers *JModifiers 683 | type_params []JObject 684 | TypeSpec *JReferenceType 685 | Name string 686 | FormalParams []*JFormalParameter 687 | dims int 688 | throws []*JTypeName 689 | Block *JBlock 690 | } 691 | 692 | func NewJMethodDecl(formal_params []*JFormalParameter, dims int, 693 | throws []*JTypeName, block *JBlock) *JMethodDecl { 694 | return &JMethodDecl{FormalParams: formal_params, dims: dims, 695 | throws: throws, Block: block} 696 | } 697 | 698 | func (j *JMethodDecl) SetModifiers(modifiers *JModifiers) { 699 | j.Modifiers = modifiers 700 | } 701 | 702 | func (j *JMethodDecl) SetName(name string) { 703 | if name == "" { 704 | panic("Method name cannot be empty") 705 | } 706 | 707 | j.Name = name 708 | } 709 | 710 | func (j *JMethodDecl) SetType(typespec *JReferenceType) { 711 | j.TypeSpec = typespec 712 | } 713 | 714 | func (j *JMethodDecl) SetTypeParameters(type_params []JObject) { 715 | j.type_params = type_params 716 | } 717 | 718 | const ( 719 | ModPublic = 0x1 720 | modProtected = 0x2 721 | ModPrivate = 0x4 722 | modAbstract = 0x8 723 | ModFinal = 0x10 724 | ModStatic = 0x20 725 | modTransient = 0x40 726 | modVolatile = 0x80 727 | modNative = 0x100 728 | modSynchronized = 0x200 729 | modMax = modSynchronized 730 | ) 731 | 732 | type JModifiers struct { 733 | annotations []*JAnnotation 734 | mod_bits int 735 | } 736 | 737 | func NewJModifiers(name string, annotation *JAnnotation) *JModifiers { 738 | j := &JModifiers{} 739 | if name != "" { 740 | j.AddModifier(name) 741 | } else if annotation != nil { 742 | j.AddAnnotation(annotation) 743 | } 744 | return j 745 | } 746 | 747 | func (j *JModifiers) AddAnnotation(annotation *JAnnotation) *JModifiers { 748 | if j.annotations == nil { 749 | j.annotations = make([]*JAnnotation, 1) 750 | j.annotations[0] = annotation 751 | } else { 752 | j.annotations = append(j.annotations, annotation) 753 | } 754 | return j 755 | } 756 | 757 | func (j *JModifiers) AddModifier(name string) *JModifiers { 758 | switch name { 759 | case "public": j.mod_bits |= ModPublic 760 | case "protected": j.mod_bits |= modProtected 761 | case "private": j.mod_bits |= ModPrivate 762 | case "abstract": j.mod_bits |= modAbstract 763 | case "final": j.mod_bits |= ModFinal 764 | case "static": j.mod_bits |= ModStatic 765 | case "transient": j.mod_bits |= modTransient 766 | case "volatile": j.mod_bits |= modVolatile 767 | case "native": j.mod_bits |= modNative 768 | case "synchronized": j.mod_bits |= modSynchronized 769 | default: ReportError(fmt.Sprintf("Unknown modifier \"%s\"", name)) 770 | } 771 | 772 | return j 773 | } 774 | 775 | func (j *JModifiers) HasAnnotation(name string) bool { 776 | if j.annotations != nil && len(j.annotations) > 0 { 777 | for _, ann := range j.annotations { 778 | if ann.name.String() == name { 779 | return true 780 | } 781 | } 782 | } 783 | 784 | return false 785 | } 786 | 787 | func (j *JModifiers) IsSet(modbit int) bool { 788 | return (j.mod_bits & modbit) == modbit 789 | } 790 | 791 | func (j *JModifiers) String() string { 792 | b := &bytes.Buffer{} 793 | j.writeModifiers(b) 794 | return b.String() 795 | } 796 | 797 | func (j *JModifiers) writeModifiers(out io.Writer) { 798 | for m := 0x1; m <= modMax; m <<= 1 { 799 | if j.mod_bits & m == m { 800 | switch m { 801 | case ModPublic: io.WriteString(out, "public ") 802 | case modProtected: io.WriteString(out, "protected ") 803 | case ModPrivate: io.WriteString(out, "private ") 804 | case modAbstract: io.WriteString(out, "abstract ") 805 | case ModFinal: io.WriteString(out, "final ") 806 | case ModStatic: io.WriteString(out, "static ") 807 | case modTransient: io.WriteString(out, "transient ") 808 | case modVolatile: io.WriteString(out, "volatile ") 809 | case modNative: io.WriteString(out, "native ") 810 | case modSynchronized: io.WriteString(out, "synchronized ") 811 | } 812 | } 813 | } 814 | } 815 | 816 | type JNameDotObject struct { 817 | Name *JTypeName 818 | Obj JObject 819 | } 820 | 821 | func NewJNameDotObject(name *JTypeName, obj JObject) *JNameDotObject { 822 | if name == nil { 823 | ReportError("NameDotObject name cannot be nil") 824 | } else if obj == nil { 825 | ReportError("NameDotObject object cannot be nil") 826 | } 827 | 828 | return &JNameDotObject{Name: name, Obj: obj} 829 | } 830 | 831 | type JObjectDotName struct { 832 | Obj JObject 833 | Name *JTypeName 834 | } 835 | 836 | func NewJObjectDotName(obj JObject, name *JTypeName) *JObjectDotName { 837 | if obj == nil { 838 | ReportError("ObjectDotName object cannot be nil") 839 | } else if name == nil { 840 | ReportError("ObjectDotName name cannot be nil") 841 | } 842 | 843 | return &JObjectDotName{Obj: obj, Name: name} 844 | } 845 | 846 | type JPackageStmt struct { 847 | Name *JTypeName 848 | } 849 | 850 | func NewJPackageStmt(name *JTypeName) *JPackageStmt { 851 | return &JPackageStmt{Name: name} 852 | } 853 | 854 | type JParens struct { 855 | Expr JObject 856 | } 857 | 858 | func NewJParens(expr JObject) *JParens { 859 | if expr == nil { 860 | ReportError("JParens expression cannot be nil") 861 | } 862 | 863 | return &JParens{Expr: expr} 864 | } 865 | 866 | type JProgramFile struct { 867 | Pkg *JPackageStmt 868 | Imports []JObject 869 | TypeDecls []JObject 870 | } 871 | 872 | func NewJProgramFile(pobj JObject, imports []JObject, 873 | type_decls []JObject) *JProgramFile { 874 | j := &JProgramFile{} 875 | 876 | if pobj != nil { 877 | if pkg, ok := pobj.(*JPackageStmt); !ok { 878 | ReportCastError("JPackageStmt", pobj) 879 | } else { 880 | j.Pkg = pkg 881 | } 882 | } 883 | 884 | j.Imports = imports 885 | j.TypeDecls = type_decls 886 | 887 | return j 888 | } 889 | 890 | type JReferenceType struct { 891 | Name *JTypeName 892 | TypeArgs []*JTypeArgument 893 | Dims int 894 | } 895 | 896 | func NewJReferenceType(name *JTypeName, obj_args []JObject, 897 | dims int) *JReferenceType { 898 | if name == nil { 899 | ReportError("ReferenceType name cannot be nil") 900 | } 901 | 902 | var type_args []*JTypeArgument 903 | if obj_args != nil && len(obj_args) > 0 { 904 | type_args = make([]*JTypeArgument, len(obj_args)) 905 | for i, o := range obj_args { 906 | if arg, ok := o.(*JTypeArgument); ok { 907 | type_args[i] = arg 908 | } else { 909 | ReportCastError("JTypeArgument", o) 910 | } 911 | } 912 | } 913 | 914 | return &JReferenceType{Name: name, TypeArgs: type_args, Dims: dims} 915 | } 916 | 917 | type JSimpleStatement struct { 918 | Keyword *JKeyword 919 | Object JObject 920 | } 921 | 922 | func NewJSimpleStatement(keyword *JKeyword, object JObject) *JSimpleStatement { 923 | return &JSimpleStatement{Keyword: keyword, Object: object} 924 | } 925 | 926 | type JSwitch struct { 927 | Expr JObject 928 | Groups []*JSwitchGroup 929 | } 930 | 931 | func NewJSwitch(expr JObject, grouplist []JObject) *JSwitch { 932 | if expr == nil { 933 | panic("No expression for JSwitch") 934 | } 935 | 936 | var groups []*JSwitchGroup 937 | if grouplist != nil && len(grouplist) > 0 { 938 | groups = make([]*JSwitchGroup, len(grouplist)) 939 | for i, o := range grouplist { 940 | if grp, ok := o.(*JSwitchGroup); !ok { 941 | ReportCastError("JSwitch", o) 942 | } else { 943 | groups[i] = grp 944 | } 945 | } 946 | } 947 | 948 | return &JSwitch{Expr: expr, Groups: groups} 949 | } 950 | 951 | type JSwitchGroup struct { 952 | Labels []*JSwitchLabel 953 | Stmts []JObject 954 | } 955 | 956 | func NewJSwitchGroup(labellist []JObject, stmtlist []JObject) *JSwitchGroup { 957 | if labellist == nil || len(labellist) == 0 { 958 | panic("No labels on JSwitchGroup") 959 | } 960 | 961 | var labels []*JSwitchLabel 962 | if labellist != nil && len(labellist) > 0 { 963 | labels = make([]*JSwitchLabel, len(labellist)) 964 | for i, o := range labellist { 965 | if lbl, ok := o.(*JSwitchLabel); !ok { 966 | ReportCastError("JSwitchLabel", o) 967 | } else { 968 | labels[i] = lbl 969 | } 970 | } 971 | } 972 | 973 | return &JSwitchGroup{Labels: labels, Stmts: stmtlist} 974 | } 975 | 976 | type JSwitchLabel struct { 977 | Name string 978 | Expr JObject 979 | IsDefault bool 980 | } 981 | 982 | func NewJSwitchLabel(name string, expr JObject, is_default bool) *JSwitchLabel { 983 | if !is_default { 984 | if name == "" && expr == nil { 985 | panic("Must set something for JSwitchLabel") 986 | } else if name != "" && expr != nil { 987 | panic("Cannot set both name and expr for JSwitchLabel") 988 | } 989 | } else if name != "" || expr != nil { 990 | panic("Cannot set name or expr for 'default' JSwitchLabel") 991 | } 992 | 993 | return &JSwitchLabel{Name: name, Expr: expr, IsDefault: is_default} 994 | } 995 | 996 | type JSynchronized struct { 997 | Expr JObject 998 | Block *JBlock 999 | } 1000 | 1001 | func NewJSynchronized(expr JObject, block *JBlock) *JSynchronized { 1002 | if block == nil { 1003 | ReportError("JSynchronized block cannot be nil") 1004 | } 1005 | 1006 | return &JSynchronized{Expr: expr, Block: block} 1007 | } 1008 | 1009 | type JTry struct { 1010 | Block *JBlock 1011 | Catches []*JCatch 1012 | Finally *JBlock 1013 | } 1014 | 1015 | func NewJTry(block *JBlock, clist []JObject, finally *JBlock) *JTry { 1016 | if block == nil { 1017 | ReportError("JTry block cannot be nil") 1018 | } 1019 | 1020 | var catches []*JCatch 1021 | if clist != nil && len(clist) > 0 { 1022 | catches = make([]*JCatch, len(clist)) 1023 | for i, c := range clist { 1024 | if catch, ok := c.(*JCatch); !ok { 1025 | ReportCastError(fmt.Sprintf("JCatch#%d", i), c) 1026 | } else { 1027 | catches[i] = catch 1028 | } 1029 | } 1030 | } 1031 | 1032 | return &JTry{Block: block, Catches: catches, Finally: finally} 1033 | } 1034 | 1035 | const ( 1036 | TS_NONE = iota 1037 | TS_EXTENDS 1038 | TS_SUPER 1039 | TS_PLAIN 1040 | ) 1041 | 1042 | type JTypeArgument struct { 1043 | TypeSpec *JReferenceType 1044 | Ts_type int 1045 | } 1046 | 1047 | func NewJTypeArgument(typespec *JReferenceType, ts_type int) *JTypeArgument { 1048 | return &JTypeArgument{TypeSpec: typespec, Ts_type: ts_type} 1049 | } 1050 | 1051 | type JTypeName struct { 1052 | is_primitive bool 1053 | names []string 1054 | } 1055 | 1056 | func NewJTypeName(name string, is_primitive bool) *JTypeName { 1057 | if name == "" { 1058 | panic("Cannot build type name from empty string") 1059 | } 1060 | 1061 | names := make([]string, 1) 1062 | names[0] = name 1063 | 1064 | return &JTypeName{names: names, is_primitive: is_primitive} 1065 | } 1066 | 1067 | func (qn *JTypeName) Add(name string) { 1068 | if qn.is_primitive { 1069 | panic(fmt.Sprintf("Cannot add \"%s\" to primitive type \"%s\"", 1070 | name, qn.names[0])) 1071 | } else if name == "" { 1072 | panic(fmt.Sprintf("Cannot add empty string to \"%s\"", qn.String())) 1073 | } 1074 | 1075 | qn.names = append(qn.names, name) 1076 | } 1077 | 1078 | func (qn *JTypeName) FirstType() string { 1079 | return qn.names[0] 1080 | } 1081 | 1082 | func (qn *JTypeName) IsDotted() bool { 1083 | return !qn.is_primitive && len(qn.names) > 1 1084 | } 1085 | 1086 | func (qn *JTypeName) IsPrimitive() bool { 1087 | return qn.is_primitive 1088 | } 1089 | 1090 | func (qn *JTypeName) LastType() string { 1091 | return qn.names[len(qn.names)-1] 1092 | } 1093 | 1094 | func (qn *JTypeName) NotFirst() *JTypeName { 1095 | if len(qn.names) == 1 { 1096 | panic(fmt.Sprintf("Only one name found in %v", qn)) 1097 | } else if qn.is_primitive { 1098 | panic(fmt.Sprintf("Primitive type %v has only one name", qn)) 1099 | } 1100 | 1101 | return &JTypeName{names: qn.names[1:], is_primitive: false} 1102 | } 1103 | 1104 | func (qn *JTypeName) NotLast() *JTypeName { 1105 | if len(qn.names) == 1 { 1106 | panic(fmt.Sprintf("Only one name found in %v", qn)) 1107 | } else if qn.is_primitive { 1108 | panic(fmt.Sprintf("Primitive type %v has only one name", qn)) 1109 | } 1110 | 1111 | return &JTypeName{names: qn.names[0:len(qn.names)-1], is_primitive: false} 1112 | } 1113 | 1114 | func (qn *JTypeName) PackageString() string { 1115 | if len(qn.names) == 1 { 1116 | return qn.names[0] 1117 | } else if qn.is_primitive { 1118 | panic(fmt.Sprintf("Primitive type %v is not a package", qn)) 1119 | } 1120 | 1121 | return strings.Join(qn.names[:len(qn.names)-1], ".") 1122 | } 1123 | 1124 | func (qn *JTypeName) String() string { 1125 | if len(qn.names) == 1 { 1126 | return qn.names[0] 1127 | } 1128 | 1129 | return strings.Join(qn.names, ".") 1130 | } 1131 | 1132 | type JTypeParameter struct { 1133 | name string 1134 | bounds []JObject 1135 | } 1136 | 1137 | func NewJTypeParameter(name string, bounds []JObject) *JTypeParameter { 1138 | return &JTypeParameter{name: name, bounds: bounds} 1139 | } 1140 | 1141 | type JUnaryExpr struct { 1142 | Op string 1143 | Obj JObject 1144 | is_prefix bool 1145 | } 1146 | 1147 | func NewJUnaryExpr(op string, obj JObject, is_prefix bool) *JUnaryExpr { 1148 | if op == "" { 1149 | ReportError("UnaryExpr op cannot be empty") 1150 | } else if obj == nil { 1151 | ReportError("UnaryExpr object cannot be nil") 1152 | } 1153 | 1154 | return &JUnaryExpr{Op: op, Obj: obj, is_prefix: is_prefix} 1155 | } 1156 | 1157 | type JVariableDecl struct { 1158 | Modifiers *JModifiers 1159 | TypeSpec *JReferenceType 1160 | Name string 1161 | Dims int 1162 | Init *JVariableInit 1163 | } 1164 | 1165 | func NewJVariableDecl(name string, dims int, 1166 | init *JVariableInit) *JVariableDecl { 1167 | return &JVariableDecl{Name: name, Dims: dims, Init: init} 1168 | } 1169 | 1170 | func (j *JVariableDecl) SetInit(init *JVariableInit) { 1171 | j.Init = init 1172 | } 1173 | 1174 | func (j *JVariableDecl) SetModifiers(modifiers *JModifiers) { 1175 | j.Modifiers = modifiers 1176 | } 1177 | 1178 | func (j *JVariableDecl) SetType(typespec *JReferenceType) { 1179 | j.TypeSpec = typespec 1180 | } 1181 | 1182 | type JVariableInit struct { 1183 | Expr JObject 1184 | ArrayList []*JVariableInit 1185 | } 1186 | 1187 | func NewJVariableInit(expr JObject, arraylist []*JVariableInit) *JVariableInit { 1188 | if expr == nil && arraylist == nil { 1189 | panic("Either arraylist or expr must be non-nil") 1190 | } else if expr != nil && arraylist != nil && len(arraylist) > 0 { 1191 | panic("Cannot set both arraylist and expr") 1192 | } 1193 | 1194 | return &JVariableInit{Expr: expr, ArrayList: arraylist} 1195 | } 1196 | 1197 | type JWhile struct { 1198 | Expr JObject 1199 | Stmt JObject 1200 | IsDoWhile bool 1201 | } 1202 | 1203 | func NewJWhile(expr JObject, stmt JObject, is_do_while bool) *JWhile { 1204 | return &JWhile{Expr: expr, Stmt: stmt, IsDoWhile: is_do_while} 1205 | } 1206 | -------------------------------------------------------------------------------- /parser/analysis.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "go/token" 6 | "log" 7 | 8 | //"os" 9 | 10 | "java2go/grammar" 11 | ) 12 | 13 | func findMethod(owner GoMethodOwner, class GoMethodOwner, name string, 14 | arglist *GoMethodArguments, verbose bool) GoMethod { 15 | var mthd GoMethod 16 | if class != nil && !class.IsNil() { 17 | mthd = class.FindMethod(name, arglist) 18 | } 19 | 20 | if mthd == nil && owner != nil && !owner.IsNil() { 21 | mthd = owner.FindMethod(name, arglist) 22 | } 23 | 24 | if mthd == nil { 25 | mthd = NewGoMethodReference(class, name, arglist, verbose) 26 | if owner != nil && !owner.IsNil() { 27 | owner.AddMethod(mthd) 28 | } else if class != nil && !class.IsNil() { 29 | class.AddMethod(mthd) 30 | } else { 31 | panic("Both class and owner are nil") 32 | } 33 | } 34 | 35 | return mthd 36 | } 37 | 38 | func analyzeAllocationExpr(gs *GoState, owner GoMethodOwner, 39 | alloc *grammar.JClassAllocationExpr) *GoClassAlloc { 40 | if alloc.Name.IsPrimitive() { 41 | panic(fmt.Sprintf("Class allocation should not use primitive \"%s\"", 42 | alloc.Name.String())) 43 | } 44 | 45 | var type_args []*TypeData 46 | if alloc.TypeArgs != nil && len(alloc.TypeArgs) > 0 { 47 | type_args = make([]*TypeData, len(alloc.TypeArgs)) 48 | for i, arg := range alloc.TypeArgs { 49 | if arg.Ts_type != grammar.TS_NONE { 50 | log.Printf("//ERR// Ignoring allexpr ts#%d type %v\n", 51 | i, arg.Ts_type) 52 | } 53 | 54 | if arg.TypeSpec == nil { 55 | type_args[i] = genericObject 56 | } else { 57 | type_args[i] = gs.Program().createTypeData(arg.TypeSpec.Name, 58 | arg.TypeSpec.TypeArgs, 0) 59 | } 60 | } 61 | } 62 | 63 | var args []GoExpr 64 | if alloc.Arglist != nil && len(alloc.Arglist) > 0 { 65 | args = make([]GoExpr, len(alloc.Arglist)) 66 | for i, arg := range alloc.Arglist { 67 | args[i] = analyzeExpr(gs, owner, arg) 68 | } 69 | } 70 | 71 | alloc_name := alloc.Name.String() 72 | 73 | var cref GoClass 74 | 75 | var body []GoStatement 76 | for _, b := range alloc.Body { 77 | switch j := b.(type) { 78 | case *grammar.JClassBody: 79 | gs2 := NewGoState(gs) 80 | 81 | c2 := NewGoClassDefinition(gs.Program(), owner, alloc_name) 82 | analyzeClassBody(gs2, c2, j) 83 | 84 | var anon_name string 85 | for i := 0; ; i++ { 86 | anon_name = fmt.Sprintf("Anonymous_%s_%d", alloc_name, i) 87 | if gs.findClass(owner, anon_name) == nil { 88 | break 89 | } 90 | } 91 | c2.name = anon_name 92 | 93 | gs.addClass(c2) 94 | cref = c2 95 | case *grammar.JBlock: 96 | stmt := analyzeBlock(gs, owner, j) 97 | if stmt != nil { 98 | body = append(body, stmt) 99 | } 100 | case *grammar.JEmpty: 101 | // do nothing 102 | default: 103 | grammar.ReportCastError("JClassAllocationExpr.body", b) 104 | } 105 | } 106 | 107 | if cref == nil { 108 | cref = gs.findClass(owner, alloc_name) 109 | if cref == nil { 110 | cref = &GoClassReference{name: alloc_name, parent: owner} 111 | gs.addClass(cref) 112 | } 113 | } 114 | 115 | if type_args != nil && len(type_args) > 0 { 116 | if gs.Program().verbose { 117 | log.Printf("//ERR// Not handling %v type_args\n", alloc_name) 118 | } else { 119 | log.Printf("//ERR// Not handling clsalloc type_args\n") 120 | } 121 | 122 | type_args = nil 123 | } 124 | 125 | if body != nil && len(body) > 0 { 126 | if gs.Program().verbose { 127 | log.Printf( 128 | "//ERR// Ignoring %v class alloc body (%d stmts)\n", 129 | cref.Name(), len(body)) 130 | } else { 131 | log.Printf("//ERR// Not handling clsalloc body\n") 132 | } 133 | } 134 | 135 | arglist := &GoMethodArguments{args} 136 | mthd := findMethod(owner, cref, "New"+cref.Name(), arglist, 137 | gs.Program().verbose) 138 | 139 | return &GoClassAlloc{class: cref, method: mthd, type_args: type_args, 140 | args: args, body: body} 141 | } 142 | 143 | func analyzeArrayAlloc(gs *GoState, owner GoMethodOwner, aa *grammar.JArrayAlloc, 144 | govar GoVar) GoArrayExpr { 145 | td := gs.Program().createTypeData(aa.Typename, nil, aa.Dims) 146 | 147 | if aa.Dimexprs != nil && len(aa.Dimexprs) > 0 && aa.Init != nil && 148 | len(aa.Init) > 0 { 149 | panic(fmt.Sprintf("JArrayAlloc has both dimexprs#%d and init#%d", 150 | len(aa.Dimexprs), len(aa.Init))) 151 | } 152 | 153 | if aa.Dimexprs != nil && len(aa.Dimexprs) > 0 { 154 | args := make([]GoExpr, len(aa.Dimexprs)) 155 | for i, arg := range aa.Dimexprs { 156 | args[i] = analyzeExpr(gs, owner, arg) 157 | } 158 | 159 | return &GoArrayAlloc{typedata: td, args: args} 160 | } 161 | 162 | var elements []GoExpr 163 | if aa.Init != nil && len(aa.Init) > 0 { 164 | elements = make([]GoExpr, len(aa.Init)) 165 | for i, elem := range aa.Init { 166 | elements[i] = analyzeVariableInit(gs, owner, elem, govar) 167 | } 168 | } 169 | 170 | return &GoArrayInit{typedata: td, elems: elements} 171 | } 172 | 173 | func analyzeAssignExpr(gs *GoState, owner GoMethodOwner, 174 | expr *grammar.JAssignmentExpr) *GoAssign { 175 | var op token.Token 176 | switch expr.Op { 177 | case "=": 178 | op = token.ASSIGN 179 | case "+=": 180 | op = token.ADD_ASSIGN 181 | case "-=": 182 | op = token.SUB_ASSIGN 183 | case "*=": 184 | op = token.MUL_ASSIGN 185 | case "/=": 186 | op = token.QUO_ASSIGN 187 | case "%=": 188 | op = token.REM_ASSIGN 189 | case "&=": 190 | op = token.AND_ASSIGN 191 | case "|=": 192 | op = token.OR_ASSIGN 193 | case "^=": 194 | op = token.XOR_ASSIGN 195 | case "<<=": 196 | op = token.SHL_ASSIGN 197 | case ">>=": 198 | op = token.SHR_ASSIGN 199 | case "&^=": 200 | op = token.AND_NOT_ASSIGN 201 | default: 202 | panic(fmt.Sprintf("Unknown assignment operator '%s'", expr.Op)) 203 | } 204 | 205 | var lhs GoVar 206 | switch v := expr.Left.(type) { 207 | case *grammar.JArrayReference: 208 | lhs = analyzeArrayReference(gs, owner, v) 209 | case *grammar.JConditionalExpr: 210 | log.Printf("//ERR// Faking asgnexpr lhs condexpr\n") 211 | lhs = NewFakeVar("<>", nil, 0) 212 | case *grammar.JNameDotObject: 213 | log.Printf("//ERR// Faking asgnexpr lhs NDO\n") 214 | lhs = NewFakeVar(v.Name.String(), nil, 0) 215 | case *grammar.JObjectDotName: 216 | lhs = analyzeObjectDotName(gs, owner, v) 217 | case *grammar.JReferenceType: 218 | lhs = analyzeReferenceType(gs, v) 219 | default: 220 | panic(fmt.Sprintf("//ERR// Unknown asgnexpr LHS %T\n", expr.Left)) 221 | } 222 | 223 | rhs := make([]GoExpr, 1) 224 | rhs[0] = analyzeExpr(gs, owner, expr.Right) 225 | 226 | return &GoAssign{govar: lhs, tok: op, rhs: rhs} 227 | } 228 | 229 | func analyzeBinaryExpr(gs *GoState, owner GoMethodOwner, 230 | bexpr *grammar.JBinaryExpr) *GoBinaryExpr { 231 | var op token.Token 232 | switch bexpr.Op { 233 | case "+": 234 | op = token.ADD 235 | case "-": 236 | op = token.SUB 237 | case "*": 238 | op = token.MUL 239 | case "/": 240 | op = token.QUO 241 | case "%": 242 | op = token.REM 243 | case "&": 244 | op = token.AND 245 | case "|": 246 | op = token.OR 247 | case "^": 248 | op = token.XOR 249 | case "<<": 250 | op = token.SHL 251 | case ">>": 252 | op = token.SHR 253 | case "&&": 254 | op = token.LAND 255 | case "||": 256 | op = token.LOR 257 | case "==": 258 | op = token.EQL 259 | case "!=": 260 | op = token.NEQ 261 | case "<": 262 | op = token.LSS 263 | case ">": 264 | op = token.GTR 265 | case "<=": 266 | op = token.LEQ 267 | case ">=": 268 | op = token.GEQ 269 | case ">>>": 270 | op = token.SHR 271 | default: 272 | panic(fmt.Sprintf("Unknown binary operator \"%s\"", bexpr.Op)) 273 | } 274 | 275 | return &GoBinaryExpr{x: analyzeExpr(gs, owner, bexpr.Obj1), op: op, 276 | y: analyzeExpr(gs, owner, bexpr.Obj2)} 277 | } 278 | 279 | func analyzeBlock(gs *GoState, owner GoMethodOwner, blk *grammar.JBlock) *GoBlock { 280 | stmts := make([]GoStatement, 0) 281 | 282 | gs2 := NewGoState(gs) 283 | 284 | for _, bobj := range blk.List { 285 | switch b := bobj.(type) { 286 | case *grammar.JBlock: 287 | blk := analyzeBlock(gs2, owner, b) 288 | if blk != nil { 289 | stmts = append(stmts, blk) 290 | } 291 | case *grammar.JClassDecl: 292 | gs2.addClassDecl(owner, b) 293 | case *grammar.JEnumDecl: 294 | gs2.Program().addEnum(b) 295 | case *grammar.JEmpty: 296 | continue 297 | case *grammar.JForColon: 298 | stmt := analyzeForColon(gs2, owner, b) 299 | if stmt != nil { 300 | stmts = append(stmts, stmt) 301 | } 302 | case *grammar.JForExpr: 303 | stmt := analyzeForExpr(gs2, owner, b) 304 | if stmt != nil { 305 | stmts = append(stmts, stmt) 306 | } 307 | case *grammar.JForVar: 308 | stmt := analyzeForVar(gs2, owner, b) 309 | if stmt != nil { 310 | stmts = append(stmts, stmt) 311 | } 312 | case *grammar.JIfElseStmt: 313 | stmt := analyzeIfElseStmt(gs2, owner, b) 314 | if stmt != nil { 315 | stmts = append(stmts, stmt) 316 | } 317 | case *grammar.JJumpToLabel: 318 | if b != nil { 319 | stmts = append(stmts, NewGoJumpToLabel(b.Label, b.IsContinue)) 320 | } 321 | case *grammar.JLabeledStatement: 322 | stmt := analyzeLabelledStmt(gs2, owner, b) 323 | if stmt != nil { 324 | stmts = append(stmts, stmt) 325 | } 326 | case *grammar.JLocalVariableDecl: 327 | lvlist := analyzeLocalVariableDeclaration(gs2, owner, b) 328 | if lvlist != nil && len(lvlist) > 0 { 329 | stmts = append(stmts, lvlist...) 330 | } 331 | case *grammar.JMethodDecl: 332 | if cls, ok := owner.(*GoClassDefinition); ok { 333 | cls.AddNewMethod(gs2, b) 334 | } else { 335 | log.Printf("//ERR// Cannot add new method to %T\n", owner) 336 | } 337 | case *grammar.JSimpleStatement: 338 | ss := analyzeSimpleStatement(gs2, owner, b) 339 | if ss != nil { 340 | stmts = append(stmts, ss) 341 | } 342 | case *grammar.JSynchronized: 343 | ss := analyzeSynchronized(gs2, owner, b) 344 | if ss != nil { 345 | stmts = append(stmts, ss) 346 | } 347 | case *grammar.JSwitch: 348 | swtch := analyzeSwitch(gs2, owner, b) 349 | if swtch != nil { 350 | stmts = append(stmts, swtch) 351 | } 352 | case *grammar.JTry: 353 | try := analyzeTry(gs2, owner, b) 354 | if try != nil { 355 | stmts = append(stmts, try) 356 | } 357 | case *grammar.JUnimplemented: 358 | log.Printf("//ERR// Ignoring unimplemented block %s\n", b.TypeStr) 359 | case *grammar.JWhile: 360 | while := analyzeWhile(gs2, owner, b) 361 | if while != nil { 362 | stmts = append(stmts, while) 363 | } 364 | case nil: 365 | log.Printf("//ERR// Ignoring nil block entry\n") 366 | default: 367 | grammar.ReportCastError("Block", bobj) 368 | } 369 | } 370 | 371 | return &GoBlock{stmts: stmts} 372 | } 373 | 374 | func analyzeBranchStmt(gs *GoState, owner GoMethodOwner, tok token.Token, 375 | obj grammar.JObject) *GoBranchStmt { 376 | var lexpr GoExpr 377 | if obj != nil { 378 | lexpr = analyzeExpr(gs, owner, obj) 379 | } 380 | 381 | var label string 382 | if lexpr != nil { 383 | if gs.Program().verbose { 384 | log.Printf("//ERR// cannot convert %s label %v<%T>\n", tok, 385 | lexpr, lexpr) 386 | } else { 387 | log.Printf("//ERR// cannot convert branch label %T\n", lexpr) 388 | } 389 | } 390 | 391 | return &GoBranchStmt{tok: tok, label: label} 392 | } 393 | 394 | func analyzeCastExpr(gs *GoState, owner GoMethodOwner, 395 | cex *grammar.JCastExpr) *GoCastType { 396 | td := gs.Program().createTypeData(cex.Reftype.Name, 397 | cex.Reftype.TypeArgs, cex.Reftype.Dims) 398 | return &GoCastType{target: analyzeExpr(gs, owner, cex.Target), casttype: td} 399 | } 400 | 401 | func analyzeClassBody(gs *GoState, cls *GoClassDefinition, body *grammar.JClassBody) { 402 | for _, bobj := range body.List { 403 | switch b := bobj.(type) { 404 | case *grammar.JClassDecl: 405 | gs.addClassDecl(cls, b) 406 | case *grammar.JEnumDecl: 407 | gs.Program().addEnum(b) 408 | case *grammar.JInterfaceDecl: 409 | log.Printf("//ERR// Ignoring class body %T\n", b) 410 | /* 411 | idecl := analyzeInterfaceDeclaration(gs, b) 412 | if idecl != nil { 413 | decls = append(decls, idecl) 414 | } 415 | */ 416 | case *grammar.JMethodDecl: 417 | cls.AddNewMethod(gs, b) 418 | case *grammar.JUnimplemented: 419 | log.Printf("//ERR// Ignoring unimplemented body %s\n", b.TypeStr) 420 | case *grammar.JVariableDecl: 421 | govar := gs.addVariableDecl(b, true) 422 | 423 | if b.Init == nil { 424 | cls.addVar(&GoVarInit{govar: govar}) 425 | } else { 426 | cls.addVar(analyzeVariableInit(gs, cls, b.Init, govar)) 427 | } 428 | default: 429 | grammar.ReportCastError("Body.ClassDecl", bobj) 430 | } 431 | } 432 | } 433 | 434 | func analyzeConstant(gs *GoState, owner GoMethodOwner, jcon *grammar.JConstantDecl) { 435 | ctype := gs.Program().createTypeData(jcon.TypeSpec.Name, 436 | jcon.TypeSpec.TypeArgs, jcon.Dims) 437 | init := analyzeVariableInit(gs, owner, jcon.Init, nil) 438 | owner.AddConstant(&GoConstant{name: jcon.Name, typedata: ctype, init: init}) 439 | } 440 | 441 | func analyzeExpr(gs *GoState, owner GoMethodOwner, obj grammar.JObject) GoExpr { 442 | switch e := obj.(type) { 443 | case *grammar.JArrayAlloc: 444 | return analyzeArrayAlloc(gs, owner, e, nil) 445 | case *grammar.JAssignmentExpr: 446 | return analyzeAssignExpr(gs, owner, e) 447 | case *grammar.JBinaryExpr: 448 | return analyzeBinaryExpr(gs, owner, e) 449 | case *grammar.JCastExpr: 450 | return analyzeCastExpr(gs, owner, e) 451 | case *grammar.JClassAllocationExpr: 452 | return analyzeAllocationExpr(gs, owner, e) 453 | case *grammar.JConditionalExpr: 454 | if gs.Program().verbose { 455 | log.Printf("//ERR// Not converting condexpr %T (%T|?|%T|:|%T) to Expr\n", 456 | e, e.CondExpr, e.IfExpr, e.ElseExpr) 457 | } else { 458 | log.Printf("//ERR// Not converting condexpr to Expr\n") 459 | } 460 | return &GoUnimplemented{fname: "expr", text: fmt.Sprintf("%T", e)} 461 | case *grammar.JInstanceOf: 462 | return &GoInstanceOf{expr: analyzeExpr(gs, owner, e.Obj), 463 | vartype: analyzeReferenceType(gs, e.TypeSpec)} 464 | case *grammar.JKeyword: 465 | return NewGoKeyword(e.Token, e.Name) 466 | case *grammar.JLiteral: 467 | return NewGoLiteral(e.Text) 468 | case *grammar.JMethodAccess: 469 | return analyzeMethodAccess(gs, owner, e) 470 | case *grammar.JNameDotObject: 471 | return analyzeNameDotObject(gs, e) 472 | case *grammar.JArrayReference: 473 | return analyzeArrayReference(gs, owner, e) 474 | case *grammar.JObjectDotName: 475 | return analyzeObjectDotName(gs, owner, e) 476 | case *grammar.JParens: 477 | return analyzeExpr(gs, owner, e.Expr) 478 | case *GoPrimitiveType: 479 | return e 480 | case *grammar.JReferenceType: 481 | return analyzeReferenceType(gs, e) 482 | case *grammar.JUnaryExpr: 483 | return analyzeUnaryExpr(gs, owner, e) 484 | case *grammar.JUnimplemented: 485 | log.Printf("//ERR// Not analyzing unimplemented expr %s\n", e.TypeStr) 486 | return &GoUnimplemented{fname: "expr", 487 | text: fmt.Sprintf("%s", e.TypeStr)} 488 | case *grammar.JVariableInit: 489 | return analyzeVariableInit(gs, owner, e, nil) 490 | } 491 | 492 | panic(fmt.Sprintf("Unknown expression type %T", obj)) 493 | } 494 | 495 | func analyzeForColon(gs *GoState, owner GoMethodOwner, 496 | jfc *grammar.JForColon) *GoForColon { 497 | gs2 := NewGoState(gs) 498 | 499 | govar := gs2.addVariableDecl(jfc.VarDecl, false) 500 | if govar == nil { 501 | panic("ForColon addVariable returned nil") 502 | } 503 | 504 | var expr GoExpr 505 | if jfc.Expr != nil { 506 | expr = analyzeExpr(gs2, owner, jfc.Expr) 507 | } 508 | 509 | var body *GoBlock 510 | if jfc.Body != nil { 511 | body = makeBlock(gs2, owner, jfc.Body) 512 | } 513 | 514 | if body == nil { 515 | log.Printf("//ERR// adding empty forcolon body\n") 516 | list := make([]GoStatement, 0) 517 | body = &GoBlock{stmts: list} 518 | } 519 | 520 | return &GoForColon{govar: govar, expr: expr, body: body} 521 | } 522 | 523 | func analyzeForExpr(gs *GoState, owner GoMethodOwner, 524 | jfor *grammar.JForExpr) *GoForExpr { 525 | gs2 := NewGoState(gs) 526 | 527 | fe := &GoForExpr{} 528 | 529 | if jfor.Init != nil && len(jfor.Init) > 0 { 530 | fe.init = make([]GoExpr, len(jfor.Init)) 531 | for i, v := range jfor.Init { 532 | fe.init[i] = analyzeExpr(gs2, owner, v) 533 | } 534 | } 535 | 536 | if jfor.Expr != nil { 537 | fe.cond = analyzeExpr(gs2, owner, jfor.Expr) 538 | } 539 | 540 | if jfor.Incr != nil && len(jfor.Incr) > 0 { 541 | fe.incr = make([]GoExpr, len(jfor.Incr)) 542 | for i, v := range jfor.Incr { 543 | fe.incr[i] = analyzeExpr(gs2, owner, v) 544 | } 545 | } 546 | 547 | if jfor.Body != nil { 548 | fe.block = makeBlock(gs2, owner, jfor.Body) 549 | } 550 | 551 | return fe 552 | } 553 | 554 | func analyzeForVar(gs *GoState, owner GoMethodOwner, jfv *grammar.JForVar) *GoForVar { 555 | gs2 := NewGoState(gs) 556 | 557 | forvar := &GoForVar{govar: gs2.addVariableDecl(jfv.VarDecl, false)} 558 | 559 | if jfv.VarDecl.Init != nil { 560 | forvar.init = analyzeVariableInit(gs2, owner, jfv.VarDecl.Init, 561 | forvar.govar) 562 | } 563 | 564 | if jfv.Decl != nil { 565 | log.Printf("//ERR// ignoring forvar decl %T\n", jfv.Decl) 566 | } 567 | 568 | //multiple initialization; a consolidated bool expression with && and ||; multiple 'incrementation' 569 | // for i, j, s := 0, 5, "a"; i < 3 && j < 100 && s != "aaaaa"; i, j, s = i+1, j+1, s + "a" { 570 | 571 | if jfv.Expr != nil { 572 | forvar.cond = analyzeExpr(gs2, owner, jfv.Expr) 573 | } 574 | 575 | if jfv.Incr != nil && len(jfv.Incr) > 0 { 576 | forvar.incr = make([]GoStatement, 0) 577 | for _, v := range jfv.Incr { 578 | stmts := analyzeStmt(gs2, owner, v) 579 | if stmts != nil && len(stmts) > 0 { 580 | forvar.incr = append(forvar.incr, stmts...) 581 | } 582 | } 583 | } 584 | 585 | if jfv.Body != nil { 586 | forvar.block = makeBlock(gs2, owner, jfv.Body) 587 | } 588 | 589 | return forvar 590 | } 591 | 592 | func analyzeIfElseStmt(gs *GoState, owner GoMethodOwner, 593 | ifelse *grammar.JIfElseStmt) *GoIfElse { 594 | 595 | stmts := analyzeStmt(gs, owner, ifelse.IfBlock) 596 | if stmts == nil || len(stmts) == 0 { 597 | panic("IfStmt body cannot be nil") 598 | } 599 | 600 | var ifblk GoStatement 601 | if len(stmts) == 1 { 602 | ifblk = stmts[0] 603 | } else { 604 | ifblk = &GoBlock{stmts: stmts} 605 | } 606 | 607 | ifstmt := &GoIfElse{cond: analyzeExpr(gs, owner, ifelse.Cond), 608 | ifblk: ifblk} 609 | 610 | if ifelse.ElseBlock != nil { 611 | stmts = analyzeStmt(gs, owner, ifelse.ElseBlock) 612 | if stmts != nil && len(stmts) > 0 { 613 | if len(stmts) == 1 { 614 | ifstmt.elseblk = stmts[0] 615 | } else { 616 | ifstmt.elseblk = &GoBlock{stmts: stmts} 617 | } 618 | } 619 | } 620 | 621 | return ifstmt 622 | } 623 | 624 | func analyzeLabelledStmt(gs *GoState, owner GoMethodOwner, 625 | ls *grammar.JLabeledStatement) *GoLabeledStmt { 626 | stmts := analyzeStmt(gs, owner, ls.Stmt) 627 | if len(stmts) != 1 { 628 | panic("Found label assigned to multiple statements") 629 | } 630 | 631 | return &GoLabeledStmt{label: ls.Label, stmt: stmts[0]} 632 | } 633 | 634 | func analyzeLocalVariableDeclaration(gs *GoState, owner GoMethodOwner, 635 | vdec *grammar.JLocalVariableDecl) []GoStatement { 636 | if vdec.Vars == nil { 637 | return nil 638 | } 639 | 640 | stmts := make([]GoStatement, 0) 641 | for i, lvar := range vdec.Vars { 642 | lv := analyzeLocalVariableInternal(gs, owner, vdec.Modifiers, 643 | vdec.TypeSpec, lvar, i) 644 | stmts = append(stmts, lv) 645 | } 646 | 647 | return stmts 648 | } 649 | 650 | func analyzeLocalVariableInternal(gs *GoState, owner GoMethodOwner, 651 | defaultModifiers *grammar.JModifiers, defaultTypeSpec *grammar.JReferenceType, 652 | vardec *grammar.JVariableDecl, idx int) GoStatement { 653 | 654 | var typespec *grammar.JReferenceType 655 | if vardec.TypeSpec != nil { 656 | typespec = vardec.TypeSpec 657 | } else { 658 | typespec = defaultTypeSpec 659 | } 660 | 661 | var mods *grammar.JModifiers 662 | if vardec.Modifiers != nil { 663 | mods = vardec.Modifiers 664 | } else { 665 | mods = defaultModifiers 666 | } 667 | 668 | govar := gs.addVariable(vardec.Name, mods, vardec.Dims, typespec, false) 669 | if govar == nil { 670 | panic("addVariable returned nil") 671 | } 672 | 673 | if vardec.Init == nil { 674 | return NewGoLocalVarNoInit(govar) 675 | } 676 | 677 | if vardec.Init.ArrayList != nil { 678 | init := analyzeVariableInit(gs, owner, vardec.Init, govar) 679 | return NewGoLocalVarInit(govar, init) 680 | } 681 | 682 | cex, ok := vardec.Init.Expr.(*grammar.JCastExpr) 683 | if !ok { 684 | init := analyzeExpr(gs, owner, vardec.Init.Expr) 685 | return NewGoLocalVarInit(govar, init) 686 | } 687 | 688 | return NewGoLocalVarCast(govar, analyzeCastExpr(gs, owner, cex)) 689 | } 690 | 691 | func analyzeMethodAccess(gs *GoState, owner GoMethodOwner, 692 | mth *grammar.JMethodAccess) GoExpr { 693 | arglist := NewGoMethodArguments(gs, owner, mth.ArgList) 694 | 695 | if mth.NameKey != nil { 696 | is_super := mth.NameKey.Token == grammar.SUPER 697 | if !is_super && mth.NameKey.Token != grammar.THIS { 698 | panic(fmt.Sprintf("Keyword %v is neither THIS nor SUPER", 699 | mth.NameKey)) 700 | } 701 | 702 | return &GoMethodAccessKeyword{is_super: is_super, args: arglist} 703 | } 704 | 705 | if mth.Method == "" { 706 | panic("JMethodAccess name is nil") 707 | } 708 | 709 | var expr GoExpr 710 | if mth.NameObj != nil { 711 | expr = analyzeExpr(gs, owner, mth.NameObj) 712 | 713 | var class GoMethodOwner 714 | if macc, ok := expr.(*GoMethodAccess); ok { 715 | class = macc.method.Class() 716 | } else { 717 | tmpcls := gs.Class() 718 | if tmpcls != nil { 719 | class = tmpcls 720 | } else { 721 | class = nilMethodOwner 722 | } 723 | } 724 | 725 | mthd := findMethod(owner, class, mth.Method, arglist, 726 | gs.Program().verbose) 727 | 728 | return &GoMethodAccessExpr{expr: expr, method: mthd, args: arglist} 729 | } 730 | 731 | var class GoMethodOwner 732 | var govar GoVar 733 | if mth.NameType == nil { 734 | class = nilMethodOwner 735 | } else { 736 | govar = gs.findVariable(mth.NameType) 737 | if govar != nil { 738 | class = owner 739 | } else { 740 | class = gs.findClass(owner, mth.NameType.LastType()) 741 | if class == nil { 742 | fcls := NewGoFakeClass(mth.NameType.String()) 743 | gs.Program().addClass(fcls) 744 | class = fcls 745 | } 746 | } 747 | } 748 | 749 | mthd := findMethod(owner, class, mth.Method, arglist, gs.Program().verbose) 750 | 751 | if govar != nil { 752 | return &GoMethodAccessVar{govar: govar, method: mthd, args: arglist} 753 | } 754 | 755 | return &GoMethodAccess{method: mthd, args: arglist} 756 | } 757 | 758 | func analyzeNameDotObject(gs *GoState, ndo *grammar.JNameDotObject) GoExpr { 759 | switch o := ndo.Obj.(type) { 760 | case *grammar.JKeyword: 761 | log.Printf("//ERR// Not converting ndoobj %T (kwd %s)\n", ndo.Obj, o.Name) 762 | default: 763 | log.Printf("//ERR// Not converting ndoobj %T (%T) to Expr\n", ndo, ndo.Obj) 764 | } 765 | 766 | return &GoUnimplemented{fname: "ndo", text: fmt.Sprintf("%T", ndo.Obj)} 767 | } 768 | 769 | func analyzeArrayReference(gs *GoState, owner GoMethodOwner, 770 | nae *grammar.JArrayReference) *GoArrayReference { 771 | var govar GoVar 772 | var obj GoExpr 773 | if nae.Name != nil { 774 | govar = gs.findOrFakeVariable(nae.Name, "arrayref") 775 | } else { 776 | obj = analyzeExpr(gs, owner, nae.Obj) 777 | } 778 | 779 | return &GoArrayReference{govar: govar, obj: obj, 780 | index: analyzeExpr(gs, owner, nae.Expr)} 781 | } 782 | 783 | func analyzeObjectDotName(gs *GoState, owner GoMethodOwner, 784 | odn *grammar.JObjectDotName) GoVar { 785 | switch o := odn.Obj.(type) { 786 | case *grammar.JKeyword: 787 | if o.Token == grammar.THIS && gs.Receiver() != "" { 788 | rvar := gs.findVariable(grammar.NewJTypeName(gs.Receiver(), false)) 789 | if rvar == nil { 790 | rvar = gs.addVariable(gs.Receiver(), nil, 0, nil, false) 791 | } 792 | 793 | ref := gs.findVariable(odn.Name) 794 | if ref == nil { 795 | ref = gs.addVariable(gs.Receiver(), nil, 0, nil, false) 796 | } 797 | 798 | return NewGoSelector(rvar, ref) 799 | } else if o.Token == grammar.SUPER && gs.Receiver() != "" { 800 | log.Printf("//ERR// Not converting odnobj super\n") 801 | return NewFakeVar("<>", nil, 0) 802 | } else { 803 | log.Printf("//ERR// Not converting odnobj %T (kwd %s)\n", 804 | odn.Obj, o.Name) 805 | return NewFakeVar(fmt.Sprintf("<<%v>>", o.Name), nil, 0) 806 | } 807 | default: 808 | return NewObjectDotName(odn, analyzeExpr(gs, owner, odn.Obj), gs) 809 | } 810 | } 811 | 812 | func analyzeReferenceType(gs *GoState, ref *grammar.JReferenceType) GoVar { 813 | if ref.TypeArgs != nil && len(ref.TypeArgs) > 0 { 814 | fmt.Sprintf("//ERR// Not handling reftype type_args in %v\n", ref.Name) 815 | } 816 | 817 | govar := gs.findVariable(ref.Name) 818 | if govar != nil { 819 | return govar 820 | } 821 | 822 | return NewFakeVar(ref.Name.String(), ref.TypeArgs, ref.Dims) 823 | } 824 | 825 | func analyzeSimpleStatement(gs *GoState, owner GoMethodOwner, 826 | jstmt *grammar.JSimpleStatement) GoStatement { 827 | 828 | if jstmt.Keyword != nil { 829 | switch jstmt.Keyword.Token { 830 | case grammar.BREAK: 831 | return analyzeBranchStmt(gs, owner, token.BREAK, jstmt.Object) 832 | case grammar.CONTINUE: 833 | return analyzeBranchStmt(gs, owner, token.CONTINUE, jstmt.Object) 834 | case grammar.RETURN: 835 | var expr GoExpr 836 | if jstmt.Object != nil { 837 | expr = analyzeExpr(gs, owner, jstmt.Object) 838 | } 839 | 840 | return &GoReturn{expr: expr} 841 | case grammar.THROW: 842 | return &GoThrow{expr: analyzeExpr(gs, owner, jstmt.Object)} 843 | default: 844 | return &GoUnimplemented{fname: "simpstmt", 845 | text: jstmt.Keyword.Name} 846 | } 847 | } 848 | 849 | switch expr := jstmt.Object.(type) { 850 | case *grammar.JAssignmentExpr: 851 | return analyzeAssignExpr(gs, owner, expr) 852 | case *grammar.JClassAllocationExpr: 853 | return &GoExprStmt{x: analyzeAllocationExpr(gs, owner, expr)} 854 | case *grammar.JMethodAccess: 855 | return &GoExprStmt{x: analyzeMethodAccess(gs, owner, expr)} 856 | case *grammar.JUnaryExpr: 857 | return analyzeUnaryExpr(gs, owner, expr) 858 | default: 859 | log.Printf("//ERR// -------- not analyzing simpstmt %T\n", jstmt.Object) 860 | return &GoUnimplemented{fname: "simpstmt", 861 | text: fmt.Sprintf("%T", jstmt.Object)} 862 | } 863 | } 864 | 865 | func analyzeStmt(gs *GoState, owner GoMethodOwner, 866 | jstmt grammar.JObject) []GoStatement { 867 | switch stmt := jstmt.(type) { 868 | case *grammar.JAssignmentExpr: 869 | return []GoStatement{analyzeAssignExpr(gs, owner, stmt)} 870 | case *grammar.JBlock: 871 | return []GoStatement{analyzeBlock(gs, owner, stmt)} 872 | case *grammar.JForColon: 873 | return []GoStatement{analyzeForColon(gs, owner, stmt)} 874 | case *grammar.JForVar: 875 | return []GoStatement{analyzeForVar(gs, owner, stmt)} 876 | case *grammar.JIfElseStmt: 877 | return []GoStatement{analyzeIfElseStmt(gs, owner, stmt)} 878 | case *grammar.JJumpToLabel: 879 | return []GoStatement{NewGoJumpToLabel(stmt.Label, stmt.IsContinue)} 880 | case *grammar.JLocalVariableDecl: 881 | return analyzeLocalVariableDeclaration(gs, owner, stmt) 882 | case *grammar.JSimpleStatement: 883 | return []GoStatement{analyzeSimpleStatement(gs, owner, stmt)} 884 | case *grammar.JTry: 885 | return []GoStatement{analyzeTry(gs, owner, stmt)} 886 | case *grammar.JUnaryExpr: 887 | return []GoStatement{analyzeUnaryExpr(gs, owner, stmt)} 888 | case *grammar.JUnimplemented: 889 | log.Printf("//ERR// Not analyzing unimplemented stmt %s\n", stmt.TypeStr) 890 | return []GoStatement{&GoUnimplemented{fname: "stmt", 891 | text: stmt.TypeStr}} 892 | case *grammar.JWhile: 893 | return []GoStatement{analyzeWhile(gs, owner, stmt)} 894 | default: 895 | log.Printf("//ERR// Not analyzing stmt %T\n", stmt) 896 | return []GoStatement{&GoUnimplemented{fname: "stmt", 897 | text: fmt.Sprintf("%T", stmt)}} 898 | } 899 | } 900 | 901 | func analyzeSwitch(gs *GoState, owner GoMethodOwner, 902 | jsw *grammar.JSwitch) *GoSwitch { 903 | if jsw.Groups == nil || len(jsw.Groups) == 0 { 904 | // ignore empty switch statements 905 | return nil 906 | } 907 | 908 | gsw := &GoSwitch{expr: analyzeExpr(gs, owner, jsw.Expr), 909 | cases: make([]*GoSwitchCase, len(jsw.Groups))} 910 | for i, c := range jsw.Groups { 911 | gsw.cases[i] = analyzeSwitchCase(gs, owner, c) 912 | } 913 | 914 | return gsw 915 | } 916 | 917 | func analyzeSwitchCase(gs *GoState, owner GoMethodOwner, 918 | jsg *grammar.JSwitchGroup) *GoSwitchCase { 919 | if jsg.Labels == nil || len(jsg.Labels) == 0 { 920 | panic("No labels for switch case") 921 | } 922 | 923 | labels := make([]*GoSwitchLabel, len(jsg.Labels)) 924 | for i, l := range jsg.Labels { 925 | labels[i] = analyzeSwitchLabel(gs, owner, l) 926 | } 927 | 928 | stmts := make([]GoStatement, 0) 929 | for _, s := range jsg.Stmts { 930 | gs2 := NewGoState(gs) 931 | 932 | st := analyzeStmt(gs2, owner, s) 933 | if st != nil && len(st) > 0 { 934 | stmts = append(stmts, st...) 935 | } 936 | } 937 | 938 | // if last statement is 'break', delete it (it's implicit in Go) 939 | // if it's not 'break', add a fallthrough 940 | need_fall := true 941 | l := len(stmts) 942 | if l > 0 { 943 | switch br := stmts[l-1].(type) { 944 | case *GoBranchStmt: 945 | if br.tok == token.BREAK { 946 | stmts = stmts[0 : l-1] 947 | need_fall = false 948 | } 949 | case *GoJumpToLabel: 950 | need_fall = false 951 | } 952 | } 953 | 954 | if need_fall { 955 | stmts = append(stmts, &GoBranchStmt{tok: token.FALLTHROUGH}) 956 | } 957 | 958 | return &GoSwitchCase{labels: labels, stmts: stmts} 959 | } 960 | 961 | func analyzeSwitchLabel(gs *GoState, owner GoMethodOwner, 962 | jsl *grammar.JSwitchLabel) *GoSwitchLabel { 963 | if jsl.IsDefault { 964 | return &GoSwitchLabel{is_default: true} 965 | } 966 | 967 | var expr GoExpr 968 | if jsl.Name != "" { 969 | expr = &GoLiteral{text: jsl.Name} 970 | } else if jsl.Expr != nil { 971 | expr = analyzeExpr(gs, owner, jsl.Expr) 972 | } else { 973 | panic("Empty switch label") 974 | } 975 | 976 | return &GoSwitchLabel{expr: expr} 977 | } 978 | 979 | func analyzeSynchronized(gs *GoState, owner GoMethodOwner, 980 | sync *grammar.JSynchronized) *GoSynchronized { 981 | return &GoSynchronized{expr: analyzeExpr(gs, owner, sync.Expr), 982 | block: analyzeBlock(gs, owner, sync.Block)} 983 | } 984 | 985 | func analyzeTry(gs *GoState, owner GoMethodOwner, try *grammar.JTry) *GoTry { 986 | gt := &GoTry{block: analyzeBlock(NewGoState(gs), owner, try.Block)} 987 | 988 | if try.Catches != nil && len(try.Catches) > 0 { 989 | gs2 := NewGoState(gs) 990 | 991 | gt.catches = make([]*GoTryCatch, len(try.Catches)) 992 | for i, c := range try.Catches { 993 | var exc *grammar.JTypeName 994 | if len(c.TypeList) == 1 { 995 | exc = c.TypeList[0] 996 | } else { 997 | exc = grammar.NewJTypeName("Exception", false) 998 | } 999 | 1000 | govar := gs.addVariable(c.Name, c.Modifiers, 0, 1001 | grammar.NewJReferenceType(exc, nil, 0), false) 1002 | 1003 | if len(c.TypeList) != 1 { 1004 | log.Printf("//ERR// Ignoring catch#%d long typelist (len=%d)\n", 1005 | i, len(c.TypeList)) 1006 | } 1007 | 1008 | gt.catches[i] = &GoTryCatch{govar: govar, 1009 | block: analyzeBlock(gs2, owner, c.Block)} 1010 | } 1011 | } 1012 | 1013 | if try.Finally != nil { 1014 | gt.finally = analyzeBlock(NewGoState(gs), owner, try.Finally) 1015 | } 1016 | 1017 | return gt 1018 | } 1019 | 1020 | func analyzeUnaryExpr(gs *GoState, owner GoMethodOwner, uexpr *grammar.JUnaryExpr) *GoUnaryExpr { 1021 | var op token.Token 1022 | switch uexpr.Op { 1023 | case "++": 1024 | op = token.INC 1025 | case "--": 1026 | op = token.DEC 1027 | case "!": 1028 | op = token.NOT 1029 | case "~": 1030 | op = token.XOR 1031 | case "+": 1032 | op = token.ADD 1033 | case "-": 1034 | op = token.SUB 1035 | default: 1036 | panic(fmt.Sprintf("Unknown unary operator \"%s\"", uexpr.Op)) 1037 | } 1038 | 1039 | return &GoUnaryExpr{op: op, x: analyzeExpr(gs, owner, uexpr.Obj)} 1040 | } 1041 | 1042 | func analyzeVariableInit(gs *GoState, owner GoMethodOwner, 1043 | init *grammar.JVariableInit, govar GoVar) *GoVarInit { 1044 | if init.Expr != nil { 1045 | var expr GoExpr 1046 | switch v := init.Expr.(type) { 1047 | case *grammar.JVariableInit: 1048 | expr = analyzeVariableInit(gs, owner, v, govar) 1049 | case *grammar.JArrayAlloc: 1050 | expr = analyzeArrayAlloc(gs, owner, v, govar) 1051 | default: 1052 | expr = analyzeExpr(gs, owner, init.Expr) 1053 | } 1054 | 1055 | return &GoVarInit{govar: govar, expr: expr} 1056 | } 1057 | 1058 | if init.ArrayList == nil { 1059 | panic("No variable Initialization") 1060 | } 1061 | 1062 | elements := make([]GoExpr, len(init.ArrayList)) 1063 | for i, elem := range init.ArrayList { 1064 | elements[i] = analyzeVariableInit(gs, owner, elem, govar) 1065 | } 1066 | 1067 | return &GoVarInit{govar: govar, elements: elements} 1068 | } 1069 | 1070 | func analyzeWhile(gs *GoState, owner GoMethodOwner, while *grammar.JWhile) *GoWhile { 1071 | gw := &GoWhile{expr: analyzeExpr(gs, owner, while.Expr), 1072 | is_do_while: while.IsDoWhile} 1073 | 1074 | stmts := analyzeStmt(gs, owner, while.Stmt) 1075 | if stmts != nil && len(stmts) > 0 { 1076 | if len(stmts) == 1 { 1077 | gw.stmt = stmts[0] 1078 | } else { 1079 | gw.stmt = &GoBlock{stmts: stmts} 1080 | } 1081 | } 1082 | 1083 | return gw 1084 | } 1085 | 1086 | func makeBlock(gs *GoState, owner GoMethodOwner, block grammar.JObject) *GoBlock { 1087 | stmts := analyzeStmt(gs, owner, block) 1088 | if stmts == nil || len(stmts) == 0 { 1089 | return nil 1090 | } 1091 | 1092 | if len(stmts) == 1 { 1093 | if blk, ok := stmts[0].(*GoBlock); ok { 1094 | return blk 1095 | } 1096 | } 1097 | 1098 | return &GoBlock{stmts: stmts} 1099 | } 1100 | --------------------------------------------------------------------------------