Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 2 additions & 44 deletions pkg/expressions/stageAnalysis.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package expressions

import (
"strconv"
)

// monitorContext allows monitoring of context use
// largely for static analysis of an expression
//
// largely for static analysis of an expression
type monitorContext struct {
keyLookups int
}
Expand All @@ -26,42 +23,3 @@ func EvalStaticStage(stage KeyBuilderStage) (ret string, ok bool) {
ok = (monitor.keyLookups == 0)
return
}

// Eval a stage, but upon any error, returns default instead
// Deprecated: Consider using EvalStaticStage for better error detection
func EvalStageIndexOrDefault(stages []KeyBuilderStage, idx int, dflt string) string {
if idx < len(stages) {
if val, ok := EvalStaticStage(stages[idx]); ok {
return val
}
}
return dflt
}

// Evals stage and parses as int. If fails for any reason (stage eval or parsing), will return false
func EvalStageInt(stage KeyBuilderStage) (int, bool) {
if s, ok := EvalStaticStage(stage); ok {
if v, err := strconv.Atoi(s); err == nil {
return v, true
}
}
return 0, false
}

// Evals stage and parses as int. If fails for any reason (stage eval or parsing), will return false
func EvalStageInt64(stage KeyBuilderStage) (int64, bool) {
if s, ok := EvalStaticStage(stage); ok {
if v, err := strconv.ParseInt(s, 10, 64); err == nil {
return v, true
}
}
return 0, false
}

// Helper to EvalStageInt
func EvalArgInt(stages []KeyBuilderStage, idx int, dflt int) (int, bool) {
if idx < len(stages) {
return EvalStageInt(stages[idx])
}
return dflt, true
}
74 changes: 15 additions & 59 deletions pkg/expressions/stageAnalysis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,73 +6,29 @@ import (
"github.com/stretchr/testify/assert"
)

func testStageUseContext(ret string) KeyBuilderStage {
return func(context KeyBuilderContext) string {
context.GetMatch(0)
return ret
}
}

