diff --git a/_fixtures/testvariables2.go b/_fixtures/testvariables2.go index a08c3f83d1bfb445c29cd05a603111d212cf0d48..8d448d6f21f2560078373aeb29f3ec09df7aa652 100644 --- a/_fixtures/testvariables2.go +++ b/_fixtures/testvariables2.go @@ -244,6 +244,8 @@ func main() { longstr := "very long string 0123456789a0123456789b0123456789c0123456789d0123456789e0123456789f0123456789g012345678h90123456789i0123456789j0123456789" + var nilstruct *astruct = nil + var amb1 = 1 runtime.Breakpoint() for amb1 := 0; amb1 < 10; amb1++ { @@ -251,5 +253,5 @@ func main() { } runtime.Breakpoint() - fmt.Println(i1, i2, i3, p1, amb1, s1, s3, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf, mainMenu, b, b2, sd, anonstruct1, anonstruct2, anoniface1, anonfunc, mapanonstruct1, ifacearr, efacearr, ni8, ni16, ni32, pinf, ninf, nan, zsvmap, zsslice, zsvar, tm, errtypednil, emptyslice, emptymap, byteslice, runeslice, longstr) + fmt.Println(i1, i2, i3, p1, amb1, s1, s3, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf, mainMenu, b, b2, sd, anonstruct1, anonstruct2, anoniface1, anonfunc, mapanonstruct1, ifacearr, efacearr, ni8, ni16, ni32, pinf, ninf, nan, zsvmap, zsslice, zsvar, tm, errtypednil, emptyslice, emptymap, byteslice, runeslice, longstr, nilstruct) } diff --git a/pkg/proc/eval.go b/pkg/proc/eval.go index f80e4b81620565009d7b085bf882ec36a142cc11..d927fb4ebd0aa138ee9b827c879f665069643c71 100644 --- a/pkg/proc/eval.go +++ b/pkg/proc/eval.go @@ -931,19 +931,28 @@ func (scope *EvalScope) evalBinary(node *ast.BinaryExpr) (*Variable, error) { if err != nil { return nil, err } + xv.loadValue(loadFullValue) + if xv.Unreadable != nil { + return nil, xv.Unreadable + } + + // short circuits logical operators + switch node.Op { + case token.LAND: + if !constant.BoolVal(xv.Value) { + return newConstant(xv.Value, xv.mem), nil + } + case token.LOR: + if constant.BoolVal(xv.Value) { + return newConstant(xv.Value, xv.mem), nil + } + } yv, err := scope.evalAST(node.Y) if err != nil { return nil, err } - - xv.loadValue(loadFullValue) yv.loadValue(loadFullValue) - - if xv.Unreadable != nil { - return nil, xv.Unreadable - } - if yv.Unreadable != nil { return nil, yv.Unreadable } diff --git a/service/test/variables_test.go b/service/test/variables_test.go index de0b90bf1eb68e9ebc45c0dec048841da9982ce1..1c7f7883b7febc5d4e2bd0002666d393cdd2a474 100644 --- a/service/test/variables_test.go +++ b/service/test/variables_test.go @@ -735,6 +735,10 @@ func TestEvalExpression(t *testing.T) { {"ch1.dataqsiz", false, "10", "10", "uint", nil}, {"ch1.buf", false, `*[10]int [1,4,3,2,0,0,0,0,0,0]`, `(*[10]int)(…`, "*[10]int", nil}, {"ch1.buf[0]", false, "1", "1", "int", nil}, + + // shortcircuited logical operators + {"nilstruct != nil && nilstruct.A == 1", false, "false", "false", "", nil}, + {"nilstruct == nil || nilstruct.A == 1", false, "true", "true", "", nil}, } ver, _ := goversion.Parse(runtime.Version())