From da6a153985710cf82cad7f8c238fbc0747d84413 Mon Sep 17 00:00:00 2001 From: yakomaxa <47655565+yakomaxa@users.noreply.github.com> Date: Sun, 14 Aug 2022 04:03:48 +0900 Subject: [PATCH] Construction of rasmol selection command has nearly finished --- src/mol-script/transpilers/rasmol/parser.ts | 230 ++---------------- .../transpilers/rasmol/special_properties.ts | 26 +- 2 files changed, 35 insertions(+), 221 deletions(-) diff --git a/src/mol-script/transpilers/rasmol/parser.ts b/src/mol-script/transpilers/rasmol/parser.ts index f28e713df..6401a4e53 100644 --- a/src/mol-script/transpilers/rasmol/parser.ts +++ b/src/mol-script/transpilers/rasmol/parser.ts @@ -34,7 +34,7 @@ const comma = P.MonadicParser.string(','); const star = P.MonadicParser.string('*'); const bra = P.MonadicParser.string('('); const ket = P.MonadicParser.string(')'); -const numbers = P.MonadicParser.regexp(/[0-9]/); + /* is Parser -> MonadicParser substitution correct? */ function orNull(rule: P.MonadicParser<any>) { @@ -64,96 +64,6 @@ function atomSelectionQuery2(x: any) { } - -// <, <=, =, >=, >, !=, and LIKE -const valueOperators: OperatorList = [ - { - '@desc': 'value comparisons', - '@examples': [], - name: '=', - abbr: ['=='], - type: h.binaryLeft, - rule: P.MonadicParser.regexp(/\s*(LIKE|>=|<=|=|!=|>|<)\s*/i, 1), - map: (op, e1, e2) => { - // console.log(op, e1, e2) - let expr; - if (e1 === 'structure') { - expr = B.core.flags.hasAny([B.ammp('secondaryStructureFlags'), structureMap(e2)]); - } else if (e2 === 'structure') { - expr = B.core.flags.hasAny([B.ammp('secondaryStructureFlags'), structureMap(e1)]); - } else if (e1.head !== undefined) { - if (e1.head.name === 'core.type.regex') { - expr = B.core.str.match([e1, B.core.type.str([e2])]); - } - } else if (e2.head !== undefined) { - if (e2.head.name === 'core.type.regex') { - expr = B.core.str.match([e2, B.core.type.str([e1])]); - } - } else if (op.toUpperCase() === 'LIKE') { - if (e1.head) { - expr = B.core.str.match([ - B.core.type.regex([`^${e2}$`, 'i']), - B.core.type.str([e1]) - ]); - } else { - expr = B.core.str.match([ - B.core.type.regex([`^${e1}$`, 'i']), - B.core.type.str([e2]) - ]); - } - } - if (!expr) { - if (e1.head) e2 = h.wrapValue(e1, e2); - if (e2.head) e1 = h.wrapValue(e2, e1); - switch (op) { - case '=': - expr = B.core.rel.eq([e1, e2]); - break; - case '!=': - expr = B.core.rel.neq([e1, e2]); - break; - case '>': - expr = B.core.rel.gr([e1, e2]); - break; - case '<': - expr = B.core.rel.lt([e1, e2]); - break; - case '>=': - expr = B.core.rel.gre([e1, e2]); - break; - case '<=': - expr = B.core.rel.lte([e1, e2]); - break; - default: throw new Error(`value operator '${op}' not supported`); - } - } - return B.struct.generator.atomGroups({ 'atom-test': expr }); - } - } -]; - -function atomExpressionQuery(x: any[]) { - const [resno, inscode, chainname, atomname, altloc] = x[1]; - const tests: AtomGroupArgs = {}; - - if (chainname) { - // should be configurable, there is an option in Jmol to use auth or label - tests['chain-test'] = B.core.rel.eq([B.ammp('auth_asym_id'), chainname]); - } - - const resProps = []; - if (resno) resProps.push(B.core.rel.eq([B.ammp('auth_seq_id'), resno])); - if (inscode) resProps.push(B.core.rel.eq([B.ammp('pdbx_PDB_ins_code'), inscode])); - if (resProps.length) tests['residue-test'] = h.andExpr(resProps); - - const atomProps = []; - if (atomname) atomProps.push(B.core.rel.eq([B.ammp('auth_atom_id'), atomname])); - if (altloc) atomProps.push(B.core.rel.eq([B.ammp('label_alt_id'), altloc])); - if (atomProps.length) tests['atom-test'] = h.andExpr(atomProps); - - return B.struct.generator.atomGroups(tests); -} - const lang = P.MonadicParser.createLanguage({ Integer: () => P.MonadicParser.regexp(/-?[0-9]+/).map(Number).desc('integer'), @@ -167,26 +77,10 @@ const lang = P.MonadicParser.createLanguage({ Expression: function (r: any) { return P.MonadicParser.alt( -// r.Keywords, -// r.ValueQuery, + r.Keywords, + r.NamedAtomProperties, r.AtomSelectionMacro.map(atomSelectionQuery2), - r.AtomSelectionMacroResi.map(atomSelectionQuery2), -// r.NamedAtomProperties, - - - // r.Resno.lookahead(P.MonadicParser.regexp(/\s*(?!(LIKE|>=|<=|!=|[:^%/.=><]))/i)).map((x: any) => B.struct.generator.atomGroups({ - // 'residue-test': B.core.rel.eq([B.ammp('auth_seq_id'), x]) -// })), -// r.Atomno.lookahead(P.MonadicParser.regexp(/\s*(?!(LIKE|>=|<=|!=|[:^%/.=><]))/i)).map((x: any) => B.struct.generator.atomGroups({ - // 'atom-test': B.core.rel.eq([B.ammp('id'), x]) -// })), - -// r.Element.map((x: string) => B.struct.generator.atomGroups({ -// 'atom-test': B.core.rel.eq([B.acp('elementSymbol'), B.struct.type.elementSymbol(x)]) -// })), -// r.Resname.map((x: string) => B.struct.generator.atomGroups({ -// 'residue-test': B.core.rel.eq([B.ammp('label_comp_id'), x]) -// })), + r.Object ); }, @@ -201,6 +95,7 @@ const lang = P.MonadicParser.createLanguage({ // :.cg -> name ca AtomSelectionMacro: function (r: any) { return P.MonadicParser.alt( + // :A.CA :.CA colon.then(P.MonadicParser.alt( P.MonadicParser.seq( orNull(propertiesDict.chain).skip(dot), @@ -210,6 +105,7 @@ const lang = P.MonadicParser.createLanguage({ orNull(propertiesDict.name).skip(dot) ).map(x => { return {name: x[0] }; }), )), + // *A.CA *.CA star.then(P.MonadicParser.alt( P.MonadicParser.seq( orNull(propertiesDict.chain).skip(dot), @@ -219,13 +115,14 @@ const lang = P.MonadicParser.createLanguage({ orNull(propertiesDict.name).skip(dot) ).map(x => { return {name: x[0] }; }), )), - // 1-100 lys:a.ca lys:a lys lys.ca + // 1-100+201 bra.then(P.MonadicParser.alt( P.MonadicParser.alt( P.MonadicParser.seq( orNull(propertiesDict.resi).skip(ket), ).map(x => { return { resi: x[0] };}) ))), + // lys:a.ca lys:a lys lys.ca P.MonadicParser.alt( P.MonadicParser.alt( P.MonadicParser.seq( @@ -260,23 +157,20 @@ const lang = P.MonadicParser.createLanguage({ }, - AtomSelectionMacroResi: function (r: any) { - return P.MonadicParser.alt( - P.MonadicParser.alt( - P.MonadicParser.seq( - orNull(propertiesDict.resi) - ).map(x => { return { resi: x[0] };}), - ), - ); - }, - ObjectProperty: () => { const w = h.getReservedWords(special_properties, special_keywords, special_operators) .sort(h.strLenSortFn).map(h.escapeRegExp).join('|'); return P.MonadicParser.regexp(new RegExp(`(?!(${w}))[A-Z0-9_]+`, 'i')); }, + + 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')); + }, + Object: (r: any) => { - return r.ObjectProperty.notFollowedBy(slash) + return r.ObjectProperty2 .map((x: any) => { throw new Error(`property 'object' not supported, value '${x}'`); }); }, @@ -331,60 +225,18 @@ const lang = P.MonadicParser.createLanguage({ }); }, - Operator: function (r: any) { - return h.combineOperators(operators, P.MonadicParser.alt(r.Parens, r.Expression)); - }, - - AtomExpression: function (r: any) { - return P.MonadicParser.seq( - P.MonadicParser.lookahead(r.AtomPrefix), - P.MonadicParser.seq( -// r.ResnoRange.or(P.MonadicParser.of(null)), - r.Resno.or(P.MonadicParser.of(null)), - r.Atomno.or(P.MonadicParser.of(null)), -// r.Resno2.or(P.MonadicParser.of(null)), - r.Inscode.or(P.MonadicParser.of(null)), - r.Chainname.or(P.MonadicParser.of(null)), -// r.Chainname2.or(P.MonadicParser.of(null)), - r.Atomname.or(P.MonadicParser.of(null)), - r.Altloc.or(P.MonadicParser.of(null)), - r.Model.or(P.MonadicParser.of(null))), - ); - }, - - AtomPrefix: () => P.MonadicParser.regexp(/[0-9:^%/.]/).desc('atom-prefix'), - Chainname: () => P.MonadicParser.regexp(/:([A-Za-z]{1,3})/, 1).desc('chainname'), -// Chainname2: () => P.MonadicParser.regexp(/\*([A-Za-z]{1,3})/, 1).desc('chainname'), - Model: () => P.MonadicParser.regexp(/\/([0-9]+)/, 1).map(Number).desc('model'), - Element: () => P.MonadicParser.regexp(/_([A-Za-z]{1,3})/, 1).desc('element'), - Atomname: () => P.MonadicParser.regexp(/\.([a-zA-Z0-9]{1,4})/, 1).map(B.atomName).desc('atomname'), - Resname: () => P.MonadicParser.regexp(/[a-zA-Z0-9]{1,4}/).desc('resname'), - Resno: (r: any) => r.Integer.desc('resno'), - Atomno: (r: any) => r.Integer.desc('atomno'), -// Resno2: (r: any) => r.split(',').Integer.desc('resno'), - Altloc: () => P.MonadicParser.regexp(/%([a-zA-Z0-9])/, 1).desc('altloc'), - Inscode: () => P.MonadicParser.regexp(/\^([a-zA-Z0-9])/, 1).desc('inscode'), - +// Operator: function (r: any) { +// return h.combineOperators(operators, P.MonadicParser.alt(r.Parens, r.Expression)); +// }, - // function listMap(x: string) { return x.split(',').map(x => x.replace(/^["']|["']$/g, '')); } - - - - BracketedResname: function (r: any) { - return P.MonadicParser.regexp(/\.([a-zA-Z0-9]{1,4})/, 1) - .desc('bracketed-resname'); - // [0SD] + Operator: function (r: any) { + return h.combineOperators(operators, P.MonadicParser.alt(r.Parens, r.Expression, r.Operator)); }, - ResnoRange: function (r: any) { - return P.MonadicParser.regexp(/\.([\s]){1,3}/, 1) - .desc('resno-range'); - // 123-200 - // -12--3 - }, Keywords: () => P.MonadicParser.alt(...h.getKeywordRules(keywords)), + Query: function (r: any) { return P.MonadicParser.alt( r.Operator, @@ -413,45 +265,7 @@ const lang = P.MonadicParser.createLanguage({ return P.MonadicParser.alt(r.Number, r.String); }, - ValueParens: function (r: any) { - return P.MonadicParser.alt( - r.ValueParens, - r.ValueOperator, - r.ValueExpressions - ).wrap(P.MonadicParser.string('('), P.MonadicParser.string(')')); - }, - - ValuePropertyNames: function () { - return P.MonadicParser.alt(...h.getPropertyNameRules(properties, /LIKE|>=|<=|=|!=|>|<|\)|\s/i)); - }, - - ValueOperator: function (r: any) { - return h.combineOperators(valueOperators, P.MonadicParser.alt(r.ValueParens, r.ValueExpressions)); - }, - ValueExpressions: function (r: any) { - return P.MonadicParser.alt( - r.Value, - r.ValuePropertyNames - ); - }, - - ValueQuery: function (r: any) { - return P.MonadicParser.alt( - r.ValueOperator.map((x: any) => { - if (x.head.name) { - if (x.head.name.startsWith('structure-query.generator')) return x; - } else { - if (typeof x === 'string' && x.length <= 4) { - return B.struct.generator.atomGroups({ - 'residue-test': B.core.rel.eq([B.ammp('label_comp_id'), x]) - }); - } - } - throw new Error(`values must be part of an comparison, value '${x}'`); - }) - ); - } }); export const transpiler: Transpiler = str => lang.Query.tryParse(str); diff --git a/src/mol-script/transpilers/rasmol/special_properties.ts b/src/mol-script/transpilers/rasmol/special_properties.ts index afe6a9e79..4ca944c6d 100644 --- a/src/mol-script/transpilers/rasmol/special_properties.ts +++ b/src/mol-script/transpilers/rasmol/special_properties.ts @@ -9,7 +9,7 @@ import { MolScriptBuilder } from '../../../mol-script/language/builder'; const B = MolScriptBuilder; import { PropertyDict } from '../types'; -const reFloat = /[-+]?[0-9]*\.?[0-9]+/; +//const reFloat = /[-+]?[0-9]*\.?[0-9]+/; // const rePosInt = /[0-9]+/; function atomNameListMap(x: string) { return x.split(',').map(B.atomName); } @@ -44,18 +44,18 @@ function elementListMap(x: string) { return x.split('+').map(B.struct.type.elementSymbol); } -const sstrucDict: { [k: string]: string } = { - H: 'helix', - S: 'beta', - L: 'none' -}; -function sstrucListMap(x: string) { - return { - flags: B.struct.type.secondaryStructureFlags( - x.toUpperCase().split('+').map(ss => sstrucDict[ss] || 'none') - ) - }; -} +//const sstrucDict: { [k: string]: string } = { +// H: 'helix', +// S: 'beta', +// L: 'none' +//}; +//function sstrucListMap(x: string) { +// return { +// flags: B.struct.type.secondaryStructureFlags( +// x.toUpperCase().split('+').map(ss => sstrucDict[ss] || 'none') +// ) +// }; +//} export const special_properties: PropertyDict = { symbol: { -- GitLab