Skip to content

Commit

Permalink
Merge pull request #3594 from RZhang05/introduce-stringer
Browse files Browse the repository at this point in the history
Introduce StructStringer
  • Loading branch information
turbolent authored Oct 30, 2024
2 parents a185a42 + 58d7d66 commit 262de48
Show file tree
Hide file tree
Showing 17 changed files with 588 additions and 62 deletions.
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

0 comments on commit 262de48

Please sign in to comment.