...

Source file src/pkg/cmd/compile/internal/gc/lex.go

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package gc
     6	
     7	import (
     8		"cmd/compile/internal/syntax"
     9		"cmd/internal/objabi"
    10		"cmd/internal/src"
    11		"fmt"
    12		"strings"
    13	)
    14	
    15	// lineno is the source position at the start of the most recently lexed token.
    16	// TODO(gri) rename and eventually remove
    17	var lineno src.XPos
    18	
    19	func makePos(base *src.PosBase, line, col uint) src.XPos {
    20		return Ctxt.PosTable.XPos(src.MakePos(base, line, col))
    21	}
    22	
    23	func isSpace(c rune) bool {
    24		return c == ' ' || c == '\t' || c == '\n' || c == '\r'
    25	}
    26	
    27	func isQuoted(s string) bool {
    28		return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"'
    29	}
    30	
    31	const (
    32		// Func pragmas.
    33		Nointerface    syntax.Pragma = 1 << iota
    34		Noescape                     // func parameters don't escape
    35		Norace                       // func must not have race detector annotations
    36		Nosplit                      // func should not execute on separate stack
    37		Noinline                     // func should not be inlined
    38		CgoUnsafeArgs                // treat a pointer to one arg as a pointer to them all
    39		UintptrEscapes               // pointers converted to uintptr escape
    40	
    41		// Runtime-only func pragmas.
    42		// See ../../../../runtime/README.md for detailed descriptions.
    43		Systemstack        // func must run on system stack
    44		Nowritebarrier     // emit compiler error instead of write barrier
    45		Nowritebarrierrec  // error on write barrier in this or recursive callees
    46		Yeswritebarrierrec // cancels Nowritebarrierrec in this function and callees
    47	
    48		// Runtime-only type pragmas
    49		NotInHeap // values of this type must not be heap allocated
    50	)
    51	
    52	func pragmaValue(verb string) syntax.Pragma {
    53		switch verb {
    54		case "go:nointerface":
    55			if objabi.Fieldtrack_enabled != 0 {
    56				return Nointerface
    57			}
    58		case "go:noescape":
    59			return Noescape
    60		case "go:norace":
    61			return Norace
    62		case "go:nosplit":
    63			return Nosplit
    64		case "go:noinline":
    65			return Noinline
    66		case "go:systemstack":
    67			return Systemstack
    68		case "go:nowritebarrier":
    69			return Nowritebarrier
    70		case "go:nowritebarrierrec":
    71			return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
    72		case "go:yeswritebarrierrec":
    73			return Yeswritebarrierrec
    74		case "go:cgo_unsafe_args":
    75			return CgoUnsafeArgs
    76		case "go:uintptrescapes":
    77			// For the next function declared in the file
    78			// any uintptr arguments may be pointer values
    79			// converted to uintptr. This directive
    80			// ensures that the referenced allocated
    81			// object, if any, is retained and not moved
    82			// until the call completes, even though from
    83			// the types alone it would appear that the
    84			// object is no longer needed during the
    85			// call. The conversion to uintptr must appear
    86			// in the argument list.
    87			// Used in syscall/dll_windows.go.
    88			return UintptrEscapes
    89		case "go:notinheap":
    90			return NotInHeap
    91		}
    92		return 0
    93	}
    94	
    95	// pragcgo is called concurrently if files are parsed concurrently.
    96	func (p *noder) pragcgo(pos syntax.Pos, text string) {
    97		f := pragmaFields(text)
    98	
    99		verb := strings.TrimPrefix(f[0], "go:")
   100		f[0] = verb
   101	
   102		switch verb {
   103		case "cgo_export_static", "cgo_export_dynamic":
   104			switch {
   105			case len(f) == 2 && !isQuoted(f[1]):
   106			case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
   107			default:
   108				p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf(`usage: //go:%s local [remote]`, verb)})
   109				return
   110			}
   111		case "cgo_import_dynamic":
   112			switch {
   113			case len(f) == 2 && !isQuoted(f[1]):
   114			case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
   115			case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]):
   116				f[3] = strings.Trim(f[3], `"`)
   117				if objabi.GOOS == "aix" && f[3] != "" {
   118					// On Aix, library pattern must be "lib.a/object.o"
   119					// or "lib.a/libname.so.X"
   120					n := strings.Split(f[3], "/")
   121					if len(n) != 2 || !strings.HasSuffix(n[0], ".a") || (!strings.HasSuffix(n[1], ".o") && !strings.Contains(n[1], ".so.")) {
   122						p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`})
   123						return
   124					}
   125				}
   126			default:
   127				p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`})
   128				return
   129			}
   130		case "cgo_import_static":
   131			switch {
   132			case len(f) == 2 && !isQuoted(f[1]):
   133			default:
   134				p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_static local`})
   135				return
   136			}
   137		case "cgo_dynamic_linker":
   138			switch {
   139			case len(f) == 2 && isQuoted(f[1]):
   140				f[1] = strings.Trim(f[1], `"`)
   141			default:
   142				p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_dynamic_linker "path"`})
   143				return
   144			}
   145		case "cgo_ldflag":
   146			switch {
   147			case len(f) == 2 && isQuoted(f[1]):
   148				f[1] = strings.Trim(f[1], `"`)
   149			default:
   150				p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_ldflag "arg"`})
   151				return
   152			}
   153		default:
   154			return
   155		}
   156		p.pragcgobuf = append(p.pragcgobuf, f)
   157	}
   158	
   159	// pragmaFields is similar to strings.FieldsFunc(s, isSpace)
   160	// but does not split when inside double quoted regions and always
   161	// splits before the start and after the end of a double quoted region.
   162	// pragmaFields does not recognize escaped quotes. If a quote in s is not
   163	// closed the part after the opening quote will not be returned as a field.
   164	func pragmaFields(s string) []string {
   165		var a []string
   166		inQuote := false
   167		fieldStart := -1 // Set to -1 when looking for start of field.
   168		for i, c := range s {
   169			switch {
   170			case c == '"':
   171				if inQuote {
   172					inQuote = false
   173					a = append(a, s[fieldStart:i+1])
   174					fieldStart = -1
   175				} else {
   176					inQuote = true
   177					if fieldStart >= 0 {
   178						a = append(a, s[fieldStart:i])
   179					}
   180					fieldStart = i
   181				}
   182			case !inQuote && isSpace(c):
   183				if fieldStart >= 0 {
   184					a = append(a, s[fieldStart:i])
   185					fieldStart = -1
   186				}
   187			default:
   188				if fieldStart == -1 {
   189					fieldStart = i
   190				}
   191			}
   192		}
   193		if !inQuote && fieldStart >= 0 { // Last field might end at the end of the string.
   194			a = append(a, s[fieldStart:])
   195		}
   196		return a
   197	}
   198	

View as plain text