Skip to content

Commit 262de48

Browse files
authored
Merge pull request #3594 from RZhang05/introduce-stringer
Introduce StructStringer
2 parents a185a42 + 58d7d66 commit 262de48

17 files changed

+588
-62
lines changed

interpreter/interpreter.go

+4
Original file line numberDiff line numberDiff line change
@@ -4912,6 +4912,10 @@ func (interpreter *Interpreter) GetInterfaceType(
49124912
typeID TypeID,
49134913
) (*sema.InterfaceType, error) {
49144914
if location == nil {
4915+
var interfaceType = sema.NativeInterfaceTypes[qualifiedIdentifier]
4916+
if interfaceType != nil {
4917+
return interfaceType, nil
4918+
}
49154919
return nil, InterfaceMissingLocationError{
49164920
QualifiedIdentifier: qualifiedIdentifier,
49174921
}

sema/bool_type.go

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ var BoolType = &SimpleType{
3131
Comparable: true,
3232
Exportable: true,
3333
Importable: true,
34+
conformances: []*InterfaceType{
35+
StructStringerType,
36+
},
3437
}
3538

3639
var BoolTypeAnnotation = NewTypeAnnotation(BoolType)

sema/character.cdc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
access(all)
3-
struct Character: Storable, Primitive, Equatable, Comparable, Exportable, Importable {
3+
struct Character: Storable, Primitive, Equatable, Comparable, Exportable, Importable, StructStringer {
44

55
/// The byte array of the UTF-8 encoding.
66
access(all)

sema/character.gen.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sema/gen/main.go

+127-39
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ type typeDecl struct {
164164
memberDeclarations []ast.Declaration
165165
nestedTypes []*typeDecl
166166
hasConstructor bool
167+
168+
// used in simpleType generation
169+
conformances []*sema.InterfaceType
167170
}
168171

169172
type generator struct {
@@ -429,9 +432,40 @@ func (g *generator) addConstructorDocStringDeclaration(
429432
)
430433
}
431434

432-
func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_ struct{}) {
435+
func (g *generator) VisitCompositeOrInterfaceDeclaration(decl ast.ConformingDeclaration) (_ struct{}) {
436+
var compositeKind common.CompositeKind
437+
var typeName string
438+
var typeDec *typeDecl
439+
var members []ast.Declaration
440+
var conformances []*ast.NominalType
441+
var isInterfaceType bool
442+
443+
switch actualDecl := decl.(type) {
444+
case *ast.CompositeDeclaration:
445+
compositeKind = actualDecl.Kind()
446+
typeName = actualDecl.Identifier.Identifier
447+
typeDec = &typeDecl{
448+
typeName: typeName,
449+
fullTypeName: g.newFullTypeName(typeName),
450+
compositeKind: compositeKind,
451+
}
452+
members = actualDecl.Members.Declarations()
453+
conformances = actualDecl.Conformances
454+
isInterfaceType = false
455+
case *ast.InterfaceDeclaration:
456+
compositeKind = actualDecl.Kind()
457+
typeName = actualDecl.Identifier.Identifier
458+
typeDec = &typeDecl{
459+
typeName: typeName,
460+
fullTypeName: g.newFullTypeName(typeName),
461+
compositeKind: compositeKind,
462+
}
463+
members = actualDecl.Members.Declarations()
464+
isInterfaceType = true
465+
default:
466+
panic("Expected composite or interface declaration")
467+
}
433468

434-
compositeKind := decl.CompositeKind
435469
switch compositeKind {
436470
case common.CompositeKindStructure,
437471
common.CompositeKindResource,
@@ -441,25 +475,17 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
441475
panic(fmt.Sprintf("%s declarations are not supported", compositeKind.Name()))
442476
}
443477

444-
typeName := decl.Identifier.Identifier
445-
446-
typeDecl := &typeDecl{
447-
typeName: typeName,
448-
fullTypeName: g.newFullTypeName(typeName),
449-
compositeKind: compositeKind,
450-
}
451-
452478
if len(g.typeStack) > 0 {
453479
parentType := g.typeStack[len(g.typeStack)-1]
454480
parentType.nestedTypes = append(
455481
parentType.nestedTypes,
456-
typeDecl,
482+
typeDec,
457483
)
458484
}
459485

460486
g.typeStack = append(
461487
g.typeStack,
462-
typeDecl,
488+
typeDec,
463489
)
464490
defer func() {
465491
// Pop
@@ -473,6 +499,8 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
473499
// Check if the declaration is explicitly marked to be generated as a composite type.
474500
if _, ok := g.leadingPragma["compositeType"]; ok {
475501
generateSimpleType = false
502+
} else if isInterfaceType {
503+
generateSimpleType = false
476504
} else {
477505
// If not, decide what to generate depending on the type.
478506

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

495-
for _, memberDeclaration := range decl.Members.Declarations() {
523+
for _, memberDeclaration := range members {
496524
generateDeclaration(g, memberDeclaration)
497525

498526
// Visiting unsupported declarations panics,
499527
// so only supported member declarations are added
500-
typeDecl.memberDeclarations = append(
501-
typeDecl.memberDeclarations,
528+
typeDec.memberDeclarations = append(
529+
typeDec.memberDeclarations,
502530
memberDeclaration,
503531
)
504532

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

517-
for _, conformance := range decl.Conformances {
545+
for _, conformance := range conformances {
518546
switch conformance.Identifier.Identifier {
519547
case "Storable":
520548
if !generateSimpleType {
@@ -523,7 +551,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
523551
g.currentTypeID(),
524552
))
525553
}
526-
typeDecl.storable = true
554+
typeDec.storable = true
527555

528556
case "Primitive":
529557
if !generateSimpleType {
@@ -532,7 +560,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
532560
g.currentTypeID(),
533561
))
534562
}
535-
typeDecl.primitive = true
563+
typeDec.primitive = true
536564

537565
case "Equatable":
538566
if !generateSimpleType {
@@ -541,7 +569,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
541569
g.currentTypeID(),
542570
))
543571
}
544-
typeDecl.equatable = true
572+
typeDec.equatable = true
545573

546574
case "Comparable":
547575
if !generateSimpleType {
@@ -550,7 +578,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
550578
g.currentTypeID(),
551579
))
552580
}
553-
typeDecl.comparable = true
581+
typeDec.comparable = true
554582

555583
case "Exportable":
556584
if !generateSimpleType {
@@ -559,10 +587,10 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
559587
g.currentTypeID(),
560588
))
561589
}
562-
typeDecl.exportable = true
590+
typeDec.exportable = true
563591

564592
case "Importable":
565-
typeDecl.importable = true
593+
typeDec.importable = true
566594

567595
case "ContainFields":
568596
if !generateSimpleType {
@@ -571,18 +599,20 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
571599
g.currentTypeID(),
572600
))
573601
}
574-
typeDecl.memberAccessible = true
602+
typeDec.memberAccessible = true
603+
case "StructStringer":
604+
typeDec.conformances = append(typeDec.conformances, sema.StructStringerType)
575605
}
576606
}
577607

