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  }