github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/msgfmt/parse.go (about) 1 package msgfmt 2 3 import ( 4 "github.com/v2pro/plz/parse" 5 "unicode" 6 "github.com/v2pro/plz/parse/read" 7 "github.com/v2pro/plz/parse/skip" 8 "errors" 9 ) 10 11 type lexer struct { 12 leftCurly *leftCurlyToken 13 literal *literalToken 14 variable *variableLexer 15 formatter *formatterLexer 16 merge func(left interface{}, right interface{}) interface{} 17 parseLiteral func(src *parse.Source, literal string) interface{} 18 parseVariable func(src *parse.Source, id string) interface{} 19 parseFunc func(src *parse.Source, id string, funcName string, funcArgs []string) interface{} 20 } 21 22 func newLexer(initLexer func(l *lexer)) *lexer { 23 l := &lexer{ 24 leftCurly: &leftCurlyToken{}, 25 literal: &literalToken{}, 26 variable: newVariableLexer(), 27 formatter: newFormatterLexer(), 28 } 29 l.literal.lexer = l 30 l.leftCurly.lexer = l 31 l.variable.comma.lexer = l 32 initLexer(l) 33 return l 34 } 35 36 func (lexer *lexer) Parse(src *parse.Source, precedence int) interface{} { 37 var left interface{} 38 for src.Error() == nil { 39 if left == nil { 40 left = parse.Parse(src, lexer, precedence) 41 } else { 42 left = lexer.merge(left, parse.Parse(src, lexer, precedence)) 43 } 44 } 45 return left 46 } 47 48 func (lexer *lexer) PrefixToken(src *parse.Source) parse.PrefixToken { 49 switch src.Peek()[0] { 50 case '{': 51 return lexer.leftCurly 52 default: 53 return lexer.literal 54 } 55 } 56 57 func (lexer *lexer) InfixToken(src *parse.Source) (parse.InfixToken, int) { 58 return nil, 0 59 } 60 61 type leftCurlyToken struct { 62 lexer *lexer 63 } 64 65 func (token *leftCurlyToken) PrefixParse(src *parse.Source) interface{} { 66 src.Consume1('{') 67 obj := parse.Parse(src, token.lexer.variable, 0) 68 if src.Error() != nil { 69 return nil 70 } 71 id, isId := obj.(string) 72 if isId { 73 obj = token.lexer.parseVariable(src, id) 74 } 75 rightFormatter := obj.(Formatter) 76 src.Consume1('}') 77 return rightFormatter 78 } 79 80 type literalToken struct { 81 lexer *lexer 82 } 83 84 func (token *literalToken) PrefixParse(src *parse.Source) interface{} { 85 return token.lexer.parseLiteral(src, string(read.AnyExcept1(src, nil, '{'))) 86 } 87 88 // {VAR, 89 // {VAR} 90 type variableLexer struct { 91 comma *commaToken 92 id *idToken 93 } 94 95 func newVariableLexer() *variableLexer { 96 return &variableLexer{ 97 comma: &commaToken{}, 98 id: &idToken{}, 99 } 100 } 101 102 func (lexer *variableLexer) PrefixToken(src *parse.Source) parse.PrefixToken { 103 skip.UnicodeSpace(src) 104 return lexer.id 105 } 106 107 func (lexer *variableLexer) InfixToken(src *parse.Source) (parse.InfixToken, int) { 108 skip.UnicodeSpace(src) 109 switch src.Peek()[0] { 110 case ',': 111 return lexer.comma, parse.DefaultPrecedence 112 case '}': 113 return nil, 0 114 default: 115 src.ReportError(errors.New("expect , or }, but found " + string([]byte{src.Peek()[0]}))) 116 return nil, 0 117 } 118 } 119 120 type idToken struct { 121 } 122 123 var patternWhiteSpaceAndPatternSyntax = []*unicode.RangeTable{ 124 unicode.Pattern_White_Space, 125 unicode.Pattern_Syntax, 126 } 127 128 func (token *idToken) PrefixParse(src *parse.Source) interface{} { 129 runes := read.UnicodeRanges(src, nil, nil, patternWhiteSpaceAndPatternSyntax) 130 return string(runes) 131 } 132 133 type commaToken struct { 134 lexer *lexer 135 } 136 137 func (token *commaToken) InfixParse(src *parse.Source, left interface{}) interface{} { 138 src.Consume1(',') 139 funcInvocation := parse.Parse(src, token.lexer.formatter, 0).(funcInvocation) 140 return token.lexer.parseFunc(src, left.(string), funcInvocation.name, funcInvocation.args) 141 } 142 143 // {VAR, FORMATTER, 144 type formatterLexer struct { 145 funcName *funcNameToken 146 } 147 148 func newFormatterLexer() *formatterLexer { 149 return &formatterLexer{ 150 funcName: &funcNameToken{}, 151 } 152 } 153 154 func (lexer *formatterLexer) PrefixToken(src *parse.Source) parse.PrefixToken { 155 skip.UnicodeSpace(src) 156 buf, _ := src.PeekN(6) 157 str := string(buf) 158 switch str { 159 case "select": 160 panic("not implemented") 161 case "plural": 162 panic("not implemented") 163 default: 164 return lexer.funcName 165 } 166 } 167 168 func (lexer *formatterLexer) InfixToken(src *parse.Source) (parse.InfixToken, int) { 169 return nil, 0 170 } 171 172 type funcNameToken struct { 173 lexer *lexer 174 } 175 176 type funcInvocation struct { 177 name string 178 args []string 179 } 180 181 func (token *funcNameToken) PrefixParse(src *parse.Source) interface{} { 182 name := string(read.AnyExcept2(src, nil, ',', '}')) 183 var args []string 184 for { 185 skip.UnicodeSpace(src) 186 switch src.Peek1() { 187 case ',': 188 src.Consume1(',') 189 args = append(args, string(read.AnyExcept2(src, nil, ',', '}'))) 190 case '}': 191 return funcInvocation{name, args} 192 default: 193 src.ReportError(errors.New("expect , or }, but found " + string([]byte{src.Peek()[0]}))) 194 return funcInvocation{name, args} 195 } 196 } 197 } 198 199 // {VAR, select, args...} 200 type selectLexer struct { 201 } 202 203 // {VAR, plural, args...} 204 type pluralLexer struct { 205 }