您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“怎么用golang編寫基于注解的靜態(tài)代碼增強器/生成器”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“怎么用golang編寫基于注解的靜態(tài)代碼增強器/生成器”吧!
Spring的主要特性: 1. 控制反轉(zhuǎn)(Inversion of Control, IoC) 2. 面向容器 3. 面向切面(AspectOriented Programming, AOP) 源碼gitee地址: https://gitee.com/ioly/learning.gooop 原文鏈接: https://my.oschina.net/ioly
參考spring boot常用注解,使用golang編寫“基于注解的靜態(tài)代碼增強器/生成器”
今天繼續(xù)the hard part:struct/field/method元素的掃描
common/Tokens.go:添加數(shù)據(jù)類型的詞法解析支持
scanner/IStructScanner.go: 結(jié)構(gòu)體掃描器的接口及實現(xiàn)
添加數(shù)據(jù)類型的詞法解析支持:
分別解析基本類型/自定義類型/指針類型/數(shù)組類型/map類型
自定義類型需要注意排除'map'關(guān)鍵字
指針,數(shù)組和map類型都是復(fù)合類型,需遞歸解析
package common import ( "regexp" "strings" "sync" ) type tTokens struct { cache map[string]*regexp.Regexp rwmutex *sync.RWMutex } var Tokens = newTokensLib() func newTokensLib() *tTokens { it := new(tTokens) it.init() return it } func (me *tTokens) init() { me.cache = make(map[string]*regexp.Regexp) me.rwmutex = new(sync.RWMutex) } func (me *tTokens) MatchString(s string, p string) bool { return strings.HasPrefix(s, p) } func (me *tTokens) MatchRegexp(s string, p string) (bool, string) { me.rwmutex.RLock() r, ok := me.cache[p] me.rwmutex.RUnlock() if !ok { me.rwmutex.Lock() if r, ok = me.cache[p]; !ok { r, _ = regexp.Compile(p) } me.rwmutex.Unlock() } if r == nil { return false, "" } if !r.MatchString(s) { return false, "" } return true, r.FindString(s) } func (me *tTokens) MatchIdentifier(s string) (bool, string) { return me.MatchRegexp(s, "^[_a-zA-Z]\\w{0,99}") } func (me *tTokens) MatchSpaces(s string) (bool, string) { return me.MatchRegexp(s, "^\\s+") } func (me *tTokens) MatchDir(s string) (bool, string) { b, s := me.MatchRegexp(s, "^([a-zA-Z]\\:)?([\\\\/][^\\s/:*?<>|\\\"\\\\]+)+[\\/]?") if b { return b, s } b, s = me.MatchRegexp(s, "^\\\"([a-zA-Z]\\:)?([\\\\/][^/:*?<>|\\\"\\\\]+)+[\\/]?\\\"") if b { return b, s } b, s = me.MatchRegexp(s, "^'([a-zA-Z]\\:)?([\\\\/][^'/:*?<>|\\\"\\\\]+)+[\\/]?'") if b { return b, s } return false, "" } func (me *tTokens) MatchDataType(s string) (bool, string) { if ok,t := me.MatchBasicType(s);ok { return true, t } if ok,t := me.MatchCustomType(s);ok { return true, t } if ok,t := me.MatchPointerType(s);ok { return true, t } if ok,t := me.MatchArrayType(s);ok { return true, t } if ok,t := me.MatchMapType(s);ok { return true, t } return false, "" } func (me *tTokens) MatchBasicType(s string) (bool, string) { list := []string { "int", "string", "bool", "byte", "int32", "int64", "uint32", "uint64", "float32", "float64", "int8", "uint8", "int16", "uint16", "time.Time", } for _,it := range list { if me.MatchString(s, it) { return true, it } } return false, "" } func (me *tTokens) MatchCustomType(s string) (bool, string) { t := s b1, s1 := me.MatchRegexp(t, `^\w+\.`) if b1 { t = t[len(s1):] } b2, s2 := me.MatchRegexp(t, `^\w+`) if !b2 { return false, "" } if s2 == "map" { // map is reserved word return false, "" } return true, s1 + s2 } func (me *tTokens) MatchPointerType(s string) (bool, string) { t := s if t[0] != '*' { return false,"" } t = t[1:] b, s := me.MatchDataType(t) if !b { return false, "" } return true, "*" + s } func (me *tTokens) MatchArrayType(s string) (bool, string) { t := s b1, s1 := me.MatchRegexp(s, `^\[\s*\d*\s*\]\s*`) if !b1 { return false, "" } t = t[len(s1):] b2, s2 := me.MatchDataType(t) if !b2 { return false, "" } return true, s1 + s2 } func (me *tTokens) MatchMapType(s string) (bool, string) { t := s s1 := "map" if !me.MatchString(t, s1) { return false, "" } t = t[len(s1):] b2, s2 := me.MatchRegexp(t, `^\s*\[\s*`) if !b2 { return false, "" } t = t[len(s2):] b3,s3 := me.MatchDataType(t) if !b3 { return false, "" } t = t[len(s3):] b4, s4 := me.MatchRegexp(t, `^\s*\]\s*`) if !b4 { return false, "" } t = t[len(s4):] b5, s5 := me.MatchDataType(t) if !b5 { return false, "" } return true, s1 + s2 + s3 + s4 + s5 }
結(jié)構(gòu)體掃描器的接口及實現(xiàn)
package scanner import ( "errors" "learning/gooop/spring/autogen/common" "learning/gooop/spring/autogen/domain" "regexp" "strings" ) type IStructScanner interface { ScanStruct(file *domain.CodeFileInfo) } type tStructScanner int func (me *tStructScanner) ScanStruct(file *domain.CodeFileInfo) { bInStruct := false var stru *domain.StructInfo for lineNO,line := range file.CleanLines { if bInStruct { // end? if gStructEndRegexp.MatchString(line) { bInStruct = false me.scanMethod(stru, lineNO + 1) stru = nil continue } } // start? if gStructStartRegexp.MatchString(line) { bInStruct = true ss := gStructStartRegexp.FindAllString(line, -1) stru := domain.NewStructInfo() stru.LineNO = lineNO stru.CodeFile = file stru.Name = ss[1] continue } // in struct block ok,fname,ftype := me.scanField(line) if ok { stru.AppendField(lineNO, fname, ftype) } } } func (me *tStructScanner) scanField(line string) (ok bool, fldName string, fldType string) { if !gFieldStartRegexp.MatchString(line) { return false, "","" } fldName = strings.TrimSpace(gFieldStartRegexp.FindString(line)) fldType = strings.TrimSpace(line[len(fldName):]) return true, fldName, fldType } func (me *tStructScanner) scanMethod(stru *domain.StructInfo, fromLineNO int) { for i,max := fromLineNO, len(stru.CodeFile.CleanLines);i <= max;i++ { line := stru.CodeFile.CleanLines[i] if !gMethodStartRegex.MatchString(line) { continue } ss := gMethodStartRegex.FindAllString(line, -1) // declare declare := ss[0] offset := len(declare) // receiver receiver := ss[1] if receiver != stru.Name { continue } method := domain.NewMethodInfo() // name method.Name = ss[2] // method input args e,args := me.scanMethodArgs(method, strings.TrimSpace(line[offset:])) if e != nil { panic(e) } offset += len(args) // method return args e = me.scanReturnArgs(method, strings.TrimSpace(line[offset:])) if e != nil { panic(e) } // end scan method stru.AppendMethod(method) } } func (me *tStructScanner) scanMethodArgs(method *domain.MethodInfo, s string) (error, string) { t := s offset := 0 for { // name b1, s1 := common.Tokens.MatchRegexp(t, `\w+(\s*,\s*\w+)\s+`) if !b1 { break } argNames := s1 offset += len(s1) t = s[offset:] // data type b2, s2 := common.Tokens.MatchDataType(t) if !b2 { return gInvalidMethodArgs, "" } argDataType := s2 offset += len(s2) t = s[offset:] for _,it := range strings.Split(argNames, ",") { method.AppendArgument(it, argDataType) } // ,\s+ b3, s3 := common.Tokens.MatchRegexp(t, `\s*,\s*`) if !b3 { break } offset += len(s3) t = s[offset:] } return nil, s[0:offset] } func (me *tStructScanner) scanReturnArgs(method *domain.MethodInfo, s string) error { // todo: fixme panic("implements me") } var gStructStartRegexp = regexp.MustCompile(`^\s*type\s+(\w+)\s+struct\s+\{`) var gStructEndRegexp = regexp.MustCompile(`^\s*}`) var gFieldStartRegexp = regexp.MustCompile(`^\s*\w+\s+`) var gMethodStartRegex = regexp.MustCompile(`\s*func\s+\(\s*\w+\s+\*?(\w+)\s*\)\s+(\w+)\s*\(`) var gInvalidMethodArgs = errors.New("invalid method arguments") var DefaultStructScanner IStructScanner = new(tStructScanner)
到此,相信大家對“怎么用golang編寫基于注解的靜態(tài)代碼增強器/生成器”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。