Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 330ef89

Browse files
committed
[[ Bug 11323 ]] Add 'into' form to set operation commands
This patch adds an 'into' clause to the set operation commands allowing commands such as: intersect tLeft with tRight into tResult The operation of the commands is the same as the non-into form except that tLeft does not have to be a variable, and the result of the operation is placed into tResult rather than mutating tLeft.
1 parent f615725 commit 330ef89

4 files changed

Lines changed: 178 additions & 14 deletions

File tree

engine/src/cmds.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,10 +1770,10 @@ class MCSetOp : public MCStatement
17701770

17711771
private:
17721772
MCAutoPointer<MCVarref> destvar;
1773+
MCAutoPointer<MCExpression> destexpr;
17731774
MCAutoPointer<MCExpression> source;
1774-
1775-
protected:
17761775
Op op = kOpNone;
1776+
bool is_into = false;
17771777

17781778
public:
17791779
MCSetOp(Op p_op)

engine/src/cmdsm.cpp

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -865,14 +865,24 @@ Parse_stat MCSetOp::parse(MCScriptPoint &sp)
865865

866866
// MW-2011-06-22: [[ SERVER ]] Update to use SP findvar method to take into account
867867
// execution outwith a handler.
868+
MCerrorlock++;
868869
Symbol_type type;
870+
MCScriptPoint tsp(sp);
869871
if (sp.next(type) != PS_NORMAL || type != ST_ID
870872
|| sp.findvar(sp.gettoken_nameref(), &(&destvar)) != PS_NORMAL
871873
|| destvar -> parsearray(sp) != PS_NORMAL)
872874
{
873-
MCperror->add(PE_ARRAYOP_BADARRAY, sp);
874-
return PS_ERROR;
875-
}
875+
sp = tsp;
876+
MCerrorlock--;
877+
destvar.Reset();
878+
if (sp.parseexp(False, True, &(&destexpr)) != PS_NORMAL)
879+
{
880+
MCperror->add(PE_ARRAYOP_BADARRAY, sp);
881+
return PS_ERROR;
882+
}
883+
}
884+
else
885+
MCerrorlock--;
876886

877887
if (sp.skip_token(SP_REPEAT, TT_UNDEFINED, RF_WITH) == PS_ERROR
878888
&& sp.skip_token(SP_FACTOR, TT_PREP, PT_BY) == PS_ERROR)
@@ -900,6 +910,31 @@ Parse_stat MCSetOp::parse(MCScriptPoint &sp)
900910
return PS_ERROR;
901911
}
902912
}
913+
914+
if (sp.skip_token(SP_FACTOR, TT_PREP, PT_INTO) == PS_NORMAL)
915+
{
916+
if (!destexpr)
917+
{
918+
destexpr.Reset(destvar.Release());
919+
}
920+
921+
Symbol_type ttype;
922+
if (sp.next(ttype) != PS_NORMAL || ttype != ST_ID
923+
|| sp.findvar(sp.gettoken_nameref(), &(&destvar)) != PS_NORMAL
924+
|| destvar -> parsearray(sp) != PS_NORMAL)
925+
{
926+
MCperror->add(PE_ARRAYOP_BADARRAY, sp);
927+
return PS_ERROR;
928+
}
929+
930+
is_into = true;
931+
}
932+
933+
if (!destvar && is_into)
934+
{
935+
MCperror->add(PE_ARRAYOP_DSTNOTCONTAINER, sp);
936+
return PS_ERROR;
937+
}
903938

904939
return PS_NORMAL;
905940
}
@@ -911,16 +946,26 @@ void MCSetOp::exec_ctxt(MCExecContext &ctxt)
911946
if (!ctxt . EvalExprAsValueRef(*source, EE_ARRAYOP_BADEXP, &t_src))
912947
return;
913948

949+
MCAutoValueRef t_dst;
914950
MCContainer t_container;
915-
if (!destvar -> evalcontainer(ctxt, t_container))
916-
{
917-
ctxt . LegacyThrow(EE_ARRAYOP_BADEXP);
918-
return;
919-
}
951+
if (!is_into)
952+
{
953+
if (!destvar -> evalcontainer(ctxt, t_container))
954+
{
955+
ctxt . LegacyThrow(EE_ARRAYOP_BADEXP);
956+
return;
957+
}
920958

921-
MCAutoValueRef t_dst;
922-
if (!t_container.eval(ctxt, &t_dst))
923-
return;
959+
if (!t_container.eval(ctxt, &t_dst))
960+
return;
961+
}
962+
else
963+
{
964+
if (!ctxt.EvalExprAsValueRef(*destexpr, EE_ARRAYOP_BADEXP, &t_dst))
965+
{
966+
return;
967+
}
968+
}
924969

925970
MCAutoValueRef t_dst_value;
926971
switch(op)
@@ -949,7 +994,12 @@ void MCSetOp::exec_ctxt(MCExecContext &ctxt)
949994
}
950995

951996
if (!ctxt . HasError())
952-
t_container.set(ctxt, *t_dst_value);
997+
{
998+
if (!is_into)
999+
t_container.set(ctxt, *t_dst_value);
1000+
else
1001+
destvar->set(ctxt, *t_dst_value);
1002+
}
9531003
}
9541004

9551005
void MCSetOp::compile(MCSyntaxFactoryRef ctxt)

engine/src/parseerrors.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,6 +1786,9 @@ enum Parse_errors
17861786

17871787
// {PE-0578} setop: 'recursive' only makes sense for union or intersect
17881788
PE_ARRAYOP_BADRECURSIVE,
1789+
1790+
// {PE-0579} setop: destination is not a container (did you mean to use 'into'?)
1791+
PE_ARRAYOP_DSTNOTCONTAINER,
17891792
};
17901793

17911794
extern const char *MCparsingerrors;

tests/lcs/core/array/setoperations.livecodescript

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,23 @@ on TestArrayUnion
6262
TestAssert "union: left array, right array, additional key", tArray3[1] is "b"
6363
end TestArrayUnion
6464

65+
on TestArrayUnionInto
66+
local tLeft, tRight, tOut
67+
put "a" into tLeft[1]
68+
put "b" into tRight[2]
69+
union tLeft with tRight into tOut
70+
TestAssert "union into: left array unchanged", \
71+
the number of elements in tLeft is 1 and \
72+
tLeft[1] is "a"
73+
TestAssert "union into: right array unchanged", \
74+
the number of elements in tRight is 1 and \
75+
tRight[2] is "b"
76+
TestAssert "union into: out correct", \
77+
the number of elements in tOut is 2 and \
78+
tOut[1] is "a" and \
79+
tOut[2] is "b"
80+
end TestArrayUnionInto
81+
6582
on TestNestedArrayNonRecursiveUnion
6683

6784
local tLeftArray2, tRightArray2
@@ -109,6 +126,26 @@ on TestNestedArrayRecursiveUnion
109126

110127
end TestNestedArrayRecursiveUnion
111128

129+
on TestArrayRecursiveUnionInto
130+
local tLeft, tRight, tOut
131+
put "a" into tLeft[1][1]
132+
put "b" into tRight[1][2]
133+
union tLeft with tRight recursively into tOut
134+
TestAssert "union into: left array unchanged", \
135+
the number of elements in tLeft is 1 and \
136+
the number of elements in tLeft[1] is 1 and \
137+
tLeft[1][1] is "a"
138+
TestAssert "union into: right array unchanged", \
139+
the number of elements in tRight is 1 and \
140+
the number of elements in tRight[1] is 1 and \
141+
tRight[1][2] is "b"
142+
TestAssert "union into: out correct", \
143+
the number of elements in tOut is 1 and \
144+
the number of elements in tOut[1] is 2 and \
145+
tOut[1][1] is "a" and \
146+
tOut[1][2] is "b"
147+
end TestArrayRecursiveUnionInto
148+
112149
/*
113150
Semantics of array symmetric difference:
114151
@@ -184,6 +221,23 @@ on TestArraySymmetricDifference
184221
tLeftArray[3] is "d"
185222
end TestArraySymmetricDifference
186223

224+
on TestArraySymmetricDifferenceInto
225+
local tLeft, tRight, tOut
226+
put "a" into tLeft[1]
227+
put "b" into tRight[2]
228+
symmetric difference tLeft with tRight into tOut
229+
TestAssert "symmetric difference into: left array unchanged", \
230+
the number of elements in tLeft is 1 and \
231+
tLeft[1] is "a"
232+
TestAssert "symmetric difference into: right array unchanged", \
233+
the number of elements in tRight is 1 and \
234+
tRight[2] is "b"
235+
TestAssert "symmetric difference into: out correct", \
236+
the number of elements in tOut is 2 and \
237+
tOut[1] is "a" and \
238+
tOut[2] is "b"
239+
end TestArraySymmetricDifferenceInto
240+
187241
/*
188242
Semantics of array intersect:
189243
@@ -235,6 +289,24 @@ on TestArrayIntersect
235289

236290
end TestArrayIntersect
237291

292+
on TestArrayIntersectInto
293+
local tLeft, tRight, tOut
294+
put "a" into tLeft[1]
295+
put "c" into tLeft[2]
296+
put "b" into tRight[2]
297+
put "d" into tRight[3]
298+
intersect tLeft with tRight into tOut
299+
TestAssert "intersect into: left array unchanged", \
300+
the number of elements in tLeft is 2 and \
301+
tLeft[1] is "a" and tLeft[2] is "c"
302+
TestAssert "intersect into: right array unchanged", \
303+
the number of elements in tRight is 2 and \
304+
tRight[2] is "b" and tRight[3] is "d"
305+
TestAssert "intersect into: out correct", \
306+
the number of elements in tOut is 1 and \
307+
tOut[2] is "c"
308+
end TestArrayIntersectInto
309+
238310
on TestNestedArrayNonRecursiveIntersect
239311

240312
local tLeftArray2, tRightArray2
@@ -285,6 +357,27 @@ on TestNestedArrayRecursiveIntersect
285357

286358
end TestNestedArrayRecursiveIntersect
287359

360+
on TestArrayRecursiveIntersectInto
361+
local tLeft, tRight, tOut
362+
put "a" into tLeft[1][1]
363+
put "c" into tLeft[1][2]
364+
put "b" into tRight[1][2]
365+
put "d" into tRight[1][3]
366+
intersect tLeft with tRight recursively into tOut
367+
TestAssert "intersect into: left array unchanged", \
368+
the number of elements in tLeft is 1 and \
369+
the number of elements in tLeft[1] is 2 and \
370+
tLeft[1][1] is "a" and tLeft[1][2] is "c"
371+
TestAssert "intersect into: right array unchanged", \
372+
the number of elements in tRight is 1 and \
373+
the number of elements in tRight[1] is 2 and \
374+
tRight[1][2] is "b" and tRight[1][3] is "d"
375+
TestAssert "intersect into: out correct", \
376+
the number of elements in tOut is 1 and \
377+
the number of elements in tOut[1] is 1 and \
378+
tOut[1][2] is "c"
379+
end TestArrayRecursiveIntersectInto
380+
288381
/*
289382
Semantics of array difference:
290383
@@ -356,3 +449,21 @@ on TestArrayDifference
356449
the number of elements in tLeftArray is 1 and \
357450
tLeftArray[2] is "c"
358451
end TestArrayDifference
452+
453+
on TestArrayDifferenceInto
454+
local tLeft, tRight, tOut
455+
put "a" into tLeft[1]
456+
put "c" into tLeft[2]
457+
put "b" into tRight[2]
458+
put "d" into tRight[3]
459+
difference tLeft with tRight into tOut
460+
TestAssert "difference into: left array unchanged", \
461+
the number of elements in tLeft is 2 and \
462+
tLeft[1] is "a" and tLeft[2] is "c"
463+
TestAssert "difference into: right array unchanged", \
464+
the number of elements in tRight is 2 and \
465+
tRight[2] is "b" and tRIght[3] is "d"
466+
TestAssert "difference into: out correct", \
467+
the number of elements in tOut is 1 and \
468+
tOut[1] is "a"
469+
end TestArrayDifferenceInto

0 commit comments

Comments
 (0)