aboutsummaryrefslogtreecommitdiff
path: root/parser.go
blob: 014624f2ec15fb05de89aa60e67f7ded42799f49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package main

import (
	"fmt"
	"math/big"
)

type Op int

const (
	OpInvalid Op = iota
	OpAdd
	OpSub
	OpMul
	OpDiv
	OpExp
)

type Expr interface {
	Eval() *big.Int
}

type NumExpr struct {
	N *big.Int
}

func (n *NumExpr) Eval() *big.Int {
	return n.N
}

type NopExpr struct {
}

func (e *NopExpr) Eval() *big.Int {
	return &big.Int{}
}

type OpExpr struct {
	Op Op
	L  Expr
	R  Expr
}

func (o *OpExpr) Eval() *big.Int {
	l := o.L.Eval()
	r := o.R.Eval()
	n := new(big.Int)
	switch o.Op {
	case OpAdd:
		n.Add(l, r)
	case OpSub:
		n.Sub(l, r)
	case OpMul:
		n.Mul(l, r)
	case OpDiv:
		n.Div(l, r)
	case OpExp:
		n.Exp(l, r, nil)
	}
	return n
}

func Parse(d []byte) (e Expr, err error) {
	sc := newScanner(d)
	t, d := sc.Scan()
	switch t {
	case NUM:
		s := string(d)
		n, ok := big.NewInt(0).SetString(s, 10)
		if !ok {
			return nil, fmt.Errorf("invalid number %s at %d", s, sc.Pos())
		}
		l := &NumExpr{N: n}
		var op Op
		t, d = sc.Scan()
		switch t {
		case EOF:
			return l, nil
		case ADD:
			op = OpAdd
		case SUB:
			op = OpSub
		case MUL:
			op = OpMul
		case DIV:
			op = OpDiv
		case EXP:
			op = OpExp
		default:
			return nil, fmt.Errorf("expected operator at %d", sc.Pos())
		}
		t, d = sc.Scan()
		if t != NUM {
			return nil, fmt.Errorf("expected number at %d", sc.Pos())
		}
		s = string(d)
		n2, ok := big.NewInt(0).SetString(s, 10)
		if !ok {
			return nil, fmt.Errorf("invalid nummber %s at %d", s, sc.Pos())
		}
		r := &NumExpr{N: n2}
		return &OpExpr{Op: op, L: l, R: r}, nil
	case EOF:
		return &NopExpr{}, nil
	}
	return nil, fmt.Errorf("invalid token %s at index %d", t, sc.Pos())
}