a4a3d05ddd3cdf98462bbc3116bc1e464ca38538

Author
TheEdgeOfRage <git@theedgeofrage.com>
Committer
TheEdgeOfRage <git@theedgeofrage.com>
Date

Message

Improve error messages

Diff

This diff is truncated to protect this page.

  1diff --git a/rpn/lexer.go b/rpn/lexer.go
  2index 1a01c15ec9fb20071821a45958e6f622e43637c5..6dbcc8833d634c0136618640419ec4f3cf41a0ee 100644
  3--- a/rpn/lexer.go
  4+++ b/rpn/lexer.go
  5@@ -11,7 +11,7 @@ type Lexer struct {
  6 	input *Input
  7 }
  8 
  9-func (l *Lexer) parseNumber() (float64, error) {
 10+func (l *Lexer) parseNumber(negative bool) (*Token, error) {
 11 	numStr := ""
 12 	char := l.input.NextChar()
 13 	for {
 14@@ -25,10 +25,14 @@ func (l *Lexer) parseNumber() (float64, error) {
 15 
 16 	num, err := strconv.ParseFloat(numStr, 64)
 17 	if err != nil {
 18-		return 0, err
 19+		return nil, err
 20+	}
 21+	if negative {
 22+		numStr = "-" + numStr
 23+		num = -num
 24 	}
 25 
 26-	return num, nil
 27+	return &Token{number, 0, num, numStr}, nil
 28 }
 29 
 30 func (l *Lexer) parseWord() (*Token, error) {
 31@@ -45,25 +49,25 @@ func (l *Lexer) parseWord() (*Token, error) {
 32 
 33 	switch word {
 34 	case "sqrt":
 35-		return &Token{unaryOp, sqrt, 0}, nil
 36+		return &Token{unaryOp, sqrt, 0, word}, nil
 37 	case "dec":
 38-		return &Token{dec, 0, 0}, nil
 39+		return &Token{dec, 0, 0, word}, nil
 40 	case "bin":
 41-		return &Token{bin, 0, 0}, nil
 42+		return &Token{bin, 0, 0, word}, nil
 43 	case "hex":
 44-		return &Token{hex, 0, 0}, nil
 45+		return &Token{hex, 0, 0, word}, nil
 46 	case "pi":
 47-		return &Token{number, 0, math.Pi}, nil
 48+		return &Token{number, 0, math.Pi, word}, nil
 49 	case "pop":
 50-		return &Token{pop, 0, 0}, nil
 51+		return &Token{pop, 0, 0, word}, nil
 52 	case "swap":
 53-		return &Token{swap, 0, 0}, nil
 54+		return &Token{swap, 0, 0, word}, nil
 55 	case "clr":
 56-		return &Token{clr, 0, 0}, nil
 57+		return &Token{clr, 0, 0, word}, nil
 58 	case "help":
 59-		return &Token{help, 0, 0}, nil
 60+		return &Token{help, 0, 0, word}, nil
 61 	case "exit":
 62-		return &Token{exit, 0, 0}, nil
 63+		return &Token{exit, 0, 0, word}, nil
 64 	default:
 65 		return nil, fmt.Errorf("Unknown input: %s", word)
 66 	}
 67@@ -71,7 +75,6 @@ func (l *Lexer) parseWord() (*Token, error) {
 68 
 69 func (l *Lexer) Parse(input string) ([]*Token, error) {
 70 	var err error
 71-	var num float64
 72 	var token *Token
 73 	l.input = NewInput(input)
 74 	tokens := []*Token{}
 75@@ -84,30 +87,29 @@ func (l *Lexer) Parse(input string) ([]*Token, error) {
 76 		switch char {
 77 		case '+':
 78 			l.input.Eat()
 79-			token = &Token{binaryOp, plus, 0}
 80+			token = &Token{binaryOp, plus, 0, string(char)}
 81 		case '-':
 82 			char = l.input.Eat()
 83 			if unicode.IsNumber(char) {
 84-				num, err = l.parseNumber()
 85-				token = &Token{number, 0, -num}
 86+				token, err = l.parseNumber(true)
 87 				if err != nil {
 88 					return nil, err
 89 				}
 90 			} else {
 91-				token = &Token{binaryOp, minus, 0}
 92+				token = &Token{binaryOp, minus, 0, string(char)}
 93 			}
 94 		case '*':
 95 			l.input.Eat()
 96-			token = &Token{binaryOp, multiply, 0}
 97+			token = &Token{binaryOp, multiply, 0, string(char)}
 98 		case '/':
 99 			l.input.Eat()
100-			token = &Token{binaryOp, divide, 0}
101+			token = &Token{binaryOp, divide, 0, string(char)}
102 		case '%':
103 			l.input.Eat()
104-			token = &Token{binaryOp, mod, 0}
105diff --git a/rpn/rpn.go b/rpn/rpn.go
106index 558c8d5f6db0d706fb8df65062410019b1a0e004..0b5620378105ac6595ecfc55de7eb7884b0e244c 100644
107--- a/rpn/rpn.go
108+++ b/rpn/rpn.go
109@@ -1,12 +1,10 @@
110 package rpn
111 
112 import (
113-	"errors"
114+	"fmt"
115 	"math"
116 )
117 
118-var ErrExit = errors.New("exit")
119-
120 type RPN struct {
121 	stack *Stack
122 	lexer *Lexer
123@@ -62,10 +60,15 @@ func (r *RPN) Eval(input string) error {
124 				if a == 0 {
125 					r.stack.Push(b)
126 					r.stack.Push(a)
127-					return errors.New("can't divide by zero")
128+					return fmt.Errorf("Can't divide by zero")
129 				}
130 				r.stack.Push(b / a)
131 			case mod:
132+				if a == 0 {
133+					r.stack.Push(b)
134+					r.stack.Push(a)
135+					return fmt.Errorf("Can't divide by zero")
136+				}
137 				r.stack.Push(float64(int64(b) % int64(a)))
138 			case power:
139 				r.stack.Push(math.Pow(b, a))
140@@ -94,9 +97,9 @@ func (r *RPN) Eval(input string) error {
141 		case help:
142 			printHelp()
143 		case exit:
144-			return ErrExit
145+			return fmt.Errorf("exit")
146 		default:
147-			return errors.New("Unknown operation")
148+			return fmt.Errorf("Operation not implemented: %s", token.Original)
149 		}
150 	}
151 
152diff --git a/rpn/stack.go b/rpn/stack.go
153index 318334905bf475a5590168b26de4f2ca8faffe62..c937c14aaf6102229ae91a807d5ae80e69c5adc7 100644
154--- a/rpn/stack.go
155+++ b/rpn/stack.go
156@@ -1,15 +1,11 @@
157 package rpn
158 
159 import (
160-	"errors"
161 	"fmt"
162 	"math"
163 )
164 
165-var (
166-	ErrStackEmpty      = errors.New("stack is empty")
167-	ErrNotEnoughValues = errors.New("not enough values on stack")
168-)
169+var ErrNotEnoughValuesTmpl = "Need at least %d values on the stack to perform this operation"
170 
171 type Stack struct {
172 	values []float64
173@@ -22,7 +18,7 @@ func (s *Stack) Push(value float64) {
174 func (s *Stack) Pop() (float64, error) {
175 	count := s.Len()
176 	if count == 0 {
177-		return 0, ErrStackEmpty
178+		return 0, fmt.Errorf(ErrNotEnoughValuesTmpl, 1)
179 	}
180 	value := s.values[count-1]
181 	s.values = s.values[:count-1]
182@@ -32,7 +28,7 @@ func (s *Stack) Pop() (float64, error) {
183 func (s *Stack) Pop2() (float64, float64, error) {
184 	count := s.Len()
185 	if count < 2 {
186-		return 0, 0, ErrNotEnoughValues
187+		return 0, 0, fmt.Errorf(ErrNotEnoughValuesTmpl, 2)
188 	}
189 	a := s.values[count-1]
190 	b := s.values[count-2]
191@@ -47,7 +43,7 @@ func (s *Stack) Len() int {
192 func (s *Stack) Swap() error {
193 	count := s.Len()
194 	if count < 2 {
195-		return ErrNotEnoughValues
196+		return fmt.Errorf(ErrNotEnoughValuesTmpl, 2)
197 	}
198 	a := s.values[count-1]
199 	b := s.values[count-2]
200diff --git a/rpn/token.go b/rpn/token.go
201index 1d0623ca4115f20a14a6997c3440eef3c198ad93..d6d899ff68ce4eab52b11e8c5772b8f91925c542 100644
202--- a/rpn/token.go
203+++ b/rpn/token.go
204@@ -32,4 +32,5 @@ type Token struct {
205 	Type     TokenType
206 	Operator Operator
207 	Value    float64
208+	Original string
209 }