91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么用golang實現基于注解的靜態代碼增強器/生成器

發布時間:2021-10-13 15:40:30 來源:億速云 閱讀:355 作者:iii 欄目:編程語言

本篇內容主要講解“怎么用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編寫“基于注解的靜態代碼增強器/生成器”

    • 配置: ComponentScan,Configuration, Bean

    • Bean聲明:Component, Service, Controller

    • Bean注入:Autowried

    • AOP注解:Before, After, Around, PointCut

子目標(Day 6)

  • 昨天把思路擼清楚了,今天動手實現各種詞法元素的掃描

    • project.go: 掃描整個項目的所有代碼文件。module名從go.mod文件里面取

    • packages.go: 遞歸掃描某個代碼目錄

    • files.go: 掃描某個go代碼文件,并解析import/struct/field/method等元素

    • imports: 掃描指定代碼文件的所有import

    • domain/*.go:詞法元素模型集,碼略

project.go

掃描整個項目的所有代碼文件。module名從go.mod文件里面取

package scanner

import (
	"errors"
	"io/ioutil"
	"learning/gooop/spring/autogen/common"
	"learning/gooop/spring/autogen/domain"
	"os"
	"path"
	"strings"
)

func ScanProject(name, dir string) (error, *domain.ProjectInfo) {
	e, module := parseModFileAndGetModuleName(dir)
	if e != nil {
		return e, nil
	}

	files, e := ioutil.ReadDir(dir)
	if e != nil {
		return e, nil
	}

	project := domain.NewProjectInfo()
	project.Name = name
	project.LocalDir = dir
	project.Module = module

	for _, file := range files {
		if !file.IsDir() {
			continue
		}

		e, pkg := ScanPackage(project, nil, dir+"/"+file.Name())
		if e != nil {
			return e, nil
		} else {
			project.AppendPackage(pkg)
		}
	}

	return nil, project
}

func parseModFileAndGetModuleName(dir string) (error, string) {
	modfile := path.Join(dir, gModuleFile)
	_, e := os.Stat(modfile)
	if e != nil {
		return gErrorModuleFileNotFound, ""
	}

	data, e := ioutil.ReadFile(modfile)
	if e != nil {
		return e, ""
	}

	text := string(data)
	for _, line := range strings.Split(text, "\n") {
		line := strings.TrimSpace(line)
		if !common.Tokens.MatchString(line, gModulePrefix) {
			continue
		}

		if ok, s := common.Tokens.MatchRegexp(line, gModulePattern); ok {
			return nil, strings.TrimSpace(s[len(gModulePrefix)+1:])
		}
	}

	return gErrorProjectModuleNotFound, ""
}

var gModuleFile = "go.mod"
var gModulePrefix = "module"
var gModulePattern = "^module\\s+\\w+(/\\w+)*"

var gErrorModuleFileNotFound = errors.New("module file not found: go.mod")
var gErrorProjectModuleNotFound = errors.New("project module not found in go.mod")

packages.go

遞歸掃描某個代碼目錄

package scanner

import (
	"io/ioutil"
	"learning/gooop/spring/autogen/domain"
	"path/filepath"
	"strings"
)

func ScanPackage(project *domain.ProjectInfo, parent *domain.PackageInfo, dir string) (error, *domain.PackageInfo) {
	pkg := domain.NewPackageInfo()
	pkg.Project = project
	pkg.Parent = parent
	pkg.LocalDir = dir

	_, f := filepath.Split(dir)
	pkg.Name = f

	files, e := ioutil.ReadDir(dir)
	if e != nil {
		return e, nil
	}

	for _, file := range files {
		if file.IsDir() {
			e, p := ScanPackage(project, pkg, dir+"/"+file.Name())

			if e != nil {
				return e, nil

			} else if p != nil {
				pkg.AppendPackage(p)
			}

		} else if strings.HasSuffix(file.Name(), ".go") {
			e, f := ScanCodeFile(pkg, dir+"/"+file.Name())

			if e != nil {
				return e, nil

			} else if f != nil {
				pkg.AppendFile(f)
			}
		}
	}

	return nil, pkg
}

files.go

讀入某個go代碼文件,清除注釋,然后解析import/struct/field/method等元素

package scanner

import (
	"io/ioutil"
	"learning/gooop/spring/autogen/common"
	"learning/gooop/spring/autogen/domain"
	"regexp"
	"strings"
	"unicode"
)

func ScanCodeFile(pkg *domain.PackageInfo, file string) (error, *domain.CodeFileInfo) {
	fbytes, e := ioutil.ReadFile(file)
	if e != nil {
		return e, nil
	}

	ftext := string(fbytes)
	lines := strings.Split(ftext, "\n")
	for i, it := range lines {
		lines[i] = strings.TrimRightFunc(it, unicode.IsSpace)
	}

	codeFile := domain.NewCodeFileInfo()
	codeFile.Package = pkg
	codeFile.RawLines = lines

	// clean comments
	bInParaComment := false
	cleanLines := make([]string, len(lines))
	for i, it := range lines {
		s := it

		if bInParaComment {
			// para comment end?
			i := strings.Index(it, gParaCommentEnd)
			if i >= 0 {
				bInParaComment = false
				s = s[i+1:]

			} else {
				cleanLines[i] = ""
				continue
			}
		}

		if common.Tokens.MatchString(it, gLineCommentPrefix) {
			cleanLines[i] = ""
			continue
		}

		s = removeParaCommentInLine(it)
		i1 := strings.Index(s, gParaCommentStart)
		if i1 >= 0 {
			s = s[:i1]
			bInParaComment = true
		}
		cleanLines[i] = s
	}

	// parse imports
	ScanImport(codeFile)

	// todo: parse struct declares/fields/methods

	return nil, nil
}

func removeParaCommentInLine(s string) string {
	arr := gParaCommentInLine.FindAllStringIndex(s, -1)
	if len(arr) > 0 {
		for i := len(arr) - 1; i >= 0; i-- {
			from := arr[i][0]
			to := arr[i][1]
			s = s[:from] + s[to+1:]
		}
	}

	return s
}

var gLineCommentPrefix = "^\\s*//"
var gParaCommentInLine = regexp.MustCompile("/\\*.*\\*/")
var gParaCommentStart = "/*"
var gParaCommentEnd = "*/"

