Skip to content
Snippets Groups Projects
Commit 38dc2d6e authored by David Sehnal's avatar David Sehnal
Browse files

mol-script: macro support

parent ea46b1c8
No related branches found
No related tags found
No related merge requests found
// /** /**
// * Copyright (c) 2018 Mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2018-2019 Mol* contributors, licensed under MIT, See LICENSE file for more info.
// * *
// * @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
// * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
// */ */
// import B from '../../language/builder' import { MolScriptBuilder as B } from '../../language/builder';
// export function getPositionalArgs(args: any) { export function getPositionalArgs(args: any) {
// return Object.keys(args) return Object.keys(args)
// .filter(k => !isNaN(k as any)) .filter(k => !isNaN(k as any))
// .map(k => +k) .map(k => +k)
// .sort((a, b) => a - b) .sort((a, b) => a - b)
// .map(k => args[k]); .map(k => args[k]);
// } }
// export function tryGetArg(args: any, name: string | number, defaultValue?: any) { export function tryGetArg(args: any, name: string | number, defaultValue?: any) {
// return (args && args[name] !== void 0) ? args[name] : defaultValue; return (args && args[name] !== void 0) ? args[name] : defaultValue;
// } }
// export function pickArgs(args: any, ...names: string[]) { export function pickArgs(args: any, ...names: string[]) {
// const ret = Object.create(null); const ret = Object.create(null);
// let count = 0; let count = 0;
// for (let k of Object.keys(args)) { for (let k of Object.keys(args)) {
// if (names.indexOf(k) >= 0) { if (names.indexOf(k) >= 0) {
// ret[k] = args[k]; ret[k] = args[k];
// count++; count++;
// } }
// } }
// return count ? ret : void 0; return count ? ret : void 0;
// } }
// export function aggregate(property: any, fn: any, initial?: any){ export function aggregate(property: any, fn: any, initial?: any) {
// return B.struct.atomSet.reduce({ return B.struct.atomSet.reduce({
// initial: initial !== void 0 ? initial : property, initial: initial !== void 0 ? initial : property,
// value: fn([ B.struct.slot.elementSetReduce(), property ]) value: fn([ B.struct.slot.elementSetReduce(), property ])
// }); });
// } }
\ No newline at end of file \ No newline at end of file
...@@ -6,20 +6,23 @@ ...@@ -6,20 +6,23 @@
import { UniqueArray } from '../../../mol-data/generic'; import { UniqueArray } from '../../../mol-data/generic';
import Expression from '../../language/expression'; import Expression from '../../language/expression';
import { Argument, MSymbol } from '../../language/symbol'; import { Argument, MSymbol, Arguments } from '../../language/symbol';
import { MolScriptSymbolTable as MolScript } from '../../language/symbol-table'; import { MolScriptSymbolTable as MolScript } from '../../language/symbol-table';
import Type from '../../language/type'; import Type from '../../language/type';
import { Types as StructureQueryTypes } from '../../language/symbol-table/structure-query';
import { MolScriptBuilder as B } from '../../language/builder';
import { getPositionalArgs, tryGetArg } from './macro';
export type MolScriptSymbol = export type MolScriptSymbol =
| { kind: 'alias', aliases: string[], symbol: MSymbol } | { kind: 'alias', aliases: string[], symbol: MSymbol }
| { kind: 'macro', aliases: string[], symbol: MSymbol, translate: (args: any) => Expression } | { kind: 'macro', aliases: string[], symbol: MSymbol, translate: (args: any) => Expression }
function Alias(symbol: MSymbol<any>, ...aliases: string[]): MolScriptSymbol { return { kind: 'alias', aliases, symbol }; } function Alias(symbol: MSymbol<any>, ...aliases: string[]): MolScriptSymbol { return { kind: 'alias', aliases, symbol }; }
// function Macro(symbol: MSymbol<any>, translate: (args: any) => Expression, ...aliases: string[]): MolScriptSymbol { function Macro(symbol: MSymbol<any>, translate: (args: any) => Expression, ...aliases: string[]): MolScriptSymbol {
// symbol.info.namespace = 'molscript-macro'; symbol.info.namespace = 'molscript-macro';
// symbol.id = `molscript-macro.${symbol.info.name}`; symbol.id = `molscript-macro.${symbol.info.name}`;
// return { kind: 'macro', symbol, translate, aliases: [symbol.info.name, ...aliases] }; return { kind: 'macro', symbol, translate, aliases: [symbol.info.name, ...aliases] };
// } }
export function isMolScriptSymbol(x: any): x is MolScriptSymbol { export function isMolScriptSymbol(x: any): x is MolScriptSymbol {
return x.kind === 'alias' || x.kind === 'macro'; return x.kind === 'alias' || x.kind === 'macro';
...@@ -104,26 +107,26 @@ export const SymbolTable = [ ...@@ -104,26 +107,26 @@ export const SymbolTable = [
Alias(MolScript.structureQuery.generator.empty, 'sel.atom.empty'), Alias(MolScript.structureQuery.generator.empty, 'sel.atom.empty'),
Alias(MolScript.structureQuery.generator.all, 'sel.atom.all'), Alias(MolScript.structureQuery.generator.all, 'sel.atom.all'),
// Macro(MSymbol('sel.atom.atoms', Arguments.Dictionary({ Macro(MSymbol('sel.atom.atoms', Arguments.Dictionary({
// 0: Argument(Type.Bool, { isOptional: true, defaultValue: true, description: 'Test applied to each atom.' }) 0: Argument(Type.Bool, { isOptional: true, defaultValue: true, description: 'Test applied to each atom.' })
// }), Struct.Types.ElementSelection, 'A selection of singleton atom sets.'), }), StructureQueryTypes.ElementSelection, 'A selection of singleton atom sets.'),
// args => B.struct.generator.atomGroups({ 'atom-test': M.tryGetArg(args, 0, true) })), args => B.struct.generator.atomGroups({ 'atom-test': tryGetArg(args, 0, true) })),
// Macro(MSymbol('sel.atom.res', Arguments.Dictionary({ Macro(MSymbol('sel.atom.res', Arguments.Dictionary({
// 0: Argument(Type.Bool, { isOptional: true, defaultValue: true, description: 'Test applied to the 1st atom of each residue.' }) 0: Argument(Type.Bool, { isOptional: true, defaultValue: true, description: 'Test applied to the 1st atom of each residue.' })
// }), Struct.Types.ElementSelection, 'A selection of atom sets grouped by residue.'), }), StructureQueryTypes.ElementSelection, 'A selection of atom sets grouped by residue.'),
// args => B.struct.generator.atomGroups({ args => B.struct.generator.atomGroups({
// 'residue-test': M.tryGetArg(args, 0, true), 'residue-test': tryGetArg(args, 0, true),
// 'group-by': B.ammp('residueKey') 'group-by': B.ammp('residueKey')
// })), })),
// Macro(MSymbol('sel.atom.chains', Arguments.Dictionary({ Macro(MSymbol('sel.atom.chains', Arguments.Dictionary({
// 0: Argument(Type.Bool, { isOptional: true, defaultValue: true, description: 'Test applied to the 1st atom of each chain.' }) 0: Argument(Type.Bool, { isOptional: true, defaultValue: true, description: 'Test applied to the 1st atom of each chain.' })
// }), Struct.Types.ElementSelection, 'A selection of atom sets grouped by chain.'), }), StructureQueryTypes.ElementSelection, 'A selection of atom sets grouped by chain.'),
// args => B.struct.generator.atomGroups({ args => B.struct.generator.atomGroups({
// 'chain-test': M.tryGetArg(args, 0, true), 'chain-test': tryGetArg(args, 0, true),
// 'group-by': B.ammp('chainKey') 'group-by': B.ammp('chainKey')
// })), })),
], ],
[ [
'Modifiers', 'Modifiers',
...@@ -244,9 +247,9 @@ export const SymbolTable = [ ...@@ -244,9 +247,9 @@ export const SymbolTable = [
[ [
'Link Properties', 'Link Properties',
Alias(MolScript.structureQuery.linkProperty.order, 'link.order'), Alias(MolScript.structureQuery.linkProperty.order, 'link.order'),
// Macro(MSymbol('bond.is', Arguments.List(Struct.Types.LinkFlag), Type.Bool, Macro(MSymbol('link.is', Arguments.List(StructureQueryTypes.LinkFlag), Type.Bool,
// `Test if the current bond has at least one (or all if partial = false) of the specified flags: ${Type.oneOfValues(Struct.Types.LinkFlag).join(', ')}`), `Test if the current link has at least one (or all if partial = false) of the specified flags: ${Type.oneOfValues(StructureQueryTypes.LinkFlag).join(', ')}`),
// args => B.core.flags.hasAny([B.struct.bondProperty.flags(), B.struct.type.linkFlags(M.getPositionalArgs(args))])), args => B.core.flags.hasAny([B.struct.linkProperty.flags(), B.struct.type.linkFlags(getPositionalArgs(args))])),
] ]
] ]
]; ];
...@@ -305,19 +308,25 @@ function substSymbols(expr: Expression): Expression { ...@@ -305,19 +308,25 @@ function substSymbols(expr: Expression): Expression {
} }
if (Expression.isSymbol(expr)) { if (Expression.isSymbol(expr)) {
if (!SymbolMap[expr.name]) return expr; if (!SymbolMap[expr.name]) return expr;
return Expression.Symbol(SymbolMap[expr.name]!.symbol.id); const s = SymbolMap[expr.name]!;
if (s.kind === 'alias') return Expression.Symbol(SymbolMap[expr.name]!.symbol.id);
throw s.translate([]);
} }
const head = substSymbols(expr.head); const isMacro = Expression.isSymbol(expr.head) && !!SymbolMap[expr.head.name] && SymbolMap[expr.head.name]!.kind === 'macro';
const head = isMacro ? expr.head : substSymbols(expr.head);
const headChanged = head !== expr.head; const headChanged = head !== expr.head;
if (!expr.args) { if (!expr.args) {
if (isMacro) return substSymbols(expr.head); // TODO: is this correct?
return headChanged ? Expression.Apply(head) : expr; return headChanged ? Expression.Apply(head) : expr;
} }
let argsChanged = false; let argsChanged = false;
let newArgs: any;
if (Expression.isArgumentsArray(expr.args)) { if (Expression.isArgumentsArray(expr.args)) {
let newArgs: Expression[] = []; newArgs = [];
for (let i = 0, _i = expr.args.length; i < _i; i++) { for (let i = 0, _i = expr.args.length; i < _i; i++) {
const oldArg = expr.args[i]; const oldArg = expr.args[i];
const newArg = substSymbols(oldArg); const newArg = substSymbols(oldArg);
...@@ -325,21 +334,27 @@ function substSymbols(expr: Expression): Expression { ...@@ -325,21 +334,27 @@ function substSymbols(expr: Expression): Expression {
newArgs[newArgs.length] = newArg; newArgs[newArgs.length] = newArg;
} }
if (!argsChanged) newArgs = expr.args; if (!argsChanged) newArgs = expr.args;
if (!headChanged && !argsChanged) return expr; if (!isMacro && !headChanged && !argsChanged) return expr;
return Expression.Apply(head, newArgs);
} else { } else {
let newArgs: any = {} newArgs = {};
for (const key of Object.keys(expr.args)) { for (const key of Object.keys(expr.args)) {
const oldArg = expr.args[key]; const oldArg = expr.args[key];
const newArg = substSymbols(oldArg); const newArg = substSymbols(oldArg);
if (oldArg !== newArg) argsChanged = true; if (oldArg !== newArg) argsChanged = true;
newArgs[key] = newArg; newArgs[key] = newArg;
} }
if (!headChanged && !argsChanged) return expr; if (!isMacro && !headChanged && !argsChanged) return expr;
if (!argsChanged) newArgs = expr.args; if (!argsChanged) newArgs = expr.args;
}
return Expression.Apply(head, newArgs); if (isMacro) {
const macro = SymbolMap[(expr.head as Expression.Symbol).name]!;
if (macro.kind !== 'macro') return Expression.Apply(head, newArgs);
const ret = macro.translate(newArgs);
return ret;
} }
return Expression.Apply(head, newArgs);
} }
export function transpileMolScript(expr: Expression) { export function transpileMolScript(expr: Expression) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment