1
16
17
18
19 package build
20
21 import (
22 "bytes"
23 "fmt"
24 "path/filepath"
25 "sort"
26 "strings"
27 "unicode/utf8"
28 )
29
30
31
32
33
34 type FileType int
35
36 const (
37
38 TypeDefault FileType = 1 << iota
39
40 TypeBuild
41
42 TypeWorkspace
43
44 TypeBzl
45
46 TypeModule
47 )
48
49 func (t FileType) String() string {
50 switch t {
51 case TypeDefault:
52 return "default"
53 case TypeBuild:
54 return "BUILD"
55 case TypeWorkspace:
56 return "WORKSPACE"
57 case TypeBzl:
58 return ".bzl"
59 case TypeModule:
60 return "MODULE.bazel"
61 }
62 return "unknown"
63 }
64
65
66
67
68 func ParseBuild(filename string, data []byte) (*File, error) {
69 in := newInput(filename, data)
70 f, err := in.parse()
71 if f != nil {
72 f.Type = TypeBuild
73 }
74 return f, err
75 }
76
77
78
79
80 func ParseWorkspace(filename string, data []byte) (*File, error) {
81 in := newInput(filename, data)
82 f, err := in.parse()
83 if f != nil {
84 f.Type = TypeWorkspace
85 }
86 return f, err
87 }
88
89
90
91
92 func ParseModule(filename string, data []byte) (*File, error) {
93 in := newInput(filename, data)
94 f, err := in.parse()
95 if f != nil {
96 f.Type = TypeModule
97 }
98 return f, err
99 }
100
101
102
103
104 func ParseBzl(filename string, data []byte) (*File, error) {
105 in := newInput(filename, data)
106 f, err := in.parse()
107 if f != nil {
108 f.Type = TypeBzl
109 }
110 return f, err
111 }
112
113
114
115
116 func ParseDefault(filename string, data []byte) (*File, error) {
117 in := newInput(filename, data)
118 f, err := in.parse()
119 if f != nil {
120 f.Type = TypeDefault
121 }
122 return f, err
123 }
124
125 func getFileType(filename string) FileType {
126 if filename == "" {
127 return TypeDefault
128 }
129 basename := strings.ToLower(filepath.Base(filename))
130 if strings.HasSuffix(basename, ".oss") {
131 basename = basename[:len(basename)-4]
132 }
133 if basename == "module.bazel" {
134 return TypeModule
135 }
136 ext := filepath.Ext(basename)
137 switch ext {
138 case ".bzl":
139 return TypeBzl
140 case ".sky":
141 return TypeDefault
142 }
143 base := basename[:len(basename)-len(ext)]
144 switch {
145 case ext == ".build" || base == "build" || strings.HasPrefix(base, "build."):
146 return TypeBuild
147 case ext == ".workspace" || base == "workspace" || strings.HasPrefix(base, "workspace."):
148 return TypeWorkspace
149 }
150 return TypeDefault
151 }
152
153
154
155
156
157 func Parse(filename string, data []byte) (*File, error) {
158 switch getFileType(filename) {
159 case TypeBuild:
160 return ParseBuild(filename, data)
161 case TypeWorkspace:
162 return ParseWorkspace(filename, data)
163 case TypeModule:
164 return ParseModule(filename, data)
165 case TypeBzl:
166 return ParseBzl(filename, data)
167 }
168 return ParseDefault(filename, data)
169 }
170
171
172 type ParseError struct {
173 Message string
174 Filename string
175 Pos Position
176 }
177
178
179 func (e ParseError) Error() string {
180 filename := e.Filename
181 if filename == "" {
182 filename = "<stdin>"
183 }
184 return fmt.Sprintf("%s:%d:%d: %v", filename, e.Pos.Line, e.Pos.LineRune, e.Message)
185 }
186
187
188 type input struct {
189
190 filename string
191 complete []byte
192 remaining []byte
193 token []byte
194 lastToken string
195 pos Position
196 lineComments []Comment
197 suffixComments []Comment
198 depth int
199 cleanLine bool
200 indent int
201 indents []int
202
203
204 file *File
205 parseError error
206
207
208 pre []Expr
209 post []Expr
210 }
211
212 func newInput(filename string, data []byte) *input {
213
214
215
216 data = append(data, '\n')
217
218 return &input{
219 filename: filename,
220 complete: data,
221 remaining: data,
222 pos: Position{Line: 1, LineRune: 1, Byte: 0},
223 cleanLine: true,
224 indents: []int{0},
225 }
226 }
227
228 func (in *input) currentIndent() int {
229 return in.indents[len(in.indents)-1]
230 }
231
232
233 func (in *input) parse() (f *File, err error) {
234
235
236
237
238 defer func() {
239 if e := recover(); e != nil {
240 if e == in.parseError {
241 err = in.parseError
242 } else {
243 err = ParseError{Message: fmt.Sprintf("internal error: %v", e), Filename: in.filename, Pos: in.pos}
244 }
245 }
246 }()
247
248
249 yyParse(in)
250 if in.parseError != nil {
251 return nil, in.parseError
252 }
253 in.file.Path = in.filename
254
255
256 in.assignComments()
257
258 return in.file, nil
259 }
260
261
262
263
264 func (in *input) Error(s string) {
265 if s == "syntax error" && in.lastToken != "" {
266 s += " near " + in.lastToken
267 }
268 in.parseError = ParseError{Message: s, Filename: in.filename, Pos: in.pos}
269 panic(in.parseError)
270 }
271
272
273 func (in *input) eof() bool {
274 return len(in.remaining) == 0
275 }
276
277
278 func (in *input) peekRune() int {
279 if len(in.remaining) == 0 {
280 return 0
281 }
282 r, _ := utf8.DecodeRune(in.remaining)
283 return int(r)
284 }
285
286
287 func (in *input) readRune() int {
288 if len(in.remaining) == 0 {
289 in.Error("internal lexer error: readRune at EOF")
290 }
291 r, size := utf8.DecodeRune(in.remaining)
292 in.remaining = in.remaining[size:]
293 if r == '\n' {
294 in.pos.Line++
295 in.pos.LineRune = 1
296 } else {
297 in.pos.LineRune++
298 }
299 in.pos.Byte += size
300 return int(r)
301 }
302
303
304
305
306 func (in *input) startToken(val *yySymType) {
307 in.token = in.remaining
308 val.tok = ""
309 val.pos = in.pos
310 }
311
312
313
314
315
316
317
318
319 func (in *input) endToken(val *yySymType) {
320 if val.tok == "" {
321 tok := string(in.token[:len(in.token)-len(in.remaining)])
322 val.tok = tok
323 in.lastToken = val.tok
324 }
325 }
326
327
328
329
330
331
332
333
334 func (in *input) Lex(val *yySymType) int {
335
336 countNL := 0
337 for !in.eof() {
338
339
340
341 c := in.peekRune()
342 if c == ' ' || c == '\t' || c == '\r' || c == '\n' {
343 if c == '\n' {
344 in.indent = 0
345 in.cleanLine = true
346 if in.depth == 0 {
347
348 in.startToken(val)
349 in.readRune()
350 in.endToken(val)
351 return '\n'
352 }
353 countNL++
354 } else if c == ' ' && in.cleanLine {
355 in.indent++
356 }
357 in.readRune()
358 continue
359 }
360
361
362 if c == '#' {
363
364
365 in.indent = 0
366 isLineComment := in.cleanLine
367 in.cleanLine = true
368
369
370
371
372
373
374
375
376
377 i := bytes.LastIndex(in.complete[:in.pos.Byte], []byte("\n"))
378 prefix := bytes.TrimSpace(in.complete[i+1 : in.pos.Byte])
379 prefix = bytes.Replace(prefix, []byte{' '}, []byte{}, -1)
380 isSuffix := true
381 if len(prefix) == 0 ||
382 (len(prefix) == 2 && prefix[0] == ')' && prefix[1] == ':') ||
383 prefix[len(prefix)-1] == '[' ||
384 prefix[len(prefix)-1] == '(' ||
385 prefix[len(prefix)-1] == '{' {
386 isSuffix = false
387 }
388
389
390 in.startToken(val)
391 for len(in.remaining) > 0 && in.peekRune() != '\n' {
392 in.readRune()
393 }
394
395 in.endToken(val)
396
397 val.tok = strings.TrimRight(val.tok, "\n")
398 in.lastToken = "comment"
399
400
401
402
403 if in.depth == 0 && isLineComment {
404
405 return _COMMENT
406 }
407
408
409 if countNL > 1 {
410 in.lineComments = append(in.lineComments, Comment{val.pos, ""})
411 }
412 if isSuffix {
413 in.suffixComments = append(in.suffixComments, Comment{val.pos, val.tok})
414 } else {
415 in.lineComments = append(in.lineComments, Comment{val.pos, val.tok})
416 }
417 countNL = 0
418 continue
419 }
420
421 if c == '\\' && len(in.remaining) >= 2 && in.remaining[1] == '\n' {
422
423 in.readRune()
424 in.readRune()
425 continue
426 }
427
428
429 break
430 }
431
432
433
434
435 if in.depth == 0 && in.cleanLine {
436 if in.indent > in.currentIndent() {
437
438 in.indents = append(in.indents, in.indent)
439 in.lastToken = "indent"
440 in.cleanLine = false
441 return _INDENT
442 } else if in.indent < in.currentIndent() {
443
444 in.indents = in.indents[:len(in.indents)-1]
445
446
447
448
449 if in.indent > in.currentIndent() {
450 in.pos = val.pos
451 in.Error("unexpected indentation")
452 }
453 in.lastToken = "unindent"
454 return _UNINDENT
455 }
456 }
457
458 in.cleanLine = false
459
460
461 if in.eof() && in.currentIndent() > 0 {
462 in.indents = in.indents[:len(in.indents)-1]
463 in.lastToken = "unindent"
464 return _UNINDENT
465 }
466
467
468 in.startToken(val)
469 defer in.endToken(val)
470
471
472 if in.eof() {
473 in.lastToken = "EOF"
474 return _EOF
475 }
476
477
478 switch c := in.peekRune(); c {
479 case '[', '(', '{':
480 in.depth++
481 in.readRune()
482 return c
483
484 case ']', ')', '}':
485 in.depth--
486 in.readRune()
487 return c
488
489 case '.', ':', ';', ',':
490 in.readRune()
491 return c
492
493 case '<', '>', '=', '!', '+', '-', '*', '/', '%', '|', '&', '~', '^':
494 in.readRune()
495
496 if c == '~' {
497
498 return c
499 }
500
501 if c == '*' && in.peekRune() == '*' {
502
503 in.readRune()
504 return _STAR_STAR
505 }
506
507 if c == '-' && in.peekRune() == '>' {
508
509 in.readRune()
510 return _ARROW
511 }
512
513 if c == in.peekRune() {
514 switch c {
515 case '/':
516
517 in.readRune()
518 c = _INT_DIV
519 case '<':
520
521 in.readRune()
522 c = _BIT_LSH
523 case '>':
524
525 in.readRune()
526 c = _BIT_RSH
527 }
528 }
529
530 if in.peekRune() == '=' {
531 in.readRune()
532 switch c {
533 case '<':
534 return _LE
535 case '>':
536 return _GE
537 case '=':
538 return _EQ
539 case '!':
540 return _NE
541 default:
542 return _AUGM
543 }
544 }
545 return c
546
547 case 'r':
548 if len(in.remaining) < 2 || in.remaining[1] != '"' && in.remaining[1] != '\'' {
549 break
550 }
551 in.readRune()
552 c = in.peekRune()
553 fallthrough
554
555 case '"', '\'':
556 quote := c
557 if len(in.remaining) >= 3 && in.remaining[0] == byte(quote) && in.remaining[1] == byte(quote) && in.remaining[2] == byte(quote) {
558
559 in.readRune()
560 in.readRune()
561 in.readRune()
562 var c1, c2, c3 int
563 for {
564 if in.eof() {
565 in.pos = val.pos
566 in.Error("unexpected EOF in string")
567 }
568 c1, c2, c3 = c2, c3, in.readRune()
569 if c1 == quote && c2 == quote && c3 == quote {
570 break
571 }
572 if c3 == '\\' {
573 if in.eof() {
574 in.pos = val.pos
575 in.Error("unexpected EOF in string")
576 }
577 in.readRune()
578 }
579 }
580 } else {
581 in.readRune()
582 for {
583 if in.eof() {
584 in.pos = val.pos
585 in.Error("unexpected EOF in string")
586 }
587 if in.peekRune() == '\n' {
588 in.Error("unexpected newline in string")
589 }
590 c := in.readRune()
591 if c == quote {
592 break
593 }
594 if c == '\\' {
595 if in.eof() {
596 in.pos = val.pos
597 in.Error("unexpected EOF in string")
598 }
599 in.readRune()
600 }
601 }
602 }
603 in.endToken(val)
604 s, triple, err := Unquote(val.tok)
605 if err != nil {
606 in.Error(fmt.Sprint(err))
607 }
608 val.str = s
609 val.triple = triple
610 return _STRING
611 }
612
613
614 if c := in.peekRune(); !isIdent(c) {
615 in.Error(fmt.Sprintf("unexpected input character %#q", c))
616 }
617
618
619 for {
620 c := in.peekRune()
621 if !isIdent(c) {
622 break
623 }
624 in.readRune()
625 }
626
627
628
629 in.endToken(val)
630 if k := keywordToken[val.tok]; k != 0 {
631 return k
632 }
633 switch val.tok {
634 case "pass":
635 return _PASS
636 case "break":
637 return _BREAK
638 case "continue":
639 return _CONTINUE
640 }
641 if len(val.tok) > 0 && val.tok[0] >= '0' && val.tok[0] <= '9' {
642 return _INT
643 }
644 return _IDENT
645 }
646
647
648
649 func isIdent(c int) bool {
650 return '0' <= c && c <= '9' ||
651 'A' <= c && c <= 'Z' ||
652 'a' <= c && c <= 'z' ||
653 c == '_' ||
654 c >= 0x80
655 }
656
657
658
659 var keywordToken = map[string]int{
660 "and": _AND,
661 "for": _FOR,
662 "if": _IF,
663 "else": _ELSE,
664 "elif": _ELIF,
665 "in": _IN,
666 "is": _IS,
667 "lambda": _LAMBDA,
668 "load": _LOAD,
669 "not": _NOT,
670 "or": _OR,
671 "def": _DEF,
672 "return": _RETURN,
673 }
674
675
676
677
678
679
680
681
682
683
684
685 func (in *input) order(v Expr) {
686 if v != nil {
687 in.pre = append(in.pre, v)
688 }
689 switch v := v.(type) {
690 default:
691 panic(fmt.Errorf("order: unexpected type %T", v))
692 case nil:
693
694 case *End:
695
696 case *File:
697 for _, stmt := range v.Stmt {
698 in.order(stmt)
699 }
700 case *CommentBlock:
701
702 case *CallExpr:
703 in.order(v.X)
704 for _, x := range v.List {
705 in.order(x)
706 }
707 in.order(&v.End)
708 case *LoadStmt:
709 in.order(v.Module)
710 for i := range v.From {
711 in.order(v.To[i])
712 in.order(v.From[i])
713 }
714 in.order(&v.Rparen)
715 case *LiteralExpr:
716
717 case *StringExpr:
718
719 case *Ident:
720
721 case *TypedIdent:
722 in.order(v.Type)
723 case *BranchStmt:
724
725 case *DotExpr:
726 in.order(v.X)
727 case *ListExpr:
728 for _, x := range v.List {
729 in.order(x)
730 }
731 in.order(&v.End)
732 case *Comprehension:
733 in.order(v.Body)
734 for _, c := range v.Clauses {
735 in.order(c)
736 }
737 in.order(&v.End)
738 case *SetExpr:
739 for _, x := range v.List {
740 in.order(x)
741 }
742 in.order(&v.End)
743 case *ForClause:
744 in.order(v.Vars)
745 in.order(v.X)
746 case *IfClause:
747 in.order(v.Cond)
748 case *KeyValueExpr:
749 in.order(v.Key)
750 in.order(v.Value)
751 case *DictExpr:
752 for _, x := range v.List {
753 in.order(x)
754 }
755 in.order(&v.End)
756 case *TupleExpr:
757 for _, x := range v.List {
758 in.order(x)
759 }
760 if !v.NoBrackets {
761 in.order(&v.End)
762 }
763 case *UnaryExpr:
764 in.order(v.X)
765 case *BinaryExpr:
766 in.order(v.X)
767 in.order(v.Y)
768 case *AssignExpr:
769 in.order(v.LHS)
770 in.order(v.RHS)
771 case *ConditionalExpr:
772 in.order(v.Then)
773 in.order(v.Test)
774 in.order(v.Else)
775 case *ParenExpr:
776 in.order(v.X)
777 in.order(&v.End)
778 case *SliceExpr:
779 in.order(v.X)
780 in.order(v.From)
781 in.order(v.To)
782 in.order(v.Step)
783 case *IndexExpr:
784 in.order(v.X)
785 in.order(v.Y)
786 case *LambdaExpr:
787 for _, param := range v.Params {
788 in.order(param)
789 }
790 for _, expr := range v.Body {
791 in.order(expr)
792 }
793 case *ReturnStmt:
794 if v.Result != nil {
795 in.order(v.Result)
796 }
797 case *DefStmt:
798 for _, x := range v.Params {
799 in.order(x)
800 }
801 for _, x := range v.Body {
802 in.order(x)
803 }
804 case *ForStmt:
805 in.order(v.Vars)
806 in.order(v.X)
807 for _, x := range v.Body {
808 in.order(x)
809 }
810 case *IfStmt:
811 in.order(v.Cond)
812 for _, s := range v.True {
813 in.order(s)
814 }
815 if len(v.False) > 0 {
816 in.order(&v.ElsePos)
817 }
818 for _, s := range v.False {
819 in.order(s)
820 }
821 }
822 if v != nil {
823 in.post = append(in.post, v)
824 }
825 }
826
827
828 func (in *input) assignComments() {
829
830 in.order(in.file)
831 in.assignSuffixComments()
832 in.assignLineComments()
833 }
834
835 func (in *input) assignSuffixComments() {
836
837 suffix := in.suffixComments
838 for i := len(in.post) - 1; i >= 0; i-- {
839 x := in.post[i]
840
841
842 switch x.(type) {
843 case *File, *DefStmt, *IfStmt, *ForStmt, *CommentBlock:
844 continue
845 }
846
847 _, end := x.Span()
848 xcom := x.Comment()
849 for len(suffix) > 0 && end.Byte <= suffix[len(suffix)-1].Start.Byte {
850 xcom.Suffix = append(xcom.Suffix, suffix[len(suffix)-1])
851 suffix = suffix[:len(suffix)-1]
852 }
853 }
854
855
856
857
858 for _, x := range in.post {
859 reverseComments(x.Comment().Suffix)
860 }
861
862
863 in.file.Before = append(in.file.Before, suffix...)
864 }
865
866 func (in *input) assignLineComments() {
867
868 line := in.lineComments
869 for _, x := range in.pre {
870 start, _ := x.Span()
871 xcom := x.Comment()
872 for len(line) > 0 && start.Byte >= line[0].Start.Byte {
873 xcom.Before = append(xcom.Before, line[0])
874 line = line[1:]
875 }
876
877
878 sort.SliceStable(xcom.Before, func(i, j int) bool {
879 return xcom.Before[i].Start.Byte < xcom.Before[j].Start.Byte
880 })
881 }
882
883
884 in.file.After = append(in.file.After, line...)
885 }
886
887
888 func reverseComments(list []Comment) {
889 for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
890 list[i], list[j] = list[j], list[i]
891 }
892 }
893
View as plain text