重构基础类型 之前所有的类型都是用 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 { 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 { 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 ] == '"' { return &StringObject{Value: str}, Jsp.JavaScriptLexerSTRING } if renum.MatchString(str) { num, _ := strconv.Atoi(str) return &NumberObject{Value: num}, Jsp.JavaScriptLexerNUMBER } if resym.MatchString(str) { value, typ := vl.getVarByName(str) return value, typ } } }
最后则是对数组与对象的处理:
1 2 3 4 5 6 7 8 9 10 if op == "." { 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 { 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() 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) } } 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 }