Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

README #1

Merged
merged 25 commits into from
Jan 13, 2019
268 changes: 268 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
# The Tengo Language

Tengo is an embedded script language for Go.

\>> **Try Tengo in online [Playground](https://tengolang.com/)** <<

## Language Features

- Simple and intuitive syntax
- Dynamically typed with type coercions
- Bytecode compiled _(see the [benchmark](#benchmark) results)_
- First-class functions and Closures
- Garbage collected _(thanks to Go runtime)_
- Easily extendible using customizable types
- Written in pure Go _(no CGO, no external dependencies)_
- Excutable as a standalone language _(without writing any Go code)_

## Benchmark

| | fib(35) | fibt(35) | Type |
| :--- | ---: | ---: | :---: |
| Go | `68,713,331` | `3,264,992` | Go (native) |
| [**Tengo**](https://github.com/d5/tengo) | `6,811,234,411` | `4,699,512` | Go-VM |
| Lua | `1,946,451,017` | `3,220,991` | Lua (native) |
| [go-lua](https://github.com/Shopify/go-lua) | `5,658,423,479` | `4,247,160` | Go-Lua-VM |
| [GopherLua](https://github.com/yuin/gopher-lua) | `6,301,424,553` | `5,194,735` | Go-Lua-VM |
| Python | `3,159,870,102` | `28,512,040` | Python (native) |
| [otto](https://github.com/robertkrimen/otto) | `91,616,109,035` | `13,780,650` | Go-JS-Interpreter |
| [Anko](https://github.com/mattn/anko) | `119,395,411,432` | `22,266,008` | Go-Interpreter |

_*Nanoseconds_

`fib(35)` is a function to calculate 35th Fibonacci number.

```golang
fib := func(x) {
if x == 0 {
return 0
} else if x == 1 {
return 1
} else {
return fib(x-1) + fib(x-2)
}
}
fib(35)
```

`fibt(35)` is a [tail-call](https://en.wikipedia.org/wiki/Tail_call) version of `fib(35)`.

```golang
fibt := func(x, a, b) {
if x == 0 {
return a
} else if x == 1 {
return b
} else {
return fibt(x-1, b, a+b)
}
}
fibt(35, 0, 1)
```

Please see [tengobench](https://github.com/d5/tengobench) for more details.

## Tengo Syntax in 5 Minutes

Tengo supports line comments (`//...`) and block comments (`/* ... */`).

```golang
/*
multi-line block comments
*/

a := 5 // line comments
```

Tengo is a dynamically typed language, and, you can initialize the variables using `:=` operator.

```golang
a := 1984 // int
b := "aomame" // string
c := -9.22 // float
d := true // bool
e := '九' // char
f := [1, false, "foo"] // array
g := { // map
h: 439,
i: 12.34,
j: [0, 9, false]
}
k := func(l, m) { // function
return l + m
}
```
After the variable is initialized, it can be re-assigned different value using `=` operator.

```golang
a := 1928 // int
a = "foo" // string
f := func() {
a := false // 'a' is defined in the function scope
a = [1, 2, 3] // and thus does not affect 'a' in global scope.
}
print(a) // still "foo"
```

Type is not explicitly specified, but, you can use type coercion functions to convert between types.

```golang
s1 := string(1984) // "1984"
i2 := int("-999") // -999
f3 := float(-51) // -51.0
b4 := bool(1) // true
c5 := char("X") // 'X'
```

You can use dot selector (`.`) and indexer (`[]`) operator to read or write elemens of arrays or maps.

```golang
["one", "two", "three"][1] // == "two"

m := {
a: 1,
b: [2, 3, 4],
c: func() { return 10 }
}
m.a // == 1
m["b"][1] // == 3
m.c() // == 10
m.x = 5 // add 'x' to map 'm'
m.b[5] = 0 // but this is an error: index out of bounds
```

For sequence types (string or array), you can use slice operator (`[:]`) too.

```golang
[1, 2, 3, 4, 5][1:3] // == [2, 3]
[1, 2, 3, 4, 5][3:] // == [4, 5]
[1, 2, 3, 4, 5][:3] // == [1, 2, 3]
"hello world"[2:10] // == "llo worl"
```

In Tengo, functions are first-class citizen and be treated like any other variables. Tengo also supports closures, functions that captures variables in outer scopes. In the following example, the function that's being returned from `adder` function is capturing `base` variable.

```golang
adder := func(base) {
return func(x) { return base + x } // capturing 'base'
}
add5 := adder(5)
nine := add5(4) // nine
```

For flow control, Tengo currently supports **if-else**, **for**, **for-in** statements.

```golang
// IF-ELSE
if a < 0 {
// ...
} else if a == 0 {
// ...
} else {
// ...
}

// IF with init statement
if a := 0; a < 10 {
// ...
} else {
// ...
}

// FOR
for a:=0; a<10; a++ {
// ...
}

// FOR condition-only (like WHILE in other languages)
for a < 10 {
// ...
}

// FOR-IN
for x in [1, 2, 3] { // array: element
// ...
}
for i, x in [1, 2, 3] { // array: index and element
// ...
}
for k, v in {k1: 1, k2: 2} { // map: key and value
// ...
}
```

## Embed Tengo in Go

...

```golang
import "github.com/d5/tengo/script"

var code = `
reduce := func(seq, fn) {
s := 0
for x in seq { fn(x, s) }
return s
}

print(reduce([1, 2, 3], func(x, s) { s += x }))
`

func main() {
s := script.New([]byte(code))
if _, err := s.Run(); err != nil {
panic(err)
}
}
```

...


## Tengo as a Standalone Language

Although Tengo is designed as an embedded script language for Go, it can be compiled and executed as native binary without any Go code using `tengo` tool.

### Installing Tengo Tool

To install `tengo` tool, run:

```bash
go get github.com/d5/tengo/cmd/tengo
```

### Compiling and Executing Tengo Code

You can directly execute the Tengo source code by running `tengo` tool with your Tengo source file (`*.tengo`).

```bash
tengo myapp.tengo
```

Or, you can compile the code into a binary file and execute it later.

```bash
tengo -c -o myapp myapp.tengo # compile 'myapp.tengo' into binary file 'myapp'
tengo myapp # execute the compiled binary `myapp`
```

### Tengo REPL

You can run Tengo [REPL](https://en.wikipedia.org/wiki/Read–eval–print_loop) if you run `tengo` with no arguments.

```bash
tengo
```

## Roadmap

The next big features planned include:

- Module system _(or packages)_
- Standard libraries
- Better documentations
- More language constructs such as error handling, object methods, switch-case statements
- Native executables compilation
- Performance improvements
- Syntax highlighter for IDEs