// Copyright 2025 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 astimport ()// A Directive is a comment of this form://// //tool:name args//// For example, this directive://// //go:generate stringer -type Op -trimprefix Op//// would have Tool "go", Name "generate", and Args "stringer -type Op// -trimprefix Op".//// While Args does not have a strict syntax, by convention it is a// space-separated sequence of unquoted words, '"'-quoted Go strings, or// '`'-quoted raw strings.//// See https://go.dev/doc/comment#directives for specification.typeDirectivestruct { Tool string Name string Args string// no leading or trailing whitespace// Slash is the position of the "//" at the beginning of the directive. Slash token.Pos// ArgsPos is the position where Args begins, based on the position passed // to ParseDirective. ArgsPos token.Pos}// ParseDirective parses a single comment line for a directive comment.//// If the line is not a directive comment, it returns false.//// The provided text must be a single line and should include the leading "//".// If the text does not start with "//", it returns false.//// The caller may provide a file position of the start of c. This will be used// to track the position of the arguments. This may be [Comment.Slash],// synthesized by the caller, or simply 0. If the caller passes 0, then the// positions are effectively byte offsets into the string c.func ( token.Pos, string) (Directive, bool) {// Fast path to eliminate most non-directive comments. Must be a line // comment starting with [a-z0-9]if !(len() >= 3 && [0] == '/' && [1] == '/' && isalnum([2])) {returnDirective{}, false } := directiveScanner{, } .skip(len("//"))// Check for a valid directive and parse tool part. // // This logic matches isDirective. (We could combine them, but isDirective // itself is duplicated in several places.) := strings.Index(.str, ":")if <= 0 || +1 >= len(.str) {returnDirective{}, false }for := 0; <= +1; ++ {if == {continue }if !isalnum(.str[]) {returnDirective{}, false } } := .take() .skip(len(":"))// Parse name and args. := .takeNonSpace() .skipSpace() := .pos := strings.TrimRightFunc(.str, unicode.IsSpace)returnDirective{, , , , }, true}func isalnum( byte) bool {return'a' <= && <= 'z' || '0' <= && <= '9'}func ( *Directive) () token.Pos { return .Slash }func ( *Directive) () token.Pos { returntoken.Pos(int(.ArgsPos) + len(.Args)) }// A DirectiveArg is an argument to a directive comment.typeDirectiveArgstruct {// Arg is the parsed argument string. If the argument was a quoted string, // this is its unquoted form. Arg string// Pos is the position of the first character in this argument. Pos token.Pos}// ParseArgs parses a [Directive]'s arguments using the standard convention,// which is a sequence of tokens, where each token may be a bare word, or a// double quoted Go string, or a back quoted raw Go string. Each token must be// separated by one or more Unicode spaces.//// If the arguments do not conform to this syntax, it returns an error.func ( *Directive) () ([]DirectiveArg, error) { := directiveScanner{.Args, .ArgsPos} := []DirectiveArg{}for .skipSpace(); .str != ""; .skipSpace() {varstring := .posswitch .str[0] {default: = .takeNonSpace()case'`', '"': , := strconv.QuotedPrefix(.str)if != nil { // Always strconv.ErrSyntaxreturnnil, fmt.Errorf("invalid quoted string in //%s:%s: %s", .Tool, .Name, .str) }// Any errors will have been returned by QuotedPrefix , _ = strconv.Unquote(.take(len()))// Check that the quoted string is followed by a space (or nothing)if .str != "" { , := utf8.DecodeRuneInString(.str)if !unicode.IsSpace() {returnnil, fmt.Errorf("invalid quoted string in //%s:%s: %s", .Tool, .Name, .str) } } } = append(, DirectiveArg{, }) }return , nil}// directiveScanner is a helper for parsing directive comments while maintaining// position information.type directiveScanner struct { str string pos token.Pos}func ( *directiveScanner) ( int) { .pos += token.Pos() .str = .str[:]}func ( *directiveScanner) ( int) string { := .str[:] .skip()return}func ( *directiveScanner) () string { := strings.IndexFunc(.str, unicode.IsSpace)if == -1 { = len(.str) }return .take()}func ( *directiveScanner) () { := strings.TrimLeftFunc(.str, unicode.IsSpace) .skip(len(.str) - len())}
The pages are generated with Goldsv0.8.3-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.