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  }