github.com/bir3/gocompiler@v0.9.2202/src/cmd/compile/internal/noder/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 noder 6 7 import ( 8 "fmt" 9 "github.com/bir3/gocompiler/src/internal/buildcfg" 10 "strings" 11 12 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 13 "github.com/bir3/gocompiler/src/cmd/compile/internal/syntax" 14 ) 15 16 func isSpace(c rune) bool { 17 return c == ' ' || c == '\t' || c == '\n' || c == '\r' 18 } 19 20 func isQuoted(s string) bool { 21 return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' 22 } 23 24 const ( 25 funcPragmas = ir.Nointerface | 26 ir.Noescape | 27 ir.Norace | 28 ir.Nosplit | 29 ir.Noinline | 30 ir.NoCheckPtr | 31 ir.RegisterParams | // TODO(register args) remove after register abi is working 32 ir.CgoUnsafeArgs | 33 ir.UintptrKeepAlive | 34 ir.UintptrEscapes | 35 ir.Systemstack | 36 ir.Nowritebarrier | 37 ir.Nowritebarrierrec | 38 ir.Yeswritebarrierrec 39 ) 40 41 func pragmaFlag(verb string) ir.PragmaFlag { 42 switch verb { 43 case "go:build": 44 return ir.GoBuildPragma 45 case "go:nointerface": 46 if buildcfg.Experiment.FieldTrack { 47 return ir.Nointerface 48 } 49 case "go:noescape": 50 return ir.Noescape 51 case "go:norace": 52 return ir.Norace 53 case "go:nosplit": 54 return ir.Nosplit | ir.NoCheckPtr // implies NoCheckPtr (see #34972) 55 case "go:noinline": 56 return ir.Noinline 57 case "go:nocheckptr": 58 return ir.NoCheckPtr 59 case "go:systemstack": 60 return ir.Systemstack 61 case "go:nowritebarrier": 62 return ir.Nowritebarrier 63 case "go:nowritebarrierrec": 64 return ir.Nowritebarrierrec | ir.Nowritebarrier // implies Nowritebarrier 65 case "go:yeswritebarrierrec": 66 return ir.Yeswritebarrierrec 67 case "go:cgo_unsafe_args": 68 return ir.CgoUnsafeArgs | ir.NoCheckPtr // implies NoCheckPtr (see #34968) 69 case "go:uintptrkeepalive": 70 return ir.UintptrKeepAlive 71 case "go:uintptrescapes": 72 // This directive extends //go:uintptrkeepalive by forcing 73 // uintptr arguments to escape to the heap, which makes stack 74 // growth safe. 75 return ir.UintptrEscapes | ir.UintptrKeepAlive // implies UintptrKeepAlive 76 case "go:registerparams": // TODO(register args) remove after register abi is working 77 return ir.RegisterParams 78 } 79 return 0 80 } 81 82 // pragcgo is called concurrently if files are parsed concurrently. 83 func (p *noder) pragcgo(pos syntax.Pos, text string) { 84 f := pragmaFields(text) 85 86 verb := strings.TrimPrefix(f[0], "go:") 87 f[0] = verb 88 89 switch verb { 90 case "cgo_export_static", "cgo_export_dynamic": 91 switch { 92 case len(f) == 2 && !isQuoted(f[1]): 93 case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]): 94 default: 95 p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf(`usage: //go:%s local [remote]`, verb)}) 96 return 97 } 98 case "cgo_import_dynamic": 99 switch { 100 case len(f) == 2 && !isQuoted(f[1]): 101 case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]): 102 case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]): 103 f[3] = strings.Trim(f[3], `"`) 104 if buildcfg.GOOS == "aix" && f[3] != "" { 105 // On Aix, library pattern must be "lib.a/object.o" 106 // or "lib.a/libname.so.X" 107 n := strings.Split(f[3], "/") 108 if len(n) != 2 || !strings.HasSuffix(n[0], ".a") || (!strings.HasSuffix(n[1], ".o") && !strings.Contains(n[1], ".so.")) { 109 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`}) 110 return 111 } 112 } 113 default: 114 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`}) 115 return 116 } 117 case "cgo_import_static": 118 switch { 119 case len(f) == 2 && !isQuoted(f[1]): 120 default: 121 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_static local`}) 122 return 123 } 124 case "cgo_dynamic_linker": 125 switch { 126 case len(f) == 2 && isQuoted(f[1]): 127 f[1] = strings.Trim(f[1], `"`) 128 default: 129 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_dynamic_linker "path"`}) 130 return 131 } 132 case "cgo_ldflag": 133 switch { 134 case len(f) == 2 && isQuoted(f[1]): 135 f[1] = strings.Trim(f[1], `"`) 136 default: 137 p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_ldflag "arg"`}) 138 return 139 } 140 default: 141 return 142 } 143 p.pragcgobuf = append(p.pragcgobuf, f) 144 } 145 146 // pragmaFields is similar to strings.FieldsFunc(s, isSpace) 147 // but does not split when inside double quoted regions and always 148 // splits before the start and after the end of a double quoted region. 149 // pragmaFields does not recognize escaped quotes. If a quote in s is not 150 // closed the part after the opening quote will not be returned as a field. 151 func pragmaFields(s string) []string { 152 var a []string 153 inQuote := false 154 fieldStart := -1 // Set to -1 when looking for start of field. 155 for i, c := range s { 156 switch { 157 case c == '"': 158 if inQuote { 159 inQuote = false 160 a = append(a, s[fieldStart:i+1]) 161 fieldStart = -1 162 } else { 163 inQuote = true 164 if fieldStart >= 0 { 165 a = append(a, s[fieldStart:i]) 166 } 167 fieldStart = i 168 } 169 case !inQuote && isSpace(c): 170 if fieldStart >= 0 { 171 a = append(a, s[fieldStart:i]) 172 fieldStart = -1 173 } 174 default: 175 if fieldStart == -1 { 176 fieldStart = i 177 } 178 } 179 } 180 if !inQuote && fieldStart >= 0 { // Last field might end at the end of the string. 181 a = append(a, s[fieldStart:]) 182 } 183 return a 184 }