imports.go

掃描指定代碼文件的所有import

package scanner

import (
	"learning/gooop/spring/autogen/domain"
	"regexp"
)

func ScanImport(file *domain.CodeFileInfo) {
	parseSingleImport(file)
	parseMultiImports(file)
}

func parseSingleImport(file *domain.CodeFileInfo) {
	for _, it := range file.CleanLines {
		if gSingleImportRegexp.MatchString(it) {
			ss := gSingleImportRegexp.FindAllStringSubmatch(it, -1)[0]
			imp := domain.NewImportInfo()
			imp.File = file

			if len(ss) == 3 {
				imp.Alias = ""
				imp.Package = ss[1]
			} else if len(ss) == 5 {
				imp.Alias = ss[1]
				imp.Package = ss[3]
			}

			file.AppendImport(imp)
		}
	}
}

func parseMultiImports(file *domain.CodeFileInfo) {
	bInBlock := false
	for _, it := range file.CleanLines {
		if bInBlock {
			if gMultiImportEnd.MatchString(it) {
				bInBlock = false
				continue
			}

			if gImportPackage.MatchString(it) {
				ss := gImportPackage.FindAllStringSubmatch(it, -1)[0]
				imp := domain.NewImportInfo()
				imp.File = file

				if len(ss) == 3 {
					imp.Alias = ""
					imp.Package = ss[1]
				} else if len(ss) == 5 {
					imp.Alias = ss[2]
					imp.Package = ss[3]
				}
			}
		}

		if gMultiImportStart.MatchString(it) {
			bInBlock = true
			continue
		}
	}
}

var gSingleImportRegexp = regexp.MustCompile(`\s*import\s+((\w+|\.)\s+)?("\w+(/\w+)*")`)
var gMultiImportStart = regexp.MustCompile(`^\s*import\s+\(`)
var gMultiImportEnd = regexp.MustCompile(`^\s*\)`)
var gImportPackage = regexp.MustCompile(`^\s*((\w+|\.)\s+)?("\w+(/\w+)*")`)

到此,相信大家對“怎么用golang實現基于注解的靜態代碼增強器/生成器”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

壤塘县| 南漳县| 赫章县| 繁峙县| 桐城市| 广饶县| 普兰店市| 凉城县| 安多县| 鹤壁市| 乌拉特中旗| 游戏| 沙洋县| 喀喇| 建瓯市| 时尚| 呼和浩特市| 阜平县| 涡阳县| 甘谷县| 绥芬河市| 宕昌县| 呼玛县| 乌拉特前旗| 兖州市| 亚东县| 苍溪县| 萨迦县| 双流县| 曲松县| 龙口市| 新巴尔虎左旗| 凤台县| 四子王旗| 龙胜| 南华县| 金沙县| 永安市| 伽师县| 新安县| 宁陕县|