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

Introduce StructStringer #3594

Merged
merged 17 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
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
4 changes: 4 additions & 0 deletions runtime/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4866,6 +4866,10 @@ func (interpreter *Interpreter) GetInterfaceType(
typeID TypeID,
) (*sema.InterfaceType, error) {
if location == nil {
var interfaceType = sema.NativeInterfaceTypes[qualifiedIdentifier]
if interfaceType != nil {
return interfaceType, nil
}
return nil, InterfaceMissingLocationError{
QualifiedIdentifier: qualifiedIdentifier,
}
Expand Down
3 changes: 3 additions & 0 deletions runtime/sema/bool_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ var BoolType = &SimpleType{
Comparable: true,
Exportable: true,
Importable: true,
conformances: []*InterfaceType{
StructStringerType,
},
}

var BoolTypeAnnotation = NewTypeAnnotation(BoolType)
2 changes: 1 addition & 1 deletion runtime/sema/character.cdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

access(all)
struct Character: Storable, Primitive, Equatable, Comparable, Exportable, Importable {
struct Character: Storable, Primitive, Equatable, Comparable, Exportable, Importable, StructStringer {

/// The byte array of the UTF-8 encoding.
access(all)
Expand Down
1 change: 1 addition & 0 deletions runtime/sema/character.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

269 changes: 267 additions & 2 deletions runtime/sema/gen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ type typeDecl struct {
memberDeclarations []ast.Declaration
nestedTypes []*typeDecl
hasConstructor bool

// used in simpleType generation
conformances []string
}

type generator struct {
Expand Down Expand Up @@ -572,6 +575,8 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
))
}
typeDecl.memberAccessible = true
case "StructStringer":
typeDecl.conformances = append(typeDecl.conformances, "StructStringerType")
}
}

Expand Down Expand Up @@ -736,8 +741,151 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
return
}

