Skip to content

Commit e6dd323

Browse files
committed
Create a concatenation util node
Preliminary commit for object concatenation, since it needs to be recursive.
1 parent de0cc1b commit e6dd323

File tree

4 files changed

+67
-119
lines changed

4 files changed

+67
-119
lines changed

lkql_jit/language/src/main/java/com/adacore/lkql_jit/built_ins/BuiltInFunctions.java

Lines changed: 12 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.adacore.lkql_jit.LKQLTypeSystemGen;
1010
import com.adacore.lkql_jit.annotations.*;
1111
import com.adacore.lkql_jit.exception.LKQLRuntimeException;
12+
import com.adacore.lkql_jit.nodes.utils.ConcatenationNode;
1213
import com.adacore.lkql_jit.runtime.values.*;
1314
import com.adacore.lkql_jit.runtime.values.bases.BasicLKQLValue;
1415
import com.adacore.lkql_jit.runtime.values.interfaces.Indexable;
@@ -274,58 +275,22 @@ protected String executeOnString(String fileName) {
274275
)
275276
abstract static class ConcatExpr extends BuiltInBody {
276277

277-
protected static boolean isString(Object o) {
278-
return LKQLTypeSystemGen.isString(o);
279-
}
280-
281-
protected static boolean isList(Object o) {
282-
return LKQLTypeSystemGen.isLKQLList(o);
283-
}
284-
285-
@Specialization(guards = { "list.size() > 0", "isString(list.get(0))" })
286-
protected String onListOfStrings(LKQLList list) {
287-
// Create a string builder and add all strings in the list
288-
String result = LKQLTypeSystemGen.asString(list.get(0));
289-
for (int i = 1; i < list.size(); i++) {
290-
final Object item = list.get(i);
291-
if (!LKQLTypeSystemGen.isString(item)) {
292-
this.invalidElemType(list, item);
293-
}
294-
result = StringUtils.concat(result, LKQLTypeSystemGen.asString(item));
295-
}
296-
return result;
297-
}
298-
299-
@Specialization(guards = { "list.size() > 0", "isList(list.get(0))" })
300-
protected LKQLList onListOfLists(LKQLList list) {
301-
Object[] result = LKQLTypeSystemGen.asLKQLList(list.get(0)).getContent();
302-
for (int i = 1; i < list.size(); i++) {
303-
final Object item = list.get(i);
304-
if (!LKQLTypeSystemGen.isLKQLList(item)) {
305-
this.invalidElemType(list, item);
306-
}
307-
result = ArrayUtils.concat(result, LKQLTypeSystemGen.asLKQLList(item).getContent());
278+
@Specialization(guards = "list.size() > 1")
279+
protected Object onMultipleElems(LKQLList list, @Cached ConcatenationNode concat) {
280+
Object res = concat.execute(list.get(0), list.get(1), this.callNode);
281+
for (int i = 2; i < list.size(); i++) {
282+
res = concat.execute(res, list.get(i), this.callNode);
308283
}
309-
return new LKQLList(result);
284+
return res;
310285
}
311286

312-
@Specialization(guards = "notValidElem.size() > 0")
313-
@CompilerDirectives.TruffleBoundary
314-
protected LKQLList invalidElemType(
315-
@SuppressWarnings("unused") LKQLList notValidElem,
316-
@Cached("notValidElem.get(0)") Object elem
317-
) {
318-
throw LKQLRuntimeException.wrongType(
319-
LKQLTypesHelper.LKQL_LIST +
320-
" of " +
321-
LKQLTypesHelper.typeUnion(LKQLTypesHelper.LKQL_LIST, LKQLTypesHelper.LKQL_STRING),
322-
LKQLTypesHelper.fromJava(elem) + " element",
323-
argNode(0)
324-
);
287+
@Specialization(guards = "list.size() == 1")
288+
protected Object onSingleElem(LKQLList list) {
289+
return list.get(0);
325290
}
326291

327-
@Specialization(guards = "emptyList.size() == 0")
328-
protected LKQLList onEmptyList(@SuppressWarnings("unused") LKQLList emptyList) {
292+
@Specialization(guards = "list.size() == 0")
293+
protected LKQLList onEmptyList(@SuppressWarnings("unused") LKQLList list) {
329294
return new LKQLList(new Object[0]);
330295
}
331296
}

lkql_jit/language/src/main/java/com/adacore/lkql_jit/nodes/expressions/operators/BinConcat.java

Lines changed: 4 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,10 @@
55

66
package com.adacore.lkql_jit.nodes.expressions.operators;
77

8-
import com.adacore.lkql_jit.LKQLTypeSystemGen;
9-
import com.adacore.lkql_jit.exception.LKQLRuntimeException;
10-
import com.adacore.lkql_jit.runtime.values.lists.LKQLList;
11-
import com.adacore.lkql_jit.utils.Constants;
12-
import com.adacore.lkql_jit.utils.LKQLTypesHelper;
13-
import com.adacore.lkql_jit.utils.functions.ListUtils;
14-
import com.adacore.lkql_jit.utils.functions.StringUtils;
15-
import com.oracle.truffle.api.dsl.Fallback;
8+
import com.adacore.lkql_jit.nodes.utils.ConcatenationNode;
9+
import com.oracle.truffle.api.dsl.Cached;
1610
import com.oracle.truffle.api.dsl.Specialization;
17-
import com.oracle.truffle.api.interop.InteropLibrary;
18-
import com.oracle.truffle.api.library.CachedLibrary;
1911
import com.oracle.truffle.api.source.SourceSection;
20-
import java.util.ArrayList;
21-
import java.util.List;
2212

2313
/**
2414
* This node represents the concatenation operation in the LKQL language.
@@ -40,66 +30,9 @@ protected BinConcat(SourceSection location) {
4030

4131
// ----- Execution methods -----
4232

43-
/**
44-
* Concatenate two strings.
45-
*
46-
* @param left The left string value.
47-
* @param right The right string value.
48-
* @return The result of the string concatenation.
49-
*/
5033
@Specialization
51-
protected String concatStrings(String left, String right) {
52-
return StringUtils.concat(left, right);
53-
}
54-
55-
/**
56-
* Concatenate two lists.
57-
*
58-
* @param left The left list value.
59-
* @param right The right list value.
60-
* @return The result of the list concatenation.
61-
*/
62-
@Specialization(limit = Constants.SPECIALIZED_LIB_LIMIT)
63-
protected LKQLList concatLists(
64-
final LKQLList left,
65-
final LKQLList right,
66-
@CachedLibrary("left") InteropLibrary leftLibrary,
67-
@CachedLibrary("right") InteropLibrary rightLibrary
68-
) {
69-
try {
70-
final int leftSize = (int) leftLibrary.getArraySize(left);
71-
final int rightSize = (int) rightLibrary.getArraySize(right);
72-
List<Object> resContent = new ArrayList<>(leftSize + rightSize);
73-
ListUtils.addAll(resContent, left.content);
74-
ListUtils.addAll(resContent, right.content);
75-
return new LKQLList(resContent.toArray(new Object[0]));
76-
} catch (Exception e) {
77-
throw LKQLRuntimeException.fromJavaException(e, this);
78-
}
79-
}
80-
81-
/**
82-
* The fallback method if the concatenation is not applied to correct types.
83-
*
84-
* @param left The left value.
85-
* @param right The right value.
86-
*/
87-
@Fallback
88-
protected void nonConcatenable(Object left, Object right) {
89-
if (LKQLTypeSystemGen.isString(left) || LKQLTypeSystemGen.isLKQLList(left)) {
90-
throw LKQLRuntimeException.wrongType(
91-
LKQLTypesHelper.fromJava(left),
92-
LKQLTypesHelper.fromJava(right),
93-
this
94-
);
95-
} else {
96-
throw LKQLRuntimeException.unsupportedOperation(
97-
LKQLTypesHelper.fromJava(left),
98-
"&",
99-
LKQLTypesHelper.fromJava(right),
100-
this
101-
);
102-
}
34+
protected Object doDispatch(Object left, Object right, @Cached ConcatenationNode concat) {
35+
return concat.execute(left, right, this);
10336
}
10437

10538
// ----- Override methods -----
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// Copyright (C) 2005-2024, AdaCore
3+
// SPDX-License-Identifier: GPL-3.0-or-later
4+
//
5+
6+
package com.adacore.lkql_jit.nodes.utils;
7+
8+
import com.adacore.lkql_jit.exception.LKQLRuntimeException;
9+
import com.adacore.lkql_jit.nodes.LKQLNode;
10+
import com.adacore.lkql_jit.runtime.values.lists.LKQLList;
11+
import com.adacore.lkql_jit.utils.LKQLTypesHelper;
12+
import com.adacore.lkql_jit.utils.functions.StringUtils;
13+
import com.oracle.truffle.api.dsl.Fallback;
14+
import com.oracle.truffle.api.dsl.Specialization;
15+
import com.oracle.truffle.api.nodes.Node;
16+
17+
public abstract class ConcatenationNode extends Node {
18+
19+
// ---- Execution methods -----
20+
21+
/** Concat two objects. */
22+
public abstract Object execute(Object left, Object right, LKQLNode caller);
23+
24+
// ----- Specializations -----
25+
26+
@Specialization
27+
protected String doStrings(String left, String right, LKQLNode caller) {
28+
return StringUtils.concat(left, right);
29+
}
30+
31+
@Specialization
32+
protected LKQLList doLists(LKQLList left, LKQLList right, LKQLNode caller) {
33+
final int leftSize = (int) left.size();
34+
final int rightSize = (int) right.size();
35+
final Object[] resContent = new Object[leftSize + rightSize];
36+
System.arraycopy(left.content, 0, resContent, 0, leftSize);
37+
System.arraycopy(right.content, 0, resContent, leftSize, rightSize);
38+
return new LKQLList(resContent);
39+
}
40+
41+
@Fallback
42+
protected void nonConcatenable(Object left, Object right, LKQLNode caller) {
43+
throw LKQLRuntimeException.unsupportedOperation(
44+
LKQLTypesHelper.fromJava(left),
45+
"&",
46+
LKQLTypesHelper.fromJava(right),
47+
caller
48+
);
49+
}
50+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
script.lkql:1:7: error: Type error: expected List but got Int
1+
script.lkql:1:7: error: Unsupported operation: List & Int
22
1 | print([] & 2)
33
| ^^^^^^

0 commit comments

Comments
 (0)