Skip to content

Commit

Permalink
Cond eval (#139)
Browse files Browse the repository at this point in the history
Fix cond condition evaluation
  • Loading branch information
ohler55 authored Sep 11, 2023
1 parent 51d8032 commit 1a94a52
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

The structure and content of this file follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [1.19.3] - 2023-09-11
### Fixed
- asm cond condition is now evaluated correctly.

## [1.19.2] - 2023-08-07
### Fixed
- The test tool (tt) package Panic() function should return the recovered panic and now does.
Expand Down
49 changes: 44 additions & 5 deletions asm/cond.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package asm

import (
"fmt"

"github.com/ohler55/ojg/jp"
)

func init() {
Expand All @@ -20,17 +22,54 @@ is returned.`,

func cond(root map[string]any, at any, args ...any) any {
for _, arg := range args {
v := evalArg(root, at, arg)
list, ok := v.([]any)
list, ok := arg.([]any)
if !ok {
panic(fmt.Errorf("cond expects array arguments, not a %T", v))
panic(fmt.Errorf("cond expects array arguments, not a %T", arg))
}
if len(list) != 2 {
panic(fmt.Errorf("cond array arguments must have two elements, not a %d", len(list)))
}
if b, _ := evalArg(root, at, list[0]).(bool); b {
return list[1]
if bv, _ := evalValue(root, at, list[0]).(bool); bv {
return evalValue(root, at, list[1])
}
}
return nil
}

func evalValue(root map[string]any, at any, value any) (result any) {
top:
switch tv := value.(type) {
case *Fn:
result = tv.Eval(root, at, tv.Args...)
case []any:
if 0 < len(tv) {
if name, _ := tv[0].(string); 0 < len(name) {
if af := NewFn(name); af != nil {
af.Args = tv[1:]
af.compile()
value = af
goto top
}
}
}
case jp.Expr:
if 0 < len(tv) {
if _, ok := tv[0].(jp.At); ok {
result = tv.First(at)
} else {
result = tv.First(root)
}
}
case string:
if 0 < len(tv) && (tv[0] == '$' || tv[0] == '@') {
if x, err := jp.Parse([]byte(tv)); err == nil {
value = x
goto top
}
}
result = tv
default:
result = value
}
return
}
21 changes: 21 additions & 0 deletions asm/cond_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,24 @@ func TestCondArgElementCount(t *testing.T) {
err := p.Execute(map[string]any{})
tt.NotNil(t, err)
}

func TestCondEval(t *testing.T) {
root := testPlan(t,
`[
[set $.asm.a [cond [[get "$.src.x[1]"] [get "@.src.x[0]"]]]]
[set $.asm.b [cond ["$.src.x[1]" 2]]]
[set $.asm.c [cond [@.src.y @.src.z]]]
[set $.asm.d [cond [$.src.y abc]]]
]`,
"{src: {x: [1 true 3], y: true, z: 4}}",
)
opt := sopt
opt.Indent = 2
tt.Equal(t,
`{
a: 1
b: 2
c: 4
d: abc
}`, sen.String(root["asm"], &opt))
}

0 comments on commit 1a94a52

Please sign in to comment.