Skip to content

Commit

Permalink
Tests on correct scopes handling by estimator and evaluator added. (#…
Browse files Browse the repository at this point in the history
…1264)

* Tests on correct scopes handling by estimator and evaluator added.
Few compilation errors of FOLD fixed.
Comparison of Any type to other types fixed in compilation.

* Added test on FOLD compilation.
Fixed SimpeType Equal function.
  • Loading branch information
alexeykiselev authored Dec 18, 2023
1 parent f4743ed commit e5a0929
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 25 deletions.
21 changes: 15 additions & 6 deletions pkg/ride/compiler/ast_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (p *astParser) addError(token token32, format string, args ...any) {
}

func (p *astParser) loadBuildInVarsToStackByVersion() {
resVars := make(map[string]s.Variable, 0)
resVars := make(map[string]s.Variable)
ver := int(p.tree.LibVersion)
for i := 0; i < ver; i++ {
for _, v := range s.Vars().Vars[i].Append {
Expand Down Expand Up @@ -912,6 +912,8 @@ func (p *astParser) ruleListGroupOpAtomHandler(node *node32) (ast.Node, s.Type)
p.addError(curNode.token32, "Unexpected types for '++' operator '%s' and '%s'", varType, nextVarType)
return nil, nil
}
default:
panic("unhandled default case")
}
expr = ast.NewFunctionCallNode(funcId, []ast.Node{expr, nextExpr})
curNode = curNode.next
Expand Down Expand Up @@ -2357,12 +2359,19 @@ func (p *astParser) ruleFoldMacroHandler(node *node32) (ast.Node, s.Type) {
}
curNode = skipToNextRule(curNode.next)
arr, arrVarType := p.ruleExprHandler(curNode)
var elemType s.Type
if l, ok := arrVarType.(s.ListType); !ok {
p.addError(curNode.token32, "First argument of fold must be List, but '%s' found", arrVarType.String())
if arr == nil {
p.addError(curNode.token32, "Undefined first argument of FOLD macros")
return nil, nil
} else {
elemType = l.Type
}
l, ok := arrVarType.(s.ListType)
if !ok {
p.addError(curNode.token32, "First argument of FOLD macros must be List, but '%s' found",
arrVarType.String())
return nil, nil
}
elemType := l.Type
if elemType == nil { // If the type of elements is unknown, set it to Any.
elemType = s.AnyType
}
curNode = skipToNextRule(curNode.next)
start, startVarType := p.ruleExprHandler(curNode)
Expand Down
10 changes: 9 additions & 1 deletion pkg/ride/compiler/ast_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,17 @@ let arr = [1,2,3,4,5]
let a = FOLD<5>(arr, [], filterEven)
`, false, "BgICCAIDAQpmaWx0ZXJFdmVuAgVhY2N1bQRuZXh0AwkAAAIJAGoCBQRuZXh0AAIAAAkAzQgCBQVhY2N1bQUEbmV4dAUFYWNjdW0AA2FycgkAzAgCAAEJAMwIAgACCQDMCAIAAwkAzAgCAAQJAMwIAgAFBQNuaWwAAWEKAAIkbAUDYXJyCgACJHMJAJADAQUCJGwKAAUkYWNjMAUDbmlsCgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQpmaWx0ZXJFdmVuAgUCJGEJAJEDAgUCJGwFAiRpCgEFJGYwXzICAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAAIBAhNMaXN0IHNpemUgZXhjZWVkcyA1CQEFJGYwXzICCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECCQEFJGYwXzECBQUkYWNjMAAAAAEAAgADAAQABQAAWwkCmw=="},
{`
func sum(accum: Int, next: Int) = accum + next
let arr = []
let a = FOLD<5>(arr, 0, sum)
`, false, "BgICCAIDAQNzdW0CBWFjY3VtBG5leHQJAGQCBQVhY2N1bQUEbmV4dAADYXJyBQNuaWwAAWEKAAIkbAUDYXJyCg" +
"ACJHMJAJADAQUCJGwKAAUkYWNjMAAACgEFJGYwXzECAiRhAiRpAwkAZwIFAiRpBQIkcwUCJGEJAQNzdW0CBQIkYQkAkQMCBQIkbA" +
"UCJGkKAQUkZjBfMgICJGECJGkDCQBnAgUCJGkFAiRzBQIkYQkAAgECE0xpc3Qgc2l6ZSBleGNlZWRzIDUJAQUkZjBfMgIJAQUkZj" +
"BfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIJAQUkZjBfMQIFBSRhY2MwAAAAAQACAAMABAAFAABmy6Xs"},
{`
func sum(a:Int, b:Int) = a + b
let a = FOLD<5>(1, 9, sum)
`, true, "(6:17, 6:18): First argument of fold must be List, but 'Int' found"},
`, true, "(6:17, 6:18): First argument of FOLD macros must be List, but 'Int' found"},
{`
func sum(a:Int, b:String) = a
let b = FOLD<5>([1], 0, sum)
Expand Down
2 changes: 1 addition & 1 deletion pkg/ride/compiler/stdlib/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func (t SimpleType) Equal(other Type) bool {
if o, ok := other.(SimpleType); ok {
return t.Type == o.Type
}
return false
return other.Equal(AnyType)
}

func (t SimpleType) String() string {
Expand Down
129 changes: 112 additions & 17 deletions pkg/ride/tree_estimation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,29 +389,124 @@ func TestFailOnInvocationInVerifier(t *testing.T) {
}

func TestScope(t *testing.T) {
src := `
{-# STDLIB_VERSION 5 #-}
for _, test := range []struct {
source string
estimation int
estimations map[string]int
}{
{`
{-# STDLIB_VERSION 6 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}

let a = {
func bar(i: Int) = i
bar(1)
func bar(i: Int) = i
bar(1)
}
let b = {
func bar(i: Int) = i
bar(a)
}
@Callable(i)
func empty() = [IntegerEntry("empty", 0)]
@Callable(i)
func aa() = [IntegerEntry("a", a)]
@Callable(i)
func bb() = [IntegerEntry("b", b)]
`,
0, map[string]int{"empty": 3, "aa": 3 + 1, "bb": 3 + 2},
},
{`
{-# STDLIB_VERSION 6 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
let a = {
func bar(i: Int) = i
bar(1)
}
let b = {
let c = {
let d = {
func bar(i: Int) = i
bar(a)
}
func bar(i: Int) = i
bar(d)
}
func bar(i: Int) = i
bar(c)
}
let e = {
func bar(i: Int) = i
bar(b)
}
@Callable(i)
func aa() = [IntegerEntry("a", a)]
@Callable(i)
func bb() = [IntegerEntry("b", b)]
@Callable(i)
func ee() = [IntegerEntry("e", e)]
`,
0, map[string]int{"aa": 3 + 1, "bb": 3 + 4, "ee": 3 + 5},
},
{`
{-# STDLIB_VERSION 6 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
let l = []
let a = {
func foo(fooAcc: Int, i: Int) = fooAcc + i
FOLD<1>(l, 0, foo)
}
let b = {
func bar(i: Int) = i
bar(a)
func bar(barAcc: Int, i: Int) = barAcc + i
FOLD<1>(l, a, bar)
}
@Callable(i)
func aa() = [IntegerEntry("a", a)]
@Callable(i)
func bb() = [IntegerEntry("b", b)]
`,
0, map[string]int{"aa": 3 + 8, "bb": 3 + 16},
},
{`
{-# STDLIB_VERSION 6 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
let a = 1 + 1 + 1
let b = a + 1 + 1
let c = b + a + 1

@Callable(i)
func aa() = [IntegerEntry("a", a)]
@Callable(i)
func bb() = [IntegerEntry("b", b)]
@Callable(i)
func cc() = [IntegerEntry("c", c)]
`,
0, map[string]int{"aa": 3 + 2, "bb": 3 + 4, "cc": 3 + 6},
},
{`{-# STDLIB_VERSION 6 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
let a = groth16Verify(base58'', base58'', base58'')
func f(a: Boolean) = a
@Verifier(tx)
func verify() = a == b
`
tree, errs := ridec.CompileToTree(src)
require.Empty(t, errs)
func verify() = f(true)`,
2701, nil,
},
} {
tree, errs := ridec.CompileToTree(test.source)
require.Empty(t, errs, test.source)

est, err := EstimateTree(tree, 3)
assert.NoError(t, err)
assert.Equal(t, 7, est.Estimation)
est, err = EstimateTree(tree, 4)
assert.NoError(t, err)
assert.Equal(t, 3, est.Estimation)
est, err := EstimateTree(tree, 4)
assert.NoError(t, err, test.source)
if test.estimation > 0 {
assert.Equal(t, test.estimation, est.Estimation)
}
for fn, ee := range test.estimations {
ae, ok := est.Functions[fn]
require.True(t, ok)
assert.Equal(t, ee, ae, test.source)
}
}
}
62 changes: 62 additions & 0 deletions pkg/ride/tree_evaluation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5795,3 +5795,65 @@ func TestHitInDeepInvocationsLimit(t *testing.T) {
_, err := CallFunction(env.toEnv(), tree1, proto.NewFunctionCall("foo", proto.Arguments{}))
assert.EqualError(t, err, "invoke: too many internal invocations")
}

func TestGlobalDeclarationScopesEvaluation(t *testing.T) {
dApp1 := newTestAccount(t, "DAPP1") // 3MzDtgL5yw73C2xVLnLJCrT5gCL4357a4sz
sender := newTestAccount(t, "SENDER") // 3N8CkZAyS4XcDoJTJoKNuNk2xmNKmQj7myW

src := `
{-# STDLIB_VERSION 6 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}

let a = {
func bar(i: Int) = i
bar(1)
}
let b = {
let c = {
let d = {
func bar(i: Int) = i + 1
bar(a)
}
func bar(i: Int) = i * 2
bar(d)
}
func bar(i: Int) = i + 1
bar(c)
}

@Callable(i)
func foo() = {
[IntegerEntry("key", b)]
}
`
tree, errs := ridec.CompileToTree(src)
require.Empty(t, errs)

env := newTestEnv(t).withLibVersion(ast.LibV6).withComplexityLimit(ast.LibV6, 52000).
withBlockV5Activated().withProtobufTx().withRideV6Activated().
withDataEntriesSizeV2().withMessageLengthV3().withValidateInternalPayments().
withThis(dApp1).withDApp(dApp1).withSender(sender).
withInvocation("foo", withTransactionID(crypto.Digest{})).withTree(dApp1, tree).
withWrappedState()
res, err := CallFunction(env.toEnv(), tree, proto.NewFunctionCall("foo", proto.Arguments{}))
require.NoError(t, err)
assert.Equal(t, 1, len(res.ScriptActions()))
r, ok := res.(DAppResult)
require.True(t, ok)

sr, _, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{})
require.NoError(t, err)
expectedResult := &proto.ScriptResult{
DataEntries: []*proto.DataEntryScriptAction{{Entry: &proto.IntegerDataEntry{Key: "key", Value: 5}}},
Transfers: make([]*proto.TransferScriptAction, 0),
Issues: make([]*proto.IssueScriptAction, 0),
Reissues: make([]*proto.ReissueScriptAction, 0),
Burns: make([]*proto.BurnScriptAction, 0),
Sponsorships: make([]*proto.SponsorshipScriptAction, 0),
Leases: make([]*proto.LeaseScriptAction, 0),
LeaseCancels: make([]*proto.LeaseCancelScriptAction, 0),
ErrorMsg: proto.ScriptErrorMessage{},
}
assert.Equal(t, expectedResult, sr)
}

0 comments on commit e5a0929

Please sign in to comment.