github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/msgfmt/formatter.go (about)

     1  package msgfmt
     2  
     3  import (
     4  	"io"
     5  	"github.com/v2pro/plz/parse"
     6  	"fmt"
     7  	"github.com/v2pro/plz/msgfmt/jsonfmt"
     8  	"github.com/v2pro/plz/reflect2"
     9  )
    10  
    11  type Formatter interface {
    12  	Format(space []byte, kv []interface{}) []byte
    13  }
    14  
    15  type Formatters struct {
    16  	formatters []Formatter
    17  }
    18  
    19  func (formatters Formatters) Append(formatter Formatter) Formatters {
    20  	return Formatters{
    21  		append(formatters.formatters, formatter),
    22  	}
    23  }
    24  
    25  func (formatters Formatters) Format(space []byte, kv []interface{}) []byte {
    26  	for _, formatter := range formatters.formatters {
    27  		space = formatter.Format(space, kv)
    28  	}
    29  	return space
    30  }
    31  
    32  var toFormatter = newLexer(func(l *lexer) {
    33  	l.parseVariable = func(src *parse.Source, id string) interface{} {
    34  		sample := src.Attachment.([]interface{})
    35  		idx := findValueIndex(sample, id)
    36  		if idx == -1 {
    37  			src.ReportError(fmt.Errorf("%s not found in args", id))
    38  			return nil
    39  		}
    40  		sampleValue := sample[idx]
    41  		stringer, _ := sampleValue.(fmt.Stringer)
    42  		if stringer != nil {
    43  			return stringerFormatter(idx)
    44  		}
    45  		switch sampleValue.(type) {
    46  		case string:
    47  			return strFormatter(idx)
    48  		case []byte:
    49  			return bytesFormatter(idx)
    50  		default:
    51  			return &jsonFormatter{
    52  				idx:     idx,
    53  				encoder: jsonfmt.EncoderOf(reflect2.TypeOf(sampleValue)),
    54  			}
    55  		}
    56  	}
    57  	l.parseFunc = func(src *parse.Source, id string, funcName string, funcArgs []string) interface{} {
    58  		sample := src.Attachment.([]interface{})
    59  		formatter, err := newFuncFormatter(id, funcName, funcArgs, sample)
    60  		if err != nil {
    61  			src.ReportError(err)
    62  			return nil
    63  		}
    64  		return formatter
    65  	}
    66  	l.parseLiteral = func(src *parse.Source, literal string) interface{} {
    67  		return fixedFormatter(literal)
    68  	}
    69  	l.merge = func(left interface{}, right interface{}) interface{} {
    70  		formatters, isFormatters := left.(Formatters)
    71  		if isFormatters {
    72  			return formatters.Append(right.(Formatter))
    73  		}
    74  		return Formatters{[]Formatter{left.(Formatter), right.(Formatter)}}
    75  	}
    76  })
    77  
    78  func findValueIndex(sample []interface{}, target string) int {
    79  	for i := 0; i < len(sample); i += 2 {
    80  		key := sample[i].(string)
    81  		if key == target {
    82  			return i + 1
    83  		}
    84  	}
    85  	return -1
    86  }
    87  
    88  func compile(format string, sample []interface{}) Formatter {
    89  	src := parse.NewSourceString(format)
    90  	src.Attachment = sample
    91  	formatter := toFormatter.Parse(src, 0)
    92  	if src.Error() != nil {
    93  		if src.Error() == io.EOF {
    94  			return formatter.(Formatter)
    95  		}
    96  		return invalidFormatter(src.Error().Error())
    97  	}
    98  	return invalidFormatter("format not parsed completely")
    99  }