Skip to content

Commit

Permalink
Merge branch 'topic/builtin_specializations' into 'master'
Browse files Browse the repository at this point in the history
Rewrite LKQL built-ins as specialized nodes

Closes #130

See merge request eng/libadalang/langkit-query-language!300
  • Loading branch information
HugoGGuerrier committed Jan 6, 2025
2 parents da059e9 + 9539af9 commit 9d605cf
Show file tree
Hide file tree
Showing 22 changed files with 734 additions and 614 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package com.adacore.lkql_jit.built_ins;

import com.adacore.lkql_jit.nodes.LKQLNode;
import com.adacore.lkql_jit.nodes.expressions.Expr;
import com.adacore.lkql_jit.nodes.expressions.FunCall;
import com.oracle.truffle.api.frame.VirtualFrame;
Expand All @@ -24,12 +25,24 @@ protected AbstractBuiltInFunctionBody() {
super(null);
}

// ----- Getters -----

public FunCall getCallNode() {
return callNode;
}

// ----- Setters -----

public void setCallNode(FunCall callNode) {
this.callNode = callNode;
}

// ----- Instance methods -----

public LKQLNode argNode(int index) {
return this.callNode.getArgList().getArgs()[index];
}

// ----- Class methods -----

/** Create a new built-in function body from the given callback representing its execution. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// Copyright (C) 2005-2024, AdaCore
// SPDX-License-Identifier: GPL-3.0-or-later
//

package com.adacore.lkql_jit.built_ins;

import com.adacore.lkql_jit.LKQLTypeSystem;
import com.oracle.truffle.api.dsl.TypeSystemReference;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;

public abstract class SpecializedBuiltInBody<
T extends SpecializedBuiltInBody.SpecializedBuiltInNode>
extends AbstractBuiltInFunctionBody {

// ----- Attributes -----

/** This node represents the execution of the built-in function. */
@Child protected T specializedNode;

// ----- Constructors -----

/** Create a new specialized body with its corresponding execution node. */
public SpecializedBuiltInBody(T specializedNode) {
this.specializedNode = specializedNode;
this.specializedNode.body = this;
}

// ----- Instance methods -----

/** Dispatch the function arguments to the specialized execution node. */
protected abstract Object dispatch(Object[] args);

@Override
public Object executeGeneric(VirtualFrame frame) {
return this.dispatch(frame.getArguments());
}

// ----- Inner classes -----

