diff --git a/src/exprs.c b/src/exprs.c index 80dc4123efb..3fd43fbbf9d 100644 --- a/src/exprs.c +++ b/src/exprs.c @@ -919,9 +919,18 @@ Obj EvalPermExpr ( ** ** 'EvalListExpr' just calls 'ListExpr1' and 'ListExpr2' to evaluate the ** list expression. +** +** The 'safe' argument to ListExpr1 and ListExpr2 handle code which abuses ~ +** access and change the partially built list. +** +** When 'safe' is 1, we use a slower code path which ensures the list is +** in a valid state after each element is added, and not crash if the +** size or TNUM of the list is changed during the construction of elements +** in the list. +** */ -Obj ListExpr1 ( Expr expr ); -void ListExpr2 ( Obj list, Expr expr ); +Obj ListExpr1 ( Expr expr, Int safe ); +void ListExpr2 ( Obj list, Expr expr, Int safe ); Obj RecExpr1 ( Expr expr ); void RecExpr2 ( Obj rec, Expr expr ); @@ -931,8 +940,8 @@ Obj EvalListExpr ( Obj list; /* list value, result */ /* evaluate the list expression */ - list = ListExpr1( expr ); - ListExpr2( list, expr ); + list = ListExpr1( expr, 0 ); + ListExpr2( list, expr, 0 ); /* return the result */ return list; @@ -964,13 +973,13 @@ Obj EvalListTildeExpr ( tilde = STATE( Tilde ); /* create the list value */ - list = ListExpr1( expr ); + list = ListExpr1( expr, 1 ); /* assign the list to '~' */ STATE(Tilde) = list; /* evaluate the subexpressions into the list value */ - ListExpr2( list, expr ); + ListExpr2( list, expr, 1 ); /* restore old value of '~' */ STATE(Tilde) = tilde; @@ -999,8 +1008,9 @@ Obj EvalListTildeExpr ( ** '[ [1], ~[1] ]' requires that the value of one subexpression is entered ** into the list value before the next subexpression is evaluated. */ -Obj ListExpr1 ( - Expr expr ) +ALWAYS_INLINE Obj ListExpr1 ( + Expr expr, + Int safe ) { Obj list; /* list value, result */ Int len; /* logical length of the list */ @@ -1015,15 +1025,21 @@ Obj ListExpr1 ( else { list = NEW_PLIST( T_PLIST, len ); } - SET_LEN_PLIST( list, len ); + if(safe) { + SET_LEN_PLIST( list, 0 ); + } + else { + SET_LEN_PLIST( list, len ); + } /* return the list */ return list; } -void ListExpr2 ( +ALWAYS_INLINE void ListExpr2 ( Obj list, - Expr expr ) + Expr expr, + Int safe ) { Obj sub; /* value of a subexpression */ Int len; /* logical length of the list */ @@ -1053,17 +1069,25 @@ void ListExpr2 ( { if (posshole == 1) { - SET_FILT_LIST(list, FN_IS_NDENSE); + if(!safe || TNUM_OBJ(list) == T_PLIST) { + SET_FILT_LIST(list, FN_IS_NDENSE); + } posshole = 2; } sub = EVAL_EXPR( ADDR_EXPR(expr)[i-1] ); - SET_ELM_PLIST( list, i, sub ); + if(safe) { + ASS_LIST( list, i, sub ); + } + else { + SET_ELM_PLIST( list, i, sub ); + } CHANGED_BAG( list ); } } - if (!posshole) + if (!posshole && !safe) { SET_FILT_LIST(list, FN_IS_DENSE); + } } diff --git a/tst/testinstall/tilde.tst b/tst/testinstall/tilde.tst index 1c03f2567fb..df2b79b14dc 100644 --- a/tst/testinstall/tilde.tst +++ b/tst/testinstall/tilde.tst @@ -85,4 +85,15 @@ true gap> i := InputTextString( "local a; a := 10; return rec(a := a*10, b := ~);" );; gap> r := rec(a := ~, b := ReadAsFunction(i)(), c := ~.b.a); rec( a := ~, b := rec( a := 100, b := ~.b ), c := 100 ) +gap> [Length(~),Length(~),Length(~)]; +[ 0, 1, 2 ] +gap> (function() return [Length(~),Length(~),Length(~)]; end)(); +[ 0, 1, 2 ] +gap> rem := function(l) Remove(l); return 1; end;; +gap> [2,rem(~),rem(~),rem(~)]; +[ ,,, 1 ] +gap> [2,rem(~),3,4,rem(~),5,6,rem(~)]; +[ , 1, 3,, 1, 5,, 1 ] +gap> (function() return [2,rem(~),3,4,rem(~),5,6,rem(~)]; end)(); +[ , 1, 3,, 1, 5,, 1 ] gap> STOP_TEST( "tilde.tst", 1);