diff --git a/docs/resources/gno-interrealm.md b/docs/resources/gno-interrealm.md new file mode 100644 index 00000000000..74aed39aeaa --- /dev/null +++ b/docs/resources/gno-interrealm.md @@ -0,0 +1,108 @@ +# Interrealm Specification + +Gno extends Go's type system with a interrealm rules. These rules can be +checked during the static type-checking phase (but at the moment they are +partially dependent on runtime checks). + +All functions in Gno execute under a realm context as determined by the call +stack. Objects that reside in a realm can only be modified if the realm context +matches. + +A function declared in p packages when called: + + * inherits the last realm for package declared functions and closures. + * inherits the last realm when a method is called on unreal receiver. + * implicitly crosses to the receiver's resident realm when a method of the + receiver is called. The receiver's realm is also called the "borrow realm". + +A function declared in a realm package when called: + + * explicitly crosses to the realm in which the function is declared if the + function begins with a `crossing()` statement. The new realm is called the + "current realm". + * otherwise follows the same rules as for p packages. + +The `crossing()` statement must be the first statement of a function's body. +It is illegal to use anywhere else, and cannot be used in p packages. Functions +that begin with the `crossing()` statement are called "crossing" functions". + +A crossing function declared in a realm different than the last explicitly +crossed realm *must* be called like `cross(fn)(...)`. That is, functions of +calls that result in explicit realm crossings must be wrapped with `cross()`. + +`std.CurrentRealm()` returns the current realm last explicitly crossed to. + +`std.PreviousRealm()` returns the realm explicitly crossed to before that. + +A crossing function declared in the same realm package as the callee may be +called normally OR like `cross(fn)(...)`. When called normally there will be no +realm crossing, but when called like `cross(fn)(...)` there is technically a +realm crossing and the current realm and previous realm returned are the same. + +The current realm and previous realm do not depend on any implicit crossing to +the receiver's borrowed/storage realm even if the borrowed realm is the last +realm of the call stack equal to `m.Realm`. In other words `std.CurrentRealm()` +may be different than `m.Realm` (the borrow realm) when a receiver is called on +a foreign object. + +Calls of methods on receivers residing in realms different than the current +realm must not be called like `cross(fn)(...)` if the method is not a +crossing function itself, and vice versa. Or it could be said that implicit +crossing is not real realm crossing. (When you sign a document with someone +else's pen it is still your signature; signature:pen :: current:borrowed. + +A crossing method declared in a realm cannot modify the receiver if the object +resides in a different realm. However not all methods are required to be +crossing methods, and crossing methods may still read the state of the +receiver (and in general anything reacheable is readible). + +New unreal objects reachable from the borrowed realm (or current realm if there +was no method call that borrowed) become persisted in the borrowed realm (or +current realm) upon finalization of the foreign object's method (or function). +(When you put an unlabeled photo in someone else's scrap book the photo now +belongs to the other person). In the future we will introduce an `attach()` +function to prevent a new unreal object from being taken. + +MsgCall can only call (realm) crossing functions. + +MsgRun will run a file's `main()` function in the user's realm and may call +both crossing functions and non-crossing functions. + +A realm package's initialization (including init() calls) execute with current +realm of itself, and it `std.PreviousRealm()` will panic unless the call stack +includes a crossing function called like `cross(fn)(...)`. + +### Justifications + +P package code should behave the same even when copied verbatim in a realm +package. + +Realm crossing with respect to `std.CurrentRealm()` and `std.PreviousRealm()` +is important enough to be explicit and warrants type-checking. + +A crossing function of a realm should be able to call another crossing function +of the same realm without necessarily explicitly crossing realms. + +Sometimes the previous realm and current realm must be the same realm, such as +when a realm consumes a service that it offers to external realms and users. + +A method should be able to modify the receiver and associated objects of the +same borrowed realm. + +A method should be able to create new objects that reside in the same realm by +default in order to maintain storage realm consistency and encapsulation and +reduce fragmentation. + +In the future an object may be migrated from one realm to another when it loses +all references in one realm and gains references in another. The behavior of +the object should not change after migration because this type of migration is +implicit and generally not obvious without more language features. + +Code declared in p packages (or declared in "immutable" realm packages) can +help different realms enforce contracts trustlessly, even those that involve +the caller's current realm. Otherwise two mutable (upgreadeable) realms cannot +export trust unto the chain because functions declared in those two realms can +be upgraded. + +Both `crossing()` and `cross(fn)(...)` statements may become special syntax in +future Gno versions. diff --git a/docs/resources/gno-memory-model.md b/docs/resources/gno-memory-model.md new file mode 100644 index 00000000000..4b00c3b3f6d --- /dev/null +++ b/docs/resources/gno-memory-model.md @@ -0,0 +1,218 @@ +# Gno Memory Model + +## The Typed Value + +```go +type TypedValue struct { + T Type + V Value + N [8]byte +} +``` + +Both `Type` and `Value` are Go interface values. Go does not support union +types, so primitive values like bools and ints are stored in the N field for +performance. + +All values in Gno are stored represented as (type, value) tuples. Vars in +scope blocks, fields in structs, elements in arrays, keys and values of maps +are all respresented by the same `TypedValue` struct. + +This tuple representation lets the Gno VM implementation logic be simpler with +less code. Reading and writing values are the same whether the static type of +the value is an interface or something concrete with no special logic for +memory optimizations which is less relevant in a massive multi-user +transactional operating system where most of the data resides in disk anyways. + +Another benefit is that it promotes the development of new types of client +interfaces that can make use of the type information for object display and +interaction. The original vision of Tim Burners Lee's HTML DOM based World Wide +Web with restful HTTP requests like GET and POST has been steamrolled over by +continuous developments in HTML, CSS, Javascript, and the browser. The internet +is alive but the World Wide Web is dead. Gno is a reboot of the original vision +of the Web but better because everything is integrated based on a singular +well designed object-oriented language. Instead of POST requests Gno has +typed method calls. All values are annotated with their types making the +environment REST-ful to the core. + +> REST (Representational State Transfer) is a software architectural style that +> was created to describe the design and guide the development of the +> architecture for the World Wide Web. REST defines a set of constraints for +> how the architecture of a distributed, Internet-scale hypermedia system, such +> as the Web, should behave. - wikipedia + +While the Gno VM implements the memory model described here in the most +straightforward way, future alternative implementations may represent values +differently in machine memory even while conforming to the spec as implemented +by the Gno VM. + + +## Objects and Values + +There are many types of Values, and some of these value types are also Objects. +The types below are all values and those that are bolded are also objects. + + * Primitive // bool, uint, int, uint8, ... int64 + * StringValue + * BigintValue // only used for constant expressions + * BigdecValue // only used for constant expressions + * DataByteValue // invisible type for byte array optimization + * PointerValue // base is always an object + * **ArrayValue** + * SliceValue + * **StructValue** + * **FuncValue** + * **MapValue** + * **BoundMethodValue** // func & receiver + * TypeValue + * PackageValue + * **BlockValue** // for package, file, if, range, switch, func + * RefValue // reference to an object stored in disk + * **HeapItemValue** // invisible type for loopvars and closure captures + + +## Pointers + +```go +type PointerValue struct { + TV *TypedValue // escape val if pointer to var. + Base Value // array/struct/block, or heapitem. + Index int // list/fields/values index, or -1 or -2 (see below). +} +``` + +The pointer is a reference to a typed value slot in an array, struct, block, +or heap item. It is also used internally in the VM for assigning to slots. +Even internally the Base is used to tell the realm finalizer when the base +has been updated. + +## Blocks and Heap Items + +All statements enclosed in {} parentheses will allocate a new block +and push it onto the block stack of the VM. The size of the block +is determined by the number of variables declared in the block statement. + +``` +type BlockValue struct { + ObjectInfo + Source BlockNode + Values []TypedValue + Parent Value // Parent block if any, or RefValue{} to one. + Blank TypedValue // Captures "_" underscore names. + bodyStmt bodyStmt // Holds a pointer to the current statement. +} +``` + +The following Gno AST nodes when executed will create a new block: + + * FuncLitStmt + * BlockStmt // a list of statements wrapped in {} + * ForStmt + * IfCaseStmt + * RangeStmt + * SwitchCaseStmt + * FuncDecl + * FileNode + * PackageNode + +`IfStmt`s and `SwitchStmt`s also produce faux blocks that get merged onto the +following `IfCaseStmt` and `SwitchCaseStmt` respectively, but this is an +invisible implementation detail and the behavior may change. + +Heap items are only used in blocks. Conceptually they are an object container +around a singleton typed value slot. It is not visible to the gno developer +but it is important to understand how they work when inspecting the block +space. + +```go +func Example(arg int) (res *int) { + var x int = arg + 1 + return &x +} +``` + +The above code when executed will first produce the following block: + +``` +BlockValue{ + ... + Source: <*FuncDecl node>, + Values: [ + {T: nil, V: nil}, // 'arg' parameter + {T: nil, V: nil}, // 'res' result + {T: HeapItemType{}, + V: &HeapItemValue{{T: nil, V: nil}}, // 'x' variable + ], + ... +} +``` + +In the above example the third slot for `x` is not initialized to the zero +value of a typed value slot, but rather it is prefilled with a heap item. + +Variables declared in a closure or passed by reference are first discovered and +marked as such from the preprocessor, and NewBlock() will prepopulate these +slots with `*HeapItemValues`. When a `*HeapItemValue` is present in a block +slot it is not written over but instead the value is written into the heap +item's slot. + +When the example code executes `return &x` instead of returning a +`PointerValue` with `.Base` set to the `BlockValue` and `.Index` of 2, it sets +`.Base` to the `*HeapItemValue` with `.Index` of 0 since a heap item only +contains one slot. The pointer's `.TV` is set to the single slot of of the heap +item. This way the when the pointer is used later in another transaction there +is no need to load the whole original block value, but rather a single heap +item object. If `Example()` returned only `x` rather than a pointer `&x` it +would not be initialized with a heap item for the slot. + +```go +func Example2(arg int) (res func()) { + var x int = arg + 1 + return func() { + println(x) + } +} +``` + +The above example illustrates another use for heap items. Here we don't +reference `x`, but it is captured by the anonymous function literal (closure). +At runtime the closure `*FuncValue` captures the heap item object such that the +closure does not depend on the block at all. + +Variables declared at the package (global) level may also be referred to by +pointer in anonymous functions. In the future we will allow limited upgrading +features for mutable realm packages (e.g. the ability to add new functions or +replace or "swizzle" existing ones), so all package level declared variables +are wrapped in heap item objects. + +Since all global package values referenced closures can be captured as heap +objects, the execution and persistence of a closure function value does not +depend on any parent blocks. (Omitted here is how references to package +level declared functions and methods are replaced by a selector expression +on the package itself; otherwise closures would still in general depend +on their parent blocks). + +## Loopvars + +Go1.22 introduced loopvars to reduce programmer errors. Gno uses +heap items to implement loopvars. + +```go +for _, v := range values { + saveClosure(func() { + fmt.Println(v) + }) +} +``` + +The Gno VM does something special for loopvars. Instead of assigning the new +value `v` to the same slot, or even the same heap item object's slot, it +replaces the existing heap item object with a new one. This allows the closure +to capture a new heap item object with every iteration. This is called +a heap definition. + +The behavior is applied for implicit loops with `goto` statements. The +preprocessor first identifies all such variable definitions whether explicit in +range statements or implicit via `goto` statements that are captured by +closures or passed by pointer reference, and directs the VM to execute the +define statement by replacing the existing heap item object with a new one. diff --git a/docs/resources/gno-stdlibs.md b/docs/resources/gno-stdlibs.md index 2ca8bb0a400..59615ab88e7 100644 --- a/docs/resources/gno-stdlibs.md +++ b/docs/resources/gno-stdlibs.md @@ -420,7 +420,7 @@ currentRealm := std.CurrentRealm() ``` --- -### PrevRealm +### PreviousRealm ```go func PreviousRealm() Realm ``` diff --git a/docs/resources/realms.md b/docs/resources/realms.md index ab551b9935f..f81871dd7d4 100644 --- a/docs/resources/realms.md +++ b/docs/resources/realms.md @@ -1,15 +1,26 @@ -# Realms +# Realms and Packages -In gno.land, realms are entities that are addressable and identifiable by a -[Gno address](./gno-stdlibs.md#address). These can be user -realms (EOAs), as well as smart contract realms. Realms have several -properties: -- They can own, receive & send [Coins](./gno-stdlibs.md#coin) through the - [Banker](./gno-stdlibs.md#banker) module -- They can be part of a transaction call stack, as a caller or a callee -- They can be with or without code - smart contracts, or EOAs +Gno.land Realms are Packages of Gno code that are identified by their "package +paths" and are also "addressable" into an [Address](./gno-stdlibs.md#address) +which has prefix "g1...". + +A Realm is created when a Gno code Package is added to "gno.land/r/...", and +the state of realm packages are mutated by signed function call messages from +users calling exposed functions of realms. Realm functions can in turn call +other functions creating a call stack beginning at origin with a user Account. + +A "P" Package is created when a Package is added to "gno.land/p/...". "P" +Packages are immutable and cannot be modified by any message after creation. + +Realm and "P" Packages have an Account and Address derived from its package +path. Users too have an Account and Address determined cryptographically from a +BIP39 mnemonic phrase or secret. + +Realms and users can both send and receive [Coins](./gno-stdlibs.md#coin) using +the [Banker](./gno-stdlibs.md#banker) module by Address. Realms are represented by a `Realm` type in Gno: + ```go type Realm struct { addr Address // Gno address in the bech32 format @@ -44,15 +55,17 @@ Currently, EOAs are the only realms that can initiate a transaction. They can do this by calling any of the possible messages in gno.land, which can be found [here](../users/interact-with-gnokey.md#making-transactions). -### Working with realms +### Working with Realms + +Every Gno transaction produce a call stack that can switch across functions +declared in realm packages and functions declared in p packages. The `std` +package contains functions that return the current realm, previous realm, and +the origin caller's address. -In Gno, each transaction contains a realm call stack. Every item in the stack and -its properties can be accessed via different functions defined in the `std` -package in Gno: - `std.GetOrigCaller()` - returns the address of the original signer of the transaction -- `std.PrevRealm()` - returns the previous realm instance, which can be a user realm - or a smart contract realm +- `std.PreviousRealm()` - returns the previous realm instance, which can be a user + realm or a smart contract realm - `std.CurrentRealm()` - returns the instance of the realm that has called it Let's look at the return values of these functions in two distinct situations: @@ -61,15 +74,18 @@ Let's look at the return values of these functions in two distinct situations: #### 1. EOA calling a realm +When an EOA calls a realm, the call stack is initiated by the EOA, and the realm +becomes the current context. + Take these two actors in the call stack: ``` EOA: - addr: g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 + addr: `g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` pkgPath: "" // empty as this is a user realm Realm A: - addr: g17m4ga9t9dxn8uf06p3cahdavzfexe33ecg8v2s - pkgPath: gno.land/r/demo/users + addr: `g17m4ga9t9dxn8uf06p3cahdavzfexe33ecg8v2s` + pkgPath: `gno.land/r/demo/users` ┌─────────────────────┐ ┌─────────────────────────┐ │ EOA │ │ Realm A │ @@ -82,20 +98,26 @@ Realm A: └─────────────────────┘ └─────────────────────────┘ ``` -Let's look at return values for each of the methods, called from within `Realm A`: +Let's look at return values for each of the methods, called from within +`Realm A`: ``` std.GetOrigCaller() => `g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` -std.PrevRealm() => Realm { +std.PreviousRealm() => Realm { addr: `g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` pkgPath: `` } std.CurrentRealm() => Realm { addr: `g17m4ga9t9dxn8uf06p3cahdavzfexe33ecg8v2s` - pkgPath: `gno.land/r/demo/users`} + pkgPath: `gno.land/r/demo/users` +} ``` #### 2. EOA calling a sequence of realms +Assuming that you use interrealm switching, when an EOA calls a sequence of +realms, the call stack transitions through multiple realms. Each realm in the +sequence becomes the current context as the call progresses. + Take these three actors in the call stack: ``` EOA: @@ -125,7 +147,7 @@ Depending on which realm the methods are called in, the values will change. For `Realm A`: ``` std.GetOrigCaller() => `g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` -std.PrevRealm() => Realm { +std.PreviousRealm() => Realm { addr: `g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` pkgPath: `` } @@ -138,7 +160,7 @@ std.CurrentRealm() => Realm { For `Realm B`: ``` std.GetOrigCaller() => `g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5` -std.PrevRealm() => Realm { +std.PreviousRealm() => Realm { addr: `g1dvqd8qgvavqayxklzfdmccd2eps263p43pu2c6` pkgPath: `gno.land/r/demo/a` } @@ -148,6 +170,12 @@ std.CurrentRealm() => Realm { } ``` +### Resources + +See the [Gno Interrealm Specification](./gno-interrealm.md) for more +information on language rules for interrealm (cross) safety including how and +when to use the `cross()` and `crossing()` functions and more. + For more information about realms and how they fit into the gno.land ecosystem, see the [Package Path Structure](./gno-packages.md#package-path-structure) documentation. diff --git a/examples/gno.land/p/agherasie/forms/create_test.gno b/examples/gno.land/p/agherasie/forms/create_test.gno index bd5eb7497ee..c27000e403c 100644 --- a/examples/gno.land/p/agherasie/forms/create_test.gno +++ b/examples/gno.land/p/agherasie/forms/create_test.gno @@ -1,6 +1,7 @@ package forms import ( + "std" "testing" "gno.land/p/demo/testutils" @@ -10,6 +11,7 @@ import ( func TestCreateForm(t *testing.T) { alice := testutils.TestAddress("alice") testing.SetOriginCaller(alice) + testing.SetRealm(std.NewUserRealm("g1user")) db := NewDB() title := "Simple Form" description := "This is a form" diff --git a/examples/gno.land/p/agherasie/forms/submit_test.gno b/examples/gno.land/p/agherasie/forms/submit_test.gno index e5125acbae2..c6883a75a30 100644 --- a/examples/gno.land/p/agherasie/forms/submit_test.gno +++ b/examples/gno.land/p/agherasie/forms/submit_test.gno @@ -1,6 +1,7 @@ package forms import ( + "std" "testing" "time" @@ -8,6 +9,8 @@ import ( ) func TestAnswerForm(t *testing.T) { + testing.SetRealm(std.NewUserRealm("g1user")) + db := NewDB() data := `[ @@ -51,6 +54,7 @@ func TestAnswerForm(t *testing.T) { } func TestAnswerFormDates(t *testing.T) { + testing.SetRealm(std.NewUserRealm("g1user")) db := NewDB() now := time.Now() diff --git a/examples/gno.land/p/agherasie/forms/validate_test.gno b/examples/gno.land/p/agherasie/forms/validate_test.gno index 952cb6d96d4..ea2d09ed984 100644 --- a/examples/gno.land/p/agherasie/forms/validate_test.gno +++ b/examples/gno.land/p/agherasie/forms/validate_test.gno @@ -1,10 +1,12 @@ package forms import ( + "std" "testing" ) func TestAnswerFormInvalidForm(t *testing.T) { + testing.SetRealm(std.NewUserRealm("g1user")) db := NewDB() dataAllTypes := `[ diff --git a/examples/gno.land/p/moul/debug/debug_test.gno b/examples/gno.land/p/moul/debug/debug_test.gno new file mode 100644 index 00000000000..02ce5f7c9c5 --- /dev/null +++ b/examples/gno.land/p/moul/debug/debug_test.gno @@ -0,0 +1,71 @@ +package debug + +import ( + "std" + "strings" + "testing" + + "gno.land/p/demo/uassert" +) + +func TestPackage(t *testing.T) { + testing.SetRealm(std.NewUserRealm("g1user")) + + // no debug + got := Render("") + expected := `` + uassert.Equal(t, got, expected) + + // debug without logs + got = Render("?debug=1") + expected = `
debug + +### Metadata +| Key | Value | +| --- | --- | +| ±std.CurrentRealm().PkgPath()± | | +| ±std.CurrentRealm().Address()± | g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm | +| ±std.PreviousRealm().PkgPath()± | | +| ±std.PreviousRealm().Address()± | g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm | +| ±std.ChainHeight()± | 123 | +| ±time.Now().Format(time.RFC3339)± | 2009-02-13T23:31:30Z | + +
+` + expected = strings.ReplaceAll(expected, "±", "`") + + println("###################") + println(got) + println("###################") + println(expected) + println("###################") + + uassert.Equal(t, got, expected) + + return + + // debug with logs + var d Debug + d.Log("hello world!") + d.Log("foobar") + got = d.Render("?debug=1") + expected = `
debug + +### Logs +- hello world! +- foobar +### Metadata +| Key | Value | +| --- | --- | +| ±std.CurrentRealm().PkgPath()± | | +| ±std.CurrentRealm().Address()± | g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm | +| ±std.PreviousRealm().PkgPath()± | | +| ±std.PreviousRealm().Address()± | g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm | +| ±std.ChainHeight()± | 123 | +| ±time.Now().Format(time.RFC3339)± | 2009-02-13T23:31:30Z | + +
+` + expected = strings.ReplaceAll(expected, "±", "`") + uassert.Equal(t, got, expected) +} diff --git a/examples/gno.land/p/moul/debug/z1_filetest.gno b/examples/gno.land/p/moul/debug/z1_filetest.gno deleted file mode 100644 index 5016fdab605..00000000000 --- a/examples/gno.land/p/moul/debug/z1_filetest.gno +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import "gno.land/p/moul/debug" - -func main() { - println("---") - println(debug.Render("")) - println("---") - println(debug.Render("?debug=1")) - println("---") -} - -// Output: -// --- -// -// --- -//
debug -// -// ### Metadata -// | Key | Value | -// | --- | --- | -// | `std.CurrentRealm().PkgPath()` | | -// | `std.CurrentRealm().Address()` | g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm | -// | `std.PreviousRealm().PkgPath()` | | -// | `std.PreviousRealm().Address()` | g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm | -// | `std.ChainHeight()` | 123 | -// | `time.Now().Format(time.RFC3339)` | 2009-02-13T23:31:30Z | -// -//
-// -// --- diff --git a/examples/gno.land/p/moul/debug/z2_filetest.gno b/examples/gno.land/p/moul/debug/z2_filetest.gno deleted file mode 100644 index fab7e57cdc2..00000000000 --- a/examples/gno.land/p/moul/debug/z2_filetest.gno +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import "gno.land/p/moul/debug" - -func main() { - var d debug.Debug - d.Log("hello world!") - d.Log("foobar") - println("---") - println(d.Render("")) - println("---") - println(d.Render("?debug=1")) - println("---") -} - -// Output: -// --- -// -// --- -//
debug -// -// ### Logs -// - hello world! -// - foobar -// ### Metadata -// | Key | Value | -// | --- | --- | -// | `std.CurrentRealm().PkgPath()` | | -// | `std.CurrentRealm().Address()` | g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm | -// | `std.PreviousRealm().PkgPath()` | | -// | `std.PreviousRealm().Address()` | g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm | -// | `std.ChainHeight()` | 123 | -// | `time.Now().Format(time.RFC3339)` | 2009-02-13T23:31:30Z | -// -//
-// -// --- diff --git a/examples/gno.land/r/demo/nft/nft.gno b/examples/gno.land/r/demo/nft/nft.gno index fe328a5be17..45c0d41f592 100644 --- a/examples/gno.land/r/demo/nft/nft.gno +++ b/examples/gno.land/r/demo/nft/nft.gno @@ -74,7 +74,7 @@ func (grc *token) SafeTransferFrom(from, to std.Address, tid grc721.TokenID) { } func (grc *token) TransferFrom(from, to std.Address, tid grc721.TokenID) { - caller := std.CallerAt(2) + caller := std.CallerAt(2) // XXX use CurrentRealm or PreviousRealm(). token, ok := grc.getToken(tid) // Throws if `_tokenId` is not a valid NFT. if !ok { diff --git a/examples/gno.land/r/demo/tests/crossrealm/crossrealm.gno b/examples/gno.land/r/demo/tests/crossrealm/crossrealm.gno index 1cc5a3f8e18..d3c2ec54026 100644 --- a/examples/gno.land/r/demo/tests/crossrealm/crossrealm.gno +++ b/examples/gno.land/r/demo/tests/crossrealm/crossrealm.gno @@ -33,6 +33,8 @@ type Fooer interface{ Foo() } var fooer Fooer func SetFooer(f Fooer) Fooer { + crossing() + fooer = f return fooer } @@ -41,11 +43,25 @@ func GetFooer() Fooer { return fooer } func CallFooerFoo() { fooer.Foo() } +func CallFooerFooSR() { + crossing() + + fooer.Foo() +} + +func CallFooerFooSR2() { + crossing() + + cross(fooer.Foo)() +} + type FooerGetter func() Fooer var fooerGetter FooerGetter func SetFooerGetter(fg FooerGetter) FooerGetter { + crossing() + fooerGetter = fg return fg } @@ -55,3 +71,41 @@ func GetFooerGetter() FooerGetter { } func CallFooerGetterFoo() { fooerGetter().Foo() } + +func CallFooerGetterFooSR2() { + crossing() + + cross(fooerGetter().Foo)() +} + +// This is a top function that does switch realms. +func ExecSR(cb func() string) string { + crossing() + + return cb() +} + +// This is a top function that doesn't switch realms. +func Exec(cb func() string) string { + return cb() +} + +var Closure func() + +func SetClosure(f func()) { + crossing() + + Closure = f +} + +var Object any + +func SetObject(x any) { + crossing() + + Object = x +} + +func GetObject() any { + return Object +} diff --git a/examples/gno.land/r/demo/tests/crossrealm/switchrealm.gno b/examples/gno.land/r/demo/tests/crossrealm/switchrealm.gno new file mode 100644 index 00000000000..efd3ac30be4 --- /dev/null +++ b/examples/gno.land/r/demo/tests/crossrealm/switchrealm.gno @@ -0,0 +1 @@ +package crossrealm diff --git a/examples/gno.land/r/demo/tests/crossrealm_b/crossrealm.gno b/examples/gno.land/r/demo/tests/crossrealm_b/crossrealm.gno index 058c81ed034..1cc51322213 100644 --- a/examples/gno.land/r/demo/tests/crossrealm_b/crossrealm.gno +++ b/examples/gno.land/r/demo/tests/crossrealm_b/crossrealm.gno @@ -15,6 +15,8 @@ func (f *fooer) SetS(newVal string) { } func (f *fooer) Foo() { + crossing() + println("hello " + f.s + " cur=" + std.CurrentRealm().PkgPath() + " prev=" + std.PreviousRealm().PkgPath()) } @@ -23,3 +25,23 @@ var ( FooerGetter = func() crossrealm.Fooer { return Fooer } FooerGetterBuilder = func() crossrealm.FooerGetter { return func() crossrealm.Fooer { return Fooer } } ) + +var Closure func() + +func SetClosure(f func()) { + crossing() + + Closure = f +} + +var Object any + +func SetObject(x any) { + crossing() + + Object = x +} + +func GetObject() any { + return Object +} diff --git a/examples/gno.land/r/demo/tests/exploit.gno b/examples/gno.land/r/demo/tests/exploit.gno new file mode 100644 index 00000000000..db79194c9eb --- /dev/null +++ b/examples/gno.land/r/demo/tests/exploit.gno @@ -0,0 +1,23 @@ +package tests + +var MyFoo *Foo + +type Foo struct { + A int + B *Foo +} + +// method to mutate + +func (f *Foo) UpdateFoo(x int) { + f.A = x +} + +func init() { + MyFoo = &Foo{ + A: 1, + B: &Foo{ + A: 2, + }, + } +} diff --git a/examples/gno.land/r/demo/tests/interfaces.gno b/examples/gno.land/r/demo/tests/interfaces.gno index d8f64e1577b..0e76730f9fb 100644 --- a/examples/gno.land/r/demo/tests/interfaces.gno +++ b/examples/gno.land/r/demo/tests/interfaces.gno @@ -11,6 +11,8 @@ type Stringer interface { var stringers []Stringer func AddStringer(str Stringer) { + crossing() + // NOTE: this is ridiculous, a slice that will become too long // eventually. Don't do this in production programs; use // gno.land/p/demo/avl or similar structures. diff --git a/examples/gno.land/r/demo/tests/realm_method38d.gno b/examples/gno.land/r/demo/tests/realm_method38d.gno index b1dbab67e1f..029dd00b630 100644 --- a/examples/gno.land/r/demo/tests/realm_method38d.gno +++ b/examples/gno.land/r/demo/tests/realm_method38d.gno @@ -7,13 +7,15 @@ func (n nat) Add() nat { } func GetAbs() nat { - abs = []Word{0} + crossing() + abs = []Word{0} return abs } func AbsAdd() nat { - rt := GetAbs().Add() + crossing() + rt := GetAbs().Add() return rt } diff --git a/examples/gno.land/r/demo/tests/subtests/subtests.gno b/examples/gno.land/r/demo/tests/subtests/subtests.gno index ddfe54cd4b3..b8ba89ac788 100644 --- a/examples/gno.land/r/demo/tests/subtests/subtests.gno +++ b/examples/gno.land/r/demo/tests/subtests/subtests.gno @@ -5,10 +5,14 @@ import ( ) func GetCurrentRealm() std.Realm { + crossing() + return std.CurrentRealm() } func GetPreviousRealm() std.Realm { + crossing() + return std.PreviousRealm() } @@ -17,9 +21,13 @@ func Exec(fn func()) { } func CallAssertOriginCall() { + crossing() + std.AssertOriginCall() } func CallIsOriginCall() bool { + crossing() + return std.PreviousRealm().IsUser() } diff --git a/examples/gno.land/r/demo/tests/test20/test20.gno b/examples/gno.land/r/demo/tests/test20/test20.gno index 9c4df58d1c4..518d855d8e7 100644 --- a/examples/gno.land/r/demo/tests/test20/test20.gno +++ b/examples/gno.land/r/demo/tests/test20/test20.gno @@ -16,5 +16,7 @@ import ( var Token, PrivateLedger = grc20.NewToken("Test20", "TST", 4) func init() { + crossing() + grc20reg.Register(Token.Getter(), "") } diff --git a/examples/gno.land/r/demo/tests/tests.gno b/examples/gno.land/r/demo/tests/tests.gno index 452319c7aca..08b64538cf2 100644 --- a/examples/gno.land/r/demo/tests/tests.gno +++ b/examples/gno.land/r/demo/tests/tests.gno @@ -10,36 +10,52 @@ import ( var counter int func IncCounter() { + crossing() + counter++ } func Counter() int { + crossing() + return counter } func CurrentRealmPath() string { + crossing() + return std.CurrentRealm().PkgPath() } var initOriginCaller = std.OriginCaller() func InitOriginCaller() std.Address { + crossing() + return initOriginCaller } func CallAssertOriginCall() { + crossing() + std.AssertOriginCall() } func CallIsOriginCall() bool { + crossing() + return std.PreviousRealm().IsUser() } func CallSubtestsAssertOriginCall() { + crossing() + rsubtests.CallAssertOriginCall() } func CallSubtestsIsOriginCall() bool { + crossing() + return rsubtests.CallIsOriginCall() } @@ -53,6 +69,8 @@ type TestRealmObject struct { var TestRealmObjectValue TestRealmObject func ModifyTestRealmObject(t *TestRealmObject) { + crossing() + t.Field += "_modified" } @@ -75,11 +93,15 @@ var ( ) func InitTestNodes() { + crossing() + gTestNode1 = &TestNode{Name: "first"} gTestNode2 = &TestNode{Name: "second", Child: &TestNode{Name: "second's child"}} } func ModTestNodes() { + crossing() + tmp := &TestNode{} tmp.Child = gTestNode2.Child gTestNode3 = tmp // set to new-real @@ -92,25 +114,42 @@ func PrintTestNodes() { } func GetPreviousRealm() std.Realm { + crossing() + return std.PreviousRealm() } func GetRSubtestsPreviousRealm() std.Realm { - return rsubtests.GetPreviousRealm() + crossing() + + return cross(rsubtests.GetPreviousRealm)() } func Exec(fn func()) { + // no realm switching. + fn() +} + +func ExecSwitch(fn func()) { + crossing() + fn() } func IsCallerSubPath() bool { + crossing() + return nestedpkg.IsCallerSubPath() } func IsCallerParentPath() bool { + crossing() + return nestedpkg.IsCallerParentPath() } func HasCallerSameNamespace() bool { + crossing() + return nestedpkg.IsSameNamespace() } diff --git a/examples/gno.land/r/demo/tests_foo/foo.gno b/examples/gno.land/r/demo/tests_foo/foo.gno index 560d85552ab..4dc36a51077 100644 --- a/examples/gno.land/r/demo/tests_foo/foo.gno +++ b/examples/gno.land/r/demo/tests_foo/foo.gno @@ -15,5 +15,5 @@ func (fs *FooStringer) String() string { } func AddFooStringer(fa string) { - tests.AddStringer(&FooStringer{fa}) + cross(tests.AddStringer)(&FooStringer{fa}) } diff --git a/examples/gno.land/r/leon/config/config.gno b/examples/gno.land/r/leon/config/config.gno deleted file mode 100644 index 222ca98ebfa..00000000000 --- a/examples/gno.land/r/leon/config/config.gno +++ /dev/null @@ -1,85 +0,0 @@ -package config - -import ( - "errors" - "std" - "strings" - "time" - - "gno.land/p/demo/avl" - "gno.land/p/demo/ownable" - "gno.land/p/demo/seqid" -) - -var ( - cfgID seqid.ID - configs = avl.NewTree() - - absPath = strings.TrimPrefix(std.CurrentRealm().PkgPath(), std.ChainDomain()) - - // SafeObjects - OwnableMain = ownable.NewWithAddress("g125em6arxsnj49vx35f0n0z34putv5ty3376fg5") - OwnableBackup = ownable.NewWithAddress("g1lavlav7zwsjqlzzl3qdl3nl242qtf638vnhdjh") - - ErrUnauthorized = errors.New("leon's config: unauthorized") -) - -type Config struct { - id seqid.ID - name string - lines string - updated time.Time -} - -func AddConfig(name, lines string) { - if !IsAuthorized(std.PreviousRealm().Address()) { - panic(ErrUnauthorized) - } - - id := cfgID.Next() - configs.Set(id.String(), Config{ - id: id, - name: name, - lines: lines, - updated: time.Now(), - }) -} - -func EditConfig(id string, name, lines string) { - if !IsAuthorized(std.PreviousRealm().Address()) { - panic(ErrUnauthorized) - } - - raw, ok := configs.Remove(id) - if !ok { - panic("no config with that id") - } - - conf := raw.(Config) - // Overwrites data - conf.lines = lines - conf.name = name - conf.updated = time.Now() -} - -func RemoveConfig(id string) { - if !IsAuthorized(std.PreviousRealm().Address()) { - panic(ErrUnauthorized) - } - - if _, ok := configs.Remove(id); !ok { - panic("no config with that id") - } -} - -func UpdateBanner(newBanner string) { - if !IsAuthorized(std.PreviousRealm().Address()) { - panic(ErrUnauthorized) - } - - banner = newBanner -} - -func IsAuthorized(addr std.Address) bool { - return addr == OwnableMain.Owner() || addr == OwnableBackup.Owner() -} diff --git a/examples/gno.land/r/leon/config/gno.mod b/examples/gno.land/r/leon/config/gno.mod deleted file mode 100644 index e8cd5cd85b7..00000000000 --- a/examples/gno.land/r/leon/config/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/r/leon/config diff --git a/examples/gno.land/r/leon/config/render.gno b/examples/gno.land/r/leon/config/render.gno deleted file mode 100644 index 4d2c7dffcba..00000000000 --- a/examples/gno.land/r/leon/config/render.gno +++ /dev/null @@ -1,69 +0,0 @@ -package config - -import ( - "strconv" - - p "gno.land/p/demo/avl/pager" - "gno.land/p/demo/ufmt" - "gno.land/p/moul/md" - "gno.land/p/moul/realmpath" - "gno.land/p/moul/txlink" -) - -var ( - banner = "---\n[[Leon's Home page]](/r/leon/home) | [[Leon's snippets]](/r/leon/config) | [[GitHub: @leohhhn]](https://github.com/leohhhn)\n\n---" - pager = p.NewPager(configs, 10, true) -) - -func Banner() string { - return banner -} - -func Render(path string) (out string) { - req := realmpath.Parse(path) - if req.Path == "" { - out += md.H1("Leon's configs & snippets") - - out += ufmt.Sprintf("Leon's main address: %s\n\n", OwnableMain.Owner().String()) - out += ufmt.Sprintf("Leon's backup address: %s\n\n", OwnableBackup.Owner().String()) - - out += md.H2("Snippets") - - if configs.Size() == 0 { - out += "No configs yet :c\n\n" - } else { - page := pager.MustGetPageByPath(path) - for _, item := range page.Items { - out += ufmt.Sprintf("- [%s](%s:%s)\n\n", item.Value.(Config).name, absPath, item.Key) - } - - out += page.Picker(path) - out += "\n\n" - out += "Page " + strconv.Itoa(page.PageNumber) + " of " + strconv.Itoa(page.TotalPages) + "\n\n" - } - - out += Banner() - - return out - } - - return renderConfPage(req.Path) -} - -func renderConfPage(id string) (out string) { - raw, ok := configs.Get(id) - if !ok { - out += md.H1("404") - out += "That config does not exist :/" - return out - } - - conf := raw.(Config) - out += md.H1(conf.name) - out += ufmt.Sprintf("```\n%s\n```\n\n", conf.lines) - out += ufmt.Sprintf("_Last updated on %s_\n\n", conf.updated.Format("02 Jan, 2006")) - out += md.HorizontalRule() - out += ufmt.Sprintf("[[EDIT]](%s) - [[DELETE]](%s)", txlink.Call("EditConfig", "id", conf.id.String()), txlink.Call("RemoveConfig", "id", conf.id.String())) - - return out -} diff --git a/examples/gno.land/r/leon/hof/datasource.gno b/examples/gno.land/r/leon/hof/datasource.gno deleted file mode 100644 index 66afffb4ea2..00000000000 --- a/examples/gno.land/r/leon/hof/datasource.gno +++ /dev/null @@ -1,79 +0,0 @@ -package hof - -import ( - "errors" - - "gno.land/p/demo/avl" - "gno.land/p/demo/ufmt" - "gno.land/p/jeronimoalbi/datasource" - "gno.land/p/moul/md" -) - -func NewDatasource() Datasource { - return Datasource{exhibition} -} - -type Datasource struct { - exhibition *Exhibition -} - -func (ds Datasource) Size() int { return ds.exhibition.items.Size() } - -func (ds Datasource) Records(q datasource.Query) datasource.Iterator { - return &iterator{ - exhibition: ds.exhibition, - index: q.Offset, - maxIndex: q.Offset + q.Count, - } -} - -func (ds Datasource) Record(id string) (datasource.Record, error) { - v, found := ds.exhibition.items.Get(id) - if !found { - return nil, errors.New("realm submission not found") - } - return record{v.(*Item)}, nil -} - -type record struct { - item *Item -} - -func (r record) ID() string { return r.item.id.String() } -func (r record) String() string { return r.item.pkgpath } - -func (r record) Fields() (datasource.Fields, error) { - fields := avl.NewTree() - fields.Set( - "details", - ufmt.Sprintf("Votes: ⏶ %d - ⏷ %d", r.item.upvote.Size(), r.item.downvote.Size()), - ) - return fields, nil -} - -func (r record) Content() (string, error) { - content := md.H1(r.item.title) - content += md.H2(r.item.description) - content += r.item.Render(false) - return content, nil -} - -type iterator struct { - exhibition *Exhibition - index, maxIndex int - record *record -} - -func (it iterator) Record() datasource.Record { return it.record } -func (it iterator) Err() error { return nil } - -func (it *iterator) Next() bool { - if it.index >= it.maxIndex || it.index >= it.exhibition.items.Size() { - return false - } - - _, v := it.exhibition.items.GetByIndex(it.index) - it.record = &record{v.(*Item)} - it.index++ - return true -} diff --git a/examples/gno.land/r/leon/hof/datasource_test.gno b/examples/gno.land/r/leon/hof/datasource_test.gno deleted file mode 100644 index b5dfcbf7f60..00000000000 --- a/examples/gno.land/r/leon/hof/datasource_test.gno +++ /dev/null @@ -1,171 +0,0 @@ -package hof - -import ( - "strings" - "testing" - - "gno.land/p/demo/avl" - "gno.land/p/demo/uassert" - "gno.land/p/demo/ufmt" - "gno.land/p/demo/urequire" - "gno.land/p/jeronimoalbi/datasource" - "gno.land/p/moul/addrset" - "gno.land/p/moul/md" - "gno.land/p/moul/txlink" -) - -var ( - _ datasource.Datasource = (*Datasource)(nil) - _ datasource.Record = (*record)(nil) - _ datasource.ContentRecord = (*record)(nil) - _ datasource.Iterator = (*iterator)(nil) -) - -func TestDatasourceRecords(t *testing.T) { - cases := []struct { - name string - items []*Item - recordIDs []string - options []datasource.QueryOption - }{ - { - name: "all items", - items: []*Item{{id: 1}, {id: 2}, {id: 3}}, - recordIDs: []string{"0000001", "0000002", "0000003"}, - }, - { - name: "with offset", - items: []*Item{{id: 1}, {id: 2}, {id: 3}}, - recordIDs: []string{"0000002", "0000003"}, - options: []datasource.QueryOption{datasource.WithOffset(1)}, - }, - { - name: "with count", - items: []*Item{{id: 1}, {id: 2}, {id: 3}}, - recordIDs: []string{"0000001", "0000002"}, - options: []datasource.QueryOption{datasource.WithCount(2)}, - }, - { - name: "with offset and count", - items: []*Item{{id: 1}, {id: 2}, {id: 3}}, - recordIDs: []string{"0000002"}, - options: []datasource.QueryOption{ - datasource.WithOffset(1), - datasource.WithCount(1), - }, - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - // Initialize a local instance of exhibition - exhibition := &Exhibition{items: avl.NewTree()} - for _, item := range tc.items { - exhibition.items.Set(item.id.String(), item) - } - - // Get a records iterator - ds := Datasource{exhibition} - query := datasource.NewQuery(tc.options...) - iter := ds.Records(query) - - // Start asserting - urequire.Equal(t, len(tc.items), ds.Size(), "datasource size") - - var records []datasource.Record - for iter.Next() { - records = append(records, iter.Record()) - } - urequire.Equal(t, len(tc.recordIDs), len(records), "record count") - - for i, r := range records { - uassert.Equal(t, tc.recordIDs[i], r.ID()) - } - }) - } -} - -func TestDatasourceRecord(t *testing.T) { - cases := []struct { - name string - items []*Item - id string - err string - }{ - { - name: "found", - items: []*Item{{id: 1}, {id: 2}, {id: 3}}, - id: "0000001", - }, - { - name: "no found", - items: []*Item{{id: 1}, {id: 2}, {id: 3}}, - id: "42", - err: "realm submission not found", - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - // Initialize a local instance of exhibition - exhibition := &Exhibition{items: avl.NewTree()} - for _, item := range tc.items { - exhibition.items.Set(item.id.String(), item) - } - - // Get a single record - ds := Datasource{exhibition} - r, err := ds.Record(tc.id) - - // Start asserting - if tc.err != "" { - uassert.ErrorContains(t, err, tc.err) - return - } - - urequire.NoError(t, err, "no error") - urequire.NotEqual(t, nil, r, "record not nil") - uassert.Equal(t, tc.id, r.ID()) - }) - } -} - -func TestItemRecord(t *testing.T) { - pkgpath := "gno.land/r/demo/test" - item := Item{ - id: 1, - pkgpath: pkgpath, - title: "Test Realm", - description: "This is a test realm in the Hall of Fame", - blockNum: 42, - upvote: &addrset.Set{}, - downvote: &addrset.Set{}, - } - item.downvote.Add("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") - item.upvote.Add("g1w4ek2u33ta047h6lta047h6lta047h6ldvdwpn") - item.upvote.Add("g1w4ek2u3jta047h6lta047h6lta047h6l9huexc") - - r := record{&item} - - uassert.Equal(t, "0000001", r.ID()) - uassert.Equal(t, pkgpath, r.String()) - - fields, _ := r.Fields() - details, found := fields.Get("details") - urequire.True(t, found, "details field") - uassert.Equal(t, "Votes: ⏶ 2 - ⏷ 1", details) - - content, _ := r.Content() - wantContent := md.H1(item.title) + - md.H2(r.item.description) + - ufmt.Sprintf("\n%s\n\n", md.CodeBlock(item.pkgpath)) + - ufmt.Sprintf("%s\n\n", item.description) + - ufmt.Sprintf("by %s\n\n", strings.Split(item.pkgpath, "/")[2]) + - md.Link("View Realm", strings.TrimPrefix(item.pkgpath, "gno.land")) + "\n\n" + - ufmt.Sprintf("Submitted at Block #%d\n\n", item.blockNum) + - md.Bold(ufmt.Sprintf("[%d👍](%s) - [%d👎](%s)", - item.upvote.Size(), txlink.Call("Upvote", "pkgpath", item.pkgpath), - item.downvote.Size(), txlink.Call("Downvote", "pkgpath", item.pkgpath), - )) - uassert.Equal(t, wantContent, content) -} diff --git a/examples/gno.land/r/leon/hof/errors.gno b/examples/gno.land/r/leon/hof/errors.gno deleted file mode 100644 index 5fe51c922cd..00000000000 --- a/examples/gno.land/r/leon/hof/errors.gno +++ /dev/null @@ -1,11 +0,0 @@ -package hof - -import ( - "gno.land/p/leon/pkgerr" -) - -var ( - ErrNoSuchItem = pkgerr.New("no such item exists") - ErrDoubleUpvote = pkgerr.New("cannot upvote twice") - ErrDoubleDownvote = pkgerr.New("cannot downvote twice") -) diff --git a/examples/gno.land/r/leon/hof/gno.mod b/examples/gno.land/r/leon/hof/gno.mod deleted file mode 100644 index f4720eb2b5a..00000000000 --- a/examples/gno.land/r/leon/hof/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/r/leon/hof diff --git a/examples/gno.land/r/leon/hof/hof.gno b/examples/gno.land/r/leon/hof/hof.gno deleted file mode 100644 index 82b7333d1d2..00000000000 --- a/examples/gno.land/r/leon/hof/hof.gno +++ /dev/null @@ -1,200 +0,0 @@ -// Package hof is the hall of fame realm. -// The Hall of Fame is an exhibition that holds items. Users can add their realms to the Hall of Fame by -// importing the Hall of Fame realm and calling hof.Register() from their init function. -package hof - -import ( - "std" - "strconv" - "strings" - - "gno.land/p/demo/avl" - "gno.land/p/demo/ownable" - "gno.land/p/demo/pausable" - "gno.land/p/demo/seqid" - "gno.land/p/moul/addrset" - "gno.land/r/leon/config" -) - -const ( - maxTitleLength = 30 - maxDescriptionLength = 50 -) - -var ( - exhibition *Exhibition - - // Safe objects - Ownable *ownable.Ownable - Pausable *pausable.Pausable -) - -type ( - Exhibition struct { - itemCounter seqid.ID - description string - items *avl.Tree // pkgPath > *Item - itemsSortedByCreation *avl.Tree // same data but sorted by creation time - itemsSortedByUpvotes *avl.Tree // same data but sorted by upvotes - itemsSortedByDownvotes *avl.Tree // same data but sorted by downvotes - } - - Item struct { - id seqid.ID - title string - description string - pkgpath string - blockNum int64 - upvote *addrset.Set - downvote *addrset.Set - } -) - -func init() { - exhibition = &Exhibition{ - items: avl.NewTree(), - itemsSortedByCreation: avl.NewTree(), - itemsSortedByUpvotes: avl.NewTree(), - itemsSortedByDownvotes: avl.NewTree(), - } - - Ownable = ownable.NewWithAddress(config.OwnableMain.Owner()) // OrigSendOwnable? - Pausable = pausable.NewFromOwnable(Ownable) -} - -// Register registers your realm to the Hall of Fame -// Should be called from within code -func Register(title, description string) { - if Pausable.IsPaused() { - return - } - - submission := std.PreviousRealm() - pkgpath := submission.PkgPath() - - // Must be called from code - if submission.IsUser() { - return - } - - // Must not yet exist - if exhibition.items.Has(pkgpath) { - return - } - - // Title must be between 1 maxTitleLength long - if title == "" || len(title) > maxTitleLength { - return - } - - // Description must be between 1 maxDescriptionLength long - if len(description) > maxDescriptionLength { - return - } - - id := exhibition.itemCounter.Next() - i := &Item{ - id: id, - title: title, - description: description, - pkgpath: pkgpath, - blockNum: std.ChainHeight(), - upvote: &addrset.Set{}, - downvote: &addrset.Set{}, - } - - exhibition.items.Set(pkgpath, i) - exhibition.itemsSortedByCreation.Set(getCreationSortKey(i.blockNum, i.id), i) - exhibition.itemsSortedByUpvotes.Set(getVoteSortKey(i.upvote.Size(), i.id), i) - exhibition.itemsSortedByDownvotes.Set(getVoteSortKey(i.downvote.Size(), i.id), i) - - std.Emit("Registration") -} - -func Upvote(pkgpath string) { - rawItem, ok := exhibition.items.Get(pkgpath) - if !ok { - panic(ErrNoSuchItem) - } - - item := rawItem.(*Item) - caller := std.PreviousRealm().Address() - - if item.upvote.Has(caller) { - panic(ErrDoubleUpvote) - } - - if _, exists := exhibition.itemsSortedByUpvotes.Remove(getVoteSortKey(item.upvote.Size(), item.id)); !exists { - panic("error removing old upvote entry") - } - - item.upvote.Add(caller) - - exhibition.itemsSortedByUpvotes.Set(getVoteSortKey(item.upvote.Size(), item.id), item) -} - -func Downvote(pkgpath string) { - rawItem, ok := exhibition.items.Get(pkgpath) - if !ok { - panic(ErrNoSuchItem) - } - - item := rawItem.(*Item) - caller := std.PreviousRealm().Address() - - if item.downvote.Has(caller) { - panic(ErrDoubleDownvote) - } - - if _, exist := exhibition.itemsSortedByDownvotes.Remove(getVoteSortKey(item.downvote.Size(), item.id)); !exist { - panic("error removing old downvote entry") - - } - - item.downvote.Add(caller) - - exhibition.itemsSortedByDownvotes.Set(getVoteSortKey(item.downvote.Size(), item.id), item) -} - -func Delete(pkgpath string) { - if !Ownable.CallerIsOwner() { - panic(ownable.ErrUnauthorized) - } - - i, ok := exhibition.items.Get(pkgpath) - if !ok { - panic(ErrNoSuchItem) - } - - item := i.(*Item) - upvoteKey := getVoteSortKey(item.upvote.Size(), item.id) - downvoteKey := getVoteSortKey(item.downvote.Size(), item.id) - - if _, removed := exhibition.items.Remove(pkgpath); !removed { - panic(ErrNoSuchItem) - } - - if _, removed := exhibition.itemsSortedByUpvotes.Remove(upvoteKey); !removed { - panic(ErrNoSuchItem) - } - - if _, removed := exhibition.itemsSortedByDownvotes.Remove(downvoteKey); !removed { - panic(ErrNoSuchItem) - } - - if _, removed := exhibition.itemsSortedByCreation.Remove(getCreationSortKey(item.blockNum, item.id)); !removed { - panic(ErrNoSuchItem) - } -} - -func getVoteSortKey(votes int, id seqid.ID) string { - votesStr := strconv.Itoa(votes) - paddedVotes := strings.Repeat("0", 10-len(votesStr)) + votesStr - return paddedVotes + ":" + strconv.FormatUint(uint64(id), 10) -} - -func getCreationSortKey(blockNum int64, id seqid.ID) string { - blockNumStr := strconv.Itoa(int(blockNum)) - paddedBlockNum := strings.Repeat("0", 10-len(blockNumStr)) + blockNumStr - return paddedBlockNum + ":" + strconv.FormatUint(uint64(id), 10) -} diff --git a/examples/gno.land/r/leon/hof/hof_test.gno b/examples/gno.land/r/leon/hof/hof_test.gno deleted file mode 100644 index 3ee2ac29a4b..00000000000 --- a/examples/gno.land/r/leon/hof/hof_test.gno +++ /dev/null @@ -1,327 +0,0 @@ -package hof - -import ( - "std" - "testing" - - "gno.land/p/demo/testutils" - "gno.land/p/demo/uassert" - "gno.land/p/demo/urequire" - "gno.land/p/moul/addrset" -) - -const ( - rlmPath = "gno.land/r/gnoland/home" - rlmPath2 = "gno.land/r/gnoland/test2" - - rlmPath3 = "gno.land/r/gnoland/test3" - rlmPath4 = "gno.land/r/gnoland/test4" - rlmPath5 = "gno.land/r/gnoland/test5" - - validTitle = "valid title" - invalidTitle = "This title is very very very long, longer than 30 characters" - validDesc = "valid description" - invalidDescription = "This description is very very very long, longer than 50 characters" -) - -var ( - admin = Ownable.Owner() - adminRealm = std.NewUserRealm(admin) - alice = testutils.TestAddress("alice") -) - -func TestRegister(t *testing.T) { - // Test user realm register - aliceRealm := std.NewUserRealm(alice) - testing.SetRealm(aliceRealm) - - Register(validTitle, validDesc) - uassert.False(t, itemExists(t, rlmPath)) - - // Test register while paused - testing.SetRealm(adminRealm) - Pausable.Pause() - - // Set legitimate caller - testing.SetRealm(std.NewCodeRealm(rlmPath)) - - Register(validTitle, validDesc) - uassert.False(t, itemExists(t, rlmPath)) - - // Unpause - testing.SetRealm(adminRealm) - Pausable.Unpause() - - // Set legitimate caller - testing.SetRealm(std.NewCodeRealm(rlmPath)) - Register(validTitle, validDesc) - - // Find registered items - uassert.True(t, itemExists(t, rlmPath)) - - // Test register with invalid title - testing.SetRealm(std.NewCodeRealm(rlmPath2)) - Register(invalidTitle, validDesc) - uassert.False(t, itemExists(t, rlmPath2)) - - // Test register with invalid description - testing.SetRealm(std.NewCodeRealm(rlmPath2)) - Register(validTitle, invalidDescription) - uassert.False(t, itemExists(t, rlmPath2)) -} - -func TestUpvote(t *testing.T) { - raw, _ := exhibition.items.Get(rlmPath) - item := raw.(*Item) - - // 0 upvotes by default - urequire.Equal(t, item.upvote.Size(), 0) - - testing.SetRealm(adminRealm) - - urequire.NotPanics(t, func() { - Upvote(rlmPath) - }) - - // Check both trees for 1 upvote - uassert.Equal(t, item.upvote.Size(), 1) - - // Check double upvote - uassert.PanicsWithMessage(t, ErrDoubleUpvote.Error(), func() { - Upvote(rlmPath) - }) -} - -func TestDownvote(t *testing.T) { - raw, _ := exhibition.items.Get(rlmPath) - item := raw.(*Item) - - // 0 downvotes by default - urequire.Equal(t, item.downvote.Size(), 0) - - userRealm := std.NewUserRealm(alice) - testing.SetRealm(userRealm) - - urequire.NotPanics(t, func() { - Downvote(rlmPath) - }) - - // Check both trees for 1 upvote - uassert.Equal(t, item.downvote.Size(), 1) - - // Check double downvote - uassert.PanicsWithMessage(t, ErrDoubleDownvote.Error(), func() { - Downvote(rlmPath) - }) -} - -func TestDelete(t *testing.T) { - userRealm := std.NewUserRealm(admin) - testing.SetRealm(userRealm) - testing.SetOriginCaller(admin) - - uassert.PanicsWithMessage(t, ErrNoSuchItem.Error(), func() { - Delete("nonexistentpkgpath") - }) - - i, _ := exhibition.items.Get(rlmPath) - id := i.(*Item).id - - uassert.NotPanics(t, func() { - Delete(rlmPath) - }) - - uassert.False(t, exhibition.items.Has(rlmPath)) -} - -func itemExists(t *testing.T, rlmPath string) bool { - t.Helper() - - i, ok1 := exhibition.items.Get(rlmPath) - - return ok1 -} - -func TestgetVoteSortKey(t *testing.T) { - i := &Item{ - id: 1, - title: validTitle, - description: validDesc, - pkgpath: rlmPath, - blockNum: std.ChainHeight(), - upvote: &addrset.Set{}, - downvote: &addrset.Set{}, - } - - i.upvote.Add(alice) - - generatedKey := getVoteSortKey(i.upvote.Size(), i.id) - expectedKey := "0000000001:1" - - urequire.Equal(t, generatedKey, expectedKey) -} - -func TestSortByUpvote(t *testing.T) { - // Remove all items from all trees - exhibition.items.Iterate("", "", func(key string, value interface{}) bool { - exhibition.items.Remove(key) - return false - }) - exhibition.itemsSortedByUpvotes.Iterate("", "", func(key string, value interface{}) bool { - exhibition.itemsSortedByUpvotes.Remove(key) - return false - }) - exhibition.itemsSortedByDownvotes.Iterate("", "", func(key string, value interface{}) bool { - exhibition.itemsSortedByDownvotes.Remove(key) - return false - }) - exhibition.itemsSortedByCreation.Iterate("", "", func(key string, value interface{}) bool { - exhibition.itemsSortedByCreation.Remove(key) - return false - }) - - // Add items - testing.SetRealm(std.NewCodeRealm(rlmPath3)) - Register(validTitle, validDesc) - - testing.SetRealm(std.NewCodeRealm(rlmPath4)) - Register(validTitle, validDesc) - - testing.SetRealm(std.NewCodeRealm(rlmPath5)) - Register(validTitle, validDesc) - - user1 := testutils.TestAddress("user1") - user2 := testutils.TestAddress("user2") - user3 := testutils.TestAddress("user3") - - testing.SetOriginCaller(user1) - testing.SetRealm(std.NewUserRealm(user1)) - Upvote(rlmPath3) - Upvote(rlmPath4) - Upvote(rlmPath5) - - testing.SetOriginCaller(user2) - testing.SetRealm(std.NewUserRealm(user2)) - Upvote(rlmPath4) - Upvote(rlmPath5) - - testing.SetOriginCaller(user3) - testing.SetRealm(std.NewUserRealm(user3)) - Upvote(rlmPath5) - - // We are displaying data in reverse order in render, so items should be sorted in reverse order - firstKey, firstRawValue := exhibition.itemsSortedByUpvotes.GetByIndex(0) - firstValue := firstRawValue.(*Item) - uassert.Equal(t, firstValue.pkgpath, rlmPath3) - - secondKey, secondRawValue := exhibition.itemsSortedByUpvotes.GetByIndex(1) - secondValue := secondRawValue.(*Item) - uassert.Equal(t, secondValue.pkgpath, rlmPath4) -} - -func TestSortByDownvote(t *testing.T) { - // Remove all items from all trees - exhibition.items.Iterate("", "", func(key string, value interface{}) bool { - exhibition.items.Remove(key) - return false - }) - exhibition.itemsSortedByUpvotes.Iterate("", "", func(key string, value interface{}) bool { - exhibition.itemsSortedByUpvotes.Remove(key) - return false - }) - exhibition.itemsSortedByDownvotes.Iterate("", "", func(key string, value interface{}) bool { - exhibition.itemsSortedByDownvotes.Remove(key) - return false - }) - exhibition.itemsSortedByCreation.Iterate("", "", func(key string, value interface{}) bool { - exhibition.itemsSortedByCreation.Remove(key) - return false - }) - - // Add items - testing.SetRealm(std.NewCodeRealm(rlmPath3)) - Register(validTitle, validDesc) - - testing.SetRealm(std.NewCodeRealm(rlmPath4)) - Register(validTitle, validDesc) - - testing.SetRealm(std.NewCodeRealm(rlmPath5)) - Register(validTitle, validDesc) - - user1 := testutils.TestAddress("user1") - user2 := testutils.TestAddress("user2") - user3 := testutils.TestAddress("user3") - - testing.SetOriginCaller(user1) - testing.SetRealm(std.NewUserRealm(user1)) - Downvote(rlmPath3) - Downvote(rlmPath4) - Downvote(rlmPath5) - - testing.SetOriginCaller(user2) - testing.SetRealm(std.NewUserRealm(user2)) - Downvote(rlmPath4) - Downvote(rlmPath5) - - testing.SetOriginCaller(user3) - testing.SetRealm(std.NewUserRealm(user3)) - Downvote(rlmPath5) - - // We are dispalying data is reverse order in render, so items should be sorted in reverse order - firstKey, firstRawValue := exhibition.itemsSortedByDownvotes.GetByIndex(0) - - firstValue := firstRawValue.(*Item) - - uassert.Equal(t, firstValue.pkgpath, rlmPath3) - - secondKey, secondRawValue := exhibition.itemsSortedByDownvotes.GetByIndex(1) - - secondValue := secondRawValue.(*Item) - - uassert.Equal(t, secondValue.pkgpath, rlmPath4) -} - -func TestSortByCreation(t *testing.T) { - // Remove all items from all trees - exhibition.items.Iterate("", "", func(key string, value interface{}) bool { - exhibition.items.Remove(key) - return false - }) - exhibition.itemsSortedByUpvotes.Iterate("", "", func(key string, value interface{}) bool { - exhibition.itemsSortedByUpvotes.Remove(key) - return false - }) - exhibition.itemsSortedByDownvotes.Iterate("", "", func(key string, value interface{}) bool { - exhibition.itemsSortedByDownvotes.Remove(key) - return false - }) - exhibition.itemsSortedByCreation.Iterate("", "", func(key string, value interface{}) bool { - exhibition.itemsSortedByCreation.Remove(key) - return false - }) - - testing.SkipHeights(10) - testing.SetRealm(std.NewCodeRealm(rlmPath3)) - Register(validTitle, validDesc) - - testing.SkipHeights(10) - testing.SetRealm(std.NewCodeRealm(rlmPath4)) - Register(validTitle, validDesc) - - testing.SkipHeights(10) - testing.SetRealm(std.NewCodeRealm(rlmPath5)) - Register(validTitle, validDesc) - - // We are dispalying data is reverse order in render, so items should be sorted in reverse order - firstKey, firstRawValue := exhibition.itemsSortedByCreation.GetByIndex(0) - - firstValue := firstRawValue.(*Item) - - uassert.Equal(t, firstValue.pkgpath, rlmPath3) - - secondKey, secondRawValue := exhibition.itemsSortedByCreation.GetByIndex(1) - - secondValue := secondRawValue.(*Item) - - uassert.Equal(t, secondValue.pkgpath, rlmPath4) -} diff --git a/examples/gno.land/r/leon/hof/render.gno b/examples/gno.land/r/leon/hof/render.gno deleted file mode 100644 index 35b31cb87e0..00000000000 --- a/examples/gno.land/r/leon/hof/render.gno +++ /dev/null @@ -1,140 +0,0 @@ -package hof - -import ( - "net/url" - "strings" - - "gno.land/p/demo/avl" - "gno.land/p/demo/avl/pager" - "gno.land/p/demo/fqname" - "gno.land/p/demo/ufmt" - "gno.land/p/moul/md" - "gno.land/p/moul/txlink" -) - -const ( - pageSize = 5 -) - -func Render(path string) string { - out := md.H1("Hall of Fame\n\n") - out += md.Link("Reset Sort", "?") + " | " - out += md.Link("Sort by Upvotes", "?sort=upvotes") + " | " - out += md.Link("Sort by Downvotes", "?sort=downvotes") + " | " - out += md.Link("Sort by Most Recent", "?sort=creation") + " | " - out += md.Link("Sort by Oldest", "?sort=oldest") + "\n\n" - - dashboardEnabled := path == "dashboard" - - if dashboardEnabled { - out += renderDashboard() - } - - out += exhibition.Render(path, dashboardEnabled) - - return out -} - -func (e Exhibition) Render(path string, dashboard bool) string { - tree := getTreeByPath(&e, path) - - u, _ := url.Parse(path) - reversed := u.Query().Get("sort") != "oldest" - - page := pager.NewPager(tree, pageSize, reversed).MustGetPageByPath(path) - - out := ufmt.Sprintf("%s\n\n", e.description) - - if e.items.Size() == 0 { - out += "No items in this exhibition currently.\n\n" - return out - } - - out += "
\n\n" - - for _, item := range page.Items { - out += "
\n\n" - itemValue := item.Value.(*Item) - out += md.H3(itemValue.title + "\n\n") - out += itemValue.Render(dashboard) - out += "
" - } - - out += "
\n\n" - - out += page.Picker(path) - - return out -} - -func (i Item) Render(dashboard bool) string { - out := ufmt.Sprintf("\n%s\n\n", md.CodeBlock(i.pkgpath)) - out += ufmt.Sprintf("%s\n\n", i.description) - out += ufmt.Sprintf("by %s\n\n", strings.Split(i.pkgpath, "/")[2]) - out += md.Link("View Realm", strings.TrimPrefix(i.pkgpath, "gno.land")) + "\n\n" - out += ufmt.Sprintf("Submitted at Block #%d\n\n", i.blockNum) - - out += md.Bold(ufmt.Sprintf("[%d👍](%s) - [%d👎](%s)", - i.upvote.Size(), txlink.Call("Upvote", "pkgpath", i.pkgpath), - i.downvote.Size(), txlink.Call("Downvote", "pkgpath", i.pkgpath), - )) - - if dashboard { - out += md.Link("Delete", txlink.Call("Delete", "pkgpath", i.pkgpath)) - } - - return out -} - -func renderDashboard() string { - out := md.HorizontalRule() - out += md.H2("Dashboard\n\n") - out += ufmt.Sprintf("Total submissions: %d\n\n", exhibition.items.Size()) - - out += ufmt.Sprintf("Exhibition admin: %s\n\n", Ownable.Owner().String()) - - if !Pausable.IsPaused() { - out += md.Link("Pause exhibition", txlink.Call("Pause")) - } else { - out += md.Link("Unpause exhibition", txlink.Call("Unpause")) - } - - out += md.HorizontalRule() - - return out -} - -func RenderExhibWidget(itemsToRender int) string { - if itemsToRender < 1 { - return "" - } - - out := "" - i := 0 - exhibition.items.Iterate("", "", func(key string, value any) bool { - item := value.(*Item) - - out += ufmt.Sprintf("- %s\n", fqname.RenderLink(item.pkgpath, "")) - - i++ - return i >= itemsToRender - }) - - return out -} - -func getTreeByPath(e *Exhibition, path string) *avl.Tree { - u, _ := url.Parse(path) - switch u.Query().Get("sort") { - case "upvotes": - return e.itemsSortedByUpvotes - case "downvotes": - return e.itemsSortedByDownvotes - case "creation": - return e.itemsSortedByCreation - case "oldest": - return e.itemsSortedByCreation - default: - return e.items - } -} diff --git a/examples/gno.land/r/leon/home/gno.mod b/examples/gno.land/r/leon/home/gno.mod deleted file mode 100644 index 56fea265e29..00000000000 --- a/examples/gno.land/r/leon/home/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/r/leon/home diff --git a/examples/gno.land/r/leon/home/home.gno b/examples/gno.land/r/leon/home/home.gno deleted file mode 100644 index 657df7f3d6e..00000000000 --- a/examples/gno.land/r/leon/home/home.gno +++ /dev/null @@ -1,134 +0,0 @@ -package home - -import ( - "std" - "strconv" - - "gno.land/p/demo/ufmt" - - "gno.land/r/demo/art/gnoface" - "gno.land/r/demo/art/millipede" - "gno.land/r/demo/mirror" - "gno.land/r/leon/config" - "gno.land/r/leon/hof" -) - -var ( - pfp string // link to profile picture - pfpCaption string // profile picture caption - abtMe [2]string -) - -func Render(path string) string { - out := "# Leon's Homepage\n\n" - - out += renderAboutMe() - out += renderBlogPosts() - out += "\n\n" - out += renderArt() - out += "\n\n" - out += config.Banner() - out += "\n\n" - - return out -} - -func init() { - hof.Register("Leon's Home Realm", "") - mirror.Register(std.CurrentRealm().PkgPath(), Render) - - pfp = "https://i.imgflip.com/91vskx.jpg" - pfpCaption = "[My favourite painting & pfp](https://en.wikipedia.org/wiki/Wanderer_above_the_Sea_of_Fog)" - abtMe = [2]string{ - `### About me -Hi, I'm Leon, a DevRel Engineer at gno.land. I am a tech enthusiast, -life-long learner, and sharer of knowledge.`, - `### Contributions -My contributions to gno.land can mainly be found -[here](https://github.com/gnolang/gno/issues?q=sort:updated-desc+author:leohhhn). - -TODO import r/gh`, - } -} - -func UpdatePFP(url, caption string) { - if !config.IsAuthorized(std.PreviousRealm().Address()) { - panic(config.ErrUnauthorized) - } - - pfp = url - pfpCaption = caption -} - -func UpdateAboutMe(col1, col2 string) { - if !config.IsAuthorized(std.PreviousRealm().Address()) { - panic(config.ErrUnauthorized) - } - - abtMe[0] = col1 - abtMe[1] = col2 -} - -func renderBlogPosts() string { - out := "" - // out += "## Leon's Blog Posts" - - // todo fetch blog posts authored by @leohhhn - // and render them - return out -} - -func renderAboutMe() string { - out := "
" - - out += "
\n\n" - out += ufmt.Sprintf("![my profile pic](%s)\n\n%s\n\n", pfp, pfpCaption) - out += "
\n\n" - - out += "
\n\n" - out += abtMe[0] + "\n\n" - out += "
\n\n" - - out += "
\n\n" - out += abtMe[1] + "\n\n" - out += "
\n\n" - - out += "
\n\n" - - return out -} - -func renderArt() string { - out := `
` + "\n\n" - out += "# Gno Art\n\n" - - out += "
" - - out += renderGnoFace() - out += renderMillipede() - out += "Empty spot :/" - - out += "
\n\n" - - out += "This art is dynamic; it will change with every new block.\n\n" - out += `
` + "\n" - - return out -} - -func renderGnoFace() string { - out := "
\n\n" - out += gnoface.Render(strconv.Itoa(int(std.ChainHeight()))) - out += "
\n\n" - - return out -} - -func renderMillipede() string { - out := "
\n\n" - out += "Millipede\n\n" - out += "```\n" + millipede.Draw(int(std.ChainHeight())%10+1) + "```\n" - out += "
\n\n" - - return out -} diff --git a/examples/gno.land/r/leon/registree/gno.mod b/examples/gno.land/r/leon/registree/gno.mod new file mode 100644 index 00000000000..3af7024740f --- /dev/null +++ b/examples/gno.land/r/leon/registree/gno.mod @@ -0,0 +1 @@ +module gno.land/r/leon/registree diff --git a/examples/gno.land/r/leon/registree/item.gno b/examples/gno.land/r/leon/registree/item.gno new file mode 100644 index 00000000000..87f3d64e3bc --- /dev/null +++ b/examples/gno.land/r/leon/registree/item.gno @@ -0,0 +1,11 @@ +package registree + +import registry "gno.land/r/leon/registry" + +func ManualRegister() { + crossing(registry.Register) +} + +func init() { + crossing(registry.Register) +} diff --git a/examples/gno.land/r/leon/registry/gno.mod b/examples/gno.land/r/leon/registry/gno.mod new file mode 100644 index 00000000000..fbde31071c0 --- /dev/null +++ b/examples/gno.land/r/leon/registry/gno.mod @@ -0,0 +1 @@ +module gno.land/r/leon/registry diff --git a/examples/gno.land/r/leon/registry/reg.gno b/examples/gno.land/r/leon/registry/reg.gno new file mode 100644 index 00000000000..e8b3cac35ac --- /dev/null +++ b/examples/gno.land/r/leon/registry/reg.gno @@ -0,0 +1,34 @@ +package registry + +import ( + "std" + + "gno.land/p/demo/avl" + "gno.land/p/demo/ufmt" +) + +var tree = avl.NewTree() + +func Register() { + crossing() + if std.PreviousRealm().IsUser() { + return + } + + if tree.Has(std.PreviousRealm().PkgPath()) { + return + } + + tree.Set(std.PreviousRealm().PkgPath(), std.PreviousRealm().Address()) +} + +func Render(_ string) string { + out := "# Registry\n\n" + + tree.Iterate("", "", func(key string, value any) bool { + out += ufmt.Sprintf("%s: %s", key, value.(string)) + return false + }) + + return out +} diff --git a/gno.land/pkg/sdk/vm/keeper.go b/gno.land/pkg/sdk/vm/keeper.go index 1b2a729c693..4e2340f3609 100644 --- a/gno.land/pkg/sdk/vm/keeper.go +++ b/gno.land/pkg/sdk/vm/keeper.go @@ -437,7 +437,7 @@ func (vm *VMKeeper) Call(ctx sdk.Context, msg MsgCall) (res string, err error) { } argslist += fmt.Sprintf("arg%d", i) } - expr := fmt.Sprintf(`pkg.%s(%s)`, fnc, argslist) + expr := fmt.Sprintf(`cross(pkg.%s)(%s)`, fnc, argslist) xn := gno.MustParseExpr(expr) // Send send-coins to pkg from caller. pkgAddr := gno.DerivePkgAddr(pkgPath) diff --git a/gnovm/cmd/gno/run.go b/gnovm/cmd/gno/run.go index a785cf17f1b..1b59a766d5b 100644 --- a/gnovm/cmd/gno/run.go +++ b/gnovm/cmd/gno/run.go @@ -112,7 +112,7 @@ func execRun(cfg *runCfg, args []string, io commands.IO) error { var send std.Coins pkgPath := string(files[0].PkgName) - ctx := test.Context(pkgPath, send) + ctx := test.Context("", pkgPath, send) m := gno.NewMachineWithOptions(gno.MachineOptions{ PkgPath: pkgPath, Output: output, diff --git a/gnovm/cmd/gno/test.go b/gnovm/cmd/gno/test.go index 2ed3c6321cb..c6cab2be43e 100644 --- a/gnovm/cmd/gno/test.go +++ b/gnovm/cmd/gno/test.go @@ -15,7 +15,6 @@ import ( "github.com/gnolang/gno/gnovm/pkg/gnomod" "github.com/gnolang/gno/gnovm/pkg/test" "github.com/gnolang/gno/tm2/pkg/commands" - "github.com/gnolang/gno/tm2/pkg/random" ) type testCfg struct { @@ -51,8 +50,8 @@ functions. Benchmark and fuzz functions aren't supported yet. Similarly, only tests that belong to the same package are supported for now (no "xxx_test"). The package path used to execute the "*_test.gno" file is fetched from the -module name found in 'gno.mod', or else it is randomly generated like -"gno.land/r/XXXXXXXX". +module name found in 'gno.mod', or else it is set to +"gno.land/r/txtar". - "*_filetest.gno" files on the other hand are kind of unique. They exist to provide a way to interact and assert a gno contract, thanks to a set of @@ -236,9 +235,9 @@ func execTest(cfg *testCfg, args []string, io commands.IO) error { } else { gnoPkgPath = pkgPathFromRootDir(pkg.Dir, cfg.rootDir) if gnoPkgPath == "" { - // unable to read pkgPath from gno.mod, generate a random realm path + // unable to read pkgPath from gno.mod, use a deterministic path. io.ErrPrintfln("--- WARNING: unable to read package path from gno.mod or gno root directory; try creating a gno.mod file") - gnoPkgPath = "gno.land/r/" + strings.ToLower(random.RandStr(8)) // XXX: gno.land hardcoded for convenience. + gnoPkgPath = "gno.land/r/txtar" // XXX: gno.land hardcoded for convenience. } } diff --git a/gnovm/cmd/gno/testdata/test/filetest_events.txtar b/gnovm/cmd/gno/testdata/test/filetest_events.txtar index 87f873980d5..12ba6110699 100644 --- a/gnovm/cmd/gno/testdata/test/filetest_events.txtar +++ b/gnovm/cmd/gno/testdata/test/filetest_events.txtar @@ -34,8 +34,7 @@ func main() { // { // "type": "EventA", // "attrs": [], -// "pkg_path": "", -// "func": "main" +// "pkg_path": "" // }, // { // "type": "EventB", @@ -45,7 +44,6 @@ func main() { // "value": "valA" // } // ], -// "pkg_path": "", -// "func": "main" +// "pkg_path": "" // } // ] diff --git a/gnovm/cmd/gno/testdata/test/multitest_events.txtar b/gnovm/cmd/gno/testdata/test/multitest_events.txtar index 5cb134f46a1..28d4fe1fe9a 100644 --- a/gnovm/cmd/gno/testdata/test/multitest_events.txtar +++ b/gnovm/cmd/gno/testdata/test/multitest_events.txtar @@ -3,8 +3,8 @@ gno test -print-events . ! stdout .+ -stderr 'EVENTS: \[{\"type\":\"EventA\",\"attrs\":\[\],\"pkg_path\":\"gno.land/r/.*\",\"func\":\"TestA\"}\]' -stderr 'EVENTS: \[{\"type\":\"EventB\",\"attrs\":\[{\"key\":\"keyA\",\"value\":\"valA\"}\],\"pkg_path\":\"gno.land/r/.*\",\"func\":\"TestB\"},{\"type\":\"EventC\",\"attrs\":\[{\"key\":\"keyD\",\"value\":\"valD\"}\],\"pkg_path\":\"gno.land/r/.*\",\"func\":\"TestB\"}\]' +stderr 'EVENTS: \[{\"type\":\"EventA\",\"attrs\":\[\],\"pkg_path\":\"gno.land/r/.*\"\}]' +stderr 'EVENTS: \[{\"type\":\"EventB\",\"attrs\":\[{\"key\":\"keyA\",\"value\":\"valA\"}\],\"pkg_path\":\"gno.land/r/.*\"},{\"type\":\"EventC\",\"attrs\":\[{\"key\":\"keyD\",\"value\":\"valD\"}\],\"pkg_path\":\"gno.land/r/.*\"}\]' stderr 'ok \. \d+\.\d\ds' -- valid.gno -- diff --git a/gnovm/cmd/gno/testdata/test/realm_boundmethod.txtar b/gnovm/cmd/gno/testdata/test/realm_boundmethod.txtar index 0d6ffd24a92..273b1809f93 100644 --- a/gnovm/cmd/gno/testdata/test/realm_boundmethod.txtar +++ b/gnovm/cmd/gno/testdata/test/realm_boundmethod.txtar @@ -55,6 +55,8 @@ package tests import "gno.land/r/demo/realm2" func main() { + crossing() + realm2.Do() println("OK") } diff --git a/gnovm/cmd/gno/testdata/test/realm_correct.txtar b/gnovm/cmd/gno/testdata/test/realm_correct.txtar index c1763860271..c5db2719a63 100644 --- a/gnovm/cmd/gno/testdata/test/realm_correct.txtar +++ b/gnovm/cmd/gno/testdata/test/realm_correct.txtar @@ -14,17 +14,25 @@ package xx var x int func main() { + crossing() + x = 1 } // Realm: // switchrealm["gno.land/r/xx"] -// u[aea84df38908f9569d0f552575606e6e6e7e22dd:2]= -// @@ -19,6 +19,7 @@ +// u[aea84df38908f9569d0f552575606e6e6e7e22dd:3]= +// @@ -1,11 +1,12 @@ +// { +// "ObjectInfo": { +// "ID": "aea84df38908f9569d0f552575606e6e6e7e22dd:3", +// - "ModTime": "0", +// + "ModTime": "5", +// "OwnerID": "aea84df38908f9569d0f552575606e6e6e7e22dd:2", +// "RefCount": "1" // }, -// "Values": [ -// { -// + "N": "AQAAAAAAAAA=", -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "32" +// "Value": { +// + "N": "AQAAAAAAAAA=", +// "T": { +// "@type": "/gno.PrimitiveType", +// "value": "32" diff --git a/gnovm/cmd/gno/testdata/test/realm_incorrect.txtar b/gnovm/cmd/gno/testdata/test/realm_incorrect.txtar index 34a4c62f591..c64e9a1104d 100644 --- a/gnovm/cmd/gno/testdata/test/realm_incorrect.txtar +++ b/gnovm/cmd/gno/testdata/test/realm_incorrect.txtar @@ -6,10 +6,10 @@ stderr '=== RUN file/x_filetest.gno' stderr 'Realm diff:' stderr '--- Expected' -stderr '@@ -1,2 \+1,11 @@' stderr '-xxxx' stderr '-xxx' stderr '\+switchrealm\["gno.land/r/xx"\]' +stderr '\+ @@ -1,11 \+1,12 @@' stderr 'x_filetest.gno failed' -- x_filetest.gno -- @@ -19,6 +19,8 @@ package xx var x int func main() { + crossing() + x = 1 } diff --git a/gnovm/cmd/gno/testdata/test/realm_sync.txtar b/gnovm/cmd/gno/testdata/test/realm_sync.txtar index c08287e3e21..a2c2980bf37 100644 --- a/gnovm/cmd/gno/testdata/test/realm_sync.txtar +++ b/gnovm/cmd/gno/testdata/test/realm_sync.txtar @@ -16,6 +16,8 @@ package xx var x int func main() { + crossing() + x = 1 } @@ -28,17 +30,25 @@ package xx var x int func main() { + crossing() + x = 1 } // Realm: // switchrealm["gno.land/r/xx"] -// u[aea84df38908f9569d0f552575606e6e6e7e22dd:2]= -// @@ -19,6 +19,7 @@ +// u[aea84df38908f9569d0f552575606e6e6e7e22dd:3]= +// @@ -1,11 +1,12 @@ +// { +// "ObjectInfo": { +// "ID": "aea84df38908f9569d0f552575606e6e6e7e22dd:3", +// - "ModTime": "0", +// + "ModTime": "5", +// "OwnerID": "aea84df38908f9569d0f552575606e6e6e7e22dd:2", +// "RefCount": "1" // }, -// "Values": [ -// { -// + "N": "AQAAAAAAAAA=", -// "T": { -// "@type": "/gno.PrimitiveType", -// "value": "32" +// "Value": { +// + "N": "AQAAAAAAAAA=", +// "T": { +// "@type": "/gno.PrimitiveType", +// "value": "32" diff --git a/gnovm/cmd/gno/testdata/test/two_packages_init.txtar b/gnovm/cmd/gno/testdata/test/two_packages_init.txtar index 280fd1d529e..1cafa8767b7 100644 --- a/gnovm/cmd/gno/testdata/test/two_packages_init.txtar +++ b/gnovm/cmd/gno/testdata/test/two_packages_init.txtar @@ -15,7 +15,7 @@ package aa import "gno.land/r/demo/bb" func init() { - bb.Call() + cross(bb).Call() } -- examples/gno.land/r/demo/aa/a_test.gno -- @@ -31,6 +31,8 @@ package bb var called int func Call() { + crossing() + called++ } diff --git a/gnovm/pkg/gnolang/debugger_test.go b/gnovm/pkg/gnolang/debugger_test.go index b8ed7b76c35..aa504c73f14 100644 --- a/gnovm/pkg/gnolang/debugger_test.go +++ b/gnovm/pkg/gnolang/debugger_test.go @@ -47,7 +47,7 @@ func evalTest(debugAddr, in, file string) (out, err string) { Input: stdin, Output: output, Store: testStore, - Context: test.Context(string(f.PkgName), nil), + Context: test.Context(test.DefaultCaller, string(f.PkgName), nil), Debug: true, }) diff --git a/gnovm/pkg/gnolang/frame.go b/gnovm/pkg/gnolang/frame.go index cedcb97f50b..0b27dd3eee3 100644 --- a/gnovm/pkg/gnolang/frame.go +++ b/gnovm/pkg/gnolang/frame.go @@ -27,15 +27,17 @@ type Frame struct { NumArgs int // number of arguments in call IsVarg bool // is form fncall(???, vargs...) Defers []Defer // deferred calls - LastPackage *PackageValue // previous package context - LastRealm *Realm // previous realm context + LastPackage *PackageValue // previous frame's package + LastRealm *Realm // previous frame's realm + WithCross bool // true if called like cross(fn)(...). expects crossing() after. + DidCross bool // true if crossing() was called. Popped bool // true if frame has been popped } func (fr Frame) String() string { if fr.Func != nil { - return fmt.Sprintf("[FRAME FUNC:%v RECV:%s (%d args) %d/%d/%d/%d/%d LASTPKG:%s LASTRLM:%v]", + return fmt.Sprintf("[FRAME FUNC:%v RECV:%s (%d args) %d/%d/%d/%d/%d LASTPKG:%s LASTRLM:%v WSW:%v DSW:%v]", fr.Func, fr.Receiver, fr.NumArgs, @@ -45,7 +47,9 @@ func (fr Frame) String() string { fr.NumStmts, fr.NumBlocks, fr.LastPackage.PkgPath, - fr.LastRealm) + fr.LastRealm, + fr.WithCross, + fr.DidCross) } else { return fmt.Sprintf("[FRAME LABEL: %s %d/%d/%d/%d/%d]", fr.Label, @@ -74,6 +78,20 @@ func (fr *Frame) PopDefer() (res Defer, ok bool) { return } +func (fr *Frame) SetWithCross() { + if fr.WithCross { + panic("fr.WithCross already set") + } + fr.WithCross = true +} + +func (fr *Frame) SetDidCross() { + if fr.DidCross { + panic("fr.DidCross already set") + } + fr.DidCross = true +} + //---------------------------------------- // Defer @@ -205,7 +223,7 @@ func toConstExpTrace(cte *ConstExpr) string { } } - return tv.T.String() + return tv.V.String() } //---------------------------------------- diff --git a/gnovm/pkg/gnolang/go2gno.go b/gnovm/pkg/gnolang/go2gno.go index a50a727dd6b..b6c0f3af683 100644 --- a/gnovm/pkg/gnolang/go2gno.go +++ b/gnovm/pkg/gnolang/go2gno.go @@ -241,15 +241,15 @@ func Go2Gno(fs *token.FileSet, gon ast.Node) (n Node) { case *ast.Field: if len(gon.Names) == 0 { return &FieldTypeExpr{ - Name: "", - Type: toExpr(fs, gon.Type), - Tag: toExpr(fs, gon.Tag), + NameExpr: *Nx(""), + Type: toExpr(fs, gon.Type), + Tag: toExpr(fs, gon.Tag), } } else if len(gon.Names) == 1 { return &FieldTypeExpr{ - Name: toName(gon.Names[0]), - Type: toExpr(fs, gon.Type), - Tag: toExpr(fs, gon.Tag), + NameExpr: *Nx(toName(gon.Names[0])), + Type: toExpr(fs, gon.Type), + Tag: toExpr(fs, gon.Tag), } } else { panicWithPos( @@ -764,17 +764,17 @@ func toFields(fs *token.FileSet, fields ...*ast.Field) (ftxs []FieldTypeExpr) { if len(f.Names) == 0 { // a single unnamed field w/ type ftxs = append(ftxs, FieldTypeExpr{ - Name: "", - Type: toExpr(fs, f.Type), - Tag: toExpr(fs, f.Tag), + NameExpr: *Nx(""), + Type: toExpr(fs, f.Type), + Tag: toExpr(fs, f.Tag), }) } else { // one or more named fields for _, n := range f.Names { ftxs = append(ftxs, FieldTypeExpr{ - Name: toName(n), - Type: toExpr(fs, f.Type), - Tag: toExpr(fs, f.Tag), + NameExpr: *Nx(toName(n)), + Type: toExpr(fs, f.Type), + Tag: toExpr(fs, f.Tag), }) } } diff --git a/gnovm/pkg/gnolang/gotypecheck.go b/gnovm/pkg/gnolang/gotypecheck.go index 8f86deb3dc5..22867e5745f 100644 --- a/gnovm/pkg/gnolang/gotypecheck.go +++ b/gnovm/pkg/gnolang/gotypecheck.go @@ -13,6 +13,7 @@ import ( "github.com/gnolang/gno/gnovm" "go.uber.org/multierr" + "golang.org/x/tools/go/ast/astutil" ) // type checking (using go/types) @@ -140,6 +141,8 @@ func (g *gnoImporter) parseCheckMemPackage(mpkg *gnovm.MemPackage, fmt bool) (*t deleteOldIdents(delFunc, f) } + filterCrossing(f) + // enforce formatting if fmt { var buf bytes.Buffer @@ -177,3 +180,27 @@ func deleteOldIdents(idents map[string]func(), f *ast.File) { } } } + +func filterCrossing(f *ast.File) { + astutil.Apply(f, nil, func(c *astutil.Cursor) bool { + switch n := c.Node().(type) { + case *ast.ExprStmt: + if ce, ok := n.X.(*ast.CallExpr); ok { + if id, ok := ce.Fun.(*ast.Ident); ok && id.Name == "crossing" { + // Delete statement 'crossing()'. + c.Delete() + } + } + case *ast.CallExpr: + if id, ok := n.Fun.(*ast.Ident); ok && id.Name == "cross" { + // Replace expression 'cross(x)' by 'x'. + var a ast.Node + if len(n.Args) > 0 { + a = n.Args[0] + } + c.Replace(a) + } + } + return true + }) +} diff --git a/gnovm/pkg/gnolang/helpers.go b/gnovm/pkg/gnolang/helpers.go index 0384c7a9976..f032def4229 100644 --- a/gnovm/pkg/gnolang/helpers.go +++ b/gnovm/pkg/gnolang/helpers.go @@ -72,7 +72,7 @@ func N(n interface{}) Name { case Name: return n default: - panic("unexpected name arg") + panic("unexpected name type") } } @@ -136,8 +136,8 @@ func Flds(args ...interface{}) FieldTypeExprs { list := FieldTypeExprs{} for i := 0; i < len(args); i += 2 { list = append(list, FieldTypeExpr{ - Name: N(args[i]), - Type: X(args[i+1]), + NameExpr: *Nx(args[i]), + Type: X(args[i+1]), }) } return list @@ -148,8 +148,8 @@ func Recv(n, t interface{}) FieldTypeExpr { n = blankIdentifier } return FieldTypeExpr{ - Name: N(n), - Type: X(t), + NameExpr: *Nx(n), + Type: X(t), } } @@ -843,6 +843,24 @@ func SIf(cond bool, then_, else_ Stmt) Stmt { } } +// ---------------------------------------- +// AST Query + +// Unwraps IndexExpr and SelectorExpr only. +// (defensive, in case malformed exprs that mix). +func LeftmostX(x Expr) Expr { + for { + switch x := x.(type) { + case *IndexExpr: + return x.X + case *SelectorExpr: + return x.X + default: + return x + } + } +} + // ---------------------------------------- // chop functions diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index 9c2aa5e8c7e..a4e779f8086 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -419,8 +419,21 @@ func (m *Machine) RunFiles(fns ...*FileNode) { if pv == nil { panic("RunFiles requires Machine.Package") } + rlm := pv.GetRealm() + if rlm == nil && pv.IsRealm() { + rlm = NewRealm(pv.PkgPath) // throwaway + } updates := m.runFileDecls(IsStdlib(pv.PkgPath), fns...) + if rlm != nil { + pb := pv.GetBlock(m.Store) + for _, update := range updates { + rlm.DidUpdate(pb, nil, update.GetFirstObject(m.Store)) + } + } m.runInitFromUpdates(pv, updates) + if rlm != nil { + rlm.FinalizeRealmTransaction(m.Store) + } } // PreprocessFiles runs Preprocess on the given files. It is used to detect @@ -613,6 +626,8 @@ func (m *Machine) runFileDecls(withOverrides bool, fns ...*FileNode) []TypedValu // multiple files belonging to the same package in // lexical file name order to a compiler." func (m *Machine) runInitFromUpdates(pv *PackageValue, updates []TypedValue) { + // Only for the init functions make the origin caller + // the package addr. for _, tv := range updates { if tv.IsDefined() && tv.T.Kind() == FuncKind && tv.V != nil { fv, ok := tv.V.(*FuncValue) @@ -622,7 +637,7 @@ func (m *Machine) runInitFromUpdates(pv *PackageValue, updates []TypedValue) { if strings.HasPrefix(string(fv.Name), "init.") { fb := pv.GetFileBlock(m.Store, fv.FileName) m.PushBlock(fb) - m.RunFunc(fv.Name) + m.RunFunc(fv.Name, false) m.PopBlock() } } @@ -680,21 +695,25 @@ func (m *Machine) resavePackageValues(rlm *Realm) { // even after running the init function. } -func (m *Machine) RunFunc(fn Name) { +func (m *Machine) RunFunc(fn Name, withSwitch bool) { defer func() { if r := recover(); r != nil { switch r := r.(type) { case UnhandledPanicError: - fmt.Printf("Machine.RunFunc(%q) panic: %s\nStacktrace:\n%s\n", - fn, r.Error(), m.ExceptionsStacktrace()) + fmt.Printf("Machine.RunFunc(%q,%v) panic: %s\nStacktrace:\n%s\n", + fn, withSwitch, r.Error(), m.ExceptionsStacktrace()) default: - fmt.Printf("Machine.RunFunc(%q) panic: %v\nMachine State:%s\nStacktrace:\n%s\n", - fn, r, m.String(), m.Stacktrace().String()) + fmt.Printf("Machine.RunFunc(%q,%v) panic: %v\nMachine State:%s\nStacktrace:\n%s\n", + fn, withSwitch, r, m.String(), m.Stacktrace().String()) } panic(r) } }() - m.RunStatement(S(Call(Nx(fn)))) + if withSwitch { + m.RunStatement(S(Call(Call(Nx("cross"), Nx(fn))))) + } else { + m.RunStatement(S(Call(Nx(fn)))) + } } func (m *Machine) RunMain() { @@ -713,7 +732,11 @@ func (m *Machine) RunMain() { panic(r) } }() - m.RunStatement(S(Call(X("main")))) + if m.Package.IsRealm() { + m.RunStatement(S(Call(Nx("cross"), Nx("main")))) + } else { + m.RunStatement(S(Call(X("main")))) + } } // Evaluate throwaway expression in new block scope. @@ -899,9 +922,6 @@ const ( OpPrecall Op = 0x04 // sets X (func) to frame OpCall Op = 0x05 // call(Frame.Func, [...]) OpCallNativeBody Op = 0x06 // call body is native - OpReturn Op = 0x07 // return ... - OpReturnFromBlock Op = 0x08 // return results (after defers) - OpReturnToBlock Op = 0x09 // copy results to block (before defer) OpDefer Op = 0x0A // defer call(X, [...]) OpCallDeferNativeBody Op = 0x0B // call body is native OpGo Op = 0x0C // go call(X, [...]) @@ -916,6 +936,10 @@ const ( OpPopFrameAndReset Op = 0x15 // pop frame and reset. OpPanic1 Op = 0x16 // pop exception and pop call frames. OpPanic2 Op = 0x17 // pop call frames. + OpReturn Op = 0x1A // return ... + OpReturnAfterCopy Op = 0x1B // return ... (with named results) + OpReturnFromBlock Op = 0x1C // return results (after defers) + OpReturnToBlock Op = 0x1D // copy results to block (before defer) XXX rename to OpCopyResultsToBlock /* Unary & binary operators */ OpUpos Op = 0x20 // + (unary) @@ -1004,7 +1028,7 @@ const ( OpRangeIterString Op = 0xD4 OpRangeIterMap Op = 0xD5 OpRangeIterArrayPtr Op = 0xD6 - OpReturnCallDefers Op = 0xD7 // TODO rename? + OpReturnCallDefers Op = 0xD7 // XXX rename to OpCallDefers OpVoid Op = 0xFF // For profiling simple operation ) @@ -1031,9 +1055,6 @@ const ( OpCPUPrecall = 207 OpCPUCall = 256 OpCPUCallNativeBody = 424 - OpCPUReturn = 38 - OpCPUReturnFromBlock = 36 - OpCPUReturnToBlock = 23 OpCPUDefer = 64 OpCPUCallDeferNativeBody = 33 OpCPUGo = 1 // Not yet implemented @@ -1048,6 +1069,10 @@ const ( OpCPUPopFrameAndReset = 15 OpCPUPanic1 = 121 OpCPUPanic2 = 21 + OpCPUReturn = 38 + OpCPUReturnAfterCopy = 38 // XXX + OpCPUReturnFromBlock = 36 + OpCPUReturnToBlock = 23 /* Unary & binary operators */ OpCPUUpos = 7 @@ -1206,6 +1231,9 @@ func (m *Machine) Run() { case OpReturn: m.incrCPU(OpCPUReturn) m.doOpReturn() + case OpReturnAfterCopy: + m.incrCPU(OpCPUReturnAfterCopy) + m.doOpReturnAfterCopy() case OpReturnFromBlock: m.incrCPU(OpCPUReturnFromBlock) m.doOpReturnFromBlock() @@ -1626,11 +1654,24 @@ func (m *Machine) PeekValue(offset int) *TypedValue { return &m.Values[m.NumValues-offset] } +// Returns a slice of the values stack. +// Use or copy the result, as well as the slice. +func (m *Machine) PeekValues(n int) []TypedValue { + return m.Values[m.NumValues-n : m.NumValues] +} + // XXX delete? func (m *Machine) PeekType(offset int) Type { return m.Values[m.NumValues-offset].T } +func (m *Machine) PushValueFromBlock(tv TypedValue) { + if hiv, ok := tv.V.(*HeapItemValue); ok { + tv = hiv.Value + } + m.PushValue(tv) +} + func (m *Machine) PushValue(tv TypedValue) { if debug { m.Printf("+v %v\n", tv) @@ -1747,6 +1788,7 @@ func (m *Machine) PushFrameBasic(s Stmt) { // ensure the counts are consistent, otherwise we mask // bugs with frame pops. func (m *Machine) PushFrameCall(cx *CallExpr, fv *FuncValue, recv TypedValue) { + withSwitch := cx.IsWithCross() fr := &Frame{ Source: cx, NumOps: m.NumOps, @@ -1761,6 +1803,8 @@ func (m *Machine) PushFrameCall(cx *CallExpr, fv *FuncValue, recv TypedValue) { Defers: nil, LastPackage: m.Package, LastRealm: m.Realm, + WithCross: withSwitch, + DidCross: false, } if debug { if m.Package == nil { @@ -1771,29 +1815,81 @@ func (m *Machine) PushFrameCall(cx *CallExpr, fv *FuncValue, recv TypedValue) { m.Printf("+F %#v\n", fr) } m.Frames = append(m.Frames, fr) + + // Set the package. + // .Package always refers to the code being run, + // and may differ from .Realm. pv := fv.GetPackage(m.Store) if pv == nil { panic(fmt.Sprintf("package value missing in store: %s", fv.PkgPath)) } - rlm := pv.GetRealm() - if rlm == nil && recv.IsDefined() { + m.Package = pv + + // If no realm, return early. + if m.Realm == nil { + return + } + + // If cross, always switch to pv.Realm. + // If method, this means the object cannot be modified if + // stored externally by this method; but other methods can. + if withSwitch { + if !fv.IsSwitchRealm() { + panic(fmt.Sprintf( + "missing crossing() after cross call in %v from %s to %s", + fr.Func.String(), + m.Realm.Path, + pv.Realm.Path, + )) + } + m.Realm = pv.GetRealm() + return + } + + // Not called like cross(fn)(...). + if fv.IsSwitchRealm() { + if m.Realm != pv.Realm { + // panic; not explicit + panic(fmt.Sprintf( + "missing cross before external crossing() in %v from %s to %s", + fr.Func.String(), + m.Realm.Path, + pv.Realm.Path, + )) + } else { + // ok + // Technically OK even if recv.Realm is different. + return + } + } + + // Not cross nor crossing. + // Only "soft" switch to storage realm of receiver. + var rlm *Realm + if recv.IsDefined() { // method call obj := recv.GetFirstObject(m.Store) - if obj == nil { - // could be a nil receiver. - // just ignore. + if obj == nil { // nil receiver + // no switch + return } else { recvOID := obj.GetObjectInfo().ID - if !recvOID.IsZero() { - // override the pv and rlm with receiver's. + if recvOID.IsZero() || recvOID.PkgID == m.Realm.ID { + // no switch + return + } else { + // implicit switch to storage realm. + // neither cross nor didswitch. recvPkgOID := ObjectIDFromPkgID(recvOID.PkgID) - pv = m.Store.GetObject(recvPkgOID).(*PackageValue) - rlm = pv.GetRealm() // done + objpv := m.Store.GetObject(recvPkgOID).(*PackageValue) + rlm = objpv.GetRealm() + m.Realm = rlm + fr.DidCross = true + return } } - } - m.Package = pv - if rlm != nil && m.Realm != rlm { - m.Realm = rlm // enter new realm + } else { // top level function + // no switch + return } } @@ -1877,25 +1973,26 @@ func (m *Machine) NumFrames() int { return len(m.Frames) } +// Returns the current frame. func (m *Machine) LastFrame() *Frame { return m.Frames[len(m.Frames)-1] } -// MustLastCallFrame returns the last call frame with an offset of n. It panics if the frame is not found. -func (m *Machine) MustLastCallFrame(n int) *Frame { - return m.lastCallFrame(n, true) +// MustPeekCallFrame returns the last call frame with an offset of n. It panics if the frame is not found. +func (m *Machine) MustPeekCallFrame(n int) *Frame { + return m.peekCallFrame(n, true) } -// LastCallFrame behaves the same as MustLastCallFrame, but rather than panicking, +// PeekCallFrame behaves the same as MustPeekCallFrame, but rather than panicking, // returns nil if the frame is not found. -func (m *Machine) LastCallFrame(n int) *Frame { - return m.lastCallFrame(n, false) +func (m *Machine) PeekCallFrame(n int) *Frame { + return m.peekCallFrame(n, false) } // TODO: this function and PopUntilLastCallFrame() is used in conjunction // spanning two disjoint operations upon return. Optimize. // If n is 1, returns the immediately last call frame. -func (m *Machine) lastCallFrame(n int, mustBeFound bool) *Frame { +func (m *Machine) peekCallFrame(n int, mustBeFound bool) *Frame { if n == 0 { panic("n must be positive") } @@ -1969,16 +2066,55 @@ func (m *Machine) PushForPointer(lx Expr) { } } +// Pop a pointer (for writing only). func (m *Machine) PopAsPointer(lx Expr) PointerValue { + pv, ro := m.PopAsPointer2(lx) + if ro { + panic("cannot modify external-realm or non-realm object") + } + return pv +} + +// Returns true if tv is N_Readonly or, its "first object" resides in a +// different non-zero realm. Returns false for non-N_Readonly StringValue, free +// floating pointers, and unreal objects. +func (m *Machine) IsReadonly(tv *TypedValue) bool { + if m.Realm == nil { + return false + } + if tv.IsReadonly() { + return true + } + tvoid, ok := tv.GetFirstObjectID() + if !ok { + // e.g. if tv is a string, or free floating pointers. + return false + } + if tvoid.IsZero() { + return false + } + if tvoid.PkgID != m.Realm.ID { + return true + } + return false +} + +// Returns ro = true if the base is readonly, +// or if the base's storage realm != m.Realm and both are non-nil, +// and the lx isn't a name (base is a block), +// and the lx isn't a composit lit expr. +func (m *Machine) PopAsPointer2(lx Expr) (pv PointerValue, ro bool) { switch lx := lx.(type) { case *NameExpr: switch lx.Type { case NameExprTypeNormal: lb := m.LastBlock() - return lb.GetPointerTo(m.Store, lx.Path) + pv = lb.GetPointerTo(m.Store, lx.Path) + ro = false // always mutable case NameExprTypeHeapUse: lb := m.LastBlock() - return lb.GetPointerToHeapUse(m.Store, lx.Path) + pv = lb.GetPointerTo(m.Store, lx.Path) + ro = false // always mutable case NameExprTypeHeapClosure: panic("should not happen") default: @@ -1987,24 +2123,29 @@ func (m *Machine) PopAsPointer(lx Expr) PointerValue { case *IndexExpr: iv := m.PopValue() xv := m.PopValue() - return xv.GetPointerAtIndex(m.Alloc, m.Store, iv) + pv = xv.GetPointerAtIndex(m.Alloc, m.Store, iv) + ro = m.IsReadonly(xv) case *SelectorExpr: xv := m.PopValue() - return xv.GetPointerToFromTV(m.Alloc, m.Store, lx.Path) + pv = xv.GetPointerToFromTV(m.Alloc, m.Store, lx.Path) + ro = m.IsReadonly(xv) case *StarExpr: - ptr := m.PopValue().V.(PointerValue) - return ptr + xv := m.PopValue() + pv = xv.V.(PointerValue) + ro = m.IsReadonly(xv) case *CompositeLitExpr: // for *RefExpr tv := *m.PopValue() hv := m.Alloc.NewHeapItem(tv) - return PointerValue{ + pv = PointerValue{ TV: &hv.Value, Base: hv, Index: 0, } + ro = false // always mutable default: panic("should not happen") } + return } // for testing. @@ -2044,7 +2185,7 @@ func (m *Machine) Panic(ex TypedValue) { m.Exceptions, Exception{ Value: ex, - Frame: m.MustLastCallFrame(1), + Frame: m.MustPeekCallFrame(1), Stacktrace: m.Stacktrace(), }, ) @@ -2076,7 +2217,7 @@ func (m *Machine) Recover() *Exception { // If the frame is not the current frame, the exception is not in scope; return nil. // This retrieves the second most recent call frame because the first most recent // is the call to recover itself. - if frame := m.LastCallFrame(2); frame == nil || frame != exception.Frame { + if frame := m.PeekCallFrame(2); frame == nil || frame != exception.Frame { return nil } } @@ -2175,14 +2316,6 @@ func (m *Machine) String() string { } else { bsi := b.StringIndented(" ") fmt.Fprintf(builder, " %s(%d) %s\n", gens, gen, bsi) - - if b.Source != nil { - sb := b.GetSource(m.Store).GetStaticBlock().GetBlock() - fmt.Fprintf(builder, " (s vals) %s(%d) %s\n", gens, gen, sb.StringIndented(" ")) - - sts := b.GetSource(m.Store).GetStaticBlock().Types - fmt.Fprintf(builder, " (s typs) %s(%d) %s\n", gens, gen, sts) - } } // Update b @@ -2213,11 +2346,6 @@ func (m *Machine) String() string { } else { fmt.Fprintf(builder, " #%d %s\n", i, b.StringIndented(" ")) - if b.Source != nil { - sb := b.GetSource(m.Store).GetStaticBlock().GetBlock() - fmt.Fprintf(builder, " (static) #%d %s\n", i, - sb.StringIndented(" ")) - } } } diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 55e95c9450a..d2059ec99bb 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -153,11 +153,13 @@ const ( ATTR_TYPE_VALUE GnoAttribute = "ATTR_TYPE_VALUE" ATTR_TYPEOF_VALUE GnoAttribute = "ATTR_TYPEOF_VALUE" ATTR_IOTA GnoAttribute = "ATTR_IOTA" - ATTR_LOOP_DEFINES GnoAttribute = "ATTR_LOOP_DEFINES" // []Name defined within loops. - ATTR_LOOP_USES GnoAttribute = "ATTR_LOOP_USES" // []Name loop defines actually used. + ATTR_HEAP_DEFINES GnoAttribute = "ATTR_HEAP_DEFINES" // []Name heap items. + ATTR_HEAP_USES GnoAttribute = "ATTR_HEAP_USES" // []Name heap items used. ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS" ATTR_LAST_BLOCK_STMT GnoAttribute = "ATTR_LAST_BLOCK_STMT" ATTR_GLOBAL GnoAttribute = "ATTR_GLOBAL" + ATTR_PACKAGE_REF GnoAttribute = "ATTR_PACKAGE_REF" + ATTR_PACKAGE_DECL GnoAttribute = "ATTR_PACKAGE_DECL" ) type Attributes struct { @@ -426,8 +428,53 @@ type CallExpr struct { // Func(Args) Func Expr // function expression Args Exprs // function arguments, if any. Varg bool // if true, final arg is variadic. - NumArgs int // len(Args) or len(Args[0].Results) + NumArgs int // len(Args) or len(Args[0].Results). Addressability addressabilityStatus + WithCross bool // if called like cross(fn)(...). +} + +// if x is *ConstExpr returns its source. +func unwrapConstExpr(x Expr) Expr { + if cx, ok := x.(*ConstExpr); ok { + return cx.Source + } + return x +} + +// returns true if x is of form cross(fn)(...). +func (x *CallExpr) isWithCross() bool { + if fnc, ok := x.Func.(*CallExpr); ok { + if nx, ok := unwrapConstExpr(fnc.Func).(*NameExpr); ok { + if nx.Name == "cross" { + return true + } + } + } + return false +} + +// returns true if x is of form crossing(). +func (x *CallExpr) isSwitchRealm() bool { + if x == nil { + return false + } + if nx, ok := unwrapConstExpr(x.Func).(*NameExpr); ok { + if nx.Name == "crossing" { + return true + } + } + return false +} + +func (x *CallExpr) SetWithCross() { + if !x.isWithCross() { + panic("expected cross(fn)(...)") + } + x.WithCross = true +} + +func (x *CallExpr) IsWithCross() bool { + return x.WithCross } func (x *CallExpr) addressability() addressabilityStatus { @@ -655,7 +702,7 @@ var ( type FieldTypeExpr struct { Attributes - Name + NameExpr Type Expr // Currently only BasicLitExpr allowed. @@ -669,19 +716,21 @@ func (x *FieldTypeExpr) addressability() addressabilityStatus { type FieldTypeExprs []FieldTypeExpr +// Keep it slow, validating. +// If you need it faster, memoize it elsewhere. func (ftxz FieldTypeExprs) IsNamed() bool { named := false for i, ftx := range ftxz { if i == 0 { - if ftx.Name == "" || isHiddenResultVariable(string(ftx.Name)) { + if ftx.Name == "" || isMissingResult(ftx.Name) { named = false } else { named = true } } else { - if named && ftx.Name == "" { + if named && (ftx.Name == "" || isMissingResult(ftx.Name)) { panic("[]FieldTypeExpr has inconsistent namedness (starts named)") - } else if !named && (ftx.Name != "" || !isHiddenResultVariable(string(ftx.Name))) { + } else if !named && (ftx.Name != "" && !isMissingResult(ftx.Name)) { panic("[]FieldTypeExpr has inconsistent namedness (starts unnamed)") } } @@ -810,6 +859,25 @@ func (ss Body) GetLabeledStmt(label Name) (stmt Stmt, idx int) { return nil, -1 } +// Convenience, returns true if first statement is crossing() +func (ss Body) IsSwitchRealm() bool { + return ss.isSwitchRealm() +} + +// XXX deprecate +func (ss Body) isSwitchRealm() bool { + if len(ss) == 0 { + return false + } + fs := ss[0] + xs, ok := fs.(*ExprStmt) + if !ok { + return false + } + cx, ok := xs.X.(*CallExpr) + return cx.isSwitchRealm() +} + // ---------------------------------------- // non-pointer receiver to help make immutable. @@ -953,7 +1021,8 @@ type RangeStmt struct { type ReturnStmt struct { Attributes - Results Exprs // result expressions; or nil + Results Exprs // result expressions; or nil + CopyResults bool // copy results to block first } type PanicStmt struct { @@ -1051,12 +1120,13 @@ func (x *bodyStmt) String() string { active = fmt.Sprintf(" unexpected active: %v", x.Active) } } - return fmt.Sprintf("bodyStmt[%d/%d/%d]=%s%s", + return fmt.Sprintf("bodyStmt[%d/%d/%d]=%s%s Active:%v", x.ListLen, x.ListIndex, x.NextBodyIndex, next, - active) + active, + x.Active) } // ---------------------------------------- @@ -1111,6 +1181,8 @@ type FuncDecl struct { Recv FieldTypeExpr // receiver (if method); or empty (if function) Type FuncTypeExpr // function signature: parameters and results Body // function body; or empty for external (non-Go) function + + unboundType *FuncTypeExpr // memoized } func (x *FuncDecl) GetDeclNames() []Name { @@ -1121,6 +1193,22 @@ func (x *FuncDecl) GetDeclNames() []Name { } } +// If FuncDecl is for method, construct a FuncTypeExpr with receiver as first +// parameter. +func (x *FuncDecl) GetUnboundTypeExpr() *FuncTypeExpr { + if x.IsMethod { + if x.unboundType == nil { + x.unboundType = &FuncTypeExpr{ + Attributes: x.Type.Attributes, + Params: append([]FieldTypeExpr{x.Recv}, x.Type.Params...), + Results: x.Type.Results, + } + } + return x.unboundType + } + return &x.Type +} + type ImportDecl struct { Attributes NameExpr // local package name. required. @@ -1521,20 +1609,31 @@ func (x *PackageNode) PrepareNewValues(pv *PackageValue) []TypedValue { pnl := len(x.Values) // copy new top-level defined values/types. if pvl < pnl { - // XXX: deep copy heap values nvs := make([]TypedValue, pnl-pvl) copy(nvs, x.Values[pvl:pnl]) for i, tv := range nvs { if fv, ok := tv.V.(*FuncValue); ok { // copy function value and assign closure from package value. fv = fv.Copy(nilAllocator) - fv.Closure = pv.fBlocksMap[fv.FileName] - if fv.Closure == nil { + fv.Parent = pv.fBlocksMap[fv.FileName] + if fv.Parent == nil { panic(fmt.Sprintf("file block missing for file %q", fv.FileName)) } nvs[i].V = fv } } + heapItems := x.GetHeapItems() + for i, tv := range nvs { + if _, ok := tv.T.(heapItemType); ok { + panic("unexpected heap item") + } + if heapItems[pvl+i] { + nvs[i] = TypedValue{ + T: heapItemType{}, + V: &HeapItemValue{Value: nvs[i]}, + } + } + } block.Values = append(block.Values, nvs...) return block.Values[pvl:] } else if pvl > pnl { @@ -1609,6 +1708,8 @@ type BlockNode interface { GetBlockNames() []Name GetExternNames() []Name GetNumNames() uint16 + SetIsHeapItem(n Name) + GetHeapItems() []bool GetParentNode(Store) BlockNode GetPathForName(Store, Name) ValuePath GetBlockNodeForPath(Store, ValuePath) BlockNode @@ -1634,9 +1735,11 @@ type StaticBlock struct { Types []Type NumNames uint16 Names []Name + HeapItems []bool UnassignableNames []Name Consts []Name // TODO consider merging with Names. Externs []Name + Parent BlockNode Loc Location // temporary storage for rolling back redefinitions. @@ -1668,16 +1771,36 @@ func (sb *StaticBlock) InitStaticBlock(source BlockNode, parent BlockNode) { Parent: nil, } } else { - sb.Block = Block{ - Source: source, - Values: nil, - Parent: parent.GetStaticBlock().GetBlock(), + switch source.(type) { + case *IfCaseStmt, *SwitchClauseStmt: + if parent == nil { + sb.Block = Block{ + Source: source, + Values: nil, + Parent: nil, + } + } else { + parent2 := parent.GetParentNode(nil) + sb.Block = Block{ + Source: source, + Values: nil, + Parent: parent2.GetStaticBlock().GetBlock(), + } + } + default: + sb.Block = Block{ + Source: source, + Values: nil, + Parent: parent.GetStaticBlock().GetBlock(), + } } } sb.NumNames = 0 sb.Names = make([]Name, 0, 16) + sb.HeapItems = make([]bool, 0, 16) sb.Consts = make([]Name, 0, 16) sb.Externs = make([]Name, 0, 16) + sb.Parent = parent return } @@ -1709,14 +1832,14 @@ func (sb *StaticBlock) GetBlock() *Block { // Implements BlockNode. func (sb *StaticBlock) GetBlockNames() (ns []Name) { - return sb.Names // copy? + return sb.Names } // Implements BlockNode. // NOTE: Extern names may also be local, if declared after usage as an extern // (thus shadowing the extern name). func (sb *StaticBlock) GetExternNames() (ns []Name) { - return sb.Externs // copy? + return sb.Externs } func (sb *StaticBlock) addExternName(n Name) { @@ -1734,13 +1857,22 @@ func (sb *StaticBlock) GetNumNames() (nn uint16) { } // Implements BlockNode. -func (sb *StaticBlock) GetParentNode(store Store) BlockNode { - pblock := sb.Block.GetParent(store) - if pblock == nil { - return nil - } else { - return pblock.GetSource(store) +func (sb *StaticBlock) GetHeapItems() []bool { + return sb.HeapItems +} + +// Implements BlockNode. +func (sb *StaticBlock) SetIsHeapItem(n Name) { + idx, ok := sb.GetLocalIndex(n) + if !ok { + panic("name not found in block") } + sb.HeapItems[idx] = true +} + +// Implements BlockNode. +func (sb *StaticBlock) GetParentNode(store Store) BlockNode { + return sb.Parent } // Implements BlockNode. @@ -1754,26 +1886,34 @@ func (sb *StaticBlock) GetPathForName(store Store, n Name) ValuePath { if idx, ok := sb.GetLocalIndex(n); ok { return NewValuePathBlock(uint8(gen), idx, n) } + sn := sb.GetSource(store) // Register as extern. // NOTE: uverse names are externs too. // NOTE: externs may also be shadowed later in the block. Thus, usages // before the declaration will have depth > 1; following it, depth == 1, // matching the two different identifiers they refer to. - if !isFile(sb.GetSource(store)) { + if !isFile(sn) { sb.GetStaticBlock().addExternName(n) } // Check ancestors. gen++ - bp := sb.GetParentNode(store) - for bp != nil { - if idx, ok := bp.GetLocalIndex(n); ok { - return NewValuePathBlock(uint8(gen), idx, n) + faux := 0 + sn = sn.GetParentNode(store) + if fauxBlockNode(sn) { + faux++ + } + for sn != nil { + if idx, ok := sn.GetLocalIndex(n); ok { + return NewValuePathBlock(uint8(gen-faux), idx, n) } else { - if !isFile(bp) { - bp.GetStaticBlock().addExternName(n) + if !isFile(sn) { + sn.GetStaticBlock().addExternName(n) } - bp = bp.GetParentNode(store) gen++ + sn = sn.GetParentNode(store) + if fauxBlockNode(sn) { + faux++ + } if 0xff < gen { panic("value path depth overflow") } @@ -1797,6 +1937,18 @@ func (sb *StaticBlock) GetBlockNodeForPath(store Store, path ValuePath) BlockNod bn := sb.GetSource(store) for i := 1; i < int(path.Depth); i++ { bn = bn.GetParentNode(store) + if fauxBlockNode(bn) { + bn = bn.GetParentNode(store) + } + } + + // If bn is a faux block node, check also its parent. + switch bn := bn.(type) { + case *IfCaseStmt, *SwitchClauseStmt: + pn := bn.GetParentNode(store) + if path.Index < pn.GetNumNames() { + return pn + } } return bn @@ -1956,7 +2108,10 @@ func (sb *StaticBlock) Define(n Name, tv TypedValue) { // Set type to nil, only reserving the name. func (sb *StaticBlock) Predefine(isConst bool, n Name) { - sb.Define2(isConst, n, nil, anyValue(nil)) + _, exists := sb.GetLocalIndex(n) + if !exists { + sb.Define2(isConst, n, nil, anyValue(nil)) + } } // The declared type st may not be the same as the static tv; @@ -2024,6 +2179,7 @@ func (sb *StaticBlock) Define2(isConst bool, n Name, st Type, tv TypedValue) { } else { // The general case without re-definition. sb.Names = append(sb.Names, n) + sb.HeapItems = append(sb.HeapItems, false) if isConst { sb.Consts = append(sb.Consts, n) } @@ -2299,13 +2455,21 @@ func validatePkgName(name string) error { return nil } -const hiddenResultVariable = ".res_" +// The distinction is used for validation to work +// both before and after preprocessing. +const missingResultNamePrefix = ".res." // if there was no name +const underscoreResultNamePrefix = ".res_" // if was underscore -func isHiddenResultVariable(name string) bool { - if strings.HasPrefix(name, hiddenResultVariable) { - return true - } - return false +func isUnnamedResult(name Name) bool { + return isMissingResult(name) || isUnderscoreResult(name) +} + +func isMissingResult(name Name) bool { + return strings.HasPrefix(string(name), missingResultNamePrefix) +} + +func isUnderscoreResult(name Name) bool { + return strings.HasPrefix(string(name), underscoreResultNamePrefix) } type addressabilityStatus int diff --git a/gnovm/pkg/gnolang/nodes_copy.go b/gnovm/pkg/gnolang/nodes_copy.go index b5b42764802..c0ae59b1aa5 100644 --- a/gnovm/pkg/gnolang/nodes_copy.go +++ b/gnovm/pkg/gnolang/nodes_copy.go @@ -118,9 +118,9 @@ func (x *FuncLitExpr) Copy() Node { func (x *FieldTypeExpr) Copy() Node { return &FieldTypeExpr{ - Name: x.Name, - Type: x.Type.Copy().(Expr), - Tag: copyExpr(x.Tag), + NameExpr: *(x.NameExpr.Copy().(*NameExpr)), + Type: x.Type.Copy().(Expr), + Tag: copyExpr(x.Tag), } } diff --git a/gnovm/pkg/gnolang/nodes_string.go b/gnovm/pkg/gnolang/nodes_string.go index e90ea006079..9d2a48d62b4 100644 --- a/gnovm/pkg/gnolang/nodes_string.go +++ b/gnovm/pkg/gnolang/nodes_string.go @@ -134,8 +134,6 @@ func (x IndexExpr) String() string { } func (x SelectorExpr) String() string { - // NOTE: for debugging selector issues: - // return fmt.Sprintf("%s.(%v).%s", n.X, n.Path.Type, n.Sel) return fmt.Sprintf("%s.%s", x.X, x.Sel) } @@ -198,10 +196,14 @@ func (x KeyValueExpr) String() string { } func (x FieldTypeExpr) String() string { + hd := "" + if x.NameExpr.Type == NameExprTypeHeapDefine { + hd = "~" + } if x.Tag == nil { - return fmt.Sprintf("%s %s", x.Name, x.Type) + return fmt.Sprintf("%s%s %s", x.Name, hd, x.Type) } - return fmt.Sprintf("%s %s %s", x.Name, x.Type, x.Tag) + return fmt.Sprintf("%s%s %s %s", x.Name, hd, x.Type, x.Tag) } func (x ArrayTypeExpr) String() string { @@ -316,14 +318,14 @@ func (x IfStmt) String() string { then := x.Then.String() els_ := x.Else.String() if x.Else.Body == nil { - return fmt.Sprintf("if %s%s { %s }", init, cond, then) + return fmt.Sprintf("if %s%s %s", init, cond, then) } - return fmt.Sprintf("if %s%s { %s } else { %s }", + return fmt.Sprintf("if %s%s %s else %s", init, cond, then, els_) } func (x IfCaseStmt) String() string { - return x.Body.String() + return "{ " + x.Body.String() + " }" } func (x IncDecStmt) String() string { diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index a6d959612bc..efebea582e1 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -343,7 +343,7 @@ func (m *Machine) doOpBandn() { // TODO: can be much faster. func isEql(store Store, lv, rv *TypedValue) bool { // If one is undefined, the other must be as well. - // Fields/items are set to defaultValue along the way. + // Fields/items are set to defaultTypedValue along the way. lvu := lv.IsUndefined() rvu := rv.IsUndefined() if lvu { @@ -454,24 +454,7 @@ func isEql(store Store, lv, rv *TypedValue) bool { panic("function can only be compared with `nil`") } } - if _, ok := lv.V.(*BoundMethodValue); ok { - // BoundMethodValues are objects so just compare. - return lv.V == rv.V - } else if lv.V == nil && rv.V == nil { - return true - } else { - lfv := lv.V.(*FuncValue) - rfv, ok := rv.V.(*FuncValue) - if !ok { - return false - } - if lfv.Source.GetLocation() != - rfv.Source.GetLocation() { - return false - } - return lfv.GetClosure(store) == - rfv.GetClosure(store) - } + return lv.V == rv.V case PointerKind: if lv.T != rv.T && lv.T.Elem() != DataByteType && @@ -483,7 +466,7 @@ func isEql(store Store, lv, rv *TypedValue) bool { lpv := lv.V.(PointerValue) rpv := rv.V.(PointerValue) if lpv.TV.T == DataByteType && rpv.TV.T == DataByteType { - return *(lpv.TV) == *(rpv.TV) && lpv.Base == rpv.Base && lpv.Index == rpv.Index && lpv.Key == rpv.Key + return *(lpv.TV) == *(rpv.TV) && lpv.Base == rpv.Base && lpv.Index == rpv.Index } } return lv.V == rv.V diff --git a/gnovm/pkg/gnolang/op_call.go b/gnovm/pkg/gnolang/op_call.go index 58155309cc6..42814cd400d 100644 --- a/gnovm/pkg/gnolang/op_call.go +++ b/gnovm/pkg/gnolang/op_call.go @@ -17,12 +17,15 @@ func (m *Machine) doOpPrecall() { panic("should not happen") } } + + // handle cross(). switch fv := v.(type) { case *FuncValue: m.PushFrameCall(cx, fv, TypedValue{}) m.PushOp(OpCall) case *BoundMethodValue: - m.PushFrameCall(cx, fv.Func, fv.Receiver) + recv := fv.Receiver + m.PushFrameCall(cx, fv.Func, recv) m.PushOp(OpCall) case TypeValue: // Do not pop type yet. @@ -31,7 +34,6 @@ func (m *Machine) doOpPrecall() { if cx.GetAttribute(ATTR_SHIFT_RHS) == true { xv.AssertNonNegative("runtime error: negative shift amount") } - m.PushOp(OpConvert) if debug { if len(cx.Args) != 1 { @@ -47,18 +49,27 @@ func (m *Machine) doOpPrecall() { var gReturnStmt = &ReturnStmt{} +func getFuncTypeExprFromSource(source Node) *FuncTypeExpr { + if fd, ok := source.(*FuncDecl); ok { + return fd.GetUnboundTypeExpr() + } else { + return &source.(*FuncLitExpr).Type + } +} + func (m *Machine) doOpCall() { // NOTE: Frame won't be popped until the statement is complete, to // discard the correct number of results for func calls in ExprStmts. fr := m.LastFrame() fv := fr.Func + fs := fv.GetSource(m.Store) ft := fr.Func.GetType(m.Store) pts := ft.Params numParams := len(pts) isMethod := 0 // 1 if true // Create new block scope. - clo := fr.Func.GetClosure(m.Store) - b := m.Alloc.NewBlock(fr.Func.GetSource(m.Store), clo) + pb := fr.Func.GetParent(m.Store) + b := m.Alloc.NewBlock(fs, pb) // Copy *FuncValue.Captures into block // NOTE: addHeapCapture in preprocess ensures order. @@ -90,12 +101,11 @@ func (m *Machine) doOpCall() { m.PushOp(OpExec) } else { // Initialize return variables with default value. - numParams := len(ft.Params) for i, rt := range ft.Results { - // results/parameters never are heap use/closure. - ptr := b.GetPointerToInt(nil, numParams+i) dtv := defaultTypedValue(m.Alloc, rt.Type) - ptr.Assign2(m.Alloc, nil, nil, dtv, false) + ptr := b.GetPointerToInt(nil, numParams+i) + // Write to existing heap item if result is heap defined. + ptr.TV.AssignToBlock(dtv) } } // Exec body. @@ -117,17 +127,6 @@ func (m *Machine) doOpCall() { } // Assign receiver as first parameter, if any. if !fr.Receiver.IsUndefined() { - if debug { - pt := pts[0].Type - rt := fr.Receiver.T - if pt.TypeID() != rt.TypeID() { - panic(fmt.Sprintf( - "expected %s but got %s", - pt.String(), - rt.String())) - } - } - b.Values[0] = fr.Receiver isMethod = 1 } // Convert variadic argument to slice argument. @@ -157,30 +156,19 @@ func (m *Machine) doOpCall() { } // Assign non-receiver parameters in forward order. pvs := m.PopValues(numParams - isMethod) - for i := isMethod; i < numParams; i++ { - pv := pvs[i-isMethod] - if debug { - // This is how run-time untyped const - // conversions would work, but we - // expect the preprocessor to convert - // these to *ConstExpr. - /* - // Convert if untyped const. - if isUntyped(pv.T) { - ConvertUntypedTo(&pv, pv.Type) - } - */ - if isUntyped(pv.T) { - panic("unexpected untyped const type for assign during runtime") - } + for i := 0; i < numParams; i++ { + var pv TypedValue + if i >= isMethod { + pv = pvs[i-isMethod] + // Make a copy so that a reference to the argument isn't used + // in cases where the non-primitive value type is represented + // as a pointer, but the declared type is not; e.g. *StructValue + // otherwise the struct won't actually be copied by value. + pv = pv.Copy(m.Alloc) + } else { + pv = fr.Receiver } - // TODO: some more pt <> pv.Type - // reconciliations/conversions necessary. - - // Make a copy so that a reference to the argument isn't used - // in cases where the non-primitive value type is represented - // as a pointer, *StructValue, for example. - b.Values[i] = pv.Copy(m.Alloc) + b.Values[i].AssignToBlock(pv) } } @@ -195,13 +183,43 @@ func (m *Machine) doOpCallDeferNativeBody() { // Assumes that result values are pushed onto the Values stack. func (m *Machine) doOpReturn() { + // Unwind stack. cfr := m.PopUntilLastCallFrame() + + // See if we are exiting a realm boundary. + crlm := m.Realm + if crlm != nil { + if cfr.DidCross { + // Finalize realm updates! + // NOTE: This is a resource intensive undertaking. + crlm.FinalizeRealmTransaction(m.Store) + } + } + + // Finalize + m.PopFrameAndReturn() +} + +// Like doOpReturn but first copies results to block. +func (m *Machine) doOpReturnAfterCopy() { + // If there are named results that are heap defined, + // need to write to those from stack before returning. + cfr := m.MustPeekCallFrame(1) + fv := cfr.Func + ft := fv.GetType(m.Store) + numParams := len(ft.Params) + numResults := len(ft.Results) + fblock := m.Blocks[cfr.NumBlocks] // frame +1 + results := m.PeekValues(numResults) + for i := 0; i < numResults; i++ { + rtv := results[i].Copy(m.Alloc) + fblock.Values[numParams+i].AssignToBlock(rtv) + } + + // Unwind stack. + cfr = m.PopUntilLastCallFrame() + // See if we are exiting a realm boundary. - // NOTE: there are other ways to implement realm boundary transitions, - // e.g. with independent Machine instances per realm for example, or - // even only finalizing all realm transactions at the end of the - // original statement execution, but for now we handle them like this, - // per OpReturn*. crlm := m.Realm if crlm != nil { lrlm := cfr.LastRealm @@ -219,22 +237,25 @@ func (m *Machine) doOpReturn() { crlm.FinalizeRealmTransaction(m.Store) } } - // finalize + + // Finalize m.PopFrameAndReturn() } // Like doOpReturn, but with results from the block; -// i.e. named result vars declared in func signatures. +// i.e. named result vars declared in func signatures, +// because return was called with no return arguments. func (m *Machine) doOpReturnFromBlock() { // Copy results from block. cfr := m.PopUntilLastCallFrame() - ft := cfr.Func.GetType(m.Store) + fv := cfr.Func + ft := fv.GetType(m.Store) numParams := len(ft.Params) numResults := len(ft.Results) fblock := m.Blocks[cfr.NumBlocks] // frame +1 for i := 0; i < numResults; i++ { - rtv := fillValueTV(m.Store, &fblock.Values[i+numParams]) - m.PushValue(*rtv) + rtv := *fillValueTV(m.Store, &fblock.Values[i+numParams]) + m.PushValueFromBlock(rtv) } // See if we are exiting a realm boundary. crlm := m.Realm @@ -262,20 +283,21 @@ func (m *Machine) doOpReturnFromBlock() { // deferred statements can refer to results with name // expressions. func (m *Machine) doOpReturnToBlock() { - cfr := m.MustLastCallFrame(1) - ft := cfr.Func.GetType(m.Store) + cfr := m.MustPeekCallFrame(1) + fv := cfr.Func + ft := fv.GetType(m.Store) numParams := len(ft.Params) numResults := len(ft.Results) fblock := m.Blocks[cfr.NumBlocks] // frame +1 results := m.PopValues(numResults) for i := 0; i < numResults; i++ { rtv := results[i] - fblock.Values[numParams+i] = rtv + fblock.Values[numParams+i].AssignToBlock(rtv) } } func (m *Machine) doOpReturnCallDefers() { - cfr := m.MustLastCallFrame(1) + cfr := m.MustPeekCallFrame(1) dfr, ok := cfr.PopDefer() if !ok { // Done with defers. @@ -297,11 +319,9 @@ func (m *Machine) doOpReturnCallDefers() { if dfr.Func != nil { fv := dfr.Func ft := fv.GetType(m.Store) - pts := ft.Params - numParams := len(ft.Params) // Create new block scope for defer. - clo := dfr.Func.GetClosure(m.Store) - b := m.Alloc.NewBlock(fv.GetSource(m.Store), clo) + pb := dfr.Func.GetParent(m.Store) + b := m.Alloc.NewBlock(fv.GetSource(m.Store), pb) // copy values from captures if len(fv.Captures) != 0 { if len(fv.Captures) > len(b.Values) { @@ -330,31 +350,13 @@ func (m *Machine) doOpReturnCallDefers() { }) m.PushOp(OpCallDeferNativeBody) } - if ft.HasVarg() { - numArgs := len(dfr.Args) - nvar := numArgs - (numParams - 1) - if dfr.Source.Call.Varg { - if debug { - if nvar != 1 { - panic("should not happen") - } - } - // Do nothing, last arg type is already slice type - // called with form fncall(?, vargs...) - } else { - // Convert last nvar to slice. - vart := pts[len(pts)-1].Type.(*SliceType) - vargs := make([]TypedValue, nvar) - copy(vargs, dfr.Args[numArgs-nvar:numArgs]) - varg := m.Alloc.NewSliceFromList(vargs) - dfr.Args = dfr.Args[:numArgs-nvar] - dfr.Args = append(dfr.Args, TypedValue{ - T: vart, - V: varg, - }) - } + // Assign parameters in forward order. + for i, arg := range dfr.Args { + // We need to define, but b was already populated + // with new empty heap items, so AssignToBlock is + // faster. + b.Values[i].AssignToBlock(arg) } - copy(b.Values, dfr.Args) } else { panic("should not happen") } @@ -362,7 +364,7 @@ func (m *Machine) doOpReturnCallDefers() { func (m *Machine) doOpDefer() { lb := m.LastBlock() - cfr := m.MustLastCallFrame(1) + cfr := m.MustPeekCallFrame(1) ds := m.PopStmt().(*DeferStmt) // Pop arguments numArgs := len(ds.Call.Args) @@ -372,6 +374,39 @@ func (m *Machine) doOpDefer() { // Push defer. switch cv := ftv.V.(type) { case *FuncValue: + fv := cv + ft := fv.GetType(m.Store) + pts := ft.Params + numParams := len(pts) + isMethod := 0 + nvar := numArgs - (numParams - 1 - isMethod) + if ft.HasVarg() { + if ds.Call.Varg { + // Do nothing, last arg type is already slice + // type called with form fncall(?, vargs...) + if debug { + if nvar != 1 { + panic("should not happen") + } + } + } else { + // Convert last nvar to slice. + vart := pts[numParams-1].Type.(*SliceType) + list := make([]TypedValue, nvar) + copy(list, args[numParams-1-isMethod:]) + varg := m.Alloc.NewSliceFromList(list) + args = append(args[:numParams-1-isMethod], TypedValue{ + T: vart, + V: varg, + }) + } + } + /* + for i := 0; i < numParams; i++ { + // args will be copy()'d to block later. + args[i].DefineToBlock(args[i]) + } + */ cfr.PushDefer(Defer{ Func: cv, Args: args, @@ -380,21 +415,47 @@ func (m *Machine) doOpDefer() { PanicScope: m.PanicScope, }) case *BoundMethodValue: - if debug { - pt := cv.Func.GetType(m.Store).Params[0] - rt := cv.Receiver.T - if pt.TypeID() != rt.TypeID() { - panic(fmt.Sprintf( - "expected %s but got %s", - pt.String(), - rt.String())) + fv := cv.Func + ft := fv.GetType(m.Store) + pts := ft.Params + numParams := len(pts) + isMethod := 1 + nvar := numArgs - (numParams - 1 - isMethod) + if ft.HasVarg() { + if ds.Call.Varg { + // Do nothing, last arg type is already slice + // type called with form fncall(?, vargs...) + if debug { + if nvar != 1 { + panic("should not happen") + } + } + } else { + // Convert last nvar to slice. + vart := pts[numParams-1].Type.(*SliceType) + list := make([]TypedValue, nvar) + copy(list, args[numParams-1-isMethod:]) + varg := m.Alloc.NewSliceFromList(list) + args = append(args[:numParams-1-isMethod], TypedValue{ + T: vart, + V: varg, + }) } } args2 := make([]TypedValue, len(args)+1) - args2[0] = cv.Receiver - copy(args2[1:], args) + // Make heap item if param is heap defined. + // This also heap escapes the receiver. + for i := 0; i < numParams; i++ { + var pv TypedValue + if i >= isMethod { + pv = args[i-isMethod] + } else { + pv = cv.Receiver + } + args2[i] = pv + } cfr.PushDefer(Defer{ - Func: cv.Func, + Func: fv, Args: args2, Source: ds, Parent: lb, diff --git a/gnovm/pkg/gnolang/op_decl.go b/gnovm/pkg/gnolang/op_decl.go index 6dbae2d3edf..bfed8efb89d 100644 --- a/gnovm/pkg/gnolang/op_decl.go +++ b/gnovm/pkg/gnolang/op_decl.go @@ -23,8 +23,10 @@ func (m *Machine) doOpValueDecl() { // requiring the consideration of the typed-nil case. if nt == nil { tv = TypedValue{} + } else if nt.Kind() == InterfaceKind { + tv = TypedValue{} } else { - tv = TypedValue{T: nt, V: defaultValue(m.Alloc, nt)} + tv = defaultTypedValue(m.Alloc, nt) } } else { tv = rvs[i] diff --git a/gnovm/pkg/gnolang/op_eval.go b/gnovm/pkg/gnolang/op_eval.go index 5a9da93fbbd..bdb6f272dff 100644 --- a/gnovm/pkg/gnolang/op_eval.go +++ b/gnovm/pkg/gnolang/op_eval.go @@ -21,7 +21,6 @@ func (m *Machine) doOpEval() { x := m.PeekExpr(1) if debug { debug.Printf("EVAL: (%T) %v\n", x, x) - // fmt.Println(m.String()) } // This case moved out of switch for performance. // TODO: understand this better. @@ -36,7 +35,7 @@ func (m *Machine) doOpEval() { // Get value from scope. lb := m.LastBlock() // Push value, done. - ptr := lb.GetPointerToMaybeHeapUse(m.Store, nx) + ptr := lb.GetPointerTo(m.Store, nx.Path) m.PushValue(ptr.Deref()) return } @@ -248,7 +247,11 @@ func (m *Machine) doOpEval() { m.PushOp(OpEval) } // evaluate func - m.PushExpr(x.Func) + if x.IsWithCross() { + m.PushExpr(x.Func.(*CallExpr).Args[0]) + } else { + m.PushExpr(x.Func) + } m.PushOp(OpEval) case *IndexExpr: if x.HasOK { diff --git a/gnovm/pkg/gnolang/op_exec.go b/gnovm/pkg/gnolang/op_exec.go index 03060803a46..c59ba7ea026 100644 --- a/gnovm/pkg/gnolang/op_exec.go +++ b/gnovm/pkg/gnolang/op_exec.go @@ -541,7 +541,7 @@ EXEC_SWITCH: m.PushForPointer(cs.X) case *ReturnStmt: m.PopStmt() - fr := m.MustLastCallFrame(1) + fr := m.MustPeekCallFrame(1) ft := fr.Func.GetType(m.Store) hasDefers := 0 < len(fr.Defers) hasResults := 0 < len(ft.Results) @@ -561,6 +561,8 @@ EXEC_SWITCH: } else { if cs.Results == nil { m.PushOp(OpReturnFromBlock) + } else if cs.CopyResults { + m.PushOp(OpReturnAfterCopy) } else { m.PushOp(OpReturn) } @@ -686,10 +688,8 @@ EXEC_SWITCH: // compute next switch clause from BodyIndex (assigned in preprocess) nextClause := cs.BodyIndex + 1 // expand block size - cl := ss.Clauses[nextClause] - if nn := cl.GetNumNames(); int(nn) > len(b.Values) { - b.ExpandToSize(m.Alloc, nn) - } + cl := &ss.Clauses[nextClause] + b.ExpandWith(m.Alloc, cl) // exec clause body b.bodyStmt = bodyStmt{ Body: cl.Body, @@ -783,9 +783,7 @@ func (m *Machine) doOpIfCond() { if cond.GetBool() { if len(is.Then.Body) != 0 { // expand block size - if nn := is.Then.GetNumNames(); int(nn) > len(b.Values) { - b.ExpandToSize(m.Alloc, nn) - } + b.ExpandWith(m.Alloc, &is.Then) // exec then body b.bodyStmt = bodyStmt{ Body: is.Then.Body, @@ -798,9 +796,7 @@ func (m *Machine) doOpIfCond() { } else { if len(is.Else.Body) != 0 { // expand block size - if nn := is.Else.GetNumNames(); int(nn) > len(b.Values) { - b.ExpandToSize(m.Alloc, nn) - } + b.ExpandWith(m.Alloc, &is.Else) // exec then body b.bodyStmt = bodyStmt{ Body: is.Else.Body, @@ -865,20 +861,20 @@ func (m *Machine) doOpTypeSwitch() { if match { // did match if len(cs.Body) != 0 { b := m.LastBlock() + // remember size (from init) + size := len(b.Values) + // expand block size + b.ExpandWith(m.Alloc, cs) // define if varname if ss.VarName != "" { - // NOTE: assumes the var is first in block. + // NOTE: assumes the var is first after size. vp := NewValuePath( - VPBlock, 1, 0, ss.VarName) + VPBlock, 1, uint16(size), ss.VarName) // NOTE: GetPointerToMaybeHeapDefine not needed, // because this type is in new type switch clause block. ptr := b.GetPointerTo(m.Store, vp) ptr.TV.Assign(m.Alloc, *xv, false) } - // expand block size - if nn := cs.GetNumNames(); int(nn) > len(b.Values) { - b.ExpandToSize(m.Alloc, nn) - } // exec clause body b.bodyStmt = bodyStmt{ Body: cs.Body, @@ -907,7 +903,7 @@ func (m *Machine) doOpSwitchClause() { m.PopValue() // pop clause index // done! } else { - cl := ss.Clauses[idx] + cl := &ss.Clauses[idx] if len(cl.Cases) == 0 { // default clause m.PopStmt() // pop switch stmt @@ -916,9 +912,7 @@ func (m *Machine) doOpSwitchClause() { m.PopValue() // clause index no longer needed // expand block size b := m.LastBlock() - if nn := cl.GetNumNames(); int(nn) > len(b.Values) { - b.ExpandToSize(m.Alloc, nn) - } + b.ExpandWith(m.Alloc, cl) // exec clause body b.bodyStmt = bodyStmt{ Body: cl.Body, @@ -956,11 +950,9 @@ func (m *Machine) doOpSwitchClauseCase() { m.PopValue() // pop clause index // expand block size clidx := cliv.GetInt() - cl := ss.Clauses[clidx] + cl := &ss.Clauses[clidx] b := m.LastBlock() - if nn := cl.GetNumNames(); int(nn) > len(b.Values) { - b.ExpandToSize(m.Alloc, nn) - } + b.ExpandWith(m.Alloc, cl) // exec clause body b.bodyStmt = bodyStmt{ Body: cl.Body, diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index 79e9e077af2..29988a19109 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -8,13 +8,10 @@ import ( // NOTE: keep in sync with doOpIndex2. func (m *Machine) doOpIndex1() { - if debug { - _ = m.PopExpr().(*IndexExpr) - } else { - m.PopExpr() - } + m.PopExpr() iv := m.PopValue() // index xv := m.PeekValue(1) // x + ro := m.IsReadonly(xv) switch ct := baseOf(xv.T).(type) { case *MapType: mv := xv.V.(*MapValue) @@ -23,35 +20,27 @@ func (m *Machine) doOpIndex1() { *xv = vv // reuse as result } else { vt := ct.Value - *xv = TypedValue{ // reuse as result - T: vt, - V: defaultValue(m.Alloc, vt), - } + *xv = defaultTypedValue(m.Alloc, vt) // reuse as result } default: res := xv.GetPointerAtIndex(m.Alloc, m.Store, iv) *xv = res.Deref() // reuse as result } + xv.SetReadonly(ro) } // NOTE: keep in sync with doOpIndex1. func (m *Machine) doOpIndex2() { - if debug { - _ = m.PopExpr().(*IndexExpr) - } else { - m.PopExpr() - } + m.PopExpr() iv := m.PeekValue(1) // index xv := m.PeekValue(2) // x + ro := m.IsReadonly(xv) switch ct := baseOf(xv.T).(type) { case *MapType: vt := ct.Value if xv.V == nil { // uninitialized map - *xv = TypedValue{ // reuse as result - T: vt, - V: defaultValue(m.Alloc, vt), - } - *iv = untypedBool(false) // reuse as result + *xv = defaultTypedValue(m.Alloc, vt) // reuse as result + *iv = untypedBool(false) // reuse as result } else { mv := xv.V.(*MapValue) vv, exists := mv.GetValueForKey(m.Store, iv) @@ -59,27 +48,27 @@ func (m *Machine) doOpIndex2() { *xv = vv // reuse as result *iv = untypedBool(true) // reuse as result } else { - *xv = TypedValue{ // reuse as result - T: vt, - V: defaultValue(m.Alloc, vt), - } - *iv = untypedBool(false) // reuse as result + *xv = defaultTypedValue(m.Alloc, vt) // reuse as result + *iv = untypedBool(false) // reuse as result } } default: panic("should not happen") } + xv.SetReadonly(ro) } func (m *Machine) doOpSelector() { sx := m.PopExpr().(*SelectorExpr) - xv := m.PeekValue(1) + xv := m.PeekValue(1) // package, struct, whatever. + ro := m.IsReadonly(xv) res := xv.GetPointerToFromTV(m.Alloc, m.Store, sx.Path).Deref() if debug { m.Printf("-v[S] %v\n", xv) m.Printf("+v[S] %v\n", res) } *xv = res // reuse as result + xv.SetReadonly(ro) } func (m *Machine) doOpSlice() { @@ -101,12 +90,18 @@ func (m *Machine) doOpSlice() { } // slice base x xv := m.PopValue() + ro := m.IsReadonly(xv) // if a is a pointer to an array, a[low : high : max] is // shorthand for (*a)[low : high : max] + // XXX fix this in precompile instead. if xv.T.Kind() == PointerKind && xv.T.Elem().Kind() == ArrayKind { // simply deref xv. *xv = xv.V.(PointerValue).Deref() + // check array also for ro. + if !ro { + ro = xv.IsReadonly() + } } // fill default based on xv if sx.High == nil { @@ -115,10 +110,10 @@ func (m *Machine) doOpSlice() { // all low:high:max cases if maxVal == -1 { sv := xv.GetSlice(m.Alloc, lowVal, highVal) - m.PushValue(sv) + m.PushValue(sv.WithReadonly(ro)) } else { sv := xv.GetSlice2(m.Alloc, lowVal, highVal, maxVal) - m.PushValue(sv) + m.PushValue(sv.WithReadonly(ro)) } } @@ -152,17 +147,13 @@ func (m *Machine) doOpStar() { tv.SetUint8(dbv.GetByte()) m.PushValue(tv) } else { - if pv.TV.IsUndefined() && bt.Elt.Kind() != InterfaceKind { - refv := TypedValue{T: bt.Elt} - m.PushValue(refv) - } else { - m.PushValue(*pv.TV) - } + ro := m.IsReadonly(xv) + pvtv := (*pv.TV).WithReadonly(ro) + m.PushValue(pvtv) } case *TypeType: t := xv.GetType() pt := &PointerType{Elt: t} - m.PushValue(asValue(pt)) default: panic(fmt.Sprintf( @@ -174,17 +165,16 @@ func (m *Machine) doOpStar() { // XXX this is wrong, for var i interface{}; &i is *interface{}. func (m *Machine) doOpRef() { rx := m.PopExpr().(*RefExpr) - m.Alloc.AllocatePointer() - xv := m.PopAsPointer(rx.X) - // when obtaining a pointer of the databyte type, use the ElemType of databyte + xv, ro := m.PopAsPointer2(rx.X) elt := xv.TV.T if elt == DataByteType { elt = xv.TV.V.(DataByteValue).ElemType } + m.Alloc.AllocatePointer() m.PushValue(TypedValue{ T: m.Alloc.NewType(&PointerType{Elt: elt}), V: xv, - }) + }.WithReadonly(ro)) } // NOTE: keep in sync with doOpTypeAssert2. @@ -317,10 +307,7 @@ func (m *Machine) doOpTypeAssert2() { } } else { // is concrete assert if xt == nil { - *xv = TypedValue{ - T: t, - V: defaultValue(m.Alloc, t), - } + *xv = defaultTypedValue(m.Alloc, t) *tv = untypedBool(false) return } @@ -334,10 +321,7 @@ func (m *Machine) doOpTypeAssert2() { // *xv = *xv *tv = untypedBool(true) } else { - *xv = TypedValue{ - T: t, - V: defaultValue(m.Alloc, t), - } + *xv = defaultTypedValue(m.Alloc, t) *tv = untypedBool(false) } } @@ -673,30 +657,32 @@ func (m *Machine) doOpFuncLit() { // every invocation of the function. captures := []TypedValue(nil) for _, nx := range x.HeapCaptures { - ptr := lb.GetPointerTo(m.Store, nx.Path) + ptr := lb.GetPointerToDirect(m.Store, nx.Path) // check that ptr.TV is a heap item value. // it must be in the form of: // {T:heapItemType{},V:HeapItemValue{...}} if _, ok := ptr.TV.T.(heapItemType); !ok { - panic("should not happen, should be heapItemType") + panic("should not happen, should be heapItemType: " + nx.String()) } if _, ok := ptr.TV.V.(*HeapItemValue); !ok { - panic("should not happen, should be heapItemValue") + panic("should not happen, should be heapItemValue: " + nx.String()) } captures = append(captures, *ptr.TV) } m.PushValue(TypedValue{ T: ft, V: &FuncValue{ - Type: ft, - IsMethod: false, - Source: x, - Name: "", - Closure: lb, - Captures: captures, - PkgPath: m.Package.PkgPath, - body: x.Body, - nativeBody: nil, + Type: ft, + IsMethod: false, + IsClosure: true, + Source: x, + Name: "", + Parent: nil, + Captures: captures, + PkgPath: m.Package.PkgPath, + SwitchRealm: x.Body.isSwitchRealm(), + body: x.Body, + nativeBody: nil, }, }) } @@ -704,6 +690,37 @@ func (m *Machine) doOpFuncLit() { func (m *Machine) doOpConvert() { xv := m.PopValue() t := m.PopValue().GetType() + + // BEGIN conversion checks + // These protect against inter-realm conversion exploits. + + // Case 1. + // Do not allow conversion of value stored in eternal realm. + // Otherwise anyone could convert an external object insecurely. + if xv.T != nil && !xv.T.IsImmutable() && m.IsReadonly(xv) { + if xvdt, ok := xv.T.(*DeclaredType); ok && + xvdt.PkgPath == m.Realm.Path { + // Except allow if xv.T is m.Realm. + // XXX do we need/want this? + } else { + panic("illegal conversion of readonly or externally stored value") + } + } + + // Case 2. + // Do not allow conversion to type of external realm. + // Only code declared within the same realm my perform such + // conversions, otherwise the realm could be tricked + // into executing a subtle exploit of mutating some + // value (say a pointer) stored in its own realm by + // a hostile construction converted to look safe. + if tdt, ok := t.(*DeclaredType); ok && !tdt.IsImmutable() && m.Realm != nil { + if IsRealmPath(tdt.PkgPath) && tdt.PkgPath != m.Realm.Path { + panic("illegal conversion to external realm type") + } + } + // END conversion checks + ConvertTo(m.Alloc, m.Store, xv, t, false) m.PushValue(*xv) } diff --git a/gnovm/pkg/gnolang/op_unary.go b/gnovm/pkg/gnolang/op_unary.go index 73d83e32983..d3ed2267e40 100644 --- a/gnovm/pkg/gnolang/op_unary.go +++ b/gnovm/pkg/gnolang/op_unary.go @@ -78,7 +78,7 @@ func (m *Machine) doOpUnot() { case BoolType, UntypedBoolType: xv.SetBool(!xv.GetBool()) default: - panic(fmt.Sprintf("unexpected type %s in operation", + panic(fmt.Sprintf("unexpected type %v in operation", baseOf(xv.T))) } } diff --git a/gnovm/pkg/gnolang/ownership.go b/gnovm/pkg/gnolang/ownership.go index 6ce92c19ca4..752c944098f 100644 --- a/gnovm/pkg/gnolang/ownership.go +++ b/gnovm/pkg/gnolang/ownership.go @@ -84,6 +84,10 @@ func (oid ObjectID) IsZero() bool { return oid.PkgID.IsZero() } +type ObjectIDer interface { + GetObjectID() ObjectID +} + type Object interface { Value GetObjectInfo() *ObjectInfo @@ -126,6 +130,7 @@ type Object interface { var ( _ Object = &ArrayValue{} _ Object = &StructValue{} + _ Object = &FuncValue{} _ Object = &BoundMethodValue{} _ Object = &MapValue{} _ Object = &Block{} @@ -354,11 +359,13 @@ func (tv *TypedValue) GetFirstObject(store Store) Object { case *StructValue: return cv case *FuncValue: - return cv.GetClosure(store) + return cv case *MapValue: return cv case *BoundMethodValue: return cv + case *PackageValue: + return cv.GetBlock(store) case *Block: return cv case RefValue: @@ -372,3 +379,37 @@ func (tv *TypedValue) GetFirstObject(store Store) Object { return nil } } + +// returns false if there is no object. +func (tv *TypedValue) GetFirstObjectID() (ObjectID, bool) { + switch cv := tv.V.(type) { + case PointerValue: + if cv.Base == nil { + return ObjectID{}, false + } + return cv.Base.(ObjectIDer).GetObjectID(), true + case *ArrayValue: + return cv.GetObjectID(), true + case *SliceValue: + return cv.Base.(ObjectIDer).GetObjectID(), true + case *StructValue: + return cv.GetObjectID(), true + case *FuncValue: + return cv.GetObjectID(), true + case *MapValue: + return cv.GetObjectID(), true + case *BoundMethodValue: + return cv.GetObjectID(), true + case *PackageValue: + return cv.Block.(ObjectIDer).GetObjectID(), true + case *Block: + return cv.GetObjectID(), true + case RefValue: + return cv.GetObjectID(), true + case *HeapItemValue: + // should only appear in PointerValue.Base + panic("heap item value should only appear as a pointer's base") + default: + return ObjectID{}, false + } +} diff --git a/gnovm/pkg/gnolang/package.go b/gnovm/pkg/gnolang/package.go index 5d80b40451e..328623f0608 100644 --- a/gnovm/pkg/gnolang/package.go +++ b/gnovm/pkg/gnolang/package.go @@ -124,4 +124,5 @@ var Package = amino.RegisterPackage(amino.NewPackage( blockType{}, &tupleType{}, RefType{}, + heapItemType{}, )) diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 89396716c69..6a3eb52f7f2 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -116,6 +116,7 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { Attributes: base.NameExprs[j].Attributes, Path: base.NameExprs[j].Path, Name: base.NameExprs[j].Name, + Type: NameExprTypeDefine, }} if j < len(base.Values) { @@ -140,6 +141,8 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) { } // Initialize static block info. +// TODO: ensure and keep idempotent. +// PrpedefineFileSet may precede Preprocess. func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { // create stack of BlockNodes. var stack []BlockNode = make([]BlockNode, 0, 32) @@ -166,7 +169,7 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { continue } if !isLocallyDefined2(last, ln) { - // if loop extern, will promote to + // if loopvar, will promote to // NameExprTypeHeapDefine later. nx.Type = NameExprTypeDefine last.Predefine(false, ln) @@ -224,6 +227,11 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { // this also makes them unreferenceable. dname := Name(fmt.Sprintf("init.%d", idx)) n.Name = dname + } else if n.Name == blankIdentifier { + idx := pkg.GetNumNames() + dname := Name(fmt.Sprintf("._%d", idx)) + n.Name = dname + } nx := &n.NameExpr nx.Type = NameExprTypeDefine @@ -242,11 +250,13 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { } for i := range n.Results { r := &n.Results[i] + if r.Name == "" { + // create an unnamed name with leading dot. + r.Name = Name(fmt.Sprintf("%s%d", missingResultNamePrefix, i)) + } if r.Name == blankIdentifier { - // create a hidden var with leading dot. - // NOTE: document somewhere. - rn := fmt.Sprintf("%s%d", hiddenResultVariable, i) - r.Name = Name(rn) + // create an underscore name with leading dot. + r.Name = Name(fmt.Sprintf("%s%d", underscoreResultNamePrefix, i)) } } } @@ -268,38 +278,35 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { if n.Key != nil { nx := n.Key.(*NameExpr) if nx.Name != blankIdentifier { - // XXX, this should be uncommented when fully - // support Go1.22 loopvar, to make it consistent - // with for i := 0; i < 10; i++ {...}. - // nx.Type = NameExprTypeDefine - + nx.Type = NameExprTypeDefine last.Predefine(false, nx.Name) } } if n.Value != nil { nx := n.Value.(*NameExpr) if nx.Name != blankIdentifier { - // nx.Type = NameExprTypeDefine // XXX,ditto + nx.Type = NameExprTypeDefine last.Predefine(false, nx.Name) } } } case *FuncLitExpr: - for _, p := range n.Type.Params { - last.Predefine(false, p.Name) + for i := range n.Type.Params { + px := &n.Type.Params[i].NameExpr + px.Type = NameExprTypeDefine + last.Predefine(false, px.Name) } - for _, rf := range n.Type.Results { - if rf.Name != "" { - last.Predefine(false, rf.Name) + for i := range n.Type.Results { + rx := &n.Type.Results[i].NameExpr + if rx.Name == "" { + rn := fmt.Sprintf("%s%d", missingResultNamePrefix, i) + rx.Name = Name(rn) } + rx.Type = NameExprTypeDefine + last.Predefine(false, rx.Name) } case *SwitchStmt: - if n.VarName != "" { - // NOTE: this defines for default clauses too, - // see comment on block copying @ - // SwitchClauseStmt:TRANS_BLOCK. - last.Predefine(false, n.VarName) - } + // n.Varname is declared in each clause. case *SwitchClauseStmt: blen := len(n.Body) if blen > 0 { @@ -308,13 +315,14 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { // parent switch statement. ss := ns[len(ns)-1].(*SwitchStmt) - // anything declared in ss are copied, - // namely ss.VarName if defined. + // anything declared in ss.init are copied. for _, n := range ss.GetBlockNames() { last.Predefine(false, n) } if ss.IsTypeSwitch { if ss.VarName != "" { + // XXX NameExprTypeDefine in NameExpr? + // XXX XXX fix and test. last.Predefine(false, ss.VarName) } } else { @@ -324,20 +332,25 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) { } case *FuncDecl: if n.IsMethod { + n.Recv.NameExpr.Type = NameExprTypeDefine n.Predefine(false, n.Recv.Name) } - for _, pte := range n.Type.Params { - if pte.Name == "" { + for i := range n.Type.Params { + px := &n.Type.Params[i].NameExpr + if px.Name == "" { panic("should not happen") } - n.Predefine(false, pte.Name) + px.Type = NameExprTypeDefine + n.Predefine(false, px.Name) } - for i, rte := range n.Type.Results { - if rte.Name == "" { - rn := fmt.Sprintf("%s%d", hiddenResultVariable, i) - rte.Name = Name(rn) + for i := range n.Type.Results { + rx := &n.Type.Results[i].NameExpr + if rx.Name == "" { + rn := fmt.Sprintf("%s%d", missingResultNamePrefix, i) + rx.Name = Name(rn) } - n.Predefine(false, rte.Name) + rx.Type = NameExprTypeDefine + n.Predefine(false, rx.Name) } } return n, TRANS_CONTINUE @@ -415,12 +428,16 @@ var preprocessing atomic.Int32 // - Assigns BlockValuePath to NameExprs. // - TODO document what it does. func Preprocess(store Store, ctx BlockNode, n Node) Node { - // If initStaticBlocks doesn't happen here, - // it means Preprocess on blocks might fail. - // it works for now because preprocess also does pushInitBlock, - // but it's kinda weird. - // maybe consider moving initStaticBlocks here and ensure idempotency of it. + // First init static blocks if blocknode. + // This may have already happened. + // Keep this function idemponent. + if bn, ok := n.(BlockNode); ok { + initStaticBlocks(store, ctx, bn) + } + + // Bulk of the preprocessor function n = preprocess1(store, ctx, n) + // XXX check node lines and locations checkNodeLinesLocations("XXXpkgPath", "XXXfileName", n) // XXX what about the fact that preprocess1 sets the PREPROCESSED attr on all nodes? @@ -428,9 +445,10 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // XXX well the following may be isn't idempotent, // XXX so it is currently strange. if bn, ok := n.(BlockNode); ok { - findGotoLoopDefines(ctx, bn) - findLoopUses1(ctx, bn) - findLoopUses2(ctx, bn) + //findGotoLoopDefines(ctx, bn) + findHeapDefinesByUse(ctx, bn) + findHeapUsesDemoteDefines(ctx, bn) + findPackageSelectors(bn) } return n } @@ -651,19 +669,15 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // push func body block. pushInitBlock(n, &last, &stack) // define parameters in new block. - for _, p := range ft.Params { + for i, p := range ft.Params { last.Define(p.Name, anyValue(p.Type)) + n.Type.Params[i].Path = n.GetPathForName(nil, p.Name) } // define results in new block. for i, rf := range ft.Results { - if 0 < len(rf.Name) { - last.Define(rf.Name, anyValue(rf.Type)) - } else { - // create a hidden var with leading dot. - // NOTE: document somewhere. - rn := fmt.Sprintf("%s%d", hiddenResultVariable, i) - last.Define(Name(rn), anyValue(rf.Type)) - } + name := rf.Name + last.Define(name, anyValue(rf.Type)) + n.Type.Results[i].Path = n.GetPathForName(nil, name) } // TRANS_BLOCK ----------------------- @@ -684,20 +698,13 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // know which clause will match, we expand the // block once a clause has matched. pushInitBlock(n, &last, &stack) - if n.VarName != "" { - // NOTE: this defines for default clauses too, - // see comment on block copying @ - // SwitchClauseStmt:TRANS_BLOCK. - last.Define(n.VarName, anyValue(nil)) - } // TRANS_BLOCK ----------------------- case *SwitchClauseStmt: pushInitBlockAndCopy(n, &last, &stack) // parent switch statement. ss := ns[len(ns)-1].(*SwitchStmt) - // anything declared in ss are copied, - // namely ss.VarName if defined. + // anything declared in ss.Init are copied. for _, n := range ss.GetBlockNames() { tv := ss.GetValueRef(nil, n, false) last.Define(n, *tv) @@ -767,25 +774,24 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { pushInitBlock(n, &last, &stack) // define receiver in new block, if method. if n.IsMethod { - if 0 < len(n.Recv.Name) { + name := n.Recv.Name + if name != "" { rft := getType(&n.Recv).(FieldType) rt := rft.Type - last.Define(n.Recv.Name, anyValue(rt)) + last.Define(name, anyValue(rt)) + n.Recv.Path = n.GetPathForName(nil, name) } } // define parameters in new block. - for _, p := range ft.Params { + for i, p := range ft.Params { last.Define(p.Name, anyValue(p.Type)) + n.Type.Params[i].Path = n.GetPathForName(nil, p.Name) } // define results in new block. for i, rf := range ft.Results { - if 0 < len(rf.Name) { - last.Define(rf.Name, anyValue(rf.Type)) - } else { - // create a hidden var with leading dot. - rn := fmt.Sprintf("%s%d", hiddenResultVariable, i) - last.Define(Name(rn), anyValue(rf.Type)) - } + name := rf.Name + last.Define(name, anyValue(rf.Type)) + n.Type.Results[i].Path = n.GetPathForName(nil, name) } // functions that don't return a value do not need termination analysis // functions that are externally defined or builtin implemented in the vm can't be analysed @@ -1023,20 +1029,31 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { cx := evalConst(store, last, n) return cx, TRANS_CONTINUE } - // If name refers to a package, and this is not in - // the context of a selector, fail. Packages cannot - // be used as a value, for go compatibility but also - // to preserve the security expectation regarding imports. + // Special handling of packages nt := evalStaticTypeOf(store, last, n) if nt == nil { // this is fine, e.g. for TRANS_ASSIGN_LHS (define) etc. - } else if ftype != TRANS_SELECTOR_X { - nk := nt.Kind() - if nk == PackageKind { + } else if nt.Kind() == PackageKind { + // If name refers to a package, and this is not in + // the context of a selector, fail. Packages cannot + // be used as a value, for go compatibility but also + // to preserve the security expectation regarding imports. + if ftype != TRANS_SELECTOR_X { panic(fmt.Sprintf( "package %s cannot only be referred to in a selector expression", n.Name)) } + // Remember the package path + // for findPackageSelectors(). + pvc := evalConst(store, last, n) + pv, ok := pvc.V.(*PackageValue) + if !ok { + panic(fmt.Sprintf( + "missing package %s", + n.String())) + } + pref := toRefValue(pv) + n.SetAttribute(ATTR_PACKAGE_REF, pref) } } @@ -1092,13 +1109,18 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { if ric { // Left const, Right const ---------------------- // Replace with *ConstExpr if const operands. + // // First, convert untyped as necessary. - if !shouldSwapOnSpecificity(lcx.T, rcx.T) { - // convert n.Left to right type. - checkOrConvertType(store, last, n, &n.Left, rcx.T, false) - } else { - // convert n.Right to left type. - checkOrConvertType(store, last, n, &n.Right, lcx.T, false) + // If either is interface type no conversion is required. + if (lt == nil || lt.Kind() != InterfaceKind) && + (rt == nil || rt.Kind() != InterfaceKind) { + if !shouldSwapOnSpecificity(lcx.T, rcx.T) { + // convert n.Left to right type. + checkOrConvertType(store, last, n, &n.Left, rcx.T, false) + } else { + // convert n.Right to left type. + checkOrConvertType(store, last, n, &n.Right, lcx.T, false) + } } // Then, evaluate the expression. cx := evalConst(store, last, n) @@ -1354,6 +1376,15 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // The pointer value returned is not addressable, but maybe some selector // will make it addressable. For now mark it as not addressable. n.Addressability = addressabilityStatusUnsatisfied + } else if fv.PkgPath == uversePkgPath && fv.Name == "cross" { + // Memoize *CallExpr.WithCross. + pc, ok := ns[len(ns)-1].(*CallExpr) + if !ok { + panic("cross(fn) must be followed by a call") + } + pc.SetWithCross() + } else if fv.PkgPath == uversePkgPath && fv.Name == "crossing" { + // XXX Make sure it's only used in a realm. } } @@ -1783,7 +1814,7 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { var pv *PackageValue if cx, ok := n.X.(*ConstExpr); ok { // NOTE: *Machine.TestMemPackage() needs this - // to pass in an imported package as *ConstEzpr. + // to pass in an imported package as *ConstExpr. pv = cx.V.(*PackageValue) } else { // otherwise, packages can only be referred to by @@ -2099,6 +2130,19 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node { // TRANS_LEAVE ----------------------- case *ReturnStmt: fnode, ft := funcOf(last) + // Mark return statement as needing to copy + // results to named heap items of block. + // This is necessary because if the results + // are unnamed, they are omitted from block. + if ft.Results.IsNamed() && len(n.Results) != 0 { + // NOTE: We don't know yet whether any + // results are heap items or not, as + // they are found after this + // preprocessor step. Either find heap + // items before, or do another pass to + // demote for speed. + n.CopyResults = true + } // Check number of return arguments. if len(n.Results) != len(ft.Results) { if len(n.Results) == 0 { @@ -2322,12 +2366,13 @@ func defineOrDecl( node := skipFile(bn) - for i := 0; i < len(sts); i++ { - nx := nameExprs[i] + skip := 0 // skip unnamed names like _. + for i, nx := range nameExprs { if nx.Name == blankIdentifier { - nx.Path = NewValuePathBlock(0, 0, blankIdentifier) + skip++ + nx.Path = NewValuePathBlock(0, 0, nx.Name) } else { - node.Define2(isConst, nx.Name, sts[i], tvs[i]) + node.Define2(isConst, nx.Name, sts[i-skip], tvs[i-skip]) nx.Path = bn.GetPathForName(nil, nx.Name) } } @@ -2390,6 +2435,7 @@ func parseAssignFromExprList( } // Evaluate typed value for static definition. + for i := range nameExprs { // Consider value if specified. if len(valueExprs) > 0 { @@ -2481,7 +2527,13 @@ func parseMultipleAssignFromOneExpr( st = evalStaticType(store, bn, typeExpr) } - for i := 0; i < numNames; i++ { + skip := 0 // skip unnamed names like _. + for i, nx := range nameExprs { + if nx.Name == blankIdentifier { + skip++ + continue + } + // := 0; i < numNames; i++ { if st != nil { tt := tuple.Elts[i] @@ -2496,18 +2548,22 @@ func parseMultipleAssignFromOneExpr( ) } - sts[i] = st + sts[i-skip] = st } else { // Set types as return types. - sts[i] = tuple.Elts[i] + sts[i-skip] = tuple.Elts[i] } - tvs[i] = anyValue(sts[i]) + tvs[i-skip] = anyValue(sts[i-skip]) } } // Identifies NameExprTypeHeapDefines. -// Also finds GotoLoopStmts, XXX but probably remove, not needed. +// Also finds GotoLoopStmts. +// XXX DEPRECATED but kept here in case needed in the future. +// We may still want this for optimizing heap defines; +// the current implementation of findHeapDefinesByUse/findHeapUsesDemoteDefines +// produces false positives. func findGotoLoopDefines(ctx BlockNode, bn BlockNode) { // create stack of BlockNodes. var stack []BlockNode = make([]BlockNode, 0, 32) @@ -2661,12 +2717,13 @@ func findGotoLoopDefines(ctx BlockNode, bn BlockNode) { }) } -// Find uses of loop names; those names that are defined as loop defines; -// defines within loops that are used as reference or captured in a closure -// later. Also happens to adjust the type (but not paths) of such usage. -// If there is no usage of the &name or as closure capture, a -// NameExprTypeHeapDefine gets demoted to NameExprTypeDefine in demoteHeapDefines(). -func findLoopUses1(ctx BlockNode, bn BlockNode) { +// Finds heap defines by their use in ref expressions or +// closures (captures). Also adjusts the name expr type, +// and sets new closure captures' path to refer to local +// capture. +// Also happens to declare all package and file names +// as heap use, so that functions added later may use them. +func findHeapDefinesByUse(ctx BlockNode, bn BlockNode) { // create stack of BlockNodes. var stack []BlockNode = make([]BlockNode, 0, 32) var last BlockNode = ctx @@ -2677,7 +2734,7 @@ func findLoopUses1(ctx BlockNode, bn BlockNode) { defer doRecover(stack, n) if debug { - debug.Printf("findLoopUses1 %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) + debug.Printf("findHeapDefinesByUse %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) } switch stage { @@ -2686,103 +2743,125 @@ func findLoopUses1(ctx BlockNode, bn BlockNode) { pushInitBlock(n.(BlockNode), &last, &stack) // ---------------------------------------- - case TRANS_ENTER: + case TRANS_LEAVE: + + // Pop block from stack. + // NOTE: DO NOT USE TRANS_SKIP WITHIN BLOCK + // NODES, AS TRANS_LEAVE WILL BE SKIPPED; OR + // POP BLOCK YOURSELF. + defer func() { + switch n.(type) { + case BlockNode: + stack = stack[:len(stack)-1] + last = stack[len(stack)-1] + } + }() + switch n := n.(type) { + case *ValueDecl: + // Top level value decls are always heap escaped. + // See also corresponding case in findHeapUsesDemoteDefines. + if !n.Const { + switch last.(type) { + case *PackageNode, *FileNode: + pn := skipFile(last) + for _, nx := range n.NameExprs { + if nx.Name == "_" { + continue + } + addAttrHeapUse(pn, nx.Name) + } + } + } + case *RefExpr: + lmx := LeftmostX(n.X) + if nx, ok := lmx.(*NameExpr); ok { + // Find the block where name is defined + dbn := last.GetBlockNodeForPath(nil, nx.Path) + // The leftmost name of possibly nested index + // and selector exprs. + // e.g. leftmost.middle[0][2].rightmost + // Mark name for heap use. + addAttrHeapUse(dbn, nx.Name) + // adjust NameExpr type. + nx.Type = NameExprTypeHeapUse + } case *NameExpr: // Ignore non-block type paths if n.Path.Type != VPBlock { return n, TRANS_CONTINUE } + // Ignore package names + if n.GetAttribute(ATTR_PACKAGE_REF) != nil { + return n, TRANS_CONTINUE + } + // Ignore decls names. + if ftype == TRANS_VAR_NAME { + return n, TRANS_CONTINUE + } + // Find the block where name is defined + dbn := last.GetBlockNodeForPath(nil, n.Path) switch n.Type { case NameExprTypeNormal: - // Find the block where name is defined - dbn := last.GetBlockNodeForPath(nil, n.Path) - // if the name is loop defined, - lds, _ := dbn.GetAttribute(ATTR_LOOP_DEFINES).([]Name) - if slices.Contains(lds, n.Name) { - fle, depth, found := findFirstClosure(stack, dbn) - if found { - // If across a closure, - // mark name as loop used. - addAttrHeapUse(dbn, n.Name) - // The path must stay same for now, - // used later in findLoopUses2. - idx := addHeapCapture(dbn, fle, n.Name) - // adjust NameExpr type. - n.Type = NameExprTypeHeapUse - n.Path.SetDepth(uint8(depth)) - n.Path.Index = idx - } else { - if ftype == TRANS_REF_X { - // if used as a reference, - // mark name as loop used. - addAttrHeapUse(dbn, n.Name) - // Also adjust NameExpr type. - // We could do this later too. - n.Type = NameExprTypeHeapUse + for { + // If used as closure capture, mark as heap use. + flx, depth, found := findFirstClosure(stack, dbn) + if !found { + return n, TRANS_CONTINUE + } + // Ignore top level declarations. + // This get replaced by findPackageSelectors. + if pn, ok := dbn.(*PackageNode); ok { + if pn.PkgPath != ".uverse" { + n.SetAttribute(ATTR_PACKAGE_DECL, true) + return n, TRANS_CONTINUE } } - } else { - // if the name is not loop defined, - // do nothing. + + // Found a heap item closure capture. + addAttrHeapUse(dbn, n.Name) + // The path must stay same for now, + // used later in findHeapUsesDemoteDefines. + idx := addHeapCapture(dbn, flx, depth, n) + // adjust NameExpr type. + n.Type = NameExprTypeHeapUse + n.Path.SetDepth(uint8(depth)) + n.Path.Index = idx + // Loop again for more closures. + dbn = flx } - case NameExprTypeDefine: - // nothing to do. - case NameExprTypeHeapDefine: - // Set name in attribute, so later matches - // on NameExpr can know that this was loop defined - // on this block. - setAttrHeapDefine(last, n.Name) - case NameExprTypeHeapUse, NameExprTypeHeapClosure: - panic("unexpected node type") } } return n, TRANS_CONTINUE - - // ---------------------------------------- - case TRANS_LEAVE: - // Pop block from stack. - // NOTE: DO NOT USE TRANS_SKIP WITHIN BLOCK - // NODES, AS TRANS_LEAVE WILL BE SKIPPED; OR - // POP BLOCK YOURSELF. - switch n.(type) { - case BlockNode: - stack = stack[:len(stack)-1] - last = stack[len(stack)-1] - } - - return n, TRANS_CONTINUE } return n, TRANS_CONTINUE }) } -func assertNotHasName(names []Name, name Name) { - if slices.Contains(names, name) { - panic(fmt.Sprintf("name: %s already contained in names: %v", name, names)) +func addName(names []Name, name Name) []Name { + if !slices.Contains(names, name) { + names = append(names, name) } + return names } -func setAttrHeapDefine(bn BlockNode, name Name) { - bnLDs, _ := bn.GetAttribute(ATTR_LOOP_DEFINES).([]Name) - assertNotHasName(bnLDs, name) - bnLDs = append(bnLDs, name) - bn.SetAttribute(ATTR_LOOP_DEFINES, bnLDs) +func addAttrHeapUse(bn BlockNode, name Name) { + lus, _ := bn.GetAttribute(ATTR_HEAP_USES).([]Name) + lus = addName(lus, name) + bn.SetAttribute(ATTR_HEAP_USES, lus) } -func addAttrHeapUse(bn BlockNode, name Name) { - bnLUs, _ := bn.GetAttribute(ATTR_LOOP_USES).([]Name) - if slices.Contains(bnLUs, name) { - return - } else { - bnLUs = append(bnLUs, name) - bn.SetAttribute(ATTR_LOOP_USES, bnLUs) - return - } +func hasAttrHeapUse(bn BlockNode, name Name) bool { + hds, _ := bn.GetAttribute(ATTR_HEAP_USES).([]Name) + return slices.Contains(hds, name) } -// adds ~name to fle static block and to heap captures atomically. -func addHeapCapture(dbn BlockNode, fle *FuncLitExpr, name Name) (idx uint16) { +// adds ~name to func lit static block and to heap captures atomically. +func addHeapCapture(dbn BlockNode, fle *FuncLitExpr, depth int, nx *NameExpr) (idx uint16) { + if depth <= 0 { + panic("invalid depth") + } + name := nx.Name for _, ne := range fle.HeapCaptures { if ne.Name == name { // assert ~name also already defined. @@ -2805,8 +2884,11 @@ func addHeapCapture(dbn BlockNode, fle *FuncLitExpr, name Name) (idx uint16) { fle.Define("~"+name, tv.Copy(nil)) // add name to fle.HeapCaptures. - vp := fle.GetPathForName(nil, name) - vp.SetDepth(vp.Depth - 1) // minus 1 for fle itself. + // NOTE: this doesn't work with shadowing, see define1.gno. + // vp := fle.GetPathForName(nil, name) + vp := nx.Path + vp.SetDepth(vp.Depth - uint8(depth)) + //vp.SetDepth(vp.Depth - 1) // minus 1 for fle itself. ne := NameExpr{ Path: vp, Name: name, @@ -2840,8 +2922,8 @@ func findFirstClosure(stack []BlockNode, stop BlockNode) (fle *FuncLitExpr, dept fle = stbn depth = len(stack) - 1 - redundant - i + 1 // +1 since 1 is lowest. found = true - // even if found, continue iteration in case - // an earlier *FuncLitExpr is found. + // even if found, continue iteration in case + // an earlier *FuncLitExpr is found. case *IfCaseStmt, *SwitchClauseStmt: if stbn == stop { return @@ -2856,10 +2938,10 @@ func findFirstClosure(stack []BlockNode, stop BlockNode) (fle *FuncLitExpr, dept panic("stop not found in stack") } -// Convert non-loop uses of loop names to NameExprTypeHeapUse. -// Also, NameExprTypeHeapDefine gets demoted to NameExprTypeDefine if no actual -// usage was found that warrants a NameExprTypeHeapDefine. -func findLoopUses2(ctx BlockNode, bn BlockNode) { +// If a name is used as a heap item, Convert all other uses of such names +// for heap use. If a name of type heap define is not actually used +// as heap use, demotes them. +func findHeapUsesDemoteDefines(ctx BlockNode, bn BlockNode) { // create stack of BlockNodes. var stack []BlockNode = make([]BlockNode, 0, 32) var last BlockNode = ctx @@ -2870,7 +2952,7 @@ func findLoopUses2(ctx BlockNode, bn BlockNode) { defer doRecover(stack, n) if debug { - debug.Printf("findLoopUses2 %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) + debug.Printf("findHeapUsesDemoteDefines %s (%v) stage:%v\n", n.String(), reflect.TypeOf(n), stage) } switch stage { @@ -2890,29 +2972,42 @@ func findLoopUses2(ctx BlockNode, bn BlockNode) { case NameExprTypeNormal: // Find the block where name is defined dbn := last.GetBlockNodeForPath(nil, n.Path) - // if the name is loop defined, - lds, _ := dbn.GetAttribute(ATTR_LOOP_DEFINES).([]Name) - if slices.Contains(lds, n.Name) { - // if the name is actually loop used, - lus, _ := dbn.GetAttribute(ATTR_LOOP_USES).([]Name) - if slices.Contains(lus, n.Name) { - // change type finally to HeapUse. - n.Type = NameExprTypeHeapUse - } else { - // else, will be demoted in later clause. - } + // If the name is heap used, + if hasAttrHeapUse(dbn, n.Name) { + // Change type to heap use. + n.Type = NameExprTypeHeapUse } - case NameExprTypeHeapDefine: + case NameExprTypeDefine, NameExprTypeHeapDefine: // Find the block where name is defined dbn := last.GetBlockNodeForPath(nil, n.Path) - // if the name is loop defined - lds, _ := dbn.GetAttribute(ATTR_LOOP_DEFINES).([]Name) - if slices.Contains(lds, n.Name) { - // if the name is actually loop used - lus, _ := dbn.GetAttribute(ATTR_LOOP_USES).([]Name) - if !slices.Contains(lus, n.Name) { - // demote type finally to Define. - n.Type = NameExprTypeDefine + // If the name is actually heap used: + if hasAttrHeapUse(dbn, n.Name) { + // Promote type to heap define. + n.Type = NameExprTypeHeapDefine + // Make record in static block. + dbn.SetIsHeapItem(n.Name) + } else { + // Demote type to regular define. + n.Type = NameExprTypeDefine + } + } + case *ValueDecl: + // Top level var value decls are always heap escaped. + // See also corresponding case in findHeapDefinesByUse. + if !n.Const { + switch last.(type) { + case *PackageNode, *FileNode: + pn := skipFile(last) + for i := range n.NameExprs { + nx := &n.NameExprs[i] + if nx.Name == "_" { + continue + } + if !hasAttrHeapUse(pn, nx.Name) { + panic("expected heap use for top level value decl") + } + nx.Type = NameExprTypeHeapDefine + pn.SetIsHeapItem(nx.Name) } } } @@ -2936,14 +3031,47 @@ func findLoopUses2(ctx BlockNode, bn BlockNode) { switch n := n.(type) { case BlockNode: - lds, _ := n.GetAttribute(ATTR_LOOP_DEFINES).([]Name) - lus, _ := n.GetAttribute(ATTR_LOOP_USES).([]Name) - if len(lds) < len(lus) { - panic("defines should be a superset of used-defines") + switch fd := n.(type) { + case *FuncDecl: + recv := &fd.Recv + if hasAttrHeapUse(fd, recv.Name) { + recv.NameExpr.Type = NameExprTypeHeapDefine + fd.SetIsHeapItem(recv.Name) + } + for i := 0; i < len(fd.Type.Params); i++ { + name := fd.Type.Params[i].Name + if hasAttrHeapUse(fd, name) { + fd.Type.Params[i].NameExpr.Type = NameExprTypeHeapDefine + fd.SetIsHeapItem(name) + } + } + for i := 0; i < len(fd.Type.Results); i++ { + name := fd.Type.Results[i].Name + if hasAttrHeapUse(fd, name) { + fd.Type.Results[i].NameExpr.Type = NameExprTypeHeapDefine + fd.SetIsHeapItem(name) + } + } + case *FuncLitExpr: + for i := 0; i < len(fd.Type.Params); i++ { + name := fd.Type.Params[i].Name + if hasAttrHeapUse(fd, name) { + fd.Type.Params[i].NameExpr.Type = NameExprTypeHeapDefine + fd.SetIsHeapItem(name) + } + } + for i := 0; i < len(fd.Type.Results); i++ { + name := fd.Type.Results[i].Name + if hasAttrHeapUse(fd, name) { + fd.Type.Results[i].NameExpr.Type = NameExprTypeHeapDefine + fd.SetIsHeapItem(name) + } + } } + // no need anymore - n.DelAttribute(ATTR_LOOP_USES) - n.DelAttribute(ATTR_LOOP_DEFINES) + n.DelAttribute(ATTR_HEAP_USES) + n.DelAttribute(ATTR_HEAP_DEFINES) } return n, TRANS_CONTINUE } @@ -2951,6 +3079,60 @@ func findLoopUses2(ctx BlockNode, bn BlockNode) { }) } +// Replaces all pkg.name selectors with const exprs containing refs. +// TODO Do not perform this transform unless the name is used +// inside of a closure. Top level declared functions and methods +// do not need this indirection. XXX +func findPackageSelectors(bn BlockNode) { + // Iterate over all nodes recursively. + _ = Transcribe(bn, func(ns []Node, ftype TransField, index int, n Node, stage TransStage) (Node, TransCtrl) { + switch stage { + case TRANS_ENTER: + switch n := n.(type) { + case *NameExpr: + // Replace a package name with RefValue{PkgPath} + prefi := n.GetAttribute(ATTR_PACKAGE_REF) + if prefi != nil { + pref := prefi.(RefValue) + cx := &ConstExpr{ + Source: n, + TypedValue: TypedValue{ + T: gPackageType, + V: pref, + }, + } + return cx, TRANS_CONTINUE + } + // Replace a local package declared name with + // SelectorExpr{X:RefValue{PkgPath},Sel:name} + pdi := n.GetAttribute(ATTR_PACKAGE_DECL) + if pdi != nil { // is true + if n.Path.Type != VPBlock { + panic("expected block path") + } + pn := packageOf(bn) + cx := &ConstExpr{ + Source: n, + TypedValue: TypedValue{ + T: gPackageType, + V: RefValue{ + PkgPath: pn.PkgPath, + }, + }, + } + sx := &SelectorExpr{ + X: cx, + Path: NewValuePathBlock(1, n.Path.Index, n.Name), + Sel: n.Name, + } + return sx, TRANS_CONTINUE + } + } + } + return n, TRANS_CONTINUE + }) +} + func isSwitchLabel(ns []Node, label Name) bool { for { swch := lastSwitch(ns) @@ -2972,13 +3154,7 @@ func isSwitchLabel(ns []Node, label Name) bool { // Also makes sure the stack doesn't reach MaxUint8 in length. func pushInitBlock(bn BlockNode, last *BlockNode, stack *[]BlockNode) { if !bn.IsInitialized() { - switch bn.(type) { - case *IfCaseStmt, *SwitchClauseStmt: - // skip faux block - bn.InitStaticBlock(bn, (*last).GetParentNode(nil)) - default: - bn.InitStaticBlock(bn, *last) - } + bn.InitStaticBlock(bn, *last) } if bn.GetStaticBlock().Source != bn { panic("expected the source of a block node to be itself") @@ -3304,7 +3480,7 @@ func findBranchLabel(last BlockNode, label Name) ( bn = cbn return } - last = cbn.GetParentNode(nil) + last = skipFaux(cbn.GetParentNode(nil)) depth += 1 case *IfStmt: // These are faux blocks -- shouldn't happen. @@ -3363,7 +3539,7 @@ func findGotoLabel(last BlockNode, label Name) ( bn = cbn return } else { - last = cbn.GetParentNode(nil) + last = skipFaux(cbn.GetParentNode(nil)) depth += 1 } default: @@ -3531,8 +3707,11 @@ func convertType(store Store, last BlockNode, n Node, x *Expr, t Type) { // convert x to destination type t doConvertType(store, last, x, t) } else { - // if one side is declared name type and the other side is unnamed type - if isNamedConversion(xt, t) { + // if t is interface do nothing + if t != nil && t.Kind() == InterfaceKind { + // do nothing + } else if isNamedConversion(xt, t) { + // if one side is declared name type and the other side is unnamed type // covert right (xt) to the type of the left (t) doConvertType(store, last, x, t) } @@ -3542,6 +3721,7 @@ func convertType(store Store, last BlockNode, n Node, x *Expr, t Type) { // convert x to destination type t func doConvertType(store Store, last BlockNode, x *Expr, t Type) { + // XXX cx := Expr(Call(constType(*x, t), *x)) cx = Preprocess(store, last, cx).(Expr) *x = cx @@ -4534,15 +4714,16 @@ func predefineNow2(store Store, last BlockNode, d Decl, stack *[]Name) (Decl, bo } // The body may get altered during preprocessing later. if !dt.TryDefineMethod(&FuncValue{ - Type: ft, - IsMethod: true, - Source: cd, - Name: cd.Name, - Closure: nil, // set lazily. - FileName: fileNameOf(last), - PkgPath: pkg.PkgPath, - body: cd.Body, - nativeBody: nil, + Type: ft, + IsMethod: true, + Source: cd, + Name: cd.Name, + Parent: nil, // set lazily + FileName: fileNameOf(last), + PkgPath: pkg.PkgPath, + SwitchRealm: cd.Body.isSwitchRealm(), + body: cd.Body, + nativeBody: nil, }) { // Revert to old function declarations in the package we're preprocessing. pkg := packageOf(last) @@ -4805,15 +4986,16 @@ func tryPredefine(store Store, pkg *PackageNode, last BlockNode, d Decl) (un Nam // fill in later during *FuncDecl:BLOCK. // The body may get altered during preprocessing later. fv := &FuncValue{ - Type: ft, - IsMethod: false, - Source: d, - Name: d.Name, - Closure: nil, // set lazily. - FileName: fileNameOf(last), - PkgPath: pkg.PkgPath, - body: d.Body, - nativeBody: nil, + Type: ft, + IsMethod: false, + Source: d, + Name: d.Name, + Parent: nil, // set lazily. + FileName: fileNameOf(last), + PkgPath: pkg.PkgPath, + SwitchRealm: d.Body.isSwitchRealm(), + body: d.Body, + nativeBody: nil, } // NOTE: fv.body == nil means no body (ie. not even curly braces) // len(fv.body) == 0 could mean also {} (ie. no statements inside) @@ -4875,6 +5057,21 @@ func constUntypedBigint(source Expr, i64 int64) *ConstExpr { return cx } +func skipFaux(bn BlockNode) BlockNode { + if fauxBlockNode(bn) { + return bn.GetParentNode(nil) + } + return bn +} + +func fauxBlockNode(bn BlockNode) bool { + switch bn.(type) { + case *IfStmt, *SwitchStmt: + return true + } + return false +} + func fillNameExprPath(last BlockNode, nx *NameExpr, isDefineLHS bool) { if nx.Name == blankIdentifier { // Blank name has no path; caller error. @@ -4889,9 +5086,13 @@ func fillNameExprPath(last BlockNode, nx *NameExpr, isDefineLHS bool) { // and declared variables. See tests/files/define1.go for test case. var path ValuePath var i int = 0 + var faux int = 0 for { i++ last = last.GetParentNode(nil) + if fauxBlockNode(last) { + faux++ + } if last == nil { if isUverseName(nx.Name) { idx, ok := UverseNode().GetLocalIndex(nx.Name) @@ -4915,7 +5116,7 @@ func fillNameExprPath(last BlockNode, nx *NameExpr, isDefineLHS bool) { break } } - path.SetDepth(path.Depth + uint8(i)) + path.SetDepth(path.Depth + uint8(i) - uint8(faux)) path.Validate() nx.Path = path return diff --git a/gnovm/pkg/gnolang/realm.go b/gnovm/pkg/gnolang/realm.go index 56f80d63882..5bd4d735907 100644 --- a/gnovm/pkg/gnolang/realm.go +++ b/gnovm/pkg/gnolang/realm.go @@ -1,11 +1,14 @@ package gnolang +// XXX test that p is not actually mutable + +// XXX finalize should consider hard boundaries only + import ( "encoding/hex" "encoding/json" "fmt" "reflect" - "strings" "sync" bm "github.com/gnolang/gno/gnovm/pkg/benchops" @@ -116,8 +119,8 @@ type Realm struct { Time uint64 newCreated []Object - newEscaped []Object newDeleted []Object + newEscaped []Object created []Object // about to become real. updated []Object // real objects that were modified. @@ -333,8 +336,8 @@ func (rlm *Realm) FinalizeRealmTransaction(store Store) { // * newEscaped - may become escaped unless new-real and refcount 0 or 1. // * updated - includes all real updated objects, and will be appended with ancestors ensureUniq(rlm.newCreated) - ensureUniq(rlm.newEscaped) ensureUniq(rlm.newDeleted) + ensureUniq(rlm.newEscaped) ensureUniq(rlm.updated) if false || rlm.created != nil || @@ -347,12 +350,12 @@ func (rlm *Realm) FinalizeRealmTransaction(store Store) { store.LogSwitchRealm(rlm.Path) // increment recursively for created descendants. // also assigns object ids for all. - rlm.processNewCreatedMarks(store) + rlm.processNewCreatedMarks(store, 0) // decrement recursively for deleted descendants. rlm.processNewDeletedMarks(store) // at this point, all ref-counts are final. // demote any escaped if ref-count is 1. - rlm.processNewEscapedMarks(store) + rlm.processNewEscapedMarks(store, 0) // given created and updated objects, // mark all owned-ancestors also as dirty. rlm.markDirtyAncestors(store) @@ -378,9 +381,10 @@ func (rlm *Realm) FinalizeRealmTransaction(store Store) { // finding more newly created objects recursively. // All newly created objects become appended to .created, // and get assigned ids. -func (rlm *Realm) processNewCreatedMarks(store Store) { +// Starts processing with index 'start', returns len(newCreated). +func (rlm *Realm) processNewCreatedMarks(store Store, start int) int { // Create new objects and their new descendants. - for _, oo := range rlm.newCreated { + for _, oo := range rlm.newCreated[start:] { if debug { if oo.GetIsDirty() { panic("new created mark cannot be dirty") @@ -404,6 +408,7 @@ func (rlm *Realm) processNewCreatedMarks(store Store) { if len(rlm.newCreated) > 0 { store.SetPackageRealm(rlm) } + return len(rlm.newCreated) } // oo must be marked new-real, and ref-count already incremented. @@ -544,7 +549,8 @@ func (rlm *Realm) decRefDeletedDescendants(store Store, oo Object) { // demotes new-real escaped objects with refcount 0 or 1. remaining // objects get their original owners marked dirty (to be further // marked via markDirtyAncestors). -func (rlm *Realm) processNewEscapedMarks(store Store) { +// Starts processing with index 'start', returns len(newEscaped). +func (rlm *Realm) processNewEscapedMarks(store Store, start int) int { escaped := make([]Object, 0, len(rlm.newEscaped)) // These are those marked by MarkNewEscaped(), // regardless of whether new-real or was real, @@ -552,7 +558,9 @@ func (rlm *Realm) processNewEscapedMarks(store Store) { // (and never can be unescaped,) // except for new-reals that get demoted // because ref-count isn't >= 2. - for _, eo := range rlm.newEscaped { + //for _, eo := range rlm.newEscaped[start:] { + for i := 0; i < len(rlm.newEscaped[start:]); i++ { // may expand. + eo := rlm.newEscaped[i] if debug { if !eo.GetIsNewEscaped() { panic("new escaped mark not marked as new escaped") @@ -589,7 +597,9 @@ func (rlm *Realm) processNewEscapedMarks(store Store) { rlm.MarkDirty(po) } if eo.GetObjectID().IsZero() { - panic("new escaped mark has no object ID") + // eo was passed from caller. + rlm.incRefCreatedDescendants(store, eo) + eo.SetIsNewReal(true) } // escaped has no owner. eo.SetOwner(nil) @@ -597,6 +607,7 @@ func (rlm *Realm) processNewEscapedMarks(store Store) { } } rlm.escaped = escaped // XXX is this actually used? + return len(rlm.newEscaped) } //---------------------------------------- @@ -864,7 +875,7 @@ func getChildObjects(val Value, more []Value) []Value { } return more case *FuncValue: - if bv, ok := cv.Closure.(*Block); ok { + if bv, ok := cv.Parent.(*Block); ok { more = getSelfOrChildObjects(bv, more) } for _, c := range cv.Captures { @@ -872,7 +883,7 @@ func getChildObjects(val Value, more []Value) []Value { } return more case *BoundMethodValue: - more = getChildObjects(cv.Func, more) // *FuncValue not object + more = getSelfOrChildObjects(cv.Func, more) more = getSelfOrChildObjects(cv.Receiver.V, more) return more case *MapValue: @@ -1068,6 +1079,8 @@ func copyTypeWithRefs(typ Type) Type { return RefType{ ID: ct.ID, } + case heapItemType: + return ct default: panic(fmt.Sprintf( "unexpected type %v", typ)) @@ -1142,13 +1155,13 @@ func copyValueWithRefs(val Value) Value { } case *FuncValue: source := toRefNode(cv.Source) - if strings.HasSuffix(source.Location.File, "_test.gno") { - // Ignore _test files - return nil + var parent Value + if cv.Parent != nil { + parent = toRefValue(cv.Parent) } - var closure Value - if cv.Closure != nil { - closure = toRefValue(cv.Closure) + captures := make([]TypedValue, len(cv.Captures)) + for i, ctv := range cv.Captures { + captures[i] = refOrCopyValue(ctv) } // nativeBody funcs which don't come from NativeResolver (and thus don't // have NativePkg/Name) can't be persisted, and should not be able @@ -1158,22 +1171,24 @@ func copyValueWithRefs(val Value) Value { } ft := copyTypeWithRefs(cv.Type) return &FuncValue{ - Type: ft, - IsMethod: cv.IsMethod, - Source: source, - Name: cv.Name, - Closure: closure, - Captures: cv.Captures, - FileName: cv.FileName, - PkgPath: cv.PkgPath, - NativePkg: cv.NativePkg, - NativeName: cv.NativeName, + ObjectInfo: cv.ObjectInfo.Copy(), + Type: ft, + IsMethod: cv.IsMethod, + Source: source, + Name: cv.Name, + Parent: parent, + Captures: captures, + FileName: cv.FileName, + PkgPath: cv.PkgPath, + NativePkg: cv.NativePkg, + NativeName: cv.NativeName, + SwitchRealm: cv.SwitchRealm, } case *BoundMethodValue: fnc := copyValueWithRefs(cv.Func).(*FuncValue) rtv := refOrCopyValue(cv.Receiver) return &BoundMethodValue{ - ObjectInfo: cv.ObjectInfo.Copy(), // XXX ??? + ObjectInfo: cv.ObjectInfo.Copy(), Func: fnc, Receiver: rtv, } @@ -1226,18 +1241,6 @@ func copyValueWithRefs(val Value) Value { case RefValue: return cv case *HeapItemValue: - // NOTE: While this could be eliminated sometimes with some - // intelligence prior to persistence, to unwrap the - // HeapItemValue in case where the HeapItemValue only has - // refcount of 1, - // - // 1. The HeapItemValue is necessary when the .Value is a - // primitive non-object anyways, and - // 2. This would mean PointerValue.Base is nil, and we'd need - // additional logic to re-wrap when necessary, and - // 3. And with the above point, it's not clear the result - // would be any faster. But this is something we could - // explore after launch. hiv := &HeapItemValue{ ObjectInfo: cv.ObjectInfo.Copy(), Value: refOrCopyValue(cv.Value), @@ -1329,6 +1332,8 @@ func fillType(store Store, typ Type) Type { return ct case RefType: return store.GetType(ct.TypeID()) + case heapItemType: + return ct default: panic(fmt.Sprintf( "unexpected type %v", reflect.TypeOf(typ))) diff --git a/gnovm/pkg/gnolang/string_methods.go b/gnovm/pkg/gnolang/string_methods.go index ae49fe2ca9c..22aad75bbf6 100644 --- a/gnovm/pkg/gnolang/string_methods.go +++ b/gnovm/pkg/gnolang/string_methods.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=Kind,Op,TransCtrl,TransField,VPType,Word -output string_methods.go ."; DO NOT EDIT. +// Code generated by "stringer -type=Kind,Op,TransCtrl,TransField,VPType,Word -output string_methods.go"; DO NOT EDIT. package gnolang @@ -62,9 +62,6 @@ func _() { _ = x[OpPrecall-4] _ = x[OpCall-5] _ = x[OpCallNativeBody-6] - _ = x[OpReturn-7] - _ = x[OpReturnFromBlock-8] - _ = x[OpReturnToBlock-9] _ = x[OpDefer-10] _ = x[OpCallDeferNativeBody-11] _ = x[OpGo-12] @@ -79,6 +76,10 @@ func _() { _ = x[OpPopFrameAndReset-21] _ = x[OpPanic1-22] _ = x[OpPanic2-23] + _ = x[OpReturn-26] + _ = x[OpReturnAfterCopy-27] + _ = x[OpReturnFromBlock-28] + _ = x[OpReturnToBlock-29] _ = x[OpUpos-32] _ = x[OpUneg-33] _ = x[OpUnot-34] @@ -159,59 +160,119 @@ func _() { _ = x[OpVoid-255] } -const ( - _Op_name_0 = "OpInvalidOpHaltOpNoopOpExecOpPrecallOpCallOpCallNativeBodyOpReturnOpReturnFromBlockOpReturnToBlockOpDeferOpCallDeferNativeBodyOpGoOpSelectOpSwitchClauseOpSwitchClauseCaseOpTypeSwitchOpIfCondOpPopValueOpPopResultsOpPopBlockOpPopFrameAndResetOpPanic1OpPanic2" - _Op_name_1 = "OpUposOpUnegOpUnotOpUxor" - _Op_name_2 = "OpUrecvOpLorOpLandOpEqlOpNeqOpLssOpLeqOpGtrOpGeqOpAddOpSubOpBorOpXorOpMulOpQuoOpRemOpShlOpShrOpBandOpBandn" - _Op_name_3 = "OpEvalOpBinary1OpIndex1OpIndex2OpSelectorOpSliceOpStarOpRefOpTypeAssert1OpTypeAssert2OpStaticTypeOfOpCompositeLitOpArrayLitOpSliceLitOpSliceLit2OpMapLitOpStructLitOpFuncLitOpConvert" - _Op_name_4 = "OpFieldTypeOpArrayTypeOpSliceTypeOpPointerTypeOpInterfaceTypeOpChanTypeOpFuncTypeOpMapTypeOpStructType" - _Op_name_5 = "OpAssignOpAddAssignOpSubAssignOpMulAssignOpQuoAssignOpRemAssignOpBandAssignOpBandnAssignOpBorAssignOpXorAssignOpShlAssignOpShrAssignOpDefineOpIncOpDec" - _Op_name_6 = "OpValueDeclOpTypeDecl" - _Op_name_7 = "OpStickyOpBodyOpForLoopOpRangeIterOpRangeIterStringOpRangeIterMapOpRangeIterArrayPtrOpReturnCallDefers" - _Op_name_8 = "OpVoid" -) +const _Op_name = "OpInvalidOpHaltOpNoopOpExecOpPrecallOpCallOpCallNativeBodyOpDeferOpCallDeferNativeBodyOpGoOpSelectOpSwitchClauseOpSwitchClauseCaseOpTypeSwitchOpIfCondOpPopValueOpPopResultsOpPopBlockOpPopFrameAndResetOpPanic1OpPanic2OpReturnOpReturnAfterCopyOpReturnFromBlockOpReturnToBlockOpUposOpUnegOpUnotOpUxorOpUrecvOpLorOpLandOpEqlOpNeqOpLssOpLeqOpGtrOpGeqOpAddOpSubOpBorOpXorOpMulOpQuoOpRemOpShlOpShrOpBandOpBandnOpEvalOpBinary1OpIndex1OpIndex2OpSelectorOpSliceOpStarOpRefOpTypeAssert1OpTypeAssert2OpStaticTypeOfOpCompositeLitOpArrayLitOpSliceLitOpSliceLit2OpMapLitOpStructLitOpFuncLitOpConvertOpFieldTypeOpArrayTypeOpSliceTypeOpPointerTypeOpInterfaceTypeOpChanTypeOpFuncTypeOpMapTypeOpStructTypeOpAssignOpAddAssignOpSubAssignOpMulAssignOpQuoAssignOpRemAssignOpBandAssignOpBandnAssignOpBorAssignOpXorAssignOpShlAssignOpShrAssignOpDefineOpIncOpDecOpValueDeclOpTypeDeclOpStickyOpBodyOpForLoopOpRangeIterOpRangeIterStringOpRangeIterMapOpRangeIterArrayPtrOpReturnCallDefersOpVoid" -var ( - _Op_index_0 = [...]uint16{0, 9, 15, 21, 27, 36, 42, 58, 66, 83, 98, 105, 126, 130, 138, 152, 170, 182, 190, 200, 212, 222, 240, 248, 256} - _Op_index_1 = [...]uint8{0, 6, 12, 18, 24} - _Op_index_2 = [...]uint8{0, 7, 12, 18, 23, 28, 33, 38, 43, 48, 53, 58, 63, 68, 73, 78, 83, 88, 93, 99, 106} - _Op_index_3 = [...]uint8{0, 6, 15, 23, 31, 41, 48, 54, 59, 72, 85, 99, 113, 123, 133, 144, 152, 163, 172, 181} - _Op_index_4 = [...]uint8{0, 11, 22, 33, 46, 61, 71, 81, 90, 102} - _Op_index_5 = [...]uint8{0, 8, 19, 30, 41, 52, 63, 75, 88, 99, 110, 121, 132, 140, 145, 150} - _Op_index_6 = [...]uint8{0, 11, 21} - _Op_index_7 = [...]uint8{0, 8, 14, 23, 34, 51, 65, 84, 102} -) +var _Op_map = map[Op]string{ + 0: _Op_name[0:9], + 1: _Op_name[9:15], + 2: _Op_name[15:21], + 3: _Op_name[21:27], + 4: _Op_name[27:36], + 5: _Op_name[36:42], + 6: _Op_name[42:58], + 10: _Op_name[58:65], + 11: _Op_name[65:86], + 12: _Op_name[86:90], + 13: _Op_name[90:98], + 14: _Op_name[98:112], + 15: _Op_name[112:130], + 16: _Op_name[130:142], + 17: _Op_name[142:150], + 18: _Op_name[150:160], + 19: _Op_name[160:172], + 20: _Op_name[172:182], + 21: _Op_name[182:200], + 22: _Op_name[200:208], + 23: _Op_name[208:216], + 26: _Op_name[216:224], + 27: _Op_name[224:241], + 28: _Op_name[241:258], + 29: _Op_name[258:273], + 32: _Op_name[273:279], + 33: _Op_name[279:285], + 34: _Op_name[285:291], + 35: _Op_name[291:297], + 37: _Op_name[297:304], + 38: _Op_name[304:309], + 39: _Op_name[309:315], + 40: _Op_name[315:320], + 41: _Op_name[320:325], + 42: _Op_name[325:330], + 43: _Op_name[330:335], + 44: _Op_name[335:340], + 45: _Op_name[340:345], + 46: _Op_name[345:350], + 47: _Op_name[350:355], + 48: _Op_name[355:360], + 49: _Op_name[360:365], + 50: _Op_name[365:370], + 51: _Op_name[370:375], + 52: _Op_name[375:380], + 53: _Op_name[380:385], + 54: _Op_name[385:390], + 55: _Op_name[390:396], + 56: _Op_name[396:403], + 64: _Op_name[403:409], + 65: _Op_name[409:418], + 66: _Op_name[418:426], + 67: _Op_name[426:434], + 68: _Op_name[434:444], + 69: _Op_name[444:451], + 70: _Op_name[451:457], + 71: _Op_name[457:462], + 72: _Op_name[462:475], + 73: _Op_name[475:488], + 74: _Op_name[488:502], + 75: _Op_name[502:516], + 76: _Op_name[516:526], + 77: _Op_name[526:536], + 78: _Op_name[536:547], + 79: _Op_name[547:555], + 80: _Op_name[555:566], + 81: _Op_name[566:575], + 82: _Op_name[575:584], + 112: _Op_name[584:595], + 113: _Op_name[595:606], + 114: _Op_name[606:617], + 115: _Op_name[617:630], + 116: _Op_name[630:645], + 117: _Op_name[645:655], + 118: _Op_name[655:665], + 119: _Op_name[665:674], + 120: _Op_name[674:686], + 128: _Op_name[686:694], + 129: _Op_name[694:705], + 130: _Op_name[705:716], + 131: _Op_name[716:727], + 132: _Op_name[727:738], + 133: _Op_name[738:749], + 134: _Op_name[749:761], + 135: _Op_name[761:774], + 136: _Op_name[774:785], + 137: _Op_name[785:796], + 138: _Op_name[796:807], + 139: _Op_name[807:818], + 140: _Op_name[818:826], + 141: _Op_name[826:831], + 142: _Op_name[831:836], + 144: _Op_name[836:847], + 145: _Op_name[847:857], + 208: _Op_name[857:865], + 209: _Op_name[865:871], + 210: _Op_name[871:880], + 211: _Op_name[880:891], + 212: _Op_name[891:908], + 213: _Op_name[908:922], + 214: _Op_name[922:941], + 215: _Op_name[941:959], + 255: _Op_name[959:965], +} func (i Op) String() string { - switch { - case i <= 23: - return _Op_name_0[_Op_index_0[i]:_Op_index_0[i+1]] - case 32 <= i && i <= 35: - i -= 32 - return _Op_name_1[_Op_index_1[i]:_Op_index_1[i+1]] - case 37 <= i && i <= 56: - i -= 37 - return _Op_name_2[_Op_index_2[i]:_Op_index_2[i+1]] - case 64 <= i && i <= 82: - i -= 64 - return _Op_name_3[_Op_index_3[i]:_Op_index_3[i+1]] - case 112 <= i && i <= 120: - i -= 112 - return _Op_name_4[_Op_index_4[i]:_Op_index_4[i+1]] - case 128 <= i && i <= 142: - i -= 128 - return _Op_name_5[_Op_index_5[i]:_Op_index_5[i+1]] - case 144 <= i && i <= 145: - i -= 144 - return _Op_name_6[_Op_index_6[i]:_Op_index_6[i+1]] - case 208 <= i && i <= 215: - i -= 208 - return _Op_name_7[_Op_index_7[i]:_Op_index_7[i+1]] - case i == 255: - return _Op_name_8 - default: - return "Op(" + strconv.FormatInt(int64(i), 10) + ")" + if str, ok := _Op_map[i]; ok { + return str } + return "Op(" + strconv.FormatInt(int64(i), 10) + ")" } func _() { // An "invalid array index" compiler error signifies that the constant values have changed. @@ -259,67 +320,68 @@ func _() { _ = x[TRANS_FUNCLIT_TYPE-20] _ = x[TRANS_FUNCLIT_HEAP_CAPTURE-21] _ = x[TRANS_FUNCLIT_BODY-22] - _ = x[TRANS_FIELDTYPE_TYPE-23] - _ = x[TRANS_FIELDTYPE_TAG-24] - _ = x[TRANS_ARRAYTYPE_LEN-25] - _ = x[TRANS_ARRAYTYPE_ELT-26] - _ = x[TRANS_SLICETYPE_ELT-27] - _ = x[TRANS_INTERFACETYPE_METHOD-28] - _ = x[TRANS_CHANTYPE_VALUE-29] - _ = x[TRANS_FUNCTYPE_PARAM-30] - _ = x[TRANS_FUNCTYPE_RESULT-31] - _ = x[TRANS_MAPTYPE_KEY-32] - _ = x[TRANS_MAPTYPE_VALUE-33] - _ = x[TRANS_STRUCTTYPE_FIELD-34] - _ = x[TRANS_ASSIGN_LHS-35] - _ = x[TRANS_ASSIGN_RHS-36] - _ = x[TRANS_BLOCK_BODY-37] - _ = x[TRANS_DECL_BODY-38] - _ = x[TRANS_DEFER_CALL-39] - _ = x[TRANS_EXPR_X-40] - _ = x[TRANS_FOR_INIT-41] - _ = x[TRANS_FOR_COND-42] - _ = x[TRANS_FOR_POST-43] - _ = x[TRANS_FOR_BODY-44] - _ = x[TRANS_GO_CALL-45] - _ = x[TRANS_IF_INIT-46] - _ = x[TRANS_IF_COND-47] - _ = x[TRANS_IF_BODY-48] - _ = x[TRANS_IF_ELSE-49] - _ = x[TRANS_IF_CASE_BODY-50] - _ = x[TRANS_INCDEC_X-51] - _ = x[TRANS_RANGE_X-52] - _ = x[TRANS_RANGE_KEY-53] - _ = x[TRANS_RANGE_VALUE-54] - _ = x[TRANS_RANGE_BODY-55] - _ = x[TRANS_RETURN_RESULT-56] - _ = x[TRANS_PANIC_EXCEPTION-57] - _ = x[TRANS_SELECT_CASE-58] - _ = x[TRANS_SELECTCASE_COMM-59] - _ = x[TRANS_SELECTCASE_BODY-60] - _ = x[TRANS_SEND_CHAN-61] - _ = x[TRANS_SEND_VALUE-62] - _ = x[TRANS_SWITCH_INIT-63] - _ = x[TRANS_SWITCH_X-64] - _ = x[TRANS_SWITCH_CASE-65] - _ = x[TRANS_SWITCHCASE_CASE-66] - _ = x[TRANS_SWITCHCASE_BODY-67] - _ = x[TRANS_FUNC_RECV-68] - _ = x[TRANS_FUNC_TYPE-69] - _ = x[TRANS_FUNC_BODY-70] - _ = x[TRANS_IMPORT_PATH-71] - _ = x[TRANS_CONST_TYPE-72] - _ = x[TRANS_CONST_VALUE-73] - _ = x[TRANS_VAR_NAME-74] - _ = x[TRANS_VAR_TYPE-75] - _ = x[TRANS_VAR_VALUE-76] - _ = x[TRANS_TYPE_TYPE-77] - _ = x[TRANS_FILE_BODY-78] + _ = x[TRANS_FIELDTYPE_NAME-23] + _ = x[TRANS_FIELDTYPE_TYPE-24] + _ = x[TRANS_FIELDTYPE_TAG-25] + _ = x[TRANS_ARRAYTYPE_LEN-26] + _ = x[TRANS_ARRAYTYPE_ELT-27] + _ = x[TRANS_SLICETYPE_ELT-28] + _ = x[TRANS_INTERFACETYPE_METHOD-29] + _ = x[TRANS_CHANTYPE_VALUE-30] + _ = x[TRANS_FUNCTYPE_PARAM-31] + _ = x[TRANS_FUNCTYPE_RESULT-32] + _ = x[TRANS_MAPTYPE_KEY-33] + _ = x[TRANS_MAPTYPE_VALUE-34] + _ = x[TRANS_STRUCTTYPE_FIELD-35] + _ = x[TRANS_ASSIGN_LHS-36] + _ = x[TRANS_ASSIGN_RHS-37] + _ = x[TRANS_BLOCK_BODY-38] + _ = x[TRANS_DECL_BODY-39] + _ = x[TRANS_DEFER_CALL-40] + _ = x[TRANS_EXPR_X-41] + _ = x[TRANS_FOR_INIT-42] + _ = x[TRANS_FOR_COND-43] + _ = x[TRANS_FOR_POST-44] + _ = x[TRANS_FOR_BODY-45] + _ = x[TRANS_GO_CALL-46] + _ = x[TRANS_IF_INIT-47] + _ = x[TRANS_IF_COND-48] + _ = x[TRANS_IF_BODY-49] + _ = x[TRANS_IF_ELSE-50] + _ = x[TRANS_IF_CASE_BODY-51] + _ = x[TRANS_INCDEC_X-52] + _ = x[TRANS_RANGE_X-53] + _ = x[TRANS_RANGE_KEY-54] + _ = x[TRANS_RANGE_VALUE-55] + _ = x[TRANS_RANGE_BODY-56] + _ = x[TRANS_RETURN_RESULT-57] + _ = x[TRANS_PANIC_EXCEPTION-58] + _ = x[TRANS_SELECT_CASE-59] + _ = x[TRANS_SELECTCASE_COMM-60] + _ = x[TRANS_SELECTCASE_BODY-61] + _ = x[TRANS_SEND_CHAN-62] + _ = x[TRANS_SEND_VALUE-63] + _ = x[TRANS_SWITCH_INIT-64] + _ = x[TRANS_SWITCH_X-65] + _ = x[TRANS_SWITCH_CASE-66] + _ = x[TRANS_SWITCHCASE_CASE-67] + _ = x[TRANS_SWITCHCASE_BODY-68] + _ = x[TRANS_FUNC_RECV-69] + _ = x[TRANS_FUNC_TYPE-70] + _ = x[TRANS_FUNC_BODY-71] + _ = x[TRANS_IMPORT_PATH-72] + _ = x[TRANS_CONST_TYPE-73] + _ = x[TRANS_CONST_VALUE-74] + _ = x[TRANS_VAR_NAME-75] + _ = x[TRANS_VAR_TYPE-76] + _ = x[TRANS_VAR_VALUE-77] + _ = x[TRANS_TYPE_TYPE-78] + _ = x[TRANS_FILE_BODY-79] } -const _TransField_name = "TRANS_ROOTTRANS_BINARY_LEFTTRANS_BINARY_RIGHTTRANS_CALL_FUNCTRANS_CALL_ARGTRANS_INDEX_XTRANS_INDEX_INDEXTRANS_SELECTOR_XTRANS_SLICE_XTRANS_SLICE_LOWTRANS_SLICE_HIGHTRANS_SLICE_MAXTRANS_STAR_XTRANS_REF_XTRANS_TYPEASSERT_XTRANS_TYPEASSERT_TYPETRANS_UNARY_XTRANS_COMPOSITE_TYPETRANS_COMPOSITE_KEYTRANS_COMPOSITE_VALUETRANS_FUNCLIT_TYPETRANS_FUNCLIT_HEAP_CAPTURETRANS_FUNCLIT_BODYTRANS_FIELDTYPE_TYPETRANS_FIELDTYPE_TAGTRANS_ARRAYTYPE_LENTRANS_ARRAYTYPE_ELTTRANS_SLICETYPE_ELTTRANS_INTERFACETYPE_METHODTRANS_CHANTYPE_VALUETRANS_FUNCTYPE_PARAMTRANS_FUNCTYPE_RESULTTRANS_MAPTYPE_KEYTRANS_MAPTYPE_VALUETRANS_STRUCTTYPE_FIELDTRANS_ASSIGN_LHSTRANS_ASSIGN_RHSTRANS_BLOCK_BODYTRANS_DECL_BODYTRANS_DEFER_CALLTRANS_EXPR_XTRANS_FOR_INITTRANS_FOR_CONDTRANS_FOR_POSTTRANS_FOR_BODYTRANS_GO_CALLTRANS_IF_INITTRANS_IF_CONDTRANS_IF_BODYTRANS_IF_ELSETRANS_IF_CASE_BODYTRANS_INCDEC_XTRANS_RANGE_XTRANS_RANGE_KEYTRANS_RANGE_VALUETRANS_RANGE_BODYTRANS_RETURN_RESULTTRANS_PANIC_EXCEPTIONTRANS_SELECT_CASETRANS_SELECTCASE_COMMTRANS_SELECTCASE_BODYTRANS_SEND_CHANTRANS_SEND_VALUETRANS_SWITCH_INITTRANS_SWITCH_XTRANS_SWITCH_CASETRANS_SWITCHCASE_CASETRANS_SWITCHCASE_BODYTRANS_FUNC_RECVTRANS_FUNC_TYPETRANS_FUNC_BODYTRANS_IMPORT_PATHTRANS_CONST_TYPETRANS_CONST_VALUETRANS_VAR_NAMETRANS_VAR_TYPETRANS_VAR_VALUETRANS_TYPE_TYPETRANS_FILE_BODY" +const _TransField_name = "TRANS_ROOTTRANS_BINARY_LEFTTRANS_BINARY_RIGHTTRANS_CALL_FUNCTRANS_CALL_ARGTRANS_INDEX_XTRANS_INDEX_INDEXTRANS_SELECTOR_XTRANS_SLICE_XTRANS_SLICE_LOWTRANS_SLICE_HIGHTRANS_SLICE_MAXTRANS_STAR_XTRANS_REF_XTRANS_TYPEASSERT_XTRANS_TYPEASSERT_TYPETRANS_UNARY_XTRANS_COMPOSITE_TYPETRANS_COMPOSITE_KEYTRANS_COMPOSITE_VALUETRANS_FUNCLIT_TYPETRANS_FUNCLIT_HEAP_CAPTURETRANS_FUNCLIT_BODYTRANS_FIELDTYPE_NAMETRANS_FIELDTYPE_TYPETRANS_FIELDTYPE_TAGTRANS_ARRAYTYPE_LENTRANS_ARRAYTYPE_ELTTRANS_SLICETYPE_ELTTRANS_INTERFACETYPE_METHODTRANS_CHANTYPE_VALUETRANS_FUNCTYPE_PARAMTRANS_FUNCTYPE_RESULTTRANS_MAPTYPE_KEYTRANS_MAPTYPE_VALUETRANS_STRUCTTYPE_FIELDTRANS_ASSIGN_LHSTRANS_ASSIGN_RHSTRANS_BLOCK_BODYTRANS_DECL_BODYTRANS_DEFER_CALLTRANS_EXPR_XTRANS_FOR_INITTRANS_FOR_CONDTRANS_FOR_POSTTRANS_FOR_BODYTRANS_GO_CALLTRANS_IF_INITTRANS_IF_CONDTRANS_IF_BODYTRANS_IF_ELSETRANS_IF_CASE_BODYTRANS_INCDEC_XTRANS_RANGE_XTRANS_RANGE_KEYTRANS_RANGE_VALUETRANS_RANGE_BODYTRANS_RETURN_RESULTTRANS_PANIC_EXCEPTIONTRANS_SELECT_CASETRANS_SELECTCASE_COMMTRANS_SELECTCASE_BODYTRANS_SEND_CHANTRANS_SEND_VALUETRANS_SWITCH_INITTRANS_SWITCH_XTRANS_SWITCH_CASETRANS_SWITCHCASE_CASETRANS_SWITCHCASE_BODYTRANS_FUNC_RECVTRANS_FUNC_TYPETRANS_FUNC_BODYTRANS_IMPORT_PATHTRANS_CONST_TYPETRANS_CONST_VALUETRANS_VAR_NAMETRANS_VAR_TYPETRANS_VAR_VALUETRANS_TYPE_TYPETRANS_FILE_BODY" -var _TransField_index = [...]uint16{0, 10, 27, 45, 60, 74, 87, 104, 120, 133, 148, 164, 179, 191, 202, 220, 241, 254, 274, 293, 314, 332, 358, 376, 396, 415, 434, 453, 472, 498, 518, 538, 559, 576, 595, 617, 633, 649, 665, 680, 696, 708, 722, 736, 750, 764, 777, 790, 803, 816, 829, 847, 861, 874, 889, 906, 922, 941, 962, 979, 1000, 1021, 1036, 1052, 1069, 1083, 1100, 1121, 1142, 1157, 1172, 1187, 1204, 1220, 1237, 1251, 1265, 1280, 1295, 1310} +var _TransField_index = [...]uint16{0, 10, 27, 45, 60, 74, 87, 104, 120, 133, 148, 164, 179, 191, 202, 220, 241, 254, 274, 293, 314, 332, 358, 376, 396, 416, 435, 454, 473, 492, 518, 538, 558, 579, 596, 615, 637, 653, 669, 685, 700, 716, 728, 742, 756, 770, 784, 797, 810, 823, 836, 849, 867, 881, 894, 909, 926, 942, 961, 982, 999, 1020, 1041, 1056, 1072, 1089, 1103, 1120, 1141, 1162, 1177, 1192, 1207, 1224, 1240, 1257, 1271, 1285, 1300, 1315, 1330} func (i TransField) String() string { if i >= TransField(len(_TransField_index)-1) { diff --git a/gnovm/pkg/gnolang/transcribe.go b/gnovm/pkg/gnolang/transcribe.go index d14013b34de..565a7f8b3e8 100644 --- a/gnovm/pkg/gnolang/transcribe.go +++ b/gnovm/pkg/gnolang/transcribe.go @@ -48,6 +48,7 @@ const ( TRANS_FUNCLIT_TYPE TRANS_FUNCLIT_HEAP_CAPTURE TRANS_FUNCLIT_BODY + TRANS_FIELDTYPE_NAME TRANS_FIELDTYPE_TYPE TRANS_FIELDTYPE_TAG TRANS_ARRAYTYPE_LEN @@ -278,6 +279,9 @@ func transcribe(t Transform, ns []Node, ftype TransField, index int, n Node, nc } } case *FieldTypeExpr: + /* XXX make this an option. these are not normal names. + cnn.NameExpr = *(transcribe(t, nns, TRANS_FIELDTYPE_NAME, 0, &cnn.NameExpr, &c).(*NameExpr)) + */ cnn.Type = transcribe(t, nns, TRANS_FIELDTYPE_TYPE, 0, cnn.Type, &c).(Expr) if isStopOrSkip(nc, c) { return diff --git a/gnovm/pkg/gnolang/types.go b/gnovm/pkg/gnolang/types.go index 4c28fa519cd..2f588733116 100644 --- a/gnovm/pkg/gnolang/types.go +++ b/gnovm/pkg/gnolang/types.go @@ -23,7 +23,8 @@ type Type interface { String() string // for dev/debugging Elem() Type // for TODO... types GetPkgPath() string - IsNamed() bool // named vs unname type. property as a method + IsNamed() bool // named vs unname type. property as a method + IsImmutable() bool // immutable types } type TypeID string @@ -79,6 +80,25 @@ func (heapItemType) assertType() {} func (*tupleType) assertType() {} func (RefType) assertType() {} +// IsImmutable +func (PrimitiveType) IsImmutable() bool { return true } +func (*PointerType) IsImmutable() bool { return false } +func (FieldType) IsImmutable() bool { panic("should not happen") } +func (*ArrayType) IsImmutable() bool { return false } +func (*SliceType) IsImmutable() bool { return false } +func (*StructType) IsImmutable() bool { return false } +func (*FuncType) IsImmutable() bool { return true } +func (*MapType) IsImmutable() bool { return false } +func (*InterfaceType) IsImmutable() bool { return false } // preprocessor only +func (*TypeType) IsImmutable() bool { return true } +func (dt *DeclaredType) IsImmutable() bool { return dt.Base.IsImmutable() } +func (*PackageType) IsImmutable() bool { return false } +func (*ChanType) IsImmutable() bool { return true } +func (blockType) IsImmutable() bool { return false } +func (heapItemType) IsImmutable() bool { return false } +func (*tupleType) IsImmutable() bool { panic("should not happen") } +func (RefType) IsImmutable() bool { panic("should not happen") } + // ---------------------------------------- // Primitive types @@ -860,10 +880,6 @@ func (pt *PackageType) Kind() Kind { func (pt *PackageType) TypeID() TypeID { if pt.typeid.IsZero() { - // NOTE Different package types may have the same - // TypeID if and only if neither have unexported fields. - // pt.Path is only included in field names that are not - // uppercase. pt.typeid = typeid("package{}") } return pt.typeid @@ -1657,10 +1673,10 @@ func (dt *DeclaredType) GetValueAt(alloc *Allocator, store Store, path ValuePath case VPValMethod, VPPtrMethod, VPField: if path.Depth == 0 { mtv := dt.Methods[path.Index] - // Fill in *FV.Closure. + // Fill in *FV.Parent. ft := mtv.T fv := mtv.V.(*FuncValue).Copy(alloc) - fv.Closure = fv.GetClosure(store) + fv.Parent = fv.GetParent(store) return TypedValue{T: ft, V: fv} } else { panic("DeclaredType.GetValueAt() expects depth == 0") @@ -1672,7 +1688,7 @@ func (dt *DeclaredType) GetValueAt(alloc *Allocator, store Store, path ValuePath } } -// Like GetValueAt, but doesn't fill *FuncValue closures. +// Like GetValueAt, but doesn't fill *FuncValue parent blocks. func (dt *DeclaredType) GetStaticValueAt(path ValuePath) TypedValue { switch path.Type { case VPInterface: diff --git a/gnovm/pkg/gnolang/uverse.go b/gnovm/pkg/gnolang/uverse.go index ce6260fffcf..cd286d512d8 100644 --- a/gnovm/pkg/gnolang/uverse.go +++ b/gnovm/pkg/gnolang/uverse.go @@ -1,5 +1,7 @@ package gnolang +// XXX append and delete need checks too. + import ( "bytes" "fmt" @@ -690,12 +692,9 @@ func makeUverseNode() { func(m *Machine) { arg0 := m.LastBlock().GetParams1() tt := arg0.TV.GetType() - vv := defaultValue(m.Alloc, tt) + tv := defaultTypedValue(m.Alloc, tt) m.Alloc.AllocatePointer() - hi := m.Alloc.NewHeapItem(TypedValue{ - T: tt, - V: vv, - }) + hi := m.Alloc.NewHeapItem(tv) m.PushValue(TypedValue{ T: m.Alloc.NewType(&PointerType{ Elt: tt, @@ -745,6 +744,65 @@ func makeUverseNode() { } }, ) + defNative("crossing", + nil, // params + nil, // results + func(m *Machine) { + stmt := m.PeekStmt(1) + bs, ok := stmt.(*bodyStmt) + if !ok { + panic("unexpected origin of crossing call") + } + if bs.NextBodyIndex != 1 { + panic("crossing call must be the first call of a function or method") + } + fr1 := m.PeekCallFrame(1) // fr1.LastPackage created fr. + if !fr1.LastPackage.IsRealm() { + panic("crossing call only allowed in realm packages") // XXX test + } + // Verify prior fr.WithCross or fr.DidCross. + // NOTE: fr.WithCross may or may not be true, + // switcherealm() (which sets fr.DidCross) can be + // stacked. + for i := 1 + 1; ; i++ { + fri := m.PeekCallFrame(i) + if fri == nil { + panic("crossing could not find corresponding cross(fn)(...) call") + } + if fri.WithCross || fri.DidCross { + // NOTE: fri.DidCross implies + // everything under it is also valid. + // fri.DidCross && !fri.WithCross + // can happen with an implicit switch. + fr2 := m.PeekCallFrame(2) + fr2.SetDidCross() + return + } + // Neither fri.WithCross nor fri.DidCross, yet + // Realm already switched implicitly. + if fri.LastRealm != m.Realm { + panic("crossing could not find corresponding cross(fn)(...) call") + } + } + panic("should not happen") // defensive + }, + ) + defNative("cross", + Flds( // param + "x", GenT("X", nil), + ), + Flds( // results + "x", GenT("X", nil), + ), + func(m *Machine) { + // This is handled by op_call instead. + panic("cross is a virtual function") + /* + arg0 := m.LastBlock().GetParams1() + m.PushValue(arg0.Deref()) + */ + }, + ) uverseValue = uverseNode.NewPackage() } diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index d60c074316b..3c1c872ca5d 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -1,12 +1,13 @@ package gnolang +// XXX TODO address "this is wrong, for var i interface{}; &i is *interface{}." + import ( "encoding/binary" "fmt" "math/big" "reflect" "strconv" - "strings" "unsafe" "github.com/cockroachdb/apd/v3" @@ -64,8 +65,8 @@ var ( _ Value = BigdecValue{} _ Value = DataByteValue{} _ Value = PointerValue{} - _ Value = &ArrayValue{} // TODO doesn't have to be pointer? - _ Value = &SliceValue{} // TODO doesn't have to be pointer? + _ Value = &ArrayValue{} + _ Value = &SliceValue{} _ Value = &StructValue{} _ Value = &FuncValue{} _ Value = &MapValue{} @@ -165,34 +166,26 @@ func (dbv DataByteValue) SetByte(b byte) { // ---------------------------------------- // PointerValue -// Base is set if the pointer refers to an array index or -// struct field or block var. -// A pointer constructed via a &x{} composite lit -// expression or constructed via new() or make() are -// independent objects, and have nil Base. -// A pointer to a block var may end up pointing to an escape -// value after a block var escapes "to the heap". -// *(PointerValue.TypedValue) must have already become -// initialized, namely T set if a typed-nil. -// Index is -1 for the shared "_" block var, -// and -2 for (gno and native) map items. +// *(PointerValue.TypedValue) must have already become initialized, namely T +// set if a typed-nil. Index is -1 for the shared "_" block var, and -2 for +// (gno and native) map items. // // A pointer constructed via a &x{} composite lit expression or constructed via // new() or make() will have a virtual HeapItemValue as base. // -// Allocation for PointerValue is not immediate, -// as usually PointerValues are temporary for assignment -// or binary operations. When a pointer is to be -// allocated, *Allocator.AllocatePointer() is called separately, -// as in OpRef. +// The Base is only nil for references to certain values that cannot +// be modified anyways, such as top level functions. // -// Since PointerValue is used internally for assignment etc, -// it MUST stay minimal for computational efficiency. +// Allocation for PointerValue is not immediate, as usually PointerValues are +// temporary for assignment or binary operations. When a pointer is to be +// allocated, *Allocator.AllocatePointer() is called separately, as in OpRef. +// +// Since PointerValue is used internally for assignment etc, it MUST stay +// minimal for computational efficiency. type PointerValue struct { - TV *TypedValue // escape val if pointer to var. + TV *TypedValue // &Base[Index] or &Base.Index. Base Value // array/struct/block, or heapitem. Index int // list/fields/values index, or -1 or -2 (see below). - Key *TypedValue `json:",omitempty"` // for maps. } const ( @@ -226,7 +219,10 @@ func (pv PointerValue) Assign2(alloc *Allocator, store Store, rlm *Realm, tv2 Ty return } // General case - if rlm != nil && pv.Base != nil { + if rlm != nil { + if debug && pv.Base == nil { + panic("expected non-nil base for assignment") + } oo1 := pv.TV.GetFirstObject(store) pv.TV.Assign(alloc, tv2, cu) oo2 := pv.TV.GetFirstObject(store) @@ -305,7 +301,7 @@ func (av *ArrayValue) GetPointerAtIndexInt2(store Store, ii int, et Type) Pointe Index: ii, } } - bv := &TypedValue{ // heap alloc, so need to compare value rather than pointer + btv := &TypedValue{ // heap alloc, so need to compare value rather than pointer T: DataByteType, V: DataByteValue{ Base: av, @@ -315,7 +311,7 @@ func (av *ArrayValue) GetPointerAtIndexInt2(store Store, ii int, et Type) Pointe } return PointerValue{ - TV: bv, + TV: btv, Base: av, Index: ii, } @@ -478,16 +474,19 @@ func (sv *StructValue) Copy(alloc *Allocator) *StructValue { // makes construction TypedValue{T:*FuncType{},V:*FuncValue{}} // faster. type FuncValue struct { - Type Type // includes unbound receiver(s) - IsMethod bool // is an (unbound) method - Source BlockNode // for block mem allocation - Name Name // name of function/method - Closure Value // *Block or RefValue to closure (may be nil for file blocks; lazy) - Captures []TypedValue `json:",omitempty"` // HeapItemValues captured from closure. - FileName Name // file name where declared - PkgPath string - NativePkg string // for native bindings through NativeResolver - NativeName Name // not redundant with Name; this cannot be changed in userspace + ObjectInfo + Type Type // includes unbound receiver(s) + IsMethod bool // is an (unbound) method + IsClosure bool // is a func lit expr closure (not decl) + Source BlockNode // for block mem allocation + Name Name // name of function/method + Parent Value // *Block or RefValue to closure (may be nil for file blocks; lazy) + Captures []TypedValue `json:",omitempty"` // HeapItemValues captured from closure. + FileName Name // file name where declared + PkgPath string // package path in which func declared + NativePkg string // for native bindings through NativeResolver + NativeName Name // not redundant with Name; this cannot be changed in userspace + SwitchRealm bool // true if .body's first statement is crossing(). body []Stmt // function body nativeBody func(*Machine) // alternative to Body @@ -508,17 +507,18 @@ func (fv *FuncValue) IsNative() bool { func (fv *FuncValue) Copy(alloc *Allocator) *FuncValue { alloc.AllocateFunc() return &FuncValue{ - Type: fv.Type, - IsMethod: fv.IsMethod, - Source: fv.Source, - Name: fv.Name, - Closure: fv.Closure, - FileName: fv.FileName, - PkgPath: fv.PkgPath, - NativePkg: fv.NativePkg, - NativeName: fv.NativeName, - body: fv.body, - nativeBody: fv.nativeBody, + Type: fv.Type, + IsMethod: fv.IsMethod, + Source: fv.Source, + Name: fv.Name, + Parent: fv.Parent, + FileName: fv.FileName, + PkgPath: fv.PkgPath, + NativePkg: fv.NativePkg, + NativeName: fv.NativeName, + SwitchRealm: fv.SwitchRealm, + body: fv.body, + nativeBody: fv.nativeBody, } } @@ -569,11 +569,11 @@ func (fv *FuncValue) GetPackage(store Store) *PackageValue { return pv } -// NOTE: this function does not automatically memoize the closure for -// file-level declared methods and functions. For those, caller -// should set .Closure manually after *FuncValue.Copy(). -func (fv *FuncValue) GetClosure(store Store) *Block { - switch cv := fv.Closure.(type) { +func (fv *FuncValue) GetParent(store Store) *Block { + if fv.IsClosure { + return nil + } + switch cv := fv.Parent.(type) { case nil: if fv.FileName == "" { return nil @@ -583,10 +583,11 @@ func (fv *FuncValue) GetClosure(store Store) *Block { if fb == nil { panic(fmt.Sprintf("file block missing for file %q", fv.FileName)) } + fv.Parent = fb return fb case RefValue: block := store.GetObject(cv.ObjectID).(*Block) - fv.Closure = block + fv.Parent = block return block case *Block: return cv @@ -595,6 +596,10 @@ func (fv *FuncValue) GetClosure(store Store) *Block { } } +func (fv *FuncValue) IsSwitchRealm() bool { + return fv.SwitchRealm +} + // ---------------------------------------- // BoundMethodValue @@ -611,6 +616,10 @@ type BoundMethodValue struct { Receiver TypedValue } +func (bmv *BoundMethodValue) IsSwitchRealm() bool { + return bmv.Func.IsSwitchRealm() +} + // ---------------------------------------- // MapValue @@ -708,28 +717,22 @@ func (mv *MapValue) GetLength() int { return mv.List.Size // panics if uninitialized } -// NOTE: Go doesn't support referencing into maps, and maybe -// Gno will, but here we just use this method signature as we -// do for structs and arrays for assigning new entries. If key -// doesn't exist, a new slot is created. +// GetPointerForKey is only used for assignment, so the key +// is not returned as part of the pointer, and TV is not filled. func (mv *MapValue) GetPointerForKey(alloc *Allocator, store Store, key *TypedValue) PointerValue { kmk := key.ComputeMapKey(store, false) if mli, ok := mv.vmap[kmk]; ok { - key2 := key.Copy(alloc) return PointerValue{ TV: fillValueTV(store, &mli.Value), Base: mv, - Key: &key2, Index: PointerIndexMap, } } mli := mv.List.Append(alloc, *key) mv.vmap[kmk] = mli - key2 := key.Copy(alloc) return PointerValue{ TV: fillValueTV(store, &mli.Value), Base: mv, - Key: &key2, Index: PointerIndexMap, } } @@ -885,9 +888,50 @@ func (pv *PackageValue) GetPkgAddr() crypto.Address { // TypedValue (is not a value, but a tuple) type TypedValue struct { - T Type `json:",omitempty"` // never nil - V Value `json:",omitempty"` // an untyped value - N [8]byte `json:",omitempty"` // numeric bytes + T Type `json:",omitempty"` + V Value `json:",omitempty"` + N [8]byte `json:",omitempty"` +} + +// Magic 8 bytes to denote a readonly wrapped non-nil V of mutable type that is +// readonly. This happens when subvalues are retrieved from an externally +// stored realm value, such as external realm package vars, or slices or +// pointers to. +// NOTE: most of the code except copy methods do not consider N_Readonly. +// Instead the op functions should with m.IsReadonly() and tv.SetReadonly() and +// tv.WithReadonly(). +var N_Readonly [8]byte = [8]byte{'R', 'e', 'a', 'D', 'o', 'N', 'L', 'Y'} // ReaDoNLY + +// Returns true if mutable .V is readonly "wrapped". +func (tv *TypedValue) IsReadonly() bool { + return tv.N == N_Readonly && tv.V != nil +} + +// Sets tv.N to N_Readonly if ro and tv is not already immutable. If ro is +// false does nothing. See also Type.IsImmutable(). +func (tv *TypedValue) SetReadonly(ro bool) { + if tv.V == nil { + return // do nothing + } + if tv.T.IsImmutable() { + return // do nothing + } + if ro { + tv.N = N_Readonly + return + } else { + return // perserve prior tv.N + } +} + +// Convenience, makes readonly if ro is true. +func (tv TypedValue) WithReadonly(ro bool) TypedValue { + tv.SetReadonly(ro) + return tv +} + +func (tv *TypedValue) IsImmutable() bool { + return tv.T == nil || tv.T.IsImmutable() } func (tv *TypedValue) IsDefined() bool { @@ -896,22 +940,19 @@ func (tv *TypedValue) IsDefined() bool { func (tv *TypedValue) IsUndefined() bool { if debug { - if tv == nil { - panic("should not happen") - } - } - if tv.T == nil { - if debug { - if tv.V != nil || tv.N != [8]byte{} { - panic(fmt.Sprintf( - "corrupted TypeValue (nil T)")) + if tv.T == nil { + if tv.V != nil { + panic("should not happen") + } + if tv.N != [8]byte{} { + panic("should not happen") } } - return true } - return tv.IsNilInterface() + return tv.T == nil } +// (this is used mostly by the preprocessor) func (tv *TypedValue) IsNilInterface() bool { if tv.T != nil && tv.T.Kind() == InterfaceKind { if tv.V == nil { @@ -962,9 +1003,11 @@ func (tv TypedValue) Copy(alloc *Allocator) (cp TypedValue) { case *ArrayValue: cp.T = tv.T cp.V = cv.Copy(alloc) + cp.N = tv.N // preserve N_Readonly case *StructValue: cp.T = tv.T cp.V = cv.Copy(alloc) + cp.N = tv.N // preserve N_Readonly default: cp = tv } @@ -976,15 +1019,13 @@ func (tv TypedValue) Copy(alloc *Allocator) (cp TypedValue) { func (tv TypedValue) unrefCopy(alloc *Allocator, store Store) (cp TypedValue) { switch tv.V.(type) { case RefValue: - cp.T = tv.T + cp = tv // preserve N_Readonly refObject := tv.GetFirstObject(store) switch refObjectValue := refObject.(type) { case *ArrayValue: cp.V = refObjectValue.Copy(alloc) case *StructValue: cp.V = refObjectValue.Copy(alloc) - default: - cp = tv } default: cp = tv.Copy(alloc) @@ -1561,6 +1602,32 @@ func (tv *TypedValue) Assign(alloc *Allocator, tv2 TypedValue, cu bool) { } } +// Define to a block slot that takes into account heap escapes. +// (only blocks can contain heap items). +// This should only be used when both the base parent and the value are unreal +// new values, or call rlm.DidUpdate manually. +func (tv *TypedValue) AssignToBlock(other TypedValue) { + if _, ok := tv.T.(heapItemType); ok { + tv.V.(*HeapItemValue).Value = other + } else { + *tv = other + } +} + +// Like AssignToBlock but creates a new heap item instead. +// This should only be used when both the base parent and the value are unreal +// new values, or call rlm.DidUpdate manually. +func (tv *TypedValue) DefineToBlock(other TypedValue) { + if _, ok := tv.T.(heapItemType); ok { + *tv = TypedValue{ + T: heapItemType{}, + V: &HeapItemValue{Value: other}, + } + } else { + *tv = other + } +} + // NOTE: Allocation for PointerValue is not immediate, // as usually PointerValues are temporary for assignment // or binary operations. When a pointer is to be @@ -1649,7 +1716,7 @@ func (tv *TypedValue) GetPointerToFromTV(alloc *Allocator, store Store, path Val path.Type = VPValMethod case VPDerefPtrMethod: // dtv = tv.V.(PointerValue).TV - // dtv not needed for nil receivers. + // dtv not used due to possible nil receivers. isPtr = true path.Type = VPPtrMethod // XXX pseudo case VPDerefInterface: @@ -1724,6 +1791,12 @@ func (tv *TypedValue) GetPointerToFromTV(alloc *Allocator, store Store, path Val } } dtv2 := dtv.Copy(alloc) + if dtv2.V != nil { + // Clear readonly for receivers. + // Other rules still apply such as in DidUpdate. + // NOTE: dtv2 is a copy, orig is untouched. + dtv2.N = [8]byte{} + } alloc.AllocateBoundMethod() bmv := &BoundMethodValue{ Func: mv, @@ -1754,10 +1827,17 @@ func (tv *TypedValue) GetPointerToFromTV(alloc *Allocator, store Store, path Val panic("should not happen") } } + ptv := *tv + if ptv.V != nil { + // Clear readonly for receivers. + // Other rules still apply such as in DidUpdate. + // NOTE: ptv is a copy, orig is untouched. + ptv.N = [8]byte{} + } alloc.AllocateBoundMethod() bmv := &BoundMethodValue{ Func: mv, - Receiver: *tv, // bound to ptr, not dtv. + Receiver: ptv, // bound to tv ptr, not dtv. } return PointerValue{ TV: &TypedValue{ @@ -1776,13 +1856,13 @@ func (tv *TypedValue) GetPointerToFromTV(alloc *Allocator, store Store, path Val panic(fmt.Sprintf("method %s not found in type %s", path.Name, dtv.T.String())) } - bv := *dtv + btv := *dtv for i, path := range tr { - ptr := bv.GetPointerToFromTV(alloc, store, path) + ptr := btv.GetPointerToFromTV(alloc, store, path) if i == len(tr)-1 { return ptr // done } - bv = ptr.Deref() // deref + btv = ptr.Deref() // deref } panic("should not happen") default: @@ -1790,7 +1870,7 @@ func (tv *TypedValue) GetPointerToFromTV(alloc *Allocator, store Store, path Val } } -// Convenience for GetPointerAtIndex(). Slow. +// Convenience for GetPointerAtIndex(). Slow. func (tv *TypedValue) GetPointerAtIndexInt(store Store, ii int) PointerValue { iv := TypedValue{T: IntType} iv.SetInt(int64(ii)) @@ -1803,7 +1883,7 @@ func (tv *TypedValue) GetPointerAtIndex(alloc *Allocator, store Store, iv *Typed if bt == StringType || bt == UntypedStringType { sv := tv.GetString() ii := int(iv.ConvertGetInt()) - bv := &TypedValue{ // heap alloc + btv := &TypedValue{ // heap alloc T: Uint8Type, } @@ -1814,9 +1894,9 @@ func (tv *TypedValue) GetPointerAtIndex(alloc *Allocator, store Store, iv *Typed panic(&Exception{Value: typedString(fmt.Sprintf("invalid slice index %d (index must be non-negative)", ii))}) } - bv.SetUint8(sv[ii]) + btv.SetUint8(sv[ii]) return PointerValue{ - TV: bv, + TV: btv, Base: nil, // free floating } } @@ -2003,6 +2083,7 @@ func (tv *TypedValue) GetSlice(alloc *Allocator, low, high int) TypedValue { ), } case *SliceType: + // XXX consider restricting slice expansion if slice is readonly. if tv.GetCapacity() < high { panic(&Exception{Value: typedString(fmt.Sprintf( "slice bounds out of range [%d:%d] with capacity %d", @@ -2087,6 +2168,7 @@ func (tv *TypedValue) GetSlice2(alloc *Allocator, lowVal, highVal, maxVal int) T ), } case *SliceType: + // XXX consider restricting slice expansion if slice is readonly. if tv.V == nil { if lowVal != 0 || highVal != 0 || maxVal != 0 { panic("nil slice index out of range") @@ -2123,21 +2205,23 @@ func (tv *TypedValue) DeepFill(store Store) { // ---------------------------------------- // Block // -// Blocks hold values referred to by var/const/func/type -// declarations in BlockNodes such as packages, functions, -// and switch statements. Unlike structs or packages, -// names and paths may refer to parent blocks. (In the -// future, the same mechanism may be used to support -// inheritance or prototype-like functionality for structs -// and packages.) +// Blocks hold values referred to by var/const/func/type declarations in +// BlockNodes such as packages, functions, and switch statements. Unlike +// structs or packages, names and paths may refer to parent blocks. (In the +// future, the same mechanism may be used to support inheritance or +// prototype-like functionality for structs and packages.) // -// When a block would otherwise become gc'd because it is no -// longer used except for escaped reference pointers to -// variables, and there are no closures that reference the -// block, the remaining references to objects become detached -// from the block and become ownerless. - -// TODO rename to BlockValue. +// When a block would otherwise become gc'd because it is no longer used, the +// block is forgotten and GC'd. +// +// Variables declared in a closure or passed by reference are first discovered +// and marked as such from the preprocessor, and NewBlock() will prepopulate +// these slots with *HeapItemValues. When a *HeapItemValue (or sometimes +// HeapItemType in .T) is present in a block slot it is not written over but +// instead the value is written into the heap item's slot--except for loopvars +// assignments which may replace the heap item with another one. This is +// how Gno supports Go1.22 loopvars. +// TODO XXX rename to BlockValue type Block struct { ObjectInfo Source BlockNode @@ -2148,10 +2232,20 @@ type Block struct { } // NOTE: for allocation, use *Allocator.NewBlock. +// XXX pass allocator in for heap items. func NewBlock(source BlockNode, parent *Block) *Block { - var values []TypedValue - if source != nil { - values = make([]TypedValue, source.GetNumNames()) + numNames := source.GetNumNames() + values := make([]TypedValue, numNames) + // Keep in sync with ExpandWith(). + for i, isHeap := range source.GetHeapItems() { + if !isHeap { + continue + } + // indicates must always be heap item. + values[i] = TypedValue{ + T: heapItemType{}, + V: &HeapItemValue{}, + } } return &Block{ Source: source, @@ -2160,39 +2254,6 @@ func NewBlock(source BlockNode, parent *Block) *Block { } } -func (b *Block) String() string { - return b.StringIndented(" ") -} - -func (b *Block) StringIndented(indent string) string { - source := toString(b.Source) - if len(source) > 32 { - source = source[:32] + "..." - } - lines := make([]string, 0, 3) - lines = append(lines, - fmt.Sprintf("Block(ID:%v,Addr:%p,Source:%s,Parent:%p)", - b.ObjectInfo.ID, b, source, b.Parent)) // XXX Parent may be RefValue{}. - if b.Source != nil { - if _, ok := b.Source.(RefNode); ok { - lines = append(lines, - fmt.Sprintf("%s(RefNode names not shown)", indent)) - } else { - for i, n := range b.Source.GetBlockNames() { - if len(b.Values) <= i { - lines = append(lines, - fmt.Sprintf("%s%s: undefined", indent, n)) - } else { - lines = append(lines, - fmt.Sprintf("%s%s: %s", - indent, n, b.Values[i].String())) - } - } - } - } - return strings.Join(lines, "\n") -} - func (b *Block) GetSource(store Store) BlockNode { if rn, ok := b.Source.(RefNode); ok { source := store.GetBlockNode(rn.GetLocation()) @@ -2218,6 +2279,24 @@ func (b *Block) GetParent(store Store) *Block { } func (b *Block) GetPointerToInt(store Store, index int) PointerValue { + vv := fillValueTV(store, &b.Values[index]) + if hiv, ok := vv.V.(*HeapItemValue); ok { + fillValueTV(store, &hiv.Value) + return PointerValue{ + TV: &hiv.Value, + Base: vv.V, + Index: 0, + } + } else { + return PointerValue{ + TV: vv, + Base: b, + Index: index, + } + } +} + +func (b *Block) GetPointerToIntDirect(store Store, index int) PointerValue { vv := fillValueTV(store, &b.Values[index]) return PointerValue{ TV: vv, @@ -2251,70 +2330,65 @@ func (b *Block) GetPointerTo(store Store, path ValuePath) PointerValue { return b.GetPointerToInt(store, int(path.Index)) } -// Convenience -func (b *Block) GetPointerToMaybeHeapUse(store Store, nx *NameExpr) PointerValue { - switch nx.Type { - case NameExprTypeNormal: - return b.GetPointerTo(store, nx.Path) - case NameExprTypeHeapUse: - return b.GetPointerToHeapUse(store, nx.Path) - case NameExprTypeHeapClosure: - panic("should not happen with type heap closure") - default: - panic("unexpected NameExpr type for GetPointerToMaybeHeapUse") +func (b *Block) GetPointerToDirect(store Store, path ValuePath) PointerValue { + if path.IsBlockBlankPath() { + if debug { + if path.Name != blankIdentifier { + panic(fmt.Sprintf( + "zero value path is reserved for \"_\", but got %s", + path.Name)) + } + } + return PointerValue{ + TV: b.GetBlankRef(), + Base: b, + Index: PointerIndexBlockBlank, // -1 + } + } + // NOTE: For most block paths, Depth starts at 1, but + // the generation for uverse is 0. If path.Depth is + // 0, it implies that b == uverse, and the condition + // would fail as if it were 1. + for i := uint8(1); i < path.Depth; i++ { + b = b.GetParent(store) } + return b.GetPointerToIntDirect(store, int(path.Index)) } -// Convenience +// First defines a new HeapItemValue if heap slot. func (b *Block) GetPointerToMaybeHeapDefine(store Store, nx *NameExpr) PointerValue { switch nx.Type { case NameExprTypeNormal: + // XXX convert rangestmt switchstmt names + // into NameExpr and then panic here instead. return b.GetPointerTo(store, nx.Path) case NameExprTypeDefine: return b.GetPointerTo(store, nx.Path) case NameExprTypeHeapDefine: - return b.GetPointerToHeapDefine(store, nx.Path) + path := nx.Path + ptr := b.GetPointerToDirect(store, path) + if _, ok := ptr.TV.T.(heapItemType); ok { + if nx.Type != NameExprTypeHeapDefine { + panic("expected name expr heap define type") + } + hiv := &HeapItemValue{} + *ptr.TV = TypedValue{ + T: heapItemType{}, + V: hiv, + } + return PointerValue{ + TV: &hiv.Value, + Base: hiv, + Index: 0, + } + } else { + return ptr + } default: panic("unexpected NameExpr type for GetPointerToMaybeHeapDefine") } } -// First defines a new HeapItemValue. -// This gets called from NameExprTypeHeapDefine name expressions. -func (b *Block) GetPointerToHeapDefine(store Store, path ValuePath) PointerValue { - ptr := b.GetPointerTo(store, path) - hiv := &HeapItemValue{} - // point to a heapItem - *ptr.TV = TypedValue{ - T: heapItemType{}, - V: hiv, - } - - return PointerValue{ - TV: &hiv.Value, - Base: hiv, - Index: 0, - } -} - -// Assumes a HeapItemValue, and gets inner pointer. -// This gets called from NameExprTypeHeapUse name expressions. -func (b *Block) GetPointerToHeapUse(store Store, path ValuePath) PointerValue { - ptr := b.GetPointerTo(store, path) - if _, ok := ptr.TV.T.(heapItemType); !ok { - panic("should not happen, should be heapItemType") - } - if _, ok := ptr.TV.V.(*HeapItemValue); !ok { - panic("should not happen, should be HeapItemValue") - } - - return PointerValue{ - TV: &ptr.TV.V.(*HeapItemValue).Value, - Base: ptr.TV.V, - Index: 0, - } -} - // Result is used has lhs for any assignments to "_". func (b *Block) GetBlankRef() *TypedValue { return &b.Blank @@ -2345,18 +2419,44 @@ func (b *Block) GetBodyStmt() *bodyStmt { return &b.bodyStmt } -// Used by SwitchStmt upon clause match. -func (b *Block) ExpandToSize(alloc *Allocator, size uint16) { +// Used by faux blocks like IfCond and SwitchStmt upon clause match. +func (b *Block) ExpandWith(alloc *Allocator, source BlockNode) { + // XXX make more efficient by only storing new names in source. + numNames := source.GetNumNames() + if len(b.Values) > int(numNames) { + panic(fmt.Sprintf( + "unexpected block size shrinkage: %v vs %v", + len(b.Values), numNames)) + } if debug { - if len(b.Values) >= int(size) { + if len(b.Values) >= int(numNames) { panic(fmt.Sprintf( "unexpected block size shrinkage: %v vs %v", - len(b.Values), size)) + len(b.Values), numNames)) } } - alloc.AllocateBlockItems(int64(size) - int64(len(b.Values))) - values := make([]TypedValue, int(size)) + if int(numNames) == len(b.Values) { + return // nothing to do + } + alloc.AllocateBlockItems(int64(numNames) - int64(len(b.Values))) + values := make([]TypedValue, numNames) copy(values, b.Values) + // NOTE this is a bit confusing because of the faux offset. + // The heap item values are always false for the old names. + // Keep in sync with NewBlock(). + // XXX pass allocator in for heap items. + heapItems := source.GetHeapItems() + for i := len(b.Values); i < int(numNames); i++ { + isHeap := heapItems[i] + if !isHeap { + continue + } + // indicates must always be heap item. + values[i] = TypedValue{ + T: heapItemType{}, + V: &HeapItemValue{}, + } + } b.Values = values } @@ -2368,6 +2468,10 @@ type RefValue struct { Hash ValueHash `json:",omitempty"` } +func (ref RefValue) GetObjectID() ObjectID { + return ref.ObjectID +} + // Base for a detached singleton (e.g. new(int) or &struct{}) // Conceptually like a Block that holds one value. // NOTE: could be renamed to HeapItemBaseValue. @@ -2383,8 +2487,7 @@ func defaultStructFields(alloc *Allocator, st *StructType) []TypedValue { tvs := alloc.NewStructFields(len(st.Fields)) for i, ft := range st.Fields { if ft.Type.Kind() != InterfaceKind { - tvs[i].T = ft.Type - tvs[i].V = defaultValue(alloc, ft.Type) + tvs[i] = defaultTypedValue(alloc, ft.Type) } } return tvs @@ -2404,37 +2507,43 @@ func defaultArrayValue(alloc *Allocator, at *ArrayType) *ArrayValue { tvs := av.List if et := at.Elem(); et.Kind() != InterfaceKind { for i := 0; i < at.Len; i++ { - tvs[i].T = et - tvs[i].V = defaultValue(alloc, et) + tvs[i] = defaultTypedValue(alloc, et) } } return av } -func defaultValue(alloc *Allocator, t Type) Value { +func defaultTypedValue(alloc *Allocator, t Type) TypedValue { switch ct := baseOf(t).(type) { case nil: panic("unexpected nil type") + case *InterfaceType: + return TypedValue{} case *ArrayType: - return defaultArrayValue(alloc, ct) + return TypedValue{ + T: t, + V: defaultArrayValue(alloc, ct), + } case *StructType: - return defaultStructValue(alloc, ct) + return TypedValue{ + T: t, + V: defaultStructValue(alloc, ct), + } case *SliceType: - return nil + return TypedValue{ + T: t, + V: nil, + } case *MapType: - return nil + return TypedValue{ + T: t, + V: nil, + } default: - return nil - } -} - -func defaultTypedValue(alloc *Allocator, t Type) TypedValue { - if t.Kind() == InterfaceKind { - return TypedValue{} - } - return TypedValue{ - T: t, - V: defaultValue(alloc, t), + return TypedValue{ + T: t, + V: nil, + } } } @@ -2463,8 +2572,11 @@ func typedString(s string) TypedValue { return tv } +// returns the same tv instance for convenience. func fillValueTV(store Store, tv *TypedValue) *TypedValue { switch cv := tv.V.(type) { + case *HeapItemValue: + fillValueTV(store, &cv.Value) case RefValue: if cv.PkgPath != "" { // load package tv.V = store.GetPackage(cv.PkgPath, false) @@ -2475,6 +2587,7 @@ func fillValueTV(store Store, tv *TypedValue) *TypedValue { case PointerValue: // As a special case, cv.Base is filled // and cv.TV set appropriately. + // XXX but why, isn't lazy better? // Alternatively, could implement // `PointerValue.Deref(store) *TypedValue`, // but for execution speed traded off for diff --git a/gnovm/pkg/gnolang/values_conversions.go b/gnovm/pkg/gnolang/values_conversions.go index 75a66bf7a6e..d784bb9f514 100644 --- a/gnovm/pkg/gnolang/values_conversions.go +++ b/gnovm/pkg/gnolang/values_conversions.go @@ -30,9 +30,6 @@ func ConvertTo(alloc *Allocator, store Store, tv *TypedValue, t Type, isConst bo } // special case for interface target if t.Kind() == InterfaceKind { - if tv.IsUndefined() && tv.T == nil { - tv.T = t - } return } // special case for undefined/nil source diff --git a/gnovm/pkg/gnolang/values_fill.go b/gnovm/pkg/gnolang/values_fill.go index fc3e01a3092..de911d2d6c6 100644 --- a/gnovm/pkg/gnolang/values_fill.go +++ b/gnovm/pkg/gnolang/values_fill.go @@ -18,10 +18,6 @@ func (dbv DataByteValue) DeepFill(store Store) Value { } func (pv PointerValue) DeepFill(store Store) Value { - if pv.Key != nil { - // only used transiently for assignment! - panic("should not happen") - } // No need to fill pv.TV.V because // either it will be filled with .Base, // or, it was never persisted anyways. @@ -30,7 +26,6 @@ func (pv PointerValue) DeepFill(store Store) Value { TV: pv.TV, Base: pv.Base.DeepFill(store), Index: pv.Index, - Key: nil, } } return pv diff --git a/gnovm/pkg/gnolang/values_string.go b/gnovm/pkg/gnolang/values_string.go index e64b5f05845..68b9621d8d4 100644 --- a/gnovm/pkg/gnolang/values_string.go +++ b/gnovm/pkg/gnolang/values_string.go @@ -256,6 +256,40 @@ func (pv *PackageValue) String() string { return fmt.Sprintf("package(%s %s)", pv.PkgName, pv.PkgPath) } +func (b *Block) String() string { + return b.StringIndented(" ") +} + +func (b *Block) StringIndented(indent string) string { + source := toString(b.Source) + if len(source) > 32 { + source = source[:32] + "..." + } + lines := make([]string, 0, 3) + lines = append(lines, + fmt.Sprintf("Block(ID:%v,Addr:%p,Source:%s,Parent:%p)", + b.ObjectInfo.ID, b, source, b.Parent)) // XXX Parent may be RefValue{}. + if b.Source != nil { + if _, ok := b.Source.(RefNode); ok { + lines = append(lines, + fmt.Sprintf("%s(RefNode names not shown)", indent)) + } else { + types := b.Source.GetStaticBlock().Types + for i, n := range b.Source.GetBlockNames() { + if len(b.Values) <= i { + lines = append(lines, + fmt.Sprintf("%s%s: undefined static:%s", indent, n, types[i])) + } else { + lines = append(lines, + fmt.Sprintf("%s%s: %s static:%s", + indent, n, b.Values[i].String(), types[i])) + } + } + } + } + return strings.Join(lines, "\n") +} + func (rv RefValue) String() string { if rv.PkgPath == "" { return fmt.Sprintf("ref(%v)", diff --git a/gnovm/pkg/test/filetest.go b/gnovm/pkg/test/filetest.go index 5ddca5162d2..c02077d3094 100644 --- a/gnovm/pkg/test/filetest.go +++ b/gnovm/pkg/test/filetest.go @@ -47,10 +47,7 @@ func (opts *TestOptions) runFiletest(filename string, source []byte) (string, er if err != nil { return "", err } - ctx := Context( - pkgPath, - coins, - ) + ctx := Context("", pkgPath, coins) maxAllocRaw := dirs.FirstDefault(DirectiveMaxAlloc, "0") maxAlloc, err := strconv.ParseInt(maxAllocRaw, 10, 64) if err != nil { @@ -240,6 +237,7 @@ func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, filename string, conte m.Store.SetBlockNode(pn) m.Store.SetCachePackage(pv) m.SetActivePackage(pv) + m.Context.(*teststd.TestExecContext).OriginCaller = DefaultCaller n := gno.MustParseFile(filename, string(content)) m.RunFiles(n) m.RunStatement(gno.S(gno.Call(gno.X("main")))) @@ -264,6 +262,12 @@ func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, filename string, conte } orig, tx := m.Store, m.Store.BeginTransaction(nil, nil, nil) m.Store = tx + + // Validate Gno syntax and type check. + if err := gno.TypeCheckMemPackageTest(memPkg, m.Store); err != nil { + return runResult{Error: err.Error()} + } + // Run decls and init functions. m.RunMemPackage(memPkg, true) // Clear store cache and reconstruct machine from committed info @@ -272,11 +276,15 @@ func (opts *TestOptions) runTest(m *gno.Machine, pkgPath, filename string, conte m.Store = orig pv2 := m.Store.GetPackage(pkgPath, false) - m.SetActivePackage(pv2) + m.SetActivePackage(pv2) // XXX should it set the realm? + m.Context.(*teststd.TestExecContext).OriginCaller = DefaultCaller gno.EnableDebug() // clear store.opslog from init function(s). m.Store.SetLogStoreOps(opslog) // resets. - m.RunStatement(gno.S(gno.Call(gno.X("main")))) + // Call main() like withrealm(main)(). + // This will switch the realm to the package. + // main() must start with crossing(). + m.RunStatement(gno.S(gno.Call(gno.Call(gno.X("cross"), gno.X("main"))))) // switch realm. } return runResult{ diff --git a/gnovm/pkg/test/imports.go b/gnovm/pkg/test/imports.go index dcf5b4d3a50..5dcaac6fa28 100644 --- a/gnovm/pkg/test/imports.go +++ b/gnovm/pkg/test/imports.go @@ -75,7 +75,7 @@ func StoreWithOptions( baseDir := filepath.Join(rootDir, "gnovm", "tests", "files", "extern", pkgPath[len(testPath):]) memPkg := gno.MustReadMemPackage(baseDir, pkgPath) send := std.Coins{} - ctx := Context(pkgPath, send) + ctx := Context("", pkgPath, send) m2 := gno.NewMachineWithOptions(gno.MachineOptions{ PkgPath: "test", Output: output, @@ -101,7 +101,7 @@ func StoreWithOptions( } send := std.Coins{} - ctx := Context(pkgPath, send) + ctx := Context("", pkgPath, send) m2 := gno.NewMachineWithOptions(gno.MachineOptions{ PkgPath: "test", Output: output, diff --git a/gnovm/pkg/test/test.go b/gnovm/pkg/test/test.go index fe87944f913..e89e660bcba 100644 --- a/gnovm/pkg/test/test.go +++ b/gnovm/pkg/test/test.go @@ -37,11 +37,12 @@ const ( ) // Context returns a TestExecContext. Usable for test purpose only. +// The caller should be empty for package initialization. // The returned context has a mock banker, params and event logger. It will give // the pkgAddr the coins in `send` by default, and only that. // The Height and Timestamp parameters are set to the [DefaultHeight] and // [DefaultTimestamp]. -func Context(pkgPath string, send std.Coins) *teststd.TestExecContext { +func Context(caller crypto.Bech32Address, pkgPath string, send std.Coins) *teststd.TestExecContext { // FIXME: create a better package to manage this, with custom constructors pkgAddr := gno.DerivePkgAddr(pkgPath) // the addr of the pkgPath called. @@ -55,7 +56,7 @@ func Context(pkgPath string, send std.Coins) *teststd.TestExecContext { ChainDomain: "gno.land", // TODO: make this configurable Height: DefaultHeight, Timestamp: DefaultTimestamp, - OriginCaller: DefaultCaller, + OriginCaller: caller, OriginPkgAddr: pkgAddr.Bech32(), OriginSend: send, OriginSendSpent: new(std.Coins), @@ -70,11 +71,12 @@ func Context(pkgPath string, send std.Coins) *teststd.TestExecContext { } // Machine is a minimal machine, set up with just the Store, Output and Context. +// It is only used for linting/preprocessing. func Machine(testStore gno.Store, output io.Writer, pkgPath string, debug bool) *gno.Machine { return gno.NewMachineWithOptions(gno.MachineOptions{ Store: testStore, Output: output, - Context: Context(pkgPath, nil), + Context: Context("", pkgPath, nil), Debug: debug, }) } @@ -337,6 +339,7 @@ func (opts *TestOptions) runTestFiles( } pv := m.Package + // Load the test files into package and save. m.RunFiles(files.Files...) for _, tf := range tests { diff --git a/gnovm/stdlibs/generated.go b/gnovm/stdlibs/generated.go index 739bb7bf702..902e6996729 100644 --- a/gnovm/stdlibs/generated.go +++ b/gnovm/stdlibs/generated.go @@ -39,12 +39,12 @@ var nativeFuncs = [...]NativeFunc{ "crypto/ed25519", "verify", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("[]byte")}, - {Name: gno.N("p1"), Type: gno.X("[]byte")}, - {Name: gno.N("p2"), Type: gno.X("[]byte")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("[]byte")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("[]byte")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("[]byte")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("bool")}, }, false, func(m *gno.Machine) { @@ -81,10 +81,10 @@ var nativeFuncs = [...]NativeFunc{ "crypto/sha256", "sum256", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("[]byte")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("[]byte")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("[32]byte")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("[32]byte")}, }, false, func(m *gno.Machine) { @@ -111,10 +111,10 @@ var nativeFuncs = [...]NativeFunc{ "math", "Float32bits", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("float32")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("float32")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("uint32")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("uint32")}, }, false, func(m *gno.Machine) { @@ -141,10 +141,10 @@ var nativeFuncs = [...]NativeFunc{ "math", "Float32frombits", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("uint32")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("uint32")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("float32")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("float32")}, }, false, func(m *gno.Machine) { @@ -171,10 +171,10 @@ var nativeFuncs = [...]NativeFunc{ "math", "Float64bits", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("float64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("float64")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("uint64")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("uint64")}, }, false, func(m *gno.Machine) { @@ -201,10 +201,10 @@ var nativeFuncs = [...]NativeFunc{ "math", "Float64frombits", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("uint64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("uint64")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("float64")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("float64")}, }, false, func(m *gno.Machine) { @@ -231,12 +231,12 @@ var nativeFuncs = [...]NativeFunc{ "std", "bankerGetCoins", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("uint8")}, - {Name: gno.N("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("uint8")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("[]string")}, - {Name: gno.N("r1"), Type: gno.X("[]int64")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("[]string")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("[]int64")}, }, true, func(m *gno.Machine) { @@ -275,11 +275,11 @@ var nativeFuncs = [...]NativeFunc{ "std", "bankerSendCoins", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("uint8")}, - {Name: gno.N("p1"), Type: gno.X("string")}, - {Name: gno.N("p2"), Type: gno.X("string")}, - {Name: gno.N("p3"), Type: gno.X("[]string")}, - {Name: gno.N("p4"), Type: gno.X("[]int64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("uint8")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p3"), Type: gno.X("[]string")}, + {NameExpr: *gno.Nx("p4"), Type: gno.X("[]int64")}, }, []gno.FieldTypeExpr{}, true, @@ -323,11 +323,11 @@ var nativeFuncs = [...]NativeFunc{ "std", "bankerTotalCoin", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("uint8")}, - {Name: gno.N("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("uint8")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("int64")}, }, true, func(m *gno.Machine) { @@ -361,10 +361,10 @@ var nativeFuncs = [...]NativeFunc{ "std", "bankerIssueCoin", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("uint8")}, - {Name: gno.N("p1"), Type: gno.X("string")}, - {Name: gno.N("p2"), Type: gno.X("string")}, - {Name: gno.N("p3"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("uint8")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p3"), Type: gno.X("int64")}, }, []gno.FieldTypeExpr{}, true, @@ -403,10 +403,10 @@ var nativeFuncs = [...]NativeFunc{ "std", "bankerRemoveCoin", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("uint8")}, - {Name: gno.N("p1"), Type: gno.X("string")}, - {Name: gno.N("p2"), Type: gno.X("string")}, - {Name: gno.N("p3"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("uint8")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p3"), Type: gno.X("int64")}, }, []gno.FieldTypeExpr{}, true, @@ -445,8 +445,8 @@ var nativeFuncs = [...]NativeFunc{ "std", "emit", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("[]string")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("[]string")}, }, []gno.FieldTypeExpr{}, true, @@ -488,7 +488,7 @@ var nativeFuncs = [...]NativeFunc{ "ChainID", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("string")}, }, true, func(m *gno.Machine) { @@ -508,7 +508,7 @@ var nativeFuncs = [...]NativeFunc{ "ChainDomain", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("string")}, }, true, func(m *gno.Machine) { @@ -528,7 +528,7 @@ var nativeFuncs = [...]NativeFunc{ "ChainHeight", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("int64")}, }, true, func(m *gno.Machine) { @@ -548,8 +548,8 @@ var nativeFuncs = [...]NativeFunc{ "originSend", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("[]string")}, - {Name: gno.N("r1"), Type: gno.X("[]int64")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("[]string")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("[]int64")}, }, true, func(m *gno.Machine) { @@ -574,7 +574,7 @@ var nativeFuncs = [...]NativeFunc{ "originCaller", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("string")}, }, true, func(m *gno.Machine) { @@ -594,7 +594,7 @@ var nativeFuncs = [...]NativeFunc{ "originPkgAddr", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("string")}, }, true, func(m *gno.Machine) { @@ -609,47 +609,15 @@ var nativeFuncs = [...]NativeFunc{ )) }, }, - { - "std", - "callerAt", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("int")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - true, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 int - rp0 = reflect.ValueOf(&p0).Elem() - ) - - tv0 := b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV - tv0.DeepFill(m.Store) - gno.Gno2GoValue(tv0, rp0) - - r0 := libs_std.X_callerAt( - m, - p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, { "std", "getRealm", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("int")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("int")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - {Name: gno.N("r1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, }, true, func(m *gno.Machine) { @@ -695,8 +663,8 @@ var nativeFuncs = [...]NativeFunc{ "std", "setParamString", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, }, []gno.FieldTypeExpr{}, true, @@ -725,8 +693,8 @@ var nativeFuncs = [...]NativeFunc{ "std", "setParamBool", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("bool")}, }, []gno.FieldTypeExpr{}, true, @@ -755,8 +723,8 @@ var nativeFuncs = [...]NativeFunc{ "std", "setParamInt64", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("int64")}, }, []gno.FieldTypeExpr{}, true, @@ -785,8 +753,8 @@ var nativeFuncs = [...]NativeFunc{ "std", "setParamUint64", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("uint64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("uint64")}, }, []gno.FieldTypeExpr{}, true, @@ -815,8 +783,8 @@ var nativeFuncs = [...]NativeFunc{ "std", "setParamBytes", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("[]byte")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("[]byte")}, }, []gno.FieldTypeExpr{}, true, @@ -845,8 +813,8 @@ var nativeFuncs = [...]NativeFunc{ "std", "setParamStrings", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("[]string")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("[]string")}, }, []gno.FieldTypeExpr{}, true, @@ -875,10 +843,10 @@ var nativeFuncs = [...]NativeFunc{ "sys/params", "setSysParamString", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("string")}, - {Name: gno.N("p2"), Type: gno.X("string")}, - {Name: gno.N("p3"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p3"), Type: gno.X("string")}, }, []gno.FieldTypeExpr{}, true, @@ -917,10 +885,10 @@ var nativeFuncs = [...]NativeFunc{ "sys/params", "setSysParamBool", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("string")}, - {Name: gno.N("p2"), Type: gno.X("string")}, - {Name: gno.N("p3"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p3"), Type: gno.X("bool")}, }, []gno.FieldTypeExpr{}, true, @@ -959,10 +927,10 @@ var nativeFuncs = [...]NativeFunc{ "sys/params", "setSysParamInt64", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("string")}, - {Name: gno.N("p2"), Type: gno.X("string")}, - {Name: gno.N("p3"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p3"), Type: gno.X("int64")}, }, []gno.FieldTypeExpr{}, true, @@ -1001,10 +969,10 @@ var nativeFuncs = [...]NativeFunc{ "sys/params", "setSysParamUint64", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("string")}, - {Name: gno.N("p2"), Type: gno.X("string")}, - {Name: gno.N("p3"), Type: gno.X("uint64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p3"), Type: gno.X("uint64")}, }, []gno.FieldTypeExpr{}, true, @@ -1043,10 +1011,10 @@ var nativeFuncs = [...]NativeFunc{ "sys/params", "setSysParamBytes", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("string")}, - {Name: gno.N("p2"), Type: gno.X("string")}, - {Name: gno.N("p3"), Type: gno.X("[]byte")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p3"), Type: gno.X("[]byte")}, }, []gno.FieldTypeExpr{}, true, @@ -1085,10 +1053,10 @@ var nativeFuncs = [...]NativeFunc{ "sys/params", "setSysParamStrings", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("string")}, - {Name: gno.N("p2"), Type: gno.X("string")}, - {Name: gno.N("p3"), Type: gno.X("[]string")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p3"), Type: gno.X("[]string")}, }, []gno.FieldTypeExpr{}, true, @@ -1128,7 +1096,7 @@ var nativeFuncs = [...]NativeFunc{ "unixNano", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("int64")}, }, false, func(m *gno.Machine) { @@ -1146,8 +1114,8 @@ var nativeFuncs = [...]NativeFunc{ "recoverWithStacktrace", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.AnyT()}, - {Name: gno.N("r1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r0"), Type: gno.AnyT()}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, }, false, func(m *gno.Machine) { @@ -1165,12 +1133,12 @@ var nativeFuncs = [...]NativeFunc{ "testing", "matchString", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("bool")}, - {Name: gno.N("r1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, }, false, func(m *gno.Machine) { @@ -1208,9 +1176,9 @@ var nativeFuncs = [...]NativeFunc{ "now", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("int64")}, - {Name: gno.N("r1"), Type: gno.X("int32")}, - {Name: gno.N("r2"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("int32")}, + {NameExpr: *gno.Nx("r2"), Type: gno.X("int64")}, }, true, func(m *gno.Machine) { @@ -1239,11 +1207,11 @@ var nativeFuncs = [...]NativeFunc{ "time", "loadFromEmbeddedTZData", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("[]byte")}, - {Name: gno.N("r1"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("[]byte")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("bool")}, }, false, func(m *gno.Machine) { diff --git a/gnovm/stdlibs/std/emit_event.go b/gnovm/stdlibs/std/emit_event.go index 6e8f00ee3e8..f12d4081835 100644 --- a/gnovm/stdlibs/std/emit_event.go +++ b/gnovm/stdlibs/std/emit_event.go @@ -18,7 +18,6 @@ func X_emit(m *gno.Machine, typ string, attrs []string) { } _, pkgPath := currentRealm(m) - fnIdent := getPreviousFunctionNameFromTarget(m, "Emit") ctx := GetContext(m) @@ -26,7 +25,6 @@ func X_emit(m *gno.Machine, typ string, attrs []string) { Type: typ, Attributes: eventAttrs, PkgPath: pkgPath, - Func: fnIdent, } ctx.EventLogger.EmitEvent(evt) @@ -47,15 +45,16 @@ func attrKeysAndValues(attrs []string) ([]GnoEventAttribute, error) { return eventAttrs, nil } +// XXX rename to std/events.Event? type GnoEvent struct { Type string `json:"type"` Attributes []GnoEventAttribute `json:"attrs"` PkgPath string `json:"pkg_path"` - Func string `json:"func"` } func (e GnoEvent) AssertABCIEvent() {} +// XXX rename to std/events.Attribute? type GnoEventAttribute struct { Key string `json:"key"` Value string `json:"value"` diff --git a/gnovm/stdlibs/std/emit_event_test.go b/gnovm/stdlibs/std/emit_event_test.go index ecf08eebd60..474cd6e90b1 100644 --- a/gnovm/stdlibs/std/emit_event_test.go +++ b/gnovm/stdlibs/std/emit_event_test.go @@ -2,8 +2,6 @@ package std import ( "encoding/json" - "strconv" - "strings" "testing" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" @@ -11,12 +9,20 @@ import ( "github.com/stretchr/testify/assert" ) -func TestEmit(t *testing.T) { - m := gno.NewMachine("emit", nil) +func pushFuncFrame(m *gno.Machine, name gno.Name) { + fv := &gno.FuncValue{Name: name, PkgPath: m.Package.PkgPath} + m.PushFrameCall(gno.Call(name), fv, gno.TypedValue{}) // fake frame +} +func TestEmit(t *testing.T) { + m := gno.NewMachine("emit_test", nil) m.Context = ExecContext{} - + pushFuncFrame(m, "main") + pushFuncFrame(m, "Emit") _, pkgPath := X_getRealm(m, 0) + if pkgPath != "emit_test" || m.Package.PkgPath != "emit_test" { + panic("inconsistent package paths") + } tests := []struct { name string eventType string @@ -31,8 +37,7 @@ func TestEmit(t *testing.T) { expectedEvents: []GnoEvent{ { Type: "test", - PkgPath: pkgPath, - Func: "", + PkgPath: "emit_test", Attributes: []GnoEventAttribute{ {Key: "key1", Value: "value1"}, {Key: "key2", Value: "value2"}, @@ -54,8 +59,7 @@ func TestEmit(t *testing.T) { expectedEvents: []GnoEvent{ { Type: "test", - PkgPath: pkgPath, - Func: "", + PkgPath: "emit_test", Attributes: []GnoEventAttribute{ {Key: "key1", Value: ""}, {Key: "key2", Value: "value2"}, @@ -71,8 +75,7 @@ func TestEmit(t *testing.T) { expectedEvents: []GnoEvent{ { Type: "", - PkgPath: pkgPath, - Func: "", + PkgPath: "emit_test", Attributes: []GnoEventAttribute{ {Key: "key1", Value: "value1"}, {Key: "key2", Value: "value2"}, @@ -88,8 +91,7 @@ func TestEmit(t *testing.T) { expectedEvents: []GnoEvent{ { Type: "test", - PkgPath: pkgPath, - Func: "", + PkgPath: "emit_test", Attributes: []GnoEventAttribute{ {Key: "", Value: "value1"}, {Key: "key2", Value: "value2"}, @@ -106,9 +108,8 @@ func TestEmit(t *testing.T) { m.Context = ExecContext{EventLogger: elgs} if tt.expectPanic { - assert.Panics(t, func() { - X_emit(m, tt.eventType, tt.attrs) - }) + X_emit(m, tt.eventType, tt.attrs) + assert.Equal(t, 1, len(m.Exceptions)) } else { X_emit(m, tt.eventType, tt.attrs) assert.Equal(t, len(tt.expectedEvents), len(elgs.Events())) @@ -131,7 +132,9 @@ func TestEmit(t *testing.T) { func TestEmit_MultipleEvents(t *testing.T) { t.Parallel() - m := gno.NewMachine("emit", nil) + m := gno.NewMachine("emit_test", nil) + pushFuncFrame(m, "main") + pushFuncFrame(m, "Emit") elgs := sdk.NewEventLogger() m.Context = ExecContext{EventLogger: elgs} @@ -151,8 +154,7 @@ func TestEmit_MultipleEvents(t *testing.T) { expect := []GnoEvent{ { Type: "test1", - PkgPath: "", - Func: "", + PkgPath: "emit_test", Attributes: []GnoEventAttribute{ {Key: "key1", Value: "value1"}, {Key: "key2", Value: "value2"}, @@ -160,8 +162,7 @@ func TestEmit_MultipleEvents(t *testing.T) { }, { Type: "test2", - PkgPath: "", - Func: "", + PkgPath: "emit_test", Attributes: []GnoEventAttribute{ {Key: "key3", Value: "value3"}, {Key: "key4", Value: "value4"}, @@ -176,141 +177,3 @@ func TestEmit_MultipleEvents(t *testing.T) { assert.Equal(t, string(expectRes), string(res)) } - -func TestEmit_ContractInteraction(t *testing.T) { - const ( - testFoo = "foo" - testQux = "qux" - ) - - type ( - contractA struct { - foo func(*gno.Machine, func()) - } - - contractB struct { - qux func(m *gno.Machine) - } - ) - - t.Parallel() - m := gno.NewMachine("emit", nil) - elgs := sdk.NewEventLogger() - m.Context = ExecContext{EventLogger: elgs} - - baz := func(m *gno.Machine) { - X_emit(m, testFoo, []string{"k1", "v1", "k2", "v2"}) - } - - a := &contractA{ - foo: func(m *gno.Machine, cb func()) { - baz(m) - cb() - }, - } - b := &contractB{ - qux: func(m *gno.Machine) { - X_emit(m, testQux, []string{"bar", "baz"}) - }, - } - - a.foo(m, func() { - b.qux(m) - }) - - assert.Equal(t, 2, len(elgs.Events())) - - res, err := json.Marshal(elgs.Events()) - if err != nil { - t.Fatal(err) - } - - expected := `[{"type":"foo","attrs":[{"key":"k1","value":"v1"},{"key":"k2","value":"v2"}],"pkg_path":"","func":""},{"type":"qux","attrs":[{"key":"bar","value":"baz"}],"pkg_path":"","func":""}]` - - assert.Equal(t, expected, string(res)) -} - -func TestEmit_Iteration(t *testing.T) { - const testBar = "bar" - m := gno.NewMachine("emit", nil) - - elgs := sdk.NewEventLogger() - m.Context = ExecContext{EventLogger: elgs} - - iterEvent := func(m *gno.Machine) { - for i := 0; i < 10; i++ { - X_emit(m, testBar, []string{"qux", "value1"}) - } - } - iterEvent(m) - assert.Equal(t, 10, len(elgs.Events())) - - res, err := json.Marshal(elgs.Events()) - if err != nil { - t.Fatal(err) - } - - var builder strings.Builder - builder.WriteString("[") - for i := 0; i < 10; i++ { - builder.WriteString(`{"type":"bar","attrs":[{"key":"qux","value":"value1"}],"pkg_path":"","func":""},`) - } - expected := builder.String()[:builder.Len()-1] + "]" - - assert.Equal(t, expected, string(res)) -} - -func complexInteraction(m *gno.Machine) { - deferEmitExample(m) -} - -func deferEmitExample(m *gno.Machine) { - defer func() { - X_emit(m, "DeferEvent", []string{"key1", "value1", "key2", "value2"}) - }() - - forLoopEmitExample(m, 3, func(i int) { - X_emit(m, "ForLoopEvent", []string{"iteration", strconv.Itoa(i), "key", "value"}) - }) - - callbackEmitExample(m, func() { - X_emit(m, "CallbackEvent", []string{"key1", "value1", "key2", "value2"}) - }) -} - -func forLoopEmitExample(m *gno.Machine, count int, callback func(int)) { - defer func() { - X_emit(m, "ForLoopCompletionEvent", []string{"count", strconv.Itoa(count)}) - }() - - for i := 0; i < count; i++ { - callback(i) - } -} - -func callbackEmitExample(m *gno.Machine, callback func()) { - defer func() { - X_emit(m, "CallbackCompletionEvent", []string{"key", "value"}) - }() - - callback() -} - -func TestEmit_ComplexInteraction(t *testing.T) { - m := gno.NewMachine("emit", nil) - - elgs := sdk.NewEventLogger() - m.Context = ExecContext{EventLogger: elgs} - - complexInteraction(m) - - assert.Equal(t, 7, len(elgs.Events())) - - res, err := json.Marshal(elgs.Events()) - if err != nil { - t.Fatal(err) - } - - expected := `[{"type":"ForLoopEvent","attrs":[{"key":"iteration","value":"0"},{"key":"key","value":"value"}],"pkg_path":"","func":""},{"type":"ForLoopEvent","attrs":[{"key":"iteration","value":"1"},{"key":"key","value":"value"}],"pkg_path":"","func":""},{"type":"ForLoopEvent","attrs":[{"key":"iteration","value":"2"},{"key":"key","value":"value"}],"pkg_path":"","func":""},{"type":"ForLoopCompletionEvent","attrs":[{"key":"count","value":"3"}],"pkg_path":"","func":""},{"type":"CallbackEvent","attrs":[{"key":"key1","value":"value1"},{"key":"key2","value":"value2"}],"pkg_path":"","func":""},{"type":"CallbackCompletionEvent","attrs":[{"key":"key","value":"value"}],"pkg_path":"","func":""},{"type":"DeferEvent","attrs":[{"key":"key1","value":"value1"},{"key":"key2","value":"value2"}],"pkg_path":"","func":""}]` - assert.Equal(t, expected, string(res)) -} diff --git a/gnovm/stdlibs/std/native.gno b/gnovm/stdlibs/std/native.gno index 7366494825f..b047a094e22 100644 --- a/gnovm/stdlibs/std/native.gno +++ b/gnovm/stdlibs/std/native.gno @@ -37,14 +37,21 @@ func OriginPkgAddress() Address { return Address(originPkgAddr()) } +/* +This function and variations are a literal genie/demon that will create a layer +of middlemen who will take away your agency. Keep it unavailable for a thousand +years. Then uncomment, see the harm it produces, and then delete it forever. + func CallerAt(n int) Address { return Address(callerAt(n)) } +func callerAt(n int) string +*/ + // Variations which don't use named types. func originSend() (denoms []string, amounts []int64) func originCaller() string func originPkgAddr() string -func callerAt(n int) string func getRealm(height int) (address string, pkgPath string) func assertCallerIsRealm() diff --git a/gnovm/stdlibs/std/native.go b/gnovm/stdlibs/std/native.go index b226ca03afa..841c75bbd6d 100644 --- a/gnovm/stdlibs/std/native.go +++ b/gnovm/stdlibs/std/native.go @@ -1,8 +1,9 @@ package std import ( + "fmt" + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/tm2/pkg/crypto" "github.com/gnolang/gno/tm2/pkg/std" ) @@ -34,38 +35,6 @@ func ChainHeight(m *gno.Machine) int64 { return GetContext(m).Height } -// getPreviousFunctionNameFromTarget returns the last called function name (identifier) from the call stack. -func getPreviousFunctionNameFromTarget(m *gno.Machine, targetFunc string) string { - targetIndex := findTargetFunctionIndex(m, targetFunc) - if targetIndex == -1 { - return "" - } - return findPreviousFunctionName(m, targetIndex) -} - -// findTargetFunctionIndex finds and returns the index of the target function in the call stack. -func findTargetFunctionIndex(m *gno.Machine, targetFunc string) int { - for i := len(m.Frames) - 1; i >= 0; i-- { - currFunc := m.Frames[i].Func - if currFunc != nil && currFunc.Name == gno.Name(targetFunc) { - return i - } - } - return -1 -} - -// findPreviousFunctionName returns the function name before the given index in the call stack. -func findPreviousFunctionName(m *gno.Machine, targetIndex int) string { - for i := targetIndex - 1; i >= 0; i-- { - currFunc := m.Frames[i].Func - if currFunc != nil { - return string(currFunc.Name) - } - } - - panic("function name not found") -} - func X_originSend(m *gno.Machine) (denoms []string, amounts []int64) { os := GetContext(m).OriginSend return ExpandCoins(os) @@ -79,6 +48,7 @@ func X_originPkgAddr(m *gno.Machine) string { return string(GetContext(m).OriginPkgAddr) } +/* See comment in stdlibs/std/native.gno func X_callerAt(m *gno.Machine, n int) string { if n <= 0 { m.Panic(typedString("CallerAt requires positive arg")) @@ -98,40 +68,60 @@ func X_callerAt(m *gno.Machine, n int) string { ctx := GetContext(m) return string(ctx.OriginCaller) } - return string(m.MustLastCallFrame(n).LastPackage.GetPkgAddr().Bech32()) + return string(m.MustPeekCallFrame(n).LastPackage.GetPkgAddr().Bech32()) } +*/ func X_getRealm(m *gno.Machine, height int) (address, pkgPath string) { // NOTE: keep in sync with test/stdlibs/std.getRealm var ( - ctx = GetContext(m) - currentCaller crypto.Bech32Address - // Keeps track of the number of times currentCaller - // has changed. - changes int + ctx = GetContext(m) + crosses int // track realm crosses + lfr *gno.Frame = m.LastFrame() // last call frame ) for i := m.NumFrames() - 1; i >= 0; i-- { fr := m.Frames[i] - if fr.LastPackage == nil || !fr.LastPackage.IsRealm() { + + // Skip over (non-realm) non-crosses. + if !fr.IsCall() { + continue + } + if !fr.WithCross { + lfr = fr continue } - // LastPackage is a realm. Get caller and pkgPath, and compare against - // current* values. - caller := fr.LastPackage.GetPkgAddr().Bech32() - pkgPath := fr.LastPackage.PkgPath - if caller != currentCaller { - if changes == height { - return string(caller), pkgPath - } - currentCaller = caller - changes++ + // Sanity check + if !fr.DidCross { + panic(fmt.Sprintf( + "call to cross(fn) did not call crossing : %s", + fr.Func.String())) + } + + crosses++ + if crosses > height { + currlm := lfr.LastRealm + caller, rlmPath := gno.DerivePkgAddr(currlm.Path).Bech32(), currlm.Path + return string(caller), rlmPath } + lfr = fr + } + + if crosses != height { + m.Panic(typedString("frame not found")) + } + + // Special case if package initialization. + if ctx.OriginCaller == "" { + fr := m.Frames[0] + caller := string(fr.LastPackage.GetPkgAddr().Bech32()) + pkgPath := fr.LastPackage.PkgPath + return string(caller), pkgPath } - // Fallback case: return OriginCaller. + // Base case: return OriginCaller. return string(ctx.OriginCaller), "" } diff --git a/gnovm/stdlibs/std/native_test.go b/gnovm/stdlibs/std/native_test.go index e51badd4e2e..1b61743c886 100644 --- a/gnovm/stdlibs/std/native_test.go +++ b/gnovm/stdlibs/std/native_test.go @@ -1,6 +1,7 @@ package std import ( + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -18,6 +19,12 @@ func TestPreviousRealmIsOrigin(t *testing.T) { msgCallFrame = &gno.Frame{LastPackage: &gno.PackageValue{PkgPath: "main"}} msgRunFrame = &gno.Frame{LastPackage: &gno.PackageValue{PkgPath: "gno.land/r/g1337/run"}} ) + type expectations struct { + addr crypto.Bech32Address + pkgPath string + isOriginCall bool + doesPanic bool + } tests := []struct { name string machine *gno.Machine @@ -179,8 +186,13 @@ func TestPreviousRealmIsOrigin(t *testing.T) { expectedIsOriginCall: false, }, } - for _, tt := range tests { + for i, tt := range tests { t.Run(tt.name, func(t *testing.T) { + defer func() { + if r := recover(); r != nil { + fmt.Println("fail", i) + } + }() assert := assert.New(t) addr, pkgPath := X_getRealm(tt.machine, 1) diff --git a/gnovm/tests/files/access2.gno b/gnovm/tests/files/access2.gno index 46b17136b54..10ab2ffc352 100644 --- a/gnovm/tests/files/access2.gno +++ b/gnovm/tests/files/access2.gno @@ -6,6 +6,8 @@ import ( ) func main() { + crossing() + testutils.TestVar1 += 1 println(testutils.TestVar1) } diff --git a/gnovm/tests/files/assign_unnamed_type/more/assgin_interface_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/assgin_interface_filetest.gno index 92e3a1e3075..aa5de45d2ac 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/assgin_interface_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/assgin_interface_filetest.gno @@ -33,7 +33,7 @@ func main() { } // Output: -// (undefined) +// undefined // (slice[(1 int)] main.myIntSlice) // (slice[(1 int)] main.myIntSlice) // (slice[(1 int)] main.myIntSlice) diff --git a/gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest.gno index 1bc5add0440..2b6e85caef1 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/cross_realm_compositelit_filetest.gno @@ -6,6 +6,8 @@ import ( ) func main() { + crossing() + println(tests.GetZeroType()) } diff --git a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno index e3cc50ab330..a1589623f4b 100644 --- a/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno +++ b/gnovm/tests/files/assign_unnamed_type/more/realm_compositelit_filetest.gno @@ -14,6 +14,8 @@ type Int struct { } func main() { + crossing() + zero = &Int{ abs: []word{0}, } @@ -26,7 +28,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ // "Data": null, // "List": [ // { @@ -37,13 +39,13 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ // "Fields": [ // { // "T": { @@ -54,8 +56,8 @@ func main() { // "@type": "/gno.SliceValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "e256933ba4dfda233a7edb0902880d554118ba6e", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// "Hash": "053ebe7d3e2087ff390f1c09b3f36cf0763f0967", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" // }, // "Length": "1", // "Maxcap": "1", @@ -64,17 +66,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // "RefCount": "1" // }, // "Value": { @@ -84,26 +86,35 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "2b8a024c53e94431e6203115feaf86b36413d7b2", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// "Hash": "e757ea3d88983d3fc397e089882a1e31ee2c5e10", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -65,6 +65,16 @@ -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.Int" -// } -// + }, -// + "V": { -// + "@type": "/gno.PointerValue", -// + "Base": { -// + "@type": "/gno.RefValue", -// + "Hash": "3c89d875f7d6daa94113aa4c7e03432ba56202c2", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// + }, -// + "Index": "0", -// + "TV": null +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,7 +1,7 @@ +// { +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "0", +// + "ModTime": "5", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" +// }, +// @@ -12,6 +12,16 @@ +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.Int" // } -// }, -// { +// + }, +// + "V": { +// + "@type": "/gno.PointerValue", +// + "Base": { +// + "@type": "/gno.RefValue", +// + "Hash": "afc8a8a4c127ea7b6713ec59220d7c6cdd6e842e", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// + }, +// + "Index": "0", +// + "TV": null +// } +// } +// } diff --git a/gnovm/tests/files/closure10.gno b/gnovm/tests/files/closure10.gno new file mode 100644 index 00000000000..ab2eabaeca0 --- /dev/null +++ b/gnovm/tests/files/closure10.gno @@ -0,0 +1,18 @@ +package main + +func main() { + var x any = int(1) + if _, ok := x.(string); !ok { // !ok + x = func() bool { + return ok + } + } + ok2 := x.(func() bool)() + println(ok2) +} + +// Preprocessed: +// file{ package main; func main() { var x (const-type interface {}) = (const (1 int)); if _, ok := x.((const-type string)); !ok<~VPBlock(1,0)> { x = func func() .res.0 (const-type bool){ return ok<~VPBlock(1,1)> }> }; ok2 := x.(func() .res.0 (const-type bool))(); (const (println func(...interface {})))(ok2) } } + +// Output: +// false diff --git a/gnovm/tests/files/closure11.gno b/gnovm/tests/files/closure11.gno new file mode 100644 index 00000000000..19358c0d428 --- /dev/null +++ b/gnovm/tests/files/closure11.gno @@ -0,0 +1,19 @@ +package main + +type fooer interface{} + +var f fooer = 1 + +func trymake() func() { + switch v := f.(type) { + case int: + return func() { + println(v) + } + default: + } + return func() {} +} +func main() { + trymake()() +} diff --git a/gnovm/tests/files/closure12.gno b/gnovm/tests/files/closure12.gno new file mode 100644 index 00000000000..c1dda1a1ed0 --- /dev/null +++ b/gnovm/tests/files/closure12.gno @@ -0,0 +1,18 @@ +package main + +func trymake() func() { + switch i := 1; i { + case 1: + return func() { + println(i) + } + default: + } + return nil +} +func main() { + trymake()() +} + +// Output: +// 1 diff --git a/gnovm/tests/files/closure9.gno b/gnovm/tests/files/closure9.gno new file mode 100644 index 00000000000..b774b2ae656 --- /dev/null +++ b/gnovm/tests/files/closure9.gno @@ -0,0 +1,26 @@ +package main + +import "fmt" + +var p int + +func main() { + b, x := makeClosure(1) + x(true) +} + +func makeClosure(a int) (b int, c func(bool)) { + return 2, func(recurse bool) { + fmt.Println(a, b, p) + if recurse { + c(false) + } + } +} + +// Preprocessed: +// file{ package main; import fmt fmt; var p (const-type int); func main() { b, x := makeClosure((const (1 int))); x((const (true bool))) }; func makeClosure(a~ (const-type int)) b~ (const-type int), c~ func(.arg_0 (const-type bool)) { return (const (2 int)), func func(recurse (const-type bool)){ (const (ref(fmt) package{})).Println(a<~VPBlock(1,1)>, b<~VPBlock(1,2)>, (const (ref(main) package{})).p); if recurse { c<~VPBlock(2,3)>((const (false bool))) } }, b<()~VPBlock(1,1)>, c<()~VPBlock(1,2)>> } } + +// Output: +// 1 2 0 +// 1 2 0 diff --git a/gnovm/tests/files/defer/defer1.gno b/gnovm/tests/files/defer/defer1.gno new file mode 100644 index 00000000000..0c885343a10 --- /dev/null +++ b/gnovm/tests/files/defer/defer1.gno @@ -0,0 +1,27 @@ +package main + +func bar() (r int) { + defer func() { // defer 1 + r += 4 + if recover() != nil { + r += 3 + } + }() + + + var f func() // This is a nil function. + // The nil function will be pushed onto the stack and executed later. + // It will panic, and the panic will be caught by the defer statement above (defer 1). + defer f() + f = func() { // this has no effect since f (nil) is already pushed on the stack. + r += 2 + } + return 1 +} + +func main() { + println(bar()) +} + +// Output: +// 8 diff --git a/gnovm/tests/files/defer0.gno b/gnovm/tests/files/defer0.gno index 6233bffb347..f747ee58048 100644 --- a/gnovm/tests/files/defer0.gno +++ b/gnovm/tests/files/defer0.gno @@ -2,15 +2,41 @@ package main import "fmt" +type Foo struct { +} + +func (f Foo) Println(s ...string) { + println(s...) +} + func main() { println("hello") - defer fmt.Println("bye") - defer fmt.Println("au revoir") + f := Foo{} + defer func() { + println("bye1") + }() + defer println() + defer println("p1") + defer println("p2", "p3") + defer f.Println() + defer f.Println("f1") + defer f.Println("f2", "f3") + defer fmt.Println() + defer fmt.Println("fmt1") + defer fmt.Println("fmt2", "fmt3") println("world") } // Output: // hello // world -// au revoir -// bye +// fmt2 fmt3 +// fmt1 +// +// f2 f3 +// f1 +// +// p2 p3 +// p1 +// +// bye1 diff --git a/gnovm/tests/files/exploit/realm_exploiter.gno b/gnovm/tests/files/exploit/realm_exploiter.gno new file mode 100644 index 00000000000..ad9a84861e1 --- /dev/null +++ b/gnovm/tests/files/exploit/realm_exploiter.gno @@ -0,0 +1,37 @@ +// PKGPATH: gno.land/r/exploiter_test +package exploiter_test + +import ( + "gno.land/r/demo/tests" +) + +type MyBar struct { + A int + B *tests.Foo +} + +func (f *MyBar) Bar(x int) { + f.B.A = x +} + +func main() { + crossing() + + x := (struct { + A int + B *tests.Foo + })(*tests.MyFoo) // <-- this should panic + + y := MyBar(x) + z := &y + println(tests.MyFoo) + z.Bar(10) + println(tests.MyFoo) +} + +// The exploiter cannot update tests.MyFoo, but would output: +// (struct{(1 int),(&(struct{(2 int),(nil *gno.land/r/demo/tests.Foo)} gno.land/r/demo/tests.Foo) *gno.land/r/demo/tests.Foo)} gno.land/r/demo/tests.Foo) +// (struct{(1 int),(&(struct{(10 int),(nil *gno.land/r/demo/tests.Foo)} gno.land/r/demo/tests.Foo) *gno.land/r/demo/tests.Foo)} gno.land/r/demo/tests.Foo) + +// Error: +// illegal conversion of readonly or externally stored value diff --git a/gnovm/tests/files/extern/timtadh/data_structures/types/string.gno b/gnovm/tests/files/extern/timtadh/data_structures/types/string.gno index 13f94950dfa..5ccf12fd8a1 100644 --- a/gnovm/tests/files/extern/timtadh/data_structures/types/string.gno +++ b/gnovm/tests/files/extern/timtadh/data_structures/types/string.gno @@ -70,8 +70,8 @@ func (self ByteSlice) Hash() int { func hash(s []byte) int { res := sha256.Sum256(s) - return int(s[0]) | - int(s[1]<<8) | - int(s[2]<<16) | - int(s[3]<<24) + return int(res[0]) | + int(res[1]<<8) | + int(res[2]<<16) | + int(res[3]<<24) } diff --git a/gnovm/tests/files/heap_alloc_defer.gno b/gnovm/tests/files/heap_alloc_defer.gno index 788d9326695..db027d494b8 100644 --- a/gnovm/tests/files/heap_alloc_defer.gno +++ b/gnovm/tests/files/heap_alloc_defer.gno @@ -17,8 +17,6 @@ func main() { }, } - // tt is heap defined every iteration, - // different with for loopvar spec. for _, tt := range s { f := func() { println(tt.num) @@ -34,4 +32,4 @@ func main() { // 1 // 2 // hola -// hola +// hello diff --git a/gnovm/tests/files/heap_alloc_forloop1.gno b/gnovm/tests/files/heap_alloc_forloop1.gno index c746dd2e215..64e25ef8922 100644 --- a/gnovm/tests/files/heap_alloc_forloop1.gno +++ b/gnovm/tests/files/heap_alloc_forloop1.gno @@ -23,7 +23,7 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { s1 = (const (append func([]*int, ...*int) []*int))(s1, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } // Output: // s1[0] is: 3 diff --git a/gnovm/tests/files/heap_alloc_forloop1a.gno b/gnovm/tests/files/heap_alloc_forloop1a.gno index 82e7df17e1d..bcbd7d4ce6b 100644 --- a/gnovm/tests/files/heap_alloc_forloop1a.gno +++ b/gnovm/tests/files/heap_alloc_forloop1a.gno @@ -29,7 +29,7 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; import fmt fmt; type Int (const-type main.Int); var s1 []*(Int); func inc2(j *(Int)) { *(j) = *(j) + (const (2 main.Int)) }; func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 main.Int)); i<~VPBlock(1,0)> < (const (10 main.Int)); inc2(&(i<~VPBlock(1,0)>)) { s1 = (const (append func([]*main.Int, ...*main.Int) []*main.Int))(s1, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } +// file{ package main; import fmt fmt; type Int (const-type main.Int); var s1 []*(Int); func inc2(j *(Int)) { *(j) = *(j) + (const (2 main.Int)) }; func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 main.Int)); i<~VPBlock(1,0)> < (const (10 main.Int)); inc2(&(i<~VPBlock(1,0)>)) { s1<~VPBlock(4,1)> = (const (append func([]*main.Int, ...*main.Int) []*main.Int))(s1<~VPBlock(4,1)>, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } // Output: // s1[0] is: 10 diff --git a/gnovm/tests/files/heap_alloc_forloop1b.gno b/gnovm/tests/files/heap_alloc_forloop1b.gno index de8217003a5..7817ee0d0b5 100644 --- a/gnovm/tests/files/heap_alloc_forloop1b.gno +++ b/gnovm/tests/files/heap_alloc_forloop1b.gno @@ -26,7 +26,7 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { r := i<~VPBlock(1,0)>; r, ok := (const (0 int)), (const (true bool)); (const (println func(...interface {})))(ok, r); s1 = (const (append func([]*int, ...*int) []*int))(s1, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { r := i<~VPBlock(1,0)>; r, ok := (const (0 int)), (const (true bool)); (const (println func(...interface {})))(ok, r); s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } // Output: // true 0 diff --git a/gnovm/tests/files/heap_alloc_forloop2.gno b/gnovm/tests/files/heap_alloc_forloop2.gno index 43bd6259b36..b85ae39099f 100644 --- a/gnovm/tests/files/heap_alloc_forloop2.gno +++ b/gnovm/tests/files/heap_alloc_forloop2.gno @@ -25,7 +25,7 @@ func main() { // You can tell by the preprocess printout of z and z<~...>. // Preprocessed: -// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i + (const (1 int)); s1 = (const (append func([]*int, ...*int) []*int))(s1, &(z<~VPBlock(1,1)>)) } }; func main() { forLoopRef() } } +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i + (const (1 int)); s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(z<~VPBlock(1,1)>)) } }; func main() { forLoopRef() } } // Output: // s1[0] is: 1 diff --git a/gnovm/tests/files/heap_alloc_forloop2a.gno b/gnovm/tests/files/heap_alloc_forloop2a.gno index 7e9b59b4451..aa3494f3421 100644 --- a/gnovm/tests/files/heap_alloc_forloop2a.gno +++ b/gnovm/tests/files/heap_alloc_forloop2a.gno @@ -26,7 +26,7 @@ func main() { // You can tell by the preprocess printout of z and z<~...>. // Preprocessed: -// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; s1 = (const (append func([]*int, ...*int) []*int))(s1, &(z<~VPBlock(1,1)>)); z<~VPBlock(1,1)>++ } }; func main() { forLoopRef() } } +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(z<~VPBlock(1,1)>)); z<~VPBlock(1,1)>++ } }; func main() { forLoopRef() } } // Output: // s1[0] is: 1 diff --git a/gnovm/tests/files/heap_alloc_forloop3.gno b/gnovm/tests/files/heap_alloc_forloop3.gno index 8fd2da59c37..939fa9785fb 100644 --- a/gnovm/tests/files/heap_alloc_forloop3.gno +++ b/gnovm/tests/files/heap_alloc_forloop3.gno @@ -25,7 +25,7 @@ func main() { // You can tell by the preprocess printout of z and z<()~...>. // Preprocessed: -// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; fs = (const (append func([]main.f, ...main.f) []main.f))(fs, (const-type main.f)(func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } +// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop3a.gno b/gnovm/tests/files/heap_alloc_forloop3a.gno index c8504cc58a5..5b5b2309e7b 100644 --- a/gnovm/tests/files/heap_alloc_forloop3a.gno +++ b/gnovm/tests/files/heap_alloc_forloop3a.gno @@ -27,7 +27,7 @@ func main() { // You can tell by the preprocess printout of z and z<()~...>. // Preprocessed: -// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { x := i; (const (println func(...interface {})))(x); z := i; fs = (const (append func([]main.f, ...main.f) []main.f))(fs, (const-type main.f)(func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } +// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { x := i; (const (println func(...interface {})))(x); z := i; fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop4.gno b/gnovm/tests/files/heap_alloc_forloop4.gno index 7ddcea37d25..33aad1e2fac 100644 --- a/gnovm/tests/files/heap_alloc_forloop4.gno +++ b/gnovm/tests/files/heap_alloc_forloop4.gno @@ -23,7 +23,7 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range fs { f() } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { fs = (const (append func([]main.f, ...main.f) []main.f))(fs, (const-type main.f)(func func(){ (const (println func(...interface {})))(i<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } +// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ (const (println func(...interface {})))(i<~VPBlock(1,0)>) }>)) } }; func main() { forLoopClosure() } } // Output: // 3 diff --git a/gnovm/tests/files/heap_alloc_forloop5.gno b/gnovm/tests/files/heap_alloc_forloop5.gno index 1e53e6bbe1f..373b88ff8b2 100644 --- a/gnovm/tests/files/heap_alloc_forloop5.gno +++ b/gnovm/tests/files/heap_alloc_forloop5.gno @@ -24,7 +24,7 @@ func main() { } // Preprocessed: -// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range fs { f() } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { fs = (const (append func([]main.f, ...main.f) []main.f))(fs, (const-type main.f)(func func(){ z := i<~VPBlock(1,1)>; (const (println func(...interface {})))(z) }>)) } }; func main() { forLoopClosure() } } +// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ z := i<~VPBlock(1,1)>; (const (println func(...interface {})))(z) }>)) } }; func main() { forLoopClosure() } } // Output: // 3 diff --git a/gnovm/tests/files/heap_alloc_forloop5a.gno b/gnovm/tests/files/heap_alloc_forloop5a.gno index 9664ca18e85..110dd83541e 100644 --- a/gnovm/tests/files/heap_alloc_forloop5a.gno +++ b/gnovm/tests/files/heap_alloc_forloop5a.gno @@ -25,7 +25,7 @@ func main() { } // Preprocessed: -// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { x := i; fs = (const (append func([]main.f, ...main.f) []main.f))(fs, (const-type main.f)(func func(){ z := x<~VPBlock(1,1)>; (const (println func(...interface {})))(z) }>)) } }; func main() { forLoopClosure() } } +// file{ package main; type f (const-type main.f); var fs []f; func forLoopClosure() { defer func func(){ for _, f := range (const (ref(main) package{})).fs { f() } }(); for i := (const (0 int)); i < (const (3 int)); i++ { x := i; fs<~VPBlock(4,1)> = (const (append func([]main.f, ...main.f) []main.f))(fs<~VPBlock(4,1)>, (const-type main.f)(func func(){ z := x<~VPBlock(1,1)>; (const (println func(...interface {})))(z) }>)) } }; func main() { forLoopClosure() } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop6.gno b/gnovm/tests/files/heap_alloc_forloop6.gno index 1177626ac73..bea81c89924 100644 --- a/gnovm/tests/files/heap_alloc_forloop6.gno +++ b/gnovm/tests/files/heap_alloc_forloop6.gno @@ -17,7 +17,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; f := func func() (const-type int){ return z<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (3 int)); i++ { z := i; f := func func() .res.0 (const-type int){ return z<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop6a.gno b/gnovm/tests/files/heap_alloc_forloop6a.gno index c465a8cef03..ec24f562ed6 100644 --- a/gnovm/tests/files/heap_alloc_forloop6a.gno +++ b/gnovm/tests/files/heap_alloc_forloop6a.gno @@ -16,7 +16,7 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (5 int)); i<~VPBlock(1,0)>++ { f := func func() (const-type int){ return i<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (5 int)); i<~VPBlock(1,0)>++ { f := func func() .res.0 (const-type int){ return i<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 5 diff --git a/gnovm/tests/files/heap_alloc_forloop6b.gno b/gnovm/tests/files/heap_alloc_forloop6b.gno index 2e77a580ce8..6b884d661f1 100644 --- a/gnovm/tests/files/heap_alloc_forloop6b.gno +++ b/gnovm/tests/files/heap_alloc_forloop6b.gno @@ -18,7 +18,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; y := (const (0 int)); f := func func() (const-type int){ x<~VPBlock(1,1)> += y<~VPBlock(1,2)>; x<~VPBlock(1,1)> += (const (1 int)); return x<~VPBlock(1,1)> }, y<()~VPBlock(1,2)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; y := (const (0 int)); f := func func() .res.0 (const-type int){ x<~VPBlock(1,1)> += y<~VPBlock(1,2)>; x<~VPBlock(1,1)> += (const (1 int)); return x<~VPBlock(1,1)> }, y<()~VPBlock(1,2)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_forloop6c.gno b/gnovm/tests/files/heap_alloc_forloop6c.gno index 1d6a372b8da..752c7e6b4fe 100644 --- a/gnovm/tests/files/heap_alloc_forloop6c.gno +++ b/gnovm/tests/files/heap_alloc_forloop6c.gno @@ -16,7 +16,7 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (2 int)); i<~VPBlock(1,0)>++ { f := func func() (const-type int){ return i<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (2 int)); i<~VPBlock(1,0)>++ { f := func func() .res.0 (const-type int){ return i<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 2 diff --git a/gnovm/tests/files/heap_alloc_forloop6f.gno b/gnovm/tests/files/heap_alloc_forloop6f.gno index 29001216dd4..7c568884071 100644 --- a/gnovm/tests/files/heap_alloc_forloop6f.gno +++ b/gnovm/tests/files/heap_alloc_forloop6f.gno @@ -16,7 +16,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (5 int)); i++ { var x (const-type int); f := func func() (const-type int){ return x<~VPBlock(1,1)> }>; x<~VPBlock(1,1)> = i; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (5 int)); i++ { var x (const-type int); f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }>; x<~VPBlock(1,1)> = i; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop6g.gno b/gnovm/tests/files/heap_alloc_forloop6g.gno index fb0a9936fcd..c81d33ab60b 100644 --- a/gnovm/tests/files/heap_alloc_forloop6g.gno +++ b/gnovm/tests/files/heap_alloc_forloop6g.gno @@ -17,7 +17,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (5 int)); i++ { x := i; { f := func func() (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (5 int)); i++ { x := i; { f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop6h.gno b/gnovm/tests/files/heap_alloc_forloop6h.gno index e1b2adb6e31..88a2de9baad 100644 --- a/gnovm/tests/files/heap_alloc_forloop6h.gno +++ b/gnovm/tests/files/heap_alloc_forloop6h.gno @@ -18,7 +18,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; for j := (const (0 int)); j < (const (2 int)); j++ { y := j; f := func func() (const-type int){ return x<~VPBlock(1,1)> + y<~VPBlock(1,2)> }, y<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; for j := (const (0 int)); j < (const (2 int)); j++ { y := j; f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> + y<~VPBlock(1,2)> }, y<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Go Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop6h0.gno b/gnovm/tests/files/heap_alloc_forloop6h0.gno index 0ccb6edfbc3..52ad504bd1c 100644 --- a/gnovm/tests/files/heap_alloc_forloop6h0.gno +++ b/gnovm/tests/files/heap_alloc_forloop6h0.gno @@ -18,7 +18,7 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (2 int)); i<~VPBlock(1,0)>++ { for j := (const (0 int)); j<~VPBlock(1,0)> < (const (2 int)); j<~VPBlock(1,0)>++ { f := func func() (const-type int){ return i<~VPBlock(1,1)> + j<~VPBlock(1,2)> }, j<()~VPBlock(1,0)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (2 int)); i<~VPBlock(1,0)>++ { for j := (const (0 int)); j<~VPBlock(1,0)> < (const (2 int)); j<~VPBlock(1,0)>++ { f := func func() .res.0 (const-type int){ return i<~VPBlock(1,1)> + j<~VPBlock(1,2)> }, j<()~VPBlock(1,0)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 4 diff --git a/gnovm/tests/files/heap_alloc_forloop6i.gno b/gnovm/tests/files/heap_alloc_forloop6i.gno index 998a5a59f5f..a71ab9fd777 100644 --- a/gnovm/tests/files/heap_alloc_forloop6i.gno +++ b/gnovm/tests/files/heap_alloc_forloop6i.gno @@ -19,7 +19,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); var x (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x = i; for j := (const (0 int)); j < (const (2 int)); j++ { y := j; f := func func() (const-type int){ return x + y<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); var x (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x<~VPBlock(2,1)> = i; for j := (const (0 int)); j < (const (2 int)); j++ { y := j; f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> + y<~VPBlock(1,2)> }, y<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) } }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Go Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_forloop7.gno b/gnovm/tests/files/heap_alloc_forloop7.gno index 783ff92ce39..fc15ad0f3a1 100644 --- a/gnovm/tests/files/heap_alloc_forloop7.gno +++ b/gnovm/tests/files/heap_alloc_forloop7.gno @@ -21,7 +21,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() (const-type int){ if (const (true bool)) { if (const (true bool)) { return x<~VPBlock(3,1)> } }; return (const (0 int)) }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() .res.0 (const-type int){ if (const (true bool)) { if (const (true bool)) { return x<~VPBlock(3,1)> } }; return (const (0 int)) }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop7a.gno b/gnovm/tests/files/heap_alloc_forloop7a.gno index 54a8f2afc9a..0fdf062a59e 100644 --- a/gnovm/tests/files/heap_alloc_forloop7a.gno +++ b/gnovm/tests/files/heap_alloc_forloop7a.gno @@ -19,7 +19,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() (const-type int){ if (const (true bool)) { return x<~VPBlock(2,1)> }; return (const (0 int)) }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() .res.0 (const-type int){ if (const (true bool)) { return x<~VPBlock(2,1)> }; return (const (0 int)) }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop8.gno b/gnovm/tests/files/heap_alloc_forloop8.gno index 28c61a15af5..c0baf557515 100644 --- a/gnovm/tests/files/heap_alloc_forloop8.gno +++ b/gnovm/tests/files/heap_alloc_forloop8.gno @@ -18,7 +18,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() (const-type int){ { return x<~VPBlock(2,1)> } }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() .res.0 (const-type int){ { return x<~VPBlock(2,1)> } }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_forloop8a.gno b/gnovm/tests/files/heap_alloc_forloop8a.gno index fe1c4b906a4..eb58838b460 100644 --- a/gnovm/tests/files/heap_alloc_forloop8a.gno +++ b/gnovm/tests/files/heap_alloc_forloop8a.gno @@ -19,7 +19,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() (const-type int){ for i := (const (0 int)); i < (const (1 int)); i++ { x<~VPBlock(2,1)>++ }; return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; f := func func() .res.0 (const-type int){ for i := (const (0 int)); i < (const (1 int)); i++ { x<~VPBlock(2,1)>++ }; return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_forloop8b.gno b/gnovm/tests/files/heap_alloc_forloop8b.gno index 7addbf102f5..3f00f2e098c 100644 --- a/gnovm/tests/files/heap_alloc_forloop8b.gno +++ b/gnovm/tests/files/heap_alloc_forloop8b.gno @@ -21,7 +21,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; s := [](const-type int){(const (1 int)), (const (2 int))}; f := func func() (const-type int){ for _, v := range s<~VPBlock(2,1)> { x<~VPBlock(2,2)> += v }; return x<~VPBlock(1,2)> }, x<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; s := [](const-type int){(const (1 int)), (const (2 int))}; f := func func() .res.0 (const-type int){ for _, v := range s<~VPBlock(2,1)> { x<~VPBlock(2,2)> += v }; return x<~VPBlock(1,2)> }, x<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 3 diff --git a/gnovm/tests/files/heap_alloc_forloop8c.gno b/gnovm/tests/files/heap_alloc_forloop8c.gno index 7337b69a74b..f422f6ae72f 100644 --- a/gnovm/tests/files/heap_alloc_forloop8c.gno +++ b/gnovm/tests/files/heap_alloc_forloop8c.gno @@ -23,7 +23,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; y := (const (1 int)); f := func func() (const-type int){ switch y<~VPBlock(2,1)> { case (const (1 int)): x<~VPBlock(2,2)> += (const (1 int)); default: x<~VPBlock(2,2)> += (const (0 int)) }; return x<~VPBlock(1,2)> }, x<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); for i := (const (0 int)); i < (const (2 int)); i++ { x := i; y := (const (1 int)); f := func func() .res.0 (const-type int){ switch y<~VPBlock(2,1)> { case (const (1 int)): x<~VPBlock(2,2)> += (const (1 int)); default: x<~VPBlock(2,2)> += (const (0 int)) }; return x<~VPBlock(1,2)> }, x<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_forloop9.gno b/gnovm/tests/files/heap_alloc_forloop9.gno index da3dfea0749..cf93649ee30 100644 --- a/gnovm/tests/files/heap_alloc_forloop9.gno +++ b/gnovm/tests/files/heap_alloc_forloop9.gno @@ -28,7 +28,7 @@ func main() { // go 1.22 loop var is not supported for now. // Preprocessed: -// file{ package main; import fmt fmt; func main() { var fns []func(.arg_0 (const-type int)) (const-type int); var recursiveFunc func(.arg_0 (const-type int)) (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { recursiveFunc = func func(num (const-type int)) (const-type int){ x := i<~VPBlock(1,3)>; (const (println func(...interface {})))((const ("value of x: " string)), x); if num <= (const (0 int)) { return (const (1 int)) }; return num * recursiveFunc(num - (const (1 int))) }>; fns = (const (append func([]func(int) int, ...func(int) int) []func(int) int))(fns, recursiveFunc) }; for i, r := range fns { result := r(i); fmt.Printf((const ("Factorial of %d is: %d\n" string)), i, result) } } } +// file{ package main; import fmt fmt; func main() { var fns []func(.arg_0 (const-type int)) .res.0 (const-type int); var recursiveFunc func(.arg_0 (const-type int)) .res.0 (const-type int); for i := (const (0 int)); i<~VPBlock(1,0)> < (const (3 int)); i<~VPBlock(1,0)>++ { recursiveFunc<~VPBlock(2,1)> = func func(num (const-type int)) .res.0 (const-type int){ x := i<~VPBlock(1,3)>; (const (println func(...interface {})))((const ("value of x: " string)), x); if num <= (const (0 int)) { return (const (1 int)) }; return num * recursiveFunc<~VPBlock(1,4)>(num - (const (1 int))) }, recursiveFunc<()~VPBlock(2,1)>>; fns = (const (append func([]func(int) int, ...func(int) int) []func(int) int))(fns, recursiveFunc<~VPBlock(2,1)>) }; for i, r := range fns { result := r(i); (const (ref(fmt) package{})).Printf((const ("Factorial of %d is: %d\n" string)), i, result) } } } // Output: // value of x: 3 diff --git a/gnovm/tests/files/heap_alloc_forloop9_1.gno b/gnovm/tests/files/heap_alloc_forloop9_1.gno index 3fd437d5bc4..7aa58f1ccd0 100644 --- a/gnovm/tests/files/heap_alloc_forloop9_1.gno +++ b/gnovm/tests/files/heap_alloc_forloop9_1.gno @@ -16,7 +16,7 @@ func main() { } // Preprocessed: -// file{ package main; func Search(n (const-type int), f func(.arg_0 (const-type int)) (const-type bool)) (const-type int) { f((const (1 int))); return (const (0 int)) }; func main() { for x := (const (0 int)); x<~VPBlock(1,0)> < (const (2 int)); x<~VPBlock(1,0)>++ { count := (const (0 int)); (const (println func(...interface {})))((const (" first: count: " string)), count<~VPBlock(1,1)>); Search((const (1 int)), func func(i (const-type int)) (const-type bool){ count<~VPBlock(1,2)>++; return (const-type bool)(i >= x<~VPBlock(1,3)>) }, x<()~VPBlock(1,0)>>); (const (println func(...interface {})))((const ("second: count: " string)), count<~VPBlock(1,1)>) } } } +// file{ package main; func Search(n (const-type int), f func(.arg_0 (const-type int)) .res.0 (const-type bool)) .res.0 (const-type int) { f((const (1 int))); return (const (0 int)) }; func main() { for x := (const (0 int)); x<~VPBlock(1,0)> < (const (2 int)); x<~VPBlock(1,0)>++ { count := (const (0 int)); (const (println func(...interface {})))((const (" first: count: " string)), count<~VPBlock(1,1)>); Search((const (1 int)), func func(i (const-type int)) .res.0 (const-type bool){ count<~VPBlock(1,2)>++; return (const-type bool)(i >= x<~VPBlock(1,3)>) }, x<()~VPBlock(1,0)>>); (const (println func(...interface {})))((const ("second: count: " string)), count<~VPBlock(1,1)>) } } } // Output: // first: count: 0 diff --git a/gnovm/tests/files/heap_alloc_forloop9_2.gno b/gnovm/tests/files/heap_alloc_forloop9_2.gno index 6c731500e22..cb2e378a7ec 100644 --- a/gnovm/tests/files/heap_alloc_forloop9_2.gno +++ b/gnovm/tests/files/heap_alloc_forloop9_2.gno @@ -23,7 +23,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); (const (println func(...interface {})))((const ("start for loop" string))); for i := (const (0 int)); i < (const (2 int)); i++ { defer func func(){ (const (println func(...interface {})))((const ("defer" string))); for _, fn := range fns { (const (println func(...interface {})))(fn()) } }(); x := i; f := func func() (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; (const (println func(...interface {})))((const ("end for loop" string))) } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); (const (println func(...interface {})))((const ("start for loop" string))); for i := (const (0 int)); i < (const (2 int)); i++ { defer func func(){ (const (println func(...interface {})))((const ("defer" string))); for _, fn := range fns<~VPBlock(2,0)> { (const (println func(...interface {})))(fn()) } }>(); x := i; f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }>; fns<~VPBlock(2,0)> = (const (append func([]func() int, ...func() int) []func() int))(fns<~VPBlock(2,0)>, f) }; (const (println func(...interface {})))((const ("end for loop" string))) } } // Output: // start for loop diff --git a/gnovm/tests/files/heap_alloc_forloop9b.gno b/gnovm/tests/files/heap_alloc_forloop9b.gno index d58624dab3a..f5d9028a87c 100644 --- a/gnovm/tests/files/heap_alloc_forloop9b.gno +++ b/gnovm/tests/files/heap_alloc_forloop9b.gno @@ -19,7 +19,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var y (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); for i := (const (0 int)); i < (const (2 int)); i++ { for j := (const (0 int)); j < (const (2 int)); j++ { x := y; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++ } } } } +// file{ package main; func main() { var y (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); for i := (const (0 int)); i < (const (2 int)); i++ { for j := (const (0 int)); j < (const (2 int)); j++ { x := y; f<~VPBlock(3,1)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(3,1)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++ } } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop0.gno b/gnovm/tests/files/heap_alloc_gotoloop0.gno index d9b04756c0b..5a07766c111 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop0.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop0.gno @@ -21,7 +21,7 @@ LABEL_1: } // Preprocessed: -// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); if counter == (const (2 int)) { return }; x := counter; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); counter++; goto LABEL_1<0,3> } } +// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); if counter == (const (2 int)) { return }; x := counter; f<~VPBlock(1,1)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(1,1)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); counter++; goto LABEL_1<0,3> } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop2.gno b/gnovm/tests/files/heap_alloc_gotoloop2.gno index db904e58ecc..91b6b8688d0 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop2.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop2.gno @@ -22,7 +22,7 @@ loop: // You can tell by the preprocess printout of i and i<()~...>. // Preprocessed: -// file{ package main; func main() { c := (const (0 int)); closures := []func(){}; i := c; closures = (const (append func([]func(), ...func()) []func()))(closures, func func(){ (const (println func(...interface {})))(i<~VPBlock(1,0)>) }>); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, cl := range closures { cl() } } } +// file{ package main; func main() { c := (const (0 int)); closures := []func(){}; i := c; closures = (const (append func([]func(), ...func()) []func()))(closures, func func(){ (const (println func(...interface {})))(i<~VPBlock(1,0)>) }>); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, cl := range closures { cl() } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop3.gno b/gnovm/tests/files/heap_alloc_gotoloop3.gno index 6fc64db161e..b1c0d816ad5 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop3.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop3.gno @@ -19,7 +19,7 @@ loop: // You can tell by the preprocess printout of i and i<~...>. // Preprocessed: -// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; i := c; refs = (const (append func([]*int, ...*int) []*int))(refs, &(i<~VPBlock(1,2)>)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(...interface {})))(*(ref)) } } } +// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; i := c; refs = (const (append func([]*int, ...*int) []*int))(refs, &(i<~VPBlock(1,2)>)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(...interface {})))(*(ref)) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop4.gno b/gnovm/tests/files/heap_alloc_gotoloop4.gno index e626bef61cd..71c52ae08d2 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop4.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop4.gno @@ -19,7 +19,7 @@ loop: // You can tell by the preprocess printout of i and i<~...>. // Preprocessed: -// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; var i (const-type int) = c; refs = (const (append func([]*int, ...*int) []*int))(refs, &(i<~VPBlock(1,2)>)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(...interface {})))(*(ref)) } } } +// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; var i (const-type int) = c; refs = (const (append func([]*int, ...*int) []*int))(refs, &(i<~VPBlock(1,2)>)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(...interface {})))(*(ref)) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop5.gno b/gnovm/tests/files/heap_alloc_gotoloop5.gno index c9b8b2d859d..b18d38d86a0 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop5.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop5.gno @@ -24,7 +24,7 @@ loop: // You can tell by the preprocess printout of i and i<~...>. // Preprocessed: -// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; i, j := c, (const (2 int)); refs = (const (append func([]*int, ...*int) []*int))(refs, &(i<~VPBlock(1,2)>)); i<~VPBlock(1,2)> += (const (1 int)); j += (const (1 int)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(...interface {})))(*(ref)) }; if (const (false bool)) { (const (println func(...interface {})))(j) } } } +// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; i, j := c, (const (2 int)); refs = (const (append func([]*int, ...*int) []*int))(refs, &(i<~VPBlock(1,2)>)); i<~VPBlock(1,2)> += (const (1 int)); j += (const (1 int)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(...interface {})))(*(ref)) }; if (const (false bool)) { (const (println func(...interface {})))(j) } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop6.gno b/gnovm/tests/files/heap_alloc_gotoloop6.gno index 44410a3914e..7843b07af10 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop6.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop6.gno @@ -24,7 +24,7 @@ loop: // You can tell by the preprocess printout of i and i<~...>. // Preprocessed: -// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; var i, j (const-type int) = c, (const (2 int)); refs = (const (append func([]*int, ...*int) []*int))(refs, &(i<~VPBlock(1,2)>)); i<~VPBlock(1,2)> += (const (1 int)); j += (const (1 int)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(...interface {})))(*(ref)) }; if (const (false bool)) { (const (println func(...interface {})))(j) } } } +// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; var i, j (const-type int) = c, (const (2 int)); refs = (const (append func([]*int, ...*int) []*int))(refs, &(i<~VPBlock(1,2)>)); i<~VPBlock(1,2)> += (const (1 int)); j += (const (1 int)); c += (const (1 int)); if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(...interface {})))(*(ref)) }; if (const (false bool)) { (const (println func(...interface {})))(j) } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop7.gno b/gnovm/tests/files/heap_alloc_gotoloop7.gno index 90f179cc061..bc03b7142c9 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop7.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop7.gno @@ -33,7 +33,7 @@ loop: // You can tell by the preprocess printout of i and i<~...>. // Preprocessed: -// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; var i, j (const-type int) = c, (const (2 int)); refs = (const (append func([]*int, ...*int) []*int))(refs, &(i<~VPBlock(1,2)>)); i<~VPBlock(1,2)> += (const (1 int)); j += (const (1 int)); c += (const (1 int)); thing := func func(){ i := (const (2 int)); j := (const (3 int)); (const (println func(...interface {})))(i); (const (println func(...interface {})))(j) }; if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(...interface {})))(*(ref)) }; if (const (false bool)) { (const (println func(...interface {})))(j) }; if (const (false bool)) { thing() } } } +// file{ package main; func main() { c := (const (0 int)); refs := []*((const-type int)){}; var i, j (const-type int) = c, (const (2 int)); refs = (const (append func([]*int, ...*int) []*int))(refs, &(i<~VPBlock(1,2)>)); i<~VPBlock(1,2)> += (const (1 int)); j += (const (1 int)); c += (const (1 int)); thing := func func(){ i := (const (2 int)); j := (const (3 int)); (const (println func(...interface {})))(i); (const (println func(...interface {})))(j) }; if c < (const (10 int)) { goto loop<1,2> }; for _, ref := range refs { (const (println func(...interface {})))(*(ref)) }; if (const (false bool)) { (const (println func(...interface {})))(j) }; if (const (false bool)) { thing() } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop8.gno b/gnovm/tests/files/heap_alloc_gotoloop8.gno index cbfc1b7dce1..ea94b806ad1 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop8.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop8.gno @@ -22,7 +22,7 @@ loop2: // This one doesn't because the goto stmt doesn't go back far enough. // Preprocessed: -// file{ package main; func main() { c := (const (0 int)); closures := []func(){}; goto loop1<0,3>; i := (const (1 int)); closures = (const (append func([]func(), ...func()) []func()))(closures, func func(){ (const (println func(...interface {})))(i) }); c += (const (1 int)); if c < (const (10 int)) { goto loop2<1,4> }; for _, cl := range closures { cl() } } } +// file{ package main; func main() { c := (const (0 int)); closures := []func(){}; goto loop1<0,3>; i := (const (1 int)); closures = (const (append func([]func(), ...func()) []func()))(closures, func func(){ (const (println func(...interface {})))(i<~VPBlock(1,0)>) }>); c += (const (1 int)); if c < (const (10 int)) { goto loop2<1,4> }; for _, cl := range closures { cl() } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9.gno b/gnovm/tests/files/heap_alloc_gotoloop9.gno index d5ff671cabe..199eb67434a 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9.gno @@ -20,7 +20,7 @@ loop2: // This one doesn't because the goto stmt doesn't go back far enough. // Preprocessed: -// file{ package main; func main() { c := (const (0 int)); closures := []func(){}; i := (const (1 int)); closures = (const (append func([]func(), ...func()) []func()))(closures, func func(){ (const (println func(...interface {})))(i) }); c += (const (1 int)); if c < (const (10 int)) { goto loop2<1,3> }; for _, cl := range closures { cl() } } } +// file{ package main; func main() { c := (const (0 int)); closures := []func(){}; i := (const (1 int)); closures = (const (append func([]func(), ...func()) []func()))(closures, func func(){ (const (println func(...interface {})))(i<~VPBlock(1,0)>) }>); c += (const (1 int)); if c < (const (10 int)) { goto loop2<1,3> }; for _, cl := range closures { cl() } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_10.gno b/gnovm/tests/files/heap_alloc_gotoloop9_10.gno index 99ed4ded2b9..f82a12e1195 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_10.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_10.gno @@ -41,7 +41,7 @@ LOOP_2: } // Preprocessed: -// file{ package main; import fmt fmt; var s1 []*((const-type int)); var s2 []*((const-type int)); func main() { defer func func(){ for i, v := range s1 { fmt.Printf((const ("s1[%d] is %d\n" string)), i, *(v)) }; for i, v := range s2 { fmt.Printf((const ("s2[%d] is %d\n" string)), i, *(v)) } }(); var c1, c2 (const-type int); x := c1; s1 = (const (append func([]*int, ...*int) []*int))(s1, &(x<~VPBlock(1,2)>)); (const (println func(...interface {})))((const ("loop_1" string)), c1); c1++; y := c2; s2 = (const (append func([]*int, ...*int) []*int))(s2, &(y<~VPBlock(1,3)>)); (const (println func(...interface {})))((const ("loop_2" string)), c2); c2++; if c1 < (const (3 int)) { goto LOOP_1<1,2> }; if c2 < (const (6 int)) { goto LOOP_2<1,6> } } } +// file{ package main; import fmt fmt; var s1 []*((const-type int)); var s2 []*((const-type int)); func main() { defer func func(){ for i, v := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is %d\n" string)), i, *(v)) }; for i, v := range (const (ref(main) package{})).s2 { (const (ref(fmt) package{})).Printf((const ("s2[%d] is %d\n" string)), i, *(v)) } }(); var c1, c2 (const-type int); x := c1; s1<~VPBlock(3,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(3,0)>, &(x<~VPBlock(1,2)>)); (const (println func(...interface {})))((const ("loop_1" string)), c1); c1++; y := c2; s2<~VPBlock(3,1)> = (const (append func([]*int, ...*int) []*int))(s2<~VPBlock(3,1)>, &(y<~VPBlock(1,3)>)); (const (println func(...interface {})))((const ("loop_2" string)), c2); c2++; if c1 < (const (3 int)) { goto LOOP_1<1,2> }; if c2 < (const (6 int)) { goto LOOP_2<1,6> } } } // Output: // loop_1 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_11.gno b/gnovm/tests/files/heap_alloc_gotoloop9_11.gno index 46a35663c22..b23a3a5631d 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_11.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_11.gno @@ -22,7 +22,7 @@ LABEL_1: } // Preprocessed: -// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); if counter == (const (2 int)) { return }; var _, x = (const (0 int)), y; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,3> } } +// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); if counter == (const (2 int)) { return }; var _, x = (const (0 int)), y; f<~VPBlock(1,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(1,2)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,3> } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_12.gno b/gnovm/tests/files/heap_alloc_gotoloop9_12.gno index c3e4de05cca..bc8120c237a 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_12.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_12.gno @@ -41,7 +41,7 @@ LOOP_START: } // Preprocessed: -// file{ package main; import fmt fmt; func main() { counter0 := (const (0 int)); counter1 := (const (0 int)); y := (const (0 int)); var fs []func(); defer func func(){ for _, ff := range fs { ff() } }(); if counter0 < (const (2 int)) { counter1 = (const (0 int)); fmt.Printf((const ("Outer loop start: counter0=%d\n" string)), counter0); if counter1 < (const (2 int)) { fmt.Printf((const (" Nested loop: counter1=%d\n" string)), counter1); counter1++; goto NESTED_LOOP_START<1,2> }; x := y; fs = (const (append func([]func(), ...func()) []func()))(fs, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); fmt.Println((const ("Exiting nested loop" string))); counter0++; y++; goto LOOP_START<1,5> } else { return } } } +// file{ package main; import fmt fmt; func main() { counter0 := (const (0 int)); counter1 := (const (0 int)); y := (const (0 int)); var fs []func(); defer func func(){ for _, ff := range fs<~VPBlock(2,0)> { ff() } }>(); if counter0 < (const (2 int)) { counter1 = (const (0 int)); (const (ref(fmt) package{})).Printf((const ("Outer loop start: counter0=%d\n" string)), counter0); if counter1 < (const (2 int)) { (const (ref(fmt) package{})).Printf((const (" Nested loop: counter1=%d\n" string)), counter1); counter1++; goto NESTED_LOOP_START<1,2> }; x := y; fs<~VPBlock(2,3)> = (const (append func([]func(), ...func()) []func()))(fs<~VPBlock(2,3)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); (const (ref(fmt) package{})).Println((const ("Exiting nested loop" string))); counter0++; y++; goto LOOP_START<1,5> } else { return } } } // Output: // Outer loop start: counter0=0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_13.gno b/gnovm/tests/files/heap_alloc_gotoloop9_13.gno index 0d2d9445b02..23c32e62aa0 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_13.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_13.gno @@ -32,7 +32,7 @@ LABEL_2: } // Preprocessed: -// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); x := y; if counter == (const (2 int)) { counter = (const (0 int)); goto LABEL_2<1,9> }; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,3>; if counter == (const (2 int)) { return }; z := y; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_2<0,9> } } +// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); x := y; if counter == (const (2 int)) { counter = (const (0 int)); goto LABEL_2<1,9> }; f<~VPBlock(1,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(1,2)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,3>; if counter == (const (2 int)) { return }; z := y; f<~VPBlock(1,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(1,2)>, func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_2<0,9> } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_14.gno b/gnovm/tests/files/heap_alloc_gotoloop9_14.gno index db17db46477..c94a7d500c2 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_14.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_14.gno @@ -34,7 +34,7 @@ LABEL_2: } // Preprocessed: -// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); { x := y; if counter == (const (2 int)) { counter = (const (0 int)); goto LABEL_2<2,4> }; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,0> }; if counter == (const (2 int)) { return }; z := y; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_2<0,4> } } +// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); { x := y; if counter == (const (2 int)) { counter = (const (0 int)); goto LABEL_2<2,4> }; f<~VPBlock(2,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(2,2)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,0> }; if counter == (const (2 int)) { return }; z := y; f<~VPBlock(1,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(1,2)>, func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_2<0,4> } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_15.gno b/gnovm/tests/files/heap_alloc_gotoloop9_15.gno index b4df1c1c5e0..f2560e22a38 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_15.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_15.gno @@ -37,7 +37,7 @@ LABEL_2: } // Preprocessed: -// file{ package main; var y, counter (const-type int); var f []func(); func main() { defer func func(){ for _, ff := range f { ff() } }(); x := y; if counter == (const (2 int)) { counter = (const (0 int)); bar(); return }; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,1> }; func bar() { (const (println func(...interface {})))((const ("---bar---" string))); if counter == (const (2 int)) { (const (println func(...interface {})))((const ("---end---" string))); return }; z := y; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_2<0,1> } } +// file{ package main; var y, counter (const-type int); var f []func(); func main() { defer func func(){ for _, ff := range (const (ref(main) package{})).f { ff() } }(); x := y<~VPBlock(3,0)>; if counter<~VPBlock(4,1)> == (const (2 int)) { counter<~VPBlock(4,1)> = (const (0 int)); bar(); return }; f<~VPBlock(3,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(3,2)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y<~VPBlock(3,0)>++; counter<~VPBlock(3,1)>++; goto LABEL_1<0,1> }; func bar() { (const (println func(...interface {})))((const ("---bar---" string))); if counter<~VPBlock(4,1)> == (const (2 int)) { (const (println func(...interface {})))((const ("---end---" string))); return }; z := y<~VPBlock(3,0)>; f<~VPBlock(3,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(3,2)>, func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>); y<~VPBlock(3,0)>++; counter<~VPBlock(3,1)>++; goto LABEL_2<0,1> } } // Output: // ---bar--- diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_15a.gno b/gnovm/tests/files/heap_alloc_gotoloop9_15a.gno index ff5cfc99f8d..eb2b43a03af 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_15a.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_15a.gno @@ -35,7 +35,7 @@ LABEL_2: } // Preprocessed: -// file{ package main; var y, counter (const-type int); var f []func(); func main() { x := y; if counter == (const (2 int)) { counter = (const (0 int)); bar(); for _, ff := range f { ff() }; return }; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,0> }; func bar() { (const (println func(...interface {})))((const ("---bar---" string))); if counter == (const (2 int)) { (const (println func(...interface {})))((const ("---end---" string))); return }; z := y; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_2<0,1> } } +// file{ package main; var y, counter (const-type int); var f []func(); func main() { x := y<~VPBlock(3,0)>; if counter<~VPBlock(4,1)> == (const (2 int)) { counter<~VPBlock(4,1)> = (const (0 int)); bar(); for _, ff := range f<~VPBlock(5,2)> { ff() }; return }; f<~VPBlock(3,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(3,2)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y<~VPBlock(3,0)>++; counter<~VPBlock(3,1)>++; goto LABEL_1<0,0> }; func bar() { (const (println func(...interface {})))((const ("---bar---" string))); if counter<~VPBlock(4,1)> == (const (2 int)) { (const (println func(...interface {})))((const ("---end---" string))); return }; z := y<~VPBlock(3,0)>; f<~VPBlock(3,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(3,2)>, func func(){ (const (println func(...interface {})))(z<~VPBlock(1,0)>) }>); y<~VPBlock(3,0)>++; counter<~VPBlock(3,1)>++; goto LABEL_2<0,1> } } // Output: // ---bar--- diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_16.gno b/gnovm/tests/files/heap_alloc_gotoloop9_16.gno index 6ec3e814af7..adf63039919 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_16.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_16.gno @@ -41,7 +41,7 @@ LOOP_START: } // Preprocessed: -// file{ package main; import fmt fmt; func main() { counter0 := (const (0 int)); counter1 := (const (0 int)); y := (const (0 int)); var fs []func(); defer func func(){ for _, ff := range fs { ff() } }(); if counter0 < (const (2 int)) { x := y; counter1 = (const (0 int)); fmt.Printf((const ("Outer loop start: counter0=%d\n" string)), counter0); if counter1 < (const (2 int)) { fmt.Printf((const (" Nested loop: counter1=%d\n" string)), counter1); fs = (const (append func([]func(), ...func()) []func()))(fs, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); counter1++; goto NESTED_LOOP_START<1,3> }; fmt.Println((const ("Exiting nested loop" string))); counter0++; y++; goto LOOP_START<1,5> } else { return } } } +// file{ package main; import fmt fmt; func main() { counter0 := (const (0 int)); counter1 := (const (0 int)); y := (const (0 int)); var fs []func(); defer func func(){ for _, ff := range fs<~VPBlock(2,0)> { ff() } }>(); if counter0 < (const (2 int)) { x := y; counter1 = (const (0 int)); (const (ref(fmt) package{})).Printf((const ("Outer loop start: counter0=%d\n" string)), counter0); if counter1 < (const (2 int)) { (const (ref(fmt) package{})).Printf((const (" Nested loop: counter1=%d\n" string)), counter1); fs<~VPBlock(3,3)> = (const (append func([]func(), ...func()) []func()))(fs<~VPBlock(3,3)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); counter1++; goto NESTED_LOOP_START<1,3> }; (const (ref(fmt) package{})).Println((const ("Exiting nested loop" string))); counter0++; y++; goto LOOP_START<1,5> } else { return } } } // Output: // Outer loop start: counter0=0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_17.gno b/gnovm/tests/files/heap_alloc_gotoloop9_17.gno index 1e876973a8f..e6c97dd7558 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_17.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_17.gno @@ -41,7 +41,7 @@ LOOP_START: } // Preprocessed: -// file{ package main; import fmt fmt; func main() { counter0 := (const (0 int)); counter1 := (const (0 int)); y := (const (0 int)); var fs []func(); defer func func(){ for _, ff := range fs { ff() } }(); x := y; if counter0 < (const (2 int)) { counter1 = (const (0 int)); fmt.Printf((const ("Outer loop start: counter0=%d\n" string)), counter0); if counter1 < (const (2 int)) { fmt.Printf((const (" Nested loop: counter1=%d\n" string)), counter1); fs = (const (append func([]func(), ...func()) []func()))(fs, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); counter1++; goto NESTED_LOOP_START<1,2> }; fmt.Println((const ("Exiting nested loop" string))); counter0++; y++; goto LOOP_START<1,5> } else { return } } } +// file{ package main; import fmt fmt; func main() { counter0 := (const (0 int)); counter1 := (const (0 int)); y := (const (0 int)); var fs []func(); defer func func(){ for _, ff := range fs<~VPBlock(2,0)> { ff() } }>(); x := y; if counter0 < (const (2 int)) { counter1 = (const (0 int)); (const (ref(fmt) package{})).Printf((const ("Outer loop start: counter0=%d\n" string)), counter0); if counter1 < (const (2 int)) { (const (ref(fmt) package{})).Printf((const (" Nested loop: counter1=%d\n" string)), counter1); fs<~VPBlock(3,3)> = (const (append func([]func(), ...func()) []func()))(fs<~VPBlock(3,3)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); counter1++; goto NESTED_LOOP_START<1,2> }; (const (ref(fmt) package{})).Println((const ("Exiting nested loop" string))); counter0++; y++; goto LOOP_START<1,5> } else { return } } } // Output: // Outer loop start: counter0=0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_18.gno b/gnovm/tests/files/heap_alloc_gotoloop9_18.gno index be6fe21bcad..a78a1eadf04 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_18.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_18.gno @@ -23,7 +23,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); { if counter == (const (2 int)) { return }; x := y; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,0> } } } +// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); { if counter == (const (2 int)) { return }; x := y; f<~VPBlock(2,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(2,2)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,0> } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_19.gno b/gnovm/tests/files/heap_alloc_gotoloop9_19.gno index fdcd1fc6074..458c4eb24f7 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_19.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_19.gno @@ -23,7 +23,7 @@ LABEL_1: } // Preprocessed: -// file{ package main; func main() { var y, counter (const-type int); var f []func() func() (const-type int); defer func func(){ for _, ff := range f { (const (println func(...interface {})))(ff()()) } }(); if counter == (const (2 int)) { return }; x := y; f = (const (append func([]func() func() int, ...func() func() int) []func() func() int))(f, func func() func() (const-type int){ return func func() (const-type int){ return x<~VPBlock(2,1)> } }>); y++; counter++; goto LABEL_1<0,3> } } +// file{ package main; func main() { var y, counter (const-type int); var f []func() .res.0 func() .res.0 (const-type int); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { (const (println func(...interface {})))(ff()()) } }>(); if counter == (const (2 int)) { return }; x := y; f<~VPBlock(1,2)> = (const (append func([]func() func() int, ...func() func() int) []func() func() int))(f<~VPBlock(1,2)>, func func() .res.0 func() .res.0 (const-type int){ return func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }> }>); y++; counter++; goto LABEL_1<0,3> } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_20.gno b/gnovm/tests/files/heap_alloc_gotoloop9_20.gno index 22013f57a45..8e327c0a770 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_20.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_20.gno @@ -25,7 +25,7 @@ LABEL_1: } // Preprocessed: -// file{ package main; func main() { var y, counter (const-type int); var f []func() (const-type int), func() (const-type int); defer func func(){ for _, ff := range f { n, f := ff(); (const (println func(...interface {})))(n + f()) } }(); if counter == (const (2 int)) { return }; x := y; z := y; f = (const (append func([]func() (int, func() int), ...func() (int, func() int)) []func() (int, func() int)))(f, func func() (const-type int), func() (const-type int){ return z<~VPBlock(1,2)>, func func() (const-type int){ return x<~VPBlock(2,3)> } }, x<()~VPBlock(1,3)>>); y++; counter++; goto LABEL_1<0,3> } } +// file{ package main; func main() { var y, counter (const-type int); var f []func() .res.0 (const-type int), .res.1 func() .res.0 (const-type int); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { n, f := ff(); (const (println func(...interface {})))(n + f()) } }>(); if counter == (const (2 int)) { return }; x := y; z := y; f<~VPBlock(1,2)> = (const (append func([]func() (int, func() int), ...func() (int, func() int)) []func() (int, func() int)))(f<~VPBlock(1,2)>, func func() .res.0 (const-type int), .res.1 func() .res.0 (const-type int){ return z<~VPBlock(1,2)>, func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }> }, x<()~VPBlock(1,3)>>); y++; counter++; goto LABEL_1<0,3> } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_21.gno b/gnovm/tests/files/heap_alloc_gotoloop9_21.gno index 99852abf6df..1680e4ec8ac 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_21.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_21.gno @@ -24,7 +24,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); f1 := func func(){ if counter == (const (2 int)) { return }; x := counter; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); counter++; goto LABEL_1<0,0> }; f1() } } +// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); f1 := func func(){ if counter<~VPBlock(2,1)> == (const (2 int)) { return }; x := counter<~VPBlock(1,1)>; f<~VPBlock(1,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(1,2)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); counter<~VPBlock(1,1)>++; goto LABEL_1<0,0> }, f<()~VPBlock(1,1)>>; f1() } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_21a.gno b/gnovm/tests/files/heap_alloc_gotoloop9_21a.gno index 58c7ba421dc..484277af5d2 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_21a.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_21a.gno @@ -26,7 +26,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); f1 := func func(){ if counter == (const (2 int)) { return }; x := counter; func func(){ f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x<~VPBlock(2,0)>) }) }>(); counter++; goto LABEL_1<0,0> }; f1() } } +// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); f1 := func func(){ if counter<~VPBlock(2,1)> == (const (2 int)) { return }; x := counter<~VPBlock(1,1)>; func func(){ f<~VPBlock(1,0)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(1,0)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>) }, x<()~VPBlock(1,0)>>(); counter<~VPBlock(1,1)>++; goto LABEL_1<0,0> }, f<()~VPBlock(1,1)>>; f1() } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_21b.gno b/gnovm/tests/files/heap_alloc_gotoloop9_21b.gno index c5c3cf6f5bf..81008714b6c 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_21b.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_21b.gno @@ -27,7 +27,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); f1 := func func(){ if counter == (const (2 int)) { return }; func func(){ x := counter; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x) }) }(); counter++; goto LABEL_1<0,0> }; f1() } } +// file{ package main; func main() { var counter (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); f1 := func func(){ if counter<~VPBlock(2,0)> == (const (2 int)) { return }; func func(){ x := counter<~VPBlock(1,1)>; f<~VPBlock(1,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(1,2)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>) }, f<()~VPBlock(1,1)>>(); counter<~VPBlock(1,0)>++; goto LABEL_1<0,0> }, f<()~VPBlock(1,1)>>; f1() } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_gotoloop9_22.gno b/gnovm/tests/files/heap_alloc_gotoloop9_22.gno index ee55056f681..1ce41f81b12 100644 --- a/gnovm/tests/files/heap_alloc_gotoloop9_22.gno +++ b/gnovm/tests/files/heap_alloc_gotoloop9_22.gno @@ -24,7 +24,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f { ff() } }(); for i := (const (0 int)); i < (const (2 int)); i++ { counter = (const (0 int)); if counter == (const (2 int)) { continue }; x := y; f = (const (append func([]func(), ...func()) []func()))(f, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,1> } } } +// file{ package main; func main() { var y, counter (const-type int); var f []func(); defer func func(){ for _, ff := range f<~VPBlock(2,0)> { ff() } }>(); for i := (const (0 int)); i < (const (2 int)); i++ { counter = (const (0 int)); if counter == (const (2 int)) { continue }; x := y; f<~VPBlock(2,2)> = (const (append func([]func(), ...func()) []func()))(f<~VPBlock(2,2)>, func func(){ (const (println func(...interface {})))(x<~VPBlock(1,0)>) }>); y++; counter++; goto LABEL_1<0,1> } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_range1.gno b/gnovm/tests/files/heap_alloc_range1.gno index 7623e132866..d889ea9657d 100644 --- a/gnovm/tests/files/heap_alloc_range1.gno +++ b/gnovm/tests/files/heap_alloc_range1.gno @@ -22,9 +22,9 @@ func main() { } // Preprocessed: -// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); s := [](const-type int){(const (0 int)), (const (1 int)), (const (2 int))}; for i, _ := range s { s1 = (const (append func([]*int, ...*int) []*int))(s1, &(i)) } }; func main() { forLoopRef() } } +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); s := [](const-type int){(const (0 int)), (const (1 int)), (const (2 int))}; for i, _ := range s { s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(i<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } // Output: -// s1[0] is: 2 -// s1[1] is: 2 +// s1[0] is: 0 +// s1[1] is: 1 // s1[2] is: 2 diff --git a/gnovm/tests/files/heap_alloc_range2.gno b/gnovm/tests/files/heap_alloc_range2.gno index 0f39b45ee2a..01fa740b4d3 100644 --- a/gnovm/tests/files/heap_alloc_range2.gno +++ b/gnovm/tests/files/heap_alloc_range2.gno @@ -22,9 +22,9 @@ func main() { } // Preprocessed: -// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range s1 { fmt.Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); s := [](const-type int){(const (0 int)), (const (1 int)), (const (2 int))}; for _, v := range s { s1 = (const (append func([]*int, ...*int) []*int))(s1, &(v)) } }; func main() { forLoopRef() } } +// file{ package main; import fmt fmt; var s1 []*((const-type int)); func forLoopRef() { defer func func(){ for i, e := range (const (ref(main) package{})).s1 { (const (ref(fmt) package{})).Printf((const ("s1[%d] is: %d\n" string)), i, *(e)) } }(); s := [](const-type int){(const (0 int)), (const (1 int)), (const (2 int))}; for _, v := range s { s1<~VPBlock(4,0)> = (const (append func([]*int, ...*int) []*int))(s1<~VPBlock(4,0)>, &(v<~VPBlock(1,0)>)) } }; func main() { forLoopRef() } } // Output: -// s1[0] is: 2 -// s1[1] is: 2 +// s1[0] is: 0 +// s1[1] is: 1 // s1[2] is: 2 diff --git a/gnovm/tests/files/heap_alloc_range3.gno b/gnovm/tests/files/heap_alloc_range3.gno index e10a82fbedd..22c88ade8af 100644 --- a/gnovm/tests/files/heap_alloc_range3.gno +++ b/gnovm/tests/files/heap_alloc_range3.gno @@ -14,7 +14,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { s := [](const-type int){(const (1 int)), (const (2 int))}; f := func func(){ for i, v := range s { (const (println func(...interface {})))(i); (const (println func(...interface {})))(v) } }; f() } } +// file{ package main; func main() { s := [](const-type int){(const (1 int)), (const (2 int))}; f := func func(){ for i, v := range s<~VPBlock(2,0)> { (const (println func(...interface {})))(i); (const (println func(...interface {})))(v) } }>; f() } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_range4.gno b/gnovm/tests/files/heap_alloc_range4.gno index 7a8dffbb091..5a9ca3adb0a 100644 --- a/gnovm/tests/files/heap_alloc_range4.gno +++ b/gnovm/tests/files/heap_alloc_range4.gno @@ -16,7 +16,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); s := [](const-type int){(const (1 int)), (const (2 int)), (const (3 int))}; for i, _ := range s { x := i; f := func func() (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); s := [](const-type int){(const (1 int)), (const (2 int)), (const (3 int))}; for i, _ := range s { x := i; f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_range4a.gno b/gnovm/tests/files/heap_alloc_range4a.gno index 7f921ffe093..33af41de051 100644 --- a/gnovm/tests/files/heap_alloc_range4a.gno +++ b/gnovm/tests/files/heap_alloc_range4a.gno @@ -19,7 +19,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); m := map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))}; for _, v := range m { x := v; f := func func() (const-type int){ if (const (true bool)) { return x<~VPBlock(2,1)> }; return (const (0 int)) }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); m := map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))}; for _, v := range m { x := v; f := func func() .res.0 (const-type int){ if (const (true bool)) { return x<~VPBlock(2,1)> }; return (const (0 int)) }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_range4a1.gno b/gnovm/tests/files/heap_alloc_range4a1.gno index 4f70ca616f2..19b8ab00c0b 100644 --- a/gnovm/tests/files/heap_alloc_range4a1.gno +++ b/gnovm/tests/files/heap_alloc_range4a1.gno @@ -15,8 +15,8 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); m := map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))}; for _, v := range m { f := func func() (const-type int){ return v }; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); m := map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))}; for _, v := range m { f := func func() .res.0 (const-type int){ return v<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: -// 2 +// 1 // 2 diff --git a/gnovm/tests/files/heap_alloc_range4a2.gno b/gnovm/tests/files/heap_alloc_range4a2.gno index a554b024d62..934562ed33b 100644 --- a/gnovm/tests/files/heap_alloc_range4a2.gno +++ b/gnovm/tests/files/heap_alloc_range4a2.gno @@ -25,7 +25,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); y := (const (0 int)); m := map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))}; for _, v := range m { x := v; f := func func() (const-type int){ switch y { case (const (0 int)): if (const (true bool)) { return x<~VPBlock(3,1)> }; default: return (const (0 int)) }; return (const (0 int)) }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); y := (const (0 int)); m := map[(const-type string)] (const-type int){(const ("a" string)): (const (1 int)), (const ("b" string)): (const (2 int))}; for _, v := range m { x := v; f := func func() .res.0 (const-type int){ switch y<~VPBlock(2,1)> { case (const (0 int)): if (const (true bool)) { return x<~VPBlock(3,2)> }; default: return (const (0 int)) }; return (const (0 int)) }, x<()~VPBlock(1,1)>>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 1 diff --git a/gnovm/tests/files/heap_alloc_range4b.gno b/gnovm/tests/files/heap_alloc_range4b.gno index 7c66bdfcce6..6e399b9a99f 100644 --- a/gnovm/tests/files/heap_alloc_range4b.gno +++ b/gnovm/tests/files/heap_alloc_range4b.gno @@ -16,7 +16,7 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); s := (const ("hello" string)); for i, _ := range s { x := i; f := func func() (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); s := (const ("hello" string)); for i, _ := range s { x := i; f := func func() .res.0 (const-type int){ return x<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: // 0 diff --git a/gnovm/tests/files/heap_alloc_range4b1.gno b/gnovm/tests/files/heap_alloc_range4b1.gno index 523c9d24935..e8600abd983 100644 --- a/gnovm/tests/files/heap_alloc_range4b1.gno +++ b/gnovm/tests/files/heap_alloc_range4b1.gno @@ -15,11 +15,11 @@ func main() { } // Preprocessed: -// file{ package main; func main() { var fns []func() (const-type int); s := (const ("hello" string)); for i, _ := range s { f := func func() (const-type int){ return i }; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } +// file{ package main; func main() { var fns []func() .res.0 (const-type int); s := (const ("hello" string)); for i, _ := range s { f := func func() .res.0 (const-type int){ return i<~VPBlock(1,1)> }>; fns = (const (append func([]func() int, ...func() int) []func() int))(fns, f) }; for _, fn := range fns { (const (println func(...interface {})))(fn()) } } } // Output: -// 4 -// 4 -// 4 -// 4 +// 0 +// 1 +// 2 +// 3 // 4 diff --git a/gnovm/tests/files/heap_item_value.gno b/gnovm/tests/files/heap_item_value.gno index ffddb5f3ad3..ebfc2a5de8b 100644 --- a/gnovm/tests/files/heap_item_value.gno +++ b/gnovm/tests/files/heap_item_value.gno @@ -8,6 +8,8 @@ type S struct { var a, b *S func main() { + crossing() + a = new(S) a.A = 4 b = a @@ -15,7 +17,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ // "Fields": [ // { // "N": "BAAAAAAAAAA=", @@ -26,15 +28,15 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "IsEscaped": true, // "ModTime": "0", // "RefCount": "2" @@ -46,43 +48,62 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "8c001dde13b1f4dc01fc6d3a5bb4bc0cdfe2a50b", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// "Hash": "624f026b2961f3570f2ec9cbc3330418955c4895", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -54,6 +54,16 @@ -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.S" -// } -// + }, -// + "V": { -// + "@type": "/gno.PointerValue", -// + "Base": { -// + "@type": "/gno.RefValue", -// + "Escaped": true, -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// + }, -// + "Index": "0", -// + "TV": null +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,7 +1,7 @@ +// { +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "0", +// + "ModTime": "6", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" +// }, +// @@ -12,6 +12,16 @@ +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" // } -// }, -// { -// @@ -63,6 +73,16 @@ -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.S" -// } +// + }, +// + "V": { +// + "@type": "/gno.PointerValue", +// + "Base": { +// + "@type": "/gno.RefValue", +// + "Escaped": true, +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" // + }, -// + "V": { -// + "@type": "/gno.PointerValue", -// + "Base": { -// + "@type": "/gno.RefValue", -// + "Escaped": true, -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// + }, -// + "Index": "0", -// + "TV": null +// + "Index": "0", +// + "TV": null +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= +// @@ -1,7 +1,7 @@ +// { +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// - "ModTime": "0", +// + "ModTime": "6", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" +// }, +// @@ -12,6 +12,16 @@ +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" // } -// }, -// { +// + }, +// + "V": { +// + "@type": "/gno.PointerValue", +// + "Base": { +// + "@type": "/gno.RefValue", +// + "Escaped": true, +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// + }, +// + "Index": "0", +// + "TV": null +// } +// } +// } diff --git a/gnovm/tests/files/heap_item_value_init.gno b/gnovm/tests/files/heap_item_value_init.gno index a6e90c89dc2..63cb48bcefc 100644 --- a/gnovm/tests/files/heap_item_value_init.gno +++ b/gnovm/tests/files/heap_item_value_init.gno @@ -14,56 +14,49 @@ func init() { } func main() { + crossing() + b = a } // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -3,7 +3,7 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// - "ModTime": "3", -// + "ModTime": "6", -// "RefCount": "2" +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// - "ModTime": "0", +// + "ModTime": "10", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -62,7 +62,7 @@ -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// - "Hash": "4f679d9dc2ea37d8f31b020193e7afae0236c97c", -// + "Escaped": true, -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", -// @@ -76,6 +76,16 @@ -// "@type": "/gno.RefType", -// "ID": "gno.land/r/test.S" -// } -// + }, -// + "V": { -// + "@type": "/gno.PointerValue", -// + "Base": { -// + "@type": "/gno.RefValue", -// + "Escaped": true, -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// + }, -// + "Index": "0", -// + "TV": null +// @@ -12,6 +12,16 @@ +// "@type": "/gno.RefType", +// "ID": "gno.land/r/test.S" // } -// }, -// { -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= +// + }, +// + "V": { +// + "@type": "/gno.PointerValue", +// + "Base": { +// + "@type": "/gno.RefValue", +// + "Escaped": true, +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// + }, +// + "Index": "0", +// + "TV": null +// } +// } +// } +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]= // @@ -1,9 +1,10 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // - "ModTime": "0", // + "IsEscaped": true, -// + "ModTime": "6", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// + "ModTime": "10", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // - "RefCount": "1" // + "RefCount": "2" // }, diff --git a/gnovm/tests/files/heap_return0.gno b/gnovm/tests/files/heap_return0.gno new file mode 100644 index 00000000000..7c14768827b --- /dev/null +++ b/gnovm/tests/files/heap_return0.gno @@ -0,0 +1,36 @@ +package main + +import "fmt" + +type Foo struct{} + +func (foo *Foo) blah(x int, y int) (z int, cb1 func()) { + a := func(b int, c int) (d int, e int, cb2 func()) { + return 0, 100, func() { + b++ + c++ + d++ + e++ + x++ + y++ + z++ + fmt.Println(b, c, d, e, x, y, z) // 201 301 1 101 -99 -99 401 + } + } + d2, e2, cb2 := a(200, 300) + fmt.Println(d2, e2) // 0 100 + x, y, z = -100, -100, -100 + return 400, cb2 +} + +func main() { + foo := &Foo{} + z, cb1 := foo.blah(500, 600) + cb1() + fmt.Println(z) // 400 +} + +// Output: +// 0 100 +// 201 301 1 101 -99 -99 401 +// 400 diff --git a/gnovm/tests/files/interface48.gno b/gnovm/tests/files/interface48.gno index 62cc6619f64..efd0f25cf3e 100644 --- a/gnovm/tests/files/interface48.gno +++ b/gnovm/tests/files/interface48.gno @@ -18,4 +18,4 @@ func main() { } // Output: -// nil +// undefined diff --git a/gnovm/tests/files/issue-2449.gno b/gnovm/tests/files/issue-2449.gno index 6af4dbafc6c..b6c9bbc1b67 100644 --- a/gnovm/tests/files/issue-2449.gno +++ b/gnovm/tests/files/issue-2449.gno @@ -45,6 +45,8 @@ func printEvents(events []*Event) { } func main() { + crossing() + DelEvent("event2") InsertEvent("event1.5") AppendEvent("event2") diff --git a/gnovm/tests/files/issue_1326.gno b/gnovm/tests/files/issue_1326.gno index a86058a63e0..70e695053c6 100644 --- a/gnovm/tests/files/issue_1326.gno +++ b/gnovm/tests/files/issue_1326.gno @@ -11,6 +11,8 @@ func init() { } func main() { + crossing() + println(Delta()) } diff --git a/gnovm/tests/files/panic0a.gno b/gnovm/tests/files/panic0a.gno index 307a1ce9780..242457d445e 100644 --- a/gnovm/tests/files/panic0a.gno +++ b/gnovm/tests/files/panic0a.gno @@ -36,7 +36,7 @@ func main() { // Stacktrace: // panic: wtf -// f(v.((const-type int)),lit[0],*pit,&vit,!b,[](const-type string),S,map[(const-type string)] (const-type string),func(s (const-type string)) (const-type string){ ... }) +// f(v.((const-type int)),lit[0],*pit,&vit<~VPBlock(1,0)>,!b,[](const-type string),S,map[(const-type string)] (const-type string),func(s (const-type string)) .res.0 (const-type string){ ... }) // main/files/panic0a.gno:9 // main() // main/files/panic0a.gno:22 diff --git a/gnovm/tests/files/persist_map.gno b/gnovm/tests/files/persist_map.gno index 53a1ad80f77..467137f1701 100644 --- a/gnovm/tests/files/persist_map.gno +++ b/gnovm/tests/files/persist_map.gno @@ -10,6 +10,8 @@ func init() { } func main() { + crossing() + println("premain", amap) amap["c"] = "3" println("postmain", amap) diff --git a/gnovm/tests/files/ptrmap_1.gno b/gnovm/tests/files/ptrmap_1.gno index 4e496a82f39..b0b66dcdf33 100644 --- a/gnovm/tests/files/ptrmap_1.gno +++ b/gnovm/tests/files/ptrmap_1.gno @@ -19,6 +19,8 @@ func init() { } func main() { + crossing() + r := GetFromMap() println(r == 5) } diff --git a/gnovm/tests/files/ptrmap_10.gno b/gnovm/tests/files/ptrmap_10.gno index 92f61f557cb..fb985f679bb 100644 --- a/gnovm/tests/files/ptrmap_10.gno +++ b/gnovm/tests/files/ptrmap_10.gno @@ -12,6 +12,8 @@ func init() { } func main() { + crossing() + println(m[arr[0]]) // Output: first key println(m[arr[1]] == "") } diff --git a/gnovm/tests/files/ptrmap_11.gno b/gnovm/tests/files/ptrmap_11.gno index 6ffeed62f0b..1a6f375a490 100644 --- a/gnovm/tests/files/ptrmap_11.gno +++ b/gnovm/tests/files/ptrmap_11.gno @@ -13,6 +13,8 @@ func init() { } func main() { + crossing() + println(m[S[index]]) // Output: first key println(m[S[1]] == "") } diff --git a/gnovm/tests/files/ptrmap_12.gno b/gnovm/tests/files/ptrmap_12.gno index b0360fb5cef..783068c333d 100644 --- a/gnovm/tests/files/ptrmap_12.gno +++ b/gnovm/tests/files/ptrmap_12.gno @@ -12,6 +12,8 @@ func init() { } func main() { + crossing() + println(m[S[0]]) // Output: first key println(m[S[1]] == "") } diff --git a/gnovm/tests/files/ptrmap_13.gno b/gnovm/tests/files/ptrmap_13.gno index 0e0d24c6865..51ce6d9fc85 100644 --- a/gnovm/tests/files/ptrmap_13.gno +++ b/gnovm/tests/files/ptrmap_13.gno @@ -15,6 +15,8 @@ func init() { } func main() { + crossing() + println(m[s[myStruct.Index]]) } diff --git a/gnovm/tests/files/ptrmap_14.gno b/gnovm/tests/files/ptrmap_14.gno index 5eb4c436def..7747594f277 100644 --- a/gnovm/tests/files/ptrmap_14.gno +++ b/gnovm/tests/files/ptrmap_14.gno @@ -13,6 +13,8 @@ func init() { } func main() { + crossing() + println(m[*i1]) // Output: first key } diff --git a/gnovm/tests/files/ptrmap_15.gno b/gnovm/tests/files/ptrmap_15.gno index b900fc4741f..7d3c87833c6 100644 --- a/gnovm/tests/files/ptrmap_15.gno +++ b/gnovm/tests/files/ptrmap_15.gno @@ -16,6 +16,8 @@ func init() { } func main() { + crossing() + println(m[i1.Key]) // Output: first key } diff --git a/gnovm/tests/files/ptrmap_16.gno b/gnovm/tests/files/ptrmap_16.gno index 40682a2c70e..80f73d8a492 100644 --- a/gnovm/tests/files/ptrmap_16.gno +++ b/gnovm/tests/files/ptrmap_16.gno @@ -15,6 +15,8 @@ func init() { } func main() { + crossing() + println(m[&arr[0]]) println(m[&arr[1]] == "") } diff --git a/gnovm/tests/files/ptrmap_17.gno b/gnovm/tests/files/ptrmap_17.gno index 4838ae988be..7bb30d9bc71 100644 --- a/gnovm/tests/files/ptrmap_17.gno +++ b/gnovm/tests/files/ptrmap_17.gno @@ -16,6 +16,8 @@ func init() { } func main() { + crossing() + println(m[&arr[index]]) } diff --git a/gnovm/tests/files/ptrmap_18.gno b/gnovm/tests/files/ptrmap_18.gno index 03c2d431d91..c79c521b5ea 100644 --- a/gnovm/tests/files/ptrmap_18.gno +++ b/gnovm/tests/files/ptrmap_18.gno @@ -20,6 +20,8 @@ func init() { } func main() { + crossing() + r := GetFromMap() println(r == 5) diff --git a/gnovm/tests/files/ptrmap_19.gno b/gnovm/tests/files/ptrmap_19.gno index 2a3e6b5240f..314790eb010 100644 --- a/gnovm/tests/files/ptrmap_19.gno +++ b/gnovm/tests/files/ptrmap_19.gno @@ -24,6 +24,8 @@ func init() { } func main() { + crossing() + r := GetFromMap() println(r == 5) diff --git a/gnovm/tests/files/ptrmap_2.gno b/gnovm/tests/files/ptrmap_2.gno index 006de1274b7..c9ca72ffb94 100644 --- a/gnovm/tests/files/ptrmap_2.gno +++ b/gnovm/tests/files/ptrmap_2.gno @@ -22,6 +22,8 @@ func init() { // ----above is initialized and persisted before main is executed. func main() { + crossing() + r := GetFromMap() println(r == 5) diff --git a/gnovm/tests/files/ptrmap_20.gno b/gnovm/tests/files/ptrmap_20.gno index 5efe9afaac0..470a0b55da9 100644 --- a/gnovm/tests/files/ptrmap_20.gno +++ b/gnovm/tests/files/ptrmap_20.gno @@ -20,6 +20,8 @@ func init() { } func main() { + crossing() + r := GetFromMap() println(r == 5) @@ -35,4 +37,4 @@ func main() { // Output: // true // 0 -// true \ No newline at end of file +// true diff --git a/gnovm/tests/files/ptrmap_22.gno b/gnovm/tests/files/ptrmap_22.gno index 653a6f2ffe8..b057274f6c6 100644 --- a/gnovm/tests/files/ptrmap_22.gno +++ b/gnovm/tests/files/ptrmap_22.gno @@ -17,6 +17,8 @@ func init() { } func main() { + crossing() + i2 := *i1 println(m[&i2] == "") diff --git a/gnovm/tests/files/ptrmap_23.gno b/gnovm/tests/files/ptrmap_23.gno index a587d924bc7..c910849d38a 100644 --- a/gnovm/tests/files/ptrmap_23.gno +++ b/gnovm/tests/files/ptrmap_23.gno @@ -9,6 +9,7 @@ func init() { } func main() { + crossing() println(m[&arr]) // Output: example } diff --git a/gnovm/tests/files/ptrmap_24.gno b/gnovm/tests/files/ptrmap_24.gno index 2c0890f47d0..64a8034a7da 100644 --- a/gnovm/tests/files/ptrmap_24.gno +++ b/gnovm/tests/files/ptrmap_24.gno @@ -21,6 +21,8 @@ func init() { } func main() { + crossing() + println(m[&i1.key]) } diff --git a/gnovm/tests/files/ptrmap_25.gno b/gnovm/tests/files/ptrmap_25.gno index ebfa1940ce9..9cb8e40be88 100644 --- a/gnovm/tests/files/ptrmap_25.gno +++ b/gnovm/tests/files/ptrmap_25.gno @@ -20,6 +20,8 @@ func init() { } func main() { + crossing() + r := GetFromMap() println(r == 5) diff --git a/gnovm/tests/files/ptrmap_26.gno b/gnovm/tests/files/ptrmap_26.gno index 8b8faf97a2b..8a706bae567 100644 --- a/gnovm/tests/files/ptrmap_26.gno +++ b/gnovm/tests/files/ptrmap_26.gno @@ -20,6 +20,8 @@ func init() { } func main() { + crossing() + r := GetFromMap() println(r == 5) diff --git a/gnovm/tests/files/ptrmap_3.gno b/gnovm/tests/files/ptrmap_3.gno index d89c696e2f0..94e6d695a16 100644 --- a/gnovm/tests/files/ptrmap_3.gno +++ b/gnovm/tests/files/ptrmap_3.gno @@ -21,6 +21,8 @@ func init() { } func main() { + crossing() + r := GetFromMap() println(r == 5) diff --git a/gnovm/tests/files/ptrmap_4.gno b/gnovm/tests/files/ptrmap_4.gno index e8f6f2bfdb1..fe0130bbadc 100644 --- a/gnovm/tests/files/ptrmap_4.gno +++ b/gnovm/tests/files/ptrmap_4.gno @@ -15,6 +15,8 @@ func init() { } func main() { + crossing() + // Create a new slice without reallocating memory for existing elements newArr := append(sArr[:1], sArr[2:]...) // same base array diff --git a/gnovm/tests/files/ptrmap_5.gno b/gnovm/tests/files/ptrmap_5.gno index a38817867e5..c6ef8d79900 100644 --- a/gnovm/tests/files/ptrmap_5.gno +++ b/gnovm/tests/files/ptrmap_5.gno @@ -13,6 +13,8 @@ func init() { } func main() { + crossing() + // Create a new slice without reallocating memory for existing elements newArr := append(sArr[:1], sArr[2:]...) // same base array diff --git a/gnovm/tests/files/ptrmap_6.gno b/gnovm/tests/files/ptrmap_6.gno index 1af7442e09f..b9b07498e8a 100644 --- a/gnovm/tests/files/ptrmap_6.gno +++ b/gnovm/tests/files/ptrmap_6.gno @@ -17,6 +17,8 @@ func init() { } func main() { + crossing() + // Create a new slice without reallocating memory for existing elements newArr := append(sArr[:1], sArr[2:]...) diff --git a/gnovm/tests/files/ptrmap_7.gno b/gnovm/tests/files/ptrmap_7.gno index 443a112c6d8..0bd77dc07bd 100644 --- a/gnovm/tests/files/ptrmap_7.gno +++ b/gnovm/tests/files/ptrmap_7.gno @@ -1,8 +1,6 @@ // PKGPATH: gno.land/r/ptr_map package ptr_map -import "fmt" - type S struct { i int } @@ -20,6 +18,8 @@ func init() { } func main() { + crossing() + // Create a new slice without reallocating memory for existing elements newArr := append(sArr[:1], sArr[2:]...) diff --git a/gnovm/tests/files/ptrmap_8.gno b/gnovm/tests/files/ptrmap_8.gno index 0985644e9d9..95d710ce121 100644 --- a/gnovm/tests/files/ptrmap_8.gno +++ b/gnovm/tests/files/ptrmap_8.gno @@ -15,6 +15,8 @@ func init() { } func main() { + crossing() + println(m[s[m2[0]]]) println(s[m2[0]] == s2[m2[0]]) println(m[s[m2[0]]] == m[s2[m2[0]]]) diff --git a/gnovm/tests/files/ptrmap_9.gno b/gnovm/tests/files/ptrmap_9.gno index 2756ad9acc7..04e0337d977 100644 --- a/gnovm/tests/files/ptrmap_9.gno +++ b/gnovm/tests/files/ptrmap_9.gno @@ -16,6 +16,8 @@ func init() { } func main() { + crossing() + println(m[s[m2[0]]]) println(s[m2[0]] == s2[m2[0]]) println(m[s[m2[0]]] == m[s2[m2[0]]]) diff --git a/gnovm/tests/files/recover/recover1.gno b/gnovm/tests/files/recover/recover1.gno new file mode 100644 index 00000000000..53ebcca3dab --- /dev/null +++ b/gnovm/tests/files/recover/recover1.gno @@ -0,0 +1,17 @@ +package main + +func main() { + defer func() { + print(recover()) + }() + defer func() { + defer print(recover()) + defer panic("1") + recover() + }() + defer recover() + panic("2") +} + +// Output: +// 21 diff --git a/gnovm/tests/files/recover/recover2.gno b/gnovm/tests/files/recover/recover2.gno new file mode 100644 index 00000000000..0bbdc4dda85 --- /dev/null +++ b/gnovm/tests/files/recover/recover2.gno @@ -0,0 +1,25 @@ +package main + +func main() { + defer func() { + println(recover()) + }() + defer func() { + defer func() { + recover() + }() + defer recover() + panic("3") + }() + defer func() { + defer func() { + recover() + }() + defer recover() + panic("2") + }() + panic("1") +} + +// Output: +// 1 diff --git a/gnovm/tests/files/recover/recover2a.gno b/gnovm/tests/files/recover/recover2a.gno new file mode 100644 index 00000000000..0168bcf27f9 --- /dev/null +++ b/gnovm/tests/files/recover/recover2a.gno @@ -0,0 +1,23 @@ +package main + +func main() { + defer func() { + println(recover()) + }() + defer func() { + defer func() { + recover() + }() + defer recover() + panic("3") + }() + defer func() { + + defer recover() + panic("2") + }() + panic("1") +} + +// Output: +// 2 diff --git a/gnovm/tests/files/recover/recover2b.gno b/gnovm/tests/files/recover/recover2b.gno new file mode 100644 index 00000000000..f7a01d8e890 --- /dev/null +++ b/gnovm/tests/files/recover/recover2b.gno @@ -0,0 +1,25 @@ +package main + +func main() { + defer func() { + println(recover()) + }() + defer func() { + + defer recover() + panic("3") + }() + defer func() { + + defer func() { + recover() + }() + + defer recover() + panic("2") + }() + panic("1") +} + +// Output: +// 3 diff --git a/gnovm/tests/files/recover/recover2c.gno b/gnovm/tests/files/recover/recover2c.gno new file mode 100644 index 00000000000..269c77eb873 --- /dev/null +++ b/gnovm/tests/files/recover/recover2c.gno @@ -0,0 +1,25 @@ +package main + +func main() { + defer func() { + println(recover()) + }() + defer func() { + defer func() { + recover() + }() + defer recover() + panic("3") + }() + defer func() { + defer func() { + recover() + }() + defer recover() + panic("2") + }() + panic("1") +} + +// Output: +// 2 diff --git a/gnovm/tests/files/ret14a.gno b/gnovm/tests/files/ret14a.gno new file mode 100644 index 00000000000..70c6f993dee --- /dev/null +++ b/gnovm/tests/files/ret14a.gno @@ -0,0 +1,19 @@ +package main + +func main() { + retVars := func() (a int, b int) { + for { + defer func() { + a = 3 + b = 4 + }() + return 1, 2 // This gets modified by defer + } + } + + a, b := retVars() + println(a, b) +} + +// Output: +// 3 4 diff --git a/gnovm/tests/files/ret14b.gno b/gnovm/tests/files/ret14b.gno new file mode 100644 index 00000000000..15f934f0e0f --- /dev/null +++ b/gnovm/tests/files/ret14b.gno @@ -0,0 +1,20 @@ +package main + +func retVars() (_ int, _ int) { + for { + var a, b = 1, 2 + defer func() { + a = 3 + b = 4 + }() + return a, b + } +} + +func main() { + x, y := retVars() + println(x, y) +} + +// Output: +// 2 1 diff --git a/gnovm/tests/files/ret15.gno b/gnovm/tests/files/ret15.gno new file mode 100644 index 00000000000..11fb49286e6 --- /dev/null +++ b/gnovm/tests/files/ret15.gno @@ -0,0 +1,20 @@ +package main + +func mixedReturns() (a int, _ string, b bool) { + defer func() { + b = false + _ = "blank" + }() + + a = 5 + b = true + return a, "ignored", b +} + +func main() { + a, s, b := mixedReturns() + println(a, s, b) +} + +// Output: +// 5 ignored false diff --git a/gnovm/tests/files/ret16.gno b/gnovm/tests/files/ret16.gno new file mode 100644 index 00000000000..2e23ef0b453 --- /dev/null +++ b/gnovm/tests/files/ret16.gno @@ -0,0 +1,16 @@ +package main + +func assertWithClosure(x any) func() { + return func() { + if _, ok := x.(string); ok { + println("is captured:", ok, x) + } + } +} + +func main() { + assertWithClosure("a")() +} + +// Output: +// is captured: true a diff --git a/gnovm/tests/files/ret17.gno b/gnovm/tests/files/ret17.gno new file mode 100644 index 00000000000..49867b366f8 --- /dev/null +++ b/gnovm/tests/files/ret17.gno @@ -0,0 +1,36 @@ +package main + +import "fmt" + +func trymake() func() string { + if s := "hello"; true { + return func() string { + defer func() { + if r := recover(); r != nil { + fmt.Println("Recovered, r: ", r) + } + fmt.Println("Recovered, s: ", s) + }() + + defer func() { + s = "!!!" + panic(s) + }() + + println(s) // hello + return s + } + } + return func() string { return "else..." } +} + +func main() { + s1 := trymake()() + println("return value: ", s1) +} + +// Output: +// hello +// Recovered, r: !!! +// Recovered, s: !!! +// return value: hello diff --git a/gnovm/tests/files/ret18.gno b/gnovm/tests/files/ret18.gno new file mode 100644 index 00000000000..f352edf354a --- /dev/null +++ b/gnovm/tests/files/ret18.gno @@ -0,0 +1,16 @@ +package main + +func deferMixPointer() (int, *int) { // uname return value + y := new(int) + *y = 1 + defer func() { *y++ }() + return 1, y +} + +func main() { + a, ptr := deferMixPointer() + println(a, *ptr) +} + +// Output: +// 1 2 diff --git a/gnovm/tests/files/star_assign.gno b/gnovm/tests/files/star_assign.gno index e40fe2794ac..c15e85cadd5 100644 --- a/gnovm/tests/files/star_assign.gno +++ b/gnovm/tests/files/star_assign.gno @@ -22,6 +22,8 @@ func init() { } func main() { + crossing() + Delta() println(Values()) } diff --git a/gnovm/tests/files/std10.gno b/gnovm/tests/files/std10.gno index b549387feaa..32b831b540c 100644 --- a/gnovm/tests/files/std10.gno +++ b/gnovm/tests/files/std10.gno @@ -7,8 +7,8 @@ func main() { // assert panic is recoverable println(recover()) }() - std.CallerAt(0) + std.PreviousRealm() } // Output: -// CallerAt requires positive arg +// frame not found diff --git a/gnovm/tests/files/std11.gno b/gnovm/tests/files/std11.gno index 70668fe443b..1a1ca847570 100644 --- a/gnovm/tests/files/std11.gno +++ b/gnovm/tests/files/std11.gno @@ -7,8 +7,8 @@ func main() { // assert panic is recoverable println(recover()) }() - std.CallerAt(42) + std.CurrentRealm() } // Output: -// frame not found +// undefined diff --git a/gnovm/tests/files/std4.gno b/gnovm/tests/files/std4.gno index aef32507b08..6a7b9f46b51 100644 --- a/gnovm/tests/files/std4.gno +++ b/gnovm/tests/files/std4.gno @@ -5,9 +5,9 @@ import ( ) func main() { - caller1 := std.CallerAt(1) - println(caller1) + realm1 := std.CurrentRealm() + println(realm1) } // Output: -// g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// (struct{("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm" std.Address),("" string)} std.Realm) diff --git a/gnovm/tests/files/std5.gno b/gnovm/tests/files/std5.gno index 81e066c3762..528f3b5f078 100644 --- a/gnovm/tests/files/std5.gno +++ b/gnovm/tests/files/std5.gno @@ -5,18 +5,18 @@ import ( ) func main() { - caller1 := std.CallerAt(1) - println(caller1) - caller2 := std.CallerAt(2) - println(caller2) + realm1 := std.CurrentRealm() + println(realm1) + realm2 := std.PreviousRealm() + println(realm2) } // Stacktrace: // panic: frame not found -// callerAt(n) -// gonative:std.callerAt -// std.CallerAt(2) -// std/native.gno:41 +// getRealm(1) +// gonative:std.getRealm +// ref(std).PreviousRealm() +// std/native.gno:32 // main() // main/files/std5.gno:10 diff --git a/gnovm/tests/files/std6.gno b/gnovm/tests/files/std6.gno index 27c64503b13..910307b0e55 100644 --- a/gnovm/tests/files/std6.gno +++ b/gnovm/tests/files/std6.gno @@ -3,16 +3,26 @@ package main import "std" func inner() { - caller1 := std.CallerAt(1) - println(caller1) - caller2 := std.CallerAt(2) - println(caller2) + realm1 := std.CurrentRealm() + println(realm1) + realm2 := std.PreviousRealm() + println(realm2) } func main() { inner() } -// Output: -// g17rgsdnfxzza0sdfsdma37sdwxagsz378833ca4 -// g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// Stacktrace: +// panic: frame not found +// getRealm(1) +// gonative:std.getRealm +// ref(std).PreviousRealm() +// std/native.gno:32 +// inner() +// main/files/std6.gno:8 +// main() +// main/files/std6.gno:13 + +// Error: +// frame not found diff --git a/gnovm/tests/files/std7.gno b/gnovm/tests/files/std7.gno index ce767fe59e9..7e0d97d0394 100644 --- a/gnovm/tests/files/std7.gno +++ b/gnovm/tests/files/std7.gno @@ -7,12 +7,10 @@ import ( ) func inner() { - caller1 := std.CallerAt(1) - println(caller1) - caller2 := std.CallerAt(2) - println(caller2) - caller3 := std.CallerAt(3) - println(caller3) + realm1 := std.CurrentRealm() + println(realm1) + realm2 := std.PreviousRealm() + println(realm2) } func main() { @@ -20,6 +18,7 @@ func main() { } // Output: -// g17rgsdnfxzza0sdfsdma37sdwxagsz378833ca4 -// g1ssrgtfce6pzs8tp7s6y8473yrffqs9xlgntk0h -// g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// (struct{("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm" std.Address),("" string)} std.Realm) + +// Error: +// frame not found diff --git a/gnovm/tests/files/std8.gno b/gnovm/tests/files/std8.gno index 509da757e87..23b9554dbdd 100644 --- a/gnovm/tests/files/std8.gno +++ b/gnovm/tests/files/std8.gno @@ -7,32 +7,31 @@ import ( ) func inner() { - caller1 := std.CallerAt(1) - println(caller1) - caller2 := std.CallerAt(2) - println(caller2) - caller3 := std.CallerAt(3) - println(caller3) - caller4 := std.CallerAt(4) - println(caller4) + realm1 := std.CurrentRealm() + println(realm1) + realm2 := std.PreviousRealm() + println(realm2) } func main() { testutils.WrapCall(inner) } +// Output: +// (struct{("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm" std.Address),("" string)} std.Realm) + // Stacktrace: // panic: frame not found -// callerAt(n) -// gonative:std.callerAt -// std.CallerAt(4) -// std/native.gno:41 +// getRealm(1) +// gonative:std.getRealm +// ref(std).PreviousRealm() +// std/native.gno:32 // fn() -// main/files/std8.gno:16 -// testutils.WrapCall(inner) +// main/files/std8.gno:12 +// ref(gno.land/p/demo/testutils).WrapCall(inner) // gno.land/p/demo/testutils/misc.gno:5 // main() -// main/files/std8.gno:21 +// main/files/std8.gno:17 // Error: // frame not found diff --git a/gnovm/tests/files/stdlibs.gno b/gnovm/tests/files/stdlibs.gno index 261e7fbe78c..2fbfa01cec7 100644 --- a/gnovm/tests/files/stdlibs.gno +++ b/gnovm/tests/files/stdlibs.gno @@ -4,6 +4,8 @@ package test import "time" func main() { + crossing() + println(time.UTC == nil) time.UTC = nil println(time.UTC == nil) diff --git a/gnovm/tests/files/switch11.gno b/gnovm/tests/files/switch11.gno index 2dac28aea08..6709d2bd472 100644 --- a/gnovm/tests/files/switch11.gno +++ b/gnovm/tests/files/switch11.gno @@ -11,5 +11,8 @@ func main() { } } +// Preprocessed: +// file{ package main; func main() { var i (const-type interface {}) = (const ("truc" string)); switch b := (const (2 int)); a:=i { case (const-type string): (const (println func(...interface {})))((const ("string" string)), a + (const (" ok" string))); default: (const (println func(...interface {})))((const ("unknown" string)), b) } } } + // Output: // string truc ok diff --git a/gnovm/tests/files/type24b.gno b/gnovm/tests/files/type24b.gno index 648acbca28f..38f838ff81d 100644 --- a/gnovm/tests/files/type24b.gno +++ b/gnovm/tests/files/type24b.gno @@ -45,5 +45,5 @@ func assertValue() { // Output: // int is not of type string -// interface {} is not of type string +// nil is not of type string // *github.com/gnolang/gno/_test/net/http/httptest.ResponseRecorder doesn't implement interface {Push func(string, *github.com/gnolang/gno/_test/net/http.PushOptions) .uverse.error} (missing method Push) diff --git a/gnovm/tests/files/type_alias.gno b/gnovm/tests/files/type_alias.gno index 09918f6d591..abf97e50dd6 100644 --- a/gnovm/tests/files/type_alias.gno +++ b/gnovm/tests/files/type_alias.gno @@ -6,6 +6,8 @@ import "gno.land/p/demo/uassert" type TestingT = uassert.TestingT func main() { + crossing() + println("ok") } diff --git a/gnovm/tests/files/zpersist_valids.gno b/gnovm/tests/files/zpersist_valids.gno index e6400ff45da..8480b14c35d 100644 --- a/gnovm/tests/files/zpersist_valids.gno +++ b/gnovm/tests/files/zpersist_valids.gno @@ -26,7 +26,7 @@ var ( auint16 uint16 = 16 auint32 uint32 = 16 auint64 uint64 = 16 - ainterface any = struct{ a float32 }{16.0} + ainterface any = struct{ a float32 }{16.0} afunc func() string = func() string { return "A" } // TODO: @@ -45,6 +45,8 @@ func init() { } func main() { + crossing() + printVars("premain ") mutateVars("C") printVars("postmain") diff --git a/gnovm/tests/files/zrealm0.gno b/gnovm/tests/files/zrealm0.gno index e38d623aa25..7b98d2fb596 100644 --- a/gnovm/tests/files/zrealm0.gno +++ b/gnovm/tests/files/zrealm0.gno @@ -4,13 +4,15 @@ package test var root any func main() { + crossing() + println(root) root = 1 println(root) } // Output: -// nil +// undefined // 1 // The below tests that the realm's block (of 1 variable) changed. The first @@ -20,19 +22,22 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -19,11 +19,10 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,9 +1,15 @@ +// { +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "0", +// + "ModTime": "5", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Values": [ -// { -// + "N": "AQAAAAAAAAA=", -// "T": { -// - "@type": "/gno.InterfaceType", -// - "Generic": "", -// - "Methods": null, -// - "PkgPath": "" -// + "@type": "/gno.PrimitiveType", -// + "value": "32" -// } -// }, -// { +// - "Value": {} +// + "Value": { +// + "N": "AQAAAAAAAAA=", +// + "T": { +// + "@type": "/gno.PrimitiveType", +// + "value": "32" +// + } +// + } +// } diff --git a/gnovm/tests/files/zrealm1.gno b/gnovm/tests/files/zrealm1.gno index e707e7c3f39..61329eecc71 100644 --- a/gnovm/tests/files/zrealm1.gno +++ b/gnovm/tests/files/zrealm1.gno @@ -15,6 +15,8 @@ type InnerNode struct { } func main() { + crossing() + key := "somekey" root = InnerNode{ Key: key, @@ -25,7 +27,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ // "Fields": [ // { // "T": { @@ -41,24 +43,32 @@ func main() { // {} // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -21,7 +21,12 @@ -// { -// "T": { -// "@type": "/gno.RefType", -// - "ID": "gno.land/r/test.Node" -// + "ID": "gno.land/r/test.InnerNode" -// + }, -// + "V": { -// + "@type": "/gno.RefValue", -// + "Hash": "ae4e9e2d205cc0081d4ee249e1d188ebe270b220", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// } -// }, -// { +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,9 +1,19 @@ +// { +// "ObjectInfo": { +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "0", +// + "ModTime": "5", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" +// }, +// - "Value": {} +// + "Value": { +// + "T": { +// + "@type": "/gno.RefType", +// + "ID": "gno.land/r/test.InnerNode" +// + }, +// + "V": { +// + "@type": "/gno.RefValue", +// + "Hash": "860c81a9b1ccd2bc42fc95635a1e940c88b758d7", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// + } +// + } +// } diff --git a/gnovm/tests/files/zrealm10.gno b/gnovm/tests/files/zrealm10.gno index e3d98cf4079..a68da50a066 100644 --- a/gnovm/tests/files/zrealm10.gno +++ b/gnovm/tests/files/zrealm10.gno @@ -12,6 +12,8 @@ func init() { } func main() { + crossing() + println(ms) ms.Field += 2 println(ms) @@ -23,7 +25,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= // @@ -1,7 +1,7 @@ // { // "Fields": [ diff --git a/gnovm/tests/files/zrealm11.gno b/gnovm/tests/files/zrealm11.gno index fd4b834a592..17a117b4d78 100644 --- a/gnovm/tests/files/zrealm11.gno +++ b/gnovm/tests/files/zrealm11.gno @@ -12,6 +12,8 @@ func init() { } func main() { + crossing() + println(ms) ms.Field -= 2 println(ms) @@ -23,7 +25,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= // @@ -1,7 +1,7 @@ // { // "Fields": [ diff --git a/gnovm/tests/files/zrealm13.gno b/gnovm/tests/files/zrealm13.gno index 7dcad050ca5..7b115b1b9c3 100644 --- a/gnovm/tests/files/zrealm13.gno +++ b/gnovm/tests/files/zrealm13.gno @@ -6,7 +6,6 @@ var ( b [2]*B ) - type A struct { A string } @@ -16,7 +15,7 @@ type B struct { } func init() { - c := B{ + c := B{ A: a, B: "c", } @@ -30,13 +29,14 @@ func init() { } func main() { + crossing() + b[0] = nil } - // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= // @@ -8,16 +8,6 @@ // "@type": "/gno.RefType", // "ID": "gno.land/r/test.B" @@ -46,8 +46,8 @@ func main() { // - "@type": "/gno.PointerValue", // - "Base": { // - "@type": "/gno.RefValue", -// - "Escaped": true, -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// - "Hash": "ff7ee2df0e65a933be3dce7550bf361d29e83bc0", +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" // - }, // - "Index": "0", // - "TV": null @@ -57,21 +57,23 @@ func main() { // @@ -42,7 +32,7 @@ // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", -// - "ModTime": "6", -// + "ModTime": "9", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// - "ModTime": "10", +// + "ModTime": "14", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= -// @@ -3,8 +3,8 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= +// @@ -2,8 +2,8 @@ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "IsEscaped": true, -// - "ModTime": "0", -// - "RefCount": "2" -// + "ModTime": "9", -// + "RefCount": "1" +// - "ModTime": "12", +// - "RefCount": "3" +// + "ModTime": "14", +// + "RefCount": "2" // }, -// "Parent": { -// "@type": "/gno.RefValue", +// "Value": { +// "T": { +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:11] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:12] diff --git a/gnovm/tests/files/zrealm14.gno b/gnovm/tests/files/zrealm14.gno index 30e9301091f..5bbc996540b 100644 --- a/gnovm/tests/files/zrealm14.gno +++ b/gnovm/tests/files/zrealm14.gno @@ -6,7 +6,6 @@ var ( b [2]*B ) - type A struct { A string } @@ -16,7 +15,7 @@ type B struct { } func init() { - c := B{ + c := B{ A: a, B: "c", } @@ -30,13 +29,15 @@ func init() { } func main() { + crossing() + b[0] = nil b[1] = nil } // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= // @@ -8,16 +8,6 @@ // "@type": "/gno.RefType", // "ID": "gno.land/r/test.B" @@ -46,8 +47,8 @@ func main() { // - "@type": "/gno.PointerValue", // - "Base": { // - "@type": "/gno.RefValue", -// - "Escaped": true, -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// - "Hash": "ff7ee2df0e65a933be3dce7550bf361d29e83bc0", +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" // - }, // - "Index": "0", // - "TV": null @@ -63,55 +64,34 @@ func main() { // - "@type": "/gno.PointerValue", // - "Base": { // - "@type": "/gno.RefValue", -// - "Escaped": true, -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// - "Hash": "ff020e571a6e197bf9ed4e90057ba19a576e0622", +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13" // - }, -// - "Index": "1", +// - "Index": "0", // - "TV": null // } // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", -// - "ModTime": "6", -// + "ModTime": "9", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// - "ModTime": "10", +// + "ModTime": "14", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= -// @@ -3,8 +3,8 @@ -// "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", -// "IsEscaped": true, -// - "ModTime": "0", -// - "RefCount": "2" -// + "ModTime": "9", -// + "RefCount": "0" -// }, -// "Parent": { -// "@type": "/gno.RefValue", -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= // @@ -2,8 +2,8 @@ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "IsEscaped": true, -// - "ModTime": "8", +// - "ModTime": "12", // - "RefCount": "3" -// + "ModTime": "9", +// + "ModTime": "14", // + "RefCount": "1" // }, // "Value": { // "T": { -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]= -// @@ -4,7 +4,7 @@ -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", -// "IsEscaped": true, -// "ModTime": "9", -// - "RefCount": "4" -// + "RefCount": "3" -// }, -// "Parent": { -// "@type": "/gno.RefValue", -// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:7] -// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:8] -// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:9] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:11] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:12] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:13] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:14] diff --git a/gnovm/tests/files/zrealm15.gno b/gnovm/tests/files/zrealm15.gno index 86cb2eec64d..7a1c758b470 100644 --- a/gnovm/tests/files/zrealm15.gno +++ b/gnovm/tests/files/zrealm15.gno @@ -7,7 +7,7 @@ var ( s *S ) -type S struct { +type S struct { S string } type A struct { @@ -22,7 +22,7 @@ func init() { s = &S{ S: "c", } - c := B{ + c := B{ A: a, B: s, } @@ -32,15 +32,16 @@ func init() { } func main() { + crossing() + b[0] = nil b[1] = nil a.A = nil } - // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= // @@ -8,16 +8,6 @@ // "@type": "/gno.RefType", // "ID": "gno.land/r/test.B" @@ -51,7 +52,7 @@ func main() { // - "Base": { // - "@type": "/gno.RefValue", // - "Escaped": true, -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14" // - }, // - "Index": "0", // - "TV": null @@ -68,7 +69,7 @@ func main() { // - "Base": { // - "@type": "/gno.RefValue", // - "Escaped": true, -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14" // - }, // - "Index": "0", // - "TV": null @@ -76,25 +77,25 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", -// - "ModTime": "6", -// + "ModTime": "10", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// - "ModTime": "11", +// + "ModTime": "15", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]= -// @@ -3,8 +3,8 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:14]= +// @@ -2,8 +2,8 @@ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", // "IsEscaped": true, // - "ModTime": "0", // - "RefCount": "2" -// + "ModTime": "10", +// + "ModTime": "15", // + "RefCount": "0" // }, -// "Parent": { -// "@type": "/gno.RefValue", -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= +// "Value": { +// "T": { +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]= // @@ -7,22 +7,12 @@ // "@type": "/gno.RefType", // "ID": "gno.land/r/test.S" @@ -105,7 +106,7 @@ func main() { // - "Base": { // - "@type": "/gno.RefValue", // - "Escaped": true, -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" // - }, // - "Index": "0", // - "TV": null @@ -113,29 +114,29 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", -// - "ModTime": "6", -// + "ModTime": "10", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// - "ModTime": "11", +// + "ModTime": "15", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:12]= // @@ -2,8 +2,8 @@ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", // "IsEscaped": true, // - "ModTime": "0", // - "RefCount": "3" -// + "ModTime": "10", +// + "ModTime": "15", // + "RefCount": "1" // }, // "Value": { // "T": { -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= // @@ -3,7 +3,7 @@ -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "IsEscaped": true, -// "ModTime": "10", +// "ModTime": "15", // - "RefCount": "2" // + "RefCount": "1" // }, @@ -145,20 +146,10 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// - "Hash": "38707548446d3e67a38939d1af16cbc2f3a311f9", -// + "Hash": "e82e410f22425e48d5f6c611160084a4dd50d3d1", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// - "Hash": "4641faa430640c89d2730115d8159609a3fd1492", +// + "Hash": "47746c70f1dda9b50d12a68174a4d2f3cb7065e8", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]= -// @@ -4,7 +4,7 @@ -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", -// "IsEscaped": true, -// "ModTime": "10", -// - "RefCount": "4" -// + "RefCount": "3" -// }, -// "Parent": { -// "@type": "/gno.RefValue", -// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:9] -// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:10] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:14] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:15] diff --git a/gnovm/tests/files/zrealm16.gno b/gnovm/tests/files/zrealm16.gno index 710aaac20b1..88132700452 100644 --- a/gnovm/tests/files/zrealm16.gno +++ b/gnovm/tests/files/zrealm16.gno @@ -30,52 +30,54 @@ func init() { } func main() { + crossing() + b[0].A = a2 } // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:15]= // @@ -13,7 +13,7 @@ // "Base": { // "@type": "/gno.RefValue", // "Escaped": true, -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3" -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" // }, // "Index": "0", // "TV": null // @@ -32,7 +32,7 @@ // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15", // - "ModTime": "0", -// + "ModTime": "11", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// + "ModTime": "17", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= // @@ -1,9 +1,10 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // - "ModTime": "0", // + "IsEscaped": true, -// + "ModTime": "11", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// + "ModTime": "17", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", // - "RefCount": "1" // + "RefCount": "2" // }, // "Value": { // "T": { -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= // @@ -2,8 +2,8 @@ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "IsEscaped": true, -// - "ModTime": "10", +// - "ModTime": "15", // - "RefCount": "3" -// + "ModTime": "11", +// + "ModTime": "17", // + "RefCount": "2" // }, // "Value": { diff --git a/gnovm/tests/files/zrealm2.gno b/gnovm/tests/files/zrealm2.gno index e2f6b8fbc08..14d6c904d3f 100644 --- a/gnovm/tests/files/zrealm2.gno +++ b/gnovm/tests/files/zrealm2.gno @@ -21,6 +21,8 @@ func init() { } func main() { + crossing() + root = InnerNode{ Key: "new", } @@ -28,7 +30,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ // "Fields": [ // { // "T": { @@ -44,31 +46,31 @@ func main() { // {} // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // "RefCount": "1" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -3,7 +3,7 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// - "ModTime": "3", -// + "ModTime": "4", -// "RefCount": "2" +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "6", +// + "ModTime": "7", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -25,8 +25,8 @@ -// }, -// "V": { -// "@type": "/gno.RefValue", -// - "Hash": "d9cf719bd2589ae934ec781c5ede54ca30ed2189", -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// + "Hash": "61d4aa77a87c01e07038c6030d6aca299d0fdc1b", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// } +// @@ -12,8 +12,8 @@ // }, -// { -// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:4] +// "V": { +// "@type": "/gno.RefValue", +// - "Hash": "c1bfc6b3d7043721364563a780c15c757c10a49f", +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// + "Hash": "17c8ef092e704bbac8183328f9295793011c8364", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// } +// } +// } +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:7] diff --git a/gnovm/tests/files/zrealm3.gno b/gnovm/tests/files/zrealm3.gno index 8eaa04d2e7b..373c8a9d543 100644 --- a/gnovm/tests/files/zrealm3.gno +++ b/gnovm/tests/files/zrealm3.gno @@ -18,6 +18,8 @@ func init() { } func main() { + crossing() + root = &Node{ Key: "new", } @@ -25,7 +27,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ // "Fields": [ // { // "T": { @@ -57,17 +59,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // "RefCount": "1" // }, // "Value": { @@ -77,31 +79,31 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "567a18d9c7594ece7956ce54384b0858888bb834", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// "Hash": "24da1ffa2b1135d506e4e79ad56ba790d5bb3d36", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -3,7 +3,7 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// - "ModTime": "3", -// + "ModTime": "5", -// "RefCount": "2" +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "6", +// + "ModTime": "8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -30,8 +30,8 @@ -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// - "Hash": "f901abc9f5949266042ebee17842ca5f373821c9", -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// + "Hash": "8197b7c5b4f2c7bf9c12b1c614f6b4dc6e7ce8dd", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// }, -// "Index": "0", -// "TV": null -// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:4] -// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:5] +// @@ -17,8 +17,8 @@ +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// - "Hash": "477e1546db4d3a70091c73a992039811bc2666fe", +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// + "Hash": "d8185ab144b70c0fec8cbda653cabee29619a499", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// }, +// "Index": "0", +// "TV": null +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:7] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:8] diff --git a/gnovm/tests/files/zrealm4.gno b/gnovm/tests/files/zrealm4.gno index 521a23dab4f..a70447f4511 100644 --- a/gnovm/tests/files/zrealm4.gno +++ b/gnovm/tests/files/zrealm4.gno @@ -13,6 +13,8 @@ func init() { } func main() { + crossing() + var updated bool tree, updated = tree.Put(types.String("key0"), "value0-new") println(updated, tree.Size()) @@ -23,7 +25,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]= // @@ -17,7 +17,7 @@ // }, // "V": { @@ -36,47 +38,47 @@ func main() { // @@ -48,7 +48,7 @@ // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // - "ModTime": "0", -// + "ModTime": "5", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// + "ModTime": "8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= // @@ -1,7 +1,7 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // - "ModTime": "0", -// + "ModTime": "5", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// + "ModTime": "8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // "RefCount": "1" // }, // @@ -12,7 +12,7 @@ // }, // "V": { // "@type": "/gno.RefValue", -// - "Hash": "b819bc3b7c351c8e571654d4ce054a997a3ac50f", -// + "Hash": "d57ee28f5030eb8c612b374155fd545675633288", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// - "Hash": "741337baec39cbc5700d7a34e508b6a1ef51d17b", +// + "Hash": "16280818f1c7acbde1e80e4b223540ae16a57024", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -3,7 +3,7 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// - "ModTime": "3", -// + "ModTime": "5", -// "RefCount": "2" +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "6", +// + "ModTime": "8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -30,7 +30,7 @@ -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// - "Hash": "7b9d58f40430bbbcbafd47eefb7a6dd342477f71", -// + "Hash": "ef474e536e2d4229156a07798a88edc3767c0896", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", +// @@ -17,7 +17,7 @@ +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// - "Hash": "1a5319ef6d9d1b28c2427abdbe35e6fc6450d0ff", +// + "Hash": "b05627b5eca2b468a119b7bbca9cf903a2873b70", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// }, +// "Index": "0", diff --git a/gnovm/tests/files/zrealm5.gno b/gnovm/tests/files/zrealm5.gno index 2e0d4c31ad5..3ae71145335 100644 --- a/gnovm/tests/files/zrealm5.gno +++ b/gnovm/tests/files/zrealm5.gno @@ -13,6 +13,8 @@ func init() { } func main() { + crossing() + var updated bool tree, updated = tree.Put(types.String("key1"), "value1") println(updated, tree.Size()) @@ -23,7 +25,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ // "Fields": [ // { // "T": { @@ -72,17 +74,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "RefCount": "1" // }, // "Value": { @@ -92,12 +94,12 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "8a86634afa28ef7d7a1f4272255637f16daae2cd", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// "Hash": "fbc298a120d90a76556a2c336da0fce9a5089589", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]= // @@ -21,7 +21,7 @@ // } // }, @@ -116,8 +118,8 @@ func main() { // + "@type": "/gno.PointerValue", // + "Base": { // + "@type": "/gno.RefValue", -// + "Hash": "7c63a8fd451cd7c470c1851f1ead037246422ded", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// + "Hash": "83679a93d6368efc955986ec72780bc7a5c77162", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" // + }, // + "Index": "0", // + "TV": null @@ -125,47 +127,47 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // - "ModTime": "0", -// + "ModTime": "5", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// + "ModTime": "8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= // @@ -1,7 +1,7 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // - "ModTime": "0", -// + "ModTime": "5", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// + "ModTime": "8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // "RefCount": "1" // }, // @@ -12,7 +12,7 @@ // }, // "V": { // "@type": "/gno.RefValue", -// - "Hash": "b819bc3b7c351c8e571654d4ce054a997a3ac50f", -// + "Hash": "115779a405a1cae45446397ea897a98a4043cbb2", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// - "Hash": "741337baec39cbc5700d7a34e508b6a1ef51d17b", +// + "Hash": "a182fe8928af8ad42e141c2f0f7428650f81200e", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -3,7 +3,7 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// - "ModTime": "3", -// + "ModTime": "5", -// "RefCount": "2" +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "6", +// + "ModTime": "8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -30,7 +30,7 @@ -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// - "Hash": "7b9d58f40430bbbcbafd47eefb7a6dd342477f71", -// + "Hash": "4d1fa77f34d3e7a828c62ed4b74365cf7b665042", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", +// @@ -17,7 +17,7 @@ +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// - "Hash": "1a5319ef6d9d1b28c2427abdbe35e6fc6450d0ff", +// + "Hash": "9d5e4d8e9a2f3e07b7aa3682705cf9a1e3c3c28d", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// }, +// "Index": "0", diff --git a/gnovm/tests/files/zrealm6.gno b/gnovm/tests/files/zrealm6.gno index 1d09a067286..b3541fe22c5 100644 --- a/gnovm/tests/files/zrealm6.gno +++ b/gnovm/tests/files/zrealm6.gno @@ -14,6 +14,8 @@ func init() { } func main() { + crossing() + var updated bool tree, updated = tree.Put(types.String("key3"), "value3") println(updated, tree.Size()) @@ -24,7 +26,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:12]={ // "Fields": [ // { // "T": { @@ -73,17 +75,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:11]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "RefCount": "1" // }, // "Value": { @@ -93,12 +95,12 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "34a46349a2bc1b58591d0222a145b585452683be", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// "Hash": "98fd1f163604dba9a5d6c9f7f4136afecb113eda", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]= // @@ -21,7 +21,7 @@ // } // }, @@ -117,8 +119,8 @@ func main() { // + "@type": "/gno.PointerValue", // + "Base": { // + "@type": "/gno.RefValue", -// + "Hash": "81074f5da453299a913435a2ddd05248ee012f8c", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// + "Hash": "76fe7a131717e81aef46d94770e6d6af3b2501bb", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" // + }, // + "Index": "0", // + "TV": null @@ -126,32 +128,32 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // - "ModTime": "0", -// + "ModTime": "7", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// + "ModTime": "10", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]= // @@ -1,7 +1,7 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // - "ModTime": "0", -// + "ModTime": "7", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// + "ModTime": "10", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "RefCount": "1" // }, // @@ -12,7 +12,7 @@ // }, // "V": { // "@type": "/gno.RefValue", -// - "Hash": "8a86634afa28ef7d7a1f4272255637f16daae2cd", -// + "Hash": "5d64092f4f064ca58bdeffa32f6a119545b401c8", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// - "Hash": "fbc298a120d90a76556a2c336da0fce9a5089589", +// + "Hash": "95c60c98bb4cbda49a1a9229403ce2b674cc9543", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]= // @@ -21,7 +21,7 @@ // } // }, @@ -165,55 +167,55 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// - "Hash": "7c63a8fd451cd7c470c1851f1ead037246422ded", -// + "Hash": "32593d23afa555fe99d433dbca1130b3843da97a", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// - "Hash": "83679a93d6368efc955986ec72780bc7a5c77162", +// + "Hash": "bc46fa54ed09ac71604dc838162a025e5c010423", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" // }, // "Index": "0", // @@ -58,7 +58,7 @@ // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // - "ModTime": "0", -// + "ModTime": "7", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// + "ModTime": "10", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= // @@ -1,7 +1,7 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // - "ModTime": "0", -// + "ModTime": "7", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// + "ModTime": "10", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // "RefCount": "1" // }, // @@ -12,7 +12,7 @@ // }, // "V": { // "@type": "/gno.RefValue", -// - "Hash": "b108e3ffd3ab3f3646673648aa103ff557e5b08c", -// + "Hash": "131993c49dced230bd7071e9bae8d95e28733b73", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// - "Hash": "22d5200e240bec5c6426e14a26d010011f3c4242", +// + "Hash": "e0e2bbcbdd45126bf7281fcb3ddb0a443d631240", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -3,7 +3,7 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// - "ModTime": "3", -// + "ModTime": "7", -// "RefCount": "2" +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "6", +// + "ModTime": "10", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -30,7 +30,7 @@ -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// - "Hash": "ade9fce2a987ef1924040a1d75c0172410c66952", -// + "Hash": "5c52e0d7b383389f6a176fb490e91211197eca77", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// }, -// "Index": "0", +// @@ -17,7 +17,7 @@ +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// - "Hash": "150d3a4f7d4f6a55576a572177b56120c367a981", +// + "Hash": "14317bebbcc09033d1ceb2912168e3bad8d2147e", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// }, +// "Index": "0", diff --git a/gnovm/tests/files/zrealm7.gno b/gnovm/tests/files/zrealm7.gno index 331c5b2fa6d..766c06bfdd0 100644 --- a/gnovm/tests/files/zrealm7.gno +++ b/gnovm/tests/files/zrealm7.gno @@ -15,6 +15,8 @@ func init() { } func main() { + crossing() + var updated bool tree, updated = tree.Put(types.String("key3"), "value3") println(updated, tree.Size()) @@ -25,7 +27,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:11]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:14]={ // "Fields": [ // { // "T": { @@ -74,17 +76,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:13]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", // "RefCount": "1" // }, // "Value": { @@ -94,12 +96,12 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "42cd813e173ad23c7873e9605901e8bea1176c96", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" +// "Hash": "05bd76386d87574e052920ddc58592064cbd0c71", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:12]= // @@ -21,7 +21,7 @@ // } // }, @@ -118,8 +120,8 @@ func main() { // + "@type": "/gno.PointerValue", // + "Base": { // + "@type": "/gno.RefValue", -// + "Hash": "4f88fcdc73a4a94905e8e4044aa50c2ec7bf2227", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" +// + "Hash": "817ecb447e03f87e9968b39fbdfefbddd7b646ae", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13" // + }, // + "Index": "0", // + "TV": null @@ -127,13 +129,13 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", // - "ModTime": "0", -// + "ModTime": "9", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// + "ModTime": "12", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]= // @@ -21,7 +21,7 @@ // } // }, @@ -152,8 +154,8 @@ func main() { // - "@type": "/gno.PointerValue", // - "Base": { // - "@type": "/gno.RefValue", -// - "Hash": "e47c9fe5fa842d7ec1bbbc99317cb157a4174877", -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// - "Hash": "623ee3909f3dc15cc8f00c580c6ffa88dab5fb08", +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" // - }, // - "Index": "0", // - "TV": null @@ -161,51 +163,51 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // - "ModTime": "0", -// + "ModTime": "9", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// + "ModTime": "12", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= // @@ -1,7 +1,7 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // - "ModTime": "0", -// + "ModTime": "9", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// + "ModTime": "12", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // "RefCount": "1" // }, // @@ -12,7 +12,7 @@ // }, // "V": { // "@type": "/gno.RefValue", -// - "Hash": "916668cd920db8d3551f75ba22194d2e1e1cc804", -// + "Hash": "d7fbb234dca9f194f35fe5409a62db9daf39b0fc", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// - "Hash": "eab62fdb97e44c0b7df3ef5bddd99216cd57031e", +// + "Hash": "8dc7bc264f77aad9b4906b4da2ec30921ce8440e", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:11]= // @@ -1,7 +1,7 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // - "ModTime": "0", -// + "ModTime": "9", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// + "ModTime": "12", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "RefCount": "1" // }, // @@ -12,7 +12,7 @@ // }, // "V": { // "@type": "/gno.RefValue", -// - "Hash": "17ce788733dc5f31545164a039c5eee6b30e3b25", -// + "Hash": "2c172bbe0183ccc73c59d9acb196c45b0331c39e", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// - "Hash": "09f4c620a1a9ed2443740b6ee7fd7132d21303c9", +// + "Hash": "3fb4e90907e1322b3bfbbcb34d2714cc9e5617a6", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]= // @@ -21,19 +21,10 @@ // } // }, @@ -231,9 +233,9 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// - "Hash": "750e6705842b4af3b3602ccaaca3d089f8402679", -// + "Hash": "76a40dcf03d32c312c2213265c14d4de1b12a810", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// - "Hash": "2911a4420697921a6669f02a0a0855d8e8b5803b", +// + "Hash": "daf566f610636694564c5d1bc51259a3a4aaec82", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" // + }, // + "Index": "0", // + "TV": null @@ -251,56 +253,56 @@ func main() { // + "@type": "/gno.PointerValue", // + "Base": { // + "@type": "/gno.RefValue", -// + "Hash": "43f69f24b7827a331921b4af0f667346d186e0c3", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// + "Hash": "de3dc0de4894c035bdf7bb5160ea0e8c36d5239d", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" // }, // "Index": "0", // @@ -58,7 +68,7 @@ // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // - "ModTime": "0", -// + "ModTime": "9", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// + "ModTime": "12", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "RefCount": "1" // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]= // @@ -1,7 +1,7 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // - "ModTime": "0", -// + "ModTime": "9", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// + "ModTime": "12", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "RefCount": "1" // }, // @@ -12,7 +12,7 @@ // }, // "V": { // "@type": "/gno.RefValue", -// - "Hash": "71038fd71391c2de4859dedffaaf6feae2282dae", -// + "Hash": "92b2f4ebab764951f64086bce480f898f755de5a", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// - "Hash": "a87f98e79ac8505b3ea372dbdcac9d4e7abe9e52", +// + "Hash": "e38f1378fcc8de0659a7f7aa229e756f3e6fd230", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -3,7 +3,7 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// - "ModTime": "3", -// + "ModTime": "9", -// "RefCount": "2" +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "6", +// + "ModTime": "12", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -30,8 +30,8 @@ -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// - "Hash": "a4fa9bdf45caf8c6b5be7a3752704423817b3ef2", -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// + "Hash": "a303dd292d2104ce5461b1e795b9855540fbe179", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// }, -// "Index": "0", -// "TV": null +// @@ -17,8 +17,8 @@ +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// - "Hash": "ec39be2fca263e78179cfe43be626b2cccc49729", +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// + "Hash": "03b49fe8731b492dae5ebab3cb78c09c61402950", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// }, +// "Index": "0", +// "TV": null diff --git a/gnovm/tests/files/zrealm8.gno b/gnovm/tests/files/zrealm8.gno index 6d48112ac01..95ba5a0a04c 100644 --- a/gnovm/tests/files/zrealm8.gno +++ b/gnovm/tests/files/zrealm8.gno @@ -12,6 +12,8 @@ func init() { } func main() { + crossing() + println(ms) ms.Field++ println(ms) @@ -23,7 +25,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= // @@ -1,7 +1,7 @@ // { // "Fields": [ diff --git a/gnovm/tests/files/zrealm9.gno b/gnovm/tests/files/zrealm9.gno index 75e49da5e8f..dee797de8d6 100644 --- a/gnovm/tests/files/zrealm9.gno +++ b/gnovm/tests/files/zrealm9.gno @@ -12,6 +12,8 @@ func init() { } func main() { + crossing() + println(ms) ms.Field-- println(ms) @@ -23,7 +25,7 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= // @@ -1,7 +1,6 @@ // { // "Fields": [ diff --git a/gnovm/tests/files/zrealm_avl0.gno b/gnovm/tests/files/zrealm_avl0.gno index 73cf1a4dccf..f3caa2812ca 100644 --- a/gnovm/tests/files/zrealm_avl0.gno +++ b/gnovm/tests/files/zrealm_avl0.gno @@ -13,6 +13,8 @@ func init() { } func main() { + crossing() + var updated bool node, updated = node.Set("key1", "value1") // println(node, updated) @@ -24,19 +26,19 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]= // @@ -1,8 +1,8 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", // - "ModTime": "0", -// - "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// + "ModTime": "7", -// + "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// - "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// + "ModTime": "10", +// + "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "RefCount": "1" // }, // "Value": { -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:12]={ // "Fields": [ // { // "T": { @@ -91,17 +93,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:11]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "RefCount": "1" // }, // "Value": { @@ -111,12 +113,12 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "b28057ab7be6383785c0a5503e8a531bdbc21851", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// "Hash": "3288b3597947d02e04dfdc35f06b380f3c323ed5", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" // } // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ // "Fields": [ // { // "T": { @@ -155,8 +157,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "6da365f0d6cacbcdf53cd5a4b125803cddce08c2", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" +// "Hash": "27689d532d3d0324ffa3fda9408ef11e3e12b2d9", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" // }, // "Index": "0", // "TV": null @@ -174,8 +176,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "f216afe7b5a17f4ebdbb98dceccedbc22e237596", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// "Hash": "149bdb243dd96ad31fd4f897d7dbe1fe932734c0", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" // }, // "Index": "0", // "TV": null @@ -183,17 +185,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // "RefCount": "1" // }, // "Value": { @@ -203,29 +205,29 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "ff1a50d8489090af37a2c7766d659f0d717939b5", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// "Hash": "2a80953f4db02c933cfd1b5b9fed586c4695e845", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -3,7 +3,7 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// - "ModTime": "3", -// + "ModTime": "5", -// "RefCount": "2" +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "6", +// + "ModTime": "8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -30,8 +30,8 @@ -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// - "Hash": "424b49c215f471979ccd718172a016e6ec9dd934", -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// + "Hash": "ae86874f9b47fa5e64c30b3e92e9d07f2ec967a4", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" -// }, -// "Index": "0", -// "TV": null +// @@ -17,8 +17,8 @@ +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// - "Hash": "276d9e20c54d77da7b8d9652d5e4c0102be192f7", +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// + "Hash": "7112df693d0606ff9f21eb56b5e21228f9fd0463", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// }, +// "Index": "0", +// "TV": null diff --git a/gnovm/tests/files/zrealm_avl1.gno b/gnovm/tests/files/zrealm_avl1.gno index 932cc8053cc..31fe160b31d 100644 --- a/gnovm/tests/files/zrealm_avl1.gno +++ b/gnovm/tests/files/zrealm_avl1.gno @@ -13,6 +13,8 @@ func init() { } func main() { + crossing() + var updated bool node, updated = node.Set("key2", "value2") // println(node, updated) @@ -24,27 +26,27 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:6]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]= // @@ -1,7 +1,7 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", // - "ModTime": "0", -// + "ModTime": "11", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// + "ModTime": "14", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "RefCount": "1" // }, -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:11]= // @@ -1,7 +1,7 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // - "ModTime": "0", -// + "ModTime": "13", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// + "ModTime": "16", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // "RefCount": "1" // }, -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:15]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:18]={ // "Fields": [ // { // "T": { @@ -99,17 +101,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:18", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:17", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:14]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:17]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:17", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:16", // "RefCount": "1" // }, // "Value": { @@ -119,12 +121,12 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "143aebc820da33550f7338723fb1e2eec575b196", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15" +// "Hash": "27c82fe9c0e010bd7055e873dcc8e394963b7fd2", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:18" // } // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:13]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:16]={ // "Fields": [ // { // "T": { @@ -163,8 +165,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "cafae89e4d4aaaefe7fdf0691084508d4274a981", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// "Hash": "6fedda0be1874c2ab889c6498ab942a5b4788635", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" // }, // "Index": "0", // "TV": null @@ -182,8 +184,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "2e733a8e9e74fe14f0a5d10fb0f6728fa53d052d", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14" +// "Hash": "98954fd1c465552a4ba7dd00877348820d4dc0a2", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:17" // }, // "Index": "0", // "TV": null @@ -191,17 +193,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:16", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:12]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:15]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", // "RefCount": "1" // }, // "Value": { @@ -211,12 +213,12 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "b2e446f490656c19a83c43055de29c96e92a1549", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13" +// "Hash": "7c93c5b0ba175d456548c4aa126490dec76fd9ea", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:16" // } // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:11]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:14]={ // "Fields": [ // { // "T": { @@ -255,8 +257,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "4e56eeb96eb1d9b27cf603140cd03a1622b6358b", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:6" +// "Hash": "4bdce8127e004a4f9d332aeb5a78cfe8c6ca96b0", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" // }, // "Index": "0", // "TV": null @@ -274,8 +276,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "7b61530859954d1d14b2f696c91c5f37d39c21e7", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" +// "Hash": "6073f435fc15cdb2c58b42fa7d297b8c4d3543fa", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:15" // }, // "Index": "0", // "TV": null @@ -283,17 +285,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:13]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // "RefCount": "1" // }, // "Value": { @@ -303,31 +305,31 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "fedc6d430b38c985dc6a985b2fcaee97e88ba6da", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" +// "Hash": "0eb69253ed71f09f5fa08ff9f2234f576f296b13", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:14" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -3,7 +3,7 @@ +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", -// "IsEscaped": true, -// - "ModTime": "3", -// + "ModTime": "9", -// "RefCount": "2" +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// - "ModTime": "6", +// + "ModTime": "12", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -30,8 +30,8 @@ -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// - "Hash": "213a2c56908ed00c6d21377f37be61a76102cd5f", -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4" -// + "Hash": "515b45e4a6f5fa153a0251d7108781d86c52ce1c", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" -// }, -// "Index": "0", -// "TV": null -// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:4] -// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:5] +// @@ -17,8 +17,8 @@ +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// - "Hash": "b04c19a6409cd14ac64426556d8d883ee2b6a55d", +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// + "Hash": "d32ff23c6146ecf73934b20d0a0367ac558d87e4", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13" +// }, +// "Index": "0", +// "TV": null +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:7] +// d[a8ada09dee16d791fd406d629fe29bb0ed084a30:8] diff --git a/gnovm/tests/files/zrealm_avl2.gno b/gnovm/tests/files/zrealm_avl2.gno index e42fd7e8fe5..3f088b5ba83 100644 --- a/gnovm/tests/files/zrealm_avl2.gno +++ b/gnovm/tests/files/zrealm_avl2.gno @@ -12,6 +12,8 @@ func init() { } func main() { + crossing() + var updated bool updated = tree.Set("key2", "value2") // println(tree, updated) @@ -23,19 +25,19 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:5]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]= // @@ -1,8 +1,8 @@ // { // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", // - "ModTime": "0", -// - "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", -// + "ModTime": "8", -// + "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// - "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// + "ModTime": "11", +// + "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // "RefCount": "1" // }, // "Value": { -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:13]={ // "Fields": [ // { // "T": { @@ -90,17 +92,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:9]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:12]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // "RefCount": "1" // }, // "Value": { @@ -110,12 +112,12 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "be751422ef4c2bc068a456f9467d2daca27db8ca", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" +// "Hash": "4dba380235bb2da730434d50decc59b8e9e44d48", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:13" // } // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:8]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:11]={ // "Fields": [ // { // "T": { @@ -154,8 +156,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "9fa04d8791e205a6de2eedce81bb4dbd0883cac7", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" +// "Hash": "a87525f2721b8f7a44d92bfb16e49ef5f871a6cd", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" // }, // "Index": "0", // "TV": null @@ -173,8 +175,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "a55a6a6b2027d6ec5e322aa32d4269b974fe1a4f", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:9" +// "Hash": "2902f943b5a422592e03caee355d00280b055809", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:12" // }, // "Index": "0", // "TV": null @@ -182,17 +184,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "RefCount": "1" // } // } -// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:7]={ +// c[a8ada09dee16d791fd406d629fe29bb0ed084a30:10]={ // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10", // "ModTime": "0", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", // "RefCount": "1" // }, // "Value": { @@ -202,29 +204,29 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "03d901636a4e56d5bd32a75a7b923c7700c8859a", -// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// "Hash": "69090b750a9f5eb9fe19dc6a1b56023c10c4e5f4", +// "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:11" // } // } // } -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:4]= // @@ -12,8 +12,8 @@ // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// - "Hash": "89e08e63f94e2ebb6f98ee2f66057f92229e2ad7", -// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:5" -// + "Hash": "953a28a33bf1bae93eb1fcb4d1b348ccabcbaabd", -// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:7" +// - "Hash": "38d92623e7ba4beb1d35693382b944d1dd9df1d2", +// - "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:8" +// + "Hash": "c33568a8795f10e8834d5e6d0319d7eaef1841e4", +// + "ObjectID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:10" // }, // "Index": "0", // "TV": null // @@ -22,7 +22,7 @@ // ], // "ObjectInfo": { -// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", -// - "ModTime": "4", -// + "ModTime": "6", -// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:2", +// "ID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:4", +// - "ModTime": "7", +// + "ModTime": "9", +// "OwnerID": "a8ada09dee16d791fd406d629fe29bb0ed084a30:3", // "RefCount": "1" // } diff --git a/gnovm/tests/files/zrealm_borrow0.gno b/gnovm/tests/files/zrealm_borrow0.gno new file mode 100644 index 00000000000..f314e3420c0 --- /dev/null +++ b/gnovm/tests/files/zrealm_borrow0.gno @@ -0,0 +1,88 @@ +// PKGPATH: gno.land/r/borrow_test +package borrow_test + +import ( + "fmt" + "std" + + "gno.land/r/demo/tests/crossrealm" +) + +type Struct struct { + A int +} + +func (s *Struct) Mutate() { + s.A += 1 +} + +func (s *Struct) Get() int { + return s.A +} + +func (s *Struct) PrintRealms() { + s.printRealms() +} + +func (s *Struct) printRealms() { + // XXX + // printRealm is called from s.PrintRealm() + // which in this test is persisted in the same realm. + // Therefore p.printRealm() -> s.PrintRealm() + // borrows this realm, and then the crossing() + // below is called. + // Should this be allowed? + // Whether it panics or not is determined by + // 'fr.DidCross = true' in PushFrameCall. + crossing() + + fmt.Println(std.CurrentRealm()) + fmt.Println(std.PreviousRealm()) +} + +type Passthrough struct { + S *Struct +} + +func (p *Passthrough) Mutate() { + p.S.Mutate() +} + +func (p *Passthrough) Get() int { + return p.S.Get() +} + +func (p *Passthrough) PrintRealms() { + p.printRealm() +} + +func (p *Passthrough) printRealm() { + p.S.PrintRealms() +} + +var s *Struct + +func init() { + s = &Struct{A: 100} // saved in borrow_test. +} + +func main() { + crossing() + + // cross(crossrealm_b.SetObject)(s) // saved in crossrealm_b + + p := &Passthrough{S: s} + + cross(crossrealm.SetObject)(p) // saved in crossrealm. + + p.Mutate() // receiver method borrows crossrealm_b. + + println(p.Get()) + + p.PrintRealms() +} + +// Output: +// 101 +// {g1evmgnh6rmk8vgahd4p2pc3reh0dw26twaz3rqq gno.land/r/borrow_test} +// {g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm } diff --git a/gnovm/tests/files/zrealm_const.gno b/gnovm/tests/files/zrealm_const.gno index 210ceff3373..a78b71d3f51 100644 --- a/gnovm/tests/files/zrealm_const.gno +++ b/gnovm/tests/files/zrealm_const.gno @@ -4,6 +4,8 @@ package const_test import "std" func main() { + crossing() + println(std.RawAddressSize) } diff --git a/gnovm/tests/files/zrealm_crossrealm0.gno b/gnovm/tests/files/zrealm_crossrealm0.gno index 5bf34c2c852..b66428aadf3 100644 --- a/gnovm/tests/files/zrealm_crossrealm0.gno +++ b/gnovm/tests/files/zrealm_crossrealm0.gno @@ -9,6 +9,8 @@ import ( var somevalue tests.TestRealmObject func main() { + crossing() + somevalue.Field = "test" println(somevalue) } diff --git a/gnovm/tests/files/zrealm_crossrealm1.gno b/gnovm/tests/files/zrealm_crossrealm1.gno index 686468b40c7..14d197070b2 100644 --- a/gnovm/tests/files/zrealm_crossrealm1.gno +++ b/gnovm/tests/files/zrealm_crossrealm1.gno @@ -13,6 +13,8 @@ func init() { } func main() { + crossing() + println(somevalue) } diff --git a/gnovm/tests/files/zrealm_crossrealm10.gno b/gnovm/tests/files/zrealm_crossrealm10.gno index 73ad3ea74d7..4693d3cce76 100644 --- a/gnovm/tests/files/zrealm_crossrealm10.gno +++ b/gnovm/tests/files/zrealm_crossrealm10.gno @@ -6,6 +6,8 @@ import ( ) func main() { + crossing() + tests.ModifyTestRealmObject2c() println("done") } diff --git a/gnovm/tests/files/zrealm_crossrealm11.gno b/gnovm/tests/files/zrealm_crossrealm11.gno index 29295e99d10..1c4d0c40e7c 100644 --- a/gnovm/tests/files/zrealm_crossrealm11.gno +++ b/gnovm/tests/files/zrealm_crossrealm11.gno @@ -18,6 +18,8 @@ func Exec(fn func()) { } func main() { + crossing() + // Create a map of the potential callers, this will give more understandable // output than the bech32 addresses. callersByAddr := make(map[std.Address]string) @@ -40,30 +42,37 @@ func main() { tests := []struct { callStackAdd string callerFn func() std.Realm + isSwitch bool }{ { - callStackAdd: "", + callStackAdd: " -> std.PreviousRealm", callerFn: std.PreviousRealm, + isSwitch: false, }, { callStackAdd: " -> r/crossrealm_test.getPreviousRealm", callerFn: getPreviousRealm, + isSwitch: false, }, { callStackAdd: " -> p/demo/tests", callerFn: ptests.GetPreviousRealm, + isSwitch: false, }, { callStackAdd: " -> p/demo/tests -> p/demo/tests/subtests", callerFn: ptests.GetPSubtestsPreviousRealm, + isSwitch: false, }, { - callStackAdd: " -> r/demo/tests", + callStackAdd: " !> r/demo/tests", callerFn: rtests.GetPreviousRealm, + isSwitch: true, }, { - callStackAdd: " -> r/demo/tests -> r/demo/tests/subtests", + callStackAdd: " !> r/demo/tests !> r/demo/tests/subtests", callerFn: rtests.GetRSubtestsPreviousRealm, + isSwitch: true, }, } @@ -71,21 +80,55 @@ func main() { printColumns("STACK", "std.PreviousRealm") printColumns("-----", "------------------") - baseCallStack := "user1.gno -> r/crossrealm_test.main" + baseCallStack := "user1.gno !> r/crossrealm_test.main2" for i, tt := range tests { - printColumns(baseCallStack+tt.callStackAdd, callersByAddr[tt.callerFn().Address()]) + { // with no Exec + var r std.Realm + if tt.isSwitch { + r = cross(tt.callerFn)() + } else { + r = tt.callerFn() + } + printColumns(baseCallStack+tt.callStackAdd, callersByAddr[r.Address()]) + + } Exec(func() { - r := tt.callerFn() + var r std.Realm + if tt.isSwitch { + r = cross(tt.callerFn)() + } else { + r = tt.callerFn() + } assertRealm(r) printColumns(baseCallStack+" -> r/crossrealm_test.Exec"+tt.callStackAdd, callersByAddr[r.Address()]) }) rtests.Exec(func() { - r := tt.callerFn() + var r std.Realm + if tt.isSwitch { + r = cross(tt.callerFn)() + } else { + r = tt.callerFn() + } assertRealm(r) printColumns(baseCallStack+" -> r/demo/tests.Exec"+tt.callStackAdd, callersByAddr[r.Address()]) }) + cross(rtests.ExecSwitch)(func() { + var r std.Realm + if tt.isSwitch { + r = cross(tt.callerFn)() + } else { + r = tt.callerFn() + } + assertRealm(r) + printColumns(baseCallStack+" !> r/demo/tests.ExecSwitch"+tt.callStackAdd, callersByAddr[r.Address()]) + }) ptests.Exec(func() { - r := tt.callerFn() + var r std.Realm + if tt.isSwitch { + r = cross(tt.callerFn)() + } else { + r = tt.callerFn() + } assertRealm(r) printColumns(baseCallStack+" -> p/demo/tests.Exec"+tt.callStackAdd, callersByAddr[r.Address()]) }) @@ -113,27 +156,33 @@ func printColumns(left, right string) { // --- // STACK = std.PreviousRealm // ----- = ------------------ -// user1.gno -> r/crossrealm_test.main = user1.gno -// user1.gno -> r/crossrealm_test.main -> r/crossrealm_test.Exec = user1.gno -// user1.gno -> r/crossrealm_test.main -> r/demo/tests.Exec = gno.land/r/demo/tests -// user1.gno -> r/crossrealm_test.main -> p/demo/tests.Exec = user1.gno -// user1.gno -> r/crossrealm_test.main -> r/crossrealm_test.getPreviousRealm = user1.gno -// user1.gno -> r/crossrealm_test.main -> r/crossrealm_test.Exec -> r/crossrealm_test.getPreviousRealm = user1.gno -// user1.gno -> r/crossrealm_test.main -> r/demo/tests.Exec -> r/crossrealm_test.getPreviousRealm = gno.land/r/demo/tests -// user1.gno -> r/crossrealm_test.main -> p/demo/tests.Exec -> r/crossrealm_test.getPreviousRealm = user1.gno -// user1.gno -> r/crossrealm_test.main -> p/demo/tests = user1.gno -// user1.gno -> r/crossrealm_test.main -> r/crossrealm_test.Exec -> p/demo/tests = user1.gno -// user1.gno -> r/crossrealm_test.main -> r/demo/tests.Exec -> p/demo/tests = gno.land/r/demo/tests -// user1.gno -> r/crossrealm_test.main -> p/demo/tests.Exec -> p/demo/tests = user1.gno -// user1.gno -> r/crossrealm_test.main -> p/demo/tests -> p/demo/tests/subtests = user1.gno -// user1.gno -> r/crossrealm_test.main -> r/crossrealm_test.Exec -> p/demo/tests -> p/demo/tests/subtests = user1.gno -// user1.gno -> r/crossrealm_test.main -> r/demo/tests.Exec -> p/demo/tests -> p/demo/tests/subtests = gno.land/r/demo/tests -// user1.gno -> r/crossrealm_test.main -> p/demo/tests.Exec -> p/demo/tests -> p/demo/tests/subtests = user1.gno -// user1.gno -> r/crossrealm_test.main -> r/demo/tests = gno.land/r/crossrealm_test -// user1.gno -> r/crossrealm_test.main -> r/crossrealm_test.Exec -> r/demo/tests = gno.land/r/crossrealm_test -// user1.gno -> r/crossrealm_test.main -> r/demo/tests.Exec -> r/demo/tests = gno.land/r/crossrealm_test -// user1.gno -> r/crossrealm_test.main -> p/demo/tests.Exec -> r/demo/tests = gno.land/r/crossrealm_test -// user1.gno -> r/crossrealm_test.main -> r/demo/tests -> r/demo/tests/subtests = gno.land/r/demo/tests -// user1.gno -> r/crossrealm_test.main -> r/crossrealm_test.Exec -> r/demo/tests -> r/demo/tests/subtests = gno.land/r/demo/tests -// user1.gno -> r/crossrealm_test.main -> r/demo/tests.Exec -> r/demo/tests -> r/demo/tests/subtests = gno.land/r/demo/tests -// user1.gno -> r/crossrealm_test.main -> p/demo/tests.Exec -> r/demo/tests -> r/demo/tests/subtests = gno.land/r/demo/tests +// user1.gno !> r/crossrealm_test.main2 -> std.PreviousRealm = user1.gno +// user1.gno !> r/crossrealm_test.main2 -> r/crossrealm_test.Exec -> std.PreviousRealm = user1.gno +// user1.gno !> r/crossrealm_test.main2 -> r/demo/tests.Exec -> std.PreviousRealm = user1.gno +// user1.gno !> r/crossrealm_test.main2 !> r/demo/tests.ExecSwitch -> std.PreviousRealm = gno.land/r/crossrealm_test +// user1.gno !> r/crossrealm_test.main2 -> p/demo/tests.Exec -> std.PreviousRealm = user1.gno +// user1.gno !> r/crossrealm_test.main2 -> r/crossrealm_test.getPreviousRealm = user1.gno +// user1.gno !> r/crossrealm_test.main2 -> r/crossrealm_test.Exec -> r/crossrealm_test.getPreviousRealm = user1.gno +// user1.gno !> r/crossrealm_test.main2 -> r/demo/tests.Exec -> r/crossrealm_test.getPreviousRealm = user1.gno +// user1.gno !> r/crossrealm_test.main2 !> r/demo/tests.ExecSwitch -> r/crossrealm_test.getPreviousRealm = gno.land/r/crossrealm_test +// user1.gno !> r/crossrealm_test.main2 -> p/demo/tests.Exec -> r/crossrealm_test.getPreviousRealm = user1.gno +// user1.gno !> r/crossrealm_test.main2 -> p/demo/tests = user1.gno +// user1.gno !> r/crossrealm_test.main2 -> r/crossrealm_test.Exec -> p/demo/tests = user1.gno +// user1.gno !> r/crossrealm_test.main2 -> r/demo/tests.Exec -> p/demo/tests = user1.gno +// user1.gno !> r/crossrealm_test.main2 !> r/demo/tests.ExecSwitch -> p/demo/tests = gno.land/r/crossrealm_test +// user1.gno !> r/crossrealm_test.main2 -> p/demo/tests.Exec -> p/demo/tests = user1.gno +// user1.gno !> r/crossrealm_test.main2 -> p/demo/tests -> p/demo/tests/subtests = user1.gno +// user1.gno !> r/crossrealm_test.main2 -> r/crossrealm_test.Exec -> p/demo/tests -> p/demo/tests/subtests = user1.gno +// user1.gno !> r/crossrealm_test.main2 -> r/demo/tests.Exec -> p/demo/tests -> p/demo/tests/subtests = user1.gno +// user1.gno !> r/crossrealm_test.main2 !> r/demo/tests.ExecSwitch -> p/demo/tests -> p/demo/tests/subtests = gno.land/r/crossrealm_test +// user1.gno !> r/crossrealm_test.main2 -> p/demo/tests.Exec -> p/demo/tests -> p/demo/tests/subtests = user1.gno +// user1.gno !> r/crossrealm_test.main2 !> r/demo/tests = gno.land/r/crossrealm_test +// user1.gno !> r/crossrealm_test.main2 -> r/crossrealm_test.Exec !> r/demo/tests = gno.land/r/crossrealm_test +// user1.gno !> r/crossrealm_test.main2 -> r/demo/tests.Exec !> r/demo/tests = gno.land/r/crossrealm_test +// user1.gno !> r/crossrealm_test.main2 !> r/demo/tests.ExecSwitch !> r/demo/tests = gno.land/r/demo/tests +// user1.gno !> r/crossrealm_test.main2 -> p/demo/tests.Exec !> r/demo/tests = gno.land/r/crossrealm_test +// user1.gno !> r/crossrealm_test.main2 !> r/demo/tests !> r/demo/tests/subtests = gno.land/r/demo/tests +// user1.gno !> r/crossrealm_test.main2 -> r/crossrealm_test.Exec !> r/demo/tests !> r/demo/tests/subtests = gno.land/r/demo/tests +// user1.gno !> r/crossrealm_test.main2 -> r/demo/tests.Exec !> r/demo/tests !> r/demo/tests/subtests = gno.land/r/demo/tests +// user1.gno !> r/crossrealm_test.main2 !> r/demo/tests.ExecSwitch !> r/demo/tests !> r/demo/tests/subtests = gno.land/r/demo/tests +// user1.gno !> r/crossrealm_test.main2 -> p/demo/tests.Exec !> r/demo/tests !> r/demo/tests/subtests = gno.land/r/demo/tests diff --git a/gnovm/tests/files/zrealm_crossrealm12.gno b/gnovm/tests/files/zrealm_crossrealm12.gno index 5ae4d69879a..8b5ce5b7dbe 100644 --- a/gnovm/tests/files/zrealm_crossrealm12.gno +++ b/gnovm/tests/files/zrealm_crossrealm12.gno @@ -10,12 +10,16 @@ import ( ) func main() { + crossing() + tests := []struct { fn func() std.Realm }{ {std.CurrentRealm}, {psubtests.GetCurrentRealm}, - {rsubtests.GetCurrentRealm}, + {func() std.Realm { + return cross(rsubtests.GetCurrentRealm)() + }}, } for _, test := range tests { diff --git a/gnovm/tests/files/zrealm_crossrealm13.gno b/gnovm/tests/files/zrealm_crossrealm13.gno index 7aad332a3c0..9c5440f26ef 100644 --- a/gnovm/tests/files/zrealm_crossrealm13.gno +++ b/gnovm/tests/files/zrealm_crossrealm13.gno @@ -6,6 +6,12 @@ import ( ) func main() { + // Need this as base frame because main2 calls PreviousRealm. + testing.SetRealm(std.NewUserRealm("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm")) + main2() +} + +func main2() { PrintRealm() println(pad("CurrentRealm:"), std.CurrentRealm()) println(pad("PreviousRealm:"), std.PreviousRealm()) @@ -31,9 +37,6 @@ func PrintRealm() { println(pad("PrintRealm: PreviousRealm:"), std.PreviousRealm()) } -// Because this is the context of a package, using PrintRealm() -// should not change the output of the main function. - // Output: // PrintRealm: CurrentRealm: (struct{("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm" std.Address),("" string)} std.Realm) // PrintRealm: PreviousRealm: (struct{("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm" std.Address),("" string)} std.Realm) diff --git a/gnovm/tests/files/zrealm_crossrealm13a.gno b/gnovm/tests/files/zrealm_crossrealm13a.gno index 19f15c7261d..08ed6b214b6 100644 --- a/gnovm/tests/files/zrealm_crossrealm13a.gno +++ b/gnovm/tests/files/zrealm_crossrealm13a.gno @@ -7,15 +7,17 @@ import ( ) func main() { + crossing() + PrintRealm() println(pad("CurrentRealm:"), std.CurrentRealm()) println(pad("PreviousRealm:"), std.PreviousRealm()) testing.SetRealm(std.NewUserRealm("g1user")) - PrintRealm() + cross(PrintRealm)() println(pad("CurrentRealm:"), std.CurrentRealm()) println(pad("PreviousRealm:"), std.PreviousRealm()) testing.SetRealm(std.NewCodeRealm("gno.land/r/sys/users")) - PrintRealm() + cross(PrintRealm)() println(pad("CurrentRealm:"), std.CurrentRealm()) println(pad("PreviousRealm:"), std.PreviousRealm()) } @@ -28,6 +30,8 @@ func pad(s string) string { } func PrintRealm() { + crossing() + println(pad("PrintRealm: CurrentRealm:"), std.CurrentRealm()) println(pad("PrintRealm: PreviousRealm:"), std.PreviousRealm()) } diff --git a/gnovm/tests/files/zrealm_crossrealm14.gno b/gnovm/tests/files/zrealm_crossrealm14.gno index 23451e6f5d1..ab869880ccd 100644 --- a/gnovm/tests/files/zrealm_crossrealm14.gno +++ b/gnovm/tests/files/zrealm_crossrealm14.gno @@ -6,6 +6,8 @@ import ( ) func main() { + crossing() + // even though we are running within a realm, // we aren't storing the result of crossrealm.Make1(), // so this should print fine. diff --git a/gnovm/tests/files/zrealm_crossrealm15.gno b/gnovm/tests/files/zrealm_crossrealm15.gno index b6f38d81abb..f0dd58d5983 100644 --- a/gnovm/tests/files/zrealm_crossrealm15.gno +++ b/gnovm/tests/files/zrealm_crossrealm15.gno @@ -15,13 +15,18 @@ var f *fooer func init() { f = &fooer{} - crossrealm.SetFooer(f) + cross(crossrealm.SetFooer)(f) crossrealm.CallFooerFoo() + cross(crossrealm.CallFooerFooSR)() } func main() { + crossing() + print(".") } -// Error: -// new escaped mark has no object ID +// Output: +// hello gno.land/r/crossrealm_test +// hello gno.land/r/demo/tests/crossrealm +// . diff --git a/gnovm/tests/files/zrealm_crossrealm16.gno b/gnovm/tests/files/zrealm_crossrealm16.gno index e1b4001801c..9907af076b4 100644 --- a/gnovm/tests/files/zrealm_crossrealm16.gno +++ b/gnovm/tests/files/zrealm_crossrealm16.gno @@ -14,11 +14,16 @@ func (fooer) Foo() { println("hello " + std.CurrentRealm().PkgPath()) } var f *fooer func main() { + crossing() + f = &fooer{} - crossrealm.SetFooer(f) + cross(crossrealm.SetFooer)(f) crossrealm.CallFooerFoo() + cross(crossrealm.CallFooerFooSR)() print(".") } -// Error: -// new escaped mark has no object ID +// Output: +// hello gno.land/r/crossrealm_test +// hello gno.land/r/demo/tests/crossrealm +// . diff --git a/gnovm/tests/files/zrealm_crossrealm17.gno b/gnovm/tests/files/zrealm_crossrealm17.gno index 9abb918689a..b553c6a566d 100644 --- a/gnovm/tests/files/zrealm_crossrealm17.gno +++ b/gnovm/tests/files/zrealm_crossrealm17.gno @@ -16,12 +16,17 @@ type fooer struct{} var f *fooer func main() { + crossing() + f = &fooer{} c := &container{f} - crossrealm.SetFooer(c) + cross(crossrealm.SetFooer)(c) crossrealm.CallFooerFoo() + cross(crossrealm.CallFooerFooSR)() print(".") } -// Error: -// new escaped mark has no object ID +// Output: +// hello container gno.land/r/crossrealm_test +// hello container gno.land/r/demo/tests/crossrealm +// . diff --git a/gnovm/tests/files/zrealm_crossrealm18.gno b/gnovm/tests/files/zrealm_crossrealm18.gno index f7a318ed3a0..f08b787898f 100644 --- a/gnovm/tests/files/zrealm_crossrealm18.gno +++ b/gnovm/tests/files/zrealm_crossrealm18.gno @@ -11,13 +11,15 @@ type fooer struct{} func (fooer) Foo() { println("hello " + std.CurrentRealm().PkgPath()) } -var f crossrealm.Fooer = crossrealm.SetFooer(&fooer{}) +var f crossrealm.Fooer = cross(crossrealm.SetFooer)(&fooer{}) func init() { crossrealm.CallFooerFoo() } func main() { + crossing() + crossrealm.CallFooerFoo() print(".") } @@ -27,9 +29,5 @@ func main() { // hello gno.land/r/crossrealm_test // . -// Error: - // Realm: // switchrealm["gno.land/r/crossrealm_test"] -// switchrealm["gno.land/r/demo/tests/crossrealm"] -// switchrealm["gno.land/r/crossrealm_test"] diff --git a/gnovm/tests/files/zrealm_crossrealm19_stdlibs.gno b/gnovm/tests/files/zrealm_crossrealm19_stdlibs.gno index a3b864755fd..fdee941d669 100644 --- a/gnovm/tests/files/zrealm_crossrealm19_stdlibs.gno +++ b/gnovm/tests/files/zrealm_crossrealm19_stdlibs.gno @@ -20,13 +20,16 @@ var f *fooer func init() { f = &fooer{s: "A"} - crossrealm.SetFooer(f) + cross(crossrealm.SetFooer)(f) crossrealm.CallFooerFoo() } func main() { + crossing() + print(".") } -// Error: -// new escaped mark has no object ID +// Output: +// hello B gno.land/r/crossrealm_test +// . diff --git a/gnovm/tests/files/zrealm_crossrealm2.gno b/gnovm/tests/files/zrealm_crossrealm2.gno index cfcd4e6898c..ea0ab417adc 100644 --- a/gnovm/tests/files/zrealm_crossrealm2.gno +++ b/gnovm/tests/files/zrealm_crossrealm2.gno @@ -13,8 +13,10 @@ func init() { } func main() { + crossing() + // NOTE: but it is invalid to modify it using an external realm function. - tests.ModifyTestRealmObject(&somevalue) + cross(tests.ModifyTestRealmObject)(&somevalue) println(somevalue) } diff --git a/gnovm/tests/files/zrealm_crossrealm20.gno b/gnovm/tests/files/zrealm_crossrealm20.gno index 32fac2e95b9..2a1cb8b0db0 100644 --- a/gnovm/tests/files/zrealm_crossrealm20.gno +++ b/gnovm/tests/files/zrealm_crossrealm20.gno @@ -21,13 +21,15 @@ var f *fooer func init() { f = &fooer{s: "A"} fg := func() crossrealm.Fooer { return f } - crossrealm.SetFooerGetter(fg) + cross(crossrealm.SetFooerGetter)(fg) crossrealm.CallFooerGetterFoo() f.s = "C" crossrealm.CallFooerGetterFoo() } func main() { + crossing() + print(".") } @@ -38,6 +40,3 @@ func main() { // Realm: // switchrealm["gno.land/r/crossrealm_test"] - -// Error: -// diff --git a/gnovm/tests/files/zrealm_crossrealm21.gno b/gnovm/tests/files/zrealm_crossrealm21.gno index 482023ba9ec..a2fd9bedbf6 100644 --- a/gnovm/tests/files/zrealm_crossrealm21.gno +++ b/gnovm/tests/files/zrealm_crossrealm21.gno @@ -2,18 +2,18 @@ package crossrealm_test import ( - "std" - "gno.land/r/demo/tests/crossrealm" "gno.land/r/demo/tests/crossrealm_b" ) func main() { + crossing() + f := crossrealm_b.Fooer - crossrealm.SetFooer(f) - crossrealm.CallFooerFoo() + cross(crossrealm.SetFooer)(f) + cross(crossrealm.CallFooerFooSR2)() f.SetS("B") - crossrealm.CallFooerFoo() + cross(crossrealm.CallFooerFooSR2)() print(".") } @@ -24,49 +24,46 @@ func main() { // Realm: // switchrealm["gno.land/r/demo/tests/crossrealm"] -// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:2]= -// @@ -3,7 +3,7 @@ +// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:7]= +// @@ -1,9 +1,27 @@ +// { // "ObjectInfo": { -// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", -// "IsEscaped": true, -// - "ModTime": "3", -// + "ModTime": "5", -// "RefCount": "2" +// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:7", +// - "ModTime": "0", +// + "ModTime": "27", +// "OwnerID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -283,8 +283,21 @@ -// }, -// { -// "T": { -// - "@type": "/gno.RefType", -// - "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// + "@type": "/gno.PointerType", -// + "Elt": { -// + "@type": "/gno.RefType", -// + "ID": "gno.land/r/demo/tests/crossrealm_b.fooer" -// + } +// - "Value": {} +// + "Value": { +// + "T": { +// + "@type": "/gno.PointerType", +// + "Elt": { +// + "@type": "/gno.RefType", +// + "ID": "gno.land/r/demo/tests/crossrealm_b.fooer" +// + } +// + }, +// + "V": { +// + "@type": "/gno.PointerValue", +// + "Base": { +// + "@type": "/gno.RefValue", +// + "Escaped": true, +// + "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:4" // + }, -// + "V": { -// + "@type": "/gno.PointerValue", -// + "Base": { -// + "@type": "/gno.RefValue", -// + "Escaped": true, -// + "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:3" -// + }, -// + "Index": "0", -// + "TV": null -// } -// }, -// { -// u[0edc46caf30c00efd87b6c272673239eafbd051e:3]= +// + "Index": "0", +// + "TV": null +// + } +// + } +// } +// u[0edc46caf30c00efd87b6c272673239eafbd051e:4]= // @@ -1,9 +1,10 @@ // { // "ObjectInfo": { -// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:3", +// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:4", // - "ModTime": "0", // + "IsEscaped": true, -// + "ModTime": "5", -// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:2", +// + "ModTime": "27", +// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:3", // - "RefCount": "1" // + "RefCount": "2" // }, @@ -75,7 +72,7 @@ func main() { // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm"] // switchrealm["gno.land/r/demo/tests/crossrealm_b"] -// u[0edc46caf30c00efd87b6c272673239eafbd051e:4]= +// u[0edc46caf30c00efd87b6c272673239eafbd051e:5]= // @@ -7,13 +7,13 @@ // }, // "V": { @@ -86,15 +83,12 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:4", +// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:5", // - "ModTime": "0", -// + "ModTime": "5", -// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:3", +// + "ModTime": "15", +// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:4", // "RefCount": "1" // } // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm"] // switchrealm["gno.land/r/crossrealm_test"] - -// Error: -// diff --git a/gnovm/tests/files/zrealm_crossrealm22.gno b/gnovm/tests/files/zrealm_crossrealm22.gno index e0391f4dfe9..8a333467f74 100644 --- a/gnovm/tests/files/zrealm_crossrealm22.gno +++ b/gnovm/tests/files/zrealm_crossrealm22.gno @@ -2,28 +2,28 @@ package crossrealm_test import ( - "std" - "gno.land/r/demo/tests/crossrealm" "gno.land/r/demo/tests/crossrealm_b" ) func main() { + crossing() + f := crossrealm_b.Fooer - crossrealm.SetFooerGetter(func() crossrealm.Fooer { return f }) - crossrealm.CallFooerGetterFoo() + cross(crossrealm.SetFooerGetter)(func() crossrealm.Fooer { return f }) + cross(crossrealm.CallFooerGetterFooSR2)() f.SetS("B") - crossrealm.CallFooerGetterFoo() + cross(crossrealm.CallFooerGetterFooSR2)() println(".") f.SetS("C") - crossrealm.SetFooerGetter(crossrealm_b.FooerGetter) - crossrealm.CallFooerGetterFoo() + cross(crossrealm.SetFooerGetter)(crossrealm_b.FooerGetter) + cross(crossrealm.CallFooerGetterFooSR2)() println(".") f.SetS("D") - crossrealm.SetFooerGetter(crossrealm_b.FooerGetterBuilder()) - crossrealm.CallFooerGetterFoo() + cross(crossrealm.SetFooerGetter)(crossrealm_b.FooerGetterBuilder()) + cross(crossrealm.CallFooerGetterFooSR2)() println(".") } @@ -38,139 +38,128 @@ func main() { // Realm: // switchrealm["gno.land/r/demo/tests/crossrealm"] -// c[1712ac7adcfdc8e58a67e5615e20fb312394c4df:6]={ -// "Blank": {}, +// c[1712ac7adcfdc8e58a67e5615e20fb312394c4df:29]={ // "ObjectInfo": { -// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:6", +// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:29", // "ModTime": "0", -// "OwnerID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", +// "OwnerID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:28", // "RefCount": "1" // }, -// "Parent": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "f5a516808f8976c33939133293d598ce3bca4e8d:3" +// "Value": { +// "T": { +// "@type": "/gno.PointerType", +// "Elt": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/tests/crossrealm_b.fooer" +// } +// }, +// "V": { +// "@type": "/gno.PointerValue", +// "Base": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:4" +// }, +// "Index": "0", +// "TV": null +// } +// } +// } +// c[1712ac7adcfdc8e58a67e5615e20fb312394c4df:28]={ +// "Captures": [ +// { +// "T": { +// "@type": "/gno.heapItemType" +// }, +// "V": { +// "@type": "/gno.RefValue", +// "Hash": "3149f32e902d2cb3fb2913334a4472280aecf1f1", +// "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:29" +// } +// } +// ], +// "FileName": "", +// "IsClosure": false, +// "IsMethod": false, +// "Name": "", +// "NativeName": "", +// "NativePkg": "", +// "ObjectInfo": { +// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:28", +// "ModTime": "0", +// "OwnerID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:13", +// "RefCount": "1" // }, +// "Parent": null, +// "PkgPath": "gno.land/r/crossrealm_test", // "Source": { // "@type": "/gno.RefNode", // "BlockNode": null, // "Location": { -// "Column": "1", +// "Column": "35", // "File": "files/zrealm_crossrealm22.gno", -// "Line": "11", +// "Line": "13", // "PkgPath": "gno.land/r/crossrealm_test" // } // }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.PointerType", -// "Elt": { +// "SwitchRealm": false, +// "Type": { +// "@type": "/gno.FuncType", +// "IsClosure": false, +// "Params": [], +// "Results": [ +// { +// "Embedded": false, +// "Name": ".res.0", +// "Tag": "", +// "Type": { // "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm_b.fooer" +// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" // } -// }, -// "V": { -// "@type": "/gno.PointerValue", -// "Base": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:3" -// }, -// "Index": "0", -// "TV": null // } -// } -// ] +// ] +// } // } -// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:2]= -// @@ -3,7 +3,7 @@ +// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:13]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", -// "IsEscaped": true, -// - "ModTime": "3", -// + "ModTime": "5", -// "RefCount": "2" +// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:13", +// - "ModTime": "0", +// + "ModTime": "27", +// "OwnerID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -495,6 +495,46 @@ -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" -// + }, -// + "V": { -// + "@type": "/gno.FuncValue", -// + "Closure": { -// + "@type": "/gno.RefValue", -// + "Hash": "23de97a577d573252d00394ce9b71c24b0646546", -// + "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:6" -// + }, -// + "FileName": "", -// + "IsMethod": false, -// + "Name": "", -// + "NativeName": "", -// + "NativePkg": "", -// + "PkgPath": "gno.land/r/crossrealm_test", -// + "Source": { -// + "@type": "/gno.RefNode", -// + "BlockNode": null, -// + "Location": { -// + "Column": "28", -// + "File": "files/zrealm_crossrealm22.gno", -// + "Line": "13", -// + "PkgPath": "gno.land/r/crossrealm_test" -// + } -// + }, -// + "Type": { -// + "@type": "/gno.FuncType", -// + "IsClosure": false, -// + "Params": null, -// + "Results": [ -// + { -// + "Embedded": false, -// + "Name": "", -// + "Tag": "", -// + "Type": { -// + "@type": "/gno.RefType", -// + "ID": "gno.land/r/demo/tests/crossrealm.Fooer" -// + } -// + } -// + ] -// + } -// } -// }, -// { -// u[0edc46caf30c00efd87b6c272673239eafbd051e:3]= +// @@ -9,6 +9,11 @@ +// "T": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" +// + }, +// + "V": { +// + "@type": "/gno.RefValue", +// + "Hash": "96fa7ba7744e6e490ac43c0d656e11e09f3e9450", +// + "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:28" +// } +// } +// } +// u[0edc46caf30c00efd87b6c272673239eafbd051e:4]= // @@ -1,9 +1,10 @@ // { // "ObjectInfo": { -// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:3", +// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:4", // - "ModTime": "0", // + "IsEscaped": true, -// + "ModTime": "6", -// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:2", +// + "ModTime": "29", +// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:3", // - "RefCount": "1" // + "RefCount": "2" // }, // "Value": { // "T": { -// u[f5a516808f8976c33939133293d598ce3bca4e8d:3]= -// @@ -3,8 +3,8 @@ -// "ObjectInfo": { -// "ID": "f5a516808f8976c33939133293d598ce3bca4e8d:3", -// "IsEscaped": true, -// - "ModTime": "0", -// - "RefCount": "2" -// + "ModTime": "6", -// + "RefCount": "3" -// }, -// "Parent": { -// "@type": "/gno.RefValue", -// switchrealm["gno.land/r/crossrealm_test"] // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm"] // switchrealm["gno.land/r/demo/tests/crossrealm_b"] -// u[0edc46caf30c00efd87b6c272673239eafbd051e:4]= +// u[0edc46caf30c00efd87b6c272673239eafbd051e:5]= // @@ -7,13 +7,13 @@ // }, // "V": { @@ -181,17 +170,16 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:4", +// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:5", // - "ModTime": "0", -// + "ModTime": "5", -// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:3", +// + "ModTime": "15", +// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:4", // "RefCount": "1" // } -// switchrealm["gno.land/r/crossrealm_test"] // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm"] // switchrealm["gno.land/r/demo/tests/crossrealm_b"] -// u[0edc46caf30c00efd87b6c272673239eafbd051e:4]= +// u[0edc46caf30c00efd87b6c272673239eafbd051e:5]= // @@ -7,7 +7,7 @@ // }, // "V": { @@ -202,68 +190,46 @@ func main() { // } // ], // switchrealm["gno.land/r/demo/tests/crossrealm"] -// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:2]= -// @@ -3,7 +3,7 @@ +// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:13]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", -// "IsEscaped": true, -// - "ModTime": "5", -// + "ModTime": "6", -// "RefCount": "2" +// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:13", +// - "ModTime": "27", +// + "ModTime": "29", +// "OwnerID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -500,23 +500,23 @@ -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// - "Hash": "23de97a577d573252d00394ce9b71c24b0646546", -// - "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:6" -// + "Escaped": true, -// + "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:5" -// }, -// "FileName": "", -// "IsMethod": false, -// "Name": "", -// "NativeName": "", -// "NativePkg": "", -// - "PkgPath": "gno.land/r/crossrealm_test", -// - "Source": { -// - "@type": "/gno.RefNode", -// - "BlockNode": null, -// - "Location": { -// - "Column": "28", -// - "File": "files/zrealm_crossrealm22.gno", -// - "Line": "13", -// - "PkgPath": "gno.land/r/crossrealm_test" -// + "PkgPath": "gno.land/r/demo/tests/crossrealm_b", -// + "Source": { -// + "@type": "/gno.RefNode", -// + "BlockNode": null, -// + "Location": { -// + "Column": "23", -// + "File": "crossrealm.gno", -// + "Line": "23", -// + "PkgPath": "gno.land/r/demo/tests/crossrealm_b" -// } -// }, -// "Type": { -// u[0edc46caf30c00efd87b6c272673239eafbd051e:5]= -// @@ -3,8 +3,8 @@ +// @@ -12,8 +12,8 @@ +// }, +// "V": { +// "@type": "/gno.RefValue", +// - "Hash": "96fa7ba7744e6e490ac43c0d656e11e09f3e9450", +// - "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:28" +// + "Escaped": true, +// + "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:7" +// } +// } +// } +// u[0edc46caf30c00efd87b6c272673239eafbd051e:7]= +// @@ -7,9 +7,10 @@ +// "NativePkg": "", // "ObjectInfo": { -// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:5", -// "IsEscaped": true, +// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:7", // - "ModTime": "0", -// - "RefCount": "3" -// + "ModTime": "6", -// + "RefCount": "4" +// + "IsEscaped": true, +// + "ModTime": "29", +// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:6", +// - "RefCount": "1" +// + "RefCount": "2" // }, -// "Parent": { -// "@type": "/gno.RefValue", -// u[0edc46caf30c00efd87b6c272673239eafbd051e:3]= +// "Parent": null, +// "PkgPath": "gno.land/r/demo/tests/crossrealm_b", +// u[0edc46caf30c00efd87b6c272673239eafbd051e:4]= // @@ -4,7 +4,7 @@ // "IsEscaped": true, -// "ModTime": "6", -// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:2", +// "ModTime": "29", +// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:3", // - "RefCount": "2" // + "RefCount": "1" // }, @@ -273,27 +239,17 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// - "Hash": "8222b763e9bc04b4b7805e165e9f1324a39f28b6", -// + "Hash": "759fd5b507fff8ea1b18d401550d918387a63445", -// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:4" +// - "Hash": "7c146728a91cd7c6aa3141a00cede434f9601daa", +// + "Hash": "05d1e2f278c92ed1ffbe4634b915c053ac5949c2", +// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:5" // } // } -// u[f5a516808f8976c33939133293d598ce3bca4e8d:3]= -// @@ -4,7 +4,7 @@ -// "ID": "f5a516808f8976c33939133293d598ce3bca4e8d:3", -// "IsEscaped": true, -// "ModTime": "6", -// - "RefCount": "3" -// + "RefCount": "2" -// }, -// "Parent": { -// "@type": "/gno.RefValue", -// d[1712ac7adcfdc8e58a67e5615e20fb312394c4df:6] -// switchrealm["gno.land/r/demo/tests/crossrealm_b"] +// d[1712ac7adcfdc8e58a67e5615e20fb312394c4df:28] +// d[1712ac7adcfdc8e58a67e5615e20fb312394c4df:29] // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm"] // switchrealm["gno.land/r/demo/tests/crossrealm_b"] -// u[0edc46caf30c00efd87b6c272673239eafbd051e:4]= +// u[0edc46caf30c00efd87b6c272673239eafbd051e:5]= // @@ -7,7 +7,7 @@ // }, // "V": { @@ -303,70 +259,72 @@ func main() { // } // } // ], -// switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm"] -// c[1712ac7adcfdc8e58a67e5615e20fb312394c4df:7]={ -// "Blank": {}, +// c[1712ac7adcfdc8e58a67e5615e20fb312394c4df:30]={ +// "FileName": "", +// "IsClosure": false, +// "IsMethod": false, +// "Name": "", +// "NativeName": "", +// "NativePkg": "", // "ObjectInfo": { -// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:7", +// "ID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:30", // "ModTime": "0", -// "OwnerID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:2", +// "OwnerID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:13", // "RefCount": "1" // }, -// "Parent": { -// "@type": "/gno.RefValue", -// "Escaped": true, -// "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:5" -// }, +// "Parent": null, +// "PkgPath": "gno.land/r/demo/tests/crossrealm_b", // "Source": { // "@type": "/gno.RefNode", // "BlockNode": null, // "Location": { -// "Column": "23", +// "Column": "62", // "File": "crossrealm.gno", -// "Line": "24", +// "Line": "26", // "PkgPath": "gno.land/r/demo/tests/crossrealm_b" // } // }, -// "Values": [ -// { -// "T": { -// "@type": "/gno.RefType", -// "ID": "gno.land/r/demo/tests/crossrealm.FooerGetter" +// "SwitchRealm": false, +// "Type": { +// "@type": "/gno.FuncType", +// "IsClosure": false, +// "Params": [], +// "Results": [ +// { +// "Embedded": false, +// "Name": ".res.0", +// "Tag": "", +// "Type": { +// "@type": "/gno.RefType", +// "ID": "gno.land/r/demo/tests/crossrealm.Fooer" +// } // } -// } -// ] +// ] +// } // } -// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:2]= -// @@ -500,8 +500,8 @@ -// "@type": "/gno.FuncValue", -// "Closure": { -// "@type": "/gno.RefValue", -// - "Escaped": true, -// - "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:5" -// + "Hash": "89352b352826005a86eee78e6c832b43ae0ab6a6", -// + "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:7" -// }, -// "FileName": "", -// "IsMethod": false, -// @@ -513,9 +513,9 @@ -// "@type": "/gno.RefNode", -// "BlockNode": null, -// "Location": { -// - "Column": "23", -// - "File": "crossrealm.gno", -// - "Line": "23", -// + "Column": "62", -// + "File": "crossrealm.gno", -// + "Line": "24", -// "PkgPath": "gno.land/r/demo/tests/crossrealm_b" -// } -// }, -// u[0edc46caf30c00efd87b6c272673239eafbd051e:5]=(noop) -// switchrealm["gno.land/r/demo/tests/crossrealm_b"] +// u[1712ac7adcfdc8e58a67e5615e20fb312394c4df:13]= +// @@ -12,8 +12,8 @@ +// }, +// "V": { +// "@type": "/gno.RefValue", +// - "Escaped": true, +// - "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:7" +// + "Hash": "d55f6f80443199ddb7062c89a2ec81bc3dd60113", +// + "ObjectID": "1712ac7adcfdc8e58a67e5615e20fb312394c4df:30" +// } +// } +// } +// u[0edc46caf30c00efd87b6c272673239eafbd051e:7]= +// @@ -10,7 +10,7 @@ +// "IsEscaped": true, +// "ModTime": "29", +// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:6", +// - "RefCount": "2" +// + "RefCount": "1" +// }, +// "Parent": null, +// "PkgPath": "gno.land/r/demo/tests/crossrealm_b", // switchrealm["gno.land/r/demo/tests/crossrealm_b"] // switchrealm["gno.land/r/demo/tests/crossrealm"] // switchrealm["gno.land/r/crossrealm_test"] - -// Error: -// diff --git a/gnovm/tests/files/zrealm_crossrealm23.gno b/gnovm/tests/files/zrealm_crossrealm23.gno new file mode 100644 index 00000000000..436fe7ca8ce --- /dev/null +++ b/gnovm/tests/files/zrealm_crossrealm23.gno @@ -0,0 +1,26 @@ +// PKGPATH: gno.land/r/crossrealm_test +package crossrealm_test + +import ( + "std" + + "gno.land/r/demo/tests/crossrealm" +) + +func main() { + crossing() + + println(cross(crossrealm.ExecSR)(func() string { + rlm1 := std.CurrentRealm() + rlm2 := std.PreviousRealm() + return string(rlm1.Address()) + " " + rlm1.PkgPath() + "\n" + string(rlm2.Address()) + " " + rlm2.PkgPath() + })) +} + +// Output: +// g1m6pzw9ex0xk3hamzch0wtad4e696gjyju0z2tz gno.land/r/demo/tests/crossrealm +// g1vla5mffzum6060t99u4xhm8mnhgxr0sz4k574p gno.land/r/crossrealm_test + +// Realm: +// switchrealm["gno.land/r/demo/tests/crossrealm"] +// switchrealm["gno.land/r/crossrealm_test"] diff --git a/gnovm/tests/files/zrealm_crossrealm24.gno b/gnovm/tests/files/zrealm_crossrealm24.gno new file mode 100644 index 00000000000..32b5dddf00b --- /dev/null +++ b/gnovm/tests/files/zrealm_crossrealm24.gno @@ -0,0 +1,26 @@ +// PKGPATH: gno.land/r/crossrealm_test +package crossrealm_test + +import ( + "gno.land/r/demo/tests/crossrealm_b" +) + +type Struct struct { + A int +} + +func main() { + crossing() + + a := 1 + s := &Struct{A: 100} + cross(crossrealm_b.SetClosure)(func() {}) + cross(crossrealm_b.SetObject)(&a) + //cross(crossrealm_b.SetObject)(&s.A) + //cross(crossrealm_b.SetObject)(func() { &s.A }) + s.A = 123 + println(s, a) +} + +// Output: +// &(struct{(123 int)} gno.land/r/crossrealm_test.Struct) 1 diff --git a/gnovm/tests/files/zrealm_crossrealm25.gno b/gnovm/tests/files/zrealm_crossrealm25.gno new file mode 100644 index 00000000000..967097f078d --- /dev/null +++ b/gnovm/tests/files/zrealm_crossrealm25.gno @@ -0,0 +1,22 @@ +// PKGPATH: gno.land/r/crossrealm_test +package crossrealm_test + +import ( + "gno.land/r/demo/tests/crossrealm_b" +) + +type Struct struct { + A int +} + +func main() { + crossing() + + s := &Struct{A: 100} + cross(crossrealm_b.SetObject)(&s.A) + s.A = 123 + println(s) +} + +// Error: +// cannot modify external-realm or non-realm object diff --git a/gnovm/tests/files/zrealm_crossrealm26.gno b/gnovm/tests/files/zrealm_crossrealm26.gno new file mode 100644 index 00000000000..7aa1012e922 --- /dev/null +++ b/gnovm/tests/files/zrealm_crossrealm26.gno @@ -0,0 +1,22 @@ +// PKGPATH: gno.land/r/crossrealm_test +package crossrealm_test + +import ( + "gno.land/r/demo/tests/crossrealm_b" +) + +type Struct struct { + A int +} + +func main() { + crossing() + + s := &Struct{A: 100} + cross(crossrealm_b.SetObject)(func() { &s.A }) + s.A = 123 + println(s) +} + +// Error: +// cannot modify external-realm or non-realm object diff --git a/gnovm/tests/files/zrealm_crossrealm27.gno b/gnovm/tests/files/zrealm_crossrealm27.gno new file mode 100644 index 00000000000..a0ac3ac4d17 --- /dev/null +++ b/gnovm/tests/files/zrealm_crossrealm27.gno @@ -0,0 +1,31 @@ +// PKGPATH: gno.land/r/crossrealm_test +package crossrealm_test + +import ( + "gno.land/r/demo/tests/crossrealm_b" +) + +type Struct struct { + A int +} + +var s *Struct + +func init() { + s2 := &Struct{A: 100} + cross(crossrealm_b.SetObject)(func() { &s2.A }) + s = s2 +} + +func main() { + crossing() + + s.A = 123 + println(s) +} + +// Error: +// cannot modify external-realm or non-realm object + +// Preprocessed: +// file{ package crossrealm_test; import crossrealm_b gno.land/r/demo/tests/crossrealm_b; type Struct (const-type gno.land/r/crossrealm_test.Struct); var s *(Struct); func init.2() { s2 := &(Struct{A: (const (100 int))}); (const (cross func(func(interface {})) func(interface {})))((const (ref(gno.land/r/demo/tests/crossrealm_b) package{})).SetObject)(func func(){ &(s2<~VPBlock(1,0)>.A) }>); s<~VPBlock(3,1)> = s2<~VPBlock(1,0)> }; func main() { (const (crossing func()))(); s<~VPBlock(3,1)>.A = (const (123 int)); (const (println func(...interface {})))(s<~VPBlock(3,1)>) } } diff --git a/gnovm/tests/files/zrealm_crossrealm28.gno b/gnovm/tests/files/zrealm_crossrealm28.gno new file mode 100644 index 00000000000..b87d86c600b --- /dev/null +++ b/gnovm/tests/files/zrealm_crossrealm28.gno @@ -0,0 +1,83 @@ +// PKGPATH: gno.land/r/crossrealm_test +package crossrealm_test + +import ( + "gno.land/r/demo/tests/crossrealm_b" +) + +type Struct struct { + A int +} + +var s *Struct + +func init() { + s = &Struct{A: 100} + cross(crossrealm_b.SetObject)(func() { &s.A }) +} + +func main() { + crossing() + + //s := &Struct{A: 100} + cross(crossrealm_b.SetObject)(123) + s.A = 123 + println(s) +} + +// Output: +// &(struct{(123 int)} gno.land/r/crossrealm_test.Struct) + +// Preprocessed: +// file{ package crossrealm_test; import crossrealm_b gno.land/r/demo/tests/crossrealm_b; type Struct (const-type gno.land/r/crossrealm_test.Struct); var s *(Struct); func init.2() { s<~VPBlock(3,1)> = &(Struct{A: (const (100 int))}); (const (cross func(func(interface {})) func(interface {})))((const (ref(gno.land/r/demo/tests/crossrealm_b) package{})).SetObject)(func func(){ &((const (ref(gno.land/r/crossrealm_test) package{})).s.A) }) }; func main() { (const (crossing func()))(); (const (cross func(func(interface {})) func(interface {})))((const (ref(gno.land/r/demo/tests/crossrealm_b) package{})).SetObject)((const (123 int))); s<~VPBlock(3,1)>.A = (const (123 int)); (const (println func(...interface {})))(s<~VPBlock(3,1)>) } } + +// Realm: +// switchrealm["gno.land/r/demo/tests/crossrealm_b"] +// u[0edc46caf30c00efd87b6c272673239eafbd051e:13]= +// @@ -1,21 +1,15 @@ +// { +// "ObjectInfo": { +// "ID": "0edc46caf30c00efd87b6c272673239eafbd051e:13", +// - "ModTime": "15", +// + "ModTime": "16", +// "OwnerID": "0edc46caf30c00efd87b6c272673239eafbd051e:2", +// "RefCount": "1" +// }, +// "Value": { +// + "N": "ewAAAAAAAAA=", +// "T": { +// - "@type": "/gno.FuncType", +// - "IsClosure": false, +// - "Params": null, +// - "Results": null +// - }, +// - "V": { +// - "@type": "/gno.RefValue", +// - "Hash": "5b8e03f7f8b6fe2399fb8f4a27dd5a1a49518df8", +// - "ObjectID": "0edc46caf30c00efd87b6c272673239eafbd051e:16" +// + "@type": "/gno.PrimitiveType", +// + "value": "32" +// } +// } +// } +// d[0edc46caf30c00efd87b6c272673239eafbd051e:16] +// switchrealm["gno.land/r/crossrealm_test"] +// u[f5a516808f8976c33939133293d598ce3bca4e8d:8]= +// @@ -1,7 +1,7 @@ +// { +// "Fields": [ +// { +// - "N": "ZAAAAAAAAAA=", +// + "N": "ewAAAAAAAAA=", +// "T": { +// "@type": "/gno.PrimitiveType", +// "value": "32" +// @@ -10,7 +10,7 @@ +// ], +// "ObjectInfo": { +// "ID": "f5a516808f8976c33939133293d598ce3bca4e8d:8", +// - "ModTime": "0", +// + "ModTime": "8", +// "OwnerID": "f5a516808f8976c33939133293d598ce3bca4e8d:7", +// "RefCount": "1" +// } diff --git a/gnovm/tests/files/zrealm_crossrealm29.gno b/gnovm/tests/files/zrealm_crossrealm29.gno new file mode 100644 index 00000000000..4bfed945db2 --- /dev/null +++ b/gnovm/tests/files/zrealm_crossrealm29.gno @@ -0,0 +1,35 @@ +// PKGPATH: gno.land/r/crossrealm_test +package crossrealm_test + +import ( + "gno.land/r/demo/tests/crossrealm_b" +) + +type Struct struct { + A int +} + +var s *Struct + +func init() { + s = &Struct{A: 100} + // This is OK, 's' is short for 'crossrelm_test.s', + // so there are no captures for the closure. + // Since s is a 'field' of the package block + // the object 's' is not stored in crossrealm_b, + // it is lazily attached to this realm!!! + cross(crossrealm_b.SetObject)(func() { &s.A }) +} + +func main() { + crossing() + + s.A = 123 + println(s) +} + +// Output: +// &(struct{(123 int)} gno.land/r/crossrealm_test.Struct) + +// Preprocessed: +// file{ package crossrealm_test; import crossrealm_b gno.land/r/demo/tests/crossrealm_b; type Struct (const-type gno.land/r/crossrealm_test.Struct); var s *(Struct); func init.2() { s<~VPBlock(3,1)> = &(Struct{A: (const (100 int))}); (const (cross func(func(interface {})) func(interface {})))((const (ref(gno.land/r/demo/tests/crossrealm_b) package{})).SetObject)(func func(){ &((const (ref(gno.land/r/crossrealm_test) package{})).s.A) }) }; func main() { (const (crossing func()))(); s<~VPBlock(3,1)>.A = (const (123 int)); (const (println func(...interface {})))(s<~VPBlock(3,1)>) } } diff --git a/gnovm/tests/files/zrealm_crossrealm3.gno b/gnovm/tests/files/zrealm_crossrealm3.gno index 6aa9c5247d8..7f20eeb72bc 100644 --- a/gnovm/tests/files/zrealm_crossrealm3.gno +++ b/gnovm/tests/files/zrealm_crossrealm3.gno @@ -13,10 +13,12 @@ func init() { } func main() { - // NOTE: but it is invalid to modify it using an external realm function. + crossing() + + // NOTE: it is also valid to modify it using an external realm function. somevalue.Modify() println(somevalue) } -// Error: -// cannot modify external-realm or non-realm object +// Output: +// (struct{("test_modified" string)} gno.land/r/demo/tests.TestRealmObject) diff --git a/gnovm/tests/files/zrealm_crossrealm4.gno b/gnovm/tests/files/zrealm_crossrealm4.gno index ed73b7ad6bb..a28af50e9e5 100644 --- a/gnovm/tests/files/zrealm_crossrealm4.gno +++ b/gnovm/tests/files/zrealm_crossrealm4.gno @@ -13,6 +13,8 @@ func init() { } func main() { + crossing() + // NOTE: it is valid to modify it using the external realm function. somevalue.Modify() println(somevalue) diff --git a/gnovm/tests/files/zrealm_crossrealm5.gno b/gnovm/tests/files/zrealm_crossrealm5.gno index c7560b21463..b78acc9969c 100644 --- a/gnovm/tests/files/zrealm_crossrealm5.gno +++ b/gnovm/tests/files/zrealm_crossrealm5.gno @@ -13,6 +13,8 @@ func init() { } func main() { + crossing() + // NOTE: but it is invalid to modify it directly. somevalue.Field = "test" println(somevalue) diff --git a/gnovm/tests/files/zrealm_crossrealm6.gno b/gnovm/tests/files/zrealm_crossrealm6.gno index d2e7a4b096a..3de0bcf48ae 100644 --- a/gnovm/tests/files/zrealm_crossrealm6.gno +++ b/gnovm/tests/files/zrealm_crossrealm6.gno @@ -12,6 +12,8 @@ func init() { } func main() { + crossing() + // this is OK because the method is declared in a non-realm package. somevalue.Modify() println(somevalue) diff --git a/gnovm/tests/files/zrealm_crossrealm7.gno b/gnovm/tests/files/zrealm_crossrealm7.gno index 5a4dc3002cc..1ac062ff56e 100644 --- a/gnovm/tests/files/zrealm_crossrealm7.gno +++ b/gnovm/tests/files/zrealm_crossrealm7.gno @@ -6,6 +6,8 @@ import ( ) func main() { + crossing() + tests.ModifyTestRealmObject2a() println("done") } diff --git a/gnovm/tests/files/zrealm_crossrealm8.gno b/gnovm/tests/files/zrealm_crossrealm8.gno index f03085ff4c7..1decf6f6728 100644 --- a/gnovm/tests/files/zrealm_crossrealm8.gno +++ b/gnovm/tests/files/zrealm_crossrealm8.gno @@ -6,6 +6,8 @@ import ( ) func main() { + crossing() + tests.ModifyTestRealmObject2b() println("done") } diff --git a/gnovm/tests/files/zrealm_crossrealm9.gno b/gnovm/tests/files/zrealm_crossrealm9.gno index 96a7a3484d7..dce0cf22bad 100644 --- a/gnovm/tests/files/zrealm_crossrealm9.gno +++ b/gnovm/tests/files/zrealm_crossrealm9.gno @@ -6,6 +6,8 @@ import ( ) func main() { + crossing() + tests.SomeValue2.Field = "modified" println("done") } diff --git a/gnovm/tests/files/zrealm_example.gno b/gnovm/tests/files/zrealm_example.gno index d105f5cbe6e..f4bc4015389 100644 --- a/gnovm/tests/files/zrealm_example.gno +++ b/gnovm/tests/files/zrealm_example.gno @@ -12,6 +12,8 @@ func init() { } func main() { + crossing() + gPlot.AddPost("TEST_TITLE", "TEST_BODY") println(gPlot.String()) } @@ -24,7 +26,7 @@ func main() { // Realm: // switchrealm["gno.land/r/example"] -// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:11]={ +// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:14]={ // "Fields": [ // { // "T": { @@ -37,13 +39,13 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:11", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:14", // "ModTime": "0", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:10", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:13", // "RefCount": "1" // } // } -// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:10]={ +// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:13]={ // "Fields": [ // { // "T": { @@ -72,23 +74,23 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "f190df54e397e2006cee3fc525bcc1b4d556e4c4", -// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:11" +// "Hash": "5de3e7ff11ff5edc7f205674996c7c47a0c45029", +// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:14" // } // } // ], // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:10", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:13", // "ModTime": "0", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:9", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:12", // "RefCount": "1" // } // } -// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:9]={ +// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:12]={ // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:9", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:12", // "ModTime": "0", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:8", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:11", // "RefCount": "1" // }, // "Value": { @@ -98,12 +100,12 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "a74fad6da10f1cec74ad3a8751490b4dca957761", -// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:10" +// "Hash": "98e91a75929fc778d9f0f62886abd62f9152de1a", +// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:13" // } // } // } -// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:8]={ +// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:11]={ // "Fields": [ // { // "T": { @@ -127,8 +129,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "8b11b3d07ddeb034f70a114c9433ec6bd5cbf899", -// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:9" +// "Hash": "3c03811f000dfdd7e40014cc745f93b22e29d4b8", +// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:12" // }, // "Index": "0", // "TV": null @@ -167,17 +169,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:8", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:11", // "ModTime": "0", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:7", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:10", // "RefCount": "1" // } // } -// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:7]={ +// c[1ffd45e074aa1b8df562907c95ad97526b7ca187:10]={ // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:7", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:10", // "ModTime": "0", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:6", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:9", // "RefCount": "1" // }, // "Value": { @@ -187,12 +189,12 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "869abdac30a3ae78b2191806e1c894c48e399122", -// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:8" +// "Hash": "8e780dfd5043f7bd20a8898f2447cc1f130d436a", +// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:11" // } // } // } -// u[1ffd45e074aa1b8df562907c95ad97526b7ca187:6]= +// u[1ffd45e074aa1b8df562907c95ad97526b7ca187:9]= // @@ -7,12 +7,22 @@ // "@type": "/gno.RefType", // "ID": "gno.land/p/demo/avl.Node" @@ -202,8 +204,8 @@ func main() { // + "@type": "/gno.PointerValue", // + "Base": { // + "@type": "/gno.RefValue", -// + "Hash": "a919087d0eba652876f9a8df18b30ec5ddc8c26e", -// + "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:7" +// + "Hash": "cdd32e91aaf44002f38742d156dc218b01f96341", +// + "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:10" // + }, // + "Index": "0", // + "TV": null @@ -211,20 +213,20 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:6", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:9", // - "ModTime": "0", -// + "ModTime": "6", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:5", +// + "ModTime": "9", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:8", // "RefCount": "1" // } -// u[1ffd45e074aa1b8df562907c95ad97526b7ca187:5]= +// u[1ffd45e074aa1b8df562907c95ad97526b7ca187:8]= // @@ -17,11 +17,12 @@ // }, // "V": { // "@type": "/gno.RefValue", -// - "Hash": "56a1f8857b80bef7ca5a1c4c2c2d222d3338662d", -// + "Hash": "dfdeb7ed80c5b030c3a5e9701d00c66203de6f57", -// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:6" +// - "Hash": "26d848664a18b9656977e1a343672fa667890bac", +// + "Hash": "543a4c092422658607a07f8bf0e0533d04ef7fe2", +// "ObjectID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:9" // } // }, // { @@ -235,9 +237,9 @@ func main() { // @@ -30,7 +31,7 @@ // ], // "ObjectInfo": { -// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:5", +// "ID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:8", // - "ModTime": "0", -// + "ModTime": "6", -// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:4", +// + "ModTime": "9", +// "OwnerID": "1ffd45e074aa1b8df562907c95ad97526b7ca187:7", // "RefCount": "1" // } diff --git a/gnovm/tests/files/zrealm_initctx.gno b/gnovm/tests/files/zrealm_initctx.gno index 4fc05a6e59c..91c6e78f00c 100644 --- a/gnovm/tests/files/zrealm_initctx.gno +++ b/gnovm/tests/files/zrealm_initctx.gno @@ -2,8 +2,9 @@ package tests_test import ( - "gno.land/r/demo/tests" "std" + + "gno.land/r/demo/tests" ) var addr = std.Address("test") @@ -11,17 +12,21 @@ var addrInit = std.Address("addrInit") func init() { addr = std.OriginCaller() - addrInit = tests.InitOriginCaller() + addrInit = cross(tests.InitOriginCaller)() } func main() { + crossing() + + // Prints blanks because init's origin caller is blank. + // XXX consider panic instead println(addr) println(addrInit) } // Output: -// g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm -// g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm +// +// // Realm: // switchrealm["gno.land/r/demo/tests_test"] diff --git a/gnovm/tests/files/zrealm_map0.gno b/gnovm/tests/files/zrealm_map0.gno index 1dd2deff755..855712081a9 100644 --- a/gnovm/tests/files/zrealm_map0.gno +++ b/gnovm/tests/files/zrealm_map0.gno @@ -8,6 +8,8 @@ func init() { } func main() { + crossing() + m["foobar"] = 1 println(m) } diff --git a/gnovm/tests/files/zrealm_natbind0.gno b/gnovm/tests/files/zrealm_natbind0.gno index 37182519838..f7c71a10c92 100644 --- a/gnovm/tests/files/zrealm_natbind0.gno +++ b/gnovm/tests/files/zrealm_natbind0.gno @@ -12,6 +12,8 @@ func init() { } func main() { + crossing() + // NOTE: this test uses ChainHeight and ChainID, which are "pure" // natively bound functions (ie. not indirections through a wrapper fn, // to convert the types to builtin go/gno identifiers). @@ -28,43 +30,46 @@ func main() { // Realm: // switchrealm["gno.land/r/test"] -// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:2]= -// @@ -30,7 +30,7 @@ -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// - "value": "1024" -// + "value": "16" -// } -// } -// ] -// @@ -44,8 +44,8 @@ -// }, -// "FileName": "native.gno", -// "IsMethod": false, -// - "Name": "ChainHeight", -// - "NativeName": "ChainHeight", -// + "Name": "ChainID", -// + "NativeName": "ChainID", -// "NativePkg": "std", -// "PkgPath": "std", -// "Source": { -// @@ -54,7 +54,7 @@ -// "Location": { -// "Column": "1", -// "File": "native.gno", -// - "Line": "11", -// + "Line": "9", -// "PkgPath": "std" +// u[a8ada09dee16d791fd406d629fe29bb0ed084a30:3]= +// @@ -17,7 +17,7 @@ +// "Tag": "", +// "Type": { +// "@type": "/gno.PrimitiveType", +// - "value": "1024" +// + "value": "16" // } -// }, -// @@ -69,7 +69,7 @@ -// "Tag": "", -// "Type": { -// "@type": "/gno.PrimitiveType", -// - "value": "1024" -// + "value": "16" -// } -// } -// ] -// u[a7f5397443359ea76c50be82c77f1f893a060925:10]=(noop) +// } +// ] +// @@ -25,7 +25,7 @@ +// "V": { +// "@type": "/gno.RefValue", +// "Escaped": true, +// - "ObjectID": "a7f5397443359ea76c50be82c77f1f893a060925:36" +// + "ObjectID": "a7f5397443359ea76c50be82c77f1f893a060925:33" +// } +// } +// } +// u[a7f5397443359ea76c50be82c77f1f893a060925:33]= +// @@ -7,9 +7,10 @@ +// "NativePkg": "std", +// "ObjectInfo": { +// "ID": "a7f5397443359ea76c50be82c77f1f893a060925:33", +// - "ModTime": "0", +// + "IsEscaped": true, +// + "ModTime": "6", +// "OwnerID": "a7f5397443359ea76c50be82c77f1f893a060925:2", +// - "RefCount": "1" +// + "RefCount": "2" +// }, +// "Parent": { +// "@type": "/gno.RefValue", +// u[a7f5397443359ea76c50be82c77f1f893a060925:36]= +// @@ -10,7 +10,7 @@ +// "IsEscaped": true, +// "ModTime": "6", +// "OwnerID": "a7f5397443359ea76c50be82c77f1f893a060925:2", +// - "RefCount": "2" +// + "RefCount": "1" +// }, +// "Parent": { +// "@type": "/gno.RefValue", diff --git a/gnovm/tests/files/zrealm_natbind1_stdlibs.gno b/gnovm/tests/files/zrealm_natbind1_stdlibs.gno index 5b2c12b3c39..8a6666cd91a 100644 --- a/gnovm/tests/files/zrealm_natbind1_stdlibs.gno +++ b/gnovm/tests/files/zrealm_natbind1_stdlibs.gno @@ -6,6 +6,8 @@ import ( ) func main() { + crossing() + println(std.ChainDomain()) } diff --git a/gnovm/tests/files/zrealm_no_borrow.gno b/gnovm/tests/files/zrealm_no_borrow.gno new file mode 100644 index 00000000000..38e175c22cb --- /dev/null +++ b/gnovm/tests/files/zrealm_no_borrow.gno @@ -0,0 +1,49 @@ +// PKGPATH: gno.land/r/borrow_test +package borrow_test + +import ( + "fmt" + "std" + + "gno.land/r/demo/tests/crossrealm" +) + +type Struct struct { + A int +} + +func (s *Struct) Mutate() { + s.A += 1 + fmt.Printf("s.A: %d\n", s.A) + fmt.Println("current realm: ", std.CurrentRealm()) + fmt.Println("previous realm: ", std.PreviousRealm()) +} + +type Passthrough struct { + S *Struct +} + +func (p *Passthrough) Mutate() { + p.S.Mutate() +} + +func main() { + crossing() + + s := &Struct{A: 100} + p := &Passthrough{S: s} + + cross(crossrealm.SetObject)(p) // saved in crossrealm. + + p.Mutate() +} + +// Note: 1. p and s are stored in `crossrealm`, so no borrow to `borrow_test`. +// 2. the `CurrentRealm` and `PreviousRealm` are `borrow_test` +// and the origin user realm. which means the borrowed realm +// is excluded from CurrentRealm and PreviousRealm. + +// Output: +// s.A: 101 +// current realm: {g1evmgnh6rmk8vgahd4p2pc3reh0dw26twaz3rqq gno.land/r/borrow_test} +// previous realm: {g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm } diff --git a/gnovm/tests/files/zrealm_panic.gno b/gnovm/tests/files/zrealm_panic.gno index 154a93ac8bf..0176655b1ef 100644 --- a/gnovm/tests/files/zrealm_panic.gno +++ b/gnovm/tests/files/zrealm_panic.gno @@ -8,6 +8,8 @@ func (ms MyStruct) Panic() { } func main() { + crossing() + ms := MyStruct{} ms.Panic() } @@ -19,5 +21,5 @@ func main() { // panic: panic // ms.Panic() // gno.land/r/test/files/zrealm_panic.gno:7 -// main() -// gno.land/r/test/files/zrealm_panic.gno:12 +// cross(main)() +// gno.land/r/test/files/zrealm_panic.gno:14 diff --git a/gnovm/tests/files/zrealm_std0.gno b/gnovm/tests/files/zrealm_std0.gno index fff6d6882b8..41c00ef99bb 100644 --- a/gnovm/tests/files/zrealm_std0.gno +++ b/gnovm/tests/files/zrealm_std0.gno @@ -6,6 +6,8 @@ import ( ) func main() { + crossing() + caller := std.OriginCaller() println(caller) } diff --git a/gnovm/tests/files/zrealm_std1.gno b/gnovm/tests/files/zrealm_std1.gno index 8206b7b4097..372eb09a480 100644 --- a/gnovm/tests/files/zrealm_std1.gno +++ b/gnovm/tests/files/zrealm_std1.gno @@ -8,12 +8,16 @@ import ( var aset *std.AddressList func init() { - caller := std.OriginCaller() + // This won't work, init is called with empty caller. + // caller := std.OriginCaller() + caller := std.Address("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm") aset = std.NewAddressList() aset.AddAddress(caller) } func main() { + crossing() + println(*aset) caller := std.OriginCaller() err := aset.AddAddress(caller) @@ -25,7 +29,7 @@ func main() { } // Output: -// (slice[ref(1ed29bd278d735e20e296bd4afe927501941392f:5)] std.AddressList) +// (slice[ref(1ed29bd278d735e20e296bd4afe927501941392f:8)] std.AddressList) // error: address already exists // has: true // has: false diff --git a/gnovm/tests/files/zrealm_std2.gno b/gnovm/tests/files/zrealm_std2.gno index 15d137bf556..59c7f49a07a 100644 --- a/gnovm/tests/files/zrealm_std2.gno +++ b/gnovm/tests/files/zrealm_std2.gno @@ -9,12 +9,16 @@ import ( var aset std.AddressSet func init() { - caller := std.OriginCaller() + // This won't work, init is called with empty caller. + // caller := std.OriginCaller() + caller := std.Address("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm") aset = std.NewAddressList() aset.AddAddress(caller) } func main() { + crossing() + println(*(aset.(*std.AddressList))) caller := std.OriginCaller() err := aset.AddAddress(caller) @@ -26,7 +30,7 @@ func main() { } // Output: -// (slice[ref(1ed29bd278d735e20e296bd4afe927501941392f:5)] std.AddressList) +// (slice[ref(1ed29bd278d735e20e296bd4afe927501941392f:8)] std.AddressList) // error: address already exists // has: true // has: false diff --git a/gnovm/tests/files/zrealm_std3.gno b/gnovm/tests/files/zrealm_std3.gno index 4f1d1bc827a..27a3b59e5c9 100644 --- a/gnovm/tests/files/zrealm_std3.gno +++ b/gnovm/tests/files/zrealm_std3.gno @@ -10,6 +10,8 @@ func foo() { } func main() { + crossing() + println("main", std.CurrentRealm().PkgPath()) foo() } diff --git a/gnovm/tests/files/zrealm_std4.gno b/gnovm/tests/files/zrealm_std4.gno index 4b8a1d6dfb3..1f146f02758 100644 --- a/gnovm/tests/files/zrealm_std4.gno +++ b/gnovm/tests/files/zrealm_std4.gno @@ -6,12 +6,14 @@ import ( ) func main() { - println("test1", tests.CurrentRealmPath()) + crossing() + + println("test1", cross(tests.CurrentRealmPath)()) func() { - println("test2", tests.CurrentRealmPath()) + println("test2", cross(tests.CurrentRealmPath)()) }() x := tests.CurrentRealmPath - println("test3", x()) + println("test3", cross(x)()) } // Output: diff --git a/gnovm/tests/files/zrealm_std5.gno b/gnovm/tests/files/zrealm_std5.gno index 86d26eef368..6b5749a036e 100644 --- a/gnovm/tests/files/zrealm_std5.gno +++ b/gnovm/tests/files/zrealm_std5.gno @@ -6,6 +6,8 @@ import ( ) func main() { + crossing() + println("test1", tests.CurrentRealmPath()) func() { println("test2", tests.CurrentRealmPath()) diff --git a/gnovm/tests/files/zrealm_std6.gno b/gnovm/tests/files/zrealm_std6.gno index b2ab6432d13..b82332b0388 100644 --- a/gnovm/tests/files/zrealm_std6.gno +++ b/gnovm/tests/files/zrealm_std6.gno @@ -10,6 +10,8 @@ var ( ) func main() { + crossing() + println(realmAddr) } diff --git a/gnovm/tests/files/zrealm_tests0.gno b/gnovm/tests/files/zrealm_tests0.gno index cf1155ec025..1a1bb7eb449 100644 --- a/gnovm/tests/files/zrealm_tests0.gno +++ b/gnovm/tests/files/zrealm_tests0.gno @@ -12,6 +12,8 @@ func init() { } func main() { + crossing() + tests_foo.AddFooStringer("three") println(tests.Render("")) println("end") @@ -26,7 +28,7 @@ func main() { // Realm: // switchrealm["gno.land/r/demo/tests"] -// c[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:19]={ +// c[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:59]={ // "Fields": [ // { // "T": { @@ -40,17 +42,17 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:19", +// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:59", // "ModTime": "0", -// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:18", +// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:58", // "RefCount": "1" // } // } -// c[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:18]={ +// c[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:58]={ // "ObjectInfo": { -// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:18", +// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:58", // "ModTime": "0", -// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:17", +// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:57", // "RefCount": "1" // }, // "Value": { @@ -60,12 +62,12 @@ func main() { // }, // "V": { // "@type": "/gno.RefValue", -// "Hash": "6b9b731f6118c2419f23ba57e1481679f17f4a8f", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:19" +// "Hash": "a7c81f1e07e69c77e7d4cd89ec82fc78cc28fc63", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:59" // } // } // } -// c[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:17]={ +// c[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:57]={ // "Data": null, // "List": [ // { @@ -80,8 +82,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "4e0d77a91ba35733bf82329317bf8c8dffa6f655", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:12" +// "Hash": "e237f5d9b1327cf79b3b81212360b718dab745ed", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:52" // }, // "Index": "0", // "TV": null @@ -99,8 +101,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "fa414e1770821b8deb8e6d46d97828c47f7d5fa5", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:15" +// "Hash": "06a3eec56308db2a854688299249e9325c8efa05", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:55" // }, // "Index": "0", // "TV": null @@ -118,8 +120,8 @@ func main() { // "@type": "/gno.PointerValue", // "Base": { // "@type": "/gno.RefValue", -// "Hash": "aaa64d049cf8660d689780acac9f546f270eaa4e", -// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:18" +// "Hash": "e9679398e8552c552254fc5dbfef3a9b34162c9d", +// "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:58" // }, // "Index": "0", // "TV": null @@ -127,63 +129,60 @@ func main() { // } // ], // "ObjectInfo": { -// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:17", +// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:57", // "ModTime": "0", -// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:2", +// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:6", // "RefCount": "1" // } // } -// u[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:2]= -// @@ -3,7 +3,7 @@ +// u[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:6]= +// @@ -1,7 +1,7 @@ +// { // "ObjectInfo": { -// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:2", -// "IsEscaped": true, -// - "ModTime": "13", -// + "ModTime": "16", -// "RefCount": "5" +// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:6", +// - "ModTime": "53", +// + "ModTime": "56", +// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:2", +// "RefCount": "1" // }, -// "Parent": null, -// @@ -73,11 +73,11 @@ -// "@type": "/gno.SliceValue", -// "Base": { -// "@type": "/gno.RefValue", -// - "Hash": "694cb4385eb8d5e25fe7737cbc45695c7ac83f3c", -// - "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:14" -// - }, -// - "Length": "2", -// - "Maxcap": "2", -// + "Hash": "c2aab89570a9faa4acf463a140a04e9b96fae73d", -// + "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:17" -// + }, -// + "Length": "3", -// + "Maxcap": "3", -// "Offset": "0" -// } -// }, -// u[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:12]= +// @@ -18,11 +18,11 @@ +// "@type": "/gno.SliceValue", +// "Base": { +// "@type": "/gno.RefValue", +// - "Hash": "0a4e300c064e340c37a1704afebf583034c7fe96", +// - "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:54" +// + "Hash": "6abf6994a55444381588af249eb4d9185910e7af", +// + "ObjectID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:57" +// }, +// - "Length": "2", +// - "Maxcap": "2", +// + "Length": "3", +// + "Maxcap": "3", +// "Offset": "0" +// } +// } +// u[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:52]= // @@ -1,7 +1,7 @@ // { // "ObjectInfo": { -// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:12", -// - "ModTime": "14", -// + "ModTime": "17", -// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:11", +// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:52", +// - "ModTime": "54", +// + "ModTime": "57", +// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:51", // "RefCount": "1" // }, -// u[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:15]= +// u[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:55]= // @@ -1,7 +1,7 @@ // { // "ObjectInfo": { -// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:15", +// "ID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:55", // - "ModTime": "0", -// + "ModTime": "17", -// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:14", +// + "ModTime": "57", +// "OwnerID": "0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:54", // "RefCount": "1" // }, -// d[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:14] -// switchrealm["gno.land/r/demo/tests_foo"] -// switchrealm["gno.land/r/demo/tests_foo"] -// switchrealm["gno.land/r/demo/tests_foo"] -// switchrealm["gno.land/r/demo/tests_foo"] +// d[0ffe7732b4d549b4cf9ec18bd68641cd2c75ad0a:54] +// switchrealm["gno.land/r/demo/tests"] +// switchrealm["gno.land/r/demo/tests"] // switchrealm["gno.land/r/demo/tests"] // switchrealm["gno.land/r/demo/tests_test"] diff --git a/gnovm/tests/files/zrealm_testutils0.gno b/gnovm/tests/files/zrealm_testutils0.gno index 33322f76719..38100290ebc 100644 --- a/gnovm/tests/files/zrealm_testutils0.gno +++ b/gnovm/tests/files/zrealm_testutils0.gno @@ -6,6 +6,8 @@ import ( ) func main() { + crossing() + println(testutils.TestAddress("test1")) println(testutils.TestAddress("test2")) } diff --git a/gnovm/tests/stdlibs/fmt/print.go b/gnovm/tests/stdlibs/fmt/print.go index 9d5a4efc725..c206e188dac 100644 --- a/gnovm/tests/stdlibs/fmt/print.go +++ b/gnovm/tests/stdlibs/fmt/print.go @@ -102,8 +102,7 @@ func X_getAddr(m *gnolang.Machine, v gnolang.TypedValue) uint64 { } return uint64(uintptr(unsafe.Pointer(v.TV))) ^ uint64(uintptr(unsafe.Pointer(&v.Base))) ^ - uint64(v.Index) ^ - uint64(uintptr(unsafe.Pointer(v.Key))) + uint64(v.Index) case *gnolang.FuncValue: return uint64(uintptr(unsafe.Pointer(v))) case *gnolang.MapValue: diff --git a/gnovm/tests/stdlibs/generated.go b/gnovm/tests/stdlibs/generated.go index add535822d6..bea162e085d 100644 --- a/gnovm/tests/stdlibs/generated.go +++ b/gnovm/tests/stdlibs/generated.go @@ -37,10 +37,10 @@ var nativeFuncs = [...]NativeFunc{ "fmt", "typeString", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("any")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("string")}, }, false, func(m *gno.Machine) { @@ -60,14 +60,14 @@ var nativeFuncs = [...]NativeFunc{ "fmt", "valueOfInternal", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("any")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - {Name: gno.N("r1"), Type: gno.X("string")}, - {Name: gno.N("r2"), Type: gno.X("uint64")}, - {Name: gno.N("r3"), Type: gno.X("any")}, - {Name: gno.N("r4"), Type: gno.X("int")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r2"), Type: gno.X("uint64")}, + {NameExpr: *gno.Nx("r3"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("r4"), Type: gno.X("int")}, }, false, func(m *gno.Machine) { @@ -103,10 +103,10 @@ var nativeFuncs = [...]NativeFunc{ "fmt", "getAddr", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("any")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("uint64")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("uint64")}, }, true, func(m *gno.Machine) { @@ -128,10 +128,10 @@ var nativeFuncs = [...]NativeFunc{ "fmt", "getPtrElem", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("any")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("any")}, }, false, func(m *gno.Machine) { @@ -147,11 +147,11 @@ var nativeFuncs = [...]NativeFunc{ "fmt", "mapKeyValues", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("any")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("[]any")}, - {Name: gno.N("r1"), Type: gno.X("[]any")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("[]any")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("[]any")}, }, false, func(m *gno.Machine) { @@ -168,11 +168,11 @@ var nativeFuncs = [...]NativeFunc{ "fmt", "arrayIndex", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("any")}, - {Name: gno.N("p1"), Type: gno.X("int")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("int")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("any")}, }, true, func(m *gno.Machine) { @@ -198,12 +198,12 @@ var nativeFuncs = [...]NativeFunc{ "fmt", "fieldByIndex", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("any")}, - {Name: gno.N("p1"), Type: gno.X("int")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("int")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - {Name: gno.N("r1"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("any")}, }, false, func(m *gno.Machine) { @@ -232,11 +232,11 @@ var nativeFuncs = [...]NativeFunc{ "fmt", "asByteSlice", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("any")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("any")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("[]byte")}, - {Name: gno.N("r1"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("[]byte")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("bool")}, }, false, func(m *gno.Machine) { @@ -257,11 +257,11 @@ var nativeFuncs = [...]NativeFunc{ "os", "write", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("[]byte")}, - {Name: gno.N("p1"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("[]byte")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("bool")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("int")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("int")}, }, true, func(m *gno.Machine) { @@ -295,7 +295,7 @@ var nativeFuncs = [...]NativeFunc{ "os", "sleep", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("int64")}, }, []gno.FieldTypeExpr{}, true, @@ -327,47 +327,15 @@ var nativeFuncs = [...]NativeFunc{ ) }, }, - { - "std", - "callerAt", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("int")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - true, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 int - rp0 = reflect.ValueOf(&p0).Elem() - ) - - tv0 := b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV - tv0.DeepFill(m.Store) - gno.Gno2GoValue(tv0, rp0) - - r0 := testlibs_std.X_callerAt( - m, - p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, { "std", "getRealm", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("int")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("int")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - {Name: gno.N("r1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, }, true, func(m *gno.Machine) { @@ -401,10 +369,10 @@ var nativeFuncs = [...]NativeFunc{ "std", "isRealm", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("bool")}, }, true, func(m *gno.Machine) { @@ -434,16 +402,16 @@ var nativeFuncs = [...]NativeFunc{ "getContext", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - {Name: gno.N("r1"), Type: gno.X("string")}, - {Name: gno.N("r2"), Type: gno.X("[]string")}, - {Name: gno.N("r3"), Type: gno.X("[]int64")}, - {Name: gno.N("r4"), Type: gno.X("[]string")}, - {Name: gno.N("r5"), Type: gno.X("[]int64")}, - {Name: gno.N("r6"), Type: gno.X("string")}, - {Name: gno.N("r7"), Type: gno.X("int64")}, - {Name: gno.N("r8"), Type: gno.X("int64")}, - {Name: gno.N("r9"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r2"), Type: gno.X("[]string")}, + {NameExpr: *gno.Nx("r3"), Type: gno.X("[]int64")}, + {NameExpr: *gno.Nx("r4"), Type: gno.X("[]string")}, + {NameExpr: *gno.Nx("r5"), Type: gno.X("[]int64")}, + {NameExpr: *gno.Nx("r6"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r7"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("r8"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("r9"), Type: gno.X("int64")}, }, true, func(m *gno.Machine) { @@ -507,18 +475,18 @@ var nativeFuncs = [...]NativeFunc{ "testing", "setContext", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("string")}, - {Name: gno.N("p2"), Type: gno.X("string")}, - {Name: gno.N("p3"), Type: gno.X("string")}, - {Name: gno.N("p4"), Type: gno.X("[]string")}, - {Name: gno.N("p5"), Type: gno.X("[]int64")}, - {Name: gno.N("p6"), Type: gno.X("[]string")}, - {Name: gno.N("p7"), Type: gno.X("[]int64")}, - {Name: gno.N("p8"), Type: gno.X("string")}, - {Name: gno.N("p9"), Type: gno.X("int64")}, - {Name: gno.N("p10"), Type: gno.X("int64")}, - {Name: gno.N("p11"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p3"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p4"), Type: gno.X("[]string")}, + {NameExpr: *gno.Nx("p5"), Type: gno.X("[]int64")}, + {NameExpr: *gno.Nx("p6"), Type: gno.X("[]string")}, + {NameExpr: *gno.Nx("p7"), Type: gno.X("[]int64")}, + {NameExpr: *gno.Nx("p8"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p9"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("p10"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("p11"), Type: gno.X("int64")}, }, []gno.FieldTypeExpr{}, true, @@ -597,9 +565,9 @@ var nativeFuncs = [...]NativeFunc{ "testing", "testIssueCoins", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("[]string")}, - {Name: gno.N("p2"), Type: gno.X("[]int64")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("[]string")}, + {NameExpr: *gno.Nx("p2"), Type: gno.X("[]int64")}, }, []gno.FieldTypeExpr{}, true, @@ -634,7 +602,7 @@ var nativeFuncs = [...]NativeFunc{ "unixNano", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("int64")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("int64")}, }, false, func(m *gno.Machine) { @@ -651,12 +619,12 @@ var nativeFuncs = [...]NativeFunc{ "testing", "matchString", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - {Name: gno.N("p1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("p1"), Type: gno.X("string")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("bool")}, - {Name: gno.N("r1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, }, false, func(m *gno.Machine) { @@ -694,8 +662,8 @@ var nativeFuncs = [...]NativeFunc{ "recoverWithStacktrace", []gno.FieldTypeExpr{}, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.AnyT()}, - {Name: gno.N("r1"), Type: gno.X("string")}, + {NameExpr: *gno.Nx("r0"), Type: gno.AnyT()}, + {NameExpr: *gno.Nx("r1"), Type: gno.X("string")}, }, true, func(m *gno.Machine) { @@ -715,10 +683,10 @@ var nativeFuncs = [...]NativeFunc{ "unicode", "IsPrint", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("rune")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("rune")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("bool")}, }, false, func(m *gno.Machine) { @@ -745,10 +713,10 @@ var nativeFuncs = [...]NativeFunc{ "unicode", "IsGraphic", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("rune")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("rune")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("bool")}, }, false, func(m *gno.Machine) { @@ -775,10 +743,10 @@ var nativeFuncs = [...]NativeFunc{ "unicode", "SimpleFold", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("rune")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("rune")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("rune")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("rune")}, }, false, func(m *gno.Machine) { @@ -805,10 +773,10 @@ var nativeFuncs = [...]NativeFunc{ "unicode", "IsUpper", []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("rune")}, + {NameExpr: *gno.Nx("p0"), Type: gno.X("rune")}, }, []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("bool")}, + {NameExpr: *gno.Nx("r0"), Type: gno.X("bool")}, }, false, func(m *gno.Machine) { diff --git a/gnovm/tests/stdlibs/std/std.gno b/gnovm/tests/stdlibs/std/std.gno index e0e0509bbf4..5ac866cd20e 100644 --- a/gnovm/tests/stdlibs/std/std.gno +++ b/gnovm/tests/stdlibs/std/std.gno @@ -2,8 +2,10 @@ package std func AssertOriginCall() // injected +/* See comment in stdlibs/std/native.gno // CallerAt calls callerAt, which we overwrite func callerAt(n int) string +*/ // native bindings func getRealm(height int) (address string, pkgPath string) diff --git a/gnovm/tests/stdlibs/std/std.go b/gnovm/tests/stdlibs/std/std.go index 5ff6c8fbeeb..805525157f9 100644 --- a/gnovm/tests/stdlibs/std/std.go +++ b/gnovm/tests/stdlibs/std/std.go @@ -62,6 +62,7 @@ func isOriginCall(m *gno.Machine) bool { panic("unable to determine if test is a _test or a _filetest") } +/* See comment in stdlibs/std/native.gno func X_callerAt(m *gno.Machine, n int) string { if n <= 0 { m.Panic(typedString("CallerAt requires positive arg")) @@ -81,45 +82,72 @@ func X_callerAt(m *gno.Machine, n int) string { ctx := m.Context.(*TestExecContext) return string(ctx.OriginCaller) } - return string(m.MustLastCallFrame(n).LastPackage.GetPkgAddr().Bech32()) + return string(m.MustPeekCallFrame(n).LastPackage.GetPkgAddr().Bech32()) } +*/ func X_getRealm(m *gno.Machine, height int) (address string, pkgPath string) { // NOTE: keep in sync with stdlibs/std.getRealm var ( - ctx = m.Context.(*TestExecContext) - currentCaller crypto.Bech32Address - // Keeps track of the number of times currentCaller - // has changed. - changes int + ctx = m.Context.(*TestExecContext) + crosses int // track realm crosses + lfr *gno.Frame = m.LastFrame() // last call frame ) for i := m.NumFrames() - 1; i >= 0; i-- { fr := m.Frames[i] - override, overridden := ctx.RealmFrames[m.Frames[max(i-1, 0)]] - if !overridden && - (fr.LastPackage == nil || !fr.LastPackage.IsRealm()) { - continue + + // Skip over (non-realm) non-crosses. + // Override implies cross. + override, overridden := ctx.RealmFrames[m.Frames[i]] + if !overridden { + if !fr.IsCall() { + continue + } + if !fr.WithCross { + lfr = fr + continue + } } - // LastPackage is a realm. Get caller and pkgPath, and compare against - // currentCaller. - caller, pkgPath := override.Addr, override.PkgPath + // Sanity check XXX move check elsewhere if !overridden { - caller = fr.LastPackage.GetPkgAddr().Bech32() - pkgPath = fr.LastPackage.PkgPath + if !fr.DidCross { + panic(fmt.Sprintf( + "cross(fn) but fn didn't call crossing(): %s.%s", + fr.Func.PkgPath, + fr.Func.String())) + } } - if caller != currentCaller { - if changes == height { + + crosses++ + if crosses > height { + if overridden { + caller, pkgPath := override.Addr, override.PkgPath return string(caller), pkgPath + } else { + currlm := lfr.LastRealm + caller, rlmPath := gno.DerivePkgAddr(currlm.Path).Bech32(), currlm.Path + return string(caller), rlmPath } - currentCaller = caller - changes++ } + lfr = fr + } + + if crosses != height { + m.Panic(typedString("frame not found")) + } + + // Special case if package initialization. + if ctx.OriginCaller == "" { + fr := m.Frames[0] + caller := string(fr.LastPackage.GetPkgAddr().Bech32()) + pkgPath := fr.LastPackage.PkgPath + return string(caller), pkgPath } - // Fallback case: return OriginCaller. + // Base case: return OriginCaller. return string(ctx.OriginCaller), "" } diff --git a/gnovm/tests/stdlibs/testing/context_testing.gno b/gnovm/tests/stdlibs/testing/context_testing.gno index 70330309fc0..201f1d10e91 100644 --- a/gnovm/tests/stdlibs/testing/context_testing.gno +++ b/gnovm/tests/stdlibs/testing/context_testing.gno @@ -97,7 +97,7 @@ func SetHeight(height int64) { // SetRealm sets the realm for the current frame. // After calling SetRealm, calling CurrentRealm() in the test function will yield the value of -// rlm, while if a realm function is called, using PrevRealm() will yield rlm. +// rlm, while if a realm function is called, using PreviousRealm() will yield rlm. func SetRealm(rlm std.Realm) { ctx := GetContext() ctx.CurrentRealm = rlm diff --git a/gnovm/tests/stdlibs/testing/context_testing.go b/gnovm/tests/stdlibs/testing/context_testing.go index 52d89d1014e..7b70621a90b 100644 --- a/gnovm/tests/stdlibs/testing/context_testing.go +++ b/gnovm/tests/stdlibs/testing/context_testing.go @@ -67,8 +67,8 @@ func X_setContext( // #7: [FRAME FUNC:setContext RECV:(undefined) (15 args) 11/3/0/6/4 LASTPKG:testing ...] // #6: [FRAME FUNC:SetContext RECV:(undefined) (1 args) 8/2/0/4/3 LASTPKG:testing ...] // #5: [FRAME FUNC:SetRealm RECV:(undefined) (1 args) 5/1/0/2/2 LASTPKG:gno.land/r/demo/groups ...] - // We want to set the Realm of the frame where testing.SetRealm is being called, hence -3. - for i := m.NumFrames() - 3; i >= 0; i-- { + // We want to set the Realm of the frame where testing.SetRealm is being called, hence -3-1. + for i := m.NumFrames() - 4; i >= 0; i-- { // Must be a frame from calling a function. if fr := m.Frames[i]; fr.Func != nil && fr.Func.PkgPath != "testing" { frame = fr diff --git a/misc/genstd/template.tmpl b/misc/genstd/template.tmpl index b59f8f7fc8f..32561a45fdf 100644 --- a/misc/genstd/template.tmpl +++ b/misc/genstd/template.tmpl @@ -38,12 +38,12 @@ var nativeFuncs = [...]NativeFunc{ {{- /* TODO: set nil if empty */}} []gno.FieldTypeExpr{ {{- range $i, $p := $m.Params }} - {Name: gno.N("p{{ $i }}"), Type: {{ $p.GnoTypeExpression -}} }, + {NameExpr: *gno.Nx("p{{ $i }}"), Type: {{ $p.GnoTypeExpression -}} }, {{- end }} }, []gno.FieldTypeExpr{ {{- range $i, $r := $m.Results }} - {Name: gno.N("r{{ $i }}"), Type: {{ $r.GnoTypeExpression -}} }, + {NameExpr: *gno.Nx("r{{ $i }}"), Type: {{ $r.GnoTypeExpression -}} }, {{- end }} }, {{ if $m.MachineParam }}true{{ else }}false{{ end }},