commit
f7b0cd8299
16 changed files with 126 additions and 139 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1 @@
|
||||||
bin/
|
dist/
|
15
.goreleaser.yml
Normal file
15
.goreleaser.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
builds:
|
||||||
|
- env:
|
||||||
|
- CGO_ENABLED=0
|
||||||
|
main: ./cmd/tengo/main.go
|
||||||
|
goos:
|
||||||
|
- darwin
|
||||||
|
- linux
|
||||||
|
- windows
|
||||||
|
archive:
|
||||||
|
files:
|
||||||
|
- none*
|
||||||
|
checksum:
|
||||||
|
name_template: 'checksums.txt'
|
||||||
|
changelog:
|
||||||
|
sort: asc
|
|
@ -8,3 +8,10 @@ install:
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- make test
|
- make test
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
- provider: script
|
||||||
|
skip_cleanup: true
|
||||||
|
script: curl -sL https://git.io/goreleaser | bash
|
||||||
|
on:
|
||||||
|
tags: true
|
41
README.md
41
README.md
|
@ -47,16 +47,16 @@ s := sum("", [1, 2, 3]) // == "123"
|
||||||
| | fib(35) | fibt(35) | Type |
|
| | fib(35) | fibt(35) | Type |
|
||||||
| :--- | ---: | ---: | :---: |
|
| :--- | ---: | ---: | :---: |
|
||||||
| Go | `58ms` | `4ms` | Go (native) |
|
| Go | `58ms` | `4ms` | Go (native) |
|
||||||
| [**Tengo**](https://github.com/d5/tengo) | `4,334ms` | `5ms` | VM on Go |
|
| [**Tengo**](https://github.com/d5/tengo) | `4,180ms` | `5ms` | VM on Go |
|
||||||
| Lua | `1,740ms` | `3ms` | Lua (native) |
|
| Lua | `1,695ms` | `3ms` | Lua (native) |
|
||||||
| [go-lua](https://github.com/Shopify/go-lua) | `5,229ms` | `5ms` | Lua VM on Go |
|
| [go-lua](https://github.com/Shopify/go-lua) | `5,163ms` | `5ms` | Lua VM on Go |
|
||||||
| [GopherLua](https://github.com/yuin/gopher-lua) | `5,486ms` | `5ms` | Lua VM on Go |
|
| [GopherLua](https://github.com/yuin/gopher-lua) | `5,525ms` | `5ms` | Lua VM on Go |
|
||||||
| Python | `3,116ms` | `27ms` | Python (native) |
|
| Python | `3,097ms` | `27ms` | Python (native) |
|
||||||
| [starlark-go](https://github.com/google/starlark-go) | `15,414ms` | `5ms` | Python-like Interpreter on Go |
|
| [starlark-go](https://github.com/google/starlark-go) | `15,307ms` | `5ms` | Python-like Interpreter on Go |
|
||||||
| [gpython](https://github.com/go-python/gpython) | `17,754ms` | `6ms` | Python Interpreter on Go |
|
| [gpython](https://github.com/go-python/gpython) | `17,656ms` | `5ms` | Python Interpreter on Go |
|
||||||
| [goja](https://github.com/dop251/goja) | `6,843ms` | `6ms` | JS VM on Go |
|
| [goja](https://github.com/dop251/goja) | `6,876ms` | `5ms` | JS VM on Go |
|
||||||
| [otto](https://github.com/robertkrimen/otto) | `86,542ms` | `13ms` | JS Interpreter on Go |
|
| [otto](https://github.com/robertkrimen/otto) | `81,886ms` | `12ms` | JS Interpreter on Go |
|
||||||
| [Anko](https://github.com/mattn/anko) | `98,962ms` | `26ms` | Interpreter on Go |
|
| [Anko](https://github.com/mattn/anko) | `97,517ms` | `14ms` | Interpreter on Go |
|
||||||
|
|
||||||
_* [fib(35)](https://github.com/d5/tengobench/blob/master/code/fib.tengo): Fibonacci(35)_
|
_* [fib(35)](https://github.com/d5/tengobench/blob/master/code/fib.tengo): Fibonacci(35)_
|
||||||
_* [fibt(35)](https://github.com/d5/tengobench/blob/master/code/fibtc.tengo): [tail-call](https://en.wikipedia.org/wiki/Tail_call) version of Fibonacci(35)_
|
_* [fibt(35)](https://github.com/d5/tengobench/blob/master/code/fibtc.tengo): [tail-call](https://en.wikipedia.org/wiki/Tail_call) version of Fibonacci(35)_
|
||||||
|
@ -72,24 +72,3 @@ _* See [here](https://github.com/d5/tengobench) for commands/codes used_
|
||||||
- [Interoperability](https://github.com/d5/tengo/blob/master/docs/interoperability.md)
|
- [Interoperability](https://github.com/d5/tengo/blob/master/docs/interoperability.md)
|
||||||
- [Tengo CLI](https://github.com/d5/tengo/blob/master/docs/tengo-cli.md)
|
- [Tengo CLI](https://github.com/d5/tengo/blob/master/docs/tengo-cli.md)
|
||||||
- [Standard Library](https://github.com/d5/tengo/blob/master/docs/stdlib.md)
|
- [Standard Library](https://github.com/d5/tengo/blob/master/docs/stdlib.md)
|
||||||
|
|
||||||
## Roadmap
|
|
||||||
|
|
||||||
### v0. _(Current)_
|
|
||||||
|
|
||||||
Things are experimental, and, the focus is on the **core language features**, **stability**, **basic interoperability**, and the **performance optimization**.
|
|
||||||
|
|
||||||
### [v1. Tengo as a Script Language](https://github.com/d5/tengo/labels/v1.0)
|
|
||||||
|
|
||||||
This will be the first _versioned_ release, and, the main goal for v1 is to make Tengo as a _fast_ embeddable script language for Go, which means Tengo will be comparable to other Go-based script languages such as [Starlark](https://github.com/google/starlark-go), [Lua](https://github.com/Shopify/go-lua) [VM](https://github.com/yuin/gopher-lua)s, and [other](https://github.com/robertkrimen/otto) [interpreter](https://github.com/mattn/anko)s.
|
|
||||||
|
|
||||||
- Interoperability with Go code
|
|
||||||
- Sandbox environment
|
|
||||||
- More language features
|
|
||||||
|
|
||||||
### v2. Tengo as a Standalone Language
|
|
||||||
|
|
||||||
- Language-level concurrency support
|
|
||||||
- Tengo Standard Libraries
|
|
||||||
- Native executables compilation
|
|
||||||
- More language features
|
|
||||||
|
|
|
@ -25,15 +25,16 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
compile bool
|
compileOutput string
|
||||||
showHelp bool
|
showHelp bool
|
||||||
outputFile = flag.String("o", "", "Output file")
|
showVersion bool
|
||||||
|
version = "dev"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.BoolVar(&showHelp, "help", false, "Show help")
|
flag.BoolVar(&showHelp, "help", false, "Show help")
|
||||||
flag.BoolVar(&compile, "compile", false, "Compile input file")
|
flag.StringVar(&compileOutput, "o", "", "Compile output file")
|
||||||
flag.BoolVar(&compile, "c", false, "Compile input file")
|
flag.BoolVar(&showVersion, "version", false, "Show version")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,12 +42,15 @@ func main() {
|
||||||
if showHelp {
|
if showHelp {
|
||||||
doHelp()
|
doHelp()
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
|
} else if showVersion {
|
||||||
|
fmt.Println(version)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
inputFile := flag.Arg(0)
|
inputFile := flag.Arg(0)
|
||||||
if inputFile == "" {
|
if inputFile == "" {
|
||||||
// REPL
|
// REPL
|
||||||
doRepl(os.Stdin, os.Stdout)
|
runREPL(os.Stdin, os.Stdout)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,18 +60,18 @@ func main() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if compile {
|
if compileOutput != "" {
|
||||||
if err := doCompile(inputData, inputFile, *outputFile); err != nil {
|
if err := compileOnly(inputData, inputFile, compileOutput); err != nil {
|
||||||
_, _ = fmt.Fprintln(os.Stderr, err.Error())
|
_, _ = fmt.Fprintln(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else if filepath.Ext(inputFile) == sourceFileExt {
|
} else if filepath.Ext(inputFile) == sourceFileExt {
|
||||||
if err := doCompileRun(inputData, inputFile, *outputFile); err != nil {
|
if err := compileAndRun(inputData, inputFile); err != nil {
|
||||||
_, _ = fmt.Fprintln(os.Stderr, err.Error())
|
_, _ = fmt.Fprintln(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := doRun(inputData, inputFile, *outputFile); err != nil {
|
if err := runCompiled(inputData); err != nil {
|
||||||
_, _ = fmt.Fprintln(os.Stderr, err.Error())
|
_, _ = fmt.Fprintln(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
@ -81,27 +85,32 @@ func doHelp() {
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println("Flags:")
|
fmt.Println("Flags:")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println(" -c/-compile compile the input and produce bytecode file")
|
fmt.Println(" -o compile output file")
|
||||||
fmt.Println(" -o output")
|
fmt.Println(" -version show version")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println("Examples:")
|
fmt.Println("Examples:")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println(" tengo")
|
fmt.Println(" tengo")
|
||||||
fmt.Println(" : Start Tengo REPL")
|
fmt.Println()
|
||||||
|
fmt.Println(" Start Tengo REPL")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println(" tengo myapp.tengo")
|
fmt.Println(" tengo myapp.tengo")
|
||||||
fmt.Println(" : Compile and execute source file (myapp.tengo)")
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println(" tengo -c myapp myapp.tengo")
|
fmt.Println(" Compile and run source file (myapp.tengo)")
|
||||||
fmt.Println(" : Compile source file (myapp.tengo) and produce bytecode file (myapp)")
|
fmt.Println(" Source file must have .tengo extension")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println(" tengo -o myapp myapp.tengo")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println(" Compile source file (myapp.tengo) into bytecode file (myapp)")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println(" tengo myapp")
|
fmt.Println(" tengo myapp")
|
||||||
fmt.Println(" : Execute bytecode file (myapp)")
|
fmt.Println()
|
||||||
|
fmt.Println(" Run bytecode file (myapp)")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
|
||||||
func doCompile(data []byte, inputFile, outputFile string) (err error) {
|
func compileOnly(data []byte, inputFile, outputFile string) (err error) {
|
||||||
bytecode, err := compileSrc(data, filepath.Base(inputFile))
|
bytecode, err := compileSrc(data, filepath.Base(inputFile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -133,7 +142,7 @@ func doCompile(data []byte, inputFile, outputFile string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func doCompileRun(data []byte, inputFile, _ string) (err error) {
|
func compileAndRun(data []byte, inputFile string) (err error) {
|
||||||
bytecode, err := compileSrc(data, filepath.Base(inputFile))
|
bytecode, err := compileSrc(data, filepath.Base(inputFile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -149,7 +158,7 @@ func doCompileRun(data []byte, inputFile, _ string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func doRun(data []byte, _, _ string) (err error) {
|
func runCompiled(data []byte) (err error) {
|
||||||
bytecode := &compiler.Bytecode{}
|
bytecode := &compiler.Bytecode{}
|
||||||
err = bytecode.Decode(bytes.NewReader(data))
|
err = bytecode.Decode(bytes.NewReader(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -166,7 +175,7 @@ func doRun(data []byte, _, _ string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func doRepl(in io.Reader, out io.Writer) {
|
func runREPL(in io.Reader, out io.Writer) {
|
||||||
stdin := bufio.NewScanner(in)
|
stdin := bufio.NewScanner(in)
|
||||||
|
|
||||||
fileSet := source.NewFileSet()
|
fileSet := source.NewFileSet()
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/d5/tengo/compiler/source"
|
"github.com/d5/tengo/compiler/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReturnStmt represents a return statement.
|
// ReturnStmt represents a return statement.
|
||||||
type ReturnStmt struct {
|
type ReturnStmt struct {
|
||||||
ReturnPos source.Pos
|
ReturnPos source.Pos
|
||||||
Results []Expr
|
Result Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ReturnStmt) stmtNode() {}
|
func (s *ReturnStmt) stmtNode() {}
|
||||||
|
@ -21,21 +19,16 @@ func (s *ReturnStmt) Pos() source.Pos {
|
||||||
|
|
||||||
// End returns the position of first character immediately after the node.
|
// End returns the position of first character immediately after the node.
|
||||||
func (s *ReturnStmt) End() source.Pos {
|
func (s *ReturnStmt) End() source.Pos {
|
||||||
if n := len(s.Results); n > 0 {
|
if s.Result != nil {
|
||||||
return s.Results[n-1].End()
|
return s.Result.End()
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.ReturnPos + 6
|
return s.ReturnPos + 6
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ReturnStmt) String() string {
|
func (s *ReturnStmt) String() string {
|
||||||
if len(s.Results) > 0 {
|
if s.Result != nil {
|
||||||
var res []string
|
return "return " + s.Result.String()
|
||||||
for _, e := range s.Results {
|
|
||||||
res = append(res, e.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return "return " + strings.Join(res, ", ")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "return"
|
return "return"
|
||||||
|
|
|
@ -85,4 +85,5 @@ func init() {
|
||||||
gob.Register(&objects.MapIterator{})
|
gob.Register(&objects.MapIterator{})
|
||||||
gob.Register(&objects.ArrayIterator{})
|
gob.Register(&objects.ArrayIterator{})
|
||||||
gob.Register(&objects.Time{})
|
gob.Register(&objects.Time{})
|
||||||
|
gob.Register(&objects.CompiledModule{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,20 +69,20 @@ func TestBytecode(t *testing.T) {
|
||||||
compiler.MakeInstruction(compiler.OpAdd),
|
compiler.MakeInstruction(compiler.OpAdd),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpAdd),
|
compiler.MakeInstruction(compiler.OpAdd),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)),
|
compiler.MakeInstruction(compiler.OpReturnValue)),
|
||||||
compiledFunction(1, 0,
|
compiledFunction(1, 0,
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 2),
|
compiler.MakeInstruction(compiler.OpConstant, 2),
|
||||||
compiler.MakeInstruction(compiler.OpSetLocal, 0),
|
compiler.MakeInstruction(compiler.OpSetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpGetFree, 0),
|
compiler.MakeInstruction(compiler.OpGetFree, 0),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpClosure, 4, 2),
|
compiler.MakeInstruction(compiler.OpClosure, 4, 2),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)),
|
compiler.MakeInstruction(compiler.OpReturnValue)),
|
||||||
compiledFunction(1, 0,
|
compiledFunction(1, 0,
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 1),
|
compiler.MakeInstruction(compiler.OpConstant, 1),
|
||||||
compiler.MakeInstruction(compiler.OpSetLocal, 0),
|
compiler.MakeInstruction(compiler.OpSetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpClosure, 5, 1),
|
compiler.MakeInstruction(compiler.OpClosure, 5, 1),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
compiler.MakeInstruction(compiler.OpReturnValue)))))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBytecodeSerialization(t *testing.T, b *compiler.Bytecode) {
|
func testBytecodeSerialization(t *testing.T, b *compiler.Bytecode) {
|
||||||
|
|
|
@ -426,17 +426,14 @@ func (c *Compiler) Compile(node ast.Node) error {
|
||||||
return fmt.Errorf("return statement outside function")
|
return fmt.Errorf("return statement outside function")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch len(node.Results) {
|
if node.Result == nil {
|
||||||
case 0:
|
|
||||||
c.emit(OpReturn)
|
c.emit(OpReturn)
|
||||||
case 1:
|
} else {
|
||||||
if err := c.Compile(node.Results[0]); err != nil {
|
if err := c.Compile(node.Result); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.emit(OpReturnValue, 1)
|
c.emit(OpReturnValue)
|
||||||
default:
|
|
||||||
return fmt.Errorf("multi-value return not implemented")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
|
|
|
@ -446,7 +446,7 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 0),
|
compiler.MakeInstruction(compiler.OpConstant, 0),
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 1),
|
compiler.MakeInstruction(compiler.OpConstant, 1),
|
||||||
compiler.MakeInstruction(compiler.OpAdd),
|
compiler.MakeInstruction(compiler.OpAdd),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
compiler.MakeInstruction(compiler.OpReturnValue)))))
|
||||||
|
|
||||||
expect(t, `func() { 5 + 10 }`,
|
expect(t, `func() { 5 + 10 }`,
|
||||||
bytecode(
|
bytecode(
|
||||||
|
@ -490,7 +490,7 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 0),
|
compiler.MakeInstruction(compiler.OpConstant, 0),
|
||||||
compiler.MakeInstruction(compiler.OpPop),
|
compiler.MakeInstruction(compiler.OpPop),
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 1),
|
compiler.MakeInstruction(compiler.OpConstant, 1),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
compiler.MakeInstruction(compiler.OpReturnValue)))))
|
||||||
|
|
||||||
expect(t, `func() { if(true) { return 1 } else { return 2 } }`,
|
expect(t, `func() { if(true) { return 1 } else { return 2 } }`,
|
||||||
bytecode(
|
bytecode(
|
||||||
|
@ -501,13 +501,13 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
intObject(1),
|
intObject(1),
|
||||||
intObject(2),
|
intObject(2),
|
||||||
compiledFunction(0, 0,
|
compiledFunction(0, 0,
|
||||||
compiler.MakeInstruction(compiler.OpTrue), // 0000
|
compiler.MakeInstruction(compiler.OpTrue), // 0000
|
||||||
compiler.MakeInstruction(compiler.OpJumpFalsy, 12), // 0001
|
compiler.MakeInstruction(compiler.OpJumpFalsy, 11), // 0001
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 0), // 0004
|
compiler.MakeInstruction(compiler.OpConstant, 0), // 0004
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1), // 0007
|
compiler.MakeInstruction(compiler.OpReturnValue), // 0007
|
||||||
compiler.MakeInstruction(compiler.OpJump, 17), // 0009
|
compiler.MakeInstruction(compiler.OpJump, 15), // 0008
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 1), // 0012
|
compiler.MakeInstruction(compiler.OpConstant, 1), // 0011
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1))))) // 0014
|
compiler.MakeInstruction(compiler.OpReturnValue))))) // 0014
|
||||||
|
|
||||||
expect(t, `func() { 1; if(true) { 2 } else { 3 }; 4 }`,
|
expect(t, `func() { 1; if(true) { 2 } else { 3 }; 4 }`,
|
||||||
bytecode(
|
bytecode(
|
||||||
|
@ -564,7 +564,7 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
intObject(24),
|
intObject(24),
|
||||||
compiledFunction(0, 0,
|
compiledFunction(0, 0,
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 0),
|
compiler.MakeInstruction(compiler.OpConstant, 0),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
compiler.MakeInstruction(compiler.OpReturnValue)))))
|
||||||
|
|
||||||
expect(t, `noArg := func() { 24 }; noArg();`,
|
expect(t, `noArg := func() { 24 }; noArg();`,
|
||||||
bytecode(
|
bytecode(
|
||||||
|
@ -593,7 +593,7 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
intObject(24),
|
intObject(24),
|
||||||
compiledFunction(0, 0,
|
compiledFunction(0, 0,
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 0),
|
compiler.MakeInstruction(compiler.OpConstant, 0),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
compiler.MakeInstruction(compiler.OpReturnValue)))))
|
||||||
|
|
||||||
expect(t, `n := 55; func() { n };`,
|
expect(t, `n := 55; func() { n };`,
|
||||||
bytecode(
|
bytecode(
|
||||||
|
@ -620,23 +620,7 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 0),
|
compiler.MakeInstruction(compiler.OpConstant, 0),
|
||||||
compiler.MakeInstruction(compiler.OpDefineLocal, 0),
|
compiler.MakeInstruction(compiler.OpDefineLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
compiler.MakeInstruction(compiler.OpReturnValue)))))
|
||||||
|
|
||||||
expect(t, `func() { n := 55; n = 23; return n }`,
|
|
||||||
bytecode(
|
|
||||||
concat(
|
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 2),
|
|
||||||
compiler.MakeInstruction(compiler.OpPop)),
|
|
||||||
objectsArray(
|
|
||||||
intObject(55),
|
|
||||||
intObject(23),
|
|
||||||
compiledFunction(1, 0,
|
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 0),
|
|
||||||
compiler.MakeInstruction(compiler.OpDefineLocal, 0),
|
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 1),
|
|
||||||
compiler.MakeInstruction(compiler.OpSetLocal, 0),
|
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
|
||||||
|
|
||||||
expect(t, `func() { a := 55; b := 77; return a + b }`,
|
expect(t, `func() { a := 55; b := 77; return a + b }`,
|
||||||
bytecode(
|
bytecode(
|
||||||
|
@ -654,7 +638,7 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 1),
|
compiler.MakeInstruction(compiler.OpGetLocal, 1),
|
||||||
compiler.MakeInstruction(compiler.OpAdd),
|
compiler.MakeInstruction(compiler.OpAdd),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
compiler.MakeInstruction(compiler.OpReturnValue)))))
|
||||||
|
|
||||||
expect(t, `f1 := func(a) { return a }; f1(24);`,
|
expect(t, `f1 := func(a) { return a }; f1(24);`,
|
||||||
bytecode(
|
bytecode(
|
||||||
|
@ -668,7 +652,7 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
objectsArray(
|
objectsArray(
|
||||||
compiledFunction(1, 1,
|
compiledFunction(1, 1,
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)),
|
compiler.MakeInstruction(compiler.OpReturnValue)),
|
||||||
intObject(24))))
|
intObject(24))))
|
||||||
|
|
||||||
expect(t, `f1 := func(a, b, c) { a; b; return c; }; f1(24, 25, 26);`,
|
expect(t, `f1 := func(a, b, c) { a; b; return c; }; f1(24, 25, 26);`,
|
||||||
|
@ -689,11 +673,26 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 1),
|
compiler.MakeInstruction(compiler.OpGetLocal, 1),
|
||||||
compiler.MakeInstruction(compiler.OpPop),
|
compiler.MakeInstruction(compiler.OpPop),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 2),
|
compiler.MakeInstruction(compiler.OpGetLocal, 2),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)),
|
compiler.MakeInstruction(compiler.OpReturnValue)),
|
||||||
intObject(24),
|
intObject(24),
|
||||||
intObject(25),
|
intObject(25),
|
||||||
intObject(26))))
|
intObject(26))))
|
||||||
|
|
||||||
|
expect(t, `func() { n := 55; n = 23; return n }`,
|
||||||
|
bytecode(
|
||||||
|
concat(
|
||||||
|
compiler.MakeInstruction(compiler.OpConstant, 2),
|
||||||
|
compiler.MakeInstruction(compiler.OpPop)),
|
||||||
|
objectsArray(
|
||||||
|
intObject(55),
|
||||||
|
intObject(23),
|
||||||
|
compiledFunction(1, 0,
|
||||||
|
compiler.MakeInstruction(compiler.OpConstant, 0),
|
||||||
|
compiler.MakeInstruction(compiler.OpDefineLocal, 0),
|
||||||
|
compiler.MakeInstruction(compiler.OpConstant, 1),
|
||||||
|
compiler.MakeInstruction(compiler.OpSetLocal, 0),
|
||||||
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
|
compiler.MakeInstruction(compiler.OpReturnValue)))))
|
||||||
expect(t, `len([]);`,
|
expect(t, `len([]);`,
|
||||||
bytecode(
|
bytecode(
|
||||||
concat(
|
concat(
|
||||||
|
@ -713,7 +712,7 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
compiler.MakeInstruction(compiler.OpGetBuiltin, 3),
|
compiler.MakeInstruction(compiler.OpGetBuiltin, 3),
|
||||||
compiler.MakeInstruction(compiler.OpArray, 0),
|
compiler.MakeInstruction(compiler.OpArray, 0),
|
||||||
compiler.MakeInstruction(compiler.OpCall, 1),
|
compiler.MakeInstruction(compiler.OpCall, 1),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
compiler.MakeInstruction(compiler.OpReturnValue)))))
|
||||||
|
|
||||||
expect(t, `func(a) { func(b) { return a + b } }`,
|
expect(t, `func(a) { func(b) { return a + b } }`,
|
||||||
bytecode(
|
bytecode(
|
||||||
|
@ -725,7 +724,7 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
compiler.MakeInstruction(compiler.OpGetFree, 0),
|
compiler.MakeInstruction(compiler.OpGetFree, 0),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpAdd),
|
compiler.MakeInstruction(compiler.OpAdd),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)),
|
compiler.MakeInstruction(compiler.OpReturnValue)),
|
||||||
compiledFunction(1, 1,
|
compiledFunction(1, 1,
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpClosure, 0, 1),
|
compiler.MakeInstruction(compiler.OpClosure, 0, 1),
|
||||||
|
@ -751,16 +750,16 @@ func(a) {
|
||||||
compiler.MakeInstruction(compiler.OpAdd),
|
compiler.MakeInstruction(compiler.OpAdd),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpAdd),
|
compiler.MakeInstruction(compiler.OpAdd),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)),
|
compiler.MakeInstruction(compiler.OpReturnValue)),
|
||||||
compiledFunction(1, 1,
|
compiledFunction(1, 1,
|
||||||
compiler.MakeInstruction(compiler.OpGetFree, 0),
|
compiler.MakeInstruction(compiler.OpGetFree, 0),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpClosure, 0, 2),
|
compiler.MakeInstruction(compiler.OpClosure, 0, 2),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)),
|
compiler.MakeInstruction(compiler.OpReturnValue)),
|
||||||
compiledFunction(1, 1,
|
compiledFunction(1, 1,
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpClosure, 1, 1),
|
compiler.MakeInstruction(compiler.OpClosure, 1, 1),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
compiler.MakeInstruction(compiler.OpReturnValue)))))
|
||||||
|
|
||||||
expect(t, `
|
expect(t, `
|
||||||
g := 55;
|
g := 55;
|
||||||
|
@ -799,20 +798,20 @@ func() {
|
||||||
compiler.MakeInstruction(compiler.OpAdd),
|
compiler.MakeInstruction(compiler.OpAdd),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpAdd),
|
compiler.MakeInstruction(compiler.OpAdd),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)),
|
compiler.MakeInstruction(compiler.OpReturnValue)),
|
||||||
compiledFunction(1, 0,
|
compiledFunction(1, 0,
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 2),
|
compiler.MakeInstruction(compiler.OpConstant, 2),
|
||||||
compiler.MakeInstruction(compiler.OpDefineLocal, 0),
|
compiler.MakeInstruction(compiler.OpDefineLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpGetFree, 0),
|
compiler.MakeInstruction(compiler.OpGetFree, 0),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpClosure, 4, 2),
|
compiler.MakeInstruction(compiler.OpClosure, 4, 2),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)),
|
compiler.MakeInstruction(compiler.OpReturnValue)),
|
||||||
compiledFunction(1, 0,
|
compiledFunction(1, 0,
|
||||||
compiler.MakeInstruction(compiler.OpConstant, 1),
|
compiler.MakeInstruction(compiler.OpConstant, 1),
|
||||||
compiler.MakeInstruction(compiler.OpDefineLocal, 0),
|
compiler.MakeInstruction(compiler.OpDefineLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
compiler.MakeInstruction(compiler.OpGetLocal, 0),
|
||||||
compiler.MakeInstruction(compiler.OpClosure, 5, 1),
|
compiler.MakeInstruction(compiler.OpClosure, 5, 1),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
compiler.MakeInstruction(compiler.OpReturnValue)))))
|
||||||
|
|
||||||
expect(t, `for i:=0; i<10; i++ {}`,
|
expect(t, `for i:=0; i<10; i++ {}`,
|
||||||
bytecode(
|
bytecode(
|
||||||
|
|
|
@ -157,7 +157,7 @@ var OpcodeOperands = [...][]int{
|
||||||
OpSliceIndex: {},
|
OpSliceIndex: {},
|
||||||
OpCall: {1},
|
OpCall: {1},
|
||||||
OpReturn: {},
|
OpReturn: {},
|
||||||
OpReturnValue: {1},
|
OpReturnValue: {},
|
||||||
OpGetLocal: {1},
|
OpGetLocal: {1},
|
||||||
OpSetLocal: {1},
|
OpSetLocal: {1},
|
||||||
OpDefineLocal: {1},
|
OpDefineLocal: {1},
|
||||||
|
|
|
@ -862,15 +862,15 @@ func (p *Parser) parseReturnStmt() ast.Stmt {
|
||||||
pos := p.pos
|
pos := p.pos
|
||||||
p.expect(token.Return)
|
p.expect(token.Return)
|
||||||
|
|
||||||
var x []ast.Expr
|
var x ast.Expr
|
||||||
if p.token != token.Semicolon && p.token != token.RBrace {
|
if p.token != token.Semicolon && p.token != token.RBrace {
|
||||||
x = p.parseExprList()
|
x = p.parseExpr()
|
||||||
}
|
}
|
||||||
p.expectSemi()
|
p.expectSemi()
|
||||||
|
|
||||||
return &ast.ReturnStmt{
|
return &ast.ReturnStmt{
|
||||||
ReturnPos: pos,
|
ReturnPos: pos,
|
||||||
Results: x,
|
Result: x,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,8 +144,8 @@ func emptyStmt(implicit bool, pos source.Pos) *ast.EmptyStmt {
|
||||||
return &ast.EmptyStmt{Implicit: implicit, Semicolon: pos}
|
return &ast.EmptyStmt{Implicit: implicit, Semicolon: pos}
|
||||||
}
|
}
|
||||||
|
|
||||||
func returnStmt(pos source.Pos, results ...ast.Expr) *ast.ReturnStmt {
|
func returnStmt(pos source.Pos, result ast.Expr) *ast.ReturnStmt {
|
||||||
return &ast.ReturnStmt{Results: results, ReturnPos: pos}
|
return &ast.ReturnStmt{Result: result, ReturnPos: pos}
|
||||||
}
|
}
|
||||||
|
|
||||||
func forStmt(init ast.Stmt, cond ast.Expr, post ast.Stmt, body *ast.BlockStmt, pos source.Pos) *ast.ForStmt {
|
func forStmt(init ast.Stmt, cond ast.Expr, post ast.Stmt, body *ast.BlockStmt, pos source.Pos) *ast.ForStmt {
|
||||||
|
@ -309,7 +309,7 @@ func equalStmt(t *testing.T, expected, actual ast.Stmt) bool {
|
||||||
equalStmt(t, expected.Body, actual.(*ast.ForInStmt).Body) &&
|
equalStmt(t, expected.Body, actual.(*ast.ForInStmt).Body) &&
|
||||||
assert.Equal(t, expected.ForPos, actual.(*ast.ForInStmt).ForPos)
|
assert.Equal(t, expected.ForPos, actual.(*ast.ForInStmt).ForPos)
|
||||||
case *ast.ReturnStmt:
|
case *ast.ReturnStmt:
|
||||||
return equalExprs(t, expected.Results, actual.(*ast.ReturnStmt).Results) &&
|
return equalExpr(t, expected.Result, actual.(*ast.ReturnStmt).Result) &&
|
||||||
assert.Equal(t, expected.ReturnPos, actual.(*ast.ReturnStmt).ReturnPos)
|
assert.Equal(t, expected.ReturnPos, actual.(*ast.ReturnStmt).ReturnPos)
|
||||||
case *ast.BranchStmt:
|
case *ast.BranchStmt:
|
||||||
return equalExpr(t, expected.Label, actual.(*ast.BranchStmt).Label) &&
|
return equalExpr(t, expected.Label, actual.(*ast.BranchStmt).Label) &&
|
||||||
|
|
|
@ -62,7 +62,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the compiled bytecode
|
// run the compiled bytecode
|
||||||
// a compiled bytecode 'c' can be executed multiple without re-compiling it
|
// a compiled bytecode 'c' can be executed multiple times without re-compiling it
|
||||||
if err := c.Run(); err != nil {
|
if err := c.Run(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ To install `tengo` tool, run:
|
||||||
go get github.com/d5/tengo/cmd/tengo
|
go get github.com/d5/tengo/cmd/tengo
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Or, you can download the precompiled binaries from [here](https://github.com/d5/tengo/releases/latest).
|
||||||
|
|
||||||
## Compiling and Executing Tengo Code
|
## Compiling and Executing Tengo Code
|
||||||
|
|
||||||
You can directly execute the Tengo source code by running `tengo` tool with your Tengo source file (`*.tengo`).
|
You can directly execute the Tengo source code by running `tengo` tool with your Tengo source file (`*.tengo`).
|
||||||
|
@ -21,8 +23,8 @@ tengo myapp.tengo
|
||||||
Or, you can compile the code into a binary file and execute it later.
|
Or, you can compile the code into a binary file and execute it later.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tengo -c -o myapp myapp.tengo # compile 'myapp.tengo' into binary file 'myapp'
|
tengo -o myapp myapp.tengo # compile 'myapp.tengo' into binary file 'myapp'
|
||||||
tengo myapp # execute the compiled binary `myapp`
|
tengo myapp # execute the compiled binary `myapp`
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tengo REPL
|
## Tengo REPL
|
||||||
|
|
|
@ -785,16 +785,6 @@ func (v *VM) Run() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
case compiler.OpReturnValue:
|
case compiler.OpReturnValue:
|
||||||
//numRets := int(compiler.ReadUint8(v.curInsts[v.ip+1:]))
|
|
||||||
//_ = int64(compiler.ReadUint8(v.curInsts[v.ip+1:]))
|
|
||||||
v.ip++
|
|
||||||
|
|
||||||
// TODO: multi-value return is not fully implemented yet
|
|
||||||
//var rets []*objects.Object
|
|
||||||
//for i := 0; i < numRets; i++ {
|
|
||||||
// val := v.pop()
|
|
||||||
// rets = append(rets, val)
|
|
||||||
//}
|
|
||||||
retVal := v.stack[v.sp-1]
|
retVal := v.stack[v.sp-1]
|
||||||
//v.sp--
|
//v.sp--
|
||||||
|
|
||||||
|
@ -808,11 +798,6 @@ func (v *VM) Run() error {
|
||||||
//v.sp = lastFrame.basePointer - 1
|
//v.sp = lastFrame.basePointer - 1
|
||||||
v.sp = lastFrame.basePointer
|
v.sp = lastFrame.basePointer
|
||||||
|
|
||||||
//for _, retVal := range rets {
|
|
||||||
// if err := v.push(retVal); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
if v.sp-1 >= StackSize {
|
if v.sp-1 >= StackSize {
|
||||||
return ErrStackOverflow
|
return ErrStackOverflow
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue