Commit Graph

766 Commits

Author SHA1 Message Date
Marc Vertes
9ddecfa121 fix: correct index for embedded binary method receiver
When searching for a binary method on structures, look up on embedded
fields first, otherwise the resulting index is incorrect, as
reflect.Type.MethodByName succeeds also on container struct.

Fixes #834.
2020-09-09 12:22:03 +02:00
mpl
04770a4b81 interp: fix data races (#839)
This change fixes two distinct data races:

1) some global vars of type *itype of the interp package are actually
mutated during the lifecycle of an Interpreter. Even worse: if more than
one Interpreter instance are created and used at a given time, they are
actually racing each other for these global vars.
Therefore, this change replaces these global vars with generator
functions that create the needed type on the fly.

2) the symbols given as argument of Interpreter.Use were directly copied
as reference (since they're maps) when mapped inside an Interpreter
instance. Since the usual case is to give the symbols from the stdlib
package, it means when the interpreter mutates its own symbols in
fixStdio, it would actually mutate the corresponding global vars of the
stdlib package. Again, this is at least racy as soon as several
instances of an Intepreter are concurrently running.
This change fixes the race by making sure Interpreter.Use actually
copies the symbol values instead of copying the references.
2020-09-09 11:59:07 +02:00
Marc Vertes
341c69d922 feat: configure stdin, stdout and stderr per interpreter
The goal is to provide greater control of input, output and error
streams of the interpreter. It is now possible to specify those
as options when creating a new interpreter. The provided values
are propagated to relevant stdlib symbols (i.e fmt.Print, etc).
Care is taken to not update the global variables os.Stdout, os.Stdin
and os.Stderr, as to not interfere with the host process.

The REPL function is now simplified. The deprecated version is removed.

The tests are updated to take advantage of the simplified access
to the interpreter output and errors.

Fixes #752.
2020-08-31 15:42:03 +02:00
mpl
f4cc059e3e TestEvalScanner: "fix" data race
When running TestEvalScanner with -race=true, one can observe a data race such as:

```
WARNING: DATA RACE
Read at 0x0000029f3d68 by goroutine 52:
  github.com/containous/yaegi/interp.(*itype).defaultType()
      /Users/mpl/src/github.com/containous/yaegi/interp/type.go:1466 +0x572
...
  github.com/containous/yaegi/interp.(*Interpreter).EvalWithContext.func1()
      /Users/mpl/src/github.com/containous/yaegi/interp/interp.go:501 +0xf0

Previous write at 0x0000029f3d68 by goroutine 43:
  github.com/containous/yaegi/interp.(*itype).refType()
      /Users/mpl/src/github.com/containous/yaegi/interp/type.go:1419 +0x854
  github.com/containous/yaegi/interp.(*itype).TypeOf()
      /Users/mpl/src/github.com/containous/yaegi/interp/type.go:1427 +0xa6
...
  github.com/containous/yaegi/interp.(*Interpreter).EvalWithContext.func1()
      /Users/mpl/src/github.com/containous/yaegi/interp/interp.go:501 +0xf0
```

Before this change, since closing the pipe to the REPL is done in a defer, it
means that all the i.REPL calls (and hence each goroutine for each of these
calls) are kept running and alive until the very end of the test. It should not
matter, since a new interpreter is created for each test case, and thus all the
i.REPL calls should be completely independent from each other.

And yet, by wrapping each test case in a function call, and thus making each
i.REPL call terminate as soon as the test case is over, the data race seems to
be fixed. This could suggest that the separate i.REPL calls from separate
interpreter instances are somehow sharing some memory, but I do not know how to
explain that.

The problem has yet to be fully understood, but at least this change restores
the test, without making the CI fail again.
2020-08-31 12:46:03 +02:00
mpl
535e7e1c42 interp: enable declaration errors detection at parsing time
The Go parser is able to detect some (but not all) (re-)decleration errors,
if the DeclarationErrors flag is enabled, which was not done so far.

This PR therefore enables that flag, which allows the removal of some of
the now unneeded code that was recently added to support redeclarations.

Fixes #811
2020-08-28 14:36:00 +02:00
mpl
cb0f3a77bb REPL: retry with full wrapping for anonymous func calls
In interactive mode, a line starting with the "func" keyword is usually
"wrapped", by prepending to it a "package main" statement, to make it
a valid piece of Go source code.

However, when the line is actually an anonymous function call, such as:

func() { println(3) }()

then this wrapping is not enough, as this is not valid Go in the global
context. Therefore, this kind of of expression must also be wrapped
inside a main func (as is the default case for most REPL inputs).

Since the detection and handling of such a case turned out to be quite
unelegant, this PR instead introduces a retrying phase when a parsing
error occurs for a particular class of cases. That is to say, when a
"func expression" wrapped in a main package fails to be parsed, it is
then wrapped in a main func before parsing is retried.

N.B. TestEvalScanner has been disabled for this change, because the additional test cases revealed a (most-likely already existing) data race.

Fixes #721
2020-08-28 10:28:15 +02:00
Marc Vertes
b1279d0a21 feature: improve handling of interrupt signal in REPL
The input scanning is now performed in a sub goroutine and
the interrupt is listened in another goroutine, either to cancel Eval
or to cancel the current line scan.
Entering a '\n' after a 'Ctrl-C` to get the prompt is
not necessary anymore.
2020-08-27 15:04:04 +02:00
Nicholas Wiersma
f3f9ffaea7 feat: add builtin type checking
This adds type checking for builtin functions. It also refactors builtin names into constants due to the number of times they are used.
2020-08-27 14:02:04 +02:00
Nicholas Wiersma
e332a6b3be fix: check array size symbol kind
When determining the size of an array and a symbol is found, the symbol must be a const for the type to be valid. 

While it makes sense for this check to be done in type checking, the type can be determined by GTA which would then fail. For now this check is done when getting the node type.

Fixes #825
2020-08-27 11:52:04 +02:00
Nicholas Wiersma
358a57b4b9 feat: add star expression type checking
This adds type checking to StarExpr. This also fixes a bug in assignment where the symbol type was updated but not the scope type associated with it.
2020-08-21 10:56:03 +02:00
Nicholas Wiersma
3640f2f820 feat: add type assertion expression type checking
This adds type checking to TypeAssertExpr. In order to allow for this, method types now have a receiver type in both reflect and native cases.
2020-08-20 17:06:05 +02:00
mpl
3faa47c61e interp: take into account embedded property of struct field
The trick is that in reflect, the field is called Anonymous, which is
actually a different notion in the Go spec/vocable.

n.b. only works for non-recursive types for now.

Fixes #781
2020-08-20 14:51:14 +02:00
mpl
896bfeb5a1 interp: new EvalPath API
The recent changes that added some redeclaration checks implicitly added more
strictness related to namespaces and scopes which, among other things, broke
some uses that "accidentally" used to work.

For example, given

const script1 = `
	import "fmt"

	// more code
`
const script2 = `
	import "fmt"

	// some other code
`
If one Evals script1, then script2, with the same interpreter, without
specifying any scope, as the two fragments would be considered part of the same
(.go file) scope by default, a redeclaration error would be triggered because
import "fmt" is seen twice.

A work-around would have been to specify (a different) i.Name before each Eval
call, so that each script is considered as coming from a different .go file, and
hence are respectively in different scopes with respect to imports.

That lead us to realize we had to make specifying things such as file-scope, and
"incremental mode" (aka REPL), more obvious in the context of an Eval call.

In addition, we want to lay down the foundations for Yaegi being able to behave
more like the go tool wrt to various inputs, i.e. it should be able to take a
package directory, or an import path, as input, instead of just a .go file.

Hence the introduction of a new kind of Eval method (whose signature is not fixed yet):

func (interp *Interpreter) EvalPath(path string) (res reflect.Value, err error)

It partially solves the problem described above because:

1. the path given to EvalPath can be used as the file-scope hint mentioned
above, for now (even though the related implementation details might change).
2. Eval always runs in incremental mode, whereas EvalPath always runs in
non-incremental mode, hence clarifying the situation in that respect.

And to avoid confusion, the Name field of Interpreter is now non-exported,
since it is somewhat redundant with the path argument of EvalPath.

Note that #731 is not fully fixed (and might never be), as a requirement of the
proposed solution is to move the input bits of code into respective files
(instead of leaving them as strings).

Finally, some related bugfixes, documention changes, and some refactoring have
been included. Notably, there is no "empty scope" anymore, i.e. name defaults
to "_.go" when it is not specified.

Updates #731
Fixes #778
Fixes #798
Fixes #789 

Co-authored-by: Marc Vertes <mvertes@free.fr>
2020-08-20 13:14:15 +02:00
Nicholas Wiersma
1029d102e5 feat: add slice expression type checking
This adds type checking to SliceExpr as well as handling any required constant type conversion.

It should be noted that the check that `high` and `max` are not nil in a 3-index slice has been left out as this check is handled before type checking. Tests have been included for these cases.
2020-08-19 16:04:05 +02:00
Marc Vertes
065d4fa4d7 fix: add mutual exclusion locks for cancelable select
In a couple of occurences, tests with enabled race detector exposed
some concurrent accesses to the cancelation callback used in select and
channel operations send and recv for EvalWithContext. This change ensure
that all accesses to this object are protected by mutex.

Fixes #815.
2020-08-19 13:52:04 +02:00
mpl
332becf95d interp: more tests for ignoreScannerError
They cover the extra cases that were "sneakily" added
after 611a8c37fa
2020-08-14 15:04:11 +02:00
Nicholas Wiersma
da9e6a0d6c fix: composite literal type check
In the case of a pointer or alias composite literal expression, `compositeGenerator` changes the type to remove the pointer or alias. This causes a nested composite literal to have the wrong type.

Instead of changing the node type, the removal of the pointer or alias is moved to the runtime, allowing the node type to remain unchanged. This fixes potential issues in the type checking.
2020-08-14 12:14:03 +02:00
Nicholas Wiersma
913680d1ed feat: add call expression (not builtin) type checking
This adds type checking to CallExpr (excluding builtin type checking, as that is a PR in its own right) as well as handling any required constant type conversion.

This also changes constant strings and runes to be represented as `constant.Value`. Runes change `rval` type at CFG typing time to avoid having to type at AST time. There are also changes to importSpecs and `stdlib` to account for the string change. With this all `untyped` types should now be `constant.Value`s, although errors are still not returned if this is not the case to be sure we do not break things.

This also fixed a bug in `itype.methods` that would panic if the type was recursive.
2020-08-14 12:02:04 +02:00
Ludovic Fernandez
a004809fc2 fix: main command for goreleaser. 2020-08-13 14:22:03 +02:00
Marc Vertes
b0cd93a936 fix: correct interrupt signal handling in REPL
Avoid goroutines leak, accumulation of defered functions and
spurious resets of signal handlers. Effectively catch interrupt
signal (Ctrl-C) to cancel current eval.

Fixes #713.
v0.8.14
2020-08-12 22:22:03 +02:00
mpl
611a8c37fa interp: make REPL stricter about parsing errors
So far the REPL loop was treating any parsing error coming from
go/parser to generate the AST, as having occurred because the source
code was not yet complete (unfinished block). And it was therefore
ignoring all of them.

However, some of these errors are legitimate, and must be caught as soon
as they occur, otherwise the REPL cycle would stay in an errored state
forever (even when the block terminates), without the user getting any
feedback about it.

Therefore, this change adds an extra check when a parsing error occurs,
i.e. it verifies that it looks like an "EOF" error (unfinished block)
before it ignores it (as the user is supposed to terminate the block
eventually). Otherwise the error is treated just like a "non-parsing"
(cfg, gta, ...) error and printed out.

Fixes #637
2020-08-12 18:44:21 +02:00
Marc Vertes
e71ddc7edd chore: update golangci-lint config (#810)
Disable nlreturn. Fix one comment.
2020-08-12 17:46:28 +02:00
Ludovic Fernandez
1fe75f149d feat: update stdlib mapping for go1.15
- drop stdlib for go1.13
- generate stdlib for go1.15
-  update CI configuration.
2020-08-12 12:38:04 +02:00
Nicholas Wiersma
cdc352cee2 feat: add index and composite literal type checking
This adds type checking to both `IndexExpr` and `CompositeLitExpr` as well as handling any required constant type conversion.

This includes a change to the type propagation to the children of a composite literal. Previously in most cases the composite literal type was propagated to its children. This does not work with type checking as the actual child type is needed.
2020-08-11 15:58:04 +02:00
Nicholas Wiersma
88569f5df7 fix: interface call regression from #787
Fix #787 changes how interfaces are set on a struct (compositeSparce). This change however makes calling the interface panic. 

This PR reverts part of the change in #787 and adds a test to ensure it does not break again.
2020-08-10 16:32:05 +02:00
Marc Vertes
2ac0c6f70b feature: command line provide sub-commands
The Yaegi command line has been changed to provide subcommands.

The following sub-commands are provided:
- extract (formerly goexports)
- help
- run
- test

The previous behaviour is now implemented in run command which
is the default, so the change should be transparent.

In run command, prepare the ability to run a package or a directory
in addition to a file. Not implemented yet

The test command is not implemented yet.

The extract command is meant to generate wrappers to non stdlib
packages.

Fixes #639
2020-08-10 16:20:05 +02:00
Nicholas Wiersma
bd4ce37baa feat: refactor type checking
The previous type checking was off and did not do untyped type conversion. This endeavours to fix this with better type checking in its own type.
2020-07-31 14:00:03 +02:00
Nicholas Wiersma
9c4d3d1e5a chore: updated linter 2020-07-30 11:18:04 +02:00
Marc Vertes
25c681c1e6 fix: regression on range following #787 2020-07-30 10:52:05 +02:00
Marc Vertes
9c51f6bb69 fix: correct range on arrays of interface objects 2020-07-23 12:25:04 +02:00
Marc Vertes
589b2a0cd2 fix: correct conversion to int in slice index expressions. 2020-07-23 12:05:03 +02:00
Marc Vertes
68911f8b4e fix: type assertion expression was not forwarding type
The detection of special cases of interpreter functions and interfaces
is more precise. It allows at least to complete parsing of
code where type is derived from a type assertion expression.

Fixes #770.
2020-07-23 11:51:53 +02:00
mpl
e5a7b0de11 extract: new package to extract symbols from a dependency
cmd/goexports is now based on it.

Updates #639 

Co-authored-by: Marc Vertes <mvertes@free.fr>
2020-07-23 10:58:33 +02:00
mpl
563270ca02 interp: support yet another vendoring case
* interp: support another vendoring case

Namely, when the vendor dir is a sibling (or an uncle) relative to the
current pkg

Fixes #758

* make linter happier

* address review comments

* fix, cleanup, add unit tests

* add dummy files to force dirs into git
v0.8.13
2020-07-15 15:35:04 +02:00
Marc Vertes
5eecbe515b fix: compositeSparse handles fields of interface kind
Fixes #776.
2020-07-13 17:55:04 +02:00
Marc Vertes
0a79069dfc fix: correct control flow graph for range init expression
The range init AST execution was skipped, and range could work
only over variables or direct function calls. By setting the
start node to the start of init and not init itself, we ensure
that the init AST is always taken into account.

Fixes #775.
2020-07-13 15:35:04 +02:00
Marc Vertes
0c8f538cd9 fix: apply method receiver offset when generating interface wrapper
Fixes #772.
2020-07-12 14:20:03 +02:00
Nicholas Wiersma
ca80ada849 fix: deal with untyped in type check 2020-07-10 11:55:04 +02:00
Nicholas Wiersma
3c6df504df fix: dont allow calling init v0.8.12 2020-07-09 14:35:04 +02:00
Nicholas Wiersma
98eacf3610 fix: execute global variables in the correct order
* fix: constant definition loop on out of order vars

* fix: do not wire global varDecl

* fix: wire and execute global vars

* chore: add tests

* fix: refactor and lint
2020-07-09 14:05:03 +02:00
Marc Vertes
16ff52a949 fix: avoid a panic in CFG in case of incomplete type
By returning early in case of incomplete type in CFG, we avoid
a panic, and let a chance to a new attempt after the missing
type has been parsed.

Fixes 763.
2020-07-09 13:05:04 +02:00
Marc Vertes
640d1429e5 fix: type assert when status is _
If the status is _, there is no storage allocated in frame, and
the status assign operation should be skipped.

Fixes #761.
2020-07-09 08:45:03 +02:00
Nicholas Wiersma
659913eebe fix: convert type properly to the correct type 2020-07-08 22:55:03 +02:00
Marc Vertes
b3766509cc feature: restrict symbols which can exit the interpreter process
* feature: restrict symbols which can exit the interpreter process

Some symbols such as os.Exit or log.Fatal, which make the current process
to exit, are now restricted. They are replaced by a version which panics
instead of exiting, as panics are recovered by Eval.

The restricted os.FindProcess version is identical to the original
except it errors when trying to return the self process, in order to
forbid killing or signaling the interpreter process from script.

The os/exec symbols are available only through unrestricted package.

The original symbols are stored in an unrestricted package, which
requires an explicit Use, as for unsafe and syscall packages.

The Use() interpreter method has been slightly modified to allow inplace
updating of package symbols, allowing to replace some symbols but not
the entire imported package.

A command line option -unrestricted has been added to yaegi CLI to use
the unrestricted symbols.

Fixes #486.

* fix: lint
2020-07-08 22:35:04 +02:00
Nicholas Wiersma
bc2b224bae fix: make a copy of defined before detecting recursivness 2020-07-07 12:05:03 +02:00
Nicholas Wiersma
9d4685deea fix: handle interfaces in composite sparce (#749)
Co-authored-by: Marc Vertes <mvertes@free.fr>
2020-07-06 15:41:27 +02:00
Marc Vertes
2a70a71dc2 fix: avoid infinite loop when parsing recursive types
Mark all visited types as such when walking down struct fields.

Fixes #750.
Updates #652.
2020-07-06 15:30:04 +02:00
Nicholas Wiersma
851444453c fix: assert switch type from valueT in struct case (#747)
* fix: switch type from valueT in struct case

In a struct case in type assertion, if the source is a valueT, we still need to take the struct type to allow method and field resolution.

* fix: handle all ptr structs as well
2020-07-06 15:09:48 +02:00
Nicholas Wiersma
a8b1c2a017 fix: a const, non-const equality check must convert 2020-07-06 11:25:03 +02:00
Nicholas Wiersma
d229c2a2c7 fix: handle Func Value in genFunctionWrapper params
* fix: handle Func value in func wrapper params

* fix: lint
2020-07-03 12:25:04 +02:00