Yaegi

Yaegi 是另一个优雅的 Go 解释器。「Yaegi is Another Elegant Go Interpreter」

Github stars Tracking Chart







Yaegi

Yaegi 是另一个优雅的 Go 解释器。它在 Go 运行时的基础上,在嵌入式解释器或交互式 shell 中支持可执行的 Go 脚本和插件。

特性

  • 完全支持 Go 规范
  • 用纯 Go 语言编写,只使用标准库。
  • 简单的解释器 API:New(), Eval(), Use()
  • 在任何地方都可以使用 Go
  • 所有的 Go 和运行时资源都可以从脚本中访问(带控制)。
  • 安全性:默认情况下既不使用也不导出不安全和 syscall 包。
  • 支持 Go 1.13和 Go 1.14(最新的两个主要版本)。

安装

Go 包

import "github.com/traefik/yaegi/interp"

命令行可执行文件

go get -u github.com/traefik/yaegi/cmd/yaegi

请注意,你可以使用 rlwrap(用你喜欢的包管理器安装),并在你的 ~/.bashrc 中用 alias yaegi='rlwrap yaegi' 来别名 yaegi 命令,以获得历史和命令行版本。

CI 集成

curl -sfL https://raw.githubusercontent.com/traefik/yaegi/master/install.sh | bash -s -- -b $GOPATH/bin v0.9.0

用法

作为一个嵌入式解释器

用 New() 创建一个解释器,用 Eval() 运行 Go 代码。

package main
import (
    "github.com/traefik/yaegi/interp"
    "github.com/traefik/yaegi/stdlib"
)
func main() {
    i := interp.New(interp.Options{})
    i.Use(stdlib.Symbols)
    _, err := i.Eval(`import "fmt"`)
    if err != nil {
        panic(err)
    }
    _, err = i.Eval(`fmt.Println("Hello Yaegi")`)
    if err != nil {
        panic(err)
    }
}

Go Playground

作为一个动态扩展框架

下面的程序除了 bar() 被解释外,其他都是提前编译好的,步骤如下。

  1. 使用 i.Eval(src) 在解释器的上下文中评估脚本。
  2. 使用 v, err := i.Eval("foo.Bar") 从解释器上下文中获取符号,作为 reflect.Value。
  3. 应用 Interface() 方法和类型断言将 v 转换为 bar,就像编译时一样
package main
import "github.com/traefik/yaegi/interp"
const src = `package foo
func Bar(s string) string { return s + "-Foo" }`
func main() {
    i := interp.New(interp.Options{})
    _, err := i.Eval(src)
    if err != nil {
        panic(err)
    }
    v, err := i.Eval("foo.Bar")
    if err != nil {
        panic(err)
    }
    bar := v.Interface().(func(string) string)
    r := bar("Kung")
    println(r)
}

Go Playground

作为一个命令行解释器

Yaegi 命令可以运行一个交互式的 Read-Eval-Print-Loop。

$ yaegi
> 1 + 2
3
> import "fmt"
> fmt.Println("Hello World")
Hello World
>

或者解释 Go 文件

$ yaegi cmd/yaegi/yaegi.go
>

或为 Go 脚本中的 shebang 行。

$ cat /tmp/test
#!/usr/bin/env yaegi
package main
import "fmt"
func main() {
    fmt.Println("test")
}
$ ls -la /tmp/test
-rwxr-xr-x 1 dow184 dow184 93 Jan  6 13:38 /tmp/test
$ /tmp/test
test

文档

关于 Yaegi 命令和库的文档可以在 godoc.org 找到。

限制

  • 除了已知的 bugs 应该会在短期内修复,还有一些限制没有计划很快解决。
  • 不支持汇编文件(.s)。
  • 不支持调用 C 代码(没有虚拟的 "C" 包)。
  • 不能动态添加从预编译代码中使用的接口,因为需要预编译接口封装。
  • 用 reflect 来表示类型,用 %T 来打印值,在编译模式和解释模式之间可能会有不同的结果。
  • 解释计算密集型代码很可能仍然比编译模式慢很多。

贡献

贡献指南

许可证

Apache 2.0

(The first version translated by vz on 2020.09.26)

Main metrics

