Skip to content

Commit

Permalink
resolve comment
Browse files Browse the repository at this point in the history
  • Loading branch information
xzbdmw committed Dec 16, 2024
1 parent 1ff997d commit 9aadb46
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 75 deletions.
6 changes: 3 additions & 3 deletions gopls/internal/golang/highlight.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func Highlight(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, po
}
}
}
result, err := highlightPath(path, pgf.File, pkg.TypesInfo(), pos)
result, err := highlightPath(pkg.TypesInfo(), path, pos)
if err != nil {
return nil, err
}
Expand All @@ -71,9 +71,8 @@ func Highlight(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, po

// highlightPath returns ranges to highlight for the given enclosing path,
// which should be the result of astutil.PathEnclosingInterval.
func highlightPath(path []ast.Node, file *ast.File, info *types.Info, pos token.Pos) (map[posRange]protocol.DocumentHighlightKind, error) {
func highlightPath(info *types.Info, path []ast.Node, pos token.Pos) (map[posRange]protocol.DocumentHighlightKind, error) {
result := make(map[posRange]protocol.DocumentHighlightKind)

// Inside a printf-style call, printf("...%v...", arg)?
// Treat each corresponding ("%v", arg) pair as a highlight class.
for _, node := range path {
Expand All @@ -88,6 +87,7 @@ func highlightPath(path []ast.Node, file *ast.File, info *types.Info, pos token.
}
}

file := path[len(path)-1].(*ast.File)
switch node := path[0].(type) {
case *ast.BasicLit:
// Import path string literal?
Expand Down
142 changes: 70 additions & 72 deletions internal/fmtstr/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,67 @@
package fmtstr

import (
_ "embed"
"fmt"
"go/ast"
"go/constant"
"go/types"
"strconv"
"strings"
"unicode/utf8"
// "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
)

// FormatDirective holds the parsed representation of a printf directive such as "%3.*[4]d".
// It is constructed by [ParsePrintf].
type FormatDirective struct {
Format string // Full directive, e.g. "%[2]*.3d"
Range posRange // The range of Format within the overall format string
FirstArg int // Index of the first argument after the format string
Flags []byte // Formatting flags, e.g. ['-', '0']
Width *DirectiveSize // Width specifier, if any (e.g., '3' in '%3d')
Prec *DirectiveSize // Precision specifier, if any (e.g., '.4' in '%.4f')
Verb *DirectiveVerb // Verb specifier, if any (e.g., '[1]d' in '%[1]d')

// Parsing state (not used after parsing):
call *ast.CallExpr
argNum int
hasIndex bool
index int
indexPos int
indexPending bool
nbytes int
}

type SizeKind int

const (
Literal SizeKind = iota // A literal number, e.g. "4" in "%4d"
Asterisk // A dynamic size from an argument, e.g. "%*d"
IndexedAsterisk // A dynamic size with an explicit index, e.g. "%[2]*d"
)

// DirectiveSize describes a width or precision in a format directive.
// Depending on Kind, it may represent a literal number, a asterisk, or an indexed asterisk.
type DirectiveSize struct {
Kind SizeKind // Type of size specifier
Range posRange // Position of the size specifier within the directive
Size int // The literal size if Kind == Literal, otherwise -1
Index int // If Kind == IndexedAsterisk, the argument index used to obtain the size
ArgNum int // The argument position if Kind == Asterisk or IndexedAsterisk, relative to CallExpr.
}

// DirectiveVerb represents the verb character of a format directive (e.g., 'd', 's', 'f').
// It also includes positional information and any explicit argument indexing.
type DirectiveVerb struct {
Verb rune
Range posRange // The positional range of the verb in the format string
Index int // If the verb uses an indexed argument, this is the index, otherwise -1
ArgNum int // The argument position associated with this verb, relative to CallExpr.
}

type posRange struct {
Start, End int
}

// ParsePrintf takes a printf-like call expression,
// extracts the format string, and parses out all format directives. Each
// directive describes flags, width, precision, verb, and argument indexing.
Expand All @@ -28,7 +78,7 @@ import (
func ParsePrintf(info *types.Info, call *ast.CallExpr) ([]*FormatDirective, error) {
idx := FormatStringIndex(info, call)
if idx < 0 || idx >= len(call.Args) {
return nil, fmt.Errorf("%s", "can't parse")
return nil, fmt.Errorf("not a valid printf-like call")
}
format, ok := StringConstantExpr(info, call.Args[idx])
if !ok {
Expand Down Expand Up @@ -169,58 +219,6 @@ func StringConstantExpr(info *types.Info, expr ast.Expr) (string, bool) {
return "", false
}

// FormatDirective holds the parsed representation of a printf directive such as "%3.*[4]d".
// It is constructed by [ParsePrintf].
type FormatDirective struct {
Format string // Full directive, e.g. "%[2]*.3d"
Range posRange // The range of Format within the overall format string
FirstArg int // Index of the first argument after the format string
Flags []byte // Formatting flags, e.g. ['-', '0']
Width *DirectiveSize // Width specifier, if any (e.g., '3' in '%3d')
Prec *DirectiveSize // Precision specifier, if any (e.g., '.4' in '%.4f')
Verb *DirectiveVerb // Verb specifier, if any (e.g., '[1]d' in '%[1]d')

// Parsing state (not used after parsing):
call *ast.CallExpr
argNum int
hasIndex bool
index int
indexPos int
indexPending bool
nbytes int
}

type SizeKind int

const (
Literal SizeKind = iota // A literal number, e.g. "4" in "%4d"
Asterisk // A dynamic size from an argument, e.g. "%*d"
IndexedAsterisk // A dynamic size with an explicit index, e.g. "%[2]*d"
)

// DirectiveSize describes a width or precision in a format directive.
// Depending on Kind, it may represent a literal number, a asterisk, or an indexed asterisk.
type DirectiveSize struct {
Kind SizeKind // Type of size specifier
Range posRange // Position of the size specifier within the directive
Size int // The literal size if Kind == Literal, otherwise -1
Index int // If Kind == IndexedAsterisk, the argument index used to obtain the size
ArgNum int // The argument position if Kind == Asterisk or IndexedAsterisk, relative to CallExpr.
}

// DirectiveVerb represents the verb character of a format directive (e.g., 'd', 's', 'f').
// It also includes positional information and any explicit argument indexing.
type DirectiveVerb struct {
Verb rune
Range posRange // The positional range of the verb in the format string
Index int // If the verb uses an indexed argument, this is the index, otherwise -1
ArgNum int // The argument position associated with this verb, relative to CallExpr.
}

type posRange struct {
Start, End int
}

// addOffset adjusts the recorded positions in Verb, Width, Prec, and the
// directive's overall Range to be relative to the position in the full format string.
func (s *FormatDirective) addOffset(parsedLen int) {
Expand Down Expand Up @@ -254,23 +252,6 @@ func (s *FormatDirective) parseFlags() {
}
}

// scanNum advances through a decimal number if present, which represents a [Size] or [Index].
func (s *FormatDirective) scanNum() (int, bool) {
start := s.nbytes
for ; s.nbytes < len(s.Format); s.nbytes++ {
c := s.Format[s.nbytes]
if c < '0' || '9' < c {
if start < s.nbytes {
num, _ := strconv.ParseInt(s.Format[start:s.nbytes], 10, 32)
return int(num), true
} else {
return 0, false
}
}
}
return 0, false
}

// parseIndex parses an argument index of the form "[n]" that can appear
// in a printf directive (e.g., "%[2]d"). Returns an error if syntax is
// malformed or index is invalid.
Expand Down Expand Up @@ -310,6 +291,23 @@ func (s *FormatDirective) parseIndex() error {
return nil
}

// scanNum advances through a decimal number if present, which represents a [Size] or [Index].
func (s *FormatDirective) scanNum() (int, bool) {
start := s.nbytes
for ; s.nbytes < len(s.Format); s.nbytes++ {
c := s.Format[s.nbytes]
if c < '0' || '9' < c {
if start < s.nbytes {
num, _ := strconv.ParseInt(s.Format[start:s.nbytes], 10, 32)
return int(num), true
} else {
return 0, false
}
}
}
return 0, false
}

type sizeType int

const (
Expand Down

0 comments on commit 9aadb46

Please sign in to comment.