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

Add required mapping keyword to entitlement mapping usages #2883

Merged
merged 11 commits into from
Oct 24, 2023
82 changes: 61 additions & 21 deletions runtime/ast/access.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
}

type EntitlementSet interface {
Authorization
Entitlements() []*NominalType
Separator() Separator
}
Expand All @@ -64,6 +65,8 @@

var _ EntitlementSet = &ConjunctiveEntitlementSet{}

func (ConjunctiveEntitlementSet) isAuthorization() {}

func (s *ConjunctiveEntitlementSet) Entitlements() []*NominalType {
return s.Elements
}
Expand All @@ -82,6 +85,8 @@

var _ EntitlementSet = &DisjunctiveEntitlementSet{}

func (DisjunctiveEntitlementSet) isAuthorization() {}

func (s *DisjunctiveEntitlementSet) Entitlements() []*NominalType {
return s.Elements
}
Expand All @@ -94,6 +99,10 @@
return &DisjunctiveEntitlementSet{Elements: entitlements}
}

type Authorization interface {
isAuthorization()
}

type EntitlementAccess struct {
EntitlementSet EntitlementSet
}
Expand Down Expand Up @@ -121,7 +130,7 @@

func (e EntitlementAccess) String() string {
str := &strings.Builder{}
str.WriteString("ConjunctiveEntitlementAccess ")
str.WriteString("EntitlementAccess ")

Check warning on line 133 in runtime/ast/access.go

View check run for this annotation

Codecov / codecov/patch

runtime/ast/access.go#L133

Added line #L133 was not covered by tests
e.entitlementsString(str)
return str.String()
}
Expand All @@ -138,33 +147,64 @@
return json.Marshal(e.String())
}

func (e EntitlementAccess) subset(other EntitlementAccess) bool {
otherEntitlements := other.EntitlementSet.Entitlements()
otherSet := make(map[*NominalType]struct{}, len(otherEntitlements))
for _, entitlement := range otherEntitlements {
otherSet[entitlement] = struct{}{}
}
type MappedAccess struct {
EntitlementMap *NominalType
StartPos Position
}

for _, entitlement := range e.EntitlementSet.Entitlements() {
if _, found := otherSet[entitlement]; !found {
return false
}
}
var _ Access = &MappedAccess{}

func (*MappedAccess) isAccess() {}
func (*MappedAccess) isAuthorization() {}

return true
func (*MappedAccess) Description() string {
return "entitlement-mapped access"

Check warning on line 161 in runtime/ast/access.go

View check run for this annotation

Codecov / codecov/patch

runtime/ast/access.go#L160-L161

Added lines #L160 - L161 were not covered by tests
}

func (e EntitlementAccess) IsLessPermissiveThan(other Access) bool {
switch other := other.(type) {
case PrimitiveAccess:
return other == AccessAll
case EntitlementAccess:
return e.subset(other)
default:
return false
func NewMappedAccess(
typ *NominalType,
startPos Position,
) *MappedAccess {
return &MappedAccess{
EntitlementMap: typ,
StartPos: startPos,
}
}

func (t *MappedAccess) StartPosition() Position {
return t.StartPos
}

func (t *MappedAccess) EndPosition(memoryGauge common.MemoryGauge) Position {
return t.EntitlementMap.EndPosition(memoryGauge)
}

func (e *MappedAccess) String() string {
var str strings.Builder
str.WriteString("mapping ")
str.WriteString(e.EntitlementMap.String())
return str.String()

Check warning on line 186 in runtime/ast/access.go

View check run for this annotation

Codecov / codecov/patch

runtime/ast/access.go#L182-L186

Added lines #L182 - L186 were not covered by tests
}

func (e *MappedAccess) Keyword() string {
var str strings.Builder
str.WriteString("access(")
str.WriteString(e.String())
str.WriteString(")")
return str.String()

Check warning on line 194 in runtime/ast/access.go

View check run for this annotation

Codecov / codecov/patch

runtime/ast/access.go#L189-L194

Added lines #L189 - L194 were not covered by tests
}

func (e *MappedAccess) MarshalJSON() ([]byte, error) {
type Alias MappedAccess
return json.Marshal(&struct {
*Alias
Range
}{
Range: NewUnmeteredRangeFromPositioned(e),
Alias: (*Alias)(e),
})
}

type PrimitiveAccess uint8

// NOTE: order indicates permissiveness: from least to most permissive!
Expand Down
25 changes: 25 additions & 0 deletions runtime/ast/access_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,31 @@ func TestPrimitiveAccess_MarshalJSON(t *testing.T) {
}
}

func TestMappedAccess_MarshalJSON(t *testing.T) {

t.Parallel()

e := NewNominalType(nil, NewIdentifier(nil, "E", Position{Offset: 1, Line: 2, Column: 3}), []Identifier{})

access := NewMappedAccess(e, Position{Offset: 0, Line: 0, Column: 0})
actual, err := json.Marshal(access)
require.NoError(t, err)

assert.JSONEq(t, `{
"EntitlementMap": {
"Type": "NominalType",
"Identifier": {
"Identifier": "E",
"StartPos": {"Offset": 1, "Line": 2, "Column": 3},
"EndPos": {"Offset": 1, "Line": 2, "Column": 3}
},
"StartPos": {"Offset": 1, "Line": 2, "Column": 3},
"EndPos": {"Offset": 1, "Line": 2, "Column": 3}
},
"EndPos": {"Offset": 1, "Line": 2, "Column": 3}
}`, string(actual))
}

func TestEntitlementAccess_MarshalJSON(t *testing.T) {

t.Parallel()
Expand Down
44 changes: 25 additions & 19 deletions runtime/ast/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"github.com/turbolent/prettier"

"github.com/onflow/cadence/runtime/common"
"github.com/onflow/cadence/runtime/errors"
)

const typeSeparatorSpaceDoc = prettier.Text(": ")
Expand Down Expand Up @@ -535,22 +536,17 @@
}

// ReferenceType

type Authorization struct {
EntitlementSet EntitlementSet `json:"EntitlementSet"`
}

type ReferenceType struct {
Type Type `json:"ReferencedType"`
StartPos Position `json:"-"`
Authorization *Authorization `json:"Authorization"`
Type Type `json:"ReferencedType"`
StartPos Position `json:"-"`
Authorization Authorization `json:"Authorization"`
}

var _ Type = &ReferenceType{}

func NewReferenceType(
memoryGauge common.MemoryGauge,
authorization *Authorization,
authorization Authorization,
typ Type,
startPos Position,
) *ReferenceType {
Expand All @@ -577,25 +573,35 @@
}

const referenceTypeAuthKeywordDoc = prettier.Text("auth")
const referenceTypeMappingKeywordDoc = prettier.Text("mapping ")
const referenceTypeSymbolDoc = prettier.Text("&")

func (t *ReferenceType) Doc() prettier.Doc {
var doc prettier.Concat
if t.Authorization != nil {
doc = append(doc, referenceTypeAuthKeywordDoc)
entitlementSet := t.Authorization.EntitlementSet
if entitlementSet != nil && len(entitlementSet.Entitlements()) > 0 {
entitlements := entitlementSet.Entitlements()
// TODO: add indentation, improve separators. follow e.g. ParameterList.Doc()
doc = append(doc, prettier.Text("("))
for i, entitlement := range entitlements {
doc = append(doc, entitlement.Doc())
if i < len(entitlements)-1 {
doc = append(doc, prettier.Text(entitlementSet.Separator().String()), prettier.Space)
doc = append(doc, prettier.Text("("))
switch authorization := t.Authorization.(type) {
case EntitlementSet:
if len(authorization.Entitlements()) > 0 {
entitlements := authorization.Entitlements()
// TODO: add indentation, improve separators. follow e.g. ParameterList.Doc()
for i, entitlement := range entitlements {
doc = append(doc, entitlement.Doc())
if i < len(entitlements)-1 {
doc = append(doc, prettier.Text(authorization.Separator().String()), prettier.Space)
}
}
}
doc = append(doc, prettier.Text(")"))
case *MappedAccess:
doc = append(doc,
referenceTypeMappingKeywordDoc,
authorization.EntitlementMap.Doc(),
)
dsainati1 marked this conversation as resolved.
Show resolved Hide resolved
default:
panic(errors.NewUnreachableError())

Check warning on line 602 in runtime/ast/type.go

View check run for this annotation

Codecov / codecov/patch

runtime/ast/type.go#L601-L602

Added lines #L601 - L602 were not covered by tests
}
doc = append(doc, prettier.Text(")"))
doc = append(doc, prettier.Space)
dsainati1 marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down
Loading
Loading