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 all 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 interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4912,6 +4912,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 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 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 sema/character.gen.go

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

166 changes: 127 additions & 39 deletions 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 []*sema.InterfaceType
}

type generator struct {
Expand Down Expand Up @@ -429,9 +432,40 @@ func (g *generator) addConstructorDocStringDeclaration(
)
}

func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_ struct{}) {
func (g *generator) VisitCompositeOrInterfaceDeclaration(decl ast.ConformingDeclaration) (_ struct{}) {
var compositeKind common.CompositeKind
var typeName string
var typeDec *typeDecl
var members []ast.Declaration
var conformances []*ast.NominalType
var isInterfaceType bool

switch actualDecl := decl.(type) {
case *ast.CompositeDeclaration:
compositeKind = actualDecl.Kind()
typeName = actualDecl.Identifier.Identifier
typeDec = &typeDecl{
typeName: typeName,
fullTypeName: g.newFullTypeName(typeName),
compositeKind: compositeKind,
}
members = actualDecl.Members.Declarations()
conformances = actualDecl.Conformances
isInterfaceType = false
case *ast.InterfaceDeclaration:
compositeKind = actualDecl.Kind()
typeName = actualDecl.Identifier.Identifier
typeDec = &typeDecl{
typeName: typeName,
fullTypeName: g.newFullTypeName(typeName),
compositeKind: compositeKind,
}
members = actualDecl.Members.Declarations()
isInterfaceType = true
default:
panic("Expected composite or interface declaration")
}

compositeKind := decl.CompositeKind
switch compositeKind {
case common.CompositeKindStructure,
common.CompositeKindResource,
Expand All @@ -441,25 +475,17 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
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,
typeDec,
)
}

g.typeStack = append(
g.typeStack,
typeDecl,
typeDec,
)
defer func() {
// Pop
Expand All @@ -473,6 +499,8 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
// Check if the declaration is explicitly marked to be generated as a composite type.
if _, ok := g.leadingPragma["compositeType"]; ok {
generateSimpleType = false
} else if isInterfaceType {
generateSimpleType = false
} else {
// If not, decide what to generate depending on the type.

Expand All @@ -492,13 +520,13 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
}
}

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

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

Expand All @@ -514,7 +542,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
}
}

for _, conformance := range decl.Conformances {
for _, conformance := range conformances {
switch conformance.Identifier.Identifier {
case "Storable":
if !generateSimpleType {
Expand All @@ -523,7 +551,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
g.currentTypeID(),
))
}
typeDecl.storable = true
typeDec.storable = true

case "Primitive":
if !generateSimpleType {
Expand All @@ -532,7 +560,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
g.currentTypeID(),
))
}
typeDecl.primitive = true
typeDec.primitive = true

case "Equatable":
if !generateSimpleType {
Expand All @@ -541,7 +569,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
g.currentTypeID(),
))
}
typeDecl.equatable = true
typeDec.equatable = true

case "Comparable":
if !generateSimpleType {
Expand All @@ -550,7 +578,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
g.currentTypeID(),
))
}
typeDecl.comparable = true
typeDec.comparable = true

case "Exportable":
if !generateSimpleType {
Expand All @@ -559,10 +587,10 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
g.currentTypeID(),
))
}
typeDecl.exportable = true
typeDec.exportable = true

case "Importable":
typeDecl.importable = true
typeDec.importable = true

case "ContainFields":
if !generateSimpleType {
Expand All @@ -571,18 +599,20 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
g.currentTypeID(),
))
}
typeDecl.memberAccessible = true
typeDec.memberAccessible = true
case "StructStringer":
typeDec.conformances = append(typeDec.conformances, sema.StructStringerType)
}
}

var typeVarDecl dst.Expr
if generateSimpleType {
typeVarDecl = simpleTypeLiteral(typeDecl)
typeVarDecl = simpleTypeLiteral(typeDec)
} else {
typeVarDecl = compositeTypeExpr(typeDecl)
typeVarDecl = compositeOrInterfaceTypeExpr(typeDec, isInterfaceType)
}

