Tengo

一种用于 Go 的快速脚本语言。(A fast script language for Go)

Github stars Tracking Chart

Tengo 语言

Tengo 是一种小型、动态、快速、安全的 Go 脚本语言。

Tengo 是快速和安全的,因为它是以字节码的形式在基于堆栈的虚拟机上编译/执行的,而虚拟机是用原生 Go 编写的。

/* The Tengo Language */
fmt := import("fmt")
each := func(seq, fn) {
    for x in seq { fn(x) }
}
sum := func(init, seq) {
    each(seq, func(x) { init += x })
    return init
}
fmt.println(sum(0, [1, 2, 3]))   // "6"
fmt.println(sum("", [1, 2, 3]))  // "123"

Tengo Playground 中测试这个 Tengo 代码。

特性

  • 简单且高度可读的语法
  • 动态类型化与类型强制
  • 高阶函数和闭合
  • 不可更改的价值
  • 可安全嵌入扩展
  • 用原生 Go 编写的编译器/运行时(没有外部 deps 或 cgo)。
  • 可作为独立语言执行 / REPL
  • 使用案例:规则引擎、状态机、数据管道、transpiler

基准测试

fib(35) fibt(35) 语言(类型)
Tengo 2,931ms 4ms Tengo (VM)
go-lua 4,824ms 4ms Lua (VM)
GopherLua 5,365ms 4ms Lua (VM)
goja 5,533ms 5ms JavaScript (VM)
starlark-go 11,495ms 5ms Starlark (Interpreter)
Yaegi 15,645ms 12ms Yaegi (Interpreter)
gpython 16,322ms 5ms Python (Interpreter)
otto 73,093ms 10ms JavaScript (Interpreter)
Anko 79,809ms 8ms Anko (Interpreter)
- - - -
Go 53ms 3ms Go (Native)
Lua 1,612ms 3ms Lua (Native)
Python 2,632ms 23ms Python 2 (Native)

* fib(35): Fibonacci(35)
* fibt(35): tail-call version of Fibonacci(35)
* Go does not read the source code from file, while all other cases do
* See here for commands/codes used

快速入门

go get github.com/d5/tengo/v2

一个简单的 Go 示例代码,它可以编译/运行带有一些输入/输出值的 Tengo 脚本代码。

package main
import (
    "context"
    "fmt"
    "github.com/d5/tengo/v2"
)
func main() {
    // Tengo script code
    src := `
each := func(seq, fn) {
    for x in seq { fn(x) }
}
sum := 0
mul := 1
each([a, b, c, d], func(x) {
    sum += x
    mul *= x
})`
    // create a new Script instance
    script := tengo.NewScript([]byte(src))
    // set values
    _ = script.Add("a", 1)
    _ = script.Add("b", 9)
    _ = script.Add("c", 8)
    _ = script.Add("d", 4)
    // run the script
    compiled, err := script.RunContext(context.Background())
    if err != nil {
        panic(err)
    }
    // retrieve values
    sum := compiled.Get("sum")
    mul := compiled.Get("mul")
    fmt.Println(sum, mul) // "22 288"
}

参考文献

(The first version translated by vz on 2020.08.22)

Overview

Name With Ownerd5/tengo
Primary LanguageGo
Program languageMakefile (Language Count: 2)
PlatformLinux, Mac, Windows
License:MIT License
Release Count102
Last Release Namev2.17.0 (Posted on )
First Release Namev0.9.1 (Posted on 2019-01-30 00:58:45)
Created At2019-01-09 07:17:17
Pushed At2024-04-23 11:42:39
Last Commit At2024-02-25 07:47:25
Stargazers Count3.5k
Watchers Count59
Fork Count295
Commits Count342
Has Issues Enabled
Issues Count218
Issue Open Count64
Pull Requests Count181
Pull Requests Open Count15
Pull Requests Close Count32
Has Wiki Enabled
Is Archived
Is Fork
Is Locked
Is Mirror
Is Private

The Tengo Language

GoDoc
test
Go Report Card

Tengo is a small, dynamic, fast, secure script language for Go.

Tengo is fast and secure because it's compiled/executed as
bytecode on stack-based VM that's written in native Go.

/* The Tengo Language */
fmt := import("fmt")

each := func(seq, fn) {
    for x in seq { fn(x) }
}

sum := func(init, seq) {
    each(seq, func(x) { init += x })
    return init
}

fmt.println(sum(0, [1, 2, 3]))   // "6"
fmt.println(sum("", [1, 2, 3]))  // "123"

Test this Tengo code in the
Tengo Playground

Features

Benchmark

fib(35) fibt(35) Language (Type)
Tengo 2,315ms 3ms Tengo (VM)
go-lua 4,028ms 3ms Lua (VM)
GopherLua 4,409ms 3ms Lua (VM)
goja 5,194ms 4ms JavaScript (VM)
starlark-go 6,954ms 3ms Starlark (Interpreter)
gpython 11,324ms 4ms Python (Interpreter)
Yaegi 11,715ms 10ms Yaegi (Interpreter)
otto 48,539ms 6ms JavaScript (Interpreter)
Anko 52,821ms 6ms Anko (Interpreter)
- - - -
Go 47ms 2ms Go (Native)
Lua 756ms 2ms Lua (Native)
Python 1,907ms 14ms Python2 (Native)

* fib(35):
Fibonacci(35)

* fibt(35):
tail-call version of Fibonacci(35)

* Go does not read the source code from file, while all other cases do
* See here for commands/codes used

Quick Start

go get github.com/d5/tengo/v2

A simple Go example code that compiles/runs Tengo script code with some input/output values:

package main

import (
	"context"
	"fmt"

	"github.com/d5/tengo/v2"
)

func main() {
	// create a new Script instance
	script := tengo.NewScript([]byte(
`each := func(seq, fn) {
    for x in seq { fn(x) }
}

sum := 0
mul := 1
each([a, b, c, d], func(x) {
    sum += x
    mul *= x
})`))

	// set values
	_ = script.Add("a", 1)
	_ = script.Add("b", 9)
	_ = script.Add("c", 8)
	_ = script.Add("d", 4)

	// run the script
	compiled, err := script.RunContext(context.Background())
	if err != nil {
		panic(err)
	}

	// retrieve values
	sum := compiled.Get("sum")
	mul := compiled.Get("mul")
	fmt.Println(sum, mul) // "22 288"
}

Or, if you need to evaluate a simple expression, you can use Eval function instead:

res, err := tengo.Eval(ctx,
	`input ? "success" : "fail"`,
	map[string]interface{}{"input": 1})
if err != nil {
	panic(err)
}
fmt.Println(res) // "success"

References

To the top