Skip to content

Commit c0bc5fe

Browse files
committed
Add tests and comments
1 parent 17d7db8 commit c0bc5fe

8 files changed

+313
-57
lines changed

README.md

+56-56
Original file line numberDiff line numberDiff line change
@@ -42,56 +42,56 @@ In this case, the expression is parsed once but evaluate twice:
4242
```go
4343
// see TestWithVariablesAndFunctions() in gal_test.go for full code
4444
func main() {
45-
// first of all, parse the expression (once only)
46-
expr := `double(:val1:) + triple(:val2:)`
47-
parsedExpr := gal.Parse(expr)
48-
49-
// step 1: define funcs and vars and Eval the expression
50-
funcs := gal.Functions{
51-
"double": func(args ...gal.Value) gal.Value {
52-
value := args[0].(gal.Numberer)
53-
return value.Number().Multiply(gal.NewNumber(2))
54-
},
55-
"triple": func(args ...gal.Value) gal.Value {
56-
value := args[0].(gal.Numberer)
57-
return value.Number().Multiply(gal.NewNumber(3))
58-
},
59-
}
60-
61-
vars := gal.Variables{
62-
":val1:": gal.NewNumber(4),
63-
":val2:": gal.NewNumber(5),
64-
}
65-
66-
// returns 4 * 2 + 5 * 3 == 23
67-
parsedExpr.Eval(
68-
gal.WithVariables(vars),
69-
gal.WithFunctions(funcs),
70-
)
71-
72-
// step 2: re-define funcs and vars and Eval the expression again
73-
// note that we do not need to parse the expression again, only just evaluate it
74-
funcs = gal.Functions{
75-
"double": func(args ...gal.Value) gal.Value {
76-
value := args[0].(gal.Numberer)
77-
return value.Number().Divide(gal.NewNumber(2))
78-
},
79-
"triple": func(args ...gal.Value) gal.Value {
80-
value := args[0].(gal.Numberer)
81-
return value.Number().Divide(gal.NewNumber(3))
82-
},
83-
}
84-
85-
vars = gal.Variables{
86-
":val1:": gal.NewNumber(2),
87-
":val2:": gal.NewNumber(6),
88-
}
89-
90-
// returns 2 / 2 + 6 / 3 == 3 this time
91-
parsedExpr.Eval(
92-
gal.WithVariables(vars),
93-
gal.WithFunctions(funcs),
94-
)
45+
// first of all, parse the expression (once only)
46+
expr := `double(:val1:) + triple(:val2:)`
47+
parsedExpr := gal.Parse(expr)
48+
49+
// step 1: define funcs and vars and Eval the expression
50+
funcs := gal.Functions{
51+
"double": func(args ...gal.Value) gal.Value {
52+
value := args[0].(gal.Numberer)
53+
return value.Number().Multiply(gal.NewNumber(2))
54+
},
55+
"triple": func(args ...gal.Value) gal.Value {
56+
value := args[0].(gal.Numberer)
57+
return value.Number().Multiply(gal.NewNumber(3))
58+
},
59+
}
60+
61+
vars := gal.Variables{
62+
":val1:": gal.NewNumber(4),
63+
":val2:": gal.NewNumber(5),
64+
}
65+
66+
// returns 4 * 2 + 5 * 3 == 23
67+
parsedExpr.Eval(
68+
gal.WithVariables(vars),
69+
gal.WithFunctions(funcs),
70+
)
71+
72+
// step 2: re-define funcs and vars and Eval the expression again
73+
// note that we do not need to parse the expression again, only just evaluate it
74+
funcs = gal.Functions{
75+
"double": func(args ...gal.Value) gal.Value {
76+
value := args[0].(gal.Numberer)
77+
return value.Number().Divide(gal.NewNumber(2))
78+
},
79+
"triple": func(args ...gal.Value) gal.Value {
80+
value := args[0].(gal.Numberer)
81+
return value.Number().Divide(gal.NewNumber(3))
82+
},
83+
}
84+
85+
vars = gal.Variables{
86+
":val1:": gal.NewNumber(2),
87+
":val2:": gal.NewNumber(6),
88+
}
89+
90+
// returns 2 / 2 + 6 / 3 == 3 this time
91+
parsedExpr.Eval(
92+
gal.WithVariables(vars),
93+
gal.WithFunctions(funcs),
94+
)
9595
}
9696
```
9797

