Skip to content

Commit

Permalink
extract single apply interface
Browse files Browse the repository at this point in the history
  • Loading branch information
jitsedesmet committed Oct 23, 2023
1 parent 96062c8 commit 262692e
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 114 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import type { IActionContext } from '@comunica/types';
import type { IActionContext, IEvalContext } from '@comunica/types';
import type * as RDF from '@rdfjs/types';
import type { Algebra as Alg } from 'sparqlalgebrajs';
import type { AsyncExtension } from '../../expressions';
import * as E from '../../expressions';
import type { EvalContextAsync } from '../../functions';
import { expressionToVar } from '../../functions/Helpers';
import type { FunctionArgumentsCache } from '../../functions/OverloadTree';
import type { ITermTransformer } from '../../transformers/TermTransformer';
Expand Down Expand Up @@ -70,20 +69,25 @@ export class AsyncRecursiveEvaluator {
}

private async evalOperator(expr: E.Operator, mapping: RDF.Bindings): Promise<E.Term> {
const argPromises = expr.args.map(arg => this.evaluate(arg, mapping));
const argResults = await Promise.all(argPromises);
return expr.apply(argResults);
const context: IEvalContext = {
args: await Promise.all(expr.args.map(arg => this.evaluate(arg, mapping))),
mapping,
exprEval: this.expressionEvaluator,

...this.context,
};
return expr.apply(context);
}

