Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Ride vm and compiler. #438

Draft
wants to merge 61 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
f7bff52
Stateful compiler.
Frozen Oct 23, 2020
393bea6
Context for func execution.
Frozen Oct 23, 2020
c32e887
Function definition passed tess.
Frozen Oct 23, 2020
1975cd8
Uncomment completed tests.
Frozen Oct 23, 2020
fb77419
Pass args as reference.
Frozen Oct 30, 2020
d20052b
Pass args as mem storage.
Frozen Nov 3, 2020
197130e
Global variables.
Frozen Nov 5, 2020
980f91f
Get attribute vm.
Frozen Nov 6, 2020
b11b59e
Odd byte codes.
Frozen Nov 6, 2020
3f70cd3
Stagenet tests.
Frozen Nov 10, 2020
03e9286
Cells for variables.
Frozen Nov 12, 2020
3165334
Fix bug with if stmt.
Frozen Nov 23, 2020
f4c6943
Cache function result as variable.
Frozen Dec 1, 2020
ae6f02a
Function arguments.
Frozen Dec 2, 2020
86f9281
Cache variable result.
Frozen Dec 3, 2020
f6a69e9
Clear cache.
Frozen Dec 3, 2020
0fd9f97
Fix clear cache.
Frozen Dec 7, 2020
219cf08
Reverse assigments.
Frozen Dec 7, 2020
2f51036
Deferred code.
Frozen Dec 9, 2020
9e7f14c
Property state.
Frozen Dec 10, 2020
0296798
Call function.
Frozen Dec 10, 2020
9c0d640
Property invocation changed.
Frozen Dec 13, 2020
8f7a32a
Property bytecode checked in tests.
Frozen Dec 13, 2020
f01939c
Reversed tree.
Frozen Dec 15, 2020
4bdddaa
Fix transitions.
Frozen Dec 22, 2020
d983007
Merge branch 'master' into ride_vm_fsm
Frozen Dec 22, 2020
415c5c1
Fix transitions.
Frozen Dec 23, 2020
b43481d
Fix functions.
Frozen Dec 23, 2020
f755658
Fix functions.
Frozen Dec 24, 2020
33f2f24
Save entrypoints into meta.
Frozen Dec 24, 2020
36be49d
Testnet random script.
Frozen Jan 24, 2021
1b6f2ff
Passed testnet.
Frozen Feb 1, 2021
8a2b1cd
Enabled cache.
Frozen Feb 4, 2021
598f0aa
Merge branch 'master' into ride_vm_fsm
Frozen Feb 4, 2021
78afd85
Merged master.
Frozen Feb 4, 2021
ff8c959
Switchable bloom filter.
Frozen Feb 5, 2021
60410b4
Fix tests.
Frozen Feb 5, 2021
cc3d021
Merge branch 'optional_bloom_filter' into ride_vm_fsm
Frozen Feb 5, 2021
b70c14b
Code clean up and returned back debug info.
Frozen Feb 9, 2021
3e16ec5
Fix panic.
Frozen Feb 9, 2021
73a8ce5
Remove caching duplicates.
Frozen Feb 12, 2021
349c863
Expanded tree.
Frozen Mar 10, 2021
9c1b500
Rewrite tree by using immutable context with variables.
Frozen Mar 16, 2021
74b8cf3
Fix problems with tree expand.
Frozen Mar 17, 2021
be99ac9
Fix naming.
Frozen Mar 18, 2021
5d035b3
Remove unused code.
Frozen Mar 18, 2021
8b64449
Fix vetcheck errors.
Frozen Mar 18, 2021
366b203
Fix vetcheck errors.
Frozen Mar 18, 2021
ba560d8
Set up go 1.16
Frozen Mar 18, 2021
6c06ca0
Merge branch 'master' into ride_vm_fsm
Frozen Mar 18, 2021
b50a0c7
Rewrite path.
Frozen Mar 19, 2021
15d0cb0
Removed fmtcheck.
Frozen Mar 19, 2021
2e6c584
Clean code in tree evaluator.
Frozen Mar 19, 2021
2c1c208
Fix small errors.
Frozen Mar 19, 2021
f86c981
Clean up compiler.
Frozen Mar 22, 2021
1d6f34a
Fix bug with var override in condition stste.
Frozen Mar 25, 2021
80bfd76
Merge remote-tracking branch 'origin/expand_tree_rewrite_path' into r…
Frozen Mar 25, 2021
a644a73
Fix bug with nil values and duplicate vars in conditional state.
Frozen Apr 2, 2021
cee2edc
Merge remote-tracking branch 'origin/master' into ride_vm_fsm
Frozen Apr 2, 2021
0c792d4
Updated mocks.
Frozen Apr 2, 2021
48d19f8
Added skip file compiler_heplers
esuwu Apr 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Deferred code.
Frozen committed Dec 9, 2020
commit 2f510362fbb492d44ce8615a266a088fcf284909
154 changes: 114 additions & 40 deletions pkg/ride/compiler2_test.go
Original file line number Diff line number Diff line change
@@ -52,35 +52,36 @@ func Test22(t *testing.T) {
env RideEnvironment
res bool
}{
//{`V1: true`, "AQa3b8tH", nil, true},
//{`V1: false`, `AQfeYll6`, nil, false},
//{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true},
//{`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true},
//{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true},
//{`V1: let i = 1; let s = "string"; toString(i) == s`, "AQQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABcwIsH74=", env, false},
//{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true},
//{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true},
//{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false},
//{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true},
//{`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false},
//{`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true},
//{`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true},
//{`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true},
//{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true},
//{`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true},
{`V1: true`, "AQa3b8tH", env, true},
{`V1: false`, `AQfeYll6`, nil, false},
{`V3: let x = 1; true`, "AwQAAAABeAAAAAAAAAAAAQbtAkXn", env, true},
{`V3: let x = true; x`, "BAQAAAABeAYFAAAAAXhUb/5M", env, true},
{`V3: let x = "abc"; true`, "AwQAAAABeAIAAAADYWJjBrpUkE4=", nil, true},
{`V1: let i = 1; let s = "string"; toString(i) == s`, "BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=", env, false},
{`V3: let i = 12345; let s = "12345"; toString(i) == s`, "AwQAAAABaQAAAAAAAAAwOQQAAAABcwIAAAAFMTIzNDUJAAAAAAAAAgkAAaQAAAABBQAAAAFpBQAAAAFz1B1iCw==", nil, true},
{`V3: if (true) then {let r = true; r} else {let r = false; r}`, "AwMGBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXJ/ok0E", env, true},
{`V3: if (false) then {let r = true; r} else {let r = false; r}`, "AwMHBAAAAAFyBgUAAAABcgQAAAABcgcFAAAAAXI+tfo1", env, false},
{`V3: func abs(i:Int) = if (i >= 0) then i else -i; abs(-10) == 10`, "AwoBAAAAA2FicwAAAAEAAAABaQMJAABnAAAAAgUAAAABaQAAAAAAAAAAAAUAAAABaQkBAAAAAS0AAAABBQAAAAFpCQAAAAAAAAIJAQAAAANhYnMAAAABAP/////////2AAAAAAAAAAAKmp8BWw==", env, true},
{`V3: func a() = 1; a() == 2`, "BAoBAAAAAWEAAAAAAAAAAAAAAAABCQAAAAAAAAIJAQAAAAFhAAAAAAAAAAAAAAAAAsVdmuc=", env, false},
{`V3: func abc() = true; abc()`, "BAoBAAAAA2FiYwAAAAAGCQEAAAADYWJjAAAAANHu1ew=", env, true},
{`V3: func id(v: Boolean) = v; id(true)`, "BAoBAAAAAmlkAAAAAQAAAAF2BQAAAAF2CQEAAAACaWQAAAABBglAaUs=", env, true},
{`V3: 1 == 1`, "BAkAAAAAAAACAAAAAAAAAAABAAAAAAAAAAABq0EiMw==", env, true},
{`V3: (1 == 1) == (1 == 1)`, "BAkAAAAAAAACCQAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAAAEJAAAAAAAAAgAAAAAAAAAAAQAAAAAAAAAAAWXKjzM=", env, true},
{`V3: let x = 1; func add(i: Int) = i + 1; add(x) == 2`, "AwQAAAABeAAAAAAAAAAAAQoBAAAAA2FkZAAAAAEAAAABaQkAAGQAAAACBQAAAAFpAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAF4AAAAAAAAAAACfr6U6w==", env, true},
{`V3: let x = if (true) then true else false; x`, "BAQAAAABeAMGBgcFAAAAAXgCINPC", env, true},
{`V3: let b = base16'0000000000000001'; func add(b: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAWIJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACX00biA==", nil, true},
{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(v) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAF2AAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAACI7gYxg==", nil, true},
{`V3: let b = base16'0000000000000001'; func add(v: ByteVector) = toInt(b) + 1; add(b) == 2`, "AwQAAAABYgEAAAAIAAAAAAAAAAEKAQAAAANhZGQAAAABAAAAAXYJAABkAAAAAgkABLEAAAABBQAAAAFiAAAAAAAAAAABCQAAAAAAAAIJAQAAAANhZGQAAAABBQAAAAFiAAAAAAAAAAAChRvwnQ==", nil, true},
{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true},
//{`V3: let data = base64'AAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLw=='; func getStock(data:ByteVector) = toInt(take(drop(data, 8), 8)); getStock(data) == 1`, `AwQAAAAEZGF0YQEAAABwAAAAAAABhqAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWyt9GyysOW84u/u5V5Ah/SzLfef4c28UqXxowxFZS4SLiC6+XBh8D7aJDXyTTjpkPPED06ZPOzUE23V6VYCsLwoBAAAACGdldFN0b2NrAAAAAQAAAARkYXRhCQAEsQAAAAEJAADJAAAAAgkAAMoAAAACBQAAAARkYXRhAAAAAAAAAAAIAAAAAAAAAAAICQAAAAAAAAIJAQAAAAhnZXRTdG9jawAAAAEFAAAABGRhdGEAAAAAAAAAAAFCtabi`, nil, true},
{`V3: let ref = 999; func g(a: Int) = ref; func f(ref: Int) = g(ref); f(1) == 999`, "AwQAAAADcmVmAAAAAAAAAAPnCgEAAAABZwAAAAEAAAABYQUAAAADcmVmCgEAAAABZgAAAAEAAAADcmVmCQEAAAABZwAAAAEFAAAAA3JlZgkAAAAAAAACCQEAAAABZgAAAAEAAAAAAAAAAAEAAAAAAAAAA+fjknmW", nil, true},
{`let x = 5; 6 > 4`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGAAAAAAAAAAAEYSW6XA==`, nil, true},
{`let x = 5; 6 > x`, `AQQAAAABeAAAAAAAAAAABQkAAGYAAAACAAAAAAAAAAAGBQAAAAF4Gh24hw==`, nil, true},
{`let x = 5; 6 >= x`, `AQQAAAABeAAAAAAAAAAABQkAAGcAAAACAAAAAAAAAAAGBQAAAAF4jlxXHA==`, nil, true},
//

{`let x = throw(); true`, `AQQAAAABeAkBAAAABXRocm93AAAAAAa7bgf4`, nil, true},
{`let x = throw(); true || x`, `AQQAAAABeAkBAAAABXRocm93AAAAAAMGBgUAAAABeKRnLds=`, env, true},
{`tx == tx`, "BAkAAAAAAAACBQAAAAJ0eAUAAAACdHhnqgP4", env, true},
//{fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false},
{fcall1, "BAoBAAAABmdldEludAAAAAEAAAADa2V5BAAAAAckbWF0Y2gwCQAEGgAAAAIFAAAABHRoaXMFAAAAA2tleQMJAAABAAAAAgUAAAAHJG1hdGNoMAIAAAADSW50BAAAAAF4BQAAAAckbWF0Y2gwBQAAAAF4AAAAAAAAAAAABAAAAAFhCQEAAAAGZ2V0SW50AAAAAQIAAAABNQQAAAABYgkBAAAABmdldEludAAAAAECAAAAATYJAAAAAAAAAgUAAAABYQUAAAABYkOIJQA=", env, false},
//{`tx.id == base58''`, `AQkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAAJBtD70=`, env, false},
//{`tx.id == base58'H5C8bRzbUTMePSDVVxjiNKDUwk6CKzfZGTP2Rs7aCjsV'`, `BAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAIO7N5luRDUgN1SJ4kFmy/Ni8U2H6k7bpszok5tlLlRVgHwSHyg==`, env, true},
//{`let x = tx.id == base58'a';true`, `AQQAAAABeAkAAAAAAAACCAUAAAACdHgAAAACaWQBAAAAASEGjR0kcA==`, env, true},
@@ -174,8 +175,8 @@ func TestCallExternal(t *testing.T) {
require.Equal(t,
[]byte{
OpReturn,
OpRef, 0, 1,
OpRef, 0, 2,
OpRef, 0, 3,
OpRef, 0, 4,
OpExternalCall, 0, 3, 0, 2,
OpReturn,
},
@@ -199,30 +200,75 @@ func TestIfConditionRightByteCode(t *testing.T) {
f, err := compileFunction("", 3, []Node{n})
require.NoError(t, err)

/**
require.Equal(t,
[]byte{
OpReturn,
OpRef, 0, 1,
OpClearCache, 0, 1,
OpReturn,
OpRef, 0, 2,
OpJumpIfFalse, 0, 11, 0, 15, 0, 19,
OpJumpIfFalse, 0, 0x12, 0, 0x16, 0, 0x1a,
OpRef, 0, 3,
OpReturn,
OpRef, 0, 4,
OpReturn,

OpCache, 0, 1,

OpReturn,
OpRef, 0, 1,
OpClearCache, 0, 1,
OpReturn,
},
f.ByteCode)

/**/

rs, err := f.Run(nil, nil)
require.NoError(t, err)
require.Equal(t, true, rs.Result())
}

// let i = 1; let s = "string"; toString(i) == s
func TestCall(t *testing.T) {
source := `BAQAAAABaQAAAAAAAAAAAQQAAAABcwIAAAAGc3RyaW5nCQAAAAAAAAIJAAGkAAAAAQUAAAABaQUAAAABc6Y8UOc=`
src, err := base64.StdEncoding.DecodeString(source)
require.NoError(t, err)

tree, err := Parse(src)
require.NoError(t, err)
assert.NotNil(t, tree)

script, err := CompileVerifier("", tree)
require.NoError(t, err)
assert.NotNil(t, script)

//f, err := compileFunction("", 3, []Node{n})
//require.NoError(t, err)

//require.Equal(t,
// []byte{
// OpReturn,
// OpRef, 0, 3,
// OpRef, 0, 4,
// OpExternalCall, 0, 3, 0, 2,
// OpReturn,
//
// OpRef, 0, 5,
// OpExternalCall, 0, 0x8c, 0, 1,
// OpReturn,
//
// //OpRef, 0, 3,
// //OpReturn,
// //OpRef, 0, 4,
// //OpReturn,
// //OpReturn,
// },
// script.ByteCode)

rs, err := script.Run(nil, nil)
require.NoError(t, err)
//rs, err := f.Run(nil, nil)
require.NoError(t, err)
require.Equal(t, 2, len(rs.Calls()))
require.Equal(t, false, rs.Result())
}

//func a() = 1; a() == 1
func TestDoubleCall(t *testing.T) {
n := &FunctionDeclarationNode{
@@ -248,20 +294,22 @@ func TestDoubleCall(t *testing.T) {
f, err := compileFunction("", 3, []Node{n})
require.NoError(t, err)

/**
require.Equal(t,
[]byte{
OpReturn,
OpRef, 0, 1,
OpRef, 0, 2,
OpExternalCall, 0, 3, 0, 2,
OpReturn,

OpCall, 0, 1,
OpRef, 0, 3,
OpExternalCall, 0, 3, 0, 2,
OpReturn,
},
f.ByteCode)
/**/

require.EqualValues(t, 5, f.EntryPoints[""])
require.EqualValues(t, 1, f.EntryPoints[""])

rs, err := f.Run(nil, nil)
require.NoError(t, err)
@@ -298,9 +346,9 @@ func TestClearInternalVariables(t *testing.T) {
require.Equal(t,
[]byte{
OpReturn,
OpRef, 0, 1,
OpRef, 0, 2,
OpClearCache, 0, 2,
OpClearCache, 0, 1,
OpClearCache, 0, 4,
OpReturn,

OpReturn,
@@ -330,13 +378,12 @@ func TestCallWithConstArg(t *testing.T) {

bt := []byte{
OpReturn,
OpRef, 0, 1, // Function execution code. One line: reference to `v` argument.
OpSetArg, 0, 3, 0, 2, // Function execution code. One line: reference to `v` argument.
OpRef, 0, 1,
OpReturn,

// call function
OpSetArg, 0, 3, 0, 1,
OpCall, 0, 1,

OpRef, 0, 2,
OpReturn,
}

@@ -767,8 +814,17 @@ func Test777(t *testing.T) {
assert.Equal(t, true, r.Result())
}

/*
func abc() = 5
func cba() = 10
if abc() == cba() then {
true
} else {
false
}
*/
func Test888(t *testing.T) {
source := `BAoBAAAAAWYAAAAACQAAAgAAAAECAAAAATEKAQAAAAJmMgAAAAIAAAAFb3duZXIAAAAGaGVpZ2h0BQAAAAZoZWlnaHQJAAAAAAAAAgkBAAAAAmYyAAAAAgkBAAAAAWYAAAAABQAAAAZoZWlnaHQAAAAAAAAAAAFFcqW2`
source := `BAoBAAAAA2FiYwAAAAAAAAAAAAAAAAUKAQAAAANjYmEAAAAAAAAAAAAAAAAKAwkAAAAAAAACCQEAAAADYWJjAAAAAAkBAAAAA2NiYQAAAAAGB0hjUOM=`

state := &MockSmartState{
NewestTransactionByIDFunc: func(_ []byte) (proto.Transaction, error) {
@@ -812,8 +868,26 @@ func Test888(t *testing.T) {
require.NoError(t, err)
assert.NotNil(t, script)

_, err = script.Run(env, nil)
require.Equal(t, err.Error(), "terminated execution by throw with message \"1\"")
/**
require.Equal(t,
[]byte{
OpReturn,
OpRef, 0, 0,
OpRef, 0, 0,
OpCall, 0, 0, 0, 2,
OpJumpIfFalse, 0, 0, 0, 0, 0, 0,
OpRef, 0, 0, OpReturn, //true branch
OpRef, 0, 0, OpReturn, //false branch
OpReturn,
OpRef, 0, 0, OpReturn, // function cba
OpRef, 0, 0, OpReturn, // function abc
},
script.ByteCode)
/**/

rs, err := script.Run(env, nil)
require.Equal(t, rs.Result(), false)
//require.Equal(t, err.Error(), "terminated execution by throw with message \"1\"")
}

/*
116 changes: 77 additions & 39 deletions pkg/ride/compiler_assigment.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
package ride

import "fmt"

// Assigment: let x = 5
type AssigmentState struct {
params
prev Fsm
name string
//startedAt uint16
//ret uint16
constant rideType
//constant rideType
// ref id
n uniqueid

// Clean internal assigments.
assigments []uniqueid
deferred []Deferred
d Deferreds
}

func (a AssigmentState) retAssigment(state AssigmentState) Fsm {
//a.ret = pos
panic("assig in assig")
func (a AssigmentState) retAssigment(state Fsm) Fsm {
a.deferred = append(a.deferred, state.(Deferred))
return a
}

@@ -30,12 +32,12 @@ func (a AssigmentState) Func(name string, args []string, invoke string) Fsm {
}

func (a AssigmentState) Bytes(b []byte) Fsm {
a.constant = rideBytes(b)
a.deferred = append(a.deferred, a.constant(rideBytes(b)))
return a
}

func (a AssigmentState) Condition() Fsm {
return conditionalTransition(a, a.params)
return conditionalTransition(a, a.params, a.d)
}

func (a AssigmentState) TrueBranch() Fsm {
@@ -47,26 +49,27 @@ func (a AssigmentState) FalseBranch() Fsm {
}

func (a AssigmentState) String(s string) Fsm {
a.constant = rideString(s)
a.deferred = append(a.deferred, a.constant(rideString(s)))
return a
}

func (a AssigmentState) Boolean(v bool) Fsm {
a.constant = rideBoolean(v)
a.deferred = append(a.deferred, a.constant(rideBoolean(v)))
return a
}

func assigmentFsmTransition(prev Fsm, params params, name string, n uniqueid) Fsm {
return newAssigmentFsm(prev, params, name, n)
func assigmentFsmTransition(prev Fsm, params params, name string, n uniqueid, d Deferreds) Fsm {
params.r.set(name, n)
return newAssigmentFsm(prev, params, name, n, d)
}

func newAssigmentFsm(prev Fsm, p params, name string, n uniqueid) Fsm {
func newAssigmentFsm(prev Fsm, p params, name string, n uniqueid, d Deferreds) Fsm {
return AssigmentState{
prev: prev,
params: p,
name: name,
//startedAt: p.b.len(),
n: n,
n: n,
d: d,
}
}

@@ -76,8 +79,7 @@ func (a AssigmentState) Assigment(name string) Fsm {
params.r = newReferences(params.r)
// TODO clear var in var
n := a.params.u.next()
a.assigments = append(a.assigments, n)
return assigmentFsmTransition(a, params, name, params.u.next())
return assigmentFsmTransition(a, params, name, n, a.d)
}

func (a AssigmentState) Return() Fsm {
@@ -94,38 +96,74 @@ func (a AssigmentState) Return() Fsm {
// a.b.write(encode(a.n))
// a.b.ret()
//}
//a.r.set(a.name, a.n)
//return a.prev.retAssigment(a.startedAt, a.params.b.len())
return a.prev.retAssigment(a)
}

func (a AssigmentState) Write() {
//for i := len(a.assigments) - 1; i >= 0; i-- {
// a.b.writeByte(OpClearCache)
// a.b.write(encode(a.assigments[i]))
//}
// constant
if a.constant != nil {
a.c.set(a.n, a.constant, nil, 0, true, a.name)
} else {
a.c.set(a.n, nil, nil, a.b.len(), false, a.name)
a.b.writeByte(OpCache)
a.b.write(encode(a.n))
a.b.ret()
}
a.r.set(a.name, a.n)
return //a.prev.retAssigment(a.startedAt, a.params.b.len())
a.d.Add(a, a.n, fmt.Sprintf("ref %s", a.name))
//return a.prev.retAssigment(a.startedAt, a.params.b.len())
return a.prev //.retAssigment(a)
}

func (a AssigmentState) Long(value int64) Fsm {
a.constant = rideInt(value)
a.deferred = append(a.deferred, a.constant(rideInt(value)))
return a
}

func (a AssigmentState) Call(name string, argc uint16) Fsm {
return callTransition(a, a.params, name, argc)
return callTransition(a, a.params, name, argc, a.d)
}

func (a AssigmentState) Reference(name string) Fsm {
return reference(a, a.params, name)
a.deferred = append(a.deferred, reference(a, a.params, name))
return a
}

func (a AssigmentState) Write(_ params) {
// constant
//if a.constant != nil {
// a.c.set(a.n, a.constant, nil, 0, true, a.name)
//} else {
//a.c.set(a.n, nil, nil, a.b.len(), false, a.name)
// a.b.writeByte(OpCache)
// a.b.write(encode(a.n))
// a.b.ret()
//}
//a.r.set(a.name, a.n)

//for _, v := range a.deferred {
// v.(Clean).Clean()
//}
//
//a.b.ret()
//
//for _, v := range reverse(a.deferred) {
// v.(Write).Write()
//}

d := a.deferred

if len(d) == 0 {
panic("writeDeferred len == 0")
}
d2 := reverse(d)

d2[0].Write(a.params)

for _, v := range d2 {
v.Clean()
}

a.b.ret()
for _, v := range d2[1:] {
v.Write(a.params)
}

//writeDeferred(a.params, a.deferred)

return //a.prev.retAssigment(a.startedAt, a.params.b.len())
}

func (a AssigmentState) Clean() {
//for i := len(a.assigments) - 1; i >= 0; i-- {
a.b.writeByte(OpClearCache)
a.b.write(encode(a.n))
//}
}
93 changes: 72 additions & 21 deletions pkg/ride/compiler_call_system.go
Original file line number Diff line number Diff line change
@@ -13,12 +13,14 @@ type CallSystemState struct {
// Position where we started write code for current state.
startedAt uint16
//retAssig uint16
deferred []Deferred
deferreds Deferreds
ns []uniqueid
}

func (a CallSystemState) retAssigment(_ AssigmentState) Fsm {
//a.retAssig = pos
panic("CallSystemState retAssigment")
//return a
func (a CallSystemState) retAssigment(state Fsm) Fsm {
a.deferred = append(a.deferred, state.(Deferred))
return a
}

func (a CallSystemState) Property(name string) Fsm {
@@ -30,11 +32,12 @@ func (a CallSystemState) Func(name string, args []string, invoke string) Fsm {
}

func (a CallSystemState) Bytes(b []byte) Fsm {
return constant(a, a.params, rideBytes(b))
//return constant(a, a.params, rideBytes(b))
panic("c")
}

func (a CallSystemState) Condition() Fsm {
return conditionalTransition(a, a.params)
return conditionalTransition(a, a.params, a.deferreds)
}

func (a CallSystemState) TrueBranch() Fsm {
@@ -45,28 +48,37 @@ func (a CallSystemState) FalseBranch() Fsm {
panic("Illegal call `FalseBranch` on CallFsm")
}

func (a CallSystemState) String(s string) Fsm {
return str(a, a.params, s)
func (a CallSystemState) String(value string) Fsm {
a.deferred = append(a.deferred, a.constant(rideString(value)))
return a
}

func (a CallSystemState) Boolean(v bool) Fsm {
return boolean(a, a.params, v)
//return boolean(a, a.params, v)
panic("c")
}

func callTransition(prev Fsm, params params, name string, argc uint16) Fsm {
func callTransition(prev Fsm, params params, name string, argc uint16, d Deferreds) Fsm {
if _, ok := params.r.get(name); ok {
return newCallUserFsm(prev, params, name, argc)
return newCallUserFsm(prev, params, name, argc, d)
}
return newCallSystemFsm(prev, params, name, argc)
return newCallSystemFsm(prev, params, name, argc, d)
}

func newCallSystemFsm(prev Fsm, params params, name string, argc uint16) Fsm {
func newCallSystemFsm(prev Fsm, params params, name string, argc uint16, d Deferreds) Fsm {
var ns []uniqueid
for i := uint16(0); i < argc; i++ {
ns = append(ns, params.u.next())
}

return &CallSystemState{
prev: prev,
params: params,
name: name,
argc: argc,
startedAt: params.b.len(),
deferreds: d,
ns: ns,
}
}

@@ -76,23 +88,62 @@ func (a CallSystemState) Assigment(name string) Fsm {
}

func (a CallSystemState) Long(value int64) Fsm {
a.b.push(a.constant(rideInt(value)))
a.deferred = append(a.deferred, a.constant(rideInt(value)))
return a
}

func (a CallSystemState) Return() Fsm {
n, ok := a.f(a.name)
if !ok {
panic(fmt.Sprintf("system function named `%s` not found", a.name))

if len(a.ns) != len(a.deferred) {
panic(fmt.Sprintf("ns %d != a.deferred %d", a.argc, len(a.deferred)))
}
a.b.externalCall(n, a.argc)
return a.prev

for i, b := range a.deferred {
if _, ok := isConstant(b); ok {
// skip right now
} else {
a.deferreds.Add(b, a.ns[i], fmt.Sprintf("sys %s param #%d", a.name, i))
//a.c.set(ns[i], nil, nil, a.b.len(), false, fmt.Sprintf("sys %s param #%d", a.name, i))
//b.Write(a.params)
//a.b.ret()
}
}

return a.prev.retAssigment(a)
}

func (a CallSystemState) Call(name string, argc uint16) Fsm {
return callTransition(a, a.params, name, argc)
return callTransition(a, a.params, name, argc, a.deferreds)
}

func (a CallSystemState) Reference(name string) Fsm {
return reference(a, a.params, name)
a.deferred = append(a.deferred, reference(a, a.params, name))
return a
}

func (a CallSystemState) Clean() {

}

func (a CallSystemState) Write(_ params) {
if int(a.argc) != len(a.deferred) {
panic(fmt.Sprintf("argc %d != a.deferred %d", a.argc, len(a.deferred)))
}

for i := range a.ns {
if n, ok := isConstant(a.deferred[i]); ok {
a.b.writeByte(OpRef)
a.b.write(encode(n))
} else {
n := a.ns[i]
a.b.writeByte(OpRef)
a.b.write(encode(n))
}
}

n, ok := a.f(a.name)
if !ok {
panic(fmt.Sprintf("system function named `%s` not found", a.name))
}
a.b.externalCall(n, a.argc)
}
173 changes: 124 additions & 49 deletions pkg/ride/compiler_call_user.go
Original file line number Diff line number Diff line change
@@ -9,27 +9,27 @@ type CallUserState struct {
name string
argc uint16
// positions of arguments
argn []uniqueid
ret func(s CallUserState, at uint16, to uint16)
//argn []uniqueid
//ret func(s CallUserState, at uint16, to uint16)
startedAt uint16

deferred []Deferred
deferreds Deferreds
}

func (a CallUserState) retAssigment(state AssigmentState) Fsm {
panic("CallUserState retAssigment")
//if a.ret != nil {
// a.ret(a, startedAt, endedAt)
//}
//a.ret = nil
//return a
func (a CallUserState) retAssigment(state Fsm) Fsm {
a.deferred = append(a.deferred, state.(Deferred))
return a
}

func newCallUserFsm(prev Fsm, params params, name string, argc uint16) Fsm {
func newCallUserFsm(prev Fsm, params params, name string, argc uint16, d Deferreds) Fsm {
return &CallUserState{
prev: prev,
params: params,
name: name,
argc: argc,
startedAt: params.b.len(),
deferreds: d,
}
}

@@ -42,12 +42,12 @@ func (a CallUserState) Func(name string, args []string, invoke string) Fsm {
}

func (a CallUserState) Bytes(b []byte) Fsm {
a.argn = append(a.argn, putConstant(a.params, rideBytes(b)))
a.deferred = append(a.deferred, a.constant(rideBytes(b)))
return a
}

func (a CallUserState) Condition() Fsm {
return conditionalTransition(a, a.params)
return conditionalTransition(a, a.params, a.deferreds)
}

func (a CallUserState) TrueBranch() Fsm {
@@ -59,12 +59,12 @@ func (a CallUserState) FalseBranch() Fsm {
}

func (a CallUserState) String(s string) Fsm {
a.argn = append(a.argn, putConstant(a.params, rideString(s)))
a.deferred = append(a.deferred, a.constant(rideString(s)))
return a
}

func (a CallUserState) Boolean(v bool) Fsm {
a.argn = append(a.argn, putConstant(a.params, rideBoolean(v)))
a.deferred = append(a.deferred, a.constant(rideBoolean(v)))
return a
}

@@ -74,55 +74,130 @@ func (a CallUserState) Assigment(name string) Fsm {
}

func (a CallUserState) Long(value int64) Fsm {
a.argn = append(a.argn, putConstant(a.params, rideInt(value)))
a.deferred = append(a.deferred, a.constant(rideInt(value)))
return a
}

func (a CallUserState) Return() Fsm {
// check user functions
n, ok := a.r.get(a.name)
if !ok {
panic(fmt.Sprintf("user function `%s` not found", a.name))
}
for i, pos := range a.argn {
a.b.writeByte(OpSetArg)
funcParamID, ok := a.r.get(fmt.Sprintf("%s$%d", a.name, i))
/*
// check user functions
n, ok := a.r.get(a.name)
if !ok {
panic(fmt.Sprintf("no function param id `%s` stored in references", fmt.Sprintf("%s$%d", a.name, i)))
panic(fmt.Sprintf("user function `%s` not found", a.name))
}
for i, pos := range a.argn {
a.b.writeByte(OpSetArg)
funcParamID, ok := a.r.get(fmt.Sprintf("%s$%d", a.name, i))
if !ok {
panic(fmt.Sprintf("no function param id `%s` stored in references", fmt.Sprintf("%s$%d", a.name, i)))
}
a.b.write(encode(pos))
a.b.write(encode(funcParamID))
}
a.b.write(encode(pos))
a.b.write(encode(funcParamID))
}
point, ok := a.params.c.get(n)
if !ok {
panic(fmt.Sprintf("no point %d found in cell", n))
}
_, ok = a.params.c.get(n)
if !ok {
panic(fmt.Sprintf("no point %d found in cell", n))
}
a.b.call(point.position, a.argc)
return a.prev //.retAssigment(a.startedAt, a.b.len())
//a.b.call(point.position, a.argc)
a.b.writeByte(OpRef)
a.b.write(encode(n))
*/
return a.prev.retAssigment(a) //.retAssigment(a.startedAt, a.b.len())
}

func (a CallUserState) Call(name string, argc uint16) Fsm {
n := a.u.next()
a.c.set(n, nil, nil, 0, false, fmt.Sprintf("function as paramentr: %s$%d", name, n))
a.argn = append(a.argn, n)
if a.ret != nil {
panic("already assigned")
}
a.ret = func(state CallUserState, startedAt uint16, endedAt uint16) {
a.b.writeByte(OpCache)
a.b.write(encode(n))
a.b.writeByte(OpPop)
}
return callTransition(a, a.params, name, argc)
//n := a.u.next()
//a.c.set(n, nil, nil, 0, false, fmt.Sprintf("function as paramentr: %s$%d", name, n))
//a.argn = append(a.argn, n)
//if a.ret != nil {
// panic("already assigned")
//}
//a.ret = func(state CallUserState, startedAt uint16, endedAt uint16) {
// a.b.writeByte(OpCache)
// a.b.write(encode(n))
// a.b.writeByte(OpPop)
//}
return callTransition(a, a.params, name, argc, a.deferreds)
}

func (a CallUserState) Reference(name string) Fsm {
rs, ok := a.r.get(name)
a.deferred = append(a.deferred, reference(a, a.params, name))
//rs, ok := a.r.get(name)
//if !ok {
// panic("CallUserState Reference " + name + " not found")
//}
//a.argn = append(a.argn, rs)
return a
}

func (a CallUserState) Clean() {

}

func (a CallUserState) Write(_ params) {
// check user functions
fn, ok := a.r.get(a.name)
if !ok {
panic("CallUserState Reference " + name + " not found")
panic(fmt.Sprintf("user function `%s` not found", a.name))
}
a.argn = append(a.argn, rs)
return a

if int(a.argc) != len(a.deferred) {
panic(fmt.Sprintf("argc %d != a.deferred %d", a.argc, len(a.deferred)))
}

var ns []uniqueid
for i := uint16(0); i < a.argc; i++ {
if n, ok := isConstant(a.deferred[i]); ok {
a.b.writeByte(OpSetArg)
a.b.write(encode(n))
a.b.write(encode(fn + 1 + i))
ns = append(ns, n)
} else {
n := a.u.next()
a.b.writeByte(OpSetArg)
a.b.write(encode(n))
a.b.write(encode(fn + 1 + i))
ns = append(ns, n)
}
}

a.b.writeByte(OpRef)
a.b.write(encode(fn))
a.b.ret()

if len(ns) != len(a.deferred) {
panic(fmt.Sprintf("ns %d != a.deferred %d", a.argc, len(a.deferred)))
}

for i, b := range a.deferred {
if _, ok := isConstant(b); ok {
// skip right now
} else {
a.c.set(ns[i], nil, nil, a.b.len(), false, fmt.Sprintf("sys %s param #%d", a.name, i))
b.Write(a.params)
a.b.ret()
}
}

/*
for i := 0; i < a.argc; i++ {
a.b.writeByte(OpSetArg)
funcParamID, ok := a.r.get(a.name) // fmt.Sprintf("%s$%d", a.name, i))
if !ok {
panic(fmt.Sprintf("no function param id `%s` stored in references", fmt.Sprintf("%s$%d", a.name, i)))
}
a.b.write(encode(pos))
a.b.write(encode(funcParamID + 1 + uniqueid(i)))
}
*/

//_, ok = a.params.c.get(n)
//if !ok {
// panic(fmt.Sprintf("no point %d found in cell", n))
//}

//a.b.call(point.position, a.argc)

}
132 changes: 83 additions & 49 deletions pkg/ride/compiler_conditional.go
Original file line number Diff line number Diff line change
@@ -30,18 +30,18 @@ type ConditionalState struct {
rets []uint16

// Clean assigments after exit.
assigments []AssigmentState
//assigmentIndex int
deferred []Deferred
deferreds Deferreds

condN uniqueid
}

func (a ConditionalState) retAssigment(v AssigmentState) Fsm {
//panic("ConditionalState retAssigment")
//return a
a.assigments = append(a.assigments, v)
func (a ConditionalState) retAssigment(v Fsm) Fsm {
a.deferred = append(a.deferred, v.(Deferred))
return a
}

func (a ConditionalState) Property(name string) Fsm {
func (a ConditionalState) Property(string) Fsm {
panic("ConditionalState Property")
}

@@ -50,86 +50,120 @@ func (a ConditionalState) Func(name string, args []string, invoke string) Fsm {
}

func (a ConditionalState) Bytes(b []byte) Fsm {
a.rets = append(a.rets, a.params.b.len())
return constant(a, a.params, rideBytes(b))
//a.rets = append(a.rets, a.params.b.len())
//return constant(a, a.params, rideBytes(b))
panic("")
}

func conditionalTransition(prev Fsm, params params) Fsm {
func conditionalTransition(prev Fsm, params params, deferreds Deferreds) Fsm {
return ConditionalState{
prev: prev,
params: params,
startedAt: params.b.len(),
//assigments: make([][]AssigmentState, 3),
//assigmentIndex: 0,
//deferred: make([[]Deferred, 3),
deferreds: deferreds,
}
}

func (a ConditionalState) Condition() Fsm {
a.rets = append(a.rets, a.params.b.len())
return conditionalTransition(a, a.params)
return conditionalTransition(a, a.params, a.deferreds)
}

func (a ConditionalState) TrueBranch() Fsm {
a.b.jpmIfFalse()
a.patchTruePosition = a.b.writeStub(2)
a.patchFalsePosition = a.b.writeStub(2)
a.patchNextPosition = a.b.writeStub(2)
return a
}

func (a ConditionalState) FalseBranch() Fsm {
a.b.ret()
return a
}

func (a ConditionalState) Assigment(name string) Fsm {
n := a.params.u.next()
//a.assigments = append(a.assigments, n)
a.r.set(name, n)
return assigmentFsmTransition(a, a.params, name, n)
}

func (a ConditionalState) Return() Fsm {
a.b.ret() // return for false branch
endPos := a.b.len()

for _, v := range a.assigments {
v.Write()
}

for i := len(a.assigments) - 1; i >= 0; i-- {
a.b.writeByte(OpClearCache)
a.b.write(encode(a.assigments[i].n))
}

a.b.patch(a.patchTruePosition, encode(a.rets[1]))
a.b.patch(a.patchFalsePosition, encode(a.rets[2]))
a.b.patch(a.patchNextPosition, encode(endPos))
return a.prev //.retAssigment(a.startedAt, a.b.len())
return assigmentFsmTransition(a, a.params, name, n, a.deferreds)
}

func (a ConditionalState) Long(value int64) Fsm {
a.rets = append(a.rets, a.params.b.len())
return long(a, a.params, value)
a.deferred = append(a.deferred, a.constant(rideInt(value)))
return a
}

func (a ConditionalState) Call(name string, argc uint16) Fsm {
a.rets = append(a.rets, a.params.b.len())
// TODO check if we need ret here
return callTransition(a, a.params, name, argc)
//a.rets = append(a.rets, a.params.b.len())
return callTransition(a, a.params, name, argc, a.deferreds)
//panic("")
}

func (a ConditionalState) Reference(name string) Fsm {
a.rets = append(a.rets, a.params.b.len())
return reference(a, a.params, name)
//a.rets = append(a.rets, a.params.b.len())
//return reference(a, a.params, name)
//panic("")
a.deferred = append(a.deferred, reference(a, a.params, name))
return a
}

func (a ConditionalState) Boolean(v bool) Fsm {
a.rets = append(a.rets, a.params.b.len())
return boolean(a, a.params, v)
a.deferred = append(a.deferred, a.constant(rideBoolean(v)))
return a
}

func (a ConditionalState) String(s string) Fsm {
a.rets = append(a.rets, a.params.b.len())
return str(a, a.params, s)
//a.rets = append(a.rets, a.params.b.len())
//return str(a, a.params, s)
panic("")
}

func (a ConditionalState) Return() Fsm {
if len(a.deferred) != 3 {
panic("len(a.deferred) != 3")
}
a.condN = a.u.next()
a.deferreds.Add(a.deferred[0], a.condN, "condition cond")
return a.prev.retAssigment(a) //.retAssigment(a.startedAt, a.b.len())
}

func (a ConditionalState) Write(_ params) {
if len(a.deferred) != 3 {
panic("len(a.deferred) != 3")
}

//condB := a.deferred[0]
trueB := a.deferred[1]
falsB := a.deferred[2]

a.b.writeByte(OpRef)
a.b.write(encode(a.condN))

a.b.jpmIfFalse()
a.patchTruePosition = a.b.writeStub(2)
//a.b.write(encode(a.b.len()))
a.patchFalsePosition = a.b.writeStub(2)
a.patchNextPosition = a.b.writeStub(2)

a.b.patch(a.patchTruePosition, encode(a.b.len()))
//writeDeferred(a.params, trueB)
//a.b.ret()
trueB.Write(a.params)
a.b.ret()

a.b.patch(a.patchFalsePosition, encode(a.b.len()))
falsB.Write(a.params)
a.b.ret()

//for _, v := range condB[1:] {
// v.Write(a.params)
//}

a.b.patch(a.patchNextPosition, encode(a.b.len()))
//for _, v := range condB[1:] {
// v.Clean()
//}
a.b.ret()

//writeDeferred(a.params, a.deferred)
}
func (a ConditionalState) Clean() {
//panic("ConditionalState Clean")
}
205 changes: 119 additions & 86 deletions pkg/ride/compiler_func.go
Original file line number Diff line number Diff line change
@@ -1,37 +1,52 @@
package ride

import (
"fmt"
)
import "fmt"

type arguments []string

func (a arguments) pos(name string) int {
for i := range a {
if a[i] == name {
return i
}
}
return -1
type Deferreds interface {
Add(Deferred, uniqueid, string)
}

type dd struct {
deferred Deferred
uniq uniqueid
debug string
}

type deferreds struct {
name string
d []dd
}

func (a *deferreds) Add(deferred2 Deferred, n uniqueid, debug string) {
a.d = append(a.d, dd{
deferred: deferred2,
uniq: n,
debug: debug,
})
}

func (a *deferreds) Get() []dd {
return a.d
}

type FuncState struct {
params
prev Fsm
name string
args arguments
globalScope *references
invokeParam string
lastStmtOffset uint16
startedAt uint16
prev Fsm
name string
args arguments
n uniqueid
invokeParam string

// References that defined inside function.
// Should be cleared before exit.
assigments []AssigmentState
deferred []Deferred
defers *deferreds
//exe Fsm
}

func (a FuncState) retAssigment(as AssigmentState) Fsm {
a.assigments = append(a.assigments, as) /// []uniqueid
func (a FuncState) retAssigment(as Fsm) Fsm {
a.deferred = append(a.deferred, as.(Deferred))
return a
}

@@ -40,121 +55,111 @@ func (a FuncState) Property(name string) Fsm {
}

func funcTransition(prev Fsm, params params, name string, args []string, invokeParam string) Fsm {
startedAt := params.b.len()
// save reference to global scope, where code lower that function will be able to use it.
globalScope := params.r
n := params.u.next()
params.r.set(name, n)
// all variable we add only visible to current scope,
// avoid corrupting parent state.
params.r = newReferences(params.r)

// Function call: verifier or not.
if invokeParam != "" {
args = append([]string{invokeParam}, args...)
// tx
//pos, ok := params.r.get("tx")
//if !ok {
// panic("no `tx` in function call")
//}
//params.b.writeByte(OpExternalCall)
//params.b.write(encode(math.MaxUint16))
//params.b.write(encode(0))
//params.b.writeByte(OpReturn)
//params.r.set(invokeParam, pos)
//params.r.set(invokeParam, params.u.next())
}
//assigments := []uniqueid{}
for i := range args {
e := params.u.next()
//assigments = append(assigments, e)
params.r.set(args[i], e)
// set to global
globalScope.set(fmt.Sprintf("%s$%d", name, i), e)
//globalScope.set(fmt.Sprintf("%s$%d", name, i), e)
}
//if invokeParam != "" {
// assigments = assigments[1:]
//}

return &FuncState{
prev: prev,
name: name,
args: args,
params: params,
//offset: params.b.len(),
globalScope: globalScope,
prev: prev,
name: name,
args: args,
params: params,
n: n,
invokeParam: invokeParam,
startedAt: startedAt,
//assigments: assigments,
defers: &deferreds{
name: "func " + name,
},
}
}

func (a FuncState) Assigment(name string) Fsm {
n := a.params.u.next()
//a.assigments = append(a.assigments, n)
return assigmentFsmTransition(a, a.params, name, n)
return assigmentFsmTransition(a, a.params, name, n, a.defers)
}

func (a FuncState) Return() Fsm {
funcID := a.params.u.next()
a.globalScope.set(a.name, funcID)
a.params.c.set(funcID, nil, nil, a.lastStmtOffset, false, a.name)
// TODO clean args

// Clean internal assigments.
for i := len(a.assigments) - 1; i >= 0; i-- {
a.b.writeByte(OpClearCache)
a.b.write(encode(a.assigments[i].n))
}

a.b.ret()
/*
funcID := a.params.u.next()
a.globalScope.set(a.name, funcID)
a.params.c.set(funcID, nil, nil, a.lastStmtOffset, false, a.name)
// TODO clean args
// Clean internal assigments.
for i := len(a.assigments) - 1; i >= 0; i-- {
a.b.writeByte(OpClearCache)
a.b.write(encode(a.assigments[i].n))
}
// if function has invoke param, it means no other code will be provided.
if a.invokeParam != "" {
a.b.startPos()
for i := len(a.args) - 1; i >= 0; i-- {
a.b.writeByte(OpCache)
uniq, ok := a.params.r.get(a.args[i])
if !ok {
panic("function param `" + a.args[i] + "` not found")
a.b.ret()
// if function has invoke param, it means no other code will be provided.
if a.invokeParam != "" {
a.b.startPos()
for i := len(a.args) - 1; i >= 0; i-- {
a.b.writeByte(OpCache)
uniq, ok := a.params.r.get(a.args[i])
if !ok {
panic("function param `" + a.args[i] + "` not found")
}
a.b.write(encode(uniq))
a.b.writeByte(OpPop)
}
a.b.write(encode(uniq))
a.b.writeByte(OpPop)
a.b.writeByte(OpCall)
a.b.write(encode(a.lastStmtOffset))
}
a.b.writeByte(OpCall)
a.b.write(encode(a.lastStmtOffset))
}
return a.prev //.retAssigment(a.startedAt, a.b.len())
*/
return a.prev.retAssigment(a) //.retAssigment(a.startedAt, a.b.len())
}

func (a FuncState) Long(value int64) Fsm {
a.lastStmtOffset = a.b.len()
a.params.b.push(a.constant(rideInt(value)))
a.deferred = append(a.deferred, a.constant(rideInt(value)))
return a
}

func (a FuncState) Call(name string, argc uint16) Fsm {
a.lastStmtOffset = a.b.len()
return callTransition(a, a.params, name, argc)
return callTransition(a, a.params, name, argc, a.defers)
}

func (a FuncState) Reference(name string) Fsm {
a.lastStmtOffset = a.b.len()
return reference(a, a.params, name)
a.deferred = append(a.deferred, reference(a, a.params, name))
return a
}

func (a FuncState) Boolean(v bool) Fsm {
a.lastStmtOffset = a.b.len()
return constant(a, a.params, rideBoolean(v))
func (a FuncState) Boolean(value bool) Fsm {
a.deferred = append(a.deferred, a.constant(rideBoolean(value)))
return a
}

func (a FuncState) String(s string) Fsm {
a.lastStmtOffset = a.b.len()
return constant(a, a.params, rideString(s))
//a.lastStmtOffset = a.b.len()
//return constant(a, a.params, rideString(s))
panic("a")
}

func (a FuncState) Condition() Fsm {
a.lastStmtOffset = a.b.len()
return conditionalTransition(a, a.params)
//a.lastStmtOffset = a.b.len()
return conditionalTransition(a, a.params, a.defers)
}

func (a FuncState) TrueBranch() Fsm {
@@ -166,10 +171,38 @@ func (a FuncState) FalseBranch() Fsm {
}

func (a FuncState) Bytes(b []byte) Fsm {
a.lastStmtOffset = a.b.len()
return constant(a, a.params, rideBytes(b))
//a.lastStmtOffset = a.b.len()
//return constant(a, a.params, rideBytes(b))
panic("a")
}

func (a FuncState) Func(name string, args []string, _ string) Fsm {
panic("Illegal call `Func` is `FuncState`")
}

func (a FuncState) Clean() {

}

func (a FuncState) Write(_ params) {
pos := a.b.len()
a.params.c.set(a.n, nil, nil, pos, false, fmt.Sprintf("function %s", a.name))
//writeDeferred(a.params, a.deferred)
if len(a.deferred) != 1 {
panic("len(a.deferred) != 1")
}
a.deferred[0].Write(a.params)

// End of function body. Clear and write assigments.
for _, v := range a.defers.Get() {
v.deferred.Clean()
}
a.b.ret()

for _, v := range a.defers.Get() {
pos := a.b.len()
a.c.set(v.uniq, nil, nil, pos, false, v.debug)
v.deferred.Write(a.params)
}

}
85 changes: 81 additions & 4 deletions pkg/ride/compiler_helpers.go
Original file line number Diff line number Diff line change
@@ -72,12 +72,12 @@ func (b *builder) call(id uint16, argc uint16) {
b.w.Write(encode(id))
}

func (b *builder) startPos() {
b.startAt = uint16(b.w.Len())
}
//func (b *builder) startPos() {
// b.startAt = uint16(b.w.Len())
//}

func (b *builder) build() (uint16, []byte) {
return b.startAt, b.w.Bytes()
return 1, b.w.Bytes()
}

func (b *builder) jpmIfFalse() {
@@ -205,3 +205,80 @@ func (a *predef) getn(id int) rideFunction {
}
return a.prev.getn(id)
}

func reverse(f []Deferred) []Deferred {
out := make([]Deferred, 0, len(f))
for i := len(f) - 1; i >= 0; i-- {
out = append(out, f[i])
}
return out
}

type Deferred interface {
Write
Clean
}

type deferred struct {
write func()
clean func()
}

func (a deferred) Write(_ params) {
if a.write != nil {
a.write()
}
}

func (a deferred) Clean() {
if a.clean != nil {
a.clean()
}
}

type constantDeferred struct {
n uniqueid
}

func (a constantDeferred) Write(p params) {
p.b.writeByte(OpRef)
p.b.write(encode(a.n))
}

func (a constantDeferred) Clean() {
}

func NewDeferred(writeFunc func(), cleanFunc func()) Deferred {
return deferred{
write: writeFunc,
clean: cleanFunc,
}
}

func NewConstantDeferred(n uniqueid) constantDeferred {
return constantDeferred{n: n}
}

func writeDeferred(params params, d []Deferred) {
panic("writeDeferred 1")
if len(d) != 1 {
panic("writeDeferred len != 1")
}
d2 := reverse(d)

d2[0].Write(params)

for _, v := range d2 {
v.Clean()
}

params.b.ret()
for _, v := range d2[1:] {
v.Write(params)
}
}

func isConstant(deferred Deferred) (uniqueid, bool) {
v, ok := deferred.(constantDeferred)
return v.n, ok
}
60 changes: 40 additions & 20 deletions pkg/ride/compiler_main.go
Original file line number Diff line number Diff line change
@@ -5,11 +5,12 @@ type MainState struct {
params
retAssig uint16

assigments []AssigmentState
deferred []Deferred
deferreds *deferreds
}

func (a MainState) retAssigment(as AssigmentState) Fsm {
a.assigments = append(a.assigments, as)
func (a MainState) retAssigment(state Fsm) Fsm {
a.deferred = append(a.deferred, state.(Deferred))
return a
}

@@ -26,8 +27,8 @@ func (a MainState) Bytes(b []byte) Fsm {
}

func (a MainState) Condition() Fsm {
a.b.startPos()
return conditionalTransition(a, a.params)
//a.b.startPos()
return conditionalTransition(a, a.params, a.deferreds)
}

func (a MainState) TrueBranch() Fsm {
@@ -49,27 +50,39 @@ type BuildExecutable interface {
func NewMain(params params) Fsm {
return &MainState{
params: params,
deferreds: &deferreds{
name: "main",
},
}
}

func (a MainState) Assigment(name string) Fsm {
n := a.params.u.next()
//a.assigments = append(a.assigments, n)
a.r.set(name, n)
return assigmentFsmTransition(a, a.params, name, n)
//a.r.set(name, n)
return assigmentFsmTransition(a, a.params, name, n, a.deferreds)
}

func (a MainState) Return() Fsm {

for _, v := range a.assigments {
v.Write()
reversed := reverse(a.deferred)
for _, v := range reversed[:1] {
v.Write(a.params)
}

for i := len(a.assigments) - 1; i >= 0; i-- {
a.b.writeByte(OpClearCache)
a.b.write(encode(a.assigments[i].n))
for _, v := range a.deferreds.Get() {
v.deferred.Clean()
}
a.b.ret()
for _, v := range reversed[1:] {
v.Write(a.params)
a.b.ret()
}

for _, v := range a.deferreds.Get() {
pos := a.b.len()
a.c.set(v.uniq, nil, nil, pos, false, v.debug)
v.deferred.Write(a.params)
a.b.ret()
}
return a
}

@@ -78,18 +91,17 @@ func (a MainState) Long(int64) Fsm {
}

func (a MainState) Call(name string, argc uint16) Fsm {
a.b.startPos()
return callTransition(a, a.params, name, argc)
return callTransition(a, a.params, name, argc, a.deferreds)
}

func (a MainState) Reference(name string) Fsm {
a.b.startPos()
return reference(a, a.params, name)
a.deferred = append(a.deferred, reference(a, a.params, name))
return a
}

func (a MainState) Boolean(v bool) Fsm {
a.b.startPos()
return boolean(a, a.params, v)
a.deferred = append(a.deferred, a.constant(rideBoolean(v)))
return a
}

func (a MainState) BuildExecutable(version int) *Executable {
@@ -101,3 +113,11 @@ func (a MainState) BuildExecutable(version int) *Executable {
EntryPoints: map[string]uint16{"": startAt},
}
}

func (a MainState) Write(_ params) {

}

func (a MainState) Clean() {

}
29 changes: 21 additions & 8 deletions pkg/ride/compiler_property.go
Original file line number Diff line number Diff line change
@@ -4,9 +4,11 @@ type PropertyState struct {
prev Fsm
name string
params
deferred []Deferred
deferreds Deferreds
}

func (a PropertyState) retAssigment(as AssigmentState) Fsm {
func (a PropertyState) retAssigment(as Fsm) Fsm {
panic("implement me")
//return a
}
@@ -24,22 +26,24 @@ func (a PropertyState) Assigment(name string) Fsm {
}

func (a PropertyState) Return() Fsm {
a.b.writeByte(OpProperty)
index := a.constant(rideString(a.name))
a.params.b.write(encode(index))
return a.prev
//a.b.writeByte(OpProperty)
//index := a.constant(rideString(a.name))
//a.params.b.write(encode(index))
//return a.prev.retAssigment(a)
panic("aaaaa")
}

func (a PropertyState) Long(value int64) Fsm {
panic("Illegal call `Long` on PropertyState")
}

func (a PropertyState) Call(name string, argc uint16) Fsm {
return callTransition(a, a.params, name, argc)
return callTransition(a, a.params, name, argc, a.deferreds)
}

func (a PropertyState) Reference(name string) Fsm {
return reference(a, a.params, name)
a.deferred = append(a.deferred, reference(a, a.params, name))
return a
}

func (a PropertyState) Boolean(v bool) Fsm {
@@ -63,7 +67,8 @@ func (a PropertyState) FalseBranch() Fsm {
}

func (a PropertyState) Bytes(b []byte) Fsm {
return bts(a, a.params, b)
a.deferred = append(a.deferred, a.constant(rideBytes(b)))
return a
}

func (a PropertyState) Func(name string, args []string, invoke string) Fsm {
@@ -73,3 +78,11 @@ func (a PropertyState) Func(name string, args []string, invoke string) Fsm {
func (a PropertyState) Property(name string) Fsm {
return propertyTransition(a, a.params, name)
}

func (a PropertyState) Clean() {

}

func (a PropertyState) Write(_ params) {
panic("PropertyState Write")
}
84 changes: 47 additions & 37 deletions pkg/ride/compiler_state.go
Original file line number Diff line number Diff line change
@@ -16,7 +16,16 @@ type Fsm interface {
Bytes(b []byte) Fsm
Func(name string, args []string, invokeParam string) Fsm
Property(name string) Fsm
retAssigment(state AssigmentState) Fsm
retAssigment(state Fsm) Fsm
Deferred
}

type Write interface {
Write(params)
}

type Clean interface {
Clean()
}

type uniqid struct {
@@ -54,48 +63,49 @@ func (a *params) addPredefined(name string, id uniqueid, fn rideFunction) {
a.c.set(id, nil, fn, 0, false, name)
}

func (a *params) constant(value rideType) uniqueid {
func (a *params) constant(value rideType) constantDeferred {
n := a.u.next()
a.c.set(n, value, nil, 0, true, fmt.Sprintf("constant %q", value))
return n
}

func long(f Fsm, params params, value int64) Fsm {
params.b.push(params.constant(rideInt(value)))
return f
}

func boolean(f Fsm, params params, value bool) Fsm {
params.b.push(params.constant(rideBoolean(value)))
return f
}

func bts(f Fsm, params params, value []byte) Fsm {
params.b.push(params.constant(rideBytes(value)))
return f
}

func str(a Fsm, params params, value string) Fsm {
params.b.push(params.constant(rideString(value)))
return a
}

func constant(a Fsm, params params, value rideType) Fsm {
params.b.push(params.constant(value))
return a
}

func putConstant(params params, rideType rideType) uniqueid {
index := params.constant(rideType)
return index
return NewConstantDeferred(n)
}

func reference(f Fsm, params params, name string) Fsm {
//func long(f Fsm, params params, value int64) Fsm {
// params.b.push(params.constant(rideInt(value)))
// return f
//}

//func boolean(f Fsm, params params, value bool) Deferred {
// return NewDeferred(func() {
// params.b.push(params.constant(rideBoolean(value)))
// }, nil)
// //return f
//}

//func bts(f Fsm, params params, value []byte) Fsm {
// params.b.push(params.constant(rideBytes(value)))
// return f
//}

//func str(a Fsm, params params, value string) Deferred {
// return NewDeferred(func() {
// params.b.push(params.constant(rideString(value)))
// }, nil)
//}

//func constant(a Fsm, params params, value rideType) Fsm {
// params.b.push(params.constant(value))
// return a
//}

//func putConstant(params params, rideType rideType) uniqueid {
// index := params.constant(rideType)
// return index
//}

func reference(f Fsm, params params, name string) Deferred {
pos, ok := params.r.get(name)
if !ok {
panic(fmt.Sprintf("reference %s not found, tx %s", name, params.txID))
}
//params.b
params.b.ref(pos)
return f
return NewConstantDeferred(pos)
}
4 changes: 2 additions & 2 deletions pkg/ride/opcodes.go
Original file line number Diff line number Diff line change
@@ -17,8 +17,8 @@ const (
OpCall //10 0xa - Call a function declared at given address. One parameter: position of function declaration.
OpSetArg //11 0xb - FROM (global) -> TO (local): Set value into cell. Two parameters: constant id and cell id.
OpCache //12 0xc - Put constant on stack. One parameter: constant ID.
OpRef //14 0xd = ref id
OpClearCache //15 0xe = ref id
OpRef //13 0xd = ref id
OpClearCache //14 0xe = ref id

// odd, will be removed.
OpGlobal