Skip to content

Commit

Permalink
inject function definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
jitsedesmet committed Oct 28, 2023
1 parent f327ac8 commit 24081aa
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import type * as RDF from '@rdfjs/types';
import { LRUCache } from 'lru-cache';
import type { Algebra as Alg } from 'sparqlalgebrajs';
import * as E from '../expressions';
import { regularFunctions } from '../functions';
import type { SparqlFunction } from '../functions';
import { namedFunctions, regularFunctions, specialFunctions } from '../functions';
import { expressionToVar } from '../functions/Helpers';
import type { FunctionArgumentsCache } from '../functions/OverloadTree';
import { AlgebraTransformer } from '../transformers/AlgebraTransformer';
Expand Down Expand Up @@ -56,6 +57,11 @@ export class ExpressionEvaluator implements IExpressionEvaluator {
public readonly superTypeProvider: ISuperTypeProvider;
public readonly defaultTimeZone: ITimeZoneRepresentation;
public readonly actionContext: IActionContext;
public readonly functions: Record<C.NamedOperator | C.Operator, SparqlFunction> = {
...namedFunctions,
...specialFunctions,
...regularFunctions,
};

public constructor(public algExpr: Alg.Expression, context: IAsyncEvaluatorContext) {
this.now = context.now || new Date(Date.now());
Expand All @@ -72,7 +78,16 @@ export class ExpressionEvaluator implements IExpressionEvaluator {
this.defaultTimeZone = context.defaultTimeZone || extractTimeZone(this.now);
this.actionContext = context.actionContext;

this.transformer = new AlgebraTransformer(this.superTypeProvider);
this.transformer = new AlgebraTransformer(
this.superTypeProvider,
async({ functionName }) => {
const res: SparqlFunction | undefined = this.functions[<C.NamedOperator | C.Operator> functionName];
if (res) {
return res;
}
throw new Error('nah!');
},
);
this.expr = this.transformer.transformAlgebra(algExpr);

Check failure on line 91 in packages/expression-evaluator/lib/evaluators/ExpressionEvaluator.ts

View workflow job for this annotation

GitHub Actions / lint

Type 'Promise<Expression>' is not assignable to type 'Expression'.

Check failure on line 91 in packages/expression-evaluator/lib/evaluators/ExpressionEvaluator.ts

View workflow job for this annotation

GitHub Actions / docs

Type 'Promise<Expression>' is not assignable to type 'Expression'.

Check failure on line 91 in packages/expression-evaluator/lib/evaluators/ExpressionEvaluator.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 16.x)

Type 'Promise<Expression>' is not assignable to type 'Expression'.

Check failure on line 91 in packages/expression-evaluator/lib/evaluators/ExpressionEvaluator.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 18.x)

Type 'Promise<Expression>' is not assignable to type 'Expression'.

Check failure on line 91 in packages/expression-evaluator/lib/evaluators/ExpressionEvaluator.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 20.x)

Type 'Promise<Expression>' is not assignable to type 'Expression'.
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
import type { FunctionBusType } from '@comunica/types';
import { Algebra as Alg } from 'sparqlalgebrajs';

import * as E from '../expressions';
import { namedFunctions, regularFunctions, specialFunctions } from '../functions';
import * as C from '../util/Consts';
import * as Err from '../util/Errors';
import type { ISuperTypeProvider } from '../util/TypeHandling';
import type { ITermTransformer } from './TermTransformer';
import { TermTransformer } from './TermTransformer';

export interface IAlgebraTransformer extends ITermTransformer{
transformAlgebra: (expr: Alg.Expression) => E.Expression;
transformAlgebra: (expr: Alg.Expression) => Promise<E.Expression>;
}

