1package filter
2
3import (
4	"go/ast"
5	"go/token"
6	"go/types"
7
8	"github.com/gopherjs/gopherjs/compiler/astutil"
9)
10
11func Assign(stmt ast.Stmt, info *types.Info, pkg *types.Package) ast.Stmt {
12	if s, ok := stmt.(*ast.AssignStmt); ok && s.Tok != token.ASSIGN && s.Tok != token.DEFINE {
13		var op token.Token
14		switch s.Tok {
15		case token.ADD_ASSIGN:
16			op = token.ADD
17		case token.SUB_ASSIGN:
18			op = token.SUB
19		case token.MUL_ASSIGN:
20			op = token.MUL
21		case token.QUO_ASSIGN:
22			op = token.QUO
23		case token.REM_ASSIGN:
24			op = token.REM
25		case token.AND_ASSIGN:
26			op = token.AND
27		case token.OR_ASSIGN:
28			op = token.OR
29		case token.XOR_ASSIGN:
30			op = token.XOR
31		case token.SHL_ASSIGN:
32			op = token.SHL
33		case token.SHR_ASSIGN:
34			op = token.SHR
35		case token.AND_NOT_ASSIGN:
36			op = token.AND_NOT
37		default:
38			panic(s.Tok)
39		}
40
41		var list []ast.Stmt
42
43		var viaTmpVars func(expr ast.Expr, name string) ast.Expr
44		viaTmpVars = func(expr ast.Expr, name string) ast.Expr {
45			switch e := astutil.RemoveParens(expr).(type) {
46			case *ast.IndexExpr:
47				return astutil.SetType(info, info.TypeOf(e), &ast.IndexExpr{
48					X:     viaTmpVars(e.X, "_slice"),
49					Index: viaTmpVars(e.Index, "_index"),
50				})
51
52			case *ast.SelectorExpr:
53				sel, ok := info.Selections[e]
54				if !ok {
55					// qualified identifier
56					return e
57				}
58				newSel := &ast.SelectorExpr{
59					X:   viaTmpVars(e.X, "_struct"),
60					Sel: e.Sel,
61				}
62				info.Selections[newSel] = sel
63				return astutil.SetType(info, info.TypeOf(e), newSel)
64
65			case *ast.StarExpr:
66				return astutil.SetType(info, info.TypeOf(e), &ast.StarExpr{
67					X: viaTmpVars(e.X, "_ptr"),
68				})
69
70			case *ast.Ident, *ast.BasicLit:
71				return e
72
73			default:
74				tmpVar := astutil.NewIdent(name, info.TypeOf(e), info, pkg)
75				list = append(list, &ast.AssignStmt{
76					Lhs: []ast.Expr{tmpVar},
77					Tok: token.DEFINE,
78					Rhs: []ast.Expr{e},
79				})
80				return tmpVar
81
82			}
83		}
84
85		lhs := viaTmpVars(s.Lhs[0], "_val")
86
87		list = append(list, &ast.AssignStmt{
88			Lhs: []ast.Expr{lhs},
89			Tok: token.ASSIGN,
90			Rhs: []ast.Expr{
91				astutil.SetType(info, info.TypeOf(s.Lhs[0]), &ast.BinaryExpr{
92					X:  lhs,
93					Op: op,
94					Y: astutil.SetType(info, info.TypeOf(s.Rhs[0]), &ast.ParenExpr{
95						X: s.Rhs[0],
96					}),
97				}),
98			},
99		})
100
101		return &ast.BlockStmt{
102			List: list,
103		}
104	}
105	return stmt
106}
107