123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- /**
- * Copyright (c) 2018 Mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- */
- import Expression from '../../language/expression';
- import { QueryContext, QueryFn, Structure, ModelPropertyDescriptor } from 'mol-model/structure';
- import { MSymbol } from '../../language/symbol';
- export class QueryRuntimeTable {
- private map = new Map<string, QuerySymbolRuntime>();
- addSymbol(runtime: QuerySymbolRuntime) {
- this.map.set(runtime.symbol.id, runtime);
- }
- addCustomProp(desc: ModelPropertyDescriptor) {
- if (!desc.symbols) return;
- for (const k of Object.keys(desc.symbols)) {
- this.addSymbol((desc.symbols as any)[k]);
- }
- }
- getRuntime(id: string) {
- return this.map.get(id);
- }
- }
- export const DefaultQueryRuntimeTable = new QueryRuntimeTable();
- export class QueryCompilerCtx {
- constQueryContext: QueryContext = new QueryContext(Structure.Empty);
- constructor(public table: QueryRuntimeTable) {
- }
- }
- export type ConstQuerySymbolFn<S extends MSymbol = MSymbol> = (ctx: QueryContext, args: QueryRuntimeArguments<S>) => any
- export type QuerySymbolFn<S extends MSymbol = MSymbol> = (ctx: QueryContext, args: QueryRuntimeArguments<S>) => any
- export type QueryCompiledSymbolRuntime = { kind: 'const', value: any } | { kind: 'dynamic', runtime: QuerySymbolFn }
- export type CompiledQueryFn<T = any> = { isConst: boolean, fn: QueryFn }
- export namespace QueryCompiledSymbol {
- export function Const(value: any): QueryCompiledSymbolRuntime {
- return { kind: 'const', value }
- }
- export function Dynamic(runtime: QuerySymbolFn): QueryCompiledSymbolRuntime {
- return { kind: 'dynamic', runtime };
- }
- }
- export namespace CompiledQueryFn {
- export function Const(value: any): CompiledQueryFn {
- return { isConst: true, fn: ctx => value };
- }
- export function Dynamic(fn: QueryFn): CompiledQueryFn {
- return { isConst: false, fn };
- }
- }
- export interface QuerySymbolRuntime {
- symbol: MSymbol,
- compile(ctx: QueryCompilerCtx, args?: Expression.Arguments): CompiledQueryFn
- }
- export type QueryRuntimeArguments<S extends MSymbol> =
- { length?: number } & { [P in keyof S['args']['@type']]: QueryFn<S['args']['@type'][P]> }
- export namespace QuerySymbolRuntime {
- export function Const<S extends MSymbol<any>>(symbol: S, fn: ConstQuerySymbolFn<S>): QuerySymbolRuntime {
- return new SymbolRuntimeImpl(symbol, fn, true);
- }
- export function Dynamic<S extends MSymbol<any>>(symbol: S, fn: QuerySymbolFn<S>): QuerySymbolRuntime {
- return new SymbolRuntimeImpl(symbol, fn, false);
- }
- }
- class SymbolRuntimeImpl<S extends MSymbol> implements QuerySymbolRuntime {
- compile(ctx: QueryCompilerCtx, inputArgs?: Expression.Arguments): CompiledQueryFn {
- let args: any, constArgs = false;
- if (!inputArgs) {
- args = void 0;
- constArgs = true;
- } else if (Expression.isArgumentsArray(inputArgs)) {
- args = [];
- constArgs = false;
- for (const arg of inputArgs) {
- const compiled = _compile(ctx, arg);
- constArgs = constArgs && compiled.isConst;
- args.push(compiled.fn);
- }
- } else {
- args = Object.create(null);
- constArgs = false;
- for (const key of Object.keys(inputArgs)) {
- const compiled = _compile(ctx, inputArgs[key]);
- constArgs = constArgs && compiled.isConst;
- args[key] = compiled.fn;
- }
- }
- if (this.isConst) {
- if (this.isConst && constArgs) {
- return CompiledQueryFn.Const(this.fn(ctx.constQueryContext, args))
- }
- return CompiledQueryFn.Dynamic(createDynamicFn(this.fn, args));
- }
- return CompiledQueryFn.Dynamic(createDynamicFn(this.fn, args));
- }
- constructor(public symbol: S, private fn: QuerySymbolFn<S>, private isConst: boolean) {
- }
- }
- function createDynamicFn<S extends MSymbol>(fn: QuerySymbolFn<S>, args: any): QueryFn {
- return ctx => fn(ctx, args);
- }
- function _compile(ctx: QueryCompilerCtx, expression: Expression): CompiledQueryFn {
- if (Expression.isLiteral(expression)) {
- return CompiledQueryFn.Const(expression);
- }
- if (Expression.isSymbol(expression)) {
- // TODO: check for "nullary symbols" and automatically apply them?
- return CompiledQueryFn.Const(expression.name);
- }
- if (!Expression.isSymbol(expression.head)) {
- throw new Error('Can only apply symbols.');
- }
- const compiler = ctx.table.getRuntime(expression.head.name);
- if (!compiler) {
- throw new Error(`Symbol '${expression.head.name}' is not implemented.`);
- }
- return compiler.compile(ctx, expression.args);
- }
- export function compile<T = any>(expression: Expression): QueryFn<T> {
- const ctx = new QueryCompilerCtx(DefaultQueryRuntimeTable);
- return _compile(ctx, expression).fn;
- }
- import './table'
|