export class AlgebraTransformer extends TermTransformer implements IAlgebraTransformer {
public constructor(superTypeProvided: ISuperTypeProvider) {
private readonly functions: FunctionBusType;
public constructor(superTypeProvided: ISuperTypeProvider, functions: FunctionBusType) {
super(superTypeProvided);
this.functions = functions;
}

public transformAlgebra(expr: Alg.Expression): E.Expression {
public async transformAlgebra(expr: Alg.Expression): Promise<E.Expression> {
const types = Alg.expressionTypes;

switch (expr.expressionType) {
case types.TERM:
return this.transformTerm(expr);
case types.OPERATOR:
return this.transformOperator(expr);
return await this.transformOperator(expr);
case types.NAMED:
return this.transformNamed(expr);
return await this.transformNamed(expr);
case types.EXISTENCE:
return AlgebraTransformer.transformExistence(expr);
case types.AGGREGATE:
Expand All @@ -40,38 +42,30 @@ export class AlgebraTransformer extends TermTransformer implements IAlgebraTrans
return new E.NamedNode(term.wildcard.value);
}

private transformOperator(expr: Alg.OperatorExpression): E.OperatorExpression | E.SpecialOperatorExpression {
private async transformOperator(expr: Alg.OperatorExpression):
Promise<E.OperatorExpression | E.SpecialOperatorExpression> {
const operator = expr.operator.toLowerCase();
if (C.SpecialOperators.has(operator)) {
const specialOp = <C.SpecialOperator>operator;
const specialArgs = expr.args.map(arg => this.transformAlgebra(arg));
const specialFunc = specialFunctions[specialOp];
if (!specialFunc.checkArity(specialArgs)) {
throw new Err.InvalidArity(specialArgs, specialOp);
}
return new E.SpecialOperator(specialArgs, specialFunc.apply);
}
if (!C.Operators.has(operator)) {
throw new Err.UnknownOperator(expr.operator);
}
const regularOp = <C.RegularOperator>operator;
const regularArgs = expr.args.map(arg => this.transformAlgebra(arg));
const regularFunc = regularFunctions[regularOp];
if (!regularFunc.checkArity(regularArgs)) {
throw new Err.InvalidArity(regularArgs, regularOp);
const operatorFunc = await this.functions({ functionName: operator, arguments: expr.args });
const operatorArgs = await Promise.all(expr.args.map(arg => this.transformAlgebra(arg)));
if (!operatorFunc.checkArity(operatorArgs)) {
throw new Err.InvalidArity(operatorArgs, <C.Operator> operator);
}
if (C.SpecialOperators.has(operator)) {
return new E.SpecialOperator(operatorArgs, operatorFunc.apply);
}
return new E.Operator(regularArgs, args => regularFunc.apply(args));
return new E.Operator(operatorArgs, operatorFunc.apply);
}

// TODO: Support passing functions to override default behaviour;
private transformNamed(expr: Alg.NamedExpression):
E.NamedExpression | E.AsyncExtensionExpression | E.SyncExtensionExpression {
private async transformNamed(expr: Alg.NamedExpression): Promise<E.NamedExpression> {
const funcName = expr.name.value;
const namedArgs = expr.args.map(arg => this.transformAlgebra(arg));
const namedArgs = await Promise.all(expr.args.map(arg => this.transformAlgebra(arg)));
if (C.NamedOperators.has(<C.NamedOperator>funcName)) {
// Return a basic named expression
const op = <C.NamedOperator>expr.name.value;
const namedFunc = namedFunctions[op];
const namedFunc = await this.functions({ functionName: op, arguments: expr.args });
return new E.Named(expr.name, namedArgs, args => namedFunc.apply(args));
}
// The expression might be an extension function, check this.
Expand Down
4 changes: 4 additions & 0 deletions packages/types/lib/ExpressionEvaluator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ExpressionEvaluator } from '@comunica/expression-evaluator';
import type * as E from '@comunica/expression-evaluator/lib/expressions';
import type { SparqlFunction } from '@comunica/expression-evaluator/lib/functions';
import type * as RDF from '@rdfjs/types';
import type { Algebra as Alg } from 'sparqlalgebrajs';
import type { IActionContext } from './IActionContext';
Expand Down Expand Up @@ -83,3 +84,6 @@ export interface IFunctionExpression {
*/
checkArity: (args: E.Expression[]) => boolean;
}

export type FunctionBusType = (arg: { functionName: string; arguments: Alg.Expression[] }) =>
Promise<SparqlFunction>;

0 comments on commit 24081aa

Please sign in to comment.