github.com/go-xe2/third@v1.0.3/golang.org/x/text/internal/catmsg/codec.go (about)

     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  	"github.com/go-xe2/third/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  }