Skip to content

Commit

Permalink
Merge pull request #2728 from onflow/bastian/fix-view-annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent authored Aug 17, 2023
2 parents 898264e + db2b4eb commit a9ff019
Show file tree
Hide file tree
Showing 10 changed files with 399 additions and 11 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ require (
github.com/k0kubun/pp v3.0.1+incompatible
github.com/k0kubun/pp/v3 v3.2.0
github.com/logrusorgru/aurora/v4 v4.0.0
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
)

require github.com/zeebo/xxh3 v1.0.2 // indirect
Expand All @@ -53,7 +54,6 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/sys v0.2.0 // indirect
golang.org/x/term v0.1.0 // indirect
Expand Down
45 changes: 45 additions & 0 deletions runtime/cmd/info/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# info

A command line tool that can show various information.

Available commands:

- `dump-builtin-types`: Dumps all built-in types and their members, including nested types:

```sh
$ go run ./runtime/cmd/info -nested -members dump-builtin-types
...
- PublicAccount
- let address: Address
- let availableBalance: UFix64
- let balance: UFix64
- let capabilities: PublicAccount.Capabilities
- let contracts: PublicAccount.Contracts
- fun forEachAttachment(_ f: fun(&AnyStructAttachment): Void): Void
- fun forEachPublic(_ function: fun(PublicPath, Type): Bool): Void
- view fun getType(): Type
- view fun isInstance(_ type: Type): Bool
- let keys: PublicAccount.Keys
- let publicPaths: [PublicPath]
- let storageCapacity: UInt64
- let storageUsed: UInt64
- PublicAccount.Capabilities
- view fun borrow<T: &Any>(_ path: PublicPath): T?
- fun forEachAttachment(_ f: fun(&AnyStructAttachment): Void): Void
- view fun get<T: &Any>(_ path: PublicPath): Capability<T>?
- view fun getType(): Type
- view fun isInstance(_ type: Type): Bool
...
```

- `dump-builtin-values`: Dumps all built-in values and their types

