/** * Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Koya Sakuma <koya.sakuma.work@gmail.com> **/ import * as P from '../../../mol-util/monadic-parser'; import * as h from '../helper'; import { MolScriptBuilder } from '../../../mol-script/language/builder'; const B = MolScriptBuilder; import { properties } from './properties'; import { macroproperties } from './macroproperties'; import { operators } from './operators'; import { keywords } from './keywords'; import { AtomGroupArgs } from '../types'; import { Transpiler } from '../transpiler'; const propertiesDict = h.getPropertyRules(macroproperties); const dot = P.MonadicParser.string('.'); const colon = P.MonadicParser.string(':'); const star = P.MonadicParser.string('*'); const bra = P.MonadicParser.string('('); const ket = P.MonadicParser.string(')'); const commu = P.MonadicParser.string('['); const tator = P.MonadicParser.string(']'); function orNull(rule: P.MonadicParser<any>) { return rule.or(P.MonadicParser.of(null)); } function atomSelectionQuery2(x: any) { const tests: AtomGroupArgs = {}; const props: { [k: string]: any[] } = {}; for (const k in x) { const ps = macroproperties[k]; if (!ps) { throw new Error(`property '${k}' not supported, value '${x[k]}'`); } if (x[k] === null) continue; if (!props[ps.level]) props[ps.level] = []; props[ps.level].push(x[k]); } for (const p in props) { tests[p] = h.andExpr(props[p]); } return B.struct.generator.atomGroups(tests); } const lang = P.MonadicParser.createLanguage({ Parens: function (r: any) { return P.MonadicParser.alt( r.Parens, r.Operator, r.Expression ).wrap(P.MonadicParser.regexp(/\(\s+/), P.MonadicParser.regexp(/\s+\)/)); }, Expression: function (r: any) { return P.MonadicParser.alt( // order matters r.Keywords, r.NamedAtomProperties, r.AtomSelectionMacro.map(atomSelectionQuery2), r.Object, r.Object2, ); }, // lys:a.ca -> resn lys and chain A and name ca // lys*a.ca -> resn lys and chain A and name ca // // :a.ca -> chain A and name ca // *a.ca -> chain A and name ca // // *.cg -> name ca // :.cg -> name ca AtomSelectionMacro: function (r: any) { return P.MonadicParser.alt( // :A.CA :.CA :A colon.then(P.MonadicParser.alt( P.MonadicParser.seq( orNull(propertiesDict.chain).skip(dot), orNull(propertiesDict.name) ).map(x => { return { chain: x[0], name: x[1] }; }), P.MonadicParser.seq( orNull(propertiesDict.name).skip(dot) ).map(x => { return { name: x[0] }; }), P.MonadicParser.seq( orNull(propertiesDict.chain) ).map(x => { return { chain: x[0] }; }), )), // *A.CA *.CA star.then(P.MonadicParser.alt( P.MonadicParser.seq( orNull(propertiesDict.chain).skip(dot), orNull(propertiesDict.name) ).map(x => { return { chain: x[0], name: x[1] }; }), P.MonadicParser.seq( orNull(propertiesDict.name).skip(dot) ).map(x => { return { name: x[0] }; }), P.MonadicParser.seq( orNull(propertiesDict.chain) ).map(x => { return { chain: x[0] }; }), )), // 1-100,201 bra.then(P.MonadicParser.alt( P.MonadicParser.alt( P.MonadicParser.seq( propertiesDict.resi.skip(ket), ).map(x => { return { resi: x[0] } ; }) ) )), // [lys]10:a.ca [lys]10:a [lys]10 [lys]10.ca // [lys]:a.ca [lys]:a [lys] [lys].ca commu.then(P.MonadicParser.alt( P.MonadicParser.alt( P.MonadicParser.alt( P.MonadicParser.seq( orNull(propertiesDict.resn).skip(tator), orNull(propertiesDict.resi).skip(colon), orNull(propertiesDict.chain).skip(dot), orNull(propertiesDict.name) ).map(x => { return { resn: x[0], resi: x[1], chain: x[2], name: x[3] }; }), P.MonadicParser.seq( orNull(propertiesDict.resn).skip(tator), orNull(propertiesDict.resi).skip(colon), orNull(propertiesDict.chain) ).map(x => { return { resn: x[0], resi: x[1], chain: x[2] }; }), P.MonadicParser.seq( orNull(propertiesDict.resn).skip(tator), orNull(propertiesDict.resi).skip(colon).skip(dot), orNull(propertiesDict.name) ).map(x => { return { resn: x[0], resi: x[1], name: x[2] }; }), P.MonadicParser.seq( orNull(propertiesDict.resn).skip(tator), orNull(propertiesDict.resi).skip(dot), orNull(propertiesDict.name) ).map(x => { return { resn: x[0], resi: x[1], name: x[2] }; }), P.MonadicParser.seq( orNull(propertiesDict.resn).skip(tator), orNull(propertiesDict.resi) ).map(x => { return { resn: x[0], resi: x[1] }; }), P.MonadicParser.seq( orNull(propertiesDict.resn).skip(tator).skip(colon), orNull(propertiesDict.chain).skip(dot), orNull(propertiesDict.name) ).map(x => { return { resn: x[0], chain: x[1], name: x[2] }; }), P.MonadicParser.seq( orNull(propertiesDict.resn).skip(tator).skip(star), orNull(propertiesDict.chain).skip(dot), orNull(propertiesDict.name) ).map(x => { return { resn: x[0], chain: x[1], name: x[2] }; }), P.MonadicParser.seq( orNull(propertiesDict.resn).skip(tator).skip(colon), orNull(propertiesDict.chain), ).map(x => { return { resn: x[0], chain: x[1] }; }), P.MonadicParser.seq( orNull(propertiesDict.resn).skip(tator).skip(star), orNull(propertiesDict.chain), ).map(x => { return { resn: x[0], chain: x[1] }; }), P.MonadicParser.seq( orNull(propertiesDict.resn).skip(tator).skip(dot), orNull(propertiesDict.name), ).map(x => { return { resn: x[0], name: x[1] }; }), P.MonadicParser.seq( orNull(propertiesDict.resn).skip(tator), ).map(x => { return { resn: x[0] }; }) ) ) ) ) ); }, ObjectProperty: () => { const w = h.getReservedWords(macroproperties, keywords, operators) .sort(h.strLenSortFn).map(h.escapeRegExp).join('|'); return P.MonadicParser.regexp(new RegExp(`(?!(${w}))[A-Z0-9_]+`, 'i')); }, Object: (r: any) => { return r.ObjectProperty .map((x: any) => { throw new Error(`property 'object' not supported, value '${x}'`); }); }, ObjectProperty2: () => { const w = h.getReservedWords(properties, keywords, operators) .sort(h.strLenSortFn).map(h.escapeRegExp).join('|'); return P.MonadicParser.regexp(new RegExp(`(?!(${w}))[A-Z0-9_]+`, 'i')); }, Object2: (r: any) => { return r.ObjectProperty2 .map((x: any) => { throw new Error(`property 'object' not supported, value '${x}'`); }); }, NamedAtomProperties: function () { return P.MonadicParser.alt(...h.getNamedPropertyRules(properties)); }, Operator: function (r: any) { return h.combineOperators(operators, P.MonadicParser.alt(r.Parens, r.Expression, r.Operator)); }, Keywords: () => P.MonadicParser.alt(...h.getKeywordRules(keywords)), Query: function (r: any) { return P.MonadicParser.alt( r.Operator, r.Parens, r.Expression ).trim(P.MonadicParser.optWhitespace); } }); export const transpiler: Transpiler = str => lang.Query.tryParse(str);