OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / internal / catmsg / codec.go
1 // Copyright 2017 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package catmsg
6
7 import (
8         "errors"
9         "fmt"
10
11         "golang.org/x/text/language"
12 )
13
14 // A Renderer renders a Message.
15 type Renderer interface {
16         // Render renders the given string. The given string may be interpreted as a
17         // format string, such as the one used by the fmt package or a template.
18         Render(s string)
19
20         // Arg returns the i-th argument passed to format a message. This method
21         // should return nil if there is no such argument. Messages need access to
22         // arguments to allow selecting a message based on linguistic features of
23         // those arguments.
24         Arg(i int) interface{}
25 }
26
27 // A Dictionary specifies a source of messages, including variables or macros.
28 type Dictionary interface {
29         // Lookup returns the message for the given key. It returns false for ok if
30         // such a message could not be found.
31         Lookup(key string) (data string, ok bool)
32
33         // TODO: consider returning an interface, instead of a string. This will
34         // allow implementations to do their own message type decoding.
35 }
36
37 // An Encoder serializes a Message to a string.
38 type Encoder struct {
39         // The root encoder is used for storing encoded variables.
40         root *Encoder
41         // The parent encoder provides the surrounding scopes for resolving variable
42         // names.
43         parent *Encoder
44
45         tag language.Tag
46
47         // buf holds the encoded message so far. After a message completes encoding,
48         // the contents of buf, prefixed by the encoded length, are flushed to the
49         // parent buffer.
50         buf []byte
51
52         // vars is the lookup table of variables in the current scope.
53         vars []keyVal
54
55         err    error
56         inBody bool // if false next call must be EncodeMessageType
57 }
58
59 type keyVal struct {
60         key    string
61         offset int
62 }
63
64 // Language reports the language for which the encoded message will be stored
65 // in the Catalog.
66 func (e *Encoder) Language() language.Tag { return e.tag }
67
68 func (e *Encoder) setError(err error) {
69         if e.root.err == nil {
70                 e.root.err = err
71         }
72 }
73
74 // EncodeUint encodes x.
75 func (e *Encoder) EncodeUint(x uint64) {
76         e.checkInBody()
77         var buf [maxVarintBytes]byte
78         n := encodeUint(buf[:], x)
79         e.buf = append(e.buf, buf[:n]...)
80 }
81
82 // EncodeString encodes s.
83 func (e *Encoder) EncodeString(s string) {
84         e.checkInBody()
85         e.EncodeUint(uint64(len(s)))
86         e.buf = append(e.buf, s...)
87 }
88
89 // EncodeMessageType marks the current message to be of type h.
90 //
91 // It must be the first call of a Message's Compile method.
92 func (e *Encoder) EncodeMessageType(h Handle) {
93         if e.inBody {
94                 panic("catmsg: EncodeMessageType not the first method called")
95         }
96         e.inBody = true
97         e.EncodeUint(uint64(h))
98 }
99
100 // EncodeMessage serializes the given message inline at the current position.
101 func (e *Encoder) EncodeMessage(m Message) error {
102         e = &Encoder{root: e.root, parent: e, tag: e.tag}
103         err := m.Compile(e)
104         if _, ok := m.(*Var); !ok {
105                 e.flushTo(e.parent)
106         }
107         return err
108 }
109
110 func (e *Encoder) checkInBody() {
111         if !e.inBody {
112                 panic("catmsg: expected prior call to EncodeMessageType")
113         }
114 }
115
116 // stripPrefix indicates the number of prefix bytes that must be stripped to
117 // turn a single-element sequence into a message that is just this single member
118 // without its size prefix. If the message can be stripped, b[1:n] contains the
119 // size prefix.
120 func stripPrefix(b []byte) (n int) {
121         if len(b) > 0 && Handle(b[0]) == msgFirst {
122                 x, n, _ := decodeUint(b[1:])
123                 if 1+n+int(x) == len(b) {
124                         return 1 + n
125                 }
126         }
127         return 0
128 }
129
130 func (e *Encoder) flushTo(dst *Encoder) {
131         data := e.buf
132         p := stripPrefix(data)
133         if p > 0 {
134                 data = data[1:]
135         } else {
136                 // Prefix the size.
137                 dst.EncodeUint(uint64(len(data)))
138         }
139         dst.buf = append(dst.buf, data...)
140 }
141
142 func (e *Encoder) addVar(key string, m Message) error {
143         for _, v := range e.parent.vars {
144                 if v.key == key {
145                         err := fmt.Errorf("catmsg: duplicate variable %q", key)
146                         e.setError(err)
147                         return err
148                 }
149         }
150         scope := e.parent
151         // If a variable message is Incomplete, and does not evaluate to a message
152         // during execution, we fall back to the variable name. We encode this by
153         // appending the variable name if the message reports it's incomplete.
154
155         err := m.Compile(e)
156         if err != ErrIncomplete {
157                 e.setError(err)
158         }
159         switch {
160         case len(e.buf) == 1 && Handle(e.buf[0]) == msgFirst: // empty sequence
161                 e.buf = e.buf[:0]
162                 e.inBody = false
163                 fallthrough
164         case len(e.buf) == 0:
165                 // Empty message.
166                 if err := String(key).Compile(e); err != nil {
167                         e.setError(err)
168                 }
169         case err == ErrIncomplete:
170                 if Handle(e.buf[0]) != msgFirst {
171                         seq := &Encoder{root: e.root, parent: e}
172                         seq.EncodeMessageType(First)
173                         e.flushTo(seq)
174                         e = seq
175                 }
176                 // e contains a sequence; append the fallback string.
177                 e.EncodeMessage(String(key))
178         }
179
180         // Flush result to variable heap.
181         offset := len(e.root.buf)
182         e.flushTo(e.root)
183         e.buf = e.buf[:0]
184
185         // Record variable offset in current scope.
186         scope.vars = append(scope.vars, keyVal{key: key, offset: offset})
187         return err
188 }
189
190 const (
191         substituteVar = iota
192         substituteMacro
193         substituteError
194 )
195
196 // EncodeSubstitution inserts a resolved reference to a variable or macro.
197 //
198 // This call must be matched with a call to ExecuteSubstitution at decoding
199 // time.
200 func (e *Encoder) EncodeSubstitution(name string, arguments ...int) {
201         if arity := len(arguments); arity > 0 {
202                 // TODO: also resolve macros.
203                 e.EncodeUint(substituteMacro)
204                 e.EncodeString(name)
205                 for _, a := range arguments {
206                         e.EncodeUint(uint64(a))
207                 }
208                 return
209         }
210         for scope := e; scope != nil; scope = scope.parent {
211                 for _, v := range scope.vars {
212                         if v.key != name {
213                                 continue
214                         }
215                         e.EncodeUint(substituteVar) // TODO: support arity > 0
216                         e.EncodeUint(uint64(v.offset))
217                         return
218                 }
219         }
220         // TODO: refer to dictionary-wide scoped variables.
221         e.EncodeUint(substituteError)
222         e.EncodeString(name)
223         e.setError(fmt.Errorf("catmsg: unknown var %q", name))
224 }
225
226 // A Decoder deserializes and evaluates messages that are encoded by an encoder.
227 type Decoder struct {
228         tag    language.Tag
229         dst    Renderer
230         macros Dictionary
231
232         err  error
233         vars string
234         data string
235
236         macroArg int // TODO: allow more than one argument
237 }
238
239 // NewDecoder returns a new Decoder.
240 //
241 // Decoders are designed to be reused for multiple invocations of Execute.
242 // Only one goroutine may call Execute concurrently.
243 func NewDecoder(tag language.Tag, r Renderer, macros Dictionary) *Decoder {
244         return &Decoder{
245                 tag:    tag,
246                 dst:    r,
247                 macros: macros,
248         }
249 }
250
251 func (d *Decoder) setError(err error) {
252         if d.err == nil {
253                 d.err = err
254         }
255 }
256
257 // Language returns the language in which the message is being rendered.
258 //
259 // The destination language may be a child language of the language used for
260 // encoding. For instance, a decoding language of "pt-PT"" is consistent with an
261 // encoding language of "pt".
262 func (d *Decoder) Language() language.Tag { return d.tag }
263
264 // Done reports whether there are more bytes to process in this message.
265 func (d *Decoder) Done() bool { return len(d.data) == 0 }
266
267 // Render implements Renderer.
268 func (d *Decoder) Render(s string) { d.dst.Render(s) }
269
270 // Arg implements Renderer.
271 //
272 // During evaluation of macros, the argument positions may be mapped to
273 // arguments that differ from the original call.
274 func (d *Decoder) Arg(i int) interface{} {
275         if d.macroArg != 0 {
276                 if i != 1 {
277                         panic("catmsg: only macros with single argument supported")
278                 }
279                 i = d.macroArg
280         }
281         return d.dst.Arg(i)
282 }
283
284 // DecodeUint decodes a number that was encoded with EncodeUint and advances the
285 // position.
286 func (d *Decoder) DecodeUint() uint64 {
287         x, n, err := decodeUintString(d.data)
288         d.data = d.data[n:]
289         if err != nil {
290                 d.setError(err)
291         }
292         return x
293 }
294
295 // DecodeString decodes a string that was encoded with EncodeString and advances
296 // the position.
297 func (d *Decoder) DecodeString() string {
298         size := d.DecodeUint()
299         s := d.data[:size]
300         d.data = d.data[size:]
301         return s
302 }
303
304 // SkipMessage skips the message at the current location and advances the
305 // position.
306 func (d *Decoder) SkipMessage() {
307         n := int(d.DecodeUint())
308         d.data = d.data[n:]
309 }
310
311 // Execute decodes and evaluates msg.
312 //
313 // Only one goroutine may call execute.
314 func (d *Decoder) Execute(msg string) error {
315         d.err = nil
316         if !d.execute(msg) {
317                 return ErrNoMatch
318         }
319         return d.err
320 }
321
322 func (d *Decoder) execute(msg string) bool {
323         saved := d.data
324         d.data = msg
325         ok := d.executeMessage()
326         d.data = saved
327         return ok
328 }
329
330 // executeMessageFromData is like execute, but also decodes a leading message
331 // size and clips the given string accordingly.
332 //
333 // It reports the number of bytes consumed and whether a message was selected.
334 func (d *Decoder) executeMessageFromData(s string) (n int, ok bool) {
335         saved := d.data
336         d.data = s
337         size := int(d.DecodeUint())
338         n = len(s) - len(d.data)
339         // Sanitize the setting. This allows skipping a size argument for
340         // RawString and method Done.
341         d.data = d.data[:size]
342         ok = d.executeMessage()
343         n += size - len(d.data)
344         d.data = saved
345         return n, ok
346 }
347
348 var errUnknownHandler = errors.New("catmsg: string contains unsupported handler")
349
350 // executeMessage reads the handle id, initializes the decoder and executes the
351 // message. It is assumed that all of d.data[d.p:] is the single message.
352 func (d *Decoder) executeMessage() bool {
353         if d.Done() {
354                 // We interpret no data as a valid empty message.
355                 return true
356         }
357         handle := d.DecodeUint()
358
359         var fn Handler
360         mutex.Lock()
361         if int(handle) < len(handlers) {
362                 fn = handlers[handle]
363         }
364         mutex.Unlock()
365         if fn == nil {
366                 d.setError(errUnknownHandler)
367                 d.execute(fmt.Sprintf("\x02$!(UNKNOWNMSGHANDLER=%#x)", handle))
368                 return true
369         }
370         return fn(d)
371 }
372
373 // ExecuteMessage decodes and executes the message at the current position.
374 func (d *Decoder) ExecuteMessage() bool {
375         n, ok := d.executeMessageFromData(d.data)
376         d.data = d.data[n:]
377         return ok
378 }
379
380 // ExecuteSubstitution executes the message corresponding to the substitution
381 // as encoded by EncodeSubstitution.
382 func (d *Decoder) ExecuteSubstitution() {
383         switch x := d.DecodeUint(); x {
384         case substituteVar:
385                 offset := d.DecodeUint()
386                 d.executeMessageFromData(d.vars[offset:])
387         case substituteMacro:
388                 name := d.DecodeString()
389                 data, ok := d.macros.Lookup(name)
390                 old := d.macroArg
391                 // TODO: support macros of arity other than 1.
392                 d.macroArg = int(d.DecodeUint())
393                 switch {
394                 case !ok:
395                         // TODO: detect this at creation time.
396                         d.setError(fmt.Errorf("catmsg: undefined macro %q", name))
397                         fallthrough
398                 case !d.execute(data):
399                         d.dst.Render(name) // fall back to macro name.
400                 }
401                 d.macroArg = old
402         case substituteError:
403                 d.dst.Render(d.DecodeString())
404         default:
405                 panic("catmsg: unreachable")
406         }
407 }