-
Notifications
You must be signed in to change notification settings - Fork 546
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1531 from xushiwei/typesutil
typesutil.ExprString
- Loading branch information
Showing
5 changed files
with
356 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright (c) 2023 The GoPlus Authors (goplus.org). All rights reserved. | ||
* | ||
* 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 typesutil | ||
|
||
import ( | ||
"go/types" | ||
|
||
"github.com/goplus/gop/ast" | ||
"github.com/goplus/gop/token" | ||
) | ||
|
||
// A CheckConfig specifies the configuration for type checking. | ||
// The zero value for Config is a ready-to-use default configuration. | ||
type CheckConfig types.Config | ||
|
||
// Check type-checks a package and returns the resulting package object and | ||
// the first error if any. Additionally, if info != nil, Check populates each | ||
// of the non-nil maps in the Info struct. | ||
// | ||
// The package is marked as complete if no errors occurred, otherwise it is | ||
// incomplete. See Config.Error for controlling behavior in the presence of | ||
// errors. | ||
// | ||
// The package is specified by a list of *ast.Files and corresponding | ||
// file set, and the package path the package is identified with. | ||
// The clean path must not be empty or dot ("."). | ||
func (conf *CheckConfig) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (ret *types.Package, err error) { | ||
ret = types.NewPackage(path, "") | ||
c := NewChecker((*types.Config)(conf), &Config{Types: ret, Fset: fset}, nil, info) | ||
err = c.Files(nil, files) | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
// Copyright 2013 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// This file implements printing of expressions. | ||
|
||
package typesutil | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
|
||
"github.com/goplus/gop/ast" | ||
"github.com/goplus/gop/x/typesutil/internal/typeparams" | ||
) | ||
|
||
// ExprString returns the (possibly shortened) string representation for x. | ||
// Shortened representations are suitable for user interfaces but may not | ||
// necessarily follow Go syntax. | ||
func ExprString(x ast.Expr) string { | ||
var buf bytes.Buffer | ||
WriteExpr(&buf, x) | ||
return buf.String() | ||
} | ||
|
||
// WriteExpr writes the (possibly shortened) string representation for x to buf. | ||
// Shortened representations are suitable for user interfaces but may not | ||
// necessarily follow Go syntax. | ||
func WriteExpr(buf *bytes.Buffer, x ast.Expr) { | ||
// The AST preserves source-level parentheses so there is | ||
// no need to introduce them here to correct for different | ||
// operator precedences. (This assumes that the AST was | ||
// generated by a Go parser.) | ||
|
||
switch x := x.(type) { | ||
default: | ||
fmt.Fprintf(buf, "(ast: %T)", x) // nil, ast.BadExpr, ast.KeyValueExpr | ||
|
||
case *ast.Ident: | ||
buf.WriteString(x.Name) | ||
|
||
case *ast.Ellipsis: | ||
buf.WriteString("...") | ||
if x.Elt != nil { | ||
WriteExpr(buf, x.Elt) | ||
} | ||
|
||
case *ast.BasicLit: | ||
buf.WriteString(x.Value) | ||
|
||
case *ast.FuncLit: | ||
buf.WriteByte('(') | ||
WriteExpr(buf, x.Type) | ||
buf.WriteString(" literal)") // shortened | ||
|
||
case *ast.CompositeLit: | ||
WriteExpr(buf, x.Type) | ||
buf.WriteByte('{') | ||
if len(x.Elts) > 0 { | ||
buf.WriteString("…") | ||
} | ||
buf.WriteByte('}') | ||
|
||
case *ast.ParenExpr: | ||
buf.WriteByte('(') | ||
WriteExpr(buf, x.X) | ||
buf.WriteByte(')') | ||
|
||
case *ast.SelectorExpr: | ||
WriteExpr(buf, x.X) | ||
buf.WriteByte('.') | ||
buf.WriteString(x.Sel.Name) | ||
|
||
case *ast.IndexExpr, *ast.IndexListExpr: | ||
ix := typeparams.UnpackIndexExpr(x) | ||
WriteExpr(buf, ix.X) | ||
buf.WriteByte('[') | ||
writeExprList(buf, ix.Indices) | ||
buf.WriteByte(']') | ||
|
||
case *ast.SliceExpr: | ||
WriteExpr(buf, x.X) | ||
buf.WriteByte('[') | ||
if x.Low != nil { | ||
WriteExpr(buf, x.Low) | ||
} | ||
buf.WriteByte(':') | ||
if x.High != nil { | ||
WriteExpr(buf, x.High) | ||
} | ||
if x.Slice3 { | ||
buf.WriteByte(':') | ||
if x.Max != nil { | ||
WriteExpr(buf, x.Max) | ||
} | ||
} | ||
buf.WriteByte(']') | ||
|
||
case *ast.TypeAssertExpr: | ||
WriteExpr(buf, x.X) | ||
buf.WriteString(".(") | ||
WriteExpr(buf, x.Type) | ||
buf.WriteByte(')') | ||
|
||
case *ast.CallExpr: | ||
WriteExpr(buf, x.Fun) | ||
buf.WriteByte('(') | ||
writeExprList(buf, x.Args) | ||
if x.Ellipsis.IsValid() { | ||
buf.WriteString("...") | ||
} | ||
buf.WriteByte(')') | ||
|
||
case *ast.StarExpr: | ||
buf.WriteByte('*') | ||
WriteExpr(buf, x.X) | ||
|
||
case *ast.UnaryExpr: | ||
buf.WriteString(x.Op.String()) | ||
WriteExpr(buf, x.X) | ||
|
||
case *ast.BinaryExpr: | ||
WriteExpr(buf, x.X) | ||
buf.WriteByte(' ') | ||
buf.WriteString(x.Op.String()) | ||
buf.WriteByte(' ') | ||
WriteExpr(buf, x.Y) | ||
|
||
case *ast.ArrayType: | ||
buf.WriteByte('[') | ||
if x.Len != nil { | ||
WriteExpr(buf, x.Len) | ||
} | ||
buf.WriteByte(']') | ||
WriteExpr(buf, x.Elt) | ||
|
||
case *ast.StructType: | ||
buf.WriteString("struct{") | ||
writeFieldList(buf, x.Fields.List, "; ", false) | ||
buf.WriteByte('}') | ||
|
||
case *ast.FuncType: | ||
buf.WriteString("func") | ||
writeSigExpr(buf, x) | ||
|
||
case *ast.InterfaceType: | ||
buf.WriteString("interface{") | ||
writeFieldList(buf, x.Methods.List, "; ", true) | ||
buf.WriteByte('}') | ||
|
||
case *ast.MapType: | ||
buf.WriteString("map[") | ||
WriteExpr(buf, x.Key) | ||
buf.WriteByte(']') | ||
WriteExpr(buf, x.Value) | ||
|
||
case *ast.ChanType: | ||
var s string | ||
switch x.Dir { | ||
case ast.SEND: | ||
s = "chan<- " | ||
case ast.RECV: | ||
s = "<-chan " | ||
default: | ||
s = "chan " | ||
} | ||
buf.WriteString(s) | ||
WriteExpr(buf, x.Value) | ||
} | ||
} | ||
|
||
func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) { | ||
buf.WriteByte('(') | ||
writeFieldList(buf, sig.Params.List, ", ", false) | ||
buf.WriteByte(')') | ||
|
||
res := sig.Results | ||
n := res.NumFields() | ||
if n == 0 { | ||
// no result | ||
return | ||
} | ||
|
||
buf.WriteByte(' ') | ||
if n == 1 && len(res.List[0].Names) == 0 { | ||
// single unnamed result | ||
WriteExpr(buf, res.List[0].Type) | ||
return | ||
} | ||
|
||
// multiple or named result(s) | ||
buf.WriteByte('(') | ||
writeFieldList(buf, res.List, ", ", false) | ||
buf.WriteByte(')') | ||
} | ||
|
||
func writeFieldList(buf *bytes.Buffer, list []*ast.Field, sep string, iface bool) { | ||
for i, f := range list { | ||
if i > 0 { | ||
buf.WriteString(sep) | ||
} | ||
|
||
// field list names | ||
writeIdentList(buf, f.Names) | ||
|
||
// types of interface methods consist of signatures only | ||
if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface { | ||
writeSigExpr(buf, sig) | ||
continue | ||
} | ||
|
||
// named fields are separated with a blank from the field type | ||
if len(f.Names) > 0 { | ||
buf.WriteByte(' ') | ||
} | ||
|
||
WriteExpr(buf, f.Type) | ||
|
||
// ignore tag | ||
} | ||
} | ||
|
||
func writeIdentList(buf *bytes.Buffer, list []*ast.Ident) { | ||
for i, x := range list { | ||
if i > 0 { | ||
buf.WriteString(", ") | ||
} | ||
buf.WriteString(x.Name) | ||
} | ||
} | ||
|
||
func writeExprList(buf *bytes.Buffer, list []ast.Expr) { | ||
for i, x := range list { | ||
if i > 0 { | ||
buf.WriteString(", ") | ||
} | ||
WriteExpr(buf, x) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright 2021 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package typeparams | ||
|
||
import ( | ||
"github.com/goplus/gop/ast" | ||
"github.com/goplus/gop/token" | ||
) | ||
|
||
func PackIndexExpr(x ast.Expr, lbrack token.Pos, exprs []ast.Expr, rbrack token.Pos) ast.Expr { | ||
switch len(exprs) { | ||
case 0: | ||
panic("internal error: PackIndexExpr with empty expr slice") | ||
case 1: | ||
return &ast.IndexExpr{ | ||
X: x, | ||
Lbrack: lbrack, | ||
Index: exprs[0], | ||
Rbrack: rbrack, | ||
} | ||
default: | ||
return &ast.IndexListExpr{ | ||
X: x, | ||
Lbrack: lbrack, | ||
Indices: exprs, | ||
Rbrack: rbrack, | ||
} | ||
} | ||
} | ||
|
||
// IndexExpr wraps an ast.IndexExpr or ast.IndexListExpr. | ||
// | ||
// Orig holds the original ast.Expr from which this IndexExpr was derived. | ||
type IndexExpr struct { | ||
Orig ast.Expr // the wrapped expr, which may be distinct from the IndexListExpr below. | ||
*ast.IndexListExpr | ||
} | ||
|
||
func UnpackIndexExpr(n ast.Node) *IndexExpr { | ||
switch e := n.(type) { | ||
case *ast.IndexExpr: | ||
return &IndexExpr{e, &ast.IndexListExpr{ | ||
X: e.X, | ||
Lbrack: e.Lbrack, | ||
Indices: []ast.Expr{e.Index}, | ||
Rbrack: e.Rbrack, | ||
}} | ||
case *ast.IndexListExpr: | ||
return &IndexExpr{e, e} | ||
} | ||
return nil | ||
} |