github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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/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 func plan9quote(s string) string { 32 if s == "" { 33 return "''" 34 } 35 for _, c := range s { 36 if c <= ' ' || c == '\'' { 37 return "'" + strings.Replace(s, "'", "''", -1) + "'" 38 } 39 } 40 return s 41 } 42 43 const ( 44 // Func pragmas. 45 Nointerface syntax.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) syntax.Pragma { 65 switch verb { 66 case "go:nointerface": 67 if objabi.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 return Systemstack 80 case "go:nowritebarrier": 81 return Nowritebarrier 82 case "go:nowritebarrierrec": 83 return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier 84 case "go:yeswritebarrierrec": 85 return Yeswritebarrierrec 86 case "go:cgo_unsafe_args": 87 return CgoUnsafeArgs 88 case "go:uintptrescapes": 89 // For the next function declared in the file 90 // any uintptr arguments may be pointer values 91 // converted to uintptr. This directive 92 // ensures that the referenced allocated 93 // object, if any, is retained and not moved 94 // until the call completes, even though from 95 // the types alone it would appear that the 96 // object is no longer needed during the 97 // call. The conversion to uintptr must appear 98 // in the argument list. 99 // Used in syscall/dll_windows.go. 100 return UintptrEscapes 101 case "go:notinheap": 102 return NotInHeap 103 } 104 return 0 105 } 106 107 // pragcgo is called concurrently if files are parsed concurrently. 108 func (p *noder) pragcgo(pos src.Pos, text string) string { 109 f := pragmaFields(text) 110 111 verb := f[0][3:] // skip "go:" 112 switch verb { 113 case "cgo_export_static", "cgo_export_dynamic": 114 switch { 115 case len(f) == 2 && !isQuoted(f[1]): 116 local := plan9quote(f[1]) 117 return fmt.Sprintln(verb, local) 118 119 case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]): 120 local := plan9quote(f[1]) 121 remote := plan9quote(f[2]) 122 return fmt.Sprintln(verb, local, remote) 123 124 default: 125 p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf(`usage: //go:%s local [remote]`, verb)}) 126 } 127 case "cgo_import_dynamic": 128 switch { 129 case len(f) == 2 && !isQuoted(f[1]): 130 local := plan9quote(f[1]) 131 return fmt.Sprintln(verb, local) 132 133 case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]): 134 local := plan9quote(f[1]) 135 remote := plan9quote(f[2]) 136 return fmt.Sprintln(verb, local, remote) 137 138 case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]): 139 local := plan9quote(f[1]) 140 remote := plan9quote(f[2]) 141 library := plan9quote(strings.Trim(f[3], `"`)) 142 return fmt.Sprintln(verb, local, remote, library) 143 144 default: 145 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`}) 146 } 147 case "cgo_import_static": 148 switch { 149 case len(f) == 2 && !isQuoted(f[1]): 150 local := plan9quote(f[1]) 151 return fmt.Sprintln(verb, local) 152 153 default: 154 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_static local`}) 155 } 156 case "cgo_dynamic_linker": 157 switch { 158 case len(f) == 2 && isQuoted(f[1]): 159 path := plan9quote(strings.Trim(f[1], `"`)) 160 return fmt.Sprintln(verb, path) 161 162 default: 163 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_dynamic_linker "path"`}) 164 } 165 case "cgo_ldflag": 166 switch { 167 case len(f) == 2 && isQuoted(f[1]): 168 arg := plan9quote(strings.Trim(f[1], `"`)) 169 return fmt.Sprintln(verb, arg) 170 171 default: 172 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_ldflag "arg"`}) 173 } 174 } 175 return "" 176 } 177 178 // pragmaFields is similar to strings.FieldsFunc(s, isSpace) 179 // but does not split when inside double quoted regions and always 180 // splits before the start and after the end of a double quoted region. 181 // pragmaFields does not recognize escaped quotes. If a quote in s is not 182 // closed the part after the opening quote will not be returned as a field. 183 func pragmaFields(s string) []string { 184 var a []string 185 inQuote := false 186 fieldStart := -1 // Set to -1 when looking for start of field. 187 for i, c := range s { 188 switch { 189 case c == '"': 190 if inQuote { 191 inQuote = false 192 a = append(a, s[fieldStart:i+1]) 193 fieldStart = -1 194 } else { 195 inQuote = true 196 if fieldStart >= 0 { 197 a = append(a, s[fieldStart:i]) 198 } 199 fieldStart = i 200 } 201 case !inQuote && isSpace(c): 202 if fieldStart >= 0 { 203 a = append(a, s[fieldStart:i]) 204 fieldStart = -1 205 } 206 default: 207 if fieldStart == -1 { 208 fieldStart = i 209 } 210 } 211 } 212 if !inQuote && fieldStart >= 0 { // Last field might end at the end of the string. 213 a = append(a, s[fieldStart:]) 214 } 215 return a 216 }