scanner.mx raw
1 package syntax
2
3 import (
4 "io"
5 "mxc/token"
6 "unicode"
7 "unicode/utf8"
8 )
9
10 const (
11 comments uint32 = 1 << iota
12 directives
13 )
14
15 var sharedUtab *unicode.Tables
16
17 func getSharedUtab() (p *unicode.Tables) {
18 if sharedUtab == nil {
19 sharedUtab = unicode.NewTables()
20 }
21 return sharedUtab
22 }
23
24
25 type Scanner struct {
26 Source
27 mode uint32
28 nlsemi bool
29
30 Line, Col uint32
31 Blank bool
32 Tok token.Token
33 Lit string
34 Bad bool
35 Kind token.LitKind
36 Op token.Operator
37 Prec int32
38
39 keywordMap [1 << 6]token.Token
40 keywordsReady bool
41 utab *unicode.Tables
42 }
43
44 func (s *Scanner) Init(src io.Reader, errh func(line, col uint32, msg string), mode uint32) {
45 s.Source.init(src, errh)
46 s.mode = mode
47 s.nlsemi = false
48 s.utab = getSharedUtab()
49 s.initKeywords()
50 }
51
52 func (s *Scanner) InitBytes(src []byte, errh func(line, col uint32, msg string), mode uint32) {
53 s.Source.initBytes(src, errh)
54 s.mode = 0
55 s.nlsemi = false
56 s.utab = getSharedUtab()
57 s.initKeywords()
58 }
59
60 func (s *Scanner) Errorf(msg string) {
61 s.error(msg)
62 }
63
64 func (s *Scanner) ErrorAtf(offset int32, msg string) {
65 s.errh(s.line, s.col+uint32(offset), msg)
66 }
67
68 func (s *Scanner) SetLit(kind token.LitKind, ok bool) {
69 s.nlsemi = true
70 s.Tok = token.Literal
71 s.Lit = string(s.segmentCopy())
72 s.Bad = !ok
73 s.Kind = kind
74 }
75
76 func (s *Scanner) Next() {
77 nlsemi := s.nlsemi
78 s.nlsemi = false
79
80 redo:
81 s.stop()
82 startLine, startCol := s.pos()
83 for s.ch == ' ' || s.ch == '\t' || s.ch == '\n' && !nlsemi || s.ch == '\r' {
84 s.nextch()
85 }
86
87 s.Line, s.Col = s.pos()
88 s.Blank = s.line > startLine || startCol == token.Colbase
89 s.start()
90 if IsLetter(s.ch) || s.ch >= utf8.RuneSelf && s.AtIdentChar(true) {
91 s.nextch()
92 s.Ident()
93 return
94 }
95
96 switch s.ch {
97 case -1:
98 if nlsemi {
99 s.Lit = "EOF"
100 s.Tok = token.Semi
101 break
102 }
103 s.Tok = token.EOF
104
105 case '\n':
106 s.nextch()
107 s.Lit = "newline"
108 s.Tok = token.Semi
109
110 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
111 s.Number(false)
112
113 case '"':
114 s.stdString()
115
116 case '`':
117 s.rawString()
118
119 case '\'':
120 s.rune()
121
122 case '(':
123 s.nextch()
124 s.Tok = token.Lparen
125
126 case '[':
127 s.nextch()
128 s.Tok = token.Lbrack
129
130 case '{':
131 s.nextch()
132 s.Tok = token.Lbrace
133
134 case ',':
135 s.nextch()
136 s.Tok = token.Comma
137
138 case ';':
139 s.nextch()
140 s.Lit = "semicolon"
141 s.Tok = token.Semi
142
143 case ')':
144 s.nextch()
145 s.nlsemi = true
146 s.Tok = token.Rparen
147
148 case ']':
149 s.nextch()
150 s.nlsemi = true
151 s.Tok = token.Rbrack
152
153 case '}':
154 s.nextch()
155 s.nlsemi = true
156 s.Tok = token.Rbrace
157
158 case ':':
159 s.nextch()
160 if s.ch == '=' {
161 s.nextch()
162 s.Tok = token.Define
163 break
164 }
165 s.Tok = token.Colon
166
167 case '.':
168 s.nextch()
169 if IsDecimal(s.ch) {
170 s.Number(true)
171 break
172 }
173 if s.ch == '.' {
174 s.nextch()
175 if s.ch == '.' {
176 s.nextch()
177 s.Tok = token.DotDotDot
178 break
179 }
180 s.rewind()
181 s.nextch()
182 }
183 s.Tok = token.Dot
184
185 case '+':
186 s.nextch()
187 s.Op, s.Prec = token.Add, token.PrecAdd
188 if s.ch != '+' {
189 s.assignOp()
190 return
191 }
192 s.nextch()
193 s.nlsemi = true
194 s.Tok = token.IncOp
195
196 case '-':
197 s.nextch()
198 s.Op, s.Prec = token.Sub, token.PrecAdd
199 if s.ch != '-' {
200 s.assignOp()
201 return
202 }
203 s.nextch()
204 s.nlsemi = true
205 s.Tok = token.IncOp
206
207 case '*':
208 s.nextch()
209 s.Op, s.Prec = token.Mul, token.PrecMul
210 if s.ch == '=' {
211 s.nextch()
212 s.Tok = token.AssignOp
213 break
214 }
215 s.Tok = token.Star
216
217 case '/':
218 s.nextch()
219 if s.ch == '/' {
220 s.nextch()
221 s.lineComment()
222 goto redo
223 }
224 if s.ch == '*' {
225 s.nextch()
226 s.fullComment()
227 if line, _ := s.pos(); line > s.Line && nlsemi {
228 s.Lit = "newline"
229 s.Tok = token.Semi
230 break
231 }
232 goto redo
233 }
234 s.Op, s.Prec = token.Div, token.PrecMul
235 if s.ch == '=' {
236 s.nextch()
237 s.Tok = token.AssignOp
238 } else {
239 s.Tok = token.OperatorType
240 }
241
242 case '%':
243 s.nextch()
244 s.Op, s.Prec = token.Rem, token.PrecMul
245 if s.ch == '=' {
246 s.nextch()
247 s.Tok = token.AssignOp
248 } else {
249 s.Tok = token.OperatorType
250 }
251
252 case '&':
253 s.nextch()
254 if s.ch == '&' {
255 s.nextch()
256 s.Op, s.Prec = token.AndAnd, token.PrecAndAnd
257 s.Tok = token.OperatorType
258 break
259 }
260 s.Op, s.Prec = token.And, token.PrecMul
261 if s.ch == '^' {
262 s.nextch()
263 s.Op = token.AndNot
264 }
265 if s.ch == '=' {
266 s.nextch()
267 s.Tok = token.AssignOp
268 } else {
269 s.Tok = token.OperatorType
270 }
271
272 case '|':
273 s.nextch()
274 if s.ch == '|' {
275 s.nextch()
276 s.Op, s.Prec = token.OrOr, token.PrecOrOr
277 s.Tok = token.OperatorType
278 break
279 }
280 s.Op, s.Prec = token.Or, token.PrecAdd
281 if s.ch == '=' {
282 s.nextch()
283 s.Tok = token.AssignOp
284 } else {
285 s.Tok = token.OperatorType
286 }
287
288 case '^':
289 s.nextch()
290 s.Op, s.Prec = token.Xor, token.PrecAdd
291 if s.ch == '=' {
292 s.nextch()
293 s.Tok = token.AssignOp
294 } else {
295 s.Tok = token.OperatorType
296 }
297
298 case '<':
299 s.nextch()
300 if s.ch == '=' {
301 s.nextch()
302 s.Op, s.Prec = token.Leq, token.PrecCmp
303 s.Tok = token.OperatorType
304 break
305 }
306 if s.ch == '<' {
307 s.nextch()
308 s.Op, s.Prec = token.Shl, token.PrecMul
309 s.assignOp()
310 return
311 }
312 if s.ch == '-' {
313 s.nextch()
314 s.Tok = token.Arrow
315 break
316 }
317 s.Op, s.Prec = token.Lss, token.PrecCmp
318 s.Tok = token.OperatorType
319
320 case '>':
321 s.nextch()
322 if s.ch == '=' {
323 s.nextch()
324 s.Op, s.Prec = token.Geq, token.PrecCmp
325 s.Tok = token.OperatorType
326 break
327 }
328 if s.ch == '>' {
329 s.nextch()
330 s.Op, s.Prec = token.Shr, token.PrecMul
331 s.assignOp()
332 return
333 }
334 s.Op, s.Prec = token.Gtr, token.PrecCmp
335 s.Tok = token.OperatorType
336
337 case '=':
338 s.nextch()
339 if s.ch == '=' {
340 s.nextch()
341 s.Op, s.Prec = token.Eql, token.PrecCmp
342 s.Tok = token.OperatorType
343 break
344 }
345 s.Tok = token.Assign
346
347 case '!':
348 s.nextch()
349 if s.ch == '=' {
350 s.nextch()
351 s.Op, s.Prec = token.Neq, token.PrecCmp
352 s.Tok = token.OperatorType
353 break
354 }
355 s.Op, s.Prec = token.Not, 0
356 s.Tok = token.OperatorType
357
358 case '~':
359 s.nextch()
360 s.Op, s.Prec = token.Tilde, 0
361 s.Tok = token.OperatorType
362
363 default:
364 s.Errorf("invalid character " | fmtRuneU(s.ch))
365 s.nextch()
366 goto redo
367 }
368
369 return
370 }
371
372 func (s *Scanner) assignOp() {
373 if s.ch == '=' {
374 s.nextch()
375 s.Tok = token.AssignOp
376 return
377 }
378 s.Tok = token.OperatorType
379 }
380
381 func (s *Scanner) Ident() {
382 for IsLetter(s.ch) || IsDecimal(s.ch) {
383 s.nextch()
384 }
385
386 if s.ch >= utf8.RuneSelf {
387 for s.AtIdentChar(false) {
388 s.nextch()
389 }
390 }
391
392 lit := s.segment()
393 if len(lit) >= 2 {
394 h := (uint32(lit[0])<<4 ^ uint32(lit[1]) + uint32(len(lit))) & 63
395 if tok := s.keywordMap[h]; tok != 0 && tokStrFast(tok) == string(lit) {
396 s.nlsemi = token.Contains(1<<token.Break|1<<token.Continue|1<<token.Fallthrough|1<<token.Return, tok)
397 s.Tok = tok
398 return
399 }
400 }
401
402 s.nlsemi = true
403 c := []byte{:len(lit)}
404 copy(c, lit)
405 s.Lit = string(c)
406 s.Tok = token.NameType
407 }
408
409 func tokStrFast(tok token.Token) (s string) {
410 idx := [48]uint8{0, 3, 7, 14, 16, 19, 23, 24, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 42, 47, 51, 55, 60, 68, 75, 80, 84, 95, 98, 102, 104, 108, 110, 116, 125, 128, 135, 140, 146, 152, 158, 164, 168, 171, 171}
411 return token.TokenName[idx[tok-1]:idx[tok]]
412 }
413
414 func (s *Scanner) AtIdentChar(first bool) (ok bool) {
415 switch {
416 case s.utab.IsLetter(s.ch) || s.ch == '_':
417 case s.utab.IsDigit(s.ch):
418 if first {
419 s.Errorf("identifier cannot begin with digit " | fmtRuneU(s.ch))
420 }
421 case s.ch >= utf8.RuneSelf:
422 s.Errorf("invalid character " | fmtRuneU(s.ch) | " in identifier")
423 default:
424 return false
425 }
426 return true
427 }
428
429 func (s *Scanner) initKeywords() {
430 if s.keywordsReady {
431 return
432 }
433 s.keywordsReady = true
434 for tok := token.Break; tok <= token.Var; tok++ {
435 b := []byte(tok.String())
436 h := (uint32(b[0])<<4 ^ uint32(b[1]) + uint32(len(b))) & 63
437 if s.keywordMap[h] != 0 {
438 panic("imperfect hash")
439 }
440 s.keywordMap[h] = tok
441 }
442 }
443
444 func Lower(ch rune) (r rune) { return ('a' - 'A') | ch }
445 func IsLetter(ch rune) (ok bool) { return 'a' <= Lower(ch) && Lower(ch) <= 'z' || ch == '_' }
446 func IsDecimal(ch rune) (ok bool) { return '0' <= ch && ch <= '9' }
447 func IsHex(ch rune) (ok bool) { return '0' <= ch && ch <= '9' || 'a' <= Lower(ch) && Lower(ch) <= 'f' }
448
449 func (s *Scanner) Digits(base int32, invalid *int32) (digsep int32) {
450 if base <= 10 {
451 max := rune('0' + base)
452 for IsDecimal(s.ch) || s.ch == '_' {
453 ds := int32(1)
454 if s.ch == '_' {
455 ds = 2
456 } else if s.ch >= max && *invalid < 0 {
457 _, col := s.pos()
458 *invalid = int32(col - s.col)
459 }
460 digsep |= ds
461 s.nextch()
462 }
463 } else {
464 for IsHex(s.ch) || s.ch == '_' {
465 ds := int32(1)
466 if s.ch == '_' {
467 ds = 2
468 }
469 digsep |= ds
470 s.nextch()
471 }
472 }
473 return
474 }
475
476 func (s *Scanner) Number(seenPoint bool) {
477 ok := true
478 kind := token.IntLit
479 base := int32(10)
480 prefix := rune(0)
481 digsep := int32(0)
482 invalid := int32(-1)
483
484 if !seenPoint {
485 if s.ch == '0' {
486 s.nextch()
487 switch Lower(s.ch) {
488 case 'x':
489 s.nextch()
490 base, prefix = 16, 'x'
491 case 'o':
492 s.nextch()
493 base, prefix = 8, 'o'
494 case 'b':
495 s.nextch()
496 base, prefix = 2, 'b'
497 default:
498 base, prefix = 8, '0'
499 digsep = 1
500 }
501 }
502 digsep |= s.Digits(base, &invalid)
503 if s.ch == '.' {
504 if prefix == 'o' || prefix == 'b' {
505 s.Errorf("invalid radix point in " | baseName(base) | " literal")
506 ok = false
507 }
508 s.nextch()
509 seenPoint = true
510 }
511 }
512
513 if seenPoint {
514 kind = token.FloatLit
515 digsep |= s.Digits(base, &invalid)
516 }
517
518 if digsep&1 == 0 && ok {
519 s.Errorf(baseName(base) | " literal has no digits")
520 ok = false
521 }
522
523 if e := Lower(s.ch); e == 'e' || e == 'p' {
524 if ok {
525 switch {
526 case e == 'e' && prefix != 0 && prefix != '0':
527 s.Errorf(fmtQuoteRune(s.ch) | " exponent requires decimal mantissa")
528 ok = false
529 case e == 'p' && prefix != 'x':
530 s.Errorf(fmtQuoteRune(s.ch) | " exponent requires hexadecimal mantissa")
531 ok = false
532 }
533 }
534 s.nextch()
535 kind = token.FloatLit
536 if s.ch == '+' || s.ch == '-' {
537 s.nextch()
538 }
539 digsep = s.Digits(10, nil) | digsep&2
540 if digsep&1 == 0 && ok {
541 s.Errorf("exponent has no digits")
542 ok = false
543 }
544 } else if prefix == 'x' && kind == token.FloatLit && ok {
545 s.Errorf("hexadecimal mantissa requires a 'p' exponent")
546 ok = false
547 }
548
549 if s.ch == 'i' {
550 kind = token.ImagLit
551 s.nextch()
552 }
553
554 s.SetLit(kind, ok)
555
556 if kind == token.IntLit && invalid >= 0 && ok {
557 s.ErrorAtf(invalid, "invalid digit " | fmtQuoteRune(rune(s.Lit[invalid])) | " in " | baseName(base) | " literal")
558 ok = false
559 }
560
561 if digsep&2 != 0 && ok {
562 if i := invalidSep(s.Lit); i >= 0 {
563 s.ErrorAtf(i, "'_' must separate successive digits")
564 ok = false
565 }
566 }
567
568 s.Bad = !ok
569 }
570
571 func baseName(base int32) (s string) {
572 switch base {
573 case 2:
574 return "binary"
575 case 8:
576 return "octal"
577 case 10:
578 return "decimal"
579 case 16:
580 return "hexadecimal"
581 }
582 panic("invalid base")
583 }
584
585 func invalidSep(x string) (n int32) {
586 x1 := ' '
587 d := '.'
588 i := int32(0)
589
590 if len(x) >= 2 && x[0] == '0' {
591 x1 = Lower(rune(x[1]))
592 if x1 == 'x' || x1 == 'o' || x1 == 'b' {
593 d = '0'
594 i = 2
595 }
596 }
597
598 for ; i < int32(len(x)); i++ {
599 p := d
600 d = rune(x[i])
601 switch {
602 case d == '_':
603 if p != '0' {
604 return i
605 }
606 case IsDecimal(d) || x1 == 'x' && IsHex(d):
607 d = '0'
608 default:
609 if p == '_' {
610 return i - 1
611 }
612 d = '.'
613 }
614 }
615 if d == '_' {
616 return int32(len(x)) - 1
617 }
618
619 return -1
620 }
621
622 func (s *Scanner) rune() {
623 ok := true
624 s.nextch()
625
626 n := 0
627 for ; ; n++ {
628 if s.ch == '\'' {
629 if ok {
630 if n == 0 {
631 s.Errorf("empty rune literal or unescaped '")
632 ok = false
633 } else if n != 1 {
634 s.ErrorAtf(0, "more than one character in rune literal")
635 ok = false
636 }
637 }
638 s.nextch()
639 break
640 }
641 if s.ch == '\\' {
642 s.nextch()
643 if !s.escape('\'') {
644 ok = false
645 }
646 continue
647 }
648 if s.ch == '\n' {
649 if ok {
650 s.Errorf("newline in rune literal")
651 ok = false
652 }
653 break
654 }
655 if s.ch < 0 {
656 if ok {
657 s.ErrorAtf(0, "rune literal not terminated")
658 ok = false
659 }
660 break
661 }
662 s.nextch()
663 }
664
665 s.SetLit(token.RuneLit, ok)
666 }
667
668 func (s *Scanner) stdString() {
669 ok := true
670 s.nextch()
671
672 for {
673 if s.ch == '"' {
674 s.nextch()
675 break
676 }
677 if s.ch == '\\' {
678 s.nextch()
679 if !s.escape('"') {
680 ok = false
681 }
682 continue
683 }
684 if s.ch == '\n' {
685 s.Errorf("newline in string")
686 ok = false
687 break
688 }
689 if s.ch < 0 {
690 s.ErrorAtf(0, "string not terminated")
691 ok = false
692 break
693 }
694 s.nextch()
695 }
696
697 s.SetLit(token.StringLit, ok)
698 }
699
700 func (s *Scanner) rawString() {
701 ok := true
702 s.nextch()
703
704 for {
705 if s.ch == '`' {
706 s.nextch()
707 break
708 }
709 if s.ch < 0 {
710 s.ErrorAtf(0, "string not terminated")
711 ok = false
712 break
713 }
714 s.nextch()
715 }
716
717 s.SetLit(token.StringLit, ok)
718 }
719
720 func (s *Scanner) comment(text string) {
721 s.ErrorAtf(0, text)
722 }
723
724 func (s *Scanner) skipLine() {
725 for s.ch >= 0 && s.ch != '\n' {
726 s.nextch()
727 }
728 }
729
730 func (s *Scanner) lineComment() {
731 if s.mode&comments != 0 {
732 s.skipLine()
733 s.comment(string(s.segment()))
734 return
735 }
736
737 if s.mode&directives == 0 || (s.ch != 'g' && s.ch != 'l') {
738 s.stop()
739 s.skipLine()
740 return
741 }
742
743 prefix := "go:"
744 if s.ch == 'l' {
745 prefix = "line "
746 }
747
748 for _, r := range prefix {
749 if s.ch != rune(r) {
750 s.stop()
751 s.skipLine()
752 return
753 }
754 s.nextch()
755 }
756 s.skipLine()
757 s.comment(string(s.segment()))
758 }
759
760 func (s *Scanner) skipComment() (ok bool) {
761 for s.ch >= 0 {
762 for s.ch == '*' {
763 s.nextch()
764 if s.ch == '/' {
765 s.nextch()
766 return true
767 }
768 }
769 s.nextch()
770 }
771 s.ErrorAtf(0, "comment not terminated")
772 return false
773 }
774
775 func (s *Scanner) fullComment() {
776 if s.mode&comments != 0 {
777 if s.skipComment() {
778 s.comment(string(s.segment()))
779 }
780 return
781 }
782
783 if s.mode&directives == 0 || s.ch != 'l' {
784 s.stop()
785 s.skipComment()
786 return
787 }
788
789 const prefix = "line "
790
791 for _, r := range prefix {
792 if s.ch != rune(r) {
793 s.stop()
794 s.skipComment()
795 return
796 }
797 s.nextch()
798 }
799 if s.skipComment() {
800 s.comment(string(s.segment()))
801 }
802 }
803
804 func (s *Scanner) escape(quote rune) (ok bool) {
805 var n int32
806 var base, max uint32
807
808 switch s.ch {
809 case quote, 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\':
810 s.nextch()
811 return true
812 case '0', '1', '2', '3', '4', '5', '6', '7':
813 n, base, max = 3, 8, 255
814 case 'x':
815 s.nextch()
816 n, base, max = 2, 16, 255
817 case 'u':
818 s.nextch()
819 n, base, max = 4, 16, unicode.MaxRune
820 case 'U':
821 s.nextch()
822 n, base, max = 8, 16, unicode.MaxRune
823 default:
824 if s.ch < 0 {
825 return true
826 }
827 s.Errorf("unknown escape")
828 return false
829 }
830
831 var x uint32
832 for i := n; i > 0; i-- {
833 if s.ch < 0 {
834 return true
835 }
836 d := base
837 if IsDecimal(s.ch) {
838 d = uint32(s.ch) - '0'
839 } else if 'a' <= Lower(s.ch) && Lower(s.ch) <= 'f' {
840 d = uint32(Lower(s.ch)) - 'a' + 10
841 }
842 if d >= base {
843 s.Errorf("invalid character " | fmtQuoteRune(s.ch) | " in " | baseName(int32(base)) | " escape")
844 return false
845 }
846 x = x*base + d
847 s.nextch()
848 }
849
850 if x > max && base == 8 {
851 s.Errorf("octal escape value " | token.ItoaU32(x) | " > 255")
852 return false
853 }
854
855 if x > max || 0xD800 <= x && x < 0xE000 {
856 s.Errorf("escape is invalid Unicode code point " | fmtRuneU(rune(x)))
857 return false
858 }
859
860 return true
861 }
862
863 func String(n Node) (s string) {
864 switch n.(type) {
865 case *Name:
866 return "Name"
867 case *BasicLit:
868 return "BasicLit"
869 case *CompositeLit:
870 return "CompositeLit"
871 case *FuncLit:
872 return "FuncLit"
873 case *ParenExpr:
874 return "ParenExpr"
875 case *SelectorExpr:
876 return "SelectorExpr"
877 case *IndexExpr:
878 return "IndexExpr"
879 case *SliceExpr:
880 return "SliceExpr"
881 case *AssertExpr:
882 return "AssertExpr"
883 case *TypeSwitchGuard:
884 return "TypeSwitchGuard"
885 case *Operation:
886 return "Operation"
887 case *CallExpr:
888 return "CallExpr"
889 case *ListExpr:
890 return "ListExpr"
891 case *ArrayType:
892 return "ArrayType"
893 case *SliceType:
894 return "SliceType"
895 case *DotsType:
896 return "DotsType"
897 case *StructType:
898 return "StructType"
899 case *InterfaceType:
900 return "InterfaceType"
901 case *FuncType:
902 return "FuncType"
903 case *ChanType:
904 return "ChanType"
905 case *MapType:
906 return "MapType"
907 case *BadExpr:
908 return "BadExpr"
909 case *EmptyStmt:
910 return "EmptyStmt"
911 case *LabeledStmt:
912 return "LabeledStmt"
913 case *BlockStmt:
914 return "BlockStmt"
915 case *ExprStmt:
916 return "ExprStmt"
917 case *SendStmt:
918 return "SendStmt"
919 case *DeclStmt:
920 return "DeclStmt"
921 case *AssignStmt:
922 return "AssignStmt"
923 case *BranchStmt:
924 return "BranchStmt"
925 case *CallStmt:
926 return "CallStmt"
927 case *ReturnStmt:
928 return "ReturnStmt"
929 case *IfStmt:
930 return "IfStmt"
931 case *ForStmt:
932 return "ForStmt"
933 case *SwitchStmt:
934 return "SwitchStmt"
935 case *SelectStmt:
936 return "SelectStmt"
937 case *RangeClause:
938 return "RangeClause"
939 case *CaseClause:
940 return "CaseClause"
941 case *CommClause:
942 return "CommClause"
943 case *ImportDecl:
944 return "ImportDecl"
945 case *ConstDecl:
946 return "ConstDecl"
947 case *TypeDecl:
948 return "TypeDecl"
949 case *VarDecl:
950 return "VarDecl"
951 case *FuncDecl:
952 return "FuncDecl"
953 case *File:
954 return "File"
955 }
956 return "Node"
957 }
958
959 func StartPos(n Node) (p token.Pos) {
960 return n.Pos()
961 }
962
963 // fmtRuneU formats a rune as "U+XXXX 'c'" (like %#U).
964 func fmtRuneU(r rune) (s string) {
965 hex := fmtHex32(uint32(r))
966 s := "U+" | hex
967 if r >= 0x20 && r < 0x7f {
968 s = s | " '" | string([]byte{byte(r)}) | "'"
969 }
970 return s
971 }
972
973 // fmtQuoteRune formats a rune as 'c' (like %q for rune).
974 func fmtQuoteRune(r rune) (s string) {
975 if r >= 0x20 && r < 0x7f {
976 return "'" | string([]byte{byte(r)}) | "'"
977 }
978 return "U+" | fmtHex32(uint32(r))
979 }
980
981 // fmtHex32 formats a uint32 as uppercase hex with at least 4 digits.
982 func fmtHex32(v uint32) (s string) {
983 const digits = "0123456789ABCDEF"
984 buf := []byte{:0:8}
985 if v == 0 {
986 return "0000"
987 }
988 for v > 0 {
989 buf = append(buf, digits[v&0xf])
990 v >>= 4
991 }
992 for len(buf) < 4 {
993 buf = append(buf, '0')
994 }
995 for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 {
996 buf[i], buf[j] = buf[j], buf[i]
997 }
998 return string(buf)
999 }
1000