github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/cmd/compile/internal/gc/lex.go (about)

     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/obj"
    10  	"fmt"
    11  	"strings"
    12  )
    13  
    14  // lexlineno is the line number _after_ the most recently read rune.
    15  // In particular, it's advanced (or rewound) as newlines are read (or unread).
    16  var lexlineno int32
    17  
    18  // lineno is the line number at the start of the most recently lexed token.
    19  var lineno int32
    20  
    21  func isSpace(c rune) bool {
    22  	return c == ' ' || c == '\t' || c == '\n' || c == '\r'
    23  }
    24  
    25  func isQuoted(s string) bool {
    26  	return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"'
    27  }
    28  
    29  func plan9quote(s string) string {
    30  	if s == "" {
    31  		return "''"
    32  	}
    33  	for _, c := range s {
    34  		if c <= ' ' || c == '\'' {
    35  			return "'" + strings.Replace(s, "'", "''", -1) + "'"
    36  		}
    37  	}
    38  	return s
    39  }
    40  
    41  type Pragma syntax.Pragma
    42  
    43  const (
    44  	// Func pragmas.
    45  	Nointerface    Pragma = 1 << iota
    46  	Noescape              // func parameters don't escape
    47  	Norace                // func must not have race detector annotations
    48  	Nosplit               // func should not execute on separate stack
    49  	Noinline              // func should not be inlined
    50  	CgoUnsafeArgs         // treat a pointer to one arg as a pointer to them all
    51  	UintptrEscapes        // pointers converted to uintptr escape
    52  
    53  	// Runtime-only func pragmas.
    54  	// See ../../../../runtime/README.md for detailed descriptions.
    55  	Systemstack        // func must run on system stack
    56  	Nowritebarrier     // emit compiler error instead of write barrier
    57  	Nowritebarrierrec  // error on write barrier in this or recursive callees
    58  	Yeswritebarrierrec // cancels Nowritebarrierrec in this function and callees
    59  
    60  	// Runtime-only type pragmas
    61  	NotInHeap // values of this type must not be heap allocated
    62  )
    63  
    64  func pragmaValue(verb string) Pragma {
    65  	switch verb {
    66  	case "go:nointerface":
    67  		if obj.Fieldtrack_enabled != 0 {
    68  			return Nointerface
    69  		}
    70  	case "go:noescape":
    71  		return Noescape
    72  	case "go:norace":
    73  		return Norace
    74  	case "go:nosplit":
    75  		return Nosplit
    76  	case "go:noinline":
    77  		return Noinline
    78  	case "go:systemstack":
    79  		if !compiling_runtime {
    80  			yyerror("//go:systemstack only allowed in runtime")
    81  		}
    82  		return Systemstack
    83  	case "go:nowritebarrier":
    84  		if !compiling_runtime {
    85  			yyerror("//go:nowritebarrier only allowed in runtime")
    86  		}
    87  		return Nowritebarrier
    88  	case "go:nowritebarrierrec":
    89  		if !compiling_runtime {
    90  			yyerror("//go:nowritebarrierrec only allowed in runtime")
    91  		}
    92  		return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
    93  	case "go:yeswritebarrierrec":
    94  		if !compiling_runtime {
    95  			yyerror("//go:yeswritebarrierrec only allowed in runtime")
    96  		}
    97  		return Yeswritebarrierrec
    98  	case "go:cgo_unsafe_args":
    99  		return CgoUnsafeArgs
   100  	case "go:uintptrescapes":
   101  		// For the next function declared in the file
   102  		// any uintptr arguments may be pointer values
   103  		// converted to uintptr. This directive
   104  		// ensures that the referenced allocated
   105  		// object, if any, is retained and not moved
   106  		// until the call completes, even though from
   107  		// the types alone it would appear that the
   108  		// object is no longer needed during the
   109  		// call. The conversion to uintptr must appear
   110  		// in the argument list.
   111  		// Used in syscall/dll_windows.go.
   112  		return UintptrEscapes
   113  	case "go:notinheap":
   114  		return NotInHeap
   115  	}
   116  	return 0
   117  }
   118  
   119  var internedStrings = map[string]string{}
   120  
   121  func internString(b []byte) string {
   122  	s, ok := internedStrings[string(b)] // string(b) here doesn't allocate
   123  	if !ok {
   124  		s = string(b)
   125  		internedStrings[s] = s
   126  	}
   127  	return s
   128  }
   129  
   130  func pragcgo(text string) string {
   131  	f := pragmaFields(text)
   132  
   133  	verb := f[0][3:] // skip "go:"
   134  	switch verb {
   135  	case "cgo_export_static", "cgo_export_dynamic":
   136  		switch {
   137  		case len(f) == 2 && !isQuoted(f[1]):
   138  			local := plan9quote(f[1])
   139  			return fmt.Sprintln(verb, local)
   140  
   141  		case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
   142  			local := plan9quote(f[1])
   143  			remote := plan9quote(f[2])
   144  			return fmt.Sprintln(verb, local, remote)
   145  
   146  		default:
   147  			yyerror(`usage: //go:%s local [remote]`, verb)
   148  		}
   149  	case "cgo_import_dynamic":
   150  		switch {
   151  		case len(f) == 2 && !isQuoted(f[1]):
   152  			local := plan9quote(f[1])
   153  			return fmt.Sprintln(verb, local)
   154  
   155  		case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
   156  			local := plan9quote(f[1])
   157  			remote := plan9quote(f[2])
   158  			return fmt.Sprintln(verb, local, remote)
   159  
   160  		case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]):
   161  			local := plan9quote(f[1])
   162  			remote := plan9quote(f[2])
   163  			library := plan9quote(strings.Trim(f[3], `"`))
   164  			return fmt.Sprintln(verb, local, remote, library)
   165  
   166  		default:
   167  			yyerror(`usage: //go:cgo_import_dynamic local [remote ["library"]]`)
   168  		}
   169  	case "cgo_import_static":
   170  		switch {
   171  		case len(f) == 2 && !isQuoted(f[1]):
   172  			local := plan9quote(f[1])
   173  			return fmt.Sprintln(verb, local)
   174  
   175  		default:
   176  			yyerror(`usage: //go:cgo_import_static local`)
   177  		}
   178  	case "cgo_dynamic_linker":
   179  		switch {
   180  		case len(f) == 2 && isQuoted(f[1]):
   181  			path := plan9quote(strings.Trim(f[1], `"`))
   182  			return fmt.Sprintln(verb, path)
   183  
   184  		default:
   185  			yyerror(`usage: //go:cgo_dynamic_linker "path"`)
   186  		}
   187  	case "cgo_ldflag":
   188  		switch {
   189  		case len(f) == 2 && isQuoted(f[1]):
   190  			arg := plan9quote(strings.Trim(f[1], `"`))
   191  			return fmt.Sprintln(verb, arg)
   192  
   193  		default:
   194  			yyerror(`usage: //go:cgo_ldflag "arg"`)
   195  		}
   196  	}
   197  	return ""
   198  }
   199  
   200  // pragmaFields is similar to strings.FieldsFunc(s, isSpace)
   201  // but does not split when inside double quoted regions and always
   202  // splits before the start and after the end of a double quoted region.
   203  // pragmaFields does not recognize escaped quotes. If a quote in s is not
   204  // closed the part after the opening quote will not be returned as a field.
   205  func pragmaFields(s string) []string {
   206  	var a []string
   207  	inQuote := false
   208  	fieldStart := -1 // Set to -1 when looking for start of field.
   209  	for i, c := range s {
   210  		switch {
   211  		case c == '"':
   212  			if inQuote {
   213  				inQuote = false
   214  				a = append(a, s[fieldStart:i+1])
   215  				fieldStart = -1
   216  			} else {
   217  				inQuote = true
   218  				if fieldStart >= 0 {
   219  					a = append(a, s[fieldStart:i])
   220  				}
   221  				fieldStart = i
   222  			}
   223  		case !inQuote && isSpace(c):
   224  			if fieldStart >= 0 {
   225  				a = append(a, s[fieldStart:i])
   226  				fieldStart = -1
   227  			}
   228  		default:
   229  			if fieldStart == -1 {
   230  				fieldStart = i
   231  			}
   232  		}
   233  	}
   234  	if !inQuote && fieldStart >= 0 { // Last field might end at the end of the string.
   235  		a = append(a, s[fieldStart:])
   236  	}
   237  	return a
   238  }