github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/parse/example/expr/parse_test.go (about) 1 package test 2 3 import ( 4 "testing" 5 "github.com/v2pro/plz/test" 6 "github.com/v2pro/plz/countlog" 7 "github.com/v2pro/plz/test/must" 8 "github.com/v2pro/plz/parse" 9 "io" 10 "github.com/v2pro/plz/parse/read" 11 ) 12 13 func Test(t *testing.T) { 14 t.Run("1+1", test.Case(func(ctx *countlog.Context) { 15 src := parse.NewSourceString(`1+1`) 16 dst := expr.Parse(src, 0) 17 must.Equal(io.EOF, src.Error()) 18 must.Equal(2, dst) 19 })) 20 t.Run("1+1-1", test.Case(func(ctx *countlog.Context) { 21 src := parse.NewSourceString(`1+1-1`) 22 must.Equal(1, expr.Parse(src, 0)) 23 })) 24 t.Run("2×3+1", test.Case(func(ctx *countlog.Context) { 25 src := parse.NewSourceString(`2*3+1`) 26 must.Equal(7, expr.Parse(src, 0)) 27 })) 28 } 29 30 const precedenceAssignment = 1 31 const precedenceConditional = 2 32 const precedenceSum = 3 33 const precedenceProduct = 4 34 const precedenceExponent = 5 35 const precedencePrefix = 6 36 const precedencePostfix = 7 37 const precedenceCall = 8 38 39 type exprLexer struct { 40 value *valueToken 41 plus *plusToken 42 minus *minusToken 43 multiply *multiplyToken 44 } 45 46 var expr = newExprLexer() 47 48 func newExprLexer() *exprLexer { 49 return &exprLexer{ 50 value: &valueToken{}, 51 plus: &plusToken{}, 52 minus: &minusToken{}, 53 multiply: &multiplyToken{}, 54 } 55 } 56 57 func (lexer *exprLexer) Parse(src *parse.Source, precedence int) interface{} { 58 return parse.Parse(src, lexer, precedence) 59 } 60 61 func (lexer *exprLexer) InfixToken(src *parse.Source) (parse.InfixToken, int) { 62 switch src.Peek()[0] { 63 case '+': 64 return lexer.plus, precedenceSum 65 case '-': 66 return lexer.minus, precedenceSum 67 case '*': 68 return lexer.multiply, precedenceProduct 69 default: 70 return nil, 0 71 } 72 } 73 74 func (lexer *exprLexer) PrefixToken(src *parse.Source) parse.PrefixToken { 75 return lexer.value 76 } 77 78 type valueToken struct { 79 } 80 81 func (token *valueToken) PrefixParse(src *parse.Source) interface{} { 82 return read.Int(src) 83 } 84 85 type plusToken struct { 86 } 87 88 func (token *plusToken) InfixParse(src *parse.Source, left interface{}) interface{} { 89 leftValue := left.(int) 90 src.ConsumeN(1) 91 rightValue := expr.Parse(src, precedenceSum).(int) 92 return leftValue + rightValue 93 } 94 95 type minusToken struct { 96 } 97 98 func (token *minusToken) InfixParse(src *parse.Source, left interface{}) interface{} { 99 leftValue := left.(int) 100 src.ConsumeN(1) 101 rightValue := expr.Parse(src, precedenceSum).(int) 102 return leftValue - rightValue 103 } 104 105 type multiplyToken struct { 106 } 107 108 func (token *multiplyToken) InfixParse(src *parse.Source, left interface{}) interface{} { 109 leftValue := left.(int) 110 src.ConsumeN(1) 111 rightValue := expr.Parse(src, precedenceProduct).(int) 112 return leftValue * rightValue 113 }