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 stringer #3594

Open
wants to merge 13 commits into
base: feature/string-templates
Choose a base branch
from
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe consider making this more type-safe by using a []common.TypeID instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to an InterfaceType for simplicity

}

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{}) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anything significantly different from VisitCompositeDeclaration? If the code generation is pretty much the same, maybe refactor it into a common function

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test case to sema/gen/testdata

compositeKind := decl.CompositeKind
switch compositeKind {
case common.CompositeKindStructure,
common.CompositeKindResource,
common.CompositeKindContract:
break
default:
panic(fmt.Sprintf("%s declarations are not supported", compositeKind.Name()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
panic(fmt.Sprintf("%s declarations are not supported", compositeKind.Name()))
panic(fmt.Sprintf("%s interface 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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// StructStringer,
// StructStringerType,

// }
//}

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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: Is there anything significantly different from the composite-related functions (compositeTypeExpr, compositeTypeLiteral)? If the code generation is pretty much the same, maybe refactor it into a common function


// 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