Overview
Name With Ownertraefik/yaegi
Primary LanguageGo
Program languageMakefile (Language Count: 4)
PlatformLinux, Mac, Windows
License:Apache License 2.0
所有者活动
Created At2018-01-10 09:39:30
Pushed At2025-05-21 20:32:04
Last Commit At2025-05-22 04:32:04
Release Count69
Last Release Namev0.16.1 (Posted on )
First Release Namev0.0.1 (Posted on )
用户参与
Stargazers Count7.7k
Watchers Count60
Fork Count381
Commits Count1.1k
Has Issues Enabled
Issues Count873
Issue Open Count151
Pull Requests Count734
Pull Requests Open Count13
Pull Requests Close Count31
项目设置
Has Wiki Enabled
Is Archived
Is Fork
Is Locked
Is Mirror
Is Private

release
Build Status
GoDoc
Discourse status

Yaegi is Another Elegant Go Interpreter.
It powers executable Go scripts and plugins, in embedded interpreters or interactive shells, on top of the Go runtime.

Features

  • Complete support of Go specification
  • Written in pure Go, using only the standard library
  • Simple interpreter API: New(), Eval(), Use()
  • Works everywhere Go works
  • All Go & runtime resources accessible from script (with control)
  • Security: unsafe and syscall packages neither used nor exported by default
  • Support Go 1.12 and Go 1.13 (the latest 2 major releases)

Install

Go package

import "github.com/containous/yaegi/interp"

Command-line executable

go get -u github.com/containous/yaegi/cmd/yaegi

Note that you can use rlwrap (install with your favorite package manager),
and alias the yaegi command in alias yaegi='rlwrap yaegi' in your ~/.bashrc, to have history and command line edition.

Usage

As an embedded interpreter

Create an interpreter with New(), run Go code with Eval():

package main

import (
	"github.com/containous/yaegi/interp"
	"github.com/containous/yaegi/stdlib"
)

func main() {
	i := interp.New(interp.Options{})

	i.Use(stdlib.Symbols)

	_, err := i.Eval(`import "fmt"`)
	if err != nil {
		panic(err)
	}

	_, err = i.Eval(`fmt.Println("Hello Yaegi")`)
	if err != nil {
		panic(err)
	}
}

Go Playground

As a dynamic extension framework

The following program is compiled ahead of time, except bar() which is interpreted, with the following steps:

  1. use of i.Eval(src) to evaluate the script in the context of interpreter
  2. use of v, err := i.Eval("foo.Bar") to get the symbol from the interpreter context, as a reflect.Value
  3. application of Interface() method and type assertion to convert v into bar, as if it was compiled
package main

import "github.com/containous/yaegi/interp"

const src = `package foo
func Bar(s string) string { return s + "-Foo" }`

func main() {
	i := interp.New(interp.Options{})

	_, err := i.Eval(src)
	if err != nil {
		panic(err)
	}

	v, err := i.Eval("foo.Bar")
	if err != nil {
		panic(err)
	}

	bar := v.Interface().(func(string) string)

	r := bar("Kung")
	println(r)
}

Go Playground

As a command-line interpreter

The Yaegi command can run an interactive Read-Eval-Print-Loop:

$ yaegi
> 1 + 2
3
> import "fmt"
> fmt.Println("Hello World")
Hello World
>

Or interpret Go files:

$ yaegi cmd/yaegi/yaegi.go
>

Or for Go scripting in the shebang line:

$ cat /tmp/test
#!/usr/bin/env yaegi
package main

import "fmt"

func main() {
	fmt.Println("test")
}
$ ls -la /tmp/test
-rwxr-xr-x 1 dow184 dow184 93 Jan  6 13:38 /tmp/test
$ /tmp/test
test

Documentation

Documentation about Yaegi commands and libraries can be found at usual godoc.org.

Limitations

Beside the known bugs which are supposed to be fixed in the short term, there are some limitations not planned to be addressed soon:

  • assembly files (.s) are not supported
  • calling C code is not supported (no virtual "C" package)
  • interfaces to be used from the pre-compiled code can not be added dynamically, as it is required to pre-compile interface wrappers
  • representation of types by reflect and printing values using %T may give different results between compiled mode and interpreted mode
  • interpreting computation intensive code is likely to remain significantly slower than in compiled mode

Contributing

Contributing guide.

License

Apache 2.0.

其他资源

traefik

Træfik, a modern reverse proxy