]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/gc/lex.go
[dev.ssa] Merge remote-tracking branch 'origin/master' into ssamerge
[gostls13.git] / src / 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 //go:generate go run mkbuiltin.go
6
7 package gc
8
9 import (
10         "cmd/compile/internal/ssa"
11         "cmd/internal/obj"
12         "flag"
13         "fmt"
14         "io"
15         "log"
16         "os"
17         "path"
18         "strconv"
19         "strings"
20         "unicode"
21         "unicode/utf8"
22 )
23
24 var imported_unsafe bool
25
26 var (
27         goos    string
28         goarch  string
29         goroot  string
30         buildid string
31 )
32
33 var (
34         Debug_append int
35         Debug_panic  int
36         Debug_slice  int
37         Debug_wb     int
38 )
39
40 const BOM = 0xFEFF
41
42 // Debug arguments.
43 // These can be specified with the -d flag, as in "-d nil"
44 // to set the debug_checknil variable. In general the list passed
45 // to -d can be comma-separated.
46 var debugtab = []struct {
47         name string
48         val  *int
49 }{
50         {"append", &Debug_append},         // print information about append compilation
51         {"disablenil", &Disable_checknil}, // disable nil checks
52         {"gcprog", &Debug_gcprog},         // print dump of GC programs
53         {"nil", &Debug_checknil},          // print information about nil checks
54         {"panic", &Debug_panic},           // do not hide any compiler panic
55         {"slice", &Debug_slice},           // print information about slice compilation
56         {"typeassert", &Debug_typeassert}, // print information about type assertion inlining
57         {"wb", &Debug_wb},                 // print information about write barriers
58         {"export", &Debug_export},         // print export data
59 }
60
61 const (
62         EOF = -1
63 )
64
65 func usage() {
66         fmt.Printf("usage: compile [options] file.go...\n")
67         obj.Flagprint(1)
68         Exit(2)
69 }
70
71 func hidePanic() {
72         if Debug_panic == 0 && nsavederrors+nerrors > 0 {
73                 // If we've already complained about things
74                 // in the program, don't bother complaining
75                 // about a panic too; let the user clean up
76                 // the code and try again.
77                 if err := recover(); err != nil {
78                         errorexit()
79                 }
80         }
81 }
82
83 func doversion() {
84         p := obj.Expstring()
85         if p == "X:none" {
86                 p = ""
87         }
88         sep := ""
89         if p != "" {
90                 sep = " "
91         }
92         fmt.Printf("compile version %s%s%s\n", obj.Getgoversion(), sep, p)
93         os.Exit(0)
94 }
95
96 func Main() {
97         defer hidePanic()
98
99         // Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix,
100         // but not other values.
101         p := obj.Getgoarch()
102
103         if !strings.HasPrefix(p, Thearch.Thestring) {
104                 log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.Thechar, p)
105         }
106         goarch = p
107
108         Thearch.Linkarchinit()
109         Ctxt = obj.Linknew(Thearch.Thelinkarch)
110         Ctxt.DiagFunc = Yyerror
111         Ctxt.Bso = &bstdout
112         bstdout = *obj.Binitw(os.Stdout)
113
114         localpkg = mkpkg("")
115         localpkg.Prefix = "\"\""
116
117         // pseudo-package, for scoping
118         builtinpkg = mkpkg("go.builtin")
119
120         builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
121
122         // pseudo-package, accessed by import "unsafe"
123         unsafepkg = mkpkg("unsafe")
124
125         unsafepkg.Name = "unsafe"
126
127         // real package, referred to by generated runtime calls
128         Runtimepkg = mkpkg("runtime")
129
130         Runtimepkg.Name = "runtime"
131
132         // pseudo-packages used in symbol tables
133         gostringpkg = mkpkg("go.string")
134
135         gostringpkg.Name = "go.string"
136         gostringpkg.Prefix = "go.string" // not go%2estring
137
138         itabpkg = mkpkg("go.itab")
139
140         itabpkg.Name = "go.itab"
141         itabpkg.Prefix = "go.itab" // not go%2eitab
142
143         weaktypepkg = mkpkg("go.weak.type")
144
145         weaktypepkg.Name = "go.weak.type"
146         weaktypepkg.Prefix = "go.weak.type" // not go%2eweak%2etype
147
148         typelinkpkg = mkpkg("go.typelink")
149         typelinkpkg.Name = "go.typelink"
150         typelinkpkg.Prefix = "go.typelink" // not go%2etypelink
151
152         trackpkg = mkpkg("go.track")
153
154         trackpkg.Name = "go.track"
155         trackpkg.Prefix = "go.track" // not go%2etrack
156
157         typepkg = mkpkg("type")
158
159         typepkg.Name = "type"
160
161         goroot = obj.Getgoroot()
162         goos = obj.Getgoos()
163
164         Nacl = goos == "nacl"
165         if Nacl {
166                 flag_largemodel = 1
167         }
168
169         outfile = ""
170         obj.Flagcount("+", "compiling runtime", &compiling_runtime)
171         obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
172         obj.Flagcount("A", "for bootstrapping, allow 'any' type", &Debug['A'])
173         obj.Flagcount("B", "disable bounds checking", &Debug['B'])
174         obj.Flagstr("D", "set relative `path` for local imports", &localimport)
175         obj.Flagcount("E", "debug symbol export", &Debug['E'])
176         obj.Flagfn1("I", "add `directory` to import search path", addidir)
177         obj.Flagcount("K", "debug missing line numbers", &Debug['K'])
178         obj.Flagcount("L", "use full (long) path in error messages", &Debug['L'])
179         obj.Flagcount("M", "debug move generation", &Debug['M'])
180         obj.Flagcount("N", "disable optimizations", &Debug['N'])
181         obj.Flagcount("P", "debug peephole optimizer", &Debug['P'])
182         obj.Flagcount("R", "debug register optimizer", &Debug['R'])
183         obj.Flagcount("S", "print assembly listing", &Debug['S'])
184         obj.Flagfn0("V", "print compiler version", doversion)
185         obj.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
186         obj.Flagstr("asmhdr", "write assembly header to `file`", &asmhdr)
187         obj.Flagstr("buildid", "record `id` as the build id in the export metadata", &buildid)
188         obj.Flagcount("complete", "compiling complete package (no C or assembly)", &pure_go)
189         obj.Flagstr("d", "print debug information about items in `list`", &debugstr)
190         obj.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
191         obj.Flagcount("f", "debug stack frames", &Debug['f'])
192         obj.Flagcount("g", "debug code generation", &Debug['g'])
193         obj.Flagcount("h", "halt on error", &Debug['h'])
194         obj.Flagcount("i", "debug line number stack", &Debug['i'])
195         obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
196         obj.Flagstr("installsuffix", "set pkg directory `suffix`", &flag_installsuffix)
197         obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
198         obj.Flagcount("l", "disable inlining", &Debug['l'])
199         obj.Flagcount("live", "debug liveness analysis", &debuglive)
200         obj.Flagcount("m", "print optimization decisions", &Debug['m'])
201         obj.Flagcount("msan", "build code compatible with C/C++ memory sanitizer", &flag_msan)
202         obj.Flagcount("newexport", "use new export format", &newexport) // TODO(gri) remove eventually (issue 13241)
203         obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports)
204         obj.Flagstr("o", "write output to `file`", &outfile)
205         obj.Flagstr("p", "set expected package import `path`", &myimportpath)
206         obj.Flagcount("pack", "write package file instead of object file", &writearchive)
207         obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
208         obj.Flagcount("race", "enable race detector", &flag_race)
209         obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
210         obj.Flagstr("trimpath", "remove `prefix` from recorded source file paths", &Ctxt.LineHist.TrimPathPrefix)
211         obj.Flagcount("u", "reject unsafe code", &safemode)
212         obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
213         obj.Flagcount("w", "debug type checking", &Debug['w'])
214         use_writebarrier = 1
215         obj.Flagcount("wb", "enable write barrier", &use_writebarrier)
216         obj.Flagcount("x", "debug lexer", &Debug['x'])
217         obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y'])
218         var flag_shared int
219         var flag_dynlink bool
220         switch Thearch.Thechar {
221         case '5', '6', '7', '8', '9':
222                 obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared)
223         }
224         if Thearch.Thechar == '6' {
225                 obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel)
226         }
227         switch Thearch.Thechar {
228         case '5', '6', '7', '8', '9':
229                 flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
230         }
231         obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
232         obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
233         obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
234         obj.Flagparse(usage)
235
236         if flag_dynlink {
237                 flag_shared = 1
238         }
239         Ctxt.Flag_shared = int32(flag_shared)
240         Ctxt.Flag_dynlink = flag_dynlink
241         Ctxt.Flag_optimize = Debug['N'] == 0
242
243         Ctxt.Debugasm = int32(Debug['S'])
244         Ctxt.Debugvlog = int32(Debug['v'])
245
246         if flag.NArg() < 1 {
247                 usage()
248         }
249
250         startProfile()
251
252         if flag_race != 0 {
253                 racepkg = mkpkg("runtime/race")
254                 racepkg.Name = "race"
255         }
256         if flag_msan != 0 {
257                 msanpkg = mkpkg("runtime/msan")
258                 msanpkg.Name = "msan"
259         }
260         if flag_race != 0 && flag_msan != 0 {
261                 log.Fatal("cannot use both -race and -msan")
262         } else if flag_race != 0 || flag_msan != 0 {
263                 instrumenting = true
264         }
265
266         // parse -d argument
267         if debugstr != "" {
268         Split:
269                 for _, name := range strings.Split(debugstr, ",") {
270                         if name == "" {
271                                 continue
272                         }
273                         val := 1
274                         if i := strings.Index(name, "="); i >= 0 {
275                                 var err error
276                                 val, err = strconv.Atoi(name[i+1:])
277                                 if err != nil {
278                                         log.Fatalf("invalid debug value %v", name)
279                                 }
280                                 name = name[:i]
281                         }
282                         for _, t := range debugtab {
283                                 if t.name == name {
284                                         if t.val != nil {
285                                                 *t.val = val
286                                                 continue Split
287                                         }
288                                 }
289                         }
290                         // special case for ssa for now
291                         if strings.HasPrefix(name, "ssa/") {
292                                 // expect form ssa/phase/flag
293                                 // e.g. -d=ssa/generic_cse/time
294                                 // _ in phase name also matches space
295                                 phase := name[4:]
296                                 flag := "debug" // default flag is debug
297                                 if i := strings.Index(phase, "/"); i >= 0 {
298                                         flag = phase[i+1:]
299                                         phase = phase[:i]
300                                 }
301                                 err := ssa.PhaseOption(phase, flag, val)
302                                 if err != "" {
303                                         log.Fatalf(err)
304                                 }
305                                 continue Split
306                         }
307                         log.Fatalf("unknown debug key -d %s\n", name)
308                 }
309         }
310
311         // enable inlining.  for now:
312         //      default: inlining on.  (debug['l'] == 1)
313         //      -l: inlining off  (debug['l'] == 0)
314         //      -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
315         if Debug['l'] <= 1 {
316                 Debug['l'] = 1 - Debug['l']
317         }
318
319         Thearch.Betypeinit()
320         if Widthptr == 0 {
321                 Fatalf("betypeinit failed")
322         }
323
324         lexinit()
325         typeinit()
326         lexinit1()
327
328         blockgen = 1
329         dclcontext = PEXTERN
330         nerrors = 0
331         lexlineno = 1
332
333         loadsys()
334
335         for _, infile = range flag.Args() {
336                 if trace && Debug['x'] != 0 {
337                         fmt.Printf("--- %s ---\n", infile)
338                 }
339
340                 linehistpush(infile)
341
342                 bin, err := obj.Bopenr(infile)
343                 if err != nil {
344                         fmt.Printf("open %s: %v\n", infile, err)
345                         errorexit()
346                 }
347
348                 // Skip initial BOM if present.
349                 if obj.Bgetrune(bin) != BOM {
350                         obj.Bungetrune(bin)
351                 }
352
353                 block = 1
354                 iota_ = -1000000
355
356                 imported_unsafe = false
357
358                 parse_file(bin)
359                 if nsyntaxerrors != 0 {
360                         errorexit()
361                 }
362
363                 // Instead of converting EOF into '\n' in getc and count it as an extra line
364                 // for the line history to work, and which then has to be corrected elsewhere,
365                 // just add a line here.
366                 lexlineno++
367
368                 linehistpop()
369                 obj.Bterm(bin)
370         }
371
372         testdclstack()
373         mkpackage(localpkg.Name) // final import not used checks
374         lexfini()
375
376         typecheckok = true
377         if Debug['f'] != 0 {
378                 frame(1)
379         }
380
381         // Process top-level declarations in phases.
382
383         // Phase 1: const, type, and names and types of funcs.
384         //   This will gather all the information about types
385         //   and methods but doesn't depend on any of it.
386         defercheckwidth()
387
388         for l := xtop; l != nil; l = l.Next {
389                 if l.N.Op != ODCL && l.N.Op != OAS && l.N.Op != OAS2 {
390                         typecheck(&l.N, Etop)
391                 }
392         }
393
394         // Phase 2: Variable assignments.
395         //   To check interface assignments, depends on phase 1.
396         for l := xtop; l != nil; l = l.Next {
397                 if l.N.Op == ODCL || l.N.Op == OAS || l.N.Op == OAS2 {
398                         typecheck(&l.N, Etop)
399                 }
400         }
401         resumecheckwidth()
402
403         // Phase 3: Type check function bodies.
404         for l := xtop; l != nil; l = l.Next {
405                 if l.N.Op == ODCLFUNC || l.N.Op == OCLOSURE {
406                         Curfn = l.N
407                         decldepth = 1
408                         saveerrors()
409                         typechecklist(l.N.Nbody, Etop)
410                         checkreturn(l.N)
411                         if nerrors != 0 {
412                                 l.N.Nbody = nil // type errors; do not compile
413                         }
414                 }
415         }
416
417         // Phase 4: Decide how to capture closed variables.
418         // This needs to run before escape analysis,
419         // because variables captured by value do not escape.
420         for l := xtop; l != nil; l = l.Next {
421                 if l.N.Op == ODCLFUNC && l.N.Func.Closure != nil {
422                         Curfn = l.N
423                         capturevars(l.N)
424                 }
425         }
426
427         Curfn = nil
428
429         if nsavederrors+nerrors != 0 {
430                 errorexit()
431         }
432
433         // Phase 5: Inlining
434         if Debug['l'] > 1 {
435                 // Typecheck imported function bodies if debug['l'] > 1,
436                 // otherwise lazily when used or re-exported.
437                 for _, n := range importlist {
438                         if n.Func.Inl != nil {
439                                 saveerrors()
440                                 typecheckinl(n)
441                         }
442                 }
443
444                 if nsavederrors+nerrors != 0 {
445                         errorexit()
446                 }
447         }
448
449         if Debug['l'] != 0 {
450                 // Find functions that can be inlined and clone them before walk expands them.
451                 visitBottomUp(xtop, func(list []*Node, recursive bool) {
452                         // TODO: use a range statement here if the order does not matter
453                         for i := len(list) - 1; i >= 0; i-- {
454                                 n := list[i]
455                                 if n.Op == ODCLFUNC {
456                                         caninl(n)
457                                         inlcalls(n)
458                                 }
459                         }
460                 })
461         }
462
463         // Phase 6: Escape analysis.
464         // Required for moving heap allocations onto stack,
465         // which in turn is required by the closure implementation,
466         // which stores the addresses of stack variables into the closure.
467         // If the closure does not escape, it needs to be on the stack
468         // or else the stack copier will not update it.
469         // Large values are also moved off stack in escape analysis;
470         // because large values may contain pointers, it must happen early.
471         escapes(xtop)
472
473         // Phase 7: Transform closure bodies to properly reference captured variables.
474         // This needs to happen before walk, because closures must be transformed
475         // before walk reaches a call of a closure.
476         for l := xtop; l != nil; l = l.Next {
477                 if l.N.Op == ODCLFUNC && l.N.Func.Closure != nil {
478                         Curfn = l.N
479                         transformclosure(l.N)
480                 }
481         }
482
483         Curfn = nil
484
485         // Phase 8: Compile top level functions.
486         for l := xtop; l != nil; l = l.Next {
487                 if l.N.Op == ODCLFUNC {
488                         funccompile(l.N)
489                 }
490         }
491
492         if nsavederrors+nerrors == 0 {
493                 fninit(xtop)
494         }
495
496         if compiling_runtime != 0 {
497                 checknowritebarrierrec()
498         }
499
500         // Phase 9: Check external declarations.
501         for i, n := range externdcl {
502                 if n.Op == ONAME {
503                         typecheck(&externdcl[i], Erv)
504                 }
505         }
506
507         if nerrors+nsavederrors != 0 {
508                 errorexit()
509         }
510
511         dumpobj()
512
513         if asmhdr != "" {
514                 dumpasmhdr()
515         }
516
517         if nerrors+nsavederrors != 0 {
518                 errorexit()
519         }
520
521         Flusherrors()
522 }
523
524 var importMap = map[string]string{}
525
526 func addImportMap(s string) {
527         if strings.Count(s, "=") != 1 {
528                 log.Fatal("-importmap argument must be of the form source=actual")
529         }
530         i := strings.Index(s, "=")
531         source, actual := s[:i], s[i+1:]
532         if source == "" || actual == "" {
533                 log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
534         }
535         importMap[source] = actual
536 }
537
538 func saveerrors() {
539         nsavederrors += nerrors
540         nerrors = 0
541 }
542
543 func arsize(b *obj.Biobuf, name string) int {
544         var buf [ArhdrSize]byte
545         if _, err := io.ReadFull(b, buf[:]); err != nil {
546                 return -1
547         }
548         aname := strings.Trim(string(buf[0:16]), " ")
549         if !strings.HasPrefix(aname, name) {
550                 return -1
551         }
552         asize := strings.Trim(string(buf[48:58]), " ")
553         i, _ := strconv.Atoi(asize)
554         return i
555 }
556
557 func skiptopkgdef(b *obj.Biobuf) bool {
558         // archive header
559         p := obj.Brdline(b, '\n')
560         if p == "" {
561                 return false
562         }
563         if obj.Blinelen(b) != 8 {
564                 return false
565         }
566         if p != "!<arch>\n" {
567                 return false
568         }
569
570         // package export block should be first
571         sz := arsize(b, "__.PKGDEF")
572         return sz > 0
573 }
574
575 var idirs []string
576
577 func addidir(dir string) {
578         if dir != "" {
579                 idirs = append(idirs, dir)
580         }
581 }
582
583 func isDriveLetter(b byte) bool {
584         return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
585 }
586
587 // is this path a local name?  begins with ./ or ../ or /
588 func islocalname(name string) bool {
589         return strings.HasPrefix(name, "/") ||
590                 Ctxt.Windows != 0 && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
591                 strings.HasPrefix(name, "./") || name == "." ||
592                 strings.HasPrefix(name, "../") || name == ".."
593 }
594
595 func findpkg(name string) (file string, ok bool) {
596         if islocalname(name) {
597                 if safemode != 0 || nolocalimports != 0 {
598                         return "", false
599                 }
600
601                 // try .a before .6.  important for building libraries:
602                 // if there is an array.6 in the array.a library,
603                 // want to find all of array.a, not just array.6.
604                 file = fmt.Sprintf("%s.a", name)
605                 if _, err := os.Stat(file); err == nil {
606                         return file, true
607                 }
608                 file = fmt.Sprintf("%s.o", name)
609                 if _, err := os.Stat(file); err == nil {
610                         return file, true
611                 }
612                 return "", false
613         }
614
615         // local imports should be canonicalized already.
616         // don't want to see "encoding/../encoding/base64"
617         // as different from "encoding/base64".
618         if q := path.Clean(name); q != name {
619                 Yyerror("non-canonical import path %q (should be %q)", name, q)
620                 return "", false
621         }
622
623         for _, dir := range idirs {
624                 file = fmt.Sprintf("%s/%s.a", dir, name)
625                 if _, err := os.Stat(file); err == nil {
626                         return file, true
627                 }
628                 file = fmt.Sprintf("%s/%s.o", dir, name)
629                 if _, err := os.Stat(file); err == nil {
630                         return file, true
631                 }
632         }
633
634         if goroot != "" {
635                 suffix := ""
636                 suffixsep := ""
637                 if flag_installsuffix != "" {
638                         suffixsep = "_"
639                         suffix = flag_installsuffix
640                 } else if flag_race != 0 {
641                         suffixsep = "_"
642                         suffix = "race"
643                 } else if flag_msan != 0 {
644                         suffixsep = "_"
645                         suffix = "msan"
646                 }
647
648                 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", goroot, goos, goarch, suffixsep, suffix, name)
649                 if _, err := os.Stat(file); err == nil {
650                         return file, true
651                 }
652                 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", goroot, goos, goarch, suffixsep, suffix, name)
653                 if _, err := os.Stat(file); err == nil {
654                         return file, true
655                 }
656         }
657
658         return "", false
659 }
660
661 // loadsys loads the definitions for the low-level runtime and unsafe functions,
662 // so that the compiler can generate calls to them,
663 // but does not make the names "runtime" or "unsafe" visible as packages.
664 func loadsys() {
665         if Debug['A'] != 0 {
666                 return
667         }
668
669         block = 1
670         iota_ = -1000000
671         incannedimport = 1
672
673         importpkg = Runtimepkg
674         parse_import(obj.Binitr(strings.NewReader(runtimeimport)), nil)
675
676         importpkg = unsafepkg
677         parse_import(obj.Binitr(strings.NewReader(unsafeimport)), nil)
678
679         importpkg = nil
680         incannedimport = 0
681 }
682
683 func importfile(f *Val, indent []byte) {
684         if importpkg != nil {
685                 Fatalf("importpkg not nil")
686         }
687
688         path_, ok := f.U.(string)
689         if !ok {
690                 Yyerror("import statement not a string")
691                 return
692         }
693
694         if len(path_) == 0 {
695                 Yyerror("import path is empty")
696                 return
697         }
698
699         if isbadimport(path_) {
700                 return
701         }
702
703         // The package name main is no longer reserved,
704         // but we reserve the import path "main" to identify
705         // the main package, just as we reserve the import
706         // path "math" to identify the standard math package.
707         if path_ == "main" {
708                 Yyerror("cannot import \"main\"")
709                 errorexit()
710         }
711
712         if myimportpath != "" && path_ == myimportpath {
713                 Yyerror("import %q while compiling that package (import cycle)", path_)
714                 errorexit()
715         }
716
717         if mapped, ok := importMap[path_]; ok {
718                 path_ = mapped
719         }
720
721         if path_ == "unsafe" {
722                 if safemode != 0 {
723                         Yyerror("cannot import package unsafe")
724                         errorexit()
725                 }
726
727                 importpkg = unsafepkg
728                 imported_unsafe = true
729                 return
730         }
731
732         if islocalname(path_) {
733                 if path_[0] == '/' {
734                         Yyerror("import path cannot be absolute path")
735                         return
736                 }
737
738                 prefix := Ctxt.Pathname
739                 if localimport != "" {
740                         prefix = localimport
741                 }
742                 path_ = path.Join(prefix, path_)
743
744                 if isbadimport(path_) {
745                         return
746                 }
747         }
748
749         file, found := findpkg(path_)
750         if !found {
751                 Yyerror("can't find import: %q", path_)
752                 errorexit()
753         }
754
755         importpkg = mkpkg(path_)
756
757         if importpkg.Imported {
758                 return
759         }
760
761         importpkg.Imported = true
762
763         imp, err := obj.Bopenr(file)
764         if err != nil {
765                 Yyerror("can't open import: %q: %v", path_, err)
766                 errorexit()
767         }
768         defer obj.Bterm(imp)
769
770         if strings.HasSuffix(file, ".a") {
771                 if !skiptopkgdef(imp) {
772                         Yyerror("import %s: not a package file", file)
773                         errorexit()
774                 }
775         }
776
777         // check object header
778         p := obj.Brdstr(imp, '\n', 1)
779
780         if p != "empty archive" {
781                 if !strings.HasPrefix(p, "go object ") {
782                         Yyerror("import %s: not a go object file", file)
783                         errorexit()
784                 }
785
786                 q := fmt.Sprintf("%s %s %s %s", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
787                 if p[10:] != q {
788                         Yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
789                         errorexit()
790                 }
791         }
792
793         // assume files move (get installed)
794         // so don't record the full path.
795         linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
796
797         // In the importfile, if we find:
798         // $$\n  (old format): position the input right after $$\n and return
799         // $$B\n (new format): import directly, then feed the lexer a dummy statement
800
801         // look for $$
802         var c int
803         for {
804                 c = obj.Bgetc(imp)
805                 if c < 0 {
806                         break
807                 }
808                 if c == '$' {
809                         c = obj.Bgetc(imp)
810                         if c == '$' || c < 0 {
811                                 break
812                         }
813                 }
814         }
815
816         // get character after $$
817         if c >= 0 {
818                 c = obj.Bgetc(imp)
819         }
820
821         switch c {
822         case '\n':
823                 // old export format
824                 parse_import(imp, indent)
825
826         case 'B':
827                 // new export format
828                 obj.Bgetc(imp) // skip \n after $$B
829                 Import(imp)
830
831         default:
832                 Yyerror("no import in %q", path_)
833                 errorexit()
834         }
835
836         if safemode != 0 && !importpkg.Safe {
837                 Yyerror("cannot import unsafe package %q", importpkg.Path)
838         }
839 }
840
841 func isSpace(c rune) bool {
842         return c == ' ' || c == '\t' || c == '\n' || c == '\r'
843 }
844
845 func isLetter(c rune) bool {
846         return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_'
847 }
848
849 func isDigit(c rune) bool {
850         return '0' <= c && c <= '9'
851 }
852
853 func plan9quote(s string) string {
854         if s == "" {
855                 return "''"
856         }
857         for _, c := range s {
858                 if c <= ' ' || c == '\'' {
859                         return "'" + strings.Replace(s, "'", "''", -1) + "'"
860                 }
861         }
862         return s
863 }
864
865 type Pragma uint8
866
867 const (
868         Nointerface       Pragma = 1 << iota
869         Noescape                 // func parameters don't escape
870         Norace                   // func must not have race detector annotations
871         Nosplit                  // func should not execute on separate stack
872         Noinline                 // func should not be inlined
873         Systemstack              // func must run on system stack
874         Nowritebarrier           // emit compiler error instead of write barrier
875         Nowritebarrierrec        // error on write barrier in this or recursive callees
876 )
877
878 type lexer struct {
879         // source
880         bin    *obj.Biobuf
881         peekr1 rune
882         peekr2 rune // second peekc for ...
883
884         nlsemi bool // if set, '\n' and EOF translate to ';'
885
886         // pragma flags
887         // accumulated by lexer; reset by parser
888         pragma Pragma
889
890         // current token
891         tok  int32
892         sym_ *Sym   // valid if tok == LNAME
893         val  Val    // valid if tok == LLITERAL
894         op   Op     // valid if tok == LASOP or LINCOP, or prec > 0
895         prec OpPrec // operator precedence; 0 if not a binary operator
896 }
897
898 type OpPrec int
899
900 const (
901         // Precedences of binary operators (must be > 0).
902         PCOMM OpPrec = 1 + iota
903         POROR
904         PANDAND
905         PCMP
906         PADD
907         PMUL
908 )
909
910 const (
911         // The value of single-char tokens is just their character's Unicode value.
912         // They are all below utf8.RuneSelf. Shift other tokens up to avoid conflicts.
913         LLITERAL = utf8.RuneSelf + iota
914         LASOP
915         LCOLAS
916         LBREAK
917         LCASE
918         LCHAN
919         LCONST
920         LCONTINUE
921         LDDD
922         LDEFAULT
923         LDEFER
924         LELSE
925         LFALL
926         LFOR
927         LFUNC
928         LGO
929         LGOTO
930         LIF
931         LIMPORT
932         LINTERFACE
933         LMAP
934         LNAME
935         LPACKAGE
936         LRANGE
937         LRETURN
938         LSELECT
939         LSTRUCT
940         LSWITCH
941         LTYPE
942         LVAR
943         LANDAND
944         LANDNOT
945         LCOMM
946         LEQ
947         LGE
948         LGT
949         LIGNORE
950         LINCOP
951         LLE
952         LLSH
953         LLT
954         LNE
955         LOROR
956         LRSH
957 )
958
959 func (l *lexer) next() {
960         nlsemi := l.nlsemi
961         l.nlsemi = false
962         l.prec = 0
963
964 l0:
965         // skip white space
966         c := l.getr()
967         for isSpace(c) {
968                 if c == '\n' && nlsemi {
969                         if Debug['x'] != 0 {
970                                 fmt.Printf("lex: implicit semi\n")
971                         }
972                         // Insert implicit semicolon on previous line,
973                         // before the newline character.
974                         lineno = lexlineno - 1
975                         l.tok = ';'
976                         return
977                 }
978                 c = l.getr()
979         }
980
981         // start of token
982         lineno = lexlineno
983
984         // identifiers and keywords
985         // (for better error messages consume all chars >= utf8.RuneSelf for identifiers)
986         if isLetter(c) || c >= utf8.RuneSelf {
987                 l.ident(c)
988                 if l.tok == LIGNORE {
989                         goto l0
990                 }
991                 return
992         }
993         // c < utf8.RuneSelf
994
995         var c1 rune
996         var op Op
997         var prec OpPrec
998
999         switch c {
1000         case EOF:
1001                 l.ungetr(EOF) // return EOF again in future next call
1002                 // Treat EOF as "end of line" for the purposes
1003                 // of inserting a semicolon.
1004                 if nlsemi {
1005                         if Debug['x'] != 0 {
1006                                 fmt.Printf("lex: implicit semi\n")
1007                         }
1008                         l.tok = ';'
1009                         return
1010                 }
1011                 l.tok = -1
1012                 return
1013
1014         case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
1015                 l.number(c)
1016                 return
1017
1018         case '.':
1019                 c1 = l.getr()
1020                 if isDigit(c1) {
1021                         l.ungetr(c1)
1022                         l.number('.')
1023                         return
1024                 }
1025
1026                 if c1 == '.' {
1027                         c1 = l.getr()
1028                         if c1 == '.' {
1029                                 c = LDDD
1030                                 goto lx
1031                         }
1032
1033                         l.ungetr(c1)
1034                         c1 = '.'
1035                 }
1036
1037         case '"':
1038                 l.stdString()
1039                 return
1040
1041         case '`':
1042                 l.rawString()
1043                 return
1044
1045         case '\'':
1046                 l.rune()
1047                 return
1048
1049         case '/':
1050                 c1 = l.getr()
1051                 if c1 == '*' {
1052                         c = l.getr()
1053                         for {
1054                                 if c == '*' {
1055                                         c = l.getr()
1056                                         if c == '/' {
1057                                                 break
1058                                         }
1059                                         continue
1060                                 }
1061                                 if c == EOF {
1062                                         Yyerror("eof in comment")
1063                                         errorexit()
1064                                 }
1065                                 c = l.getr()
1066                         }
1067
1068                         // A comment containing newlines acts like a newline.
1069                         if lexlineno > lineno && nlsemi {
1070                                 if Debug['x'] != 0 {
1071                                         fmt.Printf("lex: implicit semi\n")
1072                                 }
1073                                 l.tok = ';'
1074                                 return
1075                         }
1076                         goto l0
1077                 }
1078
1079                 if c1 == '/' {
1080                         c = l.getlinepragma()
1081                         for {
1082                                 if c == '\n' || c == EOF {
1083                                         l.ungetr(c)
1084                                         goto l0
1085                                 }
1086
1087                                 c = l.getr()
1088                         }
1089                 }
1090
1091                 op = ODIV
1092                 prec = PMUL
1093                 goto binop1
1094
1095         case ':':
1096                 c1 = l.getr()
1097                 if c1 == '=' {
1098                         c = LCOLAS
1099                         goto lx
1100                 }
1101
1102         case '*':
1103                 op = OMUL
1104                 prec = PMUL
1105                 goto binop
1106
1107         case '%':
1108                 op = OMOD
1109                 prec = PMUL
1110                 goto binop
1111
1112         case '+':
1113                 op = OADD
1114                 goto incop
1115
1116         case '-':
1117                 op = OSUB
1118                 goto incop
1119
1120         case '>':
1121                 c1 = l.getr()
1122                 if c1 == '>' {
1123                         c = LRSH
1124                         op = ORSH
1125                         prec = PMUL
1126                         goto binop
1127                 }
1128
1129                 l.prec = PCMP
1130                 if c1 == '=' {
1131                         c = LGE
1132                         l.op = OGE
1133                         goto lx
1134                 }
1135                 c = LGT
1136                 l.op = OGT
1137
1138         case '<':
1139                 c1 = l.getr()
1140                 if c1 == '<' {
1141                         c = LLSH
1142                         op = OLSH
1143                         prec = PMUL
1144                         goto binop
1145                 }
1146
1147                 if c1 == '-' {
1148                         c = LCOMM
1149                         // Not a binary operator, but parsed as one
1150                         // so we can give a good error message when used
1151                         // in an expression context.
1152                         l.prec = PCOMM
1153                         l.op = OSEND
1154                         goto lx
1155                 }
1156
1157                 l.prec = PCMP
1158                 if c1 == '=' {
1159                         c = LLE
1160                         l.op = OLE
1161                         goto lx
1162                 }
1163                 c = LLT
1164                 l.op = OLT
1165
1166         case '=':
1167                 c1 = l.getr()
1168                 if c1 == '=' {
1169                         c = LEQ
1170                         l.prec = PCMP
1171                         l.op = OEQ
1172                         goto lx
1173                 }
1174
1175         case '!':
1176                 c1 = l.getr()
1177                 if c1 == '=' {
1178                         c = LNE
1179                         l.prec = PCMP
1180                         l.op = ONE
1181                         goto lx
1182                 }
1183
1184         case '&':
1185                 c1 = l.getr()
1186                 if c1 == '&' {
1187                         c = LANDAND
1188                         l.prec = PANDAND
1189                         l.op = OANDAND
1190                         goto lx
1191                 }
1192
1193                 if c1 == '^' {
1194                         c = LANDNOT
1195                         op = OANDNOT
1196                         prec = PMUL
1197                         goto binop
1198                 }
1199
1200                 op = OAND
1201                 prec = PMUL
1202                 goto binop1
1203
1204         case '|':
1205                 c1 = l.getr()
1206                 if c1 == '|' {
1207                         c = LOROR
1208                         l.prec = POROR
1209                         l.op = OOROR
1210                         goto lx
1211                 }
1212
1213                 op = OOR
1214                 prec = PADD
1215                 goto binop1
1216
1217         case '^':
1218                 op = OXOR
1219                 prec = PADD
1220                 goto binop
1221
1222         case '(', '[', '{', ',', ';':
1223                 goto lx
1224
1225         case ')', ']', '}':
1226                 l.nlsemi = true
1227                 goto lx
1228
1229         case '#', '$', '?', '@', '\\':
1230                 if importpkg != nil {
1231                         goto lx
1232                 }
1233                 fallthrough
1234
1235         default:
1236                 // anything else is illegal
1237                 Yyerror("syntax error: illegal character %#U", c)
1238                 goto l0
1239         }
1240
1241         l.ungetr(c1)
1242
1243 lx:
1244         if Debug['x'] != 0 {
1245                 if c >= utf8.RuneSelf {
1246                         fmt.Printf("%v lex: TOKEN %s\n", Ctxt.Line(int(lineno)), lexname(c))
1247                 } else {
1248                         fmt.Printf("%v lex: TOKEN '%c'\n", Ctxt.Line(int(lineno)), c)
1249                 }
1250         }
1251
1252         l.tok = c
1253         return
1254
1255 incop:
1256         c1 = l.getr()
1257         if c1 == c {
1258                 l.nlsemi = true
1259                 l.op = op
1260                 c = LINCOP
1261                 goto lx
1262         }
1263         prec = PADD
1264         goto binop1
1265
1266 binop:
1267         c1 = l.getr()
1268 binop1:
1269         if c1 != '=' {
1270                 l.ungetr(c1)
1271                 l.op = op
1272                 l.prec = prec
1273                 goto lx
1274         }
1275
1276         l.op = op
1277         if Debug['x'] != 0 {
1278                 fmt.Printf("lex: TOKEN ASOP %s=\n", goopnames[op])
1279         }
1280         l.tok = LASOP
1281 }
1282
1283 func (l *lexer) ident(c rune) {
1284         cp := &lexbuf
1285         cp.Reset()
1286
1287         // accelerate common case (7bit ASCII)
1288         for isLetter(c) || isDigit(c) {
1289                 cp.WriteByte(byte(c))
1290                 c = l.getr()
1291         }
1292
1293         // general case
1294         for {
1295                 if c >= utf8.RuneSelf {
1296                         if unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) || importpkg != nil && c == 0xb7 {
1297                                 if cp.Len() == 0 && unicode.IsDigit(c) {
1298                                         Yyerror("identifier cannot begin with digit %#U", c)
1299                                 }
1300                         } else {
1301                                 Yyerror("invalid identifier character %#U", c)
1302                         }
1303                         cp.WriteRune(c)
1304                 } else if isLetter(c) || isDigit(c) {
1305                         cp.WriteByte(byte(c))
1306                 } else {
1307                         break
1308                 }
1309                 c = l.getr()
1310         }
1311
1312         cp = nil
1313         l.ungetr(c)
1314
1315         name := lexbuf.Bytes()
1316
1317         if len(name) >= 2 {
1318                 if tok, ok := keywords[string(name)]; ok {
1319                         if Debug['x'] != 0 {
1320                                 fmt.Printf("lex: %s\n", lexname(tok))
1321                         }
1322                         switch tok {
1323                         case LBREAK, LCONTINUE, LFALL, LRETURN:
1324                                 l.nlsemi = true
1325                         }
1326                         l.tok = tok
1327                         return
1328                 }
1329         }
1330
1331         s := LookupBytes(name)
1332         if Debug['x'] != 0 {
1333                 fmt.Printf("lex: ident %s\n", s)
1334         }
1335         l.sym_ = s
1336         l.nlsemi = true
1337         l.tok = LNAME
1338 }
1339
1340 var keywords = map[string]int32{
1341         "break":       LBREAK,
1342         "case":        LCASE,
1343         "chan":        LCHAN,
1344         "const":       LCONST,
1345         "continue":    LCONTINUE,
1346         "default":     LDEFAULT,
1347         "defer":       LDEFER,
1348         "else":        LELSE,
1349         "fallthrough": LFALL,
1350         "for":         LFOR,
1351         "func":        LFUNC,
1352         "go":          LGO,
1353         "goto":        LGOTO,
1354         "if":          LIF,
1355         "import":      LIMPORT,
1356         "interface":   LINTERFACE,
1357         "map":         LMAP,
1358         "package":     LPACKAGE,
1359         "range":       LRANGE,
1360         "return":      LRETURN,
1361         "select":      LSELECT,
1362         "struct":      LSTRUCT,
1363         "switch":      LSWITCH,
1364         "type":        LTYPE,
1365         "var":         LVAR,
1366
1367         // ðŸ’©
1368         "notwithstanding":      LIGNORE,
1369         "thetruthofthematter":  LIGNORE,
1370         "despiteallobjections": LIGNORE,
1371         "whereas":              LIGNORE,
1372         "insofaras":            LIGNORE,
1373 }
1374
1375 func (l *lexer) number(c rune) {
1376         // TODO(gri) this can be done nicely with fewer or even without labels
1377
1378         var str string
1379         cp := &lexbuf
1380         cp.Reset()
1381
1382         if c != '.' {
1383                 if c != '0' {
1384                         for isDigit(c) {
1385                                 cp.WriteByte(byte(c))
1386                                 c = l.getr()
1387                         }
1388                         if c == '.' {
1389                                 goto casedot
1390                         }
1391                         if c == 'e' || c == 'E' || c == 'p' || c == 'P' {
1392                                 goto caseep
1393                         }
1394                         if c == 'i' {
1395                                 goto casei
1396                         }
1397                         goto ncu
1398                 }
1399
1400                 // c == 0
1401                 cp.WriteByte('0')
1402                 c = l.getr()
1403                 if c == 'x' || c == 'X' {
1404                         cp.WriteByte(byte(c))
1405                         c = l.getr()
1406                         for isDigit(c) || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
1407                                 cp.WriteByte(byte(c))
1408                                 c = l.getr()
1409                         }
1410                         if lexbuf.Len() == 2 {
1411                                 Yyerror("malformed hex constant")
1412                         }
1413                         if c == 'p' {
1414                                 goto caseep
1415                         }
1416                         goto ncu
1417                 }
1418
1419                 if c == 'p' { // 0p begins floating point zero
1420                         goto caseep
1421                 }
1422
1423                 has8or9 := false
1424                 for isDigit(c) {
1425                         if c > '7' {
1426                                 has8or9 = true
1427                         }
1428                         cp.WriteByte(byte(c))
1429                         c = l.getr()
1430                 }
1431                 if c == '.' {
1432                         goto casedot
1433                 }
1434                 if c == 'e' || c == 'E' {
1435                         goto caseep
1436                 }
1437                 if c == 'i' {
1438                         goto casei
1439                 }
1440                 if has8or9 {
1441                         Yyerror("malformed octal constant")
1442                 }
1443                 goto ncu
1444         }
1445
1446 casedot:
1447         // fraction
1448         // c == '.'
1449         cp.WriteByte('.')
1450         c = l.getr()
1451         for isDigit(c) {
1452                 cp.WriteByte(byte(c))
1453                 c = l.getr()
1454         }
1455         if c == 'i' {
1456                 goto casei
1457         }
1458         if c != 'e' && c != 'E' {
1459                 goto caseout
1460         }
1461         // base-2-exponents (p or P) don't appear in numbers
1462         // with fractions - ok to not test for 'p' or 'P'
1463         // above
1464
1465 caseep:
1466         // exponent
1467         if importpkg == nil && (c == 'p' || c == 'P') {
1468                 // <mantissa>p<base-2-exponent> is allowed in .a/.o imports,
1469                 // but not in .go sources.  See #9036.
1470                 Yyerror("malformed floating point constant")
1471         }
1472         cp.WriteByte(byte(c))
1473         c = l.getr()
1474         if c == '+' || c == '-' {
1475                 cp.WriteByte(byte(c))
1476                 c = l.getr()
1477         }
1478
1479         if !isDigit(c) {
1480                 Yyerror("malformed floating point constant exponent")
1481         }
1482         for isDigit(c) {
1483                 cp.WriteByte(byte(c))
1484                 c = l.getr()
1485         }
1486
1487         if c != 'i' {
1488                 goto caseout
1489         }
1490
1491 casei:
1492         // imaginary constant
1493         cp = nil
1494
1495         str = lexbuf.String()
1496         l.val.U = new(Mpcplx)
1497         Mpmovecflt(&l.val.U.(*Mpcplx).Real, 0.0)
1498         mpatoflt(&l.val.U.(*Mpcplx).Imag, str)
1499         if l.val.U.(*Mpcplx).Imag.Val.IsInf() {
1500                 Yyerror("overflow in imaginary constant")
1501                 Mpmovecflt(&l.val.U.(*Mpcplx).Imag, 0.0)
1502         }
1503
1504         if Debug['x'] != 0 {
1505                 fmt.Printf("lex: imaginary literal\n")
1506         }
1507         goto done
1508
1509 caseout:
1510         cp = nil
1511         l.ungetr(c)
1512
1513         str = lexbuf.String()
1514         l.val.U = newMpflt()
1515         mpatoflt(l.val.U.(*Mpflt), str)
1516         if l.val.U.(*Mpflt).Val.IsInf() {
1517                 Yyerror("overflow in float constant")
1518                 Mpmovecflt(l.val.U.(*Mpflt), 0.0)
1519         }
1520
1521         if Debug['x'] != 0 {
1522                 fmt.Printf("lex: floating literal\n")
1523         }
1524         goto done
1525
1526 ncu:
1527         cp = nil
1528         l.ungetr(c)
1529
1530         str = lexbuf.String()
1531         l.val.U = new(Mpint)
1532         mpatofix(l.val.U.(*Mpint), str)
1533         if l.val.U.(*Mpint).Ovf {
1534                 Yyerror("overflow in constant")
1535                 Mpmovecfix(l.val.U.(*Mpint), 0)
1536         }
1537
1538         if Debug['x'] != 0 {
1539                 fmt.Printf("lex: integer literal\n")
1540         }
1541
1542 done:
1543         litbuf = "literal " + str
1544         l.nlsemi = true
1545         l.tok = LLITERAL
1546 }
1547
1548 func (l *lexer) stdString() {
1549         lexbuf.Reset()
1550         lexbuf.WriteString(`"<string>"`)
1551
1552         cp := &strbuf
1553         cp.Reset()
1554
1555         for {
1556                 r, b, ok := l.onechar('"')
1557                 if !ok {
1558                         break
1559                 }
1560                 if r == 0 {
1561                         cp.WriteByte(b)
1562                 } else {
1563                         cp.WriteRune(r)
1564                 }
1565         }
1566
1567         l.val.U = internString(cp.Bytes())
1568         if Debug['x'] != 0 {
1569                 fmt.Printf("lex: string literal\n")
1570         }
1571         litbuf = "string literal"
1572         l.nlsemi = true
1573         l.tok = LLITERAL
1574 }
1575
1576 func (l *lexer) rawString() {
1577         lexbuf.Reset()
1578         lexbuf.WriteString("`<string>`")
1579
1580         cp := &strbuf
1581         cp.Reset()
1582
1583         for {
1584                 c := l.getr()
1585                 if c == '\r' {
1586                         continue
1587                 }
1588                 if c == EOF {
1589                         Yyerror("eof in string")
1590                         break
1591                 }
1592                 if c == '`' {
1593                         break
1594                 }
1595                 cp.WriteRune(c)
1596         }
1597
1598         l.val.U = internString(cp.Bytes())
1599         if Debug['x'] != 0 {
1600                 fmt.Printf("lex: string literal\n")
1601         }
1602         litbuf = "string literal"
1603         l.nlsemi = true
1604         l.tok = LLITERAL
1605 }
1606
1607 func (l *lexer) rune() {
1608         r, b, ok := l.onechar('\'')
1609         if !ok {
1610                 Yyerror("empty character literal or unescaped ' in character literal")
1611                 r = '\''
1612         }
1613         if r == 0 {
1614                 r = rune(b)
1615         }
1616
1617         if c := l.getr(); c != '\'' {
1618                 Yyerror("missing '")
1619                 l.ungetr(c)
1620         }
1621
1622         x := new(Mpint)
1623         l.val.U = x
1624         Mpmovecfix(x, int64(r))
1625         x.Rune = true
1626         if Debug['x'] != 0 {
1627                 fmt.Printf("lex: codepoint literal\n")
1628         }
1629         litbuf = "rune literal"
1630         l.nlsemi = true
1631         l.tok = LLITERAL
1632 }
1633
1634 var internedStrings = map[string]string{}
1635
1636 func internString(b []byte) string {
1637         s, ok := internedStrings[string(b)] // string(b) here doesn't allocate
1638         if !ok {
1639                 s = string(b)
1640                 internedStrings[s] = s
1641         }
1642         return s
1643 }
1644
1645 func more(pp *string) bool {
1646         p := *pp
1647         for p != "" && isSpace(rune(p[0])) {
1648                 p = p[1:]
1649         }
1650         *pp = p
1651         return p != ""
1652 }
1653
1654 // read and interpret syntax that looks like
1655 // //line parse.y:15
1656 // as a discontinuity in sequential line numbers.
1657 // the next line of input comes from parse.y:15
1658 func (l *lexer) getlinepragma() rune {
1659         c := l.getr()
1660         if c == 'g' { // check for //go: directive
1661                 cp := &lexbuf
1662                 cp.Reset()
1663                 cp.WriteByte('g') // already read
1664                 for {
1665                         c = l.getr()
1666                         if c == EOF || c >= utf8.RuneSelf {
1667                                 return c
1668                         }
1669                         if c == '\n' {
1670                                 break
1671                         }
1672                         cp.WriteByte(byte(c))
1673                 }
1674                 cp = nil
1675
1676                 text := strings.TrimSuffix(lexbuf.String(), "\r")
1677
1678                 if strings.HasPrefix(text, "go:cgo_") {
1679                         pragcgo(text)
1680                 }
1681
1682                 verb := text
1683                 if i := strings.Index(text, " "); i >= 0 {
1684                         verb = verb[:i]
1685                 }
1686
1687                 switch verb {
1688                 case "go:linkname":
1689                         if !imported_unsafe {
1690                                 Yyerror("//go:linkname only allowed in Go files that import \"unsafe\"")
1691                         }
1692                         f := strings.Fields(text)
1693                         if len(f) != 3 {
1694                                 Yyerror("usage: //go:linkname localname linkname")
1695                                 break
1696                         }
1697                         Lookup(f[1]).Linkname = f[2]
1698                 case "go:nointerface":
1699                         if obj.Fieldtrack_enabled != 0 {
1700                                 l.pragma |= Nointerface
1701                         }
1702                 case "go:noescape":
1703                         l.pragma |= Noescape
1704                 case "go:norace":
1705                         l.pragma |= Norace
1706                 case "go:nosplit":
1707                         l.pragma |= Nosplit
1708                 case "go:noinline":
1709                         l.pragma |= Noinline
1710                 case "go:systemstack":
1711                         if compiling_runtime == 0 {
1712                                 Yyerror("//go:systemstack only allowed in runtime")
1713                         }
1714                         l.pragma |= Systemstack
1715                 case "go:nowritebarrier":
1716                         if compiling_runtime == 0 {
1717                                 Yyerror("//go:nowritebarrier only allowed in runtime")
1718                         }
1719                         l.pragma |= Nowritebarrier
1720                 case "go:nowritebarrierrec":
1721                         if compiling_runtime == 0 {
1722                                 Yyerror("//go:nowritebarrierrec only allowed in runtime")
1723                         }
1724                         l.pragma |= Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
1725                 }
1726                 return c
1727         }
1728
1729         // check for //line directive
1730         if c != 'l' {
1731                 return c
1732         }
1733         for i := 1; i < 5; i++ {
1734                 c = l.getr()
1735                 if c != rune("line "[i]) {
1736                         return c
1737                 }
1738         }
1739
1740         cp := &lexbuf
1741         cp.Reset()
1742         linep := 0
1743         for {
1744                 c = l.getr()
1745                 if c == EOF {
1746                         return c
1747                 }
1748                 if c == '\n' {
1749                         break
1750                 }
1751                 if c == ' ' {
1752                         continue
1753                 }
1754                 if c == ':' {
1755                         linep = cp.Len() + 1
1756                 }
1757                 cp.WriteByte(byte(c))
1758         }
1759         cp = nil
1760
1761         if linep == 0 {
1762                 return c
1763         }
1764         text := strings.TrimSuffix(lexbuf.String(), "\r")
1765         n, err := strconv.Atoi(text[linep:])
1766         if err != nil {
1767                 return c // todo: make this an error instead? it is almost certainly a bug.
1768         }
1769         if n > 1e8 {
1770                 Yyerror("line number out of range")
1771                 errorexit()
1772         }
1773         if n <= 0 {
1774                 return c
1775         }
1776
1777         linehistupdate(text[:linep-1], n)
1778         return c
1779 }
1780
1781 func getimpsym(pp *string) string {
1782         more(pp) // skip spaces
1783         p := *pp
1784         if p == "" || p[0] == '"' {
1785                 return ""
1786         }
1787         i := 0
1788         for i < len(p) && !isSpace(rune(p[i])) && p[i] != '"' {
1789                 i++
1790         }
1791         sym := p[:i]
1792         *pp = p[i:]
1793         return sym
1794 }
1795
1796 func getquoted(pp *string) (string, bool) {
1797         more(pp) // skip spaces
1798         p := *pp
1799         if p == "" || p[0] != '"' {
1800                 return "", false
1801         }
1802         p = p[1:]
1803         i := strings.Index(p, `"`)
1804         if i < 0 {
1805                 return "", false
1806         }
1807         *pp = p[i+1:]
1808         return p[:i], true
1809 }
1810
1811 // Copied nearly verbatim from the C compiler's #pragma parser.
1812 // TODO: Rewrite more cleanly once the compiler is written in Go.
1813 func pragcgo(text string) {
1814         var q string
1815
1816         if i := strings.Index(text, " "); i >= 0 {
1817                 text, q = text[:i], text[i:]
1818         }
1819
1820         verb := text[3:] // skip "go:"
1821
1822         if verb == "cgo_dynamic_linker" || verb == "dynlinker" {
1823                 p, ok := getquoted(&q)
1824                 if !ok {
1825                         Yyerror("usage: //go:cgo_dynamic_linker \"path\"")
1826                         return
1827                 }
1828                 pragcgobuf += fmt.Sprintf("cgo_dynamic_linker %v\n", plan9quote(p))
1829                 return
1830
1831         }
1832
1833         if verb == "dynexport" {
1834                 verb = "cgo_export_dynamic"
1835         }
1836         if verb == "cgo_export_static" || verb == "cgo_export_dynamic" {
1837                 local := getimpsym(&q)
1838                 var remote string
1839                 if local == "" {
1840                         goto err2
1841                 }
1842                 if !more(&q) {
1843                         pragcgobuf += fmt.Sprintf("%s %v\n", verb, plan9quote(local))
1844                         return
1845                 }
1846
1847                 remote = getimpsym(&q)
1848                 if remote == "" {
1849                         goto err2
1850                 }
1851                 pragcgobuf += fmt.Sprintf("%s %v %v\n", verb, plan9quote(local), plan9quote(remote))
1852                 return
1853
1854         err2:
1855                 Yyerror("usage: //go:%s local [remote]", verb)
1856                 return
1857         }
1858
1859         if verb == "cgo_import_dynamic" || verb == "dynimport" {
1860                 var ok bool
1861                 local := getimpsym(&q)
1862                 var p string
1863                 var remote string
1864                 if local == "" {
1865                         goto err3
1866                 }
1867                 if !more(&q) {
1868                         pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v\n", plan9quote(local))
1869                         return
1870                 }
1871
1872                 remote = getimpsym(&q)
1873                 if remote == "" {
1874                         goto err3
1875                 }
1876                 if !more(&q) {
1877                         pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v\n", plan9quote(local), plan9quote(remote))
1878                         return
1879                 }
1880
1881                 p, ok = getquoted(&q)
1882                 if !ok {
1883                         goto err3
1884                 }
1885                 pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v %v\n", plan9quote(local), plan9quote(remote), plan9quote(p))
1886                 return
1887
1888         err3:
1889                 Yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]")
1890                 return
1891         }
1892
1893         if verb == "cgo_import_static" {
1894                 local := getimpsym(&q)
1895                 if local == "" || more(&q) {
1896                         Yyerror("usage: //go:cgo_import_static local")
1897                         return
1898                 }
1899                 pragcgobuf += fmt.Sprintf("cgo_import_static %v\n", plan9quote(local))
1900                 return
1901
1902         }
1903
1904         if verb == "cgo_ldflag" {
1905                 p, ok := getquoted(&q)
1906                 if !ok {
1907                         Yyerror("usage: //go:cgo_ldflag \"arg\"")
1908                         return
1909                 }
1910                 pragcgobuf += fmt.Sprintf("cgo_ldflag %v\n", plan9quote(p))
1911                 return
1912
1913         }
1914 }
1915
1916 func (l *lexer) getr() rune {
1917         // unread rune != 0 available
1918         if r := l.peekr1; r != 0 {
1919                 l.peekr1 = l.peekr2
1920                 l.peekr2 = 0
1921                 if r == '\n' && importpkg == nil {
1922                         lexlineno++
1923                 }
1924                 return r
1925         }
1926
1927 redo:
1928         // common case: 7bit ASCII
1929         c := obj.Bgetc(l.bin)
1930         if c < utf8.RuneSelf {
1931                 if c == 0 {
1932                         yyerrorl(int(lexlineno), "illegal NUL byte")
1933                         return 0
1934                 }
1935                 if c == '\n' && importpkg == nil {
1936                         lexlineno++
1937                 }
1938                 return rune(c)
1939         }
1940         // c >= utf8.RuneSelf
1941
1942         // uncommon case: non-ASCII
1943         var buf [utf8.UTFMax]byte
1944         buf[0] = byte(c)
1945         buf[1] = byte(obj.Bgetc(l.bin))
1946         i := 2
1947         for ; i < len(buf) && !utf8.FullRune(buf[:i]); i++ {
1948                 buf[i] = byte(obj.Bgetc(l.bin))
1949         }
1950
1951         r, w := utf8.DecodeRune(buf[:i])
1952         if r == utf8.RuneError && w == 1 {
1953                 // The string conversion here makes a copy for passing
1954                 // to fmt.Printf, so that buf itself does not escape and
1955                 // can be allocated on the stack.
1956                 yyerrorl(int(lexlineno), "illegal UTF-8 sequence % x", string(buf[:i]))
1957         }
1958
1959         if r == BOM {
1960                 yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")
1961                 goto redo
1962         }
1963
1964         return r
1965 }
1966
1967 func (l *lexer) ungetr(r rune) {
1968         l.peekr2 = l.peekr1
1969         l.peekr1 = r
1970         if r == '\n' && importpkg == nil {
1971                 lexlineno--
1972         }
1973 }
1974
1975 // onechar lexes a single character within a rune or interpreted string literal,
1976 // handling escape sequences as necessary.
1977 func (l *lexer) onechar(quote rune) (r rune, b byte, ok bool) {
1978         c := l.getr()
1979         switch c {
1980         case EOF:
1981                 Yyerror("eof in string")
1982                 l.ungetr(EOF)
1983                 return
1984
1985         case '\n':
1986                 Yyerror("newline in string")
1987                 l.ungetr('\n')
1988                 return
1989
1990         case '\\':
1991                 break
1992
1993         case quote:
1994                 return
1995
1996         default:
1997                 return c, 0, true
1998         }
1999
2000         c = l.getr()
2001         switch c {
2002         case 'x':
2003                 return 0, byte(l.hexchar(2)), true
2004
2005         case 'u':
2006                 return l.unichar(4), 0, true
2007
2008         case 'U':
2009                 return l.unichar(8), 0, true
2010
2011         case '0', '1', '2', '3', '4', '5', '6', '7':
2012                 x := c - '0'
2013                 for i := 2; i > 0; i-- {
2014                         c = l.getr()
2015                         if c >= '0' && c <= '7' {
2016                                 x = x*8 + c - '0'
2017                                 continue
2018                         }
2019
2020                         Yyerror("non-octal character in escape sequence: %c", c)
2021                         l.ungetr(c)
2022                 }
2023
2024                 if x > 255 {
2025                         Yyerror("octal escape value > 255: %d", x)
2026                 }
2027
2028                 return 0, byte(x), true
2029
2030         case 'a':
2031                 c = '\a'
2032         case 'b':
2033                 c = '\b'
2034         case 'f':
2035                 c = '\f'
2036         case 'n':
2037                 c = '\n'
2038         case 'r':
2039                 c = '\r'
2040         case 't':
2041                 c = '\t'
2042         case 'v':
2043                 c = '\v'
2044         case '\\':
2045                 c = '\\'
2046
2047         default:
2048                 if c != quote {
2049                         Yyerror("unknown escape sequence: %c", c)
2050                 }
2051         }
2052
2053         return c, 0, true
2054 }
2055
2056 func (l *lexer) unichar(n int) rune {
2057         x := l.hexchar(n)
2058         if x > utf8.MaxRune || 0xd800 <= x && x < 0xe000 {
2059                 Yyerror("invalid Unicode code point in escape sequence: %#x", x)
2060                 x = utf8.RuneError
2061         }
2062         return rune(x)
2063 }
2064
2065 func (l *lexer) hexchar(n int) uint32 {
2066         var x uint32
2067
2068         for ; n > 0; n-- {
2069                 var d uint32
2070                 switch c := l.getr(); {
2071                 case isDigit(c):
2072                         d = uint32(c - '0')
2073                 case 'a' <= c && c <= 'f':
2074                         d = uint32(c - 'a' + 10)
2075                 case 'A' <= c && c <= 'F':
2076                         d = uint32(c - 'A' + 10)
2077                 default:
2078                         Yyerror("non-hex character in escape sequence: %c", c)
2079                         l.ungetr(c)
2080                         return x
2081                 }
2082                 x = x*16 + d
2083         }
2084
2085         return x
2086 }
2087
2088 var basicTypes = [...]struct {
2089         name  string
2090         etype EType
2091 }{
2092         {"int8", TINT8},
2093         {"int16", TINT16},
2094         {"int32", TINT32},
2095         {"int64", TINT64},
2096         {"uint8", TUINT8},
2097         {"uint16", TUINT16},
2098         {"uint32", TUINT32},
2099         {"uint64", TUINT64},
2100         {"float32", TFLOAT32},
2101         {"float64", TFLOAT64},
2102         {"complex64", TCOMPLEX64},
2103         {"complex128", TCOMPLEX128},
2104         {"bool", TBOOL},
2105         {"string", TSTRING},
2106         {"any", TANY},
2107 }
2108
2109 var builtinFuncs = [...]struct {
2110         name string
2111         op   Op
2112 }{
2113         {"append", OAPPEND},
2114         {"cap", OCAP},
2115         {"close", OCLOSE},
2116         {"complex", OCOMPLEX},
2117         {"copy", OCOPY},
2118         {"delete", ODELETE},
2119         {"imag", OIMAG},
2120         {"len", OLEN},
2121         {"make", OMAKE},
2122         {"new", ONEW},
2123         {"panic", OPANIC},
2124         {"print", OPRINT},
2125         {"println", OPRINTN},
2126         {"real", OREAL},
2127         {"recover", ORECOVER},
2128 }
2129
2130 // lexinit initializes known symbols and the basic types.
2131 func lexinit() {
2132         for _, s := range basicTypes {
2133                 etype := s.etype
2134                 if int(etype) >= len(Types) {
2135                         Fatalf("lexinit: %s bad etype", s.name)
2136                 }
2137                 s2 := Pkglookup(s.name, builtinpkg)
2138                 t := Types[etype]
2139                 if t == nil {
2140                         t = typ(etype)
2141                         t.Sym = s2
2142                         if etype != TANY && etype != TSTRING {
2143                                 dowidth(t)
2144                         }
2145                         Types[etype] = t
2146                 }
2147                 s2.Def = typenod(t)
2148                 s2.Def.Name = new(Name)
2149         }
2150
2151         for _, s := range builtinFuncs {
2152                 // TODO(marvin): Fix Node.EType type union.
2153                 s2 := Pkglookup(s.name, builtinpkg)
2154                 s2.Def = Nod(ONAME, nil, nil)
2155                 s2.Def.Sym = s2
2156                 s2.Def.Etype = EType(s.op)
2157         }
2158
2159         // logically, the type of a string literal.
2160         // types[TSTRING] is the named type string
2161         // (the type of x in var x string or var x = "hello").
2162         // this is the ideal form
2163         // (the type of x in const x = "hello").
2164         idealstring = typ(TSTRING)
2165
2166         idealbool = typ(TBOOL)
2167
2168         s := Pkglookup("true", builtinpkg)
2169         s.Def = Nodbool(true)
2170         s.Def.Sym = Lookup("true")
2171         s.Def.Name = new(Name)
2172         s.Def.Type = idealbool
2173
2174         s = Pkglookup("false", builtinpkg)
2175         s.Def = Nodbool(false)
2176         s.Def.Sym = Lookup("false")
2177         s.Def.Name = new(Name)
2178         s.Def.Type = idealbool
2179
2180         s = Lookup("_")
2181         s.Block = -100
2182         s.Def = Nod(ONAME, nil, nil)
2183         s.Def.Sym = s
2184         Types[TBLANK] = typ(TBLANK)
2185         s.Def.Type = Types[TBLANK]
2186         nblank = s.Def
2187
2188         s = Pkglookup("_", builtinpkg)
2189         s.Block = -100
2190         s.Def = Nod(ONAME, nil, nil)
2191         s.Def.Sym = s
2192         Types[TBLANK] = typ(TBLANK)
2193         s.Def.Type = Types[TBLANK]
2194
2195         Types[TNIL] = typ(TNIL)
2196         s = Pkglookup("nil", builtinpkg)
2197         var v Val
2198         v.U = new(NilVal)
2199         s.Def = nodlit(v)
2200         s.Def.Sym = s
2201         s.Def.Name = new(Name)
2202
2203         s = Pkglookup("iota", builtinpkg)
2204         s.Def = Nod(OIOTA, nil, nil)
2205         s.Def.Sym = s
2206         s.Def.Name = new(Name)
2207 }
2208
2209 func lexinit1() {
2210         // t = interface { Error() string }
2211         rcvr := typ(TSTRUCT)
2212
2213         rcvr.Type = typ(TFIELD)
2214         rcvr.Type.Type = Ptrto(typ(TSTRUCT))
2215         rcvr.Funarg = true
2216         in := typ(TSTRUCT)
2217         in.Funarg = true
2218         out := typ(TSTRUCT)
2219         out.Type = typ(TFIELD)
2220         out.Type.Type = Types[TSTRING]
2221         out.Funarg = true
2222         f := typ(TFUNC)
2223         *getthis(f) = rcvr
2224         *Getoutarg(f) = out
2225         *getinarg(f) = in
2226         f.Thistuple = 1
2227         f.Intuple = 0
2228         f.Outnamed = false
2229         f.Outtuple = 1
2230         t := typ(TINTER)
2231         t.Type = typ(TFIELD)
2232         t.Type.Sym = Lookup("Error")
2233         t.Type.Type = f
2234
2235         // error type
2236         s := Pkglookup("error", builtinpkg)
2237         errortype = t
2238         errortype.Sym = s
2239         s.Def = typenod(errortype)
2240
2241         // byte alias
2242         s = Pkglookup("byte", builtinpkg)
2243         bytetype = typ(TUINT8)
2244         bytetype.Sym = s
2245         s.Def = typenod(bytetype)
2246         s.Def.Name = new(Name)
2247
2248         // rune alias
2249         s = Pkglookup("rune", builtinpkg)
2250         runetype = typ(TINT32)
2251         runetype.Sym = s
2252         s.Def = typenod(runetype)
2253         s.Def.Name = new(Name)
2254
2255         // backend-specific builtin types (e.g. int).
2256         for i := range Thearch.Typedefs {
2257                 s := Pkglookup(Thearch.Typedefs[i].Name, builtinpkg)
2258                 s.Def = typenod(Types[Thearch.Typedefs[i].Etype])
2259                 s.Def.Name = new(Name)
2260                 s.Origpkg = builtinpkg
2261         }
2262 }
2263
2264 func lexfini() {
2265         for _, s := range builtinpkg.Syms {
2266                 if s.Def == nil {
2267                         continue
2268                 }
2269                 s1 := Lookup(s.Name)
2270                 if s1.Def != nil {
2271                         continue
2272                 }
2273
2274                 s1.Def = s.Def
2275                 s1.Block = s.Block
2276         }
2277
2278         nodfp = Nod(ONAME, nil, nil)
2279         nodfp.Type = Types[TINT32]
2280         nodfp.Xoffset = 0
2281         nodfp.Class = PPARAM
2282         nodfp.Sym = Lookup(".fp")
2283 }
2284
2285 var lexn = map[rune]string{
2286         LANDAND:    "ANDAND",
2287         LANDNOT:    "ANDNOT",
2288         LASOP:      "ASOP",
2289         LBREAK:     "BREAK",
2290         LCASE:      "CASE",
2291         LCHAN:      "CHAN",
2292         LCOLAS:     "COLAS",
2293         LCOMM:      "<-",
2294         LCONST:     "CONST",
2295         LCONTINUE:  "CONTINUE",
2296         LDDD:       "...",
2297         LDEFAULT:   "DEFAULT",
2298         LDEFER:     "DEFER",
2299         LELSE:      "ELSE",
2300         LEQ:        "EQ",
2301         LFALL:      "FALL",
2302         LFOR:       "FOR",
2303         LFUNC:      "FUNC",
2304         LGE:        "GE",
2305         LGO:        "GO",
2306         LGOTO:      "GOTO",
2307         LGT:        "GT",
2308         LIF:        "IF",
2309         LIMPORT:    "IMPORT",
2310         LINCOP:     "INCOP",
2311         LINTERFACE: "INTERFACE",
2312         LLE:        "LE",
2313         LLITERAL:   "LITERAL",
2314         LLSH:       "LSH",
2315         LLT:        "LT",
2316         LMAP:       "MAP",
2317         LNAME:      "NAME",
2318         LNE:        "NE",
2319         LOROR:      "OROR",
2320         LPACKAGE:   "PACKAGE",
2321         LRANGE:     "RANGE",
2322         LRETURN:    "RETURN",
2323         LRSH:       "RSH",
2324         LSELECT:    "SELECT",
2325         LSTRUCT:    "STRUCT",
2326         LSWITCH:    "SWITCH",
2327         LTYPE:      "TYPE",
2328         LVAR:       "VAR",
2329 }
2330
2331 func lexname(lex rune) string {
2332         if s, ok := lexn[lex]; ok {
2333                 return s
2334         }
2335         return fmt.Sprintf("LEX-%d", lex)
2336 }
2337
2338 func pkgnotused(lineno int, path string, name string) {
2339         // If the package was imported with a name other than the final
2340         // import path element, show it explicitly in the error message.
2341         // Note that this handles both renamed imports and imports of
2342         // packages containing unconventional package declarations.
2343         // Note that this uses / always, even on Windows, because Go import
2344         // paths always use forward slashes.
2345         elem := path
2346         if i := strings.LastIndex(elem, "/"); i >= 0 {
2347                 elem = elem[i+1:]
2348         }
2349         if name == "" || elem == name {
2350                 yyerrorl(int(lineno), "imported and not used: %q", path)
2351         } else {
2352                 yyerrorl(int(lineno), "imported and not used: %q as %s", path, name)
2353         }
2354 }
2355
2356 func mkpackage(pkgname string) {
2357         if localpkg.Name == "" {
2358                 if pkgname == "_" {
2359                         Yyerror("invalid package name _")
2360                 }
2361                 localpkg.Name = pkgname
2362         } else {
2363                 if pkgname != localpkg.Name {
2364                         Yyerror("package %s; expected %s", pkgname, localpkg.Name)
2365                 }
2366                 for _, s := range localpkg.Syms {
2367                         if s.Def == nil {
2368                                 continue
2369                         }
2370                         if s.Def.Op == OPACK {
2371                                 // throw away top-level package name leftover
2372                                 // from previous file.
2373                                 // leave s->block set to cause redeclaration
2374                                 // errors if a conflicting top-level name is
2375                                 // introduced by a different file.
2376                                 if !s.Def.Used && nsyntaxerrors == 0 {
2377                                         pkgnotused(int(s.Def.Lineno), s.Def.Name.Pkg.Path, s.Name)
2378                                 }
2379                                 s.Def = nil
2380                                 continue
2381                         }
2382
2383                         if s.Def.Sym != s {
2384                                 // throw away top-level name left over
2385                                 // from previous import . "x"
2386                                 if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
2387                                         pkgnotused(int(s.Def.Name.Pack.Lineno), s.Def.Name.Pack.Name.Pkg.Path, "")
2388                                         s.Def.Name.Pack.Used = true
2389                                 }
2390
2391                                 s.Def = nil
2392                                 continue
2393                         }
2394                 }
2395         }
2396
2397         if outfile == "" {
2398                 p := infile
2399                 if i := strings.LastIndex(p, "/"); i >= 0 {
2400                         p = p[i+1:]
2401                 }
2402                 if Ctxt.Windows != 0 {
2403                         if i := strings.LastIndex(p, `\`); i >= 0 {
2404                                 p = p[i+1:]
2405                         }
2406                 }
2407                 if i := strings.LastIndex(p, "."); i >= 0 {
2408                         p = p[:i]
2409                 }
2410                 suffix := ".o"
2411                 if writearchive > 0 {
2412                         suffix = ".a"
2413                 }
2414                 outfile = p + suffix
2415         }
2416 }