func testStageNoContext(ret string) KeyBuilderStage {
return func(context KeyBuilderContext) string {
return ret
}
}
func TestEvalStaticHit(t *testing.T) {
val, ok := EvalStaticStage(func(kbc KeyBuilderContext) string {
return "static"
})

func TestEvaluateStageIndex(t *testing.T) {
stages := []KeyBuilderStage{
testStageUseContext("test1"),
testStageNoContext("test2"),
}

assert.Equal(t, "nope", EvalStageIndexOrDefault(stages, 0, "nope"))
assert.Equal(t, "test2", EvalStageIndexOrDefault(stages, 1, "nope"))
assert.Equal(t, "nope", EvalStageIndexOrDefault(stages, 2, "nope"))
}

func TestEvaluationStageInt(t *testing.T) {
val, ok := EvalStageInt(testStageNoContext("5"))
assert.Equal(t, 5, val)
assert.True(t, ok)

val, ok = EvalStageInt(testStageNoContext("5b"))
assert.Equal(t, 0, val)
assert.False(t, ok)

val, ok = EvalStageInt(testStageUseContext("5"))
assert.Equal(t, 0, val)
assert.False(t, ok)
assert.Equal(t, "static", val)
}

func TestEvaluationStageInt64(t *testing.T) {
val, ok := EvalStageInt64(testStageNoContext("5"))
assert.Equal(t, int64(5), val)
assert.True(t, ok)

val, ok = EvalStageInt64(testStageNoContext("5b"))
assert.Equal(t, int64(0), val)
assert.False(t, ok)
func TestEvalStaticMissMatch(t *testing.T) {
val, ok := EvalStaticStage(func(kbc KeyBuilderContext) string {
return kbc.GetMatch(0) + "hit"
})

val, ok = EvalStageInt64(testStageUseContext("5"))
assert.Equal(t, int64(0), val)
assert.False(t, ok)
assert.Equal(t, "hit", val)
}

func TestEvaluateArgInt(t *testing.T) {
stages := []KeyBuilderStage{
testStageUseContext("5"),
testStageNoContext("6"),
}
func TestEvalStaticMissKey(t *testing.T) {
val, ok := EvalStaticStage(func(kbc KeyBuilderContext) string {
return kbc.GetKey("stuff") + "hit"
})

val, ok := EvalArgInt(stages, 0, 1)
assert.False(t, ok)
assert.Equal(t, val, 0)

val, ok = EvalArgInt(stages, 5, 1)
assert.True(t, ok)
assert.Equal(t, val, 1)

val, ok = EvalArgInt(stages, 1, 1)
assert.True(t, ok)
assert.Equal(t, val, 6)
assert.Equal(t, "hit", val)
}
2 changes: 1 addition & 1 deletion pkg/expressions/stdlib/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func newFuncErr(expr, message string) funcError {

// Realtime errors
const (
ErrorNum = "<BAD-TYPE>" // Error parsing the principle value of the input because of unexpected type (non-numeric)
ErrorNum = "<BAD-TYPE>" // Error parsing the principle value of the input because of unexpected type (numeric)
ErrorParsing = "<PARSE-ERROR>" // Error parsing the principle value of the input (non-numeric)
ErrorArgCount = "<ARGN>" // Function to not support a variation with the given argument count
ErrorConst = "<CONST>" // Expected constant value
Expand Down
28 changes: 20 additions & 8 deletions pkg/expressions/stdlib/funcsArithmatic.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ func arithmaticHelperi(equation func(int, int) int) KeyBuilderFunction {
if len(args) < 2 {
return stageErrArgRange(args, "2+")
}

typedArgs, tOk := mapTypedArgs(args, typedParserInt)
if !tOk {
return stageError(ErrNum)
}

return KeyBuilderStage(func(context KeyBuilderContext) string {
final, err := strconv.Atoi(args[0](context))
if err != nil {
final, ok := typedArgs[0](context)
if !ok {
return ErrorNum
}

for i := 1; i < len(args); i++ {
val, err := strconv.Atoi(args[i](context))
if err != nil {
val, ok := typedArgs[i](context)
if !ok {
return ErrorNum
}
final = equation(final, val)
Expand All @@ -36,15 +42,21 @@ func arithmaticHelperf(equation func(float64, float64) float64) KeyBuilderFuncti
if len(args) < 2 {
return stageErrArgRange(args, "2+")
}

typedArgs, tOk := mapTypedArgs(args, typedParserFloat)
if !tOk {
return stageError(ErrNum)
}

return KeyBuilderStage(func(context KeyBuilderContext) string {
final, err := strconv.ParseFloat(args[0](context), 64)
if err != nil {
final, ok := typedArgs[0](context)
if !ok {
return ErrorNum
}

for i := 1; i < len(args); i++ {
val, err := strconv.ParseFloat(args[i](context), 64)
if err != nil {
val, ok := typedArgs[i](context)
if !ok {
return ErrorNum
}
final = equation(final, val)
Expand Down
18 changes: 18 additions & 0 deletions pkg/expressions/stdlib/funcsArithmatic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,21 @@ func TestLogPow(t *testing.T) {

testExpressionErr(t, mockContext(), "{sqrt 1 2}", "<ARGN>", ErrArgCount)
}

// BenchmarkSumf/{sumf_0_1_2_3_4}-4 2699511 429.5 ns/op 26 B/op 2 allocs/op

// 2 args
// Old: BenchmarkSumf/{sumf_{0}_{0}}-4 3916035 289.7 ns/op 24 B/op 1 allocs/op
// Dynamic non-static: BenchmarkSumf/{sumf_{0}_{0}}-4 3949767 296.8 ns/op 24 B/op 1 allocs/op
// Dynamic single: BenchmarkSumf/{sumf_{0}_1}-4 4475090 261.7 ns/op 24 B/op 1 allocs/op
// Dynamic static: BenchmarkSumf/{sumf_1_1}-4 5338790 220.0 ns/op 24 B/op 1 allocs/op
func BenchmarkSumf(b *testing.B) {
benchmarkExpression(b, mockContext("1"), "{sumf 1 1}", "2")
}

// Old : BenchmarkSumi/{sumi_1_1_1_1}-4 21108159 60.30 ns/op 0 B/op 0 allocs/op
// 1 var : BenchmarkSumi/{sumi_{0}_1_1_1}-4 21317667 47.90 ns/op 0 B/op 0 allocs/op
// All typed: BenchmarkSumi/{sumi_1_1_1_1}-4 31323100 32.60 ns/op 0 B/op 0 allocs/op
func BenchmarkSumi(b *testing.B) {
benchmarkExpression(b, mockContext("1"), "{sumi 1 1 1 1}", "4")
}
19 changes: 14 additions & 5 deletions pkg/expressions/stdlib/funcsComparators.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package stdlib

import (
"strconv"
"strings"

. "rare/pkg/expressions" //lint:ignore ST1001 Legacy
Expand Down Expand Up @@ -29,13 +28,23 @@ func arithmaticEqualityHelper(test func(float64, float64) bool) KeyBuilderFuncti
if len(args) != 2 {
return stageErrArgCount(args, 2)
}

leftArg, lOk := evalTypedStage(args[0], typedParserFloat)
if !lOk {
return stageArgError(ErrNum, 0)
}
rightArg, rOk := evalTypedStage(args[1], typedParserFloat)
if !rOk {
return stageArgError(ErrNum, 1)
}

return KeyBuilderStage(func(context KeyBuilderContext) string {
left, err := strconv.ParseFloat(args[0](context), 64)
if err != nil {
left, lOk := leftArg(context)
if !lOk {
return ErrorNum
}
right, err := strconv.ParseFloat(args[1](context), 64)
if err != nil {
right, rOk := rightArg(context)
if !rOk {
return ErrorNum
}

Expand Down
11 changes: 11 additions & 0 deletions pkg/expressions/stdlib/funcsComparators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func TestComparisonEquality(t *testing.T) {
testExpression(t, mockContext("123", "1234"),
"{eq {0} 123} {eq {0} 1234} {not {eq {0} abc}} {neq 1 2} {neq 1 1}",
"1 1 1 ")
testExpressionErr(t, mockContext(), "{eq a}", "<ARGN>", ErrArgCount)
}

func TestComparisonExpression(t *testing.T) {
Expand All @@ -52,10 +53,20 @@ func TestNotExpression(t *testing.T) {
func TestComparisonLtGtEqual(t *testing.T) {
testExpression(t, mockContext(), "{gte 1 1} {gte 1 2} {gte 2 1} {lte 1 1} {lte 1 2} {lte 2 1}",
"1 1 1 1 ")
testExpressionErr(t, mockContext(), "{gt a}", "<ARGN>", ErrArgCount)
testExpressionErr(t, mockContext(1), "{gt 1 a}", "<BAD-TYPE>", ErrNum)
testExpressionErr(t, mockContext(1), "{gt a 1}", "<BAD-TYPE>", ErrNum)
testExpression(t, mockContext("a"), "{gt {0} 1}", "<BAD-TYPE>")
testExpression(t, mockContext("a"), "{gt 1 {0}}", "<BAD-TYPE>")
}

func TestLike(t *testing.T) {
kb, _ := NewStdKeyBuilder().Compile("{like {0} \"a\"}{like {0} c}")
key := kb.BuildKey(mockContext("ab"))
assert.Equal(t, "ab", key)
}

// BenchmarkComparison/{gt_{0}_2}-4 14308363 81.00 ns/op 0 B/op 0 allocs/op
func BenchmarkComparison(b *testing.B) {
benchmarkExpression(b, mockContext("5"), "{gt {0} 2}", "1")
}
4 changes: 2 additions & 2 deletions pkg/expressions/stdlib/funcsLookups.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func kfLookupKey(args []expressions.KeyBuilderStage) (expressions.KeyBuilderStag
return stageArgError(ErrConst, 1)
}

commentPrefix := expressions.EvalStageIndexOrDefault(args, 2, "")
commentPrefix := EvalStageIndexOrDefault(args, 2, "")

lookup := buildLookupTable(content, commentPrefix)

Expand All @@ -99,7 +99,7 @@ func kfHasKey(args []expressions.KeyBuilderStage) (expressions.KeyBuilderStage,
return stageArgError(ErrConst, 1)
}

commentPrefix := expressions.EvalStageIndexOrDefault(args, 2, "")
commentPrefix := EvalStageIndexOrDefault(args, 2, "")

lookup := buildLookupTable(content, commentPrefix)

Expand Down
Loading