Skip to content

Commit 584aa35

Browse files
yaronfysheffer
and
ysheffer
authored
Expressions: coverage (#133)
* Repro issue 84 * Improve coverage for expressions, specifically Print * Clean up warnings --------- Co-authored-by: ysheffer <[email protected]>
1 parent 0bfaab9 commit 584aa35

File tree

2 files changed

+97
-24
lines changed

2 files changed

+97
-24
lines changed

datalog/expressions.go

+48-24
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ func (e *Expression) Evaluate(values map[Variable]*Term, symbols *SymbolTable) (
3333
return nil, fmt.Errorf("datalog: expressions: unknown variable %d", id.(Variable))
3434
}
3535
id = *idptr
36+
default: // do nothing
37+
}
38+
err := s.Push(id)
39+
if err != nil {
40+
return nil, fmt.Errorf("datalog: expressions: stack overflow")
3641
}
37-
s.Push(id)
3842
case OpTypeUnary:
3943
v, err := s.Pop()
4044
if err != nil {
@@ -45,7 +49,10 @@ func (e *Expression) Evaluate(values map[Variable]*Term, symbols *SymbolTable) (
4549
if err != nil {
4650
return nil, fmt.Errorf("datalog: expressions: unary eval failed: %w", err)
4751
}
48-
s.Push(res)
52+
err = s.Push(res)
53+
if err != nil {
54+
return nil, fmt.Errorf("datalog: expressions: stack overflow")
55+
}
4956
case OpTypeBinary:
5057
right, err := s.Pop()
5158
if err != nil {
@@ -60,7 +67,10 @@ func (e *Expression) Evaluate(values map[Variable]*Term, symbols *SymbolTable) (
6067
if err != nil {
6168
return nil, fmt.Errorf("datalog: expressions: binary eval failed: %w", err)
6269
}
63-
s.Push(res)
70+
err = s.Push(res)
71+
if err != nil {
72+
return nil, fmt.Errorf("datalog: expressions: stack overflow")
73+
}
6474
default:
6575
return nil, fmt.Errorf("datalog: expressions: unsupported Op: %v", op.Type())
6676
}
@@ -83,22 +93,31 @@ func (e *Expression) Print(symbols *SymbolTable) string {
8393
id := op.(Value).ID
8494
switch id.Type() {
8595
case TermTypeString:
86-
s.Push(fmt.Sprintf("\"%s\"", symbols.Str(id.(String))))
96+
err := s.Push(fmt.Sprintf("\"%s\"", symbols.Str(id.(String))))
97+
if err != nil {
98+
return "<invalid expression: stack overflow>"
99+
}
87100
case TermTypeVariable:
88-
s.Push(fmt.Sprintf("$%s", symbols.Var(id.(Variable))))
101+
err := s.Push(fmt.Sprintf("$%s", symbols.Var(id.(Variable))))
102+
if err != nil {
103+
return "<invalid expression: stack overflow>"
104+
}
89105
default:
90-
s.Push(id.String())
106+
err := s.Push(id.String())
107+
if err != nil {
108+
return "<invalid expression: stack overflow>"
109+
}
91110
}
92111
case OpTypeUnary:
93112
v, err := s.Pop()
94113
if err != nil {
95114
return "<invalid expression: unary operation failed to pop value>"
96115
}
97116
res := op.(UnaryOp).Print(v)
117+
err = s.Push(res)
98118
if err != nil {
99-
return "<invalid expression: binary operation failed to pop right value>"
119+
return "<invalid expression: stack overflow>"
100120
}
101-
s.Push(res)
102121
case OpTypeBinary:
103122
right, err := s.Pop()
104123
if err != nil {
@@ -109,7 +128,10 @@ func (e *Expression) Print(symbols *SymbolTable) string {
109128
return "<invalid expression: binary operation failed to pop left value>"
110129
}
111130
res := op.(BinaryOp).Print(left, right)
112-
s.Push(res)
131+
err = s.Push(res)
132+
if err != nil {
133+
return "<invalid expression: stack overflow>"
134+
}
113135
default:
114136
return fmt.Sprintf("<invalid expression: unsupported op type %v>", op.Type())
115137
}
@@ -160,6 +182,8 @@ func (op UnaryOp) Print(value string) string {
160182
out = fmt.Sprintf("!%s", value)
161183
case UnaryParens:
162184
out = fmt.Sprintf("(%s)", value)
185+
case UnaryLength:
186+
out = fmt.Sprintf("%s.length()", value)
163187
default:
164188
out = fmt.Sprintf("unknown(%s)", value)
165189
}
@@ -186,7 +210,7 @@ type Negate struct{}
186210
func (Negate) Type() UnaryOpType {
187211
return UnaryNegate
188212
}
189-
func (Negate) Eval(value Term, symbols *SymbolTable) (Term, error) {
213+
func (Negate) Eval(value Term, _ *SymbolTable) (Term, error) {
190214
var out Term
191215
switch value.Type() {
192216
case TermTypeBool:
@@ -206,7 +230,7 @@ type Parens struct{}
206230
func (Parens) Type() UnaryOpType {
207231
return UnaryParens
208232
}
209-
func (Parens) Eval(value Term, symbols *SymbolTable) (Term, error) {
233+
func (Parens) Eval(value Term, _ *SymbolTable) (Term, error) {
210234
return value, nil
211235
}
212236

@@ -228,7 +252,7 @@ func (Length) Eval(value Term, symbols *SymbolTable) (Term, error) {
228252
case TermTypeSet:
229253
out = Integer(len(value.(Set)))
230254
default:
231-
return nil, fmt.Errorf("datalog: unexpected Negate value type: %d", value.Type())
255+
return nil, fmt.Errorf("datalog: unexpected Length value type: %d", value.Type())
232256
}
233257
return out, nil
234258
}
@@ -318,7 +342,7 @@ type LessThan struct{}
318342
func (LessThan) Type() BinaryOpType {
319343
return BinaryLessThan
320344
}
321-
func (LessThan) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
345+
func (LessThan) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
322346
if g, w := left.Type(), right.Type(); g != w {
323347
return nil, fmt.Errorf("datalog: LessThan type mismatch: %d != %d", g, w)
324348
}
@@ -344,7 +368,7 @@ type LessOrEqual struct{}
344368
func (LessOrEqual) Type() BinaryOpType {
345369
return BinaryLessOrEqual
346370
}
347-
func (LessOrEqual) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
371+
func (LessOrEqual) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
348372
if g, w := left.Type(), right.Type(); g != w {
349373
return nil, fmt.Errorf("datalog: LessOrEqual type mismatch: %d != %d", g, w)
350374
}
@@ -370,7 +394,7 @@ type GreaterThan struct{}
370394
func (GreaterThan) Type() BinaryOpType {
371395
return BinaryGreaterThan
372396
}
373-
func (GreaterThan) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
397+
func (GreaterThan) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
374398
if g, w := left.Type(), right.Type(); g != w {
375399
return nil, fmt.Errorf("datalog: GreaterThan type mismatch: %d != %d", g, w)
376400
}
@@ -396,7 +420,7 @@ type GreaterOrEqual struct{}
396420
func (GreaterOrEqual) Type() BinaryOpType {
397421
return BinaryGreaterOrEqual
398422
}
399-
func (GreaterOrEqual) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
423+
func (GreaterOrEqual) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
400424
if g, w := left.Type(), right.Type(); g != w {
401425
return nil, fmt.Errorf("datalog: GreaterOrEqual type mismatch: %d != %d", g, w)
402426
}
@@ -422,7 +446,7 @@ type Equal struct{}
422446
func (Equal) Type() BinaryOpType {
423447
return BinaryEqual
424448
}
425-
func (Equal) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
449+
func (Equal) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
426450
if g, w := left.Type(), right.Type(); g != w {
427451
return nil, fmt.Errorf("datalog: Equal type mismatch: %d != %d", g, w)
428452
}
@@ -510,7 +534,7 @@ type Intersection struct{}
510534
func (Intersection) Type() BinaryOpType {
511535
return BinaryIntersection
512536
}
513-
func (Intersection) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
537+
func (Intersection) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
514538
set, ok := left.(Set)
515539
if !ok {
516540
return nil, errors.New("datalog: Intersection left value must be a Set")
@@ -530,7 +554,7 @@ type Union struct{}
530554
func (Union) Type() BinaryOpType {
531555
return BinaryUnion
532556
}
533-
func (Union) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
557+
func (Union) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
534558
set, ok := left.(Set)
535559
if !ok {
536560
return nil, errors.New("datalog: Union left value must be a Set")
@@ -654,7 +678,7 @@ type Sub struct{}
654678
func (Sub) Type() BinaryOpType {
655679
return BinarySub
656680
}
657-
func (Sub) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
681+
func (Sub) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
658682
ileft, ok := left.(Integer)
659683
if !ok {
660684
return nil, fmt.Errorf("datalog: Sub requires left value to be an Integer, got %T", left)
@@ -682,7 +706,7 @@ type Mul struct{}
682706
func (Mul) Type() BinaryOpType {
683707
return BinaryMul
684708
}
685-
func (Mul) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
709+
func (Mul) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
686710
ileft, ok := left.(Integer)
687711
if !ok {
688712
return nil, fmt.Errorf("datalog: Mul requires left value to be an Integer, got %T", left)
@@ -711,7 +735,7 @@ type Div struct{}
711735
func (Div) Type() BinaryOpType {
712736
return BinaryDiv
713737
}
714-
func (Div) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
738+
func (Div) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
715739
ileft, ok := left.(Integer)
716740
if !ok {
717741
return nil, fmt.Errorf("datalog: Div requires left value to be an Integer, got %T", left)
@@ -735,7 +759,7 @@ type And struct{}
735759
func (And) Type() BinaryOpType {
736760
return BinaryAnd
737761
}
738-
func (And) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
762+
func (And) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
739763
bleft, ok := left.(Bool)
740764
if !ok {
741765
return nil, fmt.Errorf("datalog: And requires left value to be a Bool, got %T", left)
@@ -755,7 +779,7 @@ type Or struct{}
755779
func (Or) Type() BinaryOpType {
756780
return BinaryOr
757781
}
758-
func (Or) Eval(left Term, right Term, symbols *SymbolTable) (Term, error) {
782+
func (Or) Eval(left Term, right Term, _ *SymbolTable) (Term, error) {
759783
bleft, ok := left.(Bool)
760784
if !ok {
761785
return nil, fmt.Errorf("datalog: Or requires left value to be a Bool, got %T", left)

datalog/expressions_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -1188,3 +1188,52 @@ func TestBinaryOr(t *testing.T) {
11881188
})
11891189
}
11901190
}
1191+
1192+
func TestPrint(t *testing.T) {
1193+
syms := SymbolTable{}
1194+
syms.Insert("abc")
1195+
testCases := []struct {
1196+
desc string
1197+
expr Expression
1198+
res string
1199+
}{
1200+
{
1201+
desc: "number",
1202+
expr: Expression{Value{Integer(9)}},
1203+
res: "9",
1204+
},
1205+
{
1206+
desc: "string",
1207+
expr: Expression{Value{syms.Sym("abc")}},
1208+
res: "\"abc\"",
1209+
},
1210+
{
1211+
desc: "unary",
1212+
expr: Expression{Value{syms.Sym("abc")}, UnaryOp{Length{}}},
1213+
res: "\"abc\".length()",
1214+
},
1215+
{
1216+
desc: "binary",
1217+
expr: Expression{Value{Integer(9)}, Value{Integer(4)}, BinaryOp{Mul{}}},
1218+
res: "9 * 4",
1219+
},
1220+
{
1221+
desc: "parens",
1222+
expr: Expression{
1223+
Value{Integer(9)},
1224+
Value{Integer(3)},
1225+
BinaryOp{Add{}},
1226+
UnaryOp{Parens{}},
1227+
Value{Integer(4)},
1228+
BinaryOp{Div{}},
1229+
},
1230+
res: "(9 + 3) / 4",
1231+
},
1232+
}
1233+
for _, tc := range testCases {
1234+
t.Run(tc.desc, func(t *testing.T) {
1235+
p := tc.expr.Print(&syms)
1236+
require.Equal(t, tc.res, p)
1237+
})
1238+
}
1239+
}

0 commit comments

Comments
 (0)