0%

Js-Go:重构基础类型+重构作用域

重构基础类型

之前所有的类型都是用 string 记录:

1
2
3
4
5
type Variant struct {
name string
value string
typ int
}

JavaScript 一切皆对象,这里选择为各个基础对象添加对应的结构体:

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
type BaseObject interface {
getString() string
}

type UndefObject struct {
BaseObject
Value string
}

type StringObject struct {
BaseObject
Value string
}

type NumberObject struct {
BaseObject
Value int
}

type BooleanObject struct {
BaseObject
Value bool
}

type ArrayObject struct {
BaseObject
Value []BaseObject
}

type ObjObject struct {
BaseObject
Value map[string]BaseObject
}

type VariantObject struct {
BaseObject
Value string
}
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
func (n *UndefObject) getString() string {
return "undefined"
}

func (s *StringObject) getString() string {
return s.Value
}

func (n *NumberObject) getString() string {
return fmt.Sprintf("%d", n.Value)
}

func (b *BooleanObject) getString() string {
if b.Value {
return "true"
}
return "false"
}

func (a *ArrayObject) getString() string {
str := "["
for _, n := range a.Value {
str += fmt.Sprintf(" %v,", n.getString())
}
str = str[:len(str)-1] + " ]"

return str
}

func (a *ArrayObject) setValue(num BaseObject) {
a.Value = append(a.Value, num)
}

func (a *ArrayObject) getValue(index int) BaseObject {
return a.Value[index]
}

func (o *ObjObject) getString() string {
str := "{"
for k, v := range o.Value {
str += fmt.Sprintf(" %s:%s,", k, v.getString())
}
str = str[:len(str)-1] + " }"

return str
}

func (o *ObjObject) addValue(name string, obj BaseObject) {
o.Value[name] = obj
}

func (o *ObjObject) setValue(name string, obj BaseObject) {
for i, _ := range o.Value {
if i == name {
o.Value[i] = obj
}
}
}

func (v *VariantObject) getString() string {
return v.Value
}

记录基础类型的结构体改变以后,许多地方的代码都要重构

首先是 handExpr 中对二元运算符的处理:

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
op := fmt.Sprintf("%v", exp.GetChild(1))
exp1, typ1 := handExpr(exp.GetChild(0).(*Jsp.ExprContext))
exp2, typ2 := handExpr(exp.GetChild(2).(*Jsp.ExprContext))

......

if op == "+" {
if typ1 == Jsp.JavaScriptLexerNUMBER && typ2 == Jsp.JavaScriptLexerNUMBER {
num1, _ := strconv.Atoi(exp1.getString())
num2, _ := strconv.Atoi(exp2.getString())
return &NumberObject{Value: num1 + num2}, Jsp.JavaScriptLexerNUMBER
} else if typ1 == Jsp.JavaScriptLexerSTRING || typ2 == Jsp.JavaScriptLexerSTRING {
return &StringObject{Value: exp1.getString() + exp2.getString()}, Jsp.JavaScriptLexerSTRING
} else {
return nil, -1
}
}

......

if op == ">" {
if typ1 == Jsp.JavaScriptLexerNUMBER && typ2 == Jsp.JavaScriptLexerNUMBER {
num1, _ := strconv.Atoi(exp1.getString())
num2, _ := strconv.Atoi(exp2.getString())
return &BooleanObject{Value: num1 > num2}, Jsp.JavaScriptLexerNUMBER
} else {
return nil, -1
}
}

......

handExpr 中对一元运算符的处理:

1
2
3
4
5
6
7
8
9
10
11
if op == "++" {
if typ1 == Jsp.JavaScriptLexerNUMBER {
num1, _ := strconv.Atoi(exp1.getString())
num := &NumberObject{Value: num1 + 1}
name := fmt.Sprintf("%v", exp.GetChild(0).GetChild(0).GetChild(0))
vl.setVar(name, num, Jsp.JavaScriptLexerNUMBER)
return num, Jsp.JavaScriptLexerNUMBER
} else {
return nil, -1
}
}

handExpr 中对原始数据类型的处理:

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
if exp.GetChildCount() == 1 { // funcall | num | id | str | arr | obj
if call, ok := exp.GetChild(0).(*Jsp.FuncallContext); ok {
return handExpr_funcall(call)
} else if arr, ok := exp.GetChild(0).(*Jsp.ArrContext); ok {
arrt := &ArrayObject{Value: make([]BaseObject, 0)}
for _, a := range arr.GetChildren() {
if a.GetChild(0) != nil {
num, _ := strconv.Atoi(fmt.Sprintf("%v", a.GetChild(0).GetChild(0)))
arrt.setValue(&NumberObject{Value: num})
}
}
return arrt, Jsp.JavaScriptParserRULE_arr
} else if obj, ok := exp.GetChild(0).(*Jsp.ObjContext); ok { // object
objt := &ObjObject{Value: make(map[string]BaseObject)}
for _, o := range obj.GetChildren() {
if o.GetChild(0) != nil {
name := fmt.Sprintf("%v", o.GetChild(0).GetChild(0))
value, _ := handExpr(o.GetChild(2).(*Jsp.ExprContext))
objt.addValue(name, value)
}
}
return objt, Jsp.JavaScriptParserRULE_obj
} else {
renum := regexp.MustCompile(`^\d+$`)
resym := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
str := fmt.Sprintf("%v", exp.GetChild(0).GetChild(0))
if str[0] == '"' { // string
return &StringObject{Value: str}, Jsp.JavaScriptLexerSTRING
}
if renum.MatchString(str) { // number
num, _ := strconv.Atoi(str)
return &NumberObject{Value: num}, Jsp.JavaScriptLexerNUMBER
}
if resym.MatchString(str) { // var
value, typ := vl.getVarByName(str)
return value, typ
}
}
}

