缘起

最近阅读 [Spring Boot技术内幕: 架构设计与实现原理] (朱智胜 , 2020.6)
本系列笔记拟采用golang练习之
Talk is cheap, show me the code.

Spring

  1. Spring的主要特性:
  2. 1. 控制反转(Inversion of Control, IoC
  3. 2. 面向容器
  4. 3. 面向切面(AspectOriented Programming, AOP
  5. 源码gitee地址:
  6. https://gitee.com/ioly/learning.gooop
  7. 原文链接:
  8. https://my.oschina.net/ioly

目标

  • 参考spring boot常用注解,使用golang编写“基于注解的静态代码增强器/生成器”

子目标(Day 7)

  • 今天继续the hard part:struct/field/method元素的扫描
    • common/Tokens.go:添加数据类型的词法解析支持
    • scanner/IStructScanner.go: 结构体扫描器的接口及实现

common/Tokens.go

添加数据类型的词法解析支持:

  • 分别解析基本类型/自定义类型/指针类型/数组类型/map类型
  • 自定义类型需要注意排除’map’关键字
  • 指针,数组和map类型都是复合类型,需递归解析 ```go 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()

  1. if !ok {
  2. me.rwmutex.Lock()
  3. if r, ok = me.cache[p]; !ok {
  4. r, _ = regexp.Compile(p)
  5. }
  6. me.rwmutex.Unlock()
  7. }
  8. if r == nil {
  9. return false, ""
  10. }
  11. if !r.MatchString(s) {
  12. return false, ""
  13. }
  14. 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 }

  1. b, s = me.MatchRegexp(s, "^\\\"([a-zA-Z]\\:)?([\\\\/][^/:*?<>|\\\"\\\\]+)+[\\/]?\\\"")
  2. if b {
  3. return b, s
  4. }
  5. b, s = me.MatchRegexp(s, "^'([a-zA-Z]\\:)?([\\\\/][^'/:*?<>|\\\"\\\\]+)+[\\/]?'")
  6. if b {
  7. return b, s
  8. }
  9. return false, ""

}

func (me *tTokens) MatchDataType(s string) (bool, string) { if ok,t := me.MatchBasicType(s);ok { return true, t }

  1. if ok,t := me.MatchCustomType(s);ok {
  2. return true, t
  3. }
  4. if ok,t := me.MatchPointerType(s);ok {
  5. return true, t
  6. }
  7. if ok,t := me.MatchArrayType(s);ok {
  8. return true, t
  9. }
  10. if ok,t := me.MatchMapType(s);ok {
  11. return true, t
  12. }
  13. 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 } }

  1. return false, ""

}

func (me *tTokens) MatchCustomType(s string) (bool, string) { t := s b1, s1 := me.MatchRegexp(t, ^\w+\.) if b1 { t = t[len(s1):] }

  1. b2, s2 := me.MatchRegexp(t, `^\w+`)
  2. if !b2 {
  3. return false, ""
  4. }
  5. if s2 == "map" {
  6. // map is reserved word
  7. return false, ""
  8. }
  9. return true, s1 + s2

}

func (me tTokens) MatchPointerType(s string) (bool, string) { t := s if t[0] != ‘‘ { return false,”” } t = t[1:]

  1. b, s := me.MatchDataType(t)
  2. if !b {
  3. return false, ""
  4. }
  5. 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):]

  1. b2, s2 := me.MatchDataType(t)
  2. if !b2 {
  3. return false, ""
  4. }
  5. 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):]

  1. b2, s2 := me.MatchRegexp(t, `^\s*\[\s*`)
  2. if !b2 {
  3. return false, ""
  4. }
  5. t = t[len(s2):]
  6. b3,s3 := me.MatchDataType(t)
  7. if !b3 {
  8. return false, ""
  9. }
  10. t = t[len(s3):]
  11. b4, s4 := me.MatchRegexp(t, `^\s*\]\s*`)
  12. if !b4 {
  13. return false, ""
  14. }
  15. t = t[len(s4):]
  16. b5, s5 := me.MatchDataType(t)
  17. if !b5 {
  18. return false, ""
  19. }
  20. return true, s1 + s2 + s3 + s4 + s5

}

  1. <a name="lREZ3"></a>
  2. # scanner/IStructScanner.go
  3. 结构体扫描器的接口及实现
  4. ```go
  5. package scanner
  6. import (
  7. "errors"
  8. "learning/gooop/spring/autogen/common"
  9. "learning/gooop/spring/autogen/domain"
  10. "regexp"
  11. "strings"
  12. )
  13. type IStructScanner interface {
  14. ScanStruct(file *domain.CodeFileInfo)
  15. }
  16. type tStructScanner int
  17. func (me *tStructScanner) ScanStruct(file *domain.CodeFileInfo) {
  18. bInStruct := false
  19. var stru *domain.StructInfo
  20. for lineNO,line := range file.CleanLines {
  21. if bInStruct {
  22. // end?
  23. if gStructEndRegexp.MatchString(line) {
  24. bInStruct = false
  25. me.scanMethod(stru, lineNO + 1)
  26. stru = nil
  27. continue
  28. }
  29. }
  30. // start?
  31. if gStructStartRegexp.MatchString(line) {
  32. bInStruct = true
  33. ss := gStructStartRegexp.FindAllString(line, -1)
  34. stru := domain.NewStructInfo()
  35. stru.LineNO = lineNO
  36. stru.CodeFile = file
  37. stru.Name = ss[1]
  38. continue
  39. }
  40. // in struct block
  41. ok,fname,ftype := me.scanField(line)
  42. if ok {
  43. stru.AppendField(lineNO, fname, ftype)
  44. }
  45. }
  46. }
  47. func (me *tStructScanner) scanField(line string) (ok bool, fldName string, fldType string) {
  48. if !gFieldStartRegexp.MatchString(line) {
  49. return false, "",""
  50. }
  51. fldName = strings.TrimSpace(gFieldStartRegexp.FindString(line))
  52. fldType = strings.TrimSpace(line[len(fldName):])
  53. return true, fldName, fldType
  54. }
  55. func (me *tStructScanner) scanMethod(stru *domain.StructInfo, fromLineNO int) {
  56. for i,max := fromLineNO, len(stru.CodeFile.CleanLines);i <= max;i++ {
  57. line := stru.CodeFile.CleanLines[i]
  58. if !gMethodStartRegex.MatchString(line) {
  59. continue
  60. }
  61. ss := gMethodStartRegex.FindAllString(line, -1)
  62. // declare
  63. declare := ss[0]
  64. offset := len(declare)
  65. // receiver
  66. receiver := ss[1]
  67. if receiver != stru.Name {
  68. continue
  69. }
  70. method := domain.NewMethodInfo()
  71. // name
  72. method.Name = ss[2]
  73. // method input args
  74. e,args := me.scanMethodArgs(method, strings.TrimSpace(line[offset:]))
  75. if e != nil {
  76. panic(e)
  77. }
  78. offset += len(args)
  79. // method return args
  80. e = me.scanReturnArgs(method, strings.TrimSpace(line[offset:]))
  81. if e != nil {
  82. panic(e)
  83. }
  84. // end scan method
  85. stru.AppendMethod(method)
  86. }
  87. }
  88. func (me *tStructScanner) scanMethodArgs(method *domain.MethodInfo, s string) (error, string) {
  89. t := s
  90. offset := 0
  91. for {
  92. // name
  93. b1, s1 := common.Tokens.MatchRegexp(t, `\w+(\s*,\s*\w+)\s+`)
  94. if !b1 {
  95. break
  96. }
  97. argNames := s1
  98. offset += len(s1)
  99. t = s[offset:]
  100. // data type
  101. b2, s2 := common.Tokens.MatchDataType(t)
  102. if !b2 {
  103. return gInvalidMethodArgs, ""
  104. }
  105. argDataType := s2
  106. offset += len(s2)
  107. t = s[offset:]
  108. for _,it := range strings.Split(argNames, ",") {
  109. method.AppendArgument(it, argDataType)
  110. }
  111. // ,\s+
  112. b3, s3 := common.Tokens.MatchRegexp(t, `\s*,\s*`)
  113. if !b3 {
  114. break
  115. }
  116. offset += len(s3)
  117. t = s[offset:]
  118. }
  119. return nil, s[0:offset]
  120. }
  121. func (me *tStructScanner) scanReturnArgs(method *domain.MethodInfo, s string) error {
  122. // todo: fixme
  123. panic("implements me")
  124. }
  125. var gStructStartRegexp = regexp.MustCompile(`^\s*type\s+(\w+)\s+struct\s+\{`)
  126. var gStructEndRegexp = regexp.MustCompile(`^\s*}`)
  127. var gFieldStartRegexp = regexp.MustCompile(`^\s*\w+\s+`)
  128. var gMethodStartRegex = regexp.MustCompile(`\s*func\s+\(\s*\w+\s+\*?(\w+)\s*\)\s+(\w+)\s*\(`)
  129. var gInvalidMethodArgs = errors.New("invalid method arguments")
  130. var DefaultStructScanner IStructScanner = new(tStructScanner)

(未完待续)