千家信息网

怎么用golang编写基于注解的静态代码增强器/生成器

发表于:2025-11-13 作者:千家信息网编辑
千家信息网最后更新 2025年11月13日,本篇内容主要讲解"怎么用golang编写基于注解的静态代码增强器/生成器",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么用golang编写基于注解的静态
千家信息网最后更新 2025年11月13日怎么用golang编写基于注解的静态代码增强器/生成器

本篇内容主要讲解"怎么用golang编写基于注解的静态代码增强器/生成器",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么用golang编写基于注解的静态代码增强器/生成器"吧!

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 commonimport (        "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 scannerimport (        "errors"        "learning/gooop/spring/autogen/common"        "learning/gooop/spring/autogen/domain"        "regexp"        "strings")type IStructScanner interface {        ScanStruct(file *domain.CodeFileInfo)}type tStructScanner intfunc (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编写基于注解的静态代码增强器/生成器"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0