fullTypeName := typeDecl.fullTypeName
fullTypeName := typeDec.fullTypeName

tyVarName := typeVarName(fullTypeName)

Expand All @@ -597,7 +627,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
),
)

memberDeclarations := typeDecl.memberDeclarations
memberDeclarations := typeDec.memberDeclarations

if len(memberDeclarations) > 0 {

Expand Down Expand Up @@ -700,7 +730,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
},
}

if typeDecl.hasConstructor {
if typeDec.hasConstructor {
stmts = append(
stmts,
&dst.AssignStmt{
Expand Down Expand Up @@ -736,8 +766,12 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
return
}

func (*generator) VisitInterfaceDeclaration(_ *ast.InterfaceDeclaration) struct{} {
panic("interface declarations are not supported")
func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_ struct{}) {
return g.VisitCompositeOrInterfaceDeclaration(decl)
}

func (g *generator) VisitInterfaceDeclaration(decl *ast.InterfaceDeclaration) (_ struct{}) {
return g.VisitCompositeOrInterfaceDeclaration(decl)
}

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

isResource := ty.compositeKind == common.CompositeKindResource
Expand All @@ -1609,6 +1646,33 @@ 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 {
var name = ""
switch conformance {
case sema.StructStringerType:
name = "StructStringerType"
default:
panic("Unsupported conformance typeID")
}
elts = append(elts, &dst.Ident{
Name: name,
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 @@ -1971,10 +2035,10 @@ func stringMemberResolverMapType() *dst.MapType {
}
}

func compositeTypeExpr(ty *typeDecl) dst.Expr {
func compositeOrInterfaceTypeExpr(ty *typeDecl, isInterfaceType bool) dst.Expr {

// func() *CompositeType {
// var t = &CompositeType{
// var t = &CompositeType {
// Identifier: FooTypeName,
// Kind: common.CompositeKindStructure,
// ImportableBuiltin: false,
Expand All @@ -1985,13 +2049,23 @@ func compositeTypeExpr(ty *typeDecl) dst.Expr {
// return t
// }()

// 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,
compositeTypeLiteral(ty),
compositeOrInterfaceTypeLiteral(ty, isInterfaceType),
),
},
}
Expand Down Expand Up @@ -2023,6 +2097,11 @@ func compositeTypeExpr(ty *typeDecl) dst.Expr {
},
)

name := "CompositeType"
if isInterfaceType {
name = "InterfaceType"
}

return &dst.CallExpr{
Fun: &dst.FuncLit{
Type: &dst.FuncType{
Expand All @@ -2032,7 +2111,7 @@ func compositeTypeExpr(ty *typeDecl) dst.Expr {
{
Type: &dst.StarExpr{
X: &dst.Ident{
Name: "CompositeType",
Name: name,
Path: semaPath,
},
},
Expand All @@ -2047,21 +2126,30 @@ func compositeTypeExpr(ty *typeDecl) dst.Expr {
}
}

func compositeTypeLiteral(ty *typeDecl) dst.Expr {
func compositeOrInterfaceTypeLiteral(ty *typeDecl, isInterfaceType bool) dst.Expr {
kind := compositeKindExpr(ty.compositeKind)

elements := []dst.Expr{
goKeyValue("Identifier", typeNameVarIdent(ty.fullTypeName)),
goKeyValue("Kind", kind),
goKeyValue("ImportableBuiltin", goBoolLit(ty.importable)),
goKeyValue("HasComputedMembers", goBoolLit(true)),
}

name := "InterfaceType"
if isInterfaceType {
elements = append(elements,
goKeyValue("CompositeKind", kind))
} else {
name = "CompositeType"
elements = append(elements,
goKeyValue("Kind", kind),
goKeyValue("ImportableBuiltin", goBoolLit(ty.importable)),
goKeyValue("HasComputedMembers", goBoolLit(true)))
}

return &dst.UnaryExpr{
Op: token.AND,
X: &dst.CompositeLit{
Type: &dst.Ident{
Name: "CompositeType",
Name: name,
Path: semaPath,
},
Elts: elements,
Expand Down
Loading
Loading