Skip to content

Commit cacc022

Browse files
authored
Fix: nested spread operator handling (#221)
1 parent 8f95045 commit cacc022

File tree

4 files changed

+46
-15
lines changed

4 files changed

+46
-15
lines changed

cirrus.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[[orgs]]
22
name = "Expression"
3-
definitionFile = "config/dev.json"
3+
definitionFile = "config/dev-communities.json"
44

55
[commands]
66
ls = "sf org list --skip-connection-status"
@@ -12,6 +12,7 @@ generate-library-docs = "bun scripts/generate-library-docs.mjs"
1212
prep-package = "bun scripts/prepare-for-packaging.mjs"
1313
run-package = "cirrus package create -p Expression -t minor -x -c --promote -w 60"
1414
post-package = "bun scripts/post-packaging.mjs"
15+
deploy-conference-community = "sf project deploy start -d unpackaged/examples/expression-conf/main"
1516
import-data = "sf data import tree -p unpackaged/examples/expression-conf/data/data-plan.json"
1617

1718
[flow.start-dev]
@@ -20,6 +21,7 @@ steps = [
2021
{ type = "create_scratch", org = "Expression" },
2122
{ type = "command", name = "deploy" },
2223
{ type = "command", name = "assign-perms" },
24+
{ type = "command", name = "deploy-conference-community" },
2325
{ type = "command", name = "import-data" },
2426
]
2527

expression-src/main/src/interpreter/Interpreter.cls

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
public virtual with sharing class Interpreter implements Visitor {
22
private final Environment env;
33

4-
private Boolean inListLiteral = false;
5-
private Boolean isInMapLiteral = false;
4+
private Integer inListLiteralCounter = 0;
5+
private Integer inMapLiteralCounter = 0;
6+
private final Boolean inListLiteral {
7+
get {
8+
return inListLiteralCounter > 0;
9+
}
10+
}
11+
private final Boolean isInMapLiteral {
12+
get {
13+
return inMapLiteralCounter > 0;
14+
}
15+
}
616

717
public Interpreter(Environment env) {
818
this.env = env;
919
}
1020

11-
public void setIsInListLiteral(Boolean inListLiteral) {
12-
this.inListLiteral = inListLiteral;
21+
public void setIsInListLiteral() {
22+
this.inListLiteralCounter++;
1323
}
1424

1525
public Object interpret(Expr expression) {
@@ -351,7 +361,7 @@ public virtual with sharing class Interpreter implements Visitor {
351361
}
352362

353363
public Object visit(Expr.ListLiteral listLiteral) {
354-
inListLiteral = true;
364+
inListLiteralCounter++;
355365
List<Object> resultList = new List<Object>();
356366
for (Expr expr : listLiteral.elements) {
357367
Object result = evaluate(expr);
@@ -370,7 +380,7 @@ public virtual with sharing class Interpreter implements Visitor {
370380
resultList.add(result);
371381
}
372382
}
373-
inListLiteral = false;
383+
inListLiteralCounter--;
374384
return resultList;
375385
}
376386

@@ -422,7 +432,7 @@ public virtual with sharing class Interpreter implements Visitor {
422432
}
423433

424434
public Object visit(Expr.MapLiteral mapLiteral) {
425-
isInMapLiteral = true;
435+
inMapLiteralCounter++;
426436
Map<Object, Object> resultMap = new Map<Object, Object>();
427437
for (Object element : mapLiteral.elements) {
428438
if (element instanceof Expr.KeyValue) {
@@ -447,7 +457,7 @@ public virtual with sharing class Interpreter implements Visitor {
447457
resultMap.put(conditionalKeyValuePair.key, conditionalKeyValuePair.value);
448458
}
449459
}
450-
isInMapLiteral = false;
460+
inMapLiteralCounter--;
451461
return resultMap;
452462
}
453463

expression-src/main/src/interpreter/std-lib/CollectionFunctions.cls

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public with sharing class CollectionFunctions {
6666
*/
6767
private class ListFn extends StandardFunction {
6868
public override Object call(List<Expr> arguments) {
69-
interpreter.setIsInListLiteral(true);
69+
interpreter.setIsInListLiteral();
7070

7171
List<Object> result = new List<Object>();
7272
for (Expr argument : arguments) {

expression-src/spec/language/operators/OperatorTest.cls

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,16 @@ private class OperatorTest {
215215
Assert.areEqual(3, Evaluator.run('SIZE([...LIST(1, 2, 3)])'));
216216
}
217217

218+
@IsTest
219+
private static void spreadOperatorsCanBeNested() {
220+
String formula = '[...[1, 2], ...[3, 4], ...[5, 6]]';
221+
List<Object> result = (List<Object>)Evaluator.run(formula);
222+
Assert.areEqual(6, result.size());
223+
for (Integer i = 0; i < 6; i++) {
224+
Assert.areEqual(i + 1, result[i]);
225+
}
226+
}
227+
218228
@IsTest
219229
private static void spreadOperatorCanBeUsedInsideOfAListFunction() {
220230
Assert.areEqual(3, Evaluator.run('SIZE(LIST(...LIST(1, 2, 3)))'));
@@ -223,14 +233,23 @@ private class OperatorTest {
223233

224234
@IsTest
225235
private static void mapsSupportTheSpreadOperator() {
226-
Map<Object, Object> result = (Map<Object, Object>) Evaluator.run('{...{"a": 1, "b": 2}}');
236+
Map<Object, Object> result = (Map<Object, Object>)Evaluator.run('{...{"a": 1, "b": 2}}');
237+
Assert.areEqual(1, result.get('a'));
238+
Assert.areEqual(2, result.get('b'));
239+
}
240+
241+
@IsTest
242+
private static void spreadOperatorsInMapsCanBeNested() {
243+
Map<Object, Object> result = (Map<Object, Object>)Evaluator.run('{...{"a": 1, "b": 2}, ...{"c": 3, "d": 4}}');
227244
Assert.areEqual(1, result.get('a'));
228245
Assert.areEqual(2, result.get('b'));
246+
Assert.areEqual(3, result.get('c'));
247+
Assert.areEqual(4, result.get('d'));
229248
}
230249

231250
@IsTest
232251
private static void spreadOperatorInMapRespectTheRightmostValue() {
233-
Map<Object, Object> result = (Map<Object, Object>) Evaluator.run('{...{"a": 1, "b": 2}, "b": 3}');
252+
Map<Object, Object> result = (Map<Object, Object>)Evaluator.run('{...{"a": 1, "b": 2}, "b": 3}');
234253
Assert.areEqual(1, result.get('a'));
235254
Assert.areEqual(3, result.get('b'));
236255
}
@@ -248,8 +267,8 @@ private class OperatorTest {
248267
@IsTest
249268
private static void canPipeFunctionCallsMultipleTimes() {
250269
Object result = Evaluator.run('[1, 2, 3, 4, 5, 6] -> WHERE($current > 2) -> WHERE($current < 5)');
251-
Assert.areEqual(2, ((List<Object>) result).size());
252-
Assert.areEqual(3, ((List<Object>) result)[0]);
253-
Assert.areEqual(4, ((List<Object>) result)[1]);
270+
Assert.areEqual(2, ((List<Object>)result).size());
271+
Assert.areEqual(3, ((List<Object>)result)[0]);
272+
Assert.areEqual(4, ((List<Object>)result)[1]);
254273
}
255274
}

0 commit comments

Comments
 (0)