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 }