|
7 | 7 |
|
8 | 8 | import com.adacore.lkql_jit.LKQLTypeSystemGen; |
9 | 9 | import com.adacore.lkql_jit.built_ins.BuiltInFunctionValue; |
| 10 | +import com.adacore.lkql_jit.built_ins.SpecializedBuiltInBody; |
10 | 11 | import com.adacore.lkql_jit.exception.LKQLRuntimeException; |
11 | 12 | import com.adacore.lkql_jit.nodes.expressions.Expr; |
12 | | -import com.adacore.lkql_jit.nodes.expressions.FunCall; |
13 | 13 | import com.adacore.lkql_jit.runtime.values.lists.LKQLList; |
14 | 14 | import com.adacore.lkql_jit.utils.LKQLTypesHelper; |
15 | 15 | import com.adacore.lkql_jit.utils.functions.ArrayUtils; |
16 | 16 | import com.adacore.lkql_jit.utils.functions.StringUtils; |
17 | | -import com.oracle.truffle.api.frame.VirtualFrame; |
| 17 | +import com.oracle.truffle.api.CompilerDirectives; |
| 18 | +import com.oracle.truffle.api.dsl.Cached; |
| 19 | +import com.oracle.truffle.api.dsl.Fallback; |
| 20 | +import com.oracle.truffle.api.dsl.Specialization; |
18 | 21 |
|
19 | 22 | /** |
20 | 23 | * This class represents the "concat" built-in function in the LKQL language. |
|
23 | 26 | */ |
24 | 27 | public final class ConcatFunction { |
25 | 28 |
|
26 | | - // ----- Attributes ----- |
27 | | - |
28 | | - /** The name of the function. */ |
29 | 29 | public static final String NAME = "concat"; |
30 | 30 |
|
31 | | - // ----- Class methods ----- |
32 | | - |
| 31 | + /** Get a brand new "concat" function value. */ |
33 | 32 | public static BuiltInFunctionValue getValue() { |
34 | 33 | return new BuiltInFunctionValue( |
35 | 34 | NAME, |
36 | 35 | "Given a list of lists or strings, return a concatenated list or string", |
37 | 36 | new String[] {"lists"}, |
38 | 37 | new Expr[] {null}, |
39 | | - (VirtualFrame frame, FunCall call) -> { |
40 | | - |
41 | | - // Get the argument |
42 | | - Object lists = frame.getArguments()[0]; |
43 | | - |
44 | | - // Check the type of the argument |
45 | | - if (!LKQLTypeSystemGen.isLKQLList(lists)) { |
46 | | - throw LKQLRuntimeException.wrongType( |
47 | | - LKQLTypesHelper.LKQL_LIST, |
48 | | - LKQLTypesHelper.fromJava(lists), |
49 | | - call.getArgList().getArgs()[0]); |
50 | | - } |
51 | | - |
52 | | - // Cast the argument to list |
53 | | - LKQLList listValue = LKQLTypeSystemGen.asLKQLList(lists); |
54 | | - |
55 | | - // If the list is not empty |
56 | | - if (listValue.size() > 0) { |
57 | | - final Object firstItem = listValue.get(0); |
58 | | - |
59 | | - // If the first value is a string look for strings in the list |
60 | | - if (LKQLTypeSystemGen.isString(firstItem)) { |
61 | | - // Create a string builder and add all strings in the list |
62 | | - String result = LKQLTypeSystemGen.asString(firstItem); |
63 | | - for (int i = 1; i < listValue.size(); i++) { |
64 | | - final Object item = listValue.get(i); |
65 | | - if (!LKQLTypeSystemGen.isString(item)) { |
66 | | - throw LKQLRuntimeException.wrongType( |
67 | | - LKQLTypesHelper.LKQL_STRING, |
68 | | - LKQLTypesHelper.fromJava(item), |
69 | | - call.getArgList().getArgs()[0]); |
70 | | - } |
71 | | - result = |
72 | | - StringUtils.concat( |
73 | | - result, LKQLTypeSystemGen.asString(item)); |
74 | | - } |
75 | | - |
76 | | - // Return the result |
77 | | - return result; |
78 | | - } |
79 | | - |
80 | | - // If the first item is a list look for lists in the list |
81 | | - if (LKQLTypeSystemGen.isLKQLList(firstItem)) { |
82 | | - // Create a result array and add all list of the argument |
83 | | - Object[] result = LKQLTypeSystemGen.asLKQLList(firstItem).getContent(); |
84 | | - for (int i = 1; i < listValue.size(); i++) { |
85 | | - final Object item = listValue.get(i); |
86 | | - if (!LKQLTypeSystemGen.isLKQLList(item)) { |
87 | | - throw LKQLRuntimeException.wrongType( |
88 | | - LKQLTypesHelper.LKQL_LIST, |
89 | | - LKQLTypesHelper.fromJava(item), |
90 | | - call.getArgList().getArgs()[0]); |
91 | | - } |
92 | | - result = |
93 | | - ArrayUtils.concat( |
94 | | - result, |
95 | | - LKQLTypeSystemGen.asLKQLList(item).getContent()); |
96 | | - } |
97 | | - return new LKQLList(result); |
98 | | - } |
99 | | - |
100 | | - // Else there is an error |
101 | | - throw LKQLRuntimeException.wrongType( |
102 | | - LKQLTypesHelper.typeUnion( |
103 | | - LKQLTypesHelper.LKQL_LIST, LKQLTypesHelper.LKQL_STRING), |
104 | | - LKQLTypesHelper.fromJava(firstItem), |
105 | | - call.getArgList().getArgs()[0]); |
106 | | - } |
107 | | - |
108 | | - // If the list is empty just return an empty list |
109 | | - else { |
110 | | - return new LKQLList(new Object[0]); |
| 38 | + new SpecializedBuiltInBody<>(ConcatFunctionFactory.ConcatExprNodeGen.create()) { |
| 39 | + @Override |
| 40 | + protected Object dispatch(Object[] args) { |
| 41 | + return specializedNode.executeConcat(args[0]); |
111 | 42 | } |
112 | 43 | }); |
113 | 44 | } |
| 45 | + |
| 46 | + /** Expression of the "concat" function. */ |
| 47 | + abstract static class ConcatExpr extends SpecializedBuiltInBody.SpecializedBuiltInNode { |
| 48 | + |
| 49 | + public abstract Object executeConcat(Object list); |
| 50 | + |
| 51 | + protected static boolean isString(Object o) { |
| 52 | + return LKQLTypeSystemGen.isString(o); |
| 53 | + } |
| 54 | + |
| 55 | + protected static boolean isList(Object o) { |
| 56 | + return LKQLTypeSystemGen.isLKQLList(o); |
| 57 | + } |
| 58 | + |
| 59 | + @Specialization(guards = {"list.size() > 0", "isString(list.get(0))"}) |
| 60 | + protected String onListOfStrings(LKQLList list) { |
| 61 | + // Create a string builder and add all strings in the list |
| 62 | + String result = LKQLTypeSystemGen.asString(list.get(0)); |
| 63 | + for (int i = 1; i < list.size(); i++) { |
| 64 | + final Object item = list.get(i); |
| 65 | + if (!LKQLTypeSystemGen.isString(item)) { |
| 66 | + this.invalidElemType(list, item); |
| 67 | + } |
| 68 | + result = StringUtils.concat(result, LKQLTypeSystemGen.asString(item)); |
| 69 | + } |
| 70 | + return result; |
| 71 | + } |
| 72 | + |
| 73 | + @Specialization(guards = {"list.size() > 0", "isList(list.get(0))"}) |
| 74 | + protected LKQLList onListOfLists(LKQLList list) { |
| 75 | + Object[] result = LKQLTypeSystemGen.asLKQLList(list.get(0)).getContent(); |
| 76 | + for (int i = 1; i < list.size(); i++) { |
| 77 | + final Object item = list.get(i); |
| 78 | + if (!LKQLTypeSystemGen.isLKQLList(item)) { |
| 79 | + this.invalidElemType(list, item); |
| 80 | + } |
| 81 | + result = ArrayUtils.concat(result, LKQLTypeSystemGen.asLKQLList(item).getContent()); |
| 82 | + } |
| 83 | + return new LKQLList(result); |
| 84 | + } |
| 85 | + |
| 86 | + @Specialization(guards = "notValidElem.size() > 0") |
| 87 | + @CompilerDirectives.TruffleBoundary |
| 88 | + protected LKQLList invalidElemType( |
| 89 | + @SuppressWarnings("unused") LKQLList notValidElem, |
| 90 | + @Cached("notValidElem.get(0)") Object elem) { |
| 91 | + throw LKQLRuntimeException.wrongType( |
| 92 | + LKQLTypesHelper.LKQL_LIST |
| 93 | + + " of " |
| 94 | + + LKQLTypesHelper.typeUnion( |
| 95 | + LKQLTypesHelper.LKQL_LIST, LKQLTypesHelper.LKQL_STRING), |
| 96 | + LKQLTypesHelper.fromJava(elem) + " element", |
| 97 | + body.argNode(0)); |
| 98 | + } |
| 99 | + |
| 100 | + @Specialization(guards = "emptyList.size() == 0") |
| 101 | + protected LKQLList onEmptyList(@SuppressWarnings("unused") LKQLList emptyList) { |
| 102 | + return new LKQLList(new Object[0]); |
| 103 | + } |
| 104 | + |
| 105 | + @Fallback |
| 106 | + protected LKQLList invalidType(Object notValid) { |
| 107 | + throw LKQLRuntimeException.wrongType( |
| 108 | + LKQLTypesHelper.LKQL_LIST, LKQLTypesHelper.fromJava(notValid), body.argNode(0)); |
| 109 | + } |
| 110 | + } |
114 | 111 | } |
0 commit comments