4
手撸golang 仿spring ioc/aop 之7 扫码2
source link: https://my.oschina.net/ioly/blog/5021203
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
手撸golang 仿spring ioc/aop 之7 扫码2
最近阅读 [Spring Boot技术内幕: 架构设计与实现原理] (朱智胜 , 2020.6) 本系列笔记拟采用golang练习之 Talk is cheap, show me the code.
Spring
Spring的主要特性:
1. 控制反转(Inversion of Control, IoC)
2. 面向容器
3. 面向切面(AspectOriented Programming, AOP)
源码gitee地址:
https://gitee.com/ioly/learning.gooop
原文链接:
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类型都是复合类型,需递归解析
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
}
scanner/IStructScanner.go
结构体扫描器的接口及实现
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)
(未完待续)
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK