Skip to content

Commit

Permalink
add Type.contractName
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent committed Sep 3, 2024
1 parent 799a094 commit b36bae6
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 2 deletions.
39 changes: 37 additions & 2 deletions runtime/interpreter/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,8 @@ func (v TypeValue) Equal(_ *Interpreter, _ LocationRange, other Value) bool {
return staticType.Equal(otherStaticType)
}

func (v TypeValue) GetMember(interpreter *Interpreter, _ LocationRange, name string) Value {
switch name {
func (v TypeValue) GetMember(interpreter *Interpreter, _ LocationRange, memberName string) Value {
switch memberName {
case sema.MetaTypeIdentifierFieldName:
var typeID string
staticType := v.Type
Expand Down Expand Up @@ -485,6 +485,41 @@ func (v TypeValue) GetMember(interpreter *Interpreter, _ LocationRange, name str
addressValue,
)

case sema.MetaTypeContractNameFieldName:
staticType := v.Type
if staticType == nil {
return Nil
}

location, qualifiedIdentifier, err := common.DecodeTypeID(interpreter, string(staticType.ID()))
if err != nil || location == nil {
return Nil
}

switch location.(type) {
case common.AddressLocation,
common.StringLocation:

separatorIndex := strings.Index(qualifiedIdentifier, ".")
contractNameLength := len(qualifiedIdentifier)
if separatorIndex >= 0 {
contractNameLength = separatorIndex
}

contractNameValue := NewStringValue(
interpreter,
common.NewStringMemoryUsage(contractNameLength),
func() string {
return qualifiedIdentifier[0:contractNameLength]
},
)

return NewSomeValueNonCopying(interpreter, contractNameValue)

default:
return Nil
}

}

return nil
Expand Down
16 changes: 16 additions & 0 deletions runtime/sema/meta_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@ const metaTypeAddressFieldDocString = `
The address of the type, if it was declared in a contract deployed to an account
`

const MetaTypeContractNameFieldName = "contractName"

var MetaTypeContractNameFieldType = &OptionalType{
Type: StringType,
}

const metaTypeContractNameFieldDocString = `
The contract name of the type, if it was declared in a contract
`

func init() {
MetaType.Members = func(t *SimpleType) map[string]MemberResolver {
return MembersAsResolvers([]*Member{
Expand Down Expand Up @@ -106,6 +116,12 @@ func init() {
MetaTypeAddressFieldType,
metaTypeAddressFieldDocString,
),
NewUnmeteredPublicConstantFieldMember(
t,
MetaTypeContractNameFieldName,
MetaTypeContractNameFieldType,
metaTypeContractNameFieldDocString,
),
})
}
}
11 changes: 11 additions & 0 deletions runtime/tests/checker/metatype_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,14 @@ func TestCheckMetaTypeAddress(t *testing.T) {
`)
require.NoError(t, err)
}

func TestCheckMetaTypeContractName(t *testing.T) {

t.Parallel()

_, err := ParseAndCheck(t, `
let type: Type = Type<Int>()
let contractName: String = type.contractName!
`)
require.NoError(t, err)
}
187 changes: 187 additions & 0 deletions runtime/tests/interpreter/metatype_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1224,3 +1224,190 @@ func TestInterpretMetaTypeAddress(t *testing.T) {
)
})
}

func TestInterpretMetaTypeContractName(t *testing.T) {

t.Parallel()

t.Run("built-in", func(t *testing.T) {

t.Parallel()

inter := parseCheckAndInterpret(t, `
let type = Type<Int>()
let contractName = type.contractName
`)

AssertValuesEqual(
t,
inter,
interpreter.Nil,
inter.Globals.Get("contractName").GetValue(inter),
)
})

t.Run("address location", func(t *testing.T) {

t.Parallel()

inter := parseCheckAndInterpret(t, `
fun test(): String? {
let type = CompositeType("A.0000000000000001.X.Y")!
return type.contractName
}
`)

addressLocation := common.AddressLocation{
Address: common.MustBytesToAddress([]byte{0x1}),
Name: "X",
}

yType := &sema.CompositeType{
Location: addressLocation,
Kind: common.CompositeKindStructure,
Identifier: "Y",
}
xType := &sema.CompositeType{
Location: addressLocation,
Kind: common.CompositeKindContract,
Identifier: "X",
}
xType.SetNestedType("Y", yType)
yType.SetContainerType(xType)

inter.SharedState.Config.ImportLocationHandler =
func(_ *interpreter.Interpreter, _ common.Location) interpreter.Import {
elaboration := sema.NewElaboration(nil)
elaboration.SetCompositeType(
addressLocation.TypeID(nil, "X"),
xType,
)
elaboration.SetCompositeType(
addressLocation.TypeID(nil, "X.Y"),
yType,
)
return interpreter.VirtualImport{
Elaboration: elaboration,
}
}

result, err := inter.Invoke("test")
require.NoError(t, err)

AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredSomeValueNonCopying(
interpreter.NewUnmeteredStringValue("X"),
),
result,
)
})

t.Run("string location", func(t *testing.T) {

t.Parallel()

inter := parseCheckAndInterpret(t, `
fun test(): String? {
let type = CompositeType("S.test2.X.Y")!
return type.contractName
}
`)

stringLocation := common.StringLocation("test2")

yType := &sema.CompositeType{
Location: stringLocation,
Kind: common.CompositeKindStructure,
Identifier: "Y",
}
xType := &sema.CompositeType{
Location: stringLocation,
Kind: common.CompositeKindContract,
Identifier: "X",
}
xType.SetNestedType("Y", yType)
yType.SetContainerType(xType)

inter.SharedState.Config.ImportLocationHandler =
func(_ *interpreter.Interpreter, _ common.Location) interpreter.Import {
elaboration := sema.NewElaboration(nil)
elaboration.SetCompositeType(
stringLocation.TypeID(nil, "X"),
xType,
)
elaboration.SetCompositeType(
stringLocation.TypeID(nil, "X.Y"),
yType,
)
return interpreter.VirtualImport{
Elaboration: elaboration,
}
}

result, err := inter.Invoke("test")
require.NoError(t, err)

AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredSomeValueNonCopying(
interpreter.NewUnmeteredStringValue("X"),
),
result,
)
})

t.Run("unknown", func(t *testing.T) {

t.Parallel()

valueDeclarations := []stdlib.StandardLibraryValue{
{
Name: "unknownType",
Type: sema.MetaType,
Value: interpreter.TypeValue{
Type: nil,
},
Kind: common.DeclarationKindConstant,
},
}

baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation)
for _, valueDeclaration := range valueDeclarations {
baseValueActivation.DeclareValue(valueDeclaration)
}

baseActivation := activations.NewActivation(nil, interpreter.BaseActivation)
for _, valueDeclaration := range valueDeclarations {
interpreter.Declare(baseActivation, valueDeclaration)
}

inter, err := parseCheckAndInterpretWithOptions(t,
`
let contractName = unknownType.contractName
`,
ParseCheckAndInterpretOptions{
CheckerConfig: &sema.Config{
BaseValueActivationHandler: func(_ common.Location) *sema.VariableActivation {
return baseValueActivation
},
},
Config: &interpreter.Config{
BaseActivationHandler: func(_ common.Location) *interpreter.VariableActivation {
return baseActivation
},
},
},
)
require.NoError(t, err)

AssertValuesEqual(
t,
inter,
interpreter.Nil,
inter.Globals.Get("contractName").GetValue(inter),
)
})
}

0 comments on commit b36bae6

Please sign in to comment.