@@ -102,12 +102,12 @@ Numbers implement arbitrary precision fixed-point decimal arithmetic with [shops
102102
## Supported operations
103103

104104
* Operators: `+` `-` `*` `/` `%` `**` `<<` `>>`
105-
* [Precedence](https://en.wikipedia.org/wiki/Order_of_operations#Programming_languages), highest to lowest:
106-
* `**`
107-
* `*` `/` `%`
108-
* `+` `-`
109-
* `<<` `>>`
110-
* Note: Go classifies bit shift operators with the higher `*`.
105+
* [Precedence](https://en.wikipedia.org/wiki/Order_of_operations#Programming_languages), highest to lowest:
106+
* `**`
107+
* `*` `/` `%`
108+
* `+` `-`
109+
* `<<` `>>`
110+
* Note: Go classifies bit shift operators with the higher `*`.
111111
* Types: String, Number
112112
* Associativity with parentheses
113113
* Functions:

coverage.out

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
github.com/seborama/gal/v6/function.go:13: String 100.0%
2+
github.com/seborama/gal/v6/function.go:26: NewFunction 100.0%
3+
github.com/seborama/gal/v6/function.go:34: kind 100.0%
4+
github.com/seborama/gal/v6/function.go:38: Equal 100.0%
5+
github.com/seborama/gal/v6/function.go:47: Eval 83.3%
6+
github.com/seborama/gal/v6/function.go:75: PreDefinedFunction 100.0%
7+
github.com/seborama/gal/v6/function.go:89: UserDefinedFunction 0.0%
8+
github.com/seborama/gal/v6/function.go:97: Pi 66.7%
9+
github.com/seborama/gal/v6/function.go:106: PiLong 75.0%
10+
github.com/seborama/gal/v6/function.go:117: Factorial 60.0%
11+
github.com/seborama/gal/v6/function.go:129: Cos 66.7%
12+
github.com/seborama/gal/v6/function.go:143: Sin 66.7%
13+
github.com/seborama/gal/v6/function.go:157: Tan 66.7%
14+
github.com/seborama/gal/v6/function.go:171: Sqrt 66.7%
15+
github.com/seborama/gal/v6/function.go:185: Floor 66.7%
16+
github.com/seborama/gal/v6/function.go:198: Trunc 70.0%
17+
github.com/seborama/gal/v6/gal.go:31: Parse 80.0%
18+
github.com/seborama/gal/v6/operator.go:5: kind 100.0%
19+
github.com/seborama/gal/v6/operator.go:9: String 100.0%
20+
github.com/seborama/gal/v6/operator.go:25: powerOperators 100.0%
21+
github.com/seborama/gal/v6/operator.go:29: multiplicativeOperators 100.0%
22+
github.com/seborama/gal/v6/operator.go:33: additiveOperators 100.0%
23+
github.com/seborama/gal/v6/operator.go:37: bitwiseShiftOperators 100.0%
24+
github.com/seborama/gal/v6/tree.go:20: TrunkLen 100.0%
25+
github.com/seborama/gal/v6/tree.go:25: FullLen 100.0%
26+
github.com/seborama/gal/v6/tree.go:44: Function 60.0%
27+
github.com/seborama/gal/v6/tree.go:62: Variable 100.0%
28+
github.com/seborama/gal/v6/tree.go:75: WithVariables 100.0%
29+
github.com/seborama/gal/v6/tree.go:83: WithFunctions 100.0%
30+
github.com/seborama/gal/v6/tree.go:92: Eval 100.0%
31+
github.com/seborama/gal/v6/tree.go:117: Split 100.0%
32+
github.com/seborama/gal/v6/tree.go:142: Calc 88.0%
33+
github.com/seborama/gal/v6/tree.go:245: CleanUp 100.0%
34+
github.com/seborama/gal/v6/tree.go:252: cleansePlusMinusTreeStart 87.5%
35+
github.com/seborama/gal/v6/tree.go:270: kind 100.0%
36+
github.com/seborama/gal/v6/tree.go:274: calculate 91.7%
37+
github.com/seborama/gal/v6/tree_builder.go:11: NewTreeBuilder 100.0%
38+
github.com/seborama/gal/v6/tree_builder.go:15: FromExpr 80.0%
39+
github.com/seborama/gal/v6/tree_builder.go:101: extractPart 93.9%
40+
github.com/seborama/gal/v6/tree_builder.go:165: readString 76.9%
41+
github.com/seborama/gal/v6/tree_builder.go:189: readVariable 100.0%
42+
github.com/seborama/gal/v6/tree_builder.go:209: readFunctionName 87.5%
43+
github.com/seborama/gal/v6/tree_builder.go:225: readFunctionArguments 95.0%
44+
github.com/seborama/gal/v6/tree_builder.go:258: readNumber 100.0%
45+
github.com/seborama/gal/v6/tree_builder.go:283: squashPlusMinusChain 100.0%
46+
github.com/seborama/gal/v6/tree_builder.go:308: isBlankSpace 100.0%
47+
github.com/seborama/gal/v6/tree_builder.go:312: readOperator 100.0%
48+
github.com/seborama/gal/v6/tree_builder.go:331: isOperator 100.0%
49+
github.com/seborama/gal/v6/value.go:20: ToNumber 100.0%
50+
github.com/seborama/gal/v6/value.go:28: NewString 100.0%
51+
github.com/seborama/gal/v6/value.go:32: kind 100.0%
52+
github.com/seborama/gal/v6/value.go:36: Equal 100.0%
53+
github.com/seborama/gal/v6/value.go:40: Add 0.0%
54+
github.com/seborama/gal/v6/value.go:48: Sub 0.0%
55+
github.com/seborama/gal/v6/value.go:52: Multiply 0.0%
56+
github.com/seborama/gal/v6/value.go:62: Divide 0.0%
57+
github.com/seborama/gal/v6/value.go:66: PowerOf 0.0%
58+
github.com/seborama/gal/v6/value.go:70: Mod 0.0%
59+
github.com/seborama/gal/v6/value.go:74: LShift 0.0%
60+
github.com/seborama/gal/v6/value.go:78: RShift 0.0%
61+
github.com/seborama/gal/v6/value.go:82: String 100.0%
62+
github.com/seborama/gal/v6/value.go:86: Number 75.0%
63+
github.com/seborama/gal/v6/value.go:99: NewNumber 100.0%
64+
github.com/seborama/gal/v6/value.go:105: NewNumberFromFloat 100.0%
65+
github.com/seborama/gal/v6/value.go:111: NewNumberFromString 75.0%
66+
github.com/seborama/gal/v6/value.go:120: kind 100.0%
67+
github.com/seborama/gal/v6/value.go:124: Equal 100.0%
68+
github.com/seborama/gal/v6/value.go:128: Add 66.7%
69+
github.com/seborama/gal/v6/value.go:136: Sub 40.0%
70+
github.com/seborama/gal/v6/value.go:151: Multiply 66.7%
71+
github.com/seborama/gal/v6/value.go:161: Divide 66.7%
72+
github.com/seborama/gal/v6/value.go:171: PowerOf 66.7%
73+
github.com/seborama/gal/v6/value.go:181: Mod 66.7%
74+
github.com/seborama/gal/v6/value.go:191: LShift 57.1%
75+
github.com/seborama/gal/v6/value.go:208: RShift 57.1%
76+
github.com/seborama/gal/v6/value.go:225: Neg 0.0%
77+
github.com/seborama/gal/v6/value.go:231: Sin 100.0%
78+
github.com/seborama/gal/v6/value.go:237: Cos 100.0%
79+
github.com/seborama/gal/v6/value.go:243: Sqrt 75.0%
80+
github.com/seborama/gal/v6/value.go:254: Tan 100.0%
81+
github.com/seborama/gal/v6/value.go:260: Floor 100.0%
82+
github.com/seborama/gal/v6/value.go:266: Trunc 100.0%
83+
github.com/seborama/gal/v6/value.go:272: Factorial 88.9%
84+
github.com/seborama/gal/v6/value.go:291: String 100.0%
85+
github.com/seborama/gal/v6/value.go:295: Number 100.0%
86+
github.com/seborama/gal/v6/value.go:299: Float64 100.0%
87+
github.com/seborama/gal/v6/value.go:303: Int64 100.0%
88+
github.com/seborama/gal/v6/value.go:311: NewUndefined 0.0%
89+
github.com/seborama/gal/v6/value.go:315: NewUndefinedWithReasonf 100.0%
90+
github.com/seborama/gal/v6/value.go:321: kind 100.0%
91+
github.com/seborama/gal/v6/value.go:325: Equal 100.0%
92+
github.com/seborama/gal/v6/value.go:329: Add 0.0%
93+
github.com/seborama/gal/v6/value.go:333: Sub 0.0%
94+
github.com/seborama/gal/v6/value.go:337: Multiply 0.0%
95+
github.com/seborama/gal/v6/value.go:341: Divide 0.0%
96+
github.com/seborama/gal/v6/value.go:345: PowerOf 0.0%
97+
github.com/seborama/gal/v6/value.go:349: Mod 0.0%
98+
github.com/seborama/gal/v6/value.go:353: LShift 0.0%
99+
github.com/seborama/gal/v6/value.go:357: RShift 0.0%
100+
github.com/seborama/gal/v6/value.go:361: String 0.0%
101+
github.com/seborama/gal/v6/variable.go:7: NewVariable 100.0%
102+
github.com/seborama/gal/v6/variable.go:13: kind 100.0%
103+
github.com/seborama/gal/v6/variable.go:17: String 0.0%
104+
total: (statements) 80.0%

function.go

+20
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,16 @@ func PreDefinedFunction(name string) FunctionalValue {
8484
return nil
8585
}
8686

87+
// UserDefinedFunction is a helper function that returns the definition of the
88+
// provided function name from the supplied userFunctions.
8789
func UserDefinedFunction(name string, userFunctions Functions) FunctionalValue {
8890
// note: for now function names are arbitrarily case-insensitive
8991
lowerName := strings.ToLower(name)
9092

9193
return userFunctions.Function(lowerName)
9294
}
9395

96+
// Pi returns the Value of math.Pi.
9497
func Pi(args ...Value) Value {
9598
if len(args) != 0 {
9699
return NewUndefinedWithReasonf("pi() requires no argument, got %d", len(args))
@@ -99,6 +102,18 @@ func Pi(args ...Value) Value {
99102
return NewNumberFromFloat(math.Pi)
100103
}
101104

105+
// PiLong returns a value of Pi with many more digits than Pi.
106+
func PiLong(args ...Value) Value {
107+
if len(args) != 0 {
108+
return NewUndefinedWithReasonf("pi() requires no argument, got %d", len(args))
109+
}
110+
111+
pi, _ := NewNumberFromString(Pi51199)
112+
113+
return pi
114+
}
115+
116+
// Factorial returns the factorial of the provided argument.
102117
func Factorial(args ...Value) Value {
103118
if len(args) != 1 {
104119
return NewUndefinedWithReasonf("factorial() requires 1 argument, got %d", len(args))
@@ -110,6 +125,7 @@ func Factorial(args ...Value) Value {
110125
return NewUndefinedWithReasonf("factorial(): invalid argument type '%s'", args[0].String())
111126
}
112127

128+
// Cos returns the cosine.
113129
func Cos(args ...Value) Value {
114130
if len(args) != 1 {
115131
return NewUndefinedWithReasonf("cos() requires 1 argument, got %d", len(args))
@@ -123,6 +139,7 @@ func Cos(args ...Value) Value {
123139
return NewUndefinedWithReasonf("cos(): invalid argument type '%s'", args[0].String())
124140
}
125141

142+
// Sin returns the sine.
126143
func Sin(args ...Value) Value {
127144
if len(args) != 1 {
128145
return NewUndefinedWithReasonf("sin() requires 1 argument, got %d", len(args))
@@ -136,6 +153,7 @@ func Sin(args ...Value) Value {
136153
return NewUndefinedWithReasonf("sin(): invalid argument type '%s'", args[0].String())
137154
}
138155

156+
// Tan returns the tangent.
139157
func Tan(args ...Value) Value {
140158
if len(args) != 1 {
141159
return NewUndefinedWithReasonf("tan() requires 1 argument, got %d", len(args))
@@ -149,6 +167,7 @@ func Tan(args ...Value) Value {
149167
return NewUndefinedWithReasonf("tan(): invalid argument type '%s'", args[0].String())
150168
}
151169

170+
// Sqrt returns the square root.
152171
func Sqrt(args ...Value) Value {
153172
if len(args) != 1 {
154173
return NewUndefinedWithReasonf("sqrt() requires 1 argument, got %d", len(args))
@@ -162,6 +181,7 @@ func Sqrt(args ...Value) Value {
162181
return NewUndefinedWithReasonf("sqrt(): invalid argument type '%T'", args[0])
163182
}
164183

184+
// return the floor.
165185
func Floor(args ...Value) Value {
166186
if len(args) != 1 {
167187
return NewUndefinedWithReasonf("floor() requires 1 argument, got %d", len(args))

function_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ func TestPi(t *testing.T) {
1313
assert.Equal(t, gal.NewNumberFromFloat(math.Pi).String(), val.String())
1414
}
1515

16+
func TestPiLong(t *testing.T) {
17+
val := gal.PiLong()
18+
assert.Equal(t, math.Pi, gal.ToNumber(val).Float64())
19+
}
20+
1621
func TestFactorial(t *testing.T) {
1722
val := gal.Factorial(gal.NewNumber(0))
1823
assert.Equal(t, gal.NewNumber(1).String(), val.String())
@@ -23,3 +28,28 @@ func TestFactorial(t *testing.T) {
2328
val = gal.Factorial(gal.NewNumber(10))
2429
assert.Equal(t, gal.NewNumber(3_628_800).String(), val.String())
2530
}
31+
32+
func TestCos(t *testing.T) {
33+
val := gal.Cos(gal.Pi())
34+
assert.Equal(t, -1.0, gal.ToNumber(val).Float64())
35+
}
36+
37+
func TestSin(t *testing.T) {
38+
val := gal.Sin(gal.Pi().Divide(gal.NewNumberFromFloat(2.0)))
39+
assert.Equal(t, 1.0, gal.ToNumber(val).Float64())
40+
}
41+
42+
func TestTan(t *testing.T) {
43+
val := gal.Tan(gal.NewNumberFromFloat(1.57079632))
44+
assert.Equal(t, gal.ToNumber(val).Int64(), int64(147169275))
45+
}
46+
47+
func TestSqrt(t *testing.T) {
48+
val := gal.Sqrt(gal.NewNumberFromFloat(2.0))
49+
assert.InEpsilon(t, gal.ToNumber(val).Float64(), 1.414213562, 0.000001)
50+
}
51+
52+
func TestFloor(t *testing.T) {
53+
val := gal.Floor(gal.NewNumberFromFloat(0.0))
54+
assert.Equal(t, int64(0), gal.ToNumber(val).Int64())
55+
}

pi.go

+4
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)