-
Notifications
You must be signed in to change notification settings - Fork 4
Open
Description
初步使用
XGO声明,类似于gop.mod,需要声明项目信息:
xgobuild.RegisterProject(&modfile.Project{
Ext: "_llar.gox",
Class: "FormulaApp",
Works: nil,
PkgPaths: nil,
Import: nil,
})Work:如果不为空,一个Project里面会存在多个基类,以文件后缀进行区分
PkgPaths:主要是解决泛性问题,和ixgo实现有关系(ixgo通过reflect模块进行动态函数调用,但是reflect暂时不支持泛性)
Import:添加模块导入
执行
完成项目注册后,就可以添加相关文件进行执行
ctx := ixgo.NewContext(0)
// XGO 编译成Go 代码
source, err := xgobuild.BuildFSDir(ctx, fs, "")
if err != nil {
panic(fmt.Errorf("Failed to build XGo source: %w", err))
}
// 生成解释器需要的SSA Package结构
pkg, err := ctx.LoadFile("main.go", source)
if err != nil {
panic(fmt.Errorf("Failed to load XGo source: %w", err))
}
// 新建运行时解释器
interp, err := ctx.NewInterp(pkg)
if err != nil {
panic(fmt.Errorf("Failed to create interp: %w", err))
}
// 执行,这个main.go只是名称,并不影响执行
code, err := ctx.RunInterp(interp, "main.go", source)
if err != nil {
panic(fmt.Errorf("Failed to run XGo source (code %d): %w", code, err))
}ixgo原理
ixgo是XGO运行时解释器,与常规Go静态编译不一样,ixgo允许动态执行XGO语言
其原理就是通过Go的reflect模块。如果是XGO文件,会先编译成Go。解析Go AST后,完成SSA编译。得到SSA格式后,再对其进行reflect类型翻译,和修改函数调用。
具体流程
graph TD
A[输入XGO文件] --> B[XGO源码]
B --> C[Go源码]
C --> |解析|D[Go AST]
D --> |生成|E[Go SSA]
E --> |翻译|F[Reflect 指令]
F --> |运行|G[调用 Reflect 指令]
函数调用边界
分为External和Builtin两类,这两类一般是,无法获取SSA的,例如cgo和ASM调用,或者通过Go编译器直接生成无具体实现的函数。
这两类前者会查找签名,并通过reflect.Call进行调用,后者则通过reflect.Copy类似的函数进行模拟
额外功能
自定义模块查找
ctx := ixgo.NewContext(0)
ctx.Lookup = func(root string, path string) (dir string, found bool) {
// 传入当前project根目录和查找的Module Path
// 返回Module Path所在的目录
}如果自定义查找找不到,会自动回退到Go Module查找
RegisterExternal
为声明函数注册具体实现
package main
import "fmt"
type myint int
type point struct {
x int
y int
}
func mytest1(n myint, pt point) myint
func mytest2(n myint, pt *point) myint
func main() {
n := mytest1(100, point{100,200})
if n != 400 {
panic(fmt.Errorf("error mytest1, must 400, have %v",n))
}
n = mytest2(100, &point{100,200})
if n != 30000 {
panic(fmt.Errorf("error mytest2, must 30000, have %v",n))
}
}ixgo部分:
ctx := ixgo.NewContext(0)
ixgo.RegisterExternal("main.mytest1", func(n int, pt struct {
x int
y int
}) int {
return n + pt.x + pt.y
})
ctx.RegisterExternal("main.mytest2", func(n int, pt *struct {
x int
y int
}) int {
return n * (pt.x + pt.y)
})
_, err := ctx.RunFile("main.go", src, nil)
if err != nil {
t.Fatal(err)
}如果已经存在对应符号,那么ixgo优先查找RegisterExternal实现
RegisterPatch
给指定package的特定函数进行patch操作
patch操作用于添加额外函数
package main
import "fmt"
func main() {
fmt.Println1(fmt.Pi,fmt.Patch)
fmt.Println2("hello world")
}ixgo代码:
ctx := ixgo.NewContext(0)
err := ctx.RegisterPatch("fmt", `
package fmt
import (
"fmt"
"math"
)
const Pi = math.Pi
var (
Patch = "v1.0"
)
func Println1(v ...interface{}) {
fmt.Println(v...)
}
`)
if err != nil {
t.Fatal(err)
}
err = ctx.RegisterPatch("fmt", `
package fmt
import "fmt"
func Println2(v ...interface{}) {
fmt.Println(v...)
}
`)RegisterCustomBuiltin
添加自定义Go Builtin函数
package main
import "fmt"
func main() {
fmt.Println(typeof("hello"))
}ixgo 代码:
ixgo.RegisterCustomBuiltin("typeof", reflect.TypeOf)RegisterPackage
注册一个Package
type Package struct {
// 类型信息
Interfaces map[string]reflect.Type
NamedTypes map[string]reflect.Type
AliasTypes map[string]reflect.Type
Vars map[string]reflect.Value
Funcs map[string]reflect.Value
TypedConsts map[string]TypedConst
UntypedConsts map[string]UntypedConst
// Package 依赖
Deps map[string]string // K->V: path -> name
// Package ModuleName
Name string
// Package ModulePath
Path string
Source string
}AddImport
为当前构建项目导入package
Metadata
Metadata
Assignees
Labels
No labels