bash - ast_word.go
1 package bash
2
3 import (
4 "vimagination.zapto.org/parser"
5 )
6
7 // AssignmentOrWord represents either an Assignment or a Word in a command.
8 //
9 // One, and only one, of Assignment or Word must be set.
10 type AssignmentOrWord struct {
11 Assignment *Assignment
12 Word *Word
13 Tokens Tokens
14 }
15
16 func (a *AssignmentOrWord) parse(b *bashParser) error {
17 var err error
18
19 c := b.NewGoal()
20
21 if tk := b.Peek().Type; tk == TokenIdentifierAssign || tk == TokenLetIdentifierAssign {
22 a.Assignment = new(Assignment)
23 err = a.Assignment.parse(c)
24 } else {
25 a.Word = new(Word)
26 err = a.Word.parse(c, false)
27 }
28
29 if err != nil {
30 return b.Error("AssignmentOrWord", err)
31 }
32
33 b.Score(c)
34
35 a.Tokens = b.ToTokens()
36
37 return nil
38 }
39
40 func (a *AssignmentOrWord) isMultiline(v bool) bool {
41 return a.Assignment != nil && a.Assignment.isMultiline(v) || a.Word != nil && a.Word.isMultiline(v)
42 }
43
44 // Value represents the value to be assigned in an Assignment.
45 //
46 // One, and only one, of Word or Array must be used.
47 //
48 // When assigning an array, the first set of comments are from just after the
49 // opening paren, and the second set of comments are from just before the
50 // closing paren.
51 type Value struct {
52 Word *Word
53 Array []ArrayWord
54 Comments [2]Comments
55 Tokens Tokens
56 }
57
58 func (v *Value) parse(b *bashParser) error {
59 if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "("}) {
60 v.Comments[0] = b.AcceptRunWhitespaceComments()
61
62 v.Array = []ArrayWord{}
63 c := b.NewGoal()
64
65 c.AcceptRunAllWhitespace()
66
67 for !c.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ")"}) {
68 b.AcceptRunAllWhitespaceNoComments()
69
70 c = b.NewGoal()
71
72 var a ArrayWord
73
74 if err := a.parse(c); err != nil {
75 return b.Error("Value", err)
76 }
77
78 v.Array = append(v.Array, a)
79
80 b.Score(c)
81
82 c = b.NewGoal()
83
84 c.AcceptRunAllWhitespace()
85 }
86
87 v.Comments[1] = b.AcceptRunAllWhitespaceComments()
88
89 b.AcceptRunAllWhitespaceNoComments()
90 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ")"})
91 } else {
92 c := b.NewGoal()
93 v.Word = new(Word)
94
95 if err := v.Word.parse(c, false); err != nil {
96 return b.Error("Value", err)
97 }
98
99 b.Score(c)
100 }
101
102 v.Tokens = b.ToTokens()
103
104 return nil
105 }
106
107 func (v *Value) isMultiline(vs bool) bool {
108 if len(v.Comments[0]) > 0 || len(v.Comments[1]) > 0 {
109 return true
110 }
111
112 if v.Word != nil {
113 return v.Word.isMultiline(vs)
114 }
115
116 for _, ar := range v.Array {
117 if ar.isMultiline(vs) {
118 return true
119 }
120 }
121
122 return false
123 }
124
125 // ArrayWord a word in a Values array value.
126 //
127 // The first set of comments are from just before the word, and the second set
128 // are from just after.
129 type ArrayWord struct {
130 Word Word
131 Comments [2]Comments
132 Tokens Tokens
133 }
134
135 func (a *ArrayWord) parse(b *bashParser) error {
136 a.Comments[0] = b.AcceptRunAllWhitespaceComments()
137
138 b.AcceptRunAllWhitespaceNoComments()
139
140 c := b.NewGoal()
141
142 if err := a.Word.parse(c, false); err != nil {
143 return b.Error("ArrayWord", err)
144 }
145
146 if len(a.Word.Parts) == 0 {
147 return b.Error("ArrayWord", ErrMissingWord)
148 }
149
150 b.Score(c)
151
152 a.Comments[1] = b.AcceptRunWhitespaceComments()
153 a.Tokens = b.ToTokens()
154
155 return nil
156 }
157
158 func (a *ArrayWord) isMultiline(v bool) bool {
159 if len(a.Comments[0]) > 0 || len(a.Comments[1]) > 0 {
160 return true
161 }
162
163 return a.Word.isMultiline(v)
164 }
165
166 // Word represents a collection of WordParts that make up a single word.
167 type Word struct {
168 Parts []WordPart
169 Tokens Tokens
170 }
171
172 func (w *Word) parse(b *bashParser, splitAssign bool) error {
173 for nextIsWordPart(b) {
174 nextIsAssign := b.Peek().Type == TokenIdentifierAssign
175 c := b.NewGoal()
176
177 var wp WordPart
178
179 if err := wp.parse(c); err != nil {
180 return b.Error("Word", err)
181 }
182
183 w.Parts = append(w.Parts, wp)
184
185 b.Score(c)
186
187 if nextIsAssign && splitAssign {
188 break
189 }
190 }
191
192 w.Tokens = b.ToTokens()
193
194 return nil
195 }
196
197 func (w *Word) isMultiline(v bool) bool {
198 for _, p := range w.Parts {
199 if p.isMultiline(v) {
200 return true
201 }
202 }
203
204 return false
205 }
206
207 func nextIsWordPart(b *bashParser) bool {
208 switch tk := b.Peek(); tk.Type {
209 case TokenWhitespace, TokenLineTerminator, TokenComment, TokenCloseBacktick, TokenHeredoc, TokenBinaryOperator, TokenHeredocEnd, parser.TokenDone:
210 return false
211 case TokenBraceExpansion:
212 return tk.Data != "}"
213 case TokenPunctuator:
214 switch tk.Data {
215 case "$((", "$(", "${", "<(", ">(":
216 return true
217 }
218
219 return false
220 }
221
222 return true
223 }
224
225 // WordPart represents a single part of a word.
226 //
227 // One and only one of Part, ParameterExpansion, CommandSubstitution,
228 // ArithmeticExpansion, or BraceExpansion must be set.
229 type WordPart struct {
230 Part *Token
231 ParameterExpansion *ParameterExpansion
232 CommandSubstitution *CommandSubstitution
233 ArithmeticExpansion *ArithmeticExpansion
234 BraceExpansion *BraceExpansion
235 Tokens Tokens
236 }
237
238 func (w *WordPart) parse(b *bashParser) error {
239 c := b.NewGoal()
240
241 switch tk := b.Peek(); {
242 case tk == parser.Token{Type: TokenPunctuator, Data: "${"}:
243 w.ParameterExpansion = new(ParameterExpansion)
244
245 if err := w.ParameterExpansion.parse(c); err != nil {
246 return b.Error("WordPart", err)
247 }
248 case tk == parser.Token{Type: TokenPunctuator, Data: "$(("}:
249 w.ArithmeticExpansion = new(ArithmeticExpansion)
250
251 if err := w.ArithmeticExpansion.parse(c); err != nil {
252 return b.Error("WordPart", err)
253 }
254 case tk == parser.Token{Type: TokenPunctuator, Data: "$("}, tk.Type == TokenOpenBacktick, tk == parser.Token{Type: TokenPunctuator, Data: "<("}, tk == parser.Token{Type: TokenPunctuator, Data: ">("}:
255 w.CommandSubstitution = new(CommandSubstitution)
256
257 if err := w.CommandSubstitution.parse(c); err != nil {
258 return b.Error("WordPart", err)
259 }
260 case tk == parser.Token{Type: TokenBraceExpansion, Data: "{"}, tk == parser.Token{Type: TokenBraceSequenceExpansion, Data: "{"}:
261 w.BraceExpansion = new(BraceExpansion)
262
263 if err := w.BraceExpansion.parse(c); err != nil {
264 return b.Error("WordPart", err)
265 }
266 default:
267 b.Next()
268
269 w.Part = b.GetLastToken()
270 }
271
272 b.Score(c)
273
274 w.Tokens = b.ToTokens()
275
276 return nil
277 }
278
279 func (w *WordPart) isMultiline(v bool) bool {
280 if w.ParameterExpansion != nil {
281 return w.ParameterExpansion.isMultiline(v)
282 } else if w.ArithmeticExpansion != nil {
283 return w.ArithmeticExpansion.isMultiline(v)
284 } else if w.CommandSubstitution != nil {
285 return w.CommandSubstitution.isMultiline(v)
286 } else if w.BraceExpansion != nil {
287 return w.BraceExpansion.isMultiline(v)
288 }
289
290 return false
291 }
292
293 // BraceExpansionType represents which type of BraceExpansion is being
294 // represented.
295 type BraceExpansionType uint8
296
297 // Brace Expansion types.
298 const (
299 BraceExpansionWords BraceExpansionType = iota
300 BraceExpansionSequence
301 )
302
303 // BraceExpansion represents either a sequence expansion
304 // ('{a..b}', '{1..10..2}'), or a group of words ('{ab,cd,12}').
305 type BraceExpansion struct {
306 BraceExpansionType
307 Words []Word
308 Tokens Tokens
309 }
310
311 func (be *BraceExpansion) parse(b *bashParser) error {
312 if b.Accept(TokenBraceExpansion) {
313 be.BraceExpansionType = BraceExpansionWords
314 } else {
315 b.Next()
316
317 be.BraceExpansionType = BraceExpansionSequence
318 }
319
320 for !b.AcceptToken(parser.Token{Type: TokenBraceExpansion, Data: "}"}) {
321 c := b.NewGoal()
322
323 var w Word
324
325 if err := w.parse(c, false); err != nil {
326 return b.Error("BraceExpansion", err)
327 }
328
329 be.Words = append(be.Words, w)
330
331 b.Score(c)
332 b.Accept(TokenPunctuator)
333 }
334
335 be.Tokens = b.ToTokens()
336
337 return nil
338 }
339
340 func (b *BraceExpansion) isMultiline(v bool) bool {
341 for _, w := range b.Words {
342 if w.isMultiline(v) {
343 return true
344 }
345 }
346
347 return false
348 }
349
350 // ParameterType represents the type of a ParameterExpansion.
351 type ParameterType uint8
352
353 // ParameterExpansion types.
354 const (
355 ParameterValue ParameterType = iota
356 ParameterLength
357 ParameterSubstitution
358 ParameterAssignment
359 ParameterMessage
360 ParameterSetAssign
361 ParameterUnsetSubstitution
362 ParameterUnsetAssignment
363 ParameterUnsetMessage
364 ParameterUnsetSetAssign
365 ParameterSubstring
366 ParameterPrefix
367 ParameterPrefixSeperate
368 ParameterRemoveStartShortest
369 ParameterRemoveStartLongest
370 ParameterRemoveEndShortest
371 ParameterRemoveEndLongest
372 ParameterReplace
373 ParameterReplaceAll
374 ParameterReplaceStart
375 ParameterReplaceEnd
376 ParameterLowercaseFirstMatch
377 ParameterLowercaseAllMatches
378 ParameterUppercaseFirstMatch
379 ParameterUppercaseAllMatches
380 ParameterUppercase
381 ParameterUppercaseFirst
382 ParameterLowercase
383 ParameterQuoted
384 ParameterEscaped
385 ParameterPrompt
386 ParameterDeclare
387 ParameterQuotedArrays
388 ParameterQuotedArraysSeperate
389 ParameterAttributes
390 )
391
392 // ParameterExpansion represents the expansion of a parameter.
393 type ParameterExpansion struct {
394 Indirect bool
395 Parameter Parameter
396 Type ParameterType
397 SubstringStart *Token
398 SubstringEnd *Token
399 BraceWord *BraceWord
400 Pattern *Token
401 String *String
402 Tokens Tokens
403 }
404
405 func (p *ParameterExpansion) parse(b *bashParser) error {
406 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "${"})
407
408 if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "#"}) {
409 p.Type = ParameterLength
410 } else {
411 p.Indirect = b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "!"})
412 }
413
414 c := b.NewGoal()
415
416 if err := p.Parameter.parse(c); err != nil {
417 return b.Error("ParameterExpansion", err)
418 }
419
420 b.Score(c)
421
422 if p.Type != ParameterLength {
423 var parseWord, parseReplace, parsePattern bool
424
425 if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ":="}) {
426 p.Type = ParameterSubstitution
427 parseWord = true
428 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ":?"}) {
429 p.Type = ParameterAssignment
430 parseWord = true
431 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ":+"}) {
432 p.Type = ParameterMessage
433 parseWord = true
434 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ":-"}) {
435 p.Type = ParameterSetAssign
436 parseWord = true
437 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "="}) {
438 p.Type = ParameterUnsetSubstitution
439 parseWord = true
440 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "?"}) {
441 p.Type = ParameterUnsetAssignment
442 parseWord = true
443 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "+"}) {
444 p.Type = ParameterUnsetMessage
445 parseWord = true
446 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "-"}) {
447 p.Type = ParameterUnsetSetAssign
448 parseWord = true
449 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ":"}) {
450 p.Type = ParameterSubstring
451
452 b.AcceptRunWhitespace()
453 b.Accept(TokenNumberLiteral)
454
455 p.SubstringStart = b.GetLastToken()
456
457 if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ":"}) {
458 b.AcceptRunWhitespace()
459 b.Accept(TokenNumberLiteral)
460
461 p.SubstringEnd = b.GetLastToken()
462 }
463 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "#"}) {
464 p.Type = ParameterRemoveStartShortest
465 parseWord = true
466 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "##"}) {
467 p.Type = ParameterRemoveStartLongest
468 parseWord = true
469 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "%"}) {
470 p.Type = ParameterRemoveEndShortest
471 parseWord = true
472 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "%%"}) {
473 p.Type = ParameterRemoveEndLongest
474 parseWord = true
475 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "/"}) {
476 p.Type = ParameterReplace
477 parseReplace = true
478 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "//"}) {
479 p.Type = ParameterReplaceAll
480 parseReplace = true
481 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "/#"}) {
482 p.Type = ParameterReplaceStart
483 parseReplace = true
484 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "/%"}) {
485 p.Type = ParameterReplaceEnd
486 parseReplace = true
487 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "^"}) {
488 p.Type = ParameterUppercaseFirstMatch
489 parsePattern = true
490 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "^^"}) {
491 p.Type = ParameterUppercaseAllMatches
492 parsePattern = true
493 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ","}) {
494 p.Type = ParameterLowercaseFirstMatch
495 parsePattern = true
496 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ",,"}) {
497 p.Type = ParameterLowercaseAllMatches
498 parsePattern = true
499 } else if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "@"}) {
500 if p.Indirect && b.Peek() == (parser.Token{Type: TokenPunctuator, Data: "}"}) {
501 p.Indirect = false
502 p.Type = ParameterPrefixSeperate
503 } else {
504 b.Accept(TokenBraceWord)
505
506 switch b.GetLastToken().Data {
507 case "U":
508 p.Type = ParameterUppercase
509 case "u":
510 p.Type = ParameterUppercaseFirst
511 case "L":
512 p.Type = ParameterLowercase
513 case "Q":
514 p.Type = ParameterQuoted
515 case "E":
516 p.Type = ParameterEscaped
517 case "P":
518 p.Type = ParameterPrompt
519 case "A":
520 p.Type = ParameterDeclare
521 case "K":
522 p.Type = ParameterQuotedArrays
523 case "a":
524 p.Type = ParameterAttributes
525 case "k":
526 p.Type = ParameterQuotedArraysSeperate
527 }
528 }
529 } else if p.Indirect && b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "*"}) {
530 p.Indirect = false
531 p.Type = ParameterPrefix
532 }
533
534 if parseWord {
535 c := b.NewGoal()
536 p.BraceWord = new(BraceWord)
537
538 if err := p.BraceWord.parse(c); err != nil {
539 return b.Error("ParameterExpansion", err)
540 }
541
542 b.Score(c)
543 } else if parsePattern || parseReplace {
544 b.Accept(TokenPattern)
545
546 p.Pattern = b.GetLastToken()
547
548 if parseReplace && b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "/"}) {
549 c := b.NewGoal()
550 p.String = new(String)
551
552 if err := p.String.parse(c); err != nil {
553 return b.Error("ParameterExpansion", err)
554 }
555
556 b.Score(c)
557 }
558 }
559 }
560
561 if !b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "}"}) {
562 return b.Error("ParameterExpansion", ErrMissingClosingBrace)
563 }
564
565 p.Tokens = b.ToTokens()
566
567 return nil
568 }
569
570 func (p *ParameterExpansion) isMultiline(v bool) bool {
571 if p.BraceWord != nil && p.BraceWord.isMultiline(v) {
572 return true
573 } else if p.String != nil && p.String.isMultiline(v) {
574 return true
575 }
576
577 return p.Parameter.isMultiline(v)
578 }
579
580 type BraceWord struct {
581 Parts []WordPart
582 Tokens Tokens
583 }
584
585 func (bw *BraceWord) parse(b *bashParser) error {
586 for b.Peek() != (parser.Token{Type: TokenPunctuator, Data: "}"}) {
587 c := b.NewGoal()
588
589 var wp WordPart
590
591 if err := wp.parse(c); err != nil {
592 return b.Error("BraceWord", err)
593 }
594
595 bw.Parts = append(bw.Parts, wp)
596
597 b.Score(c)
598 }
599
600 bw.Tokens = b.ToTokens()
601
602 return nil
603 }
604
605 func (b *BraceWord) isMultiline(v bool) bool {
606 for _, wp := range b.Parts {
607 if wp.isMultiline(v) {
608 return true
609 }
610 }
611
612 return false
613 }
614
615 // Parameter represents the Parameter, an Identifier with a possible Array
616 // subscript, used in a ParameterExpansion.
617 type Parameter struct {
618 Parameter *Token
619 Array []WordOrOperator
620 Tokens Tokens
621 }
622
623 func (p *Parameter) parse(b *bashParser) error {
624 if b.Accept(TokenIdentifier) {
625 p.Parameter = b.GetLastToken()
626
627 if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "["}) {
628 b.AcceptRunWhitespace()
629
630 for !b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "]"}) {
631 c := b.NewGoal()
632
633 var w WordOrOperator
634
635 if err := w.parse(c); err != nil {
636 return b.Error("Parameter", err)
637 }
638
639 p.Array = append(p.Array, w)
640
641 b.Score(c)
642 b.AcceptRunAllWhitespace()
643 }
644 }
645 } else {
646 b.Next()
647
648 p.Parameter = b.GetLastToken()
649 }
650
651 p.Tokens = b.ToTokens()
652
653 return nil
654 }
655
656 func (p *Parameter) isMultiline(v bool) bool {
657 for _, wo := range p.Array {
658 if wo.isMultiline(v) {
659 return true
660 }
661 }
662
663 return false
664 }
665
666 // String represents a collection of string or word parts that make up string.
667 type String struct {
668 WordsOrTokens []WordOrToken
669 Tokens Tokens
670 }
671
672 func (s *String) parse(b *bashParser) error {
673 for b.Peek().Type != parser.TokenDone && b.Peek() != (parser.Token{Type: TokenPunctuator, Data: "}"}) {
674 c := b.NewGoal()
675
676 var wp WordOrToken
677
678 if err := wp.parse(c); err != nil {
679 return b.Error("String", err)
680 }
681
682 b.Score(c)
683
684 s.WordsOrTokens = append(s.WordsOrTokens, wp)
685 }
686
687 s.Tokens = b.ToTokens()
688
689 return nil
690 }
691
692 func (s *String) isMultiline(v bool) bool {
693 for _, wt := range s.WordsOrTokens {
694 if wt.isMultiline(v) {
695 return true
696 }
697 }
698
699 return false
700 }
701
702 // WordOrToken represents either a string token or a Word, one and only one of
703 // which must be set.
704 type WordOrToken struct {
705 Token *Token
706 Word *Word
707 Tokens Tokens
708 }
709
710 func (w *WordOrToken) parse(b *bashParser) error {
711 if nextIsWordPart(b) {
712 c := b.NewGoal()
713 w.Word = new(Word)
714
715 if err := w.Word.parse(c, false); err != nil {
716 return b.Error("WordOrToken", err)
717 }
718
719 b.Score(c)
720 } else {
721 b.Next()
722
723 w.Token = b.GetLastToken()
724 }
725
726 w.Tokens = b.ToTokens()
727
728 return nil
729 }
730
731 func (w *WordOrToken) isMultiline(v bool) bool {
732 return w.Word != nil && w.Word.isMultiline(v)
733 }
734
735 // WordOrOperator represents either a Word or an Arithmetic Operator, one, and
736 // only one of which must be set.
737 type WordOrOperator struct {
738 Word *Word
739 Operator *Token
740 Tokens Tokens
741 }
742
743 func (w *WordOrOperator) parse(b *bashParser) error {
744 if b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "++"}) ||
745 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "--"}) ||
746 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "-"}) ||
747 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "+"}) ||
748 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "!"}) ||
749 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "~"}) ||
750 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "**"}) ||
751 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "*"}) ||
752 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "/"}) ||
753 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "%"}) ||
754 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "<<"}) ||
755 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ">>"}) ||
756 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "<="}) ||
757 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "=>"}) ||
758 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "<"}) ||
759 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ">"}) ||
760 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "?"}) ||
761 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "&"}) ||
762 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "^"}) ||
763 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "|"}) ||
764 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "&&"}) ||
765 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "||"}) ||
766 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "?"}) ||
767 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ":"}) ||
768 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "="}) ||
769 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "*="}) ||
770 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "/="}) ||
771 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "%="}) ||
772 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "+="}) ||
773 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "-="}) ||
774 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "<<="}) ||
775 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ">>="}) ||
776 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "&="}) ||
777 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "^="}) ||
778 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "!="}) ||
779 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: "("}) ||
780 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ")"}) ||
781 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ";"}) ||
782 b.AcceptToken(parser.Token{Type: TokenPunctuator, Data: ","}) {
783 w.Operator = b.GetLastToken()
784 } else {
785 c := b.NewGoal()
786 w.Word = new(Word)
787
788 if err := w.Word.parse(c, true); err != nil {
789 return b.Error("WordOrOperator", err)
790 }
791
792 b.Score(c)
793 }
794
795 w.Tokens = b.ToTokens()
796
797 return nil
798 }
799
800 func (w *WordOrOperator) isMultiline(v bool) bool {
801 return w.Word != nil && w.Word.isMultiline(v)
802 }
803
804 func (w *WordOrOperator) operatorIsToken(tk parser.Token) bool {
805 if w.Operator != nil {
806 return w.Operator.Token == tk
807 }
808
809 return false
810 }
811