/** This class represents an execution node, payload of a built-in body. */
@TypeSystemReference(LKQLTypeSystem.class)
public abstract static class SpecializedBuiltInNode extends Node {
// ----- Attributes -----

/** The built-in body that owns this specialized node. */
protected SpecializedBuiltInBody body;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

package com.adacore.lkql_jit.built_ins.functions;

import com.adacore.lkql_jit.LKQLTypeSystemGen;
import com.adacore.lkql_jit.built_ins.BuiltInFunctionValue;
import com.adacore.lkql_jit.built_ins.SpecializedBuiltInBody;
import com.adacore.lkql_jit.exception.LKQLRuntimeException;
import com.adacore.lkql_jit.nodes.expressions.Expr;
import com.adacore.lkql_jit.nodes.expressions.FunCall;
import com.adacore.lkql_jit.utils.LKQLTypesHelper;
import com.adacore.lkql_jit.utils.functions.FileUtils;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;

/**
* This class represents the "base_name" built-in function in the LKQL language.
Expand All @@ -21,33 +21,39 @@
*/
public final class BaseNameFunction {

// ----- Attributes -----

/** The name of the built-in. */
public static final String NAME = "base_name";

// ----- Class methods -----

/** Get a brand new "base_name" function value. */
public static BuiltInFunctionValue getValue() {
return new BuiltInFunctionValue(
NAME,
"Given a string that represents a file name, returns the basename",
new String[] {"str"},
new Expr[] {null},
(VirtualFrame frame, FunCall call) -> {
// Get the file full path
Object path = frame.getArguments()[0];

// Check the argument type
if (!LKQLTypeSystemGen.isString(path)) {
throw LKQLRuntimeException.wrongType(
LKQLTypesHelper.LKQL_STRING,
LKQLTypesHelper.fromJava(path),
call.getArgList().getArgs()[0]);
new SpecializedBuiltInBody<>(BaseNameFunctionFactory.BaseNameExprNodeGen.create()) {
@Override
protected Object dispatch(Object[] args) {
return specializedNode.executeBaseName(args[0]);
}

// Return the base name of the file
return FileUtils.baseName(LKQLTypeSystemGen.asString(path));
});
}

/** Expression of the "base_name" function. */
abstract static class BaseNameExpr extends SpecializedBuiltInBody.SpecializedBuiltInNode {

public abstract String executeBaseName(Object fileName);

@Specialization
protected String executeOnString(String fileName) {
return FileUtils.baseName(fileName);
}

@Fallback
protected String invalidType(Object notValid) {
throw LKQLRuntimeException.wrongType(
LKQLTypesHelper.LKQL_STRING,
LKQLTypesHelper.fromJava(notValid),
body.argNode(0));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@

import com.adacore.lkql_jit.LKQLTypeSystemGen;
import com.adacore.lkql_jit.built_ins.BuiltInFunctionValue;
import com.adacore.lkql_jit.built_ins.SpecializedBuiltInBody;
import com.adacore.lkql_jit.exception.LKQLRuntimeException;
import com.adacore.lkql_jit.nodes.expressions.Expr;
import com.adacore.lkql_jit.nodes.expressions.FunCall;
import com.adacore.lkql_jit.runtime.values.lists.LKQLList;
import com.adacore.lkql_jit.utils.LKQLTypesHelper;
import com.adacore.lkql_jit.utils.functions.ArrayUtils;
import com.adacore.lkql_jit.utils.functions.StringUtils;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;

/**
* This class represents the "concat" built-in function in the LKQL language.
Expand All @@ -23,92 +26,86 @@
*/
public final class ConcatFunction {

// ----- Attributes -----

/** The name of the function. */
public static final String NAME = "concat";

// ----- Class methods -----

/** Get a brand new "concat" function value. */
public static BuiltInFunctionValue getValue() {
return new BuiltInFunctionValue(
NAME,
"Given a list of lists or strings, return a concatenated list or string",
new String[] {"lists"},
new Expr[] {null},
(VirtualFrame frame, FunCall call) -> {

// Get the argument
Object lists = frame.getArguments()[0];

// Check the type of the argument
if (!LKQLTypeSystemGen.isLKQLList(lists)) {
throw LKQLRuntimeException.wrongType(
LKQLTypesHelper.LKQL_LIST,
LKQLTypesHelper.fromJava(lists),
call.getArgList().getArgs()[0]);
}

// Cast the argument to list
LKQLList listValue = LKQLTypeSystemGen.asLKQLList(lists);

// If the list is not empty
if (listValue.size() > 0) {
final Object firstItem = listValue.get(0);

// If the first value is a string look for strings in the list
if (LKQLTypeSystemGen.isString(firstItem)) {
// Create a string builder and add all strings in the list
String result = LKQLTypeSystemGen.asString(firstItem);
for (int i = 1; i < listValue.size(); i++) {
final Object item = listValue.get(i);
if (!LKQLTypeSystemGen.isString(item)) {
throw LKQLRuntimeException.wrongType(
LKQLTypesHelper.LKQL_STRING,
LKQLTypesHelper.fromJava(item),
call.getArgList().getArgs()[0]);
}
result =
StringUtils.concat(
result, LKQLTypeSystemGen.asString(item));
}

// Return the result
return result;
}

// If the first item is a list look for lists in the list
if (LKQLTypeSystemGen.isLKQLList(firstItem)) {
// Create a result array and add all list of the argument
Object[] result = LKQLTypeSystemGen.asLKQLList(firstItem).getContent();
for (int i = 1; i < listValue.size(); i++) {
final Object item = listValue.get(i);
if (!LKQLTypeSystemGen.isLKQLList(item)) {
throw LKQLRuntimeException.wrongType(
LKQLTypesHelper.LKQL_LIST,
LKQLTypesHelper.fromJava(item),
call.getArgList().getArgs()[0]);
}
result =
ArrayUtils.concat(
result,
LKQLTypeSystemGen.asLKQLList(item).getContent());
}
return new LKQLList(result);
}

// Else there is an error
throw LKQLRuntimeException.wrongType(
LKQLTypesHelper.typeUnion(
LKQLTypesHelper.LKQL_LIST, LKQLTypesHelper.LKQL_STRING),
LKQLTypesHelper.fromJava(firstItem),
call.getArgList().getArgs()[0]);
}

// If the list is empty just return an empty list
else {
return new LKQLList(new Object[0]);
new SpecializedBuiltInBody<>(ConcatFunctionFactory.ConcatExprNodeGen.create()) {
@Override
protected Object dispatch(Object[] args) {
return specializedNode.executeConcat(args[0]);
}
});
}

/** Expression of the "concat" function. */
abstract static class ConcatExpr extends SpecializedBuiltInBody.SpecializedBuiltInNode {

public abstract Object executeConcat(Object list);

protected static boolean isString(Object o) {
return LKQLTypeSystemGen.isString(o);
}

protected static boolean isList(Object o) {
return LKQLTypeSystemGen.isLKQLList(o);
}

@Specialization(guards = {"list.size() > 0", "isString(list.get(0))"})
protected String onListOfStrings(LKQLList list) {
// Create a string builder and add all strings in the list
String result = LKQLTypeSystemGen.asString(list.get(0));
for (int i = 1; i < list.size(); i++) {
final Object item = list.get(i);
if (!LKQLTypeSystemGen.isString(item)) {
this.invalidElemType(list, item);
}
result = StringUtils.concat(result, LKQLTypeSystemGen.asString(item));
}
return result;
}

@Specialization(guards = {"list.size() > 0", "isList(list.get(0))"})
protected LKQLList onListOfLists(LKQLList list) {
Object[] result = LKQLTypeSystemGen.asLKQLList(list.get(0)).getContent();
for (int i = 1; i < list.size(); i++) {
final Object item = list.get(i);
if (!LKQLTypeSystemGen.isLKQLList(item)) {
this.invalidElemType(list, item);
}
result = ArrayUtils.concat(result, LKQLTypeSystemGen.asLKQLList(item).getContent());
}
return new LKQLList(result);
}

@Specialization(guards = "notValidElem.size() > 0")
@CompilerDirectives.TruffleBoundary
protected LKQLList invalidElemType(
@SuppressWarnings("unused") LKQLList notValidElem,
@Cached("notValidElem.get(0)") Object elem) {
throw LKQLRuntimeException.wrongType(
LKQLTypesHelper.LKQL_LIST
+ " of "
+ LKQLTypesHelper.typeUnion(
LKQLTypesHelper.LKQL_LIST, LKQLTypesHelper.LKQL_STRING),
LKQLTypesHelper.fromJava(elem) + " element",
body.argNode(0));
}

@Specialization(guards = "emptyList.size() == 0")
protected LKQLList onEmptyList(@SuppressWarnings("unused") LKQLList emptyList) {
return new LKQLList(new Object[0]);
}

@Fallback
protected LKQLList invalidType(Object notValid) {
throw LKQLRuntimeException.wrongType(
LKQLTypesHelper.LKQL_LIST, LKQLTypesHelper.fromJava(notValid), body.argNode(0));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,9 @@
*/
public final class DocFunction {

// ----- Attributes -----

/** The name of the function. */
public static final String NAME = "doc";

// ----- Class methods -----

/** Get a brand new "doc" function value. */
public static BuiltInFunctionValue getValue() {
return new BuiltInFunctionValue(
NAME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@
public class DocumentBuiltins {
public static final String NAME = "document_builtins";

/** Get a brand new "document_builtins" function value. */
public static BuiltInFunctionValue getValue() {
return new BuiltInFunctionValue(
NAME,
"Return a string in the RsT format containing documentation for all built-ins",
new String[] {},
new Expr[] {},
(VirtualFrame frame, FunCall call) ->
documentBuiltinsImpl(frame.materialize(), call));
}

/** Function for the "document_builtins" execution. */
@CompilerDirectives.TruffleBoundary
public static String documentBuiltinsImpl(
@SuppressWarnings("unused") MaterializedFrame frame,
Expand Down Expand Up @@ -93,14 +105,4 @@ public static String documentBuiltinsImpl(
throw new RuntimeException(e);
}
}

public static BuiltInFunctionValue getValue() {
return new BuiltInFunctionValue(
NAME,
"Return a string in the RsT format containing documentation for all built-ins",
new String[] {},
new Expr[] {},
(VirtualFrame frame, FunCall call) ->
documentBuiltinsImpl(frame.materialize(), call));
}
}
Loading

0 comments on commit 9d605cf

Please sign in to comment.