Compare commits

..

9 Commits

Author SHA1 Message Date
Ludovic Fernandez
373e3204b4 chore: revert stdlib improvements 2019-07-26 22:36:03 -07:00
Marc Vertes
5f41fcb8bc doc: add a Limitations section in README 2019-07-26 20:56:03 -07:00
Ludovic Fernandez
43b8594c82 feat: improve stdlib generation. 2019-07-26 17:10:04 -07:00
Marc Vertes
4c877cc348 fix: correct assign to binary interface value (#291) 2019-07-26 10:59:16 -07:00
Marc Vertes
f199520048 doc: first attempt to document goexports command 2019-07-25 23:02:03 -07:00
Taufiq Rahman
4df03252f6 doc: Fixes the title and other formattings 2019-07-25 12:06:03 -07:00
Ludovic Fernandez
2dfede3b90 doc: add playground examples. 2019-07-25 09:08:03 -07:00
Fernandez Ludovic
6191f5d38a chore: add godoc badge. 2019-07-24 22:01:51 -07:00
Ludovic Fernandez
24db786bb6 fix: exclude syslog for windows, nacl, and plan9. 2019-07-24 18:58:04 -07:00
6 changed files with 105 additions and 47 deletions

View File

@@ -4,6 +4,7 @@
[![release](https://img.shields.io/github/tag-date/containous/yaegi.svg?label=alpha)](https://github.com/containous/yaegi/releases) [![release](https://img.shields.io/github/tag-date/containous/yaegi.svg?label=alpha)](https://github.com/containous/yaegi/releases)
[![Build Status](https://travis-ci.com/containous/yaegi.svg?branch=master)](https://travis-ci.com/containous/yaegi) [![Build Status](https://travis-ci.com/containous/yaegi.svg?branch=master)](https://travis-ci.com/containous/yaegi)
[![GoDoc](https://godoc.org/github.com/containous/yaegi?status.svg)](https://godoc.org/github.com/containous/yaegi)
Yaegi is Another Elegant Go Interpreter. 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. It powers executable Go scripts and plugins, in embedded interpreters or interactive shells, on top of the Go runtime.
@@ -11,22 +12,22 @@ It powers executable Go scripts and plugins, in embedded interpreters or interac
## Features ## Features
* Complete support of [Go specification][specs] * Complete support of [Go specification][specs]
* In pure Go, using only standard library * Written in pure Go, using only the standard library
* Simple interpreter API: `New()`, `Eval()`, `Use()` * Simple interpreter API: `New()`, `Eval()`, `Use()`
* works everywhere Go works * Works everywhere Go works
* All Go & runtime resources accessible from script (with control) * All Go & runtime resources accessible from script (with control)
* Security: `unsafe` and `syscall` packages not used or exported by default * Security: `unsafe` and `syscall` packages neither used nor exported by default
* Support Go 1.11 and Go 1.12 (the latest 2 major releases) * Support Go 1.11 and Go 1.12 (the latest 2 major releases)
## Install ## Install
### As library ### Go package
```go ```go
import "github.com/containous/yaegi/interp" import "github.com/containous/yaegi/interp"
``` ```
### REPL ### Command-line executable
```bash ```bash
go get -u github.com/containous/yaegi/cmd/yaegi go get -u github.com/containous/yaegi/cmd/yaegi
@@ -37,27 +38,6 @@ and alias the `yaegi` command in `alias yaegi='rlwrap yaegi'` in your `~/.bashrc
## Usage ## Usage
### As a command line interpreter
The Yaegi command can run an interactive Read-Eval-Print-Loop:
```console
$ yaegi
> 1 + 2
3
> import "fmt"
> fmt.Println("Hello World")
Hello World
>
```
Or interpret Go files:
```console
$ yaegi cmd/yaegi/yaegi.go
>
```
### As an embedded interpreter ### As an embedded interpreter
Create an interpreter with `New()`, run Go code with `Eval()`: Create an interpreter with `New()`, run Go code with `Eval()`:
@@ -80,13 +60,15 @@ func main() {
panic(err) panic(err)
} }
_, err = i.Eval(`fmt.Println("hello")`) _, err = i.Eval(`fmt.Println("Hello Yaegi")`)
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }
``` ```
[Go Playground](https://play.golang.org/p/zzvw4VlerLP)
### As a dynamic extension framework ### As a dynamic extension framework
The following program is compiled ahead of time, except `bar()` which is interpreted, with the following steps: The following program is compiled ahead of time, except `bar()` which is interpreted, with the following steps:
@@ -123,10 +105,43 @@ func main() {
} }
``` ```
[Go Playground](https://play.golang.org/p/6SEAoaO7n0U)
### As a command-line interpreter
The Yaegi command can run an interactive Read-Eval-Print-Loop:
```console
$ yaegi
> 1 + 2
3
> import "fmt"
> fmt.Println("Hello World")
Hello World
>
```
Or interpret Go files:
```console
$ yaegi cmd/yaegi/yaegi.go
>
```
## Documentation ## Documentation
Documentation about Yaegi commands and libraries can be found at usual [godoc.org][docs]. Documentation about Yaegi commands and libraries can be found at usual [godoc.org][docs].
## 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
Yaegi is an open source project, and your feedback and contributions are needed and always welcome. Yaegi is an open source project, and your feedback and contributions are needed and always welcome.
@@ -143,3 +158,4 @@ Yaegi is an open source project, and your feedback and contributions are needed
[github]: https://github.com/containous/yaegi [github]: https://github.com/containous/yaegi
[Issues]: https://github.com/containous/yaegi/issues [Issues]: https://github.com/containous/yaegi/issues
[pull requests]: https://github.com/containous/yaegi/issues [pull requests]: https://github.com/containous/yaegi/issues
[bugs]: https://github.com/containous/yaegi/issues?q=is%3Aissue+is%3Aopen+label%3Abug

18
_test/interface9.go Normal file
View File

@@ -0,0 +1,18 @@
package main
import "fmt"
type Int int
func (I Int) String() string {
return "foo"
}
func main() {
var i Int
var st fmt.Stringer = i
fmt.Println(st.String())
}
// Output:
// foo

View File

@@ -1,8 +1,21 @@
//go:generate go build //go:generate go build
// This program generates code to register binary program symbols to the interpreter. /*
// See stdlib.go for usage Goexports generates wrappers of package exported symbols
Output files are written in the current directory, and prefixed with the go version.
Usage:
goexports package...
Example:
goexports github.com/containous/yaegi/interp
The same goexport program is used for all target operating systems and architectures.
The GOOS and GOARCH environment variables set the desired target.
*/
package main package main
import ( import (
@@ -22,7 +35,7 @@ import (
"text/template" "text/template"
) )
const model = `// +build {{.CurrentGoVersion}},!{{.NextGoVersion}} const model = `// +build {{.BuildTags}}
package {{.Dest}} package {{.Dest}}
@@ -120,6 +133,7 @@ func genContent(dest, pkgName string) ([]byte, error) {
if !o.Exported() { if !o.Exported() {
continue continue
} }
pname := path.Base(pkgName) + "." + name pname := path.Base(pkgName) + "." + name
switch o := o.(type) { switch o := o.(type) {
case *types.Const: case *types.Const:
@@ -137,11 +151,12 @@ func genContent(dest, pkgName string) ([]byte, error) {
if !f.Exported() { if !f.Exported() {
continue continue
} }
sig := f.Type().(*types.Signature)
args := make([]string, sig.Params().Len()) sign := f.Type().(*types.Signature)
args := make([]string, sign.Params().Len())
params := make([]string, len(args)) params := make([]string, len(args))
for j := range args { for j := range args {
v := sig.Params().At(j) v := sign.Params().At(j)
if args[j] = v.Name(); args[j] == "" { if args[j] = v.Name(); args[j] == "" {
args[j] = fmt.Sprintf("a%d", j) args[j] = fmt.Sprintf("a%d", j)
} }
@@ -149,16 +164,19 @@ func genContent(dest, pkgName string) ([]byte, error) {
} }
arg := "(" + strings.Join(args, ", ") + ")" arg := "(" + strings.Join(args, ", ") + ")"
param := "(" + strings.Join(params, ", ") + ")" param := "(" + strings.Join(params, ", ") + ")"
results := make([]string, sig.Results().Len())
results := make([]string, sign.Results().Len())
for j := range results { for j := range results {
v := sig.Results().At(j) v := sign.Results().At(j)
results[j] = v.Name() + " " + types.TypeString(v.Type(), qualify) results[j] = v.Name() + " " + types.TypeString(v.Type(), qualify)
} }
result := "(" + strings.Join(results, ", ") + ")" result := "(" + strings.Join(results, ", ") + ")"
ret := "" ret := ""
if sig.Results().Len() > 0 { if sign.Results().Len() > 0 {
ret = "return" ret = "return"
} }
methods = append(methods, Method{f.Name(), param, result, arg, ret}) methods = append(methods, Method{f.Name(), param, result, arg, ret})
} }
wrap[name] = Wrap{prefix + name, methods} wrap[name] = Wrap{prefix + name, methods}
@@ -181,6 +199,11 @@ func genContent(dest, pkgName string) ([]byte, error) {
return nil, fmt.Errorf("template parsing error: %v", err) return nil, fmt.Errorf("template parsing error: %v", err)
} }
buildTags := currentGoVersion + ",!" + nextGoVersion
if pkgName == "log/syslog" {
buildTags += ",!windows,!nacl,!plan9"
}
b := &bytes.Buffer{} b := &bytes.Buffer{}
data := map[string]interface{}{ data := map[string]interface{}{
"Dest": dest, "Dest": dest,
@@ -189,8 +212,7 @@ func genContent(dest, pkgName string) ([]byte, error) {
"Val": val, "Val": val,
"Typ": typ, "Typ": typ,
"Wrap": wrap, "Wrap": wrap,
"CurrentGoVersion": currentGoVersion, "BuildTags": buildTags,
"NextGoVersion": nextGoVersion,
} }
err = parse.Execute(b, data) err = parse.Execute(b, data)
if err != nil { if err != nil {

View File

@@ -223,6 +223,8 @@ func assign(n *node) {
switch { switch {
case dest.typ.cat == interfaceT: case dest.typ.cat == interfaceT:
svalue[i] = genValueInterface(src) svalue[i] = genValueInterface(src)
case dest.typ.cat == valueT && dest.typ.rtype.Kind() == reflect.Interface:
svalue[i] = genInterfaceWrapper(src, dest.typ.rtype)
case dest.typ.cat == valueT && src.typ.cat == funcT: case dest.typ.cat == valueT && src.typ.cat == funcT:
svalue[i] = genFunctionWrapper(src) svalue[i] = genFunctionWrapper(src)
case src.kind == basicLit && src.val == nil: case src.kind == basicLit && src.val == nil:

View File

@@ -1,4 +1,4 @@
// +build go1.11,!go1.12 // +build go1.11,!go1.12,!windows,!nacl,!plan9
package stdlib package stdlib

View File

@@ -1,4 +1,4 @@
// +build go1.12,!go1.13 // +build go1.12,!go1.13,!windows,!nacl,!plan9
package stdlib package stdlib