diff --git a/runtime/sema/access.go b/runtime/sema/access.go index fcad025d94..9def8f908b 100644 --- a/runtime/sema/access.go +++ b/runtime/sema/access.go @@ -39,6 +39,7 @@ type Access interface { Equal(other Access) bool // PermitsAccess returns whether receiver access permits argument access PermitsAccess(Access) bool + QualifiedKeyword() string } type EntitlementSetKind uint8 @@ -132,8 +133,7 @@ func FormatEntitlementSetTypeID[T ~string](entitlementTypeIDs []T, kind Entitlem return T(builder.String()) } -func (e EntitlementSetAccess) string(typeFormatter func(Type) string) string { - var builder strings.Builder +func (e EntitlementSetAccess) format(sb *strings.Builder, typeFormatter func(Type) string) { var separator string switch e.SetKind { @@ -149,25 +149,36 @@ func (e EntitlementSetAccess) string(typeFormatter func(Type) string) string { e.Entitlements.ForeachWithIndex(func(i int, entitlement *EntitlementType, _ struct{}) { if i > 0 { - builder.WriteString(separator) + sb.WriteString(separator) } - builder.WriteString(typeFormatter(entitlement)) - + sb.WriteString(typeFormatter(entitlement)) }) - - return builder.String() } func (e EntitlementSetAccess) String() string { - return e.string(func(t Type) string { + var sb strings.Builder + e.format(&sb, func(t Type) string { return t.String() }) + return sb.String() } func (e EntitlementSetAccess) QualifiedString() string { - return e.string(func(t Type) string { + var sb strings.Builder + e.format(&sb, func(t Type) string { + return t.QualifiedString() + }) + return sb.String() +} + +func (e EntitlementSetAccess) QualifiedKeyword() string { + var sb strings.Builder + sb.WriteString("access(") + e.format(&sb, func(t Type) string { return t.QualifiedString() }) + sb.WriteString(")") + return sb.String() } func (e EntitlementSetAccess) Equal(other Access) bool { @@ -288,6 +299,14 @@ func (e *EntitlementMapAccess) QualifiedString() string { return e.Type.QualifiedString() } +func (e *EntitlementMapAccess) QualifiedKeyword() string { + var sb strings.Builder + sb.WriteString("access(mapping ") + sb.WriteString(e.Type.QualifiedIdentifier()) + sb.WriteString(")") + return sb.String() +} + func (e *EntitlementMapAccess) Equal(other Access) bool { switch otherAccess := other.(type) { case *EntitlementMapAccess: @@ -455,6 +474,10 @@ func (a PrimitiveAccess) QualifiedString() string { return ast.PrimitiveAccess(a).Description() } +func (a PrimitiveAccess) QualifiedKeyword() string { + return ast.PrimitiveAccess(a).Keyword() +} + func (a PrimitiveAccess) Equal(other Access) bool { switch otherAccess := other.(type) { case PrimitiveAccess: diff --git a/runtime/sema/access_test.go b/runtime/sema/access_test.go index eecba8a9d2..bcee74e122 100644 --- a/runtime/sema/access_test.go +++ b/runtime/sema/access_test.go @@ -23,9 +23,32 @@ import ( "github.com/stretchr/testify/assert" + "github.com/onflow/cadence/runtime/ast" "github.com/onflow/cadence/runtime/common" ) +func TestPrimitiveAccess_QualifiedKeyword(t *testing.T) { + + t.Parallel() + + expected := map[ast.PrimitiveAccess]string{ + ast.AccessNotSpecified: "", + ast.AccessSelf: "access(self)", + ast.AccessAll: "access(all)", + ast.AccessAccount: "access(account)", + ast.AccessContract: "access(contract)", + ast.AccessPubSettableLegacy: "pub(set)", + ast.AccessNone: "inaccessible", + } + + for access := 0; access < ast.PrimitiveAccessCount(); access++ { + assert.Equal(t, + expected[ast.PrimitiveAccess(access)], + PrimitiveAccess(access).QualifiedKeyword(), + ) + } +} + func TestNewEntitlementAccess(t *testing.T) { t.Parallel() @@ -181,6 +204,43 @@ func TestNewEntitlementAccess(t *testing.T) { }) } +func TestEntitlementSetAccess_QualifiedKeyword(t *testing.T) { + + t.Parallel() + + location := common.NewAddressLocation(nil, common.MustBytesToAddress([]byte{0x1}), "Foo") + + fooType := &CompositeType{ + Location: location, + Identifier: "Foo", + } + + barType := NewEntitlementType( + nil, + location, + "Bar", + ) + barType.SetContainerType(fooType) + + bazType := NewEntitlementType( + nil, + location, + "Baz", + ) + bazType.SetContainerType(fooType) + + assert.Equal(t, + "access(Foo.Bar | Foo.Baz)", + newEntitlementAccess( + []Type{ + barType, + bazType, + }, + Disjunction, + ).QualifiedKeyword(), + ) +} + func TestEntitlementMapAccess_ID(t *testing.T) { t.Parallel() @@ -550,3 +610,27 @@ func TestEntitlementSetAccess_QualifiedString(t *testing.T) { ) }) } + +func TestEntitlementMapAccess_QualifiedKeyword(t *testing.T) { + + t.Parallel() + + location := common.NewAddressLocation(nil, common.MustBytesToAddress([]byte{0x1}), "Foo") + + fooType := &CompositeType{ + Location: location, + Identifier: "Foo", + } + + barType := NewEntitlementMapType( + nil, + location, + "Bar", + ) + barType.SetContainerType(fooType) + + assert.Equal(t, + "access(mapping Foo.Bar)", + NewEntitlementMapAccess(barType).QualifiedKeyword(), + ) +}