578608
var typeVarDecl dst.Expr
579609
if generateSimpleType {
580-
typeVarDecl = simpleTypeLiteral(typeDecl)
610+
typeVarDecl = simpleTypeLiteral(typeDec)
581611
} else {
582-
typeVarDecl = compositeTypeExpr(typeDecl)
612+
typeVarDecl = compositeOrInterfaceTypeExpr(typeDec, isInterfaceType)
583613
}
584614

585-
fullTypeName := typeDecl.fullTypeName
615+
fullTypeName := typeDec.fullTypeName
586616

587617
tyVarName := typeVarName(fullTypeName)
588618

@@ -597,7 +627,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
597627
),
598628
)
599629

600-
memberDeclarations := typeDecl.memberDeclarations
630+
memberDeclarations := typeDec.memberDeclarations
601631

602632
if len(memberDeclarations) > 0 {
603633

@@ -700,7 +730,7 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
700730
},
701731
}
702732

703-
if typeDecl.hasConstructor {
733+
if typeDec.hasConstructor {
704734
stmts = append(
705735
stmts,
706736
&dst.AssignStmt{
@@ -736,8 +766,12 @@ func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_
736766
return
737767
}
738768

739-
func (*generator) VisitInterfaceDeclaration(_ *ast.InterfaceDeclaration) struct{} {
740-
panic("interface declarations are not supported")
769+
func (g *generator) VisitCompositeDeclaration(decl *ast.CompositeDeclaration) (_ struct{}) {
770+
return g.VisitCompositeOrInterfaceDeclaration(decl)
771+
}
772+
773+
func (g *generator) VisitInterfaceDeclaration(decl *ast.InterfaceDeclaration) (_ struct{}) {
774+
return g.VisitCompositeOrInterfaceDeclaration(decl)
741775
}
742776

743777
func (*generator) VisitAttachmentDeclaration(_ *ast.AttachmentDeclaration) struct{} {
@@ -1591,6 +1625,9 @@ func simpleTypeLiteral(ty *typeDecl) dst.Expr {
15911625
// Comparable: false,
15921626
// Exportable: false,
15931627
// Importable: false,
1628+
// comformances: []*InterfaceType {
1629+
// StructStringerType,
1630+
// }
15941631
//}
15951632

15961633
isResource := ty.compositeKind == common.CompositeKindResource
@@ -1609,6 +1646,33 @@ func simpleTypeLiteral(ty *typeDecl) dst.Expr {
16091646
goKeyValue("ContainFields", goBoolLit(ty.memberAccessible)),
16101647
}
16111648

1649+
if len(ty.conformances) > 0 {
1650+
var elts = []dst.Expr{}
1651+
for _, conformance := range ty.conformances {
1652+
var name = ""
1653+
switch conformance {
1654+
case sema.StructStringerType:
1655+
name = "StructStringerType"
1656+
default:
1657+
panic("Unsupported conformance typeID")
1658+
}
1659+
elts = append(elts, &dst.Ident{
1660+
Name: name,
1661+
Path: semaPath,
1662+
})
1663+
}
1664+
elements = append(elements, goKeyValue("conformances", &dst.CompositeLit{
1665+
Type: &dst.ArrayType{
1666+
Elt: &dst.StarExpr{
1667+
X: &dst.Ident{
1668+
Name: "InterfaceType",
1669+
},
1670+
},
1671+
},
1672+
Elts: elts,
1673+
}))
1674+
}
1675+
16121676
return &dst.UnaryExpr{
16131677
Op: token.AND,
16141678
X: &dst.CompositeLit{
@@ -1971,10 +2035,10 @@ func stringMemberResolverMapType() *dst.MapType {
19712035
}
19722036
}
19732037

1974-
func compositeTypeExpr(ty *typeDecl) dst.Expr {
2038+
func compositeOrInterfaceTypeExpr(ty *typeDecl, isInterfaceType bool) dst.Expr {
19752039

19762040
// func() *CompositeType {
1977-
// var t = &CompositeType{
2041+
// var t = &CompositeType {
19782042
// Identifier: FooTypeName,
19792043
// Kind: common.CompositeKindStructure,
19802044
// ImportableBuiltin: false,
@@ -1985,13 +2049,23 @@ func compositeTypeExpr(ty *typeDecl) dst.Expr {
19852049
// return t
19862050
// }()
19872051

2052+
// func() *InterfaceType {
2053+
// var t = &InterfaceType{
2054+
// Identifier: FooTypeName,
2055+
// CompositeKind: common.CompositeKindStructure,
2056+
// }
2057+
//
2058+
// t.SetNestedType(FooBarTypeName, FooBarType)
2059+
// return t
2060+
// }()
2061+
19882062
const typeVarName = "t"
19892063

19902064
statements := []dst.Stmt{
19912065
&dst.DeclStmt{
19922066
Decl: goVarDecl(
19932067
typeVarName,
1994-
compositeTypeLiteral(ty),
2068+
compositeOrInterfaceTypeLiteral(ty, isInterfaceType),
19952069
),
19962070
},
19972071
}
@@ -2023,6 +2097,11 @@ func compositeTypeExpr(ty *typeDecl) dst.Expr {
20232097
},
20242098
)
20252099

2100+
name := "CompositeType"
2101+
if isInterfaceType {
2102+
name = "InterfaceType"
2103+
}
2104+
20262105
return &dst.CallExpr{
20272106
Fun: &dst.FuncLit{
20282107
Type: &dst.FuncType{
@@ -2032,7 +2111,7 @@ func compositeTypeExpr(ty *typeDecl) dst.Expr {
20322111
{
20332112
Type: &dst.StarExpr{
20342113
X: &dst.Ident{
2035-
Name: "CompositeType",
2114+
Name: name,
20362115
Path: semaPath,
20372116
},
20382117
},
@@ -2047,21 +2126,30 @@ func compositeTypeExpr(ty *typeDecl) dst.Expr {
20472126
}
20482127
}
20492128

2050-
func compositeTypeLiteral(ty *typeDecl) dst.Expr {
2129+
func compositeOrInterfaceTypeLiteral(ty *typeDecl, isInterfaceType bool) dst.Expr {
20512130
kind := compositeKindExpr(ty.compositeKind)
20522131

20532132
elements := []dst.Expr{
20542133
goKeyValue("Identifier", typeNameVarIdent(ty.fullTypeName)),
2055-
goKeyValue("Kind", kind),
2056-
goKeyValue("ImportableBuiltin", goBoolLit(ty.importable)),
2057-
goKeyValue("HasComputedMembers", goBoolLit(true)),
2134+
}
2135+
2136+
name := "InterfaceType"
2137+
if isInterfaceType {
2138+
elements = append(elements,
2139+
goKeyValue("CompositeKind", kind))
2140+
} else {
2141+
name = "CompositeType"
2142+
elements = append(elements,
2143+
goKeyValue("Kind", kind),
2144+
goKeyValue("ImportableBuiltin", goBoolLit(ty.importable)),
2145+
goKeyValue("HasComputedMembers", goBoolLit(true)))
20582146
}
20592147

20602148
return &dst.UnaryExpr{
20612149
Op: token.AND,
20622150
X: &dst.CompositeLit{
20632151
Type: &dst.Ident{
2064-
Name: "CompositeType",
2152+
Name: name,
20652153
Path: semaPath,
20662154
},
20672155
Elts: elements,

0 commit comments

Comments
 (0)