```sh
$ go run ./runtime/cmd/info -members dump-builtin-values
- view fun Address(_ value: Integer): Address
- view fun fromBytes(_ bytes: [UInt8]): Address
- view fun fromString(_ input: String): Address?
- view fun getType(): Type
- view fun isInstance(_ type: Type): Bool
...
```
296 changes: 296 additions & 0 deletions runtime/cmd/info/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
/*
* Cadence - The resource-oriented smart contract programming language
*
* Copyright Dapper Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package main

import (
"flag"
"fmt"

"golang.org/x/exp/slices"

"github.com/onflow/cadence/runtime/ast"
"github.com/onflow/cadence/runtime/common"
"github.com/onflow/cadence/runtime/errors"
"github.com/onflow/cadence/runtime/sema"
"github.com/onflow/cadence/runtime/stdlib"
"github.com/onflow/cadence/runtime/tests/checker"
)

type command struct {
help string
handler func()
}

var includeNested = flag.Bool("nested", false, "include nested")
var includeMembers = flag.Bool("members", false, "include members")

func main() {
flag.Parse()
args := flag.Args()

if len(args) == 0 {
printAvailableCommands()
return
}

commandName := args[0]

command, ok := commands[commandName]
if !ok {
fmt.Printf("Unknown command %s\n", commandName)
printAvailableCommands()
return
}

command.handler()
}

var commands = map[string]command{
"dump-builtin-types": {
help: "Dumps all built-in types",
handler: dumpBuiltinTypes,
},
"dump-builtin-values": {
help: "Dumps all built-in values",
handler: dumpBuiltinValues,
},
}

func dumpBuiltinTypes() {

allBaseSemaTypes := checker.AllBaseSemaTypes()

types := make([]sema.Type, 0, len(allBaseSemaTypes))

// Gather all types in a slice, then sort them
for _, ty := range allBaseSemaTypes { //nolint:maprange
types = append(types, ty)
}

if *includeNested {
stack := make([]sema.Type, len(types))
copy(stack, types)

for len(stack) > 0 {
lastIndex := len(stack) - 1
ty := stack[lastIndex]
stack[lastIndex] = nil
stack = stack[:lastIndex]

containerType, ok := ty.(sema.ContainerType)
if !ok {
continue
}

nestedTypes := containerType.GetNestedTypes()
if nestedTypes == nil {
continue
}

nestedTypes.Foreach(func(_ string, nestedType sema.Type) {
types = append(types, nestedType)
stack = append(stack, nestedType)
})
}
}

slices.SortFunc(
types,
func(a, b sema.Type) bool {
return a.QualifiedString() < b.QualifiedString()
},
)

for _, ty := range types {
id := ty.QualifiedString()
fmt.Printf("- %s\n", id)

if *includeMembers {
dumpTypeMembers(ty)
}
}
}

func dumpTypeMembers(ty sema.Type) {
type namedResolver struct {
name string
resolver sema.MemberResolver
}

resolversByName := ty.GetMembers()

namedResolvers := make([]namedResolver, 0, len(resolversByName))

// Gather all resolvers, then sort them
for name, resolver := range resolversByName { //nolint:maprange

namedResolvers = append(
namedResolvers,
namedResolver{
name: name,
resolver: resolver,
},
)
}

slices.SortFunc(
namedResolvers,
func(a, b namedResolver) bool {
return a.name < b.name
},
)

for _, namedResolver := range namedResolvers {
name := namedResolver.name
resolver := namedResolver.resolver

member := resolver.Resolve(nil, name, ast.EmptyRange, nil)
if member == nil {
continue
}

declarationKind := resolver.Kind

switch declarationKind {
case common.DeclarationKindFunction:
memberType := member.TypeAnnotation.Type
functionType, ok := memberType.(*sema.FunctionType)
if !ok {
panic(errors.NewUnexpectedError(
"function declaration with non-function type: %s: %s",
name,
memberType,
))
}

fmt.Printf(
" - %s\n",
functionType.NamedQualifiedString(name),
)

case common.DeclarationKindField:
fmt.Printf(
" - %s %s: %s\n",
member.VariableKind.Keyword(),
name,
member.TypeAnnotation.QualifiedString(),
)

default:
panic(errors.NewUnexpectedError("unsupported declaration kind: %s", declarationKind.Name()))
}
}
}

func dumpBuiltinValues() {

type valueType struct {
name string
ty sema.Type
}

allBaseSemaValueTypes := checker.AllBaseSemaValueTypes()
standardLibraryValues := stdlib.DefaultScriptStandardLibraryValues(nil)

valueTypes := make([]valueType, 0, len(allBaseSemaValueTypes)+len(standardLibraryValues))

// Gather all values, then sort them
for name, ty := range allBaseSemaValueTypes { //nolint:maprange
valueTypes = append(
valueTypes,
valueType{
name: name,
ty: ty,
},
)
}

for _, value := range standardLibraryValues {
valueTypes = append(
valueTypes,
valueType{
name: value.ValueDeclarationName(),
ty: value.ValueDeclarationType(),
},
)
}

slices.SortFunc(
valueTypes,
func(a, b valueType) bool {
return a.name < b.name
},
)

for _, valueType := range valueTypes {

name := valueType.name
ty := valueType.ty

if functionType, ok := ty.(*sema.FunctionType); ok {
fmt.Printf(
"- %s\n",
functionType.NamedQualifiedString(name),
)
} else {
fmt.Printf(
"- %s: %s\n",
name,
sema.NewTypeAnnotation(ty).QualifiedString(),
)
}

if *includeMembers {
dumpTypeMembers(ty)
}
}
}

func printAvailableCommands() {
type commandHelp struct {
name string
help string
}

commandHelps := make([]commandHelp, 0, len(commands))

// Gather all commands, then sort them
for name, command := range commands { //nolint:maprange
commandHelps = append(
commandHelps,
commandHelp{
name: name,
help: command.help,
},
)
}

slices.SortFunc(
commandHelps,
func(a, b commandHelp) bool {
return a.name < b.name
},
)

println("Available commands:")

for _, commandHelp := range commandHelps {
fmt.Printf(" %s\t%s\n", commandHelp.name, commandHelp.help)
}
}
6 changes: 3 additions & 3 deletions runtime/sema/character.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
access(all)
struct Character: Storable, Equatable, Comparable, Exportable, Importable {

/// The byte array of the UTF-8 encoding
/// The byte array of the UTF-8 encoding.
access(all)
let utf8: [UInt8]

/// Returns this character as a String
/// Returns this character as a String.
access(all)
fun toString(): String
view fun toString(): String
}
5 changes: 3 additions & 2 deletions runtime/sema/character.gen.go

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

Loading

0 comments on commit a9ff019

Please sign in to comment.