Mercurial > projects > managesieve
annotate scanner.go @ 0:6369453d47a3
Initial revision
author | Guido Berhoerster <guido+managesieve@berhoerster.name> |
---|---|
date | Thu, 15 Oct 2020 09:11:05 +0200 |
parents | |
children |
rev | line source |
---|---|
0
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
1 // Copyright (C) 2020 Guido Berhoerster <guido+managesieve@berhoerster.name> |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
2 // |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
3 // Permission is hereby granted, free of charge, to any person obtaining |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
4 // a copy of this software and associated documentation files (the |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
5 // "Software"), to deal in the Software without restriction, including |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
6 // without limitation the rights to use, copy, modify, merge, publish, |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
7 // distribute, sublicense, and/or sell copies of the Software, and to |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
8 // permit persons to whom the Software is furnished to do so, subject to |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
9 // the following conditions: |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
10 // |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
11 // The above copyright notice and this permission notice shall be included |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
12 // in all copies or substantial portions of the Software. |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
13 // |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
17 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
18 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
19 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
20 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
21 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
22 package managesieve |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
23 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
24 import ( |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
25 "bufio" |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
26 "fmt" |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
27 "io" |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
28 "strconv" |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
29 "strings" |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
30 "unicode" |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
31 ) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
32 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
33 const ReadLimit = 1 * 1024 * 1024 // 1 MiB |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
34 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
35 type tokenType int |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
36 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
37 const ( |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
38 tokenInvalid tokenType = iota |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
39 tokenCRLF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
40 tokenLeftParenthesis |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
41 tokenRightParenthesis |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
42 tokenAtom |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
43 tokenQuotedString |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
44 tokenLiteralString |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
45 ) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
46 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
47 type token struct { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
48 typ tokenType |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
49 literal string |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
50 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
51 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
52 func (t token) String() string { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
53 switch t.typ { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
54 case tokenInvalid: |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
55 return "Invalid" |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
56 case tokenLeftParenthesis: |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
57 return "LeftParenthesis: " + t.literal |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
58 case tokenRightParenthesis: |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
59 return "RightParenthesis: " + t.literal |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
60 case tokenAtom: |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
61 return "Atom: " + t.literal |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
62 case tokenCRLF: |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
63 return fmt.Sprintf("CRLF: %q", t.literal) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
64 case tokenQuotedString: |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
65 return fmt.Sprintf("QuotedString: %q", t.literal) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
66 case tokenLiteralString: |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
67 return fmt.Sprintf("LiteralString: %q", t.literal) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
68 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
69 return fmt.Sprintf("unknown token: %q", t.literal) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
70 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
71 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
72 type scanner struct { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
73 lr *io.LimitedReader // do not read from this, only for access to N |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
74 br *bufio.Reader // wraps LimitReader |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
75 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
76 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
77 func newScanner(r io.Reader) *scanner { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
78 lr := &io.LimitedReader{R: r, N: ReadLimit} |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
79 br := bufio.NewReader(lr) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
80 return &scanner{lr, br} |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
81 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
82 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
83 func (s *scanner) scanCRLF() (*token, error) { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
84 c, _, err := s.br.ReadRune() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
85 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
86 if err == io.EOF { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
87 err = io.ErrUnexpectedEOF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
88 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
89 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
90 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
91 literal := string(c) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
92 // accept LF without CR |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
93 if c == '\r' { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
94 c, _, err = s.br.ReadRune() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
95 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
96 if err == io.EOF { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
97 err = io.ErrUnexpectedEOF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
98 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
99 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
100 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
101 literal += string(c) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
102 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
103 if c != '\n' { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
104 return nil, ParserError(fmt.Sprintf(`expected '\n', got %q`, c)) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
105 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
106 return &token{typ: tokenCRLF, literal: literal}, nil |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
107 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
108 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
109 func (s *scanner) scanParenthesis() (*token, error) { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
110 c, _, err := s.br.ReadRune() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
111 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
112 if err == io.EOF { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
113 err = io.ErrUnexpectedEOF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
114 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
115 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
116 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
117 var typ tokenType |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
118 if c == '(' { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
119 typ = tokenLeftParenthesis |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
120 } else if c == ')' { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
121 typ = tokenRightParenthesis |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
122 } else { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
123 return nil, |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
124 ParserError(fmt.Sprintf("expected parenthesis, got %q", |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
125 c)) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
126 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
127 return &token{typ: typ, literal: string(c)}, nil |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
128 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
129 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
130 func isAtomRune(c rune) bool { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
131 return c == '!' || |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
132 (c >= 0x23 && c <= 0x27) || |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
133 (c >= 0x2a && c <= 0x5b) || |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
134 (c >= 0x5d && c <= 0x7a) || |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
135 (c >= 0x7c && c <= 0x7e) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
136 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
137 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
138 func (s *scanner) scanAtom() (*token, error) { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
139 var sb strings.Builder |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
140 var c rune |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
141 for { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
142 c, _, err := s.br.ReadRune() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
143 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
144 if err == io.EOF { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
145 err = io.ErrUnexpectedEOF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
146 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
147 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
148 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
149 if isAtomRune(c) { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
150 sb.WriteRune(unicode.ToUpper(c)) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
151 } else { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
152 s.br.UnreadRune() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
153 break |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
154 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
155 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
156 if sb.Len() == 0 { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
157 return nil, ParserError(fmt.Sprintf("expected atom, got %q", c)) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
158 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
159 return &token{typ: tokenAtom, literal: sb.String()}, nil |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
160 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
161 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
162 func (s *scanner) scanQuotedString() (*token, error) { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
163 c, _, err := s.br.ReadRune() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
164 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
165 if err == io.EOF { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
166 err = io.ErrUnexpectedEOF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
167 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
168 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
169 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
170 if c != '"' { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
171 return nil, ParserError(fmt.Sprintf("expected '\"', got %q", c)) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
172 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
173 qs, err := s.br.ReadString('"') |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
174 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
175 if err == io.EOF { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
176 err = io.ErrUnexpectedEOF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
177 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
178 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
179 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
180 return &token{typ: tokenQuotedString, literal: qs[:len(qs)-1]}, |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
181 nil |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
182 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
183 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
184 func (s *scanner) scanLiteralString() (*token, error) { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
185 c, _, err := s.br.ReadRune() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
186 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
187 if err == io.EOF { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
188 err = io.ErrUnexpectedEOF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
189 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
190 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
191 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
192 if c != '{' { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
193 return nil, ParserError(fmt.Sprintf("expected '{', got %q", c)) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
194 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
195 nstr, err := s.br.ReadString('}') |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
196 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
197 if err == io.EOF { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
198 err = io.ErrUnexpectedEOF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
199 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
200 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
201 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
202 n, err := strconv.ParseUint(nstr[:len(nstr)-1], 10, 32) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
203 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
204 return nil, ParserError("failed to parse literal string length: " + err.Error()) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
205 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
206 if n > uint64(s.lr.N) { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
207 return nil, ParserError(fmt.Sprintf("string too long: %d", n)) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
208 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
209 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
210 if _, err := s.scanCRLF(); err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
211 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
212 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
213 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
214 b := make([]byte, n) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
215 _, err = io.ReadFull(s.br, b) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
216 ls := string(b) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
217 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
218 if err == io.EOF { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
219 err = io.ErrUnexpectedEOF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
220 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
221 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
222 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
223 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
224 return &token{typ: tokenLiteralString, literal: ls}, nil |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
225 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
226 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
227 func (s *scanner) skipSpace() error { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
228 for { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
229 b, err := s.br.ReadByte() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
230 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
231 if err == io.EOF { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
232 err = io.ErrUnexpectedEOF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
233 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
234 return err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
235 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
236 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
237 if b != ' ' { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
238 s.br.UnreadByte() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
239 break |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
240 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
241 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
242 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
243 return nil |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
244 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
245 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
246 func (s *scanner) scan() (*token, error) { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
247 if err := s.skipSpace(); err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
248 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
249 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
250 |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
251 buf, err := s.br.Peek(1) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
252 if err != nil { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
253 if err == io.EOF { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
254 err = io.ErrUnexpectedEOF |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
255 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
256 return nil, err |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
257 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
258 b := buf[0] |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
259 switch { |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
260 case b == '\r': |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
261 fallthrough |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
262 case b == '\n': |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
263 return s.scanCRLF() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
264 case b == '"': |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
265 return s.scanQuotedString() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
266 case b == '{': |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
267 return s.scanLiteralString() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
268 case b == '(': |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
269 fallthrough |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
270 case b == ')': |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
271 return s.scanParenthesis() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
272 case isAtomRune(rune(b)): |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
273 return s.scanAtom() |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
274 } |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
275 return nil, ParserError(fmt.Sprintf("invalid character: %q", b)) |
6369453d47a3
Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff
changeset
|
276 } |