func (*generator) VisitInterfaceDeclaration(_ *ast.InterfaceDeclaration) struct{} {
panic("interface declarations are not supported")
func (g *generator) VisitInterfaceDeclaration(decl *ast.InterfaceDeclaration) (_ struct{}) {
compositeKind := decl.CompositeKind
switch compositeKind {
case common.CompositeKindStructure,
common.CompositeKindResource,
common.CompositeKindContract:
break
default:
panic(fmt.Sprintf("%s declarations are not supported", compositeKind.Name()))
}

typeName := decl.Identifier.Identifier

typeDecl := &typeDecl{
typeName: typeName,
fullTypeName: g.newFullTypeName(typeName),
compositeKind: compositeKind,
}

if len(g.typeStack) > 0 {
parentType := g.typeStack[len(g.typeStack)-1]
parentType.nestedTypes = append(
parentType.nestedTypes,
typeDecl,
)
}

g.typeStack = append(
g.typeStack,
typeDecl,
)
defer func() {
// Pop
lastIndex := len(g.typeStack) - 1
g.typeStack[lastIndex] = nil
g.typeStack = g.typeStack[:lastIndex]
}()

for _, memberDeclaration := range decl.Members.Declarations() {
generateDeclaration(g, memberDeclaration)

// Visiting unsupported declarations panics,
// so only supported member declarations are added
typeDecl.memberDeclarations = append(
typeDecl.memberDeclarations,
memberDeclaration,
)
}

var typeVarDecl = interfaceTypeExpr(typeDecl)

fullTypeName := typeDecl.fullTypeName

tyVarName := typeVarName(fullTypeName)

g.addDecls(
goConstDecl(
typeNameVarName(fullTypeName),
goStringLit(typeName),
),
goVarDecl(
tyVarName,
typeVarDecl,
),
)

memberDeclarations := typeDecl.memberDeclarations

if len(memberDeclarations) > 0 {

// func init() {
// members := []*Member{...}
// t.Members = MembersAsMap(members)
// t.Fields = MembersFieldNames(members)=
// }

members := membersExpr(
fullTypeName,
tyVarName,
memberDeclarations,
)

const membersVariableIdentifier = "members"

stmts := []dst.Stmt{
&dst.DeclStmt{
Decl: goVarDecl(
membersVariableIdentifier,
members,
),
},
&dst.AssignStmt{
Lhs: []dst.Expr{
&dst.SelectorExpr{
X: dst.NewIdent(tyVarName),
Sel: dst.NewIdent("Members"),
},
},
Tok: token.ASSIGN,
Rhs: []dst.Expr{
&dst.CallExpr{
Fun: &dst.Ident{
Name: "MembersAsMap",
Path: semaPath,
},
Args: []dst.Expr{
dst.NewIdent(membersVariableIdentifier),
},
},
},
},
&dst.AssignStmt{
Lhs: []dst.Expr{
&dst.SelectorExpr{
X: dst.NewIdent(tyVarName),
Sel: dst.NewIdent("Fields"),
},
},
Tok: token.ASSIGN,
Rhs: []dst.Expr{
&dst.CallExpr{
Fun: &dst.Ident{
Name: "MembersFieldNames",
Path: semaPath,
},
Args: []dst.Expr{
dst.NewIdent(membersVariableIdentifier),
},
},
},
},
}

g.addDecls(
&dst.FuncDecl{
Name: dst.NewIdent("init"),
Type: &dst.FuncType{},
Body: &dst.BlockStmt{
List: stmts,
},
},
)
}

return
}

func (*generator) VisitAttachmentDeclaration(_ *ast.AttachmentDeclaration) struct{} {
Expand Down Expand Up @@ -1591,6 +1739,9 @@ func simpleTypeLiteral(ty *typeDecl) dst.Expr {
// Comparable: false,
// Exportable: false,
// Importable: false,
// comformances: []*InterfaceType {
// StructStringer,
// }
//}

isResource := ty.compositeKind == common.CompositeKindResource
Expand All @@ -1609,6 +1760,26 @@ func simpleTypeLiteral(ty *typeDecl) dst.Expr {
goKeyValue("ContainFields", goBoolLit(ty.memberAccessible)),
}

if len(ty.conformances) > 0 {
var elts = []dst.Expr{}
for _, conformance := range ty.conformances {
elts = append(elts, &dst.Ident{
Name: conformance,
Path: semaPath,
})
}
elements = append(elements, goKeyValue("conformances", &dst.CompositeLit{
Type: &dst.ArrayType{
Elt: &dst.StarExpr{
X: &dst.Ident{
Name: "InterfaceType",
},
},
},
Elts: elts,
}))
}

return &dst.UnaryExpr{
Op: token.AND,
X: &dst.CompositeLit{
Expand Down Expand Up @@ -2069,6 +2240,100 @@ func compositeTypeLiteral(ty *typeDecl) dst.Expr {
}
}

func interfaceTypeExpr(ty *typeDecl) dst.Expr {

// func() *InterfaceType {
// var t = &InterfaceType{
// Identifier: FooTypeName,
// CompositeKind: common.CompositeKindStructure,
// }
//
// t.SetNestedType(FooBarTypeName, FooBarType)
// return t
// }()

const typeVarName = "t"

statements := []dst.Stmt{
&dst.DeclStmt{
Decl: goVarDecl(
typeVarName,
interfaceTypeLiteral(ty),
),
},
}

for _, nestedType := range ty.nestedTypes {
statements = append(
statements,
&dst.ExprStmt{
X: &dst.CallExpr{
Fun: &dst.SelectorExpr{
X: dst.NewIdent(typeVarName),
Sel: dst.NewIdent("SetNestedType"),
},
Args: []dst.Expr{
typeNameVarIdent(nestedType.fullTypeName),
typeVarIdent(nestedType.fullTypeName),
},
},
},
)
}

statements = append(
statements,
&dst.ReturnStmt{
Results: []dst.Expr{
dst.NewIdent(typeVarName),
},
},
)

return &dst.CallExpr{
Fun: &dst.FuncLit{
Type: &dst.FuncType{
Func: true,
Results: &dst.FieldList{
List: []*dst.Field{
{
Type: &dst.StarExpr{
X: &dst.Ident{
Name: "InterfaceType",
Path: semaPath,
},
},
},
},
},
},
Body: &dst.BlockStmt{
List: statements,
},
},
}
}

func interfaceTypeLiteral(ty *typeDecl) dst.Expr {
kind := compositeKindExpr(ty.compositeKind)

elements := []dst.Expr{
goKeyValue("Identifier", typeNameVarIdent(ty.fullTypeName)),
goKeyValue("CompositeKind", kind),
}

return &dst.UnaryExpr{
Op: token.AND,
X: &dst.CompositeLit{
Type: &dst.Ident{
Name: "InterfaceType",
Path: semaPath,
},
Elts: elements,
},
}
}

func typeAnnotationCallExpr(ty dst.Expr) *dst.CallExpr {
return &dst.CallExpr{
Fun: &dst.Ident{
Expand Down
15 changes: 15 additions & 0 deletions runtime/sema/path_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ var PathType = &SimpleType{
Comparable: false,
Exportable: true,
Importable: true,
conformances: []*InterfaceType{
StructStringerType,
},
}

var PathTypeAnnotation = NewTypeAnnotation(PathType)
Expand All @@ -48,6 +51,9 @@ var StoragePathType = &SimpleType{
Comparable: false,
Exportable: true,
Importable: true,
conformances: []*InterfaceType{
StructStringerType,
},
}

var StoragePathTypeAnnotation = NewTypeAnnotation(StoragePathType)
Expand All @@ -65,6 +71,9 @@ var CapabilityPathType = &SimpleType{
Comparable: false,
Exportable: true,
Importable: true,
conformances: []*InterfaceType{
StructStringerType,
},
}

var CapabilityPathTypeAnnotation = NewTypeAnnotation(CapabilityPathType)
Expand All @@ -82,6 +91,9 @@ var PublicPathType = &SimpleType{
Comparable: false,
Exportable: true,
Importable: true,
conformances: []*InterfaceType{
StructStringerType,
},
}

var PublicPathTypeAnnotation = NewTypeAnnotation(PublicPathType)
Expand All @@ -99,6 +111,9 @@ var PrivatePathType = &SimpleType{
Comparable: false,
Exportable: true,
Importable: true,
conformances: []*InterfaceType{
StructStringerType,
},
}

var PrivatePathTypeAnnotation = NewTypeAnnotation(PrivatePathType)
Loading
Loading