forked from stephens2424/php
/
togo.go
93 lines (78 loc) · 2.11 KB
/
togo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package togo
import (
"bytes"
"fmt"
goast "go/ast"
"go/format"
"go/token"
"io"
"strings"
phpast "github.com/ctriv/php/ast"
"github.com/ctriv/php/parser"
"golang.org/x/tools/imports"
)
// Togo is a go php transpiler
type Togo struct {
currentScope *phpast.Scope
}
// TranspileFile transpiles a file
func TranspileFile(goFilename, phpFilename, phpStr string, gosrc io.Writer) error {
parser := parser.NewParser()
file, err := parser.Parse(phpFilename, phpStr)
if err != nil {
return fmt.Errorf("found errors while parsing %s: %s", phpFilename, err)
}
tg := Togo{currentScope: parser.FileSet.Scope}
nodes := []goast.Node{}
for _, node := range tg.beginScope(tg.currentScope) {
nodes = append(nodes, node)
}
for _, phpNode := range file.Nodes {
nodes = append(nodes, tg.ToGoStmt(phpNode.(phpast.Statement)))
}
buf := &bytes.Buffer{}
if err = format.Node(buf, token.NewFileSet(), File(phpFilename[:len(phpFilename)-4], nodes...)); err != nil {
return fmt.Errorf("error while formatting %s: %s", phpFilename, err)
}
imported, err := imports.Process(goFilename, buf.Bytes(), &imports.Options{AllErrors: true, Comments: true, TabIndent: true, TabWidth: 8})
if err != nil {
return fmt.Errorf("error while getting imports for %s: %s", phpFilename, err)
}
_, err = gosrc.Write(imported)
return err
}
// File returns a new file
func File(name string, nodes ...goast.Node) *goast.File {
f := &goast.File{
Name: goast.NewIdent("translated"),
}
stmts := []goast.Stmt{}
name = strings.Replace(name, `.`, "", -1)
name = strings.Replace(name, `/`, "_", -1)
name = strings.Title(name)
for _, n := range nodes {
switch g := n.(type) {
case goast.Stmt:
stmts = append(stmts, g)
case goast.Expr:
stmts = append(stmts, &goast.ExprStmt{X: g})
}
}
f.Decls = []goast.Decl{
&goast.FuncDecl{
Name: &goast.Ident{Name: name},
Type: &goast.FuncType{
Params: &goast.FieldList{
List: []*goast.Field{{
Names: []*goast.Ident{goast.NewIdent("ctx")},
Type: goast.NewIdent("phpctx.PHPContext"),
}},
},
},
Body: &goast.BlockStmt{
List: stmts,
},
},
}
return f
}