private async evalSpecialOperator(expr: E.SpecialOperator, mapping: RDF.Bindings): Promise<E.Term> {
const context: EvalContextAsync = {
const context: IEvalContext = {
args: expr.args,
mapping,
evaluate: this.expressionEvaluator,
exprEval: this.expressionEvaluator,

...this.context,
};
return expr.applyAsync(context);
return expr.apply(context);
}

private async _evalAsyncArgs(args: E.Expression[], mapping: RDF.Bindings): Promise<E.TermExpression[]> {
Expand All @@ -92,11 +96,25 @@ export class AsyncRecursiveEvaluator {
}

private async evalNamed(expr: E.Named, mapping: RDF.Bindings): Promise<E.Term> {
return expr.apply(await this._evalAsyncArgs(expr.args, mapping));
return expr.apply(
{
args: await this._evalAsyncArgs(expr.args, mapping),
mapping,
exprEval: this.expressionEvaluator,

...this.context,
},
);
}

private async evalAsyncExtension(expr: AsyncExtension, mapping: RDF.Bindings): Promise<E.Term> {
return await expr.apply(await this._evalAsyncArgs(expr.args, mapping));
return await expr.apply({
args: await this._evalAsyncArgs(expr.args, mapping),
mapping,
exprEval: this.expressionEvaluator,

...this.context,
});
}

private async evalExistence(expr: E.Existence, mapping: RDF.Bindings): Promise<E.Term> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { FunctionApplication } from '@comunica/types';
import type * as RDF from '@rdfjs/types';
import type { AsyncExtensionApplication, AsyncExtensionExpression, Expression } from './Expressions';
import type { AsyncExtensionExpression, Expression } from './Expressions';
import { ExpressionType } from './Expressions';

export class AsyncExtension implements AsyncExtensionExpression {
Expand All @@ -8,6 +9,6 @@ export class AsyncExtension implements AsyncExtensionExpression {
public constructor(
public name: RDF.NamedNode,
public args: Expression[],
public apply: AsyncExtensionApplication,
public apply: FunctionApplication,
) { }
}
15 changes: 8 additions & 7 deletions packages/expression-evaluator/lib/expressions/Expressions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { IEvalContext, FunctionApplication } from '@comunica/types';
import type * as RDF from '@rdfjs/types';
import type { Algebra } from 'sparqlalgebrajs';
import type { EvalContextAsync } from '../functions';

export enum ExpressionType {
Aggregate = 'aggregate',
Expand Down Expand Up @@ -43,34 +43,35 @@ export type ExistenceExpression = IExpressionProps & {
export type NamedExpression = IExpressionProps & {
expressionType: ExpressionType.Named;
name: RDF.NamedNode;
apply: SimpleApplication;
apply: FunctionApplication;
args: Expression[];
};

// TODO: this can go since we will have an indexed bus to fund functions?
export type AsyncExtensionExpression = IExpressionProps & {
expressionType: ExpressionType.AsyncExtension;
name: RDF.NamedNode;
apply: AsyncExtensionApplication;
apply: FunctionApplication;
args: Expression[];
};

export type SyncExtensionExpression = IExpressionProps & {
expressionType: ExpressionType.SyncExtension;
name: RDF.NamedNode;
apply: SimpleApplication;
apply: FunctionApplication;
args: Expression[];
};

export type OperatorExpression = IExpressionProps & {
expressionType: ExpressionType.Operator;
args: Expression[];
apply: SimpleApplication;
apply: FunctionApplication;
};

export type SpecialOperatorExpression = IExpressionProps & {
expressionType: ExpressionType.SpecialOperator;
args: Expression[];
applyAsync: SpecialApplicationAsync;
apply: FunctionApplication;
};

// TODO: Create alias Term = TermExpression
Expand Down Expand Up @@ -98,4 +99,4 @@ export type VariableExpression = IExpressionProps & {
export type SimpleApplication = (args: TermExpression[]) => TermExpression;
export type AsyncExtensionApplication = (args: TermExpression[]) => Promise<TermExpression>;

export type SpecialApplicationAsync = (context: EvalContextAsync) => Promise<TermExpression>;
export type SpecialApplicationAsync = (context: IEvalContext) => Promise<TermExpression>;
6 changes: 3 additions & 3 deletions packages/expression-evaluator/lib/expressions/Named.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { FunctionApplication } from '@comunica/types';
import type * as RDF from '@rdfjs/types';

import type { Expression,
NamedExpression,
SimpleApplication } from './Expressions';
NamedExpression } from './Expressions';
import {
ExpressionType,
} from './Expressions';
Expand All @@ -13,6 +13,6 @@ export class Named implements NamedExpression {
public constructor(
public name: RDF.NamedNode,
public args: Expression[],
public apply: SimpleApplication,
public apply: FunctionApplication,
) { }
}
6 changes: 3 additions & 3 deletions packages/expression-evaluator/lib/expressions/Operator.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { FunctionApplication } from '@comunica/types';
import type { Expression,
OperatorExpression,
SimpleApplication } from './Expressions';
OperatorExpression } from './Expressions';
import {
ExpressionType,
} from './Expressions';

export class Operator implements OperatorExpression {
public expressionType: ExpressionType.Operator = ExpressionType.Operator;

public constructor(public args: Expression[], public apply: SimpleApplication) { }
public constructor(public args: Expression[], public apply: FunctionApplication) { }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { FunctionApplication } from '@comunica/types';
import type { Expression,
SpecialApplicationAsync,
SpecialOperatorExpression } from './Expressions';
import {
ExpressionType,
Expand All @@ -10,6 +10,6 @@ export class SpecialOperator implements SpecialOperatorExpression {

public constructor(
public args: Expression[],
public applyAsync: SpecialApplicationAsync,
public apply: FunctionApplication,
) { }
}
39 changes: 17 additions & 22 deletions packages/expression-evaluator/lib/functions/Core.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
import type * as RDF from '@rdfjs/types';
import type { ICompleteEEContext } from '../evaluators/evaluatorHelpers/AsyncRecursiveEvaluator';
import type { IEvalContext, IFunctionExpression } from '@comunica/types';
import type { ExpressionEvaluator } from '../evaluators/ExpressionEvaluator';
import type * as E from '../expressions';
import type * as C from '../util/Consts';
import * as Err from '../util/Errors';
import type { ISuperTypeProvider } from '../util/TypeHandling';
import type { FunctionArgumentsCache, ImplementationFunction, OverloadTree } from './OverloadTree';

export interface IEvalContext extends ICompleteEEContext {
args: E.Expression[];
mapping: RDF.Bindings;
evaluate: ExpressionEvaluator;
}

export type EvalContextAsync = IEvalContext;

// ----------------------------------------------------------------------------
// Overloaded Functions
// ----------------------------------------------------------------------------
Expand All @@ -28,15 +19,24 @@ export interface IOverloadedDefinition {
overloads: OverloadTree;
}

export abstract class BaseFunction<Operator> {
public arity: number | number[];
export abstract class BaseFunction<Operator> implements IFunctionExpression {
private readonly arity: number | number[];
private readonly overloads: OverloadTree;

protected constructor(public operator: Operator, definition: IOverloadedDefinition) {
this.arity = definition.arity;
this.overloads = definition.overloads;
}

public checkArity(args: E.Expression[]): boolean {
// If the function has overloaded arity, the actual arity needs to be present.
if (Array.isArray(this.arity)) {
return this.arity.includes(args.length);
}

return args.length === this.arity;
}

/**
* A function application works by monomorphing the function to a specific
* instance depending on the runtime types. We then just apply this function
Expand All @@ -49,8 +49,8 @@ export abstract class BaseFunction<Operator> {
return concreteFunction(exprEval)(args);
}

public async apply(args: E.TermExpression[], exprEval: ExpressionEvaluator): Promise<E.TermExpression> {
return this.syncApply(args, exprEval);
public async apply({ args, exprEval }: IEvalContext): Promise<E.TermExpression> {
return this.syncApply(<E.TermExpression[]> args, exprEval);
}

protected abstract handleInvalidTypes(args: E.TermExpression[]): never;
Expand Down Expand Up @@ -93,8 +93,6 @@ export abstract class BaseFunction<Operator> {
* and https://www.w3.org/TR/sparql11-query/#OperatorMapping
*/
export class RegularFunction extends BaseFunction<C.RegularOperator> {
protected functionClass = <const> 'regular';

public constructor(op: C.RegularOperator, definition: IOverloadedDefinition) {
super(op, definition);
}
Expand All @@ -106,8 +104,6 @@ export class RegularFunction extends BaseFunction<C.RegularOperator> {

// Named Functions ------------------------------------------------------------
export class NamedFunction extends BaseFunction<C.NamedOperator> {
protected functionClass = <const> 'named';

public constructor(op: C.NamedOperator, definition: IOverloadedDefinition) {
super(op, definition);
}
Expand All @@ -133,15 +129,14 @@ export class NamedFunction extends BaseFunction<C.NamedOperator> {
* They can have both sync and async implementations, and both would make sense
* in some contexts.
*/
export class SpecialFunction {
public functionClass = <const> 'special';
export class SpecialFunction implements IFunctionExpression {
public arity: number;
public applyAsync: E.SpecialApplicationAsync;
public apply: E.SpecialApplicationAsync;
public checkArity: (args: E.Expression[]) => boolean;

public constructor(public operator: C.SpecialOperator, definition: ISpecialDefinition) {
this.arity = definition.arity;
this.applyAsync = definition.applyAsync;
this.apply = definition.applyAsync;
this.checkArity = definition.checkArity || defaultArityCheck(this.arity);
}
}
Expand Down
Loading

0 comments on commit 262692e

Please sign in to comment.