最后则是对数组与对象的处理:

1
2
3
4
5
6
7
8
9
10
if op == "." { // expr '.' expr
name1 := fmt.Sprintf("%v", exp.GetChild(0).GetChild(0).GetChild(0))
name2 := fmt.Sprintf("%v", exp.GetChild(2).GetChild(0).GetChild(0))
if obj, ok := exp1.(*ObjObject); ok {
obj.setValue(name1, obj.Value[name2])
return obj.Value[name2], typ
} else {
panic("Object syntax error")
}
}
1
2
3
4
5
6
7
8
9
10
11
if exp.GetChildCount() == 4 { // expr '[' expr ']'
index, _ := handExpr(exp.GetChild(2).(*Jsp.ExprContext))
exp, typ := handExpr(exp.GetChild(0).(*Jsp.ExprContext))

if arr, ok := exp.(*ArrayObject); ok {
i, _ := strconv.Atoi(index.getString())
return arr.getValue(i), typ
} else {
panic("Array syntax error")
}
}

重构作用域

之前对作用域的处理主要是针对函数:

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
func handFuncdef(name string, args []Variant) (BaseObject, int) {
var currentT = current
current = name
params, ctx := vl.getFunc(name)

defer func() {
vl.delVarAll() /* 清空SymTable中的函数参数 */
current = currentT
}()

if ctx == nil {
value, typ := vl.callInFunc(name, args)
return value, typ
}

if len(params) != len(args) {
panic("The parameters do not match")
} else {
for i, param := range params {
value, typ := args[i].value, args[i].typ
vl.addVar(param, value, typ) /* 将函数参数添加到SymTable中 */
}
}
block := ctx.GetChild(ctx.GetChildCount() - 1).(*Jsp.BlockContext)
revalue, retyp := handBlock(block)

return revalue, retyp
}
1
2
3
4
func (vl *SymTable) addVar(name string, value BaseObject, typ int) {
vl.Variants = append(vl.Variants, *NewVariant(current+"."+name, value, typ))
vl.setFuncByName(current, name)
}
1
2
3
4
5
6
7
8
func (vl *SymTable) delVarAll() {
for _, v := range vl.Variants {
substrs := strings.Split(v.name, ".")
if substrs[0] == current {
vl.Variants = vl.Variants[:len(vl.Variants)-1]
}
}
}
  • 这种写法有一个问题,那就是递归的函数也会被清除所有的参数,导致程序内部出错

重构后的作用域主要基于 Scope 结构体:

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
type Scope struct {
Outer *Scope
Objects map[string]*Variant
}

func NewScope(outer *Scope) *Scope {
return &Scope{
Outer: outer,
Objects: make(map[string]*Variant),
}
}

func (s *Scope) HasName(name string) bool {
_, ok := s.Objects[name]
return ok
}

func (s *Scope) Lookup(name string) (*Scope, *Variant) {
for ; s != nil; s = s.Outer {
if obj := s.Objects[name]; obj != nil {
return s, obj
}
}
return nil, nil
}

func (s *Scope) Insert(v *Variant) (alt *Variant) {
if alt = s.Objects[v.name]; alt == nil {
s.Objects[v.name] = v
}
return
}

每一层作用域都可以用一个 Scope 结构体表示,可以用下面两个函数进行控制:

1
2
3
4
5
6
7
func (p *SymTable) enterScope() { /* 新建并进入下一层 */
p.scope = NewScope(p.scope)
}

func (p *SymTable) leaveScope(scope *Scope) { /* 返回上一层 */
p.scope = scope
}

基于 Scope 可以对 SymTable 中的其他函数进行重构:

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
func (vl *SymTable) addVar(name string, value BaseObject, typ int) {
vl.scope.Insert(NewVariant(current+"."+name, value, typ))
vl.setFuncByName(current, name)
}

func (vl *SymTable) setVar(name string, value BaseObject, typ int) {
substrs := strings.Split(name, "@")
if _, obj := vl.scope.Lookup(current + "." + substrs[0]); obj != nil {
if typ == Jsp.JavaScriptParserRULE_obj {
if o, ok := obj.value.(*ObjObject); ok {
o.setValue(substrs[1], value)
}
} else {
obj.value = value
obj.typ = typ
}
} else {
panic(fmt.Sprintf("var %s undefined", name))
}
}

func (vl *SymTable) getVarByName(name string) (BaseObject, int) {
if _, obj := vl.scope.Lookup(current + "." + name); obj != nil {
return obj.value, obj.typ
}
return nil, -1
}

最后在 handBlock 中添加对 Scope 的处理即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func (h *Handler) handBlock(blo *Jsp.BlockContext) (BaseObject, int) {
defer vl.leaveScope(vl.scope)
vl.enterScope()

for _, c := range blo.GetChildren() {
if h.isBreak {
break
}
if h.isContinue {
continue
}
if c.GetChild(0) != nil {
value, typ := h.handStm(c.(*Jsp.StmContext))
if h.isReturn {
return value, typ
}
}
}

return nil, -1
}