Browse Source

Within operator was implemented in RasMol

yakomaxa 2 years ago
parent
commit
10cf0db050

+ 15 - 0
src/mol-script/transpilers/helper.ts

@@ -29,6 +29,16 @@ export function prefix(opParser: P.MonadicParser<any>, nextParser: P.MonadicPars
     return parser;
 }
 
+export function prefixRemoveKet(opParser: P.MonadicParser<any>, nextParser: P.MonadicParser<any>, mapFn: any) {
+    const parser: P.MonadicParser<any> = P.MonadicParser.lazy(() => {
+        return P.MonadicParser.seq(opParser, parser.skip(P.MonadicParser.string(")")))
+            .map(x => mapFn(...x))
+            .or(nextParser);
+    });
+    return parser;
+}
+
+
 // Ideally this function would be just like `PREFIX` but reordered like
 // `P.seq(parser, opParser).or(nextParser)`, but that doesn't work. The
 // reason for that is that Parsimmon will get stuck in infinite recursion, since
@@ -129,6 +139,11 @@ export function prefixOp(re: RegExp, group: number = 0) {
     return P.MonadicParser.regexp(re, group).skip(P.MonadicParser.whitespace);
 }
 
+export function prefixOpNoWhiteSpace(re: RegExp, group: number = 0) {
+    //    return P.MonadicParser.regexp(re, group).skip(P.MonadicParser.regexp(/\s*/));
+    return P.MonadicParser.regexp(re, group).skip(P.MonadicParser.regexp(/\s*/));
+}
+
 export function postfixOp(re: RegExp, group: number = 0) {
     return P.MonadicParser.whitespace.then(P.MonadicParser.regexp(re, group));
 }

+ 2 - 2
src/mol-script/transpilers/rasmol/special_properties.ts → src/mol-script/transpilers/rasmol/macroproperties.ts

@@ -1,4 +1,4 @@
-\[/**
+/**
  * Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -60,7 +60,7 @@ function elementListMap(x: string) {
 //    };
 // }
 
-export const special_properties: PropertyDict = {
+export const macroproperties: PropertyDict = {
     symbol: {
         '@desc': 'chemical-symbol-list: list of 1- or 2-letter chemical symbols from the periodic table',
         '@examples': ['symbol O+N'],

+ 66 - 6
src/mol-script/transpilers/rasmol/operators.ts

@@ -4,7 +4,7 @@
  * @author Panagiotis Tourlas <panagiot_tourlov@hotmail.com>
  *
  * @author Koya Sakuma
- * This module is based on jmol transpiler from MolQL and modified in similar manner as pymol and vmd tranpilers.                                             \
+ * This module is based on jmol transpiler from MolQL and modified in similar manner as pymol and vmd tranpilers
  */
 
 
@@ -14,6 +14,10 @@ import { MolScriptBuilder } from '../../../mol-script/language/builder';
 const B = MolScriptBuilder;
 import { OperatorList } from '../types';
 import { Expression } from '../../language/expression';
+import { macroproperties } from './macroproperties'
+
+const propNames = Object.keys(macroproperties).sort(h.strLenSortFn)
+    .filter(name => !macroproperties[name].isUnsupported).join('|');
 
 
 export const operators: OperatorList = [
@@ -30,7 +34,8 @@ export const operators: OperatorList = [
         '@examples': ['ASP and .CA'],
         name: 'and',
         type: h.binaryLeft,
-        rule: h.infixOp(/AND|&/i),
+	rule: P.MonadicParser.alt(h.infixOp(/AND|&/i), P.MonadicParser.whitespace),
+        //rule: h.infixOp(/AND|&/i),
         map: (op, selection, by) => B.struct.modifier.intersectBy({ 0: selection, by })
     },
     {
@@ -41,15 +46,70 @@ export const operators: OperatorList = [
         rule: h.infixOp(/OR|\||\|\|/i),
         map: (op, s1, s2) => B.struct.combinator.merge([s1, s2])
     },
+    /*
     {
         '@desc': 'Selects atoms within a specified distance of a selection',
-        '@examples': ['within 5 of name FE'],
+        '@examples': ['within (5.0, LYS:A.CA)'],
+        name: 'aaa',
+        type: h.prefixRemoveKet,
+        rule: h.prefixOpNoWhiteSpace(/within\s*\(\s*([-+]?[0-9]*\.?[0-9]+)\s*,/, 1).map((x: any) => {
+            console.log(x)
+	    return parseFloat(x)}),
+	map: (radius: number, selection: Expression) => {
+	    
+            return B.struct.modifier.includeSurroundings({ 0: selection, radius });
+        }
+    },
+  */
+    {
+        '@desc':'Selects atoms in s1 that are within X Angstroms of any atom in s2.',
+        '@examples': ['chain A WITHIN 3 OF chain B'],
         name: 'within',
+        abbr: ['w2.'],
+	//   type: h.binaryLeft,
+	type: h.prefixRemoveKet,
+        rule: h.prefixOpNoWhiteSpace(/within\s*\(\s*([-+]?[0-9]*\.?[0-9]+)\s*,/i, 1).map((x: any) => {
+	    console.log(x)
+	    return parseFloat(x)}),
+        map: (radius: number, target: Expression) => {
+	    return B.struct.filter.within({
+                0: B.struct.generator.all(),
+                target,
+                'max-radius': radius,
+	    });
+        },
+    },
+    {
+        '@desc': 'Selects atoms which have the same keyword as the atoms in a given selection',
+        '@examples': ['same resid as name FE'],
+        name: 'same',
         type: h.prefix,
-        rule: h.prefixOp(/within\s+([-+]?[0-9]*\.?[0-9]+)\s+of/, 1).map((x: any) => parseFloat(x)),
-        map: (radius: number, selection: Expression) => {
-            return B.struct.modifier.includeSurroundings({ 0: selection, radius });
+        rule: h.prefixOp(new RegExp(`SAME\\s+(${propNames})\\s+AS`, 'i'), 1).map((x: any) => macroproperties[x].property),
+        map: (property: Expression, source: Expression) => {
+            return B.struct.filter.withSameAtomProperties({
+                '0': B.struct.generator.all(),
+                source,
+                property
+            });
         }
     },
+    {
+        '@desc':
+            'Selects atoms in s1 whose identifiers name and resi match atoms in s2.',
+        '@examples': ['chain A LIKE chain B'],
+        name: 'like',
+        type: h.binaryLeft,
+        rule: h.infixOp(/LIKE|l\./i),
+        map: (op: string, selection: Expression, source: Expression) => {
+            return B.struct.filter.withSameAtomProperties({
+                0: selection,
+                source,
+                property: B.core.type.compositeKey([
+                    B.ammp('label_atom_id'),
+                    B.ammp('label_seq_id'),
+                ]),
+            });
+        },
+    },
 ];
 

+ 29 - 41
src/mol-script/transpilers/rasmol/parser.ts

@@ -12,9 +12,9 @@ import * as h from '../helper';
 import { MolScriptBuilder } from '../../../mol-script/language/builder';
 const B = MolScriptBuilder;
 import { properties } from './properties';
-import { special_properties } from './special_properties';
-import { special_keywords } from './special_keywords';
-import { special_operators } from './special_operators';
+import { macroproperties } from './macroproperties';
+//import { macrokeywords } from './macrokeywords';
+//import { macrooperators } from './macrooperators';
 import { operators } from './operators';
 import { keywords } from './keywords';
 import { AtomGroupArgs } from '../types';
@@ -25,7 +25,7 @@ import { Transpiler } from '../transpiler';
 
 // const slash = P.MonadicParser.string('/');
 
-const propertiesDict = h.getPropertyRules(special_properties);
+const propertiesDict = h.getPropertyRules(macroproperties);
 
 // const slash = P.MonadicParser.string('/');
 const dot = P.MonadicParser.string('.');
@@ -49,7 +49,7 @@ function atomSelectionQuery2(x: any) {
     const props: { [k: string]: any[] } = {};
 
     for (const k in x) {
-        const ps = special_properties[k];
+        const ps = macroproperties[k];
         if (!ps) {
             throw new Error(`property '${k}' not supported, value '${x[k]}'`);
         }
@@ -65,33 +65,12 @@ function atomSelectionQuery2(x: any) {
     return B.struct.generator.atomGroups(tests);
 }
 
-function atomExpressionQuery(x: any[]) {
-    const resname = x[0];
-//    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);
-*/
-    if (resname){
-	return B.struct.generator.atomGroups({'residue-test': B.core.rel.eq([B.ammp('label_comp_id'), resname])})
-    }
-				  
-}
-
+//function atomExpressionQuery(x: any[]) {
+//    const resname = x[0];
+//    if (resname){
+//	return B.struct.generator.atomGroups({'residue-test': B.core.rel.eq([B.ammp('label_comp_id'), resname])})
+//    }				  
+//}
 
 const lang = P.MonadicParser.createLanguage({
 
@@ -109,11 +88,17 @@ const lang = P.MonadicParser.createLanguage({
 	    r.Keywords,
 	    r.NamedAtomProperties,
 	    r.AtomSelectionMacro.map(atomSelectionQuery2),
-//	    r.AtomExpression.map(atomExpressionQuery),
-	    r.Object	    
+//	    r.AtomExparession.map(atomExpressionQuery),
+	    r.Object,
+	    r.Object2,	    
         );
     },
 
+//    AtomExpression: function (r: any) {
+//	return P.MonadicParser.seq(r.Resname.or(P.MonadicParser.of(null)));
+//    },
+
+
 
     //    lys:a.ca  -> resn lys and chain A and name ca
     //    lys*a.ca  -> resn lys and chain A and name ca
@@ -191,7 +176,7 @@ const lang = P.MonadicParser.createLanguage({
 			).map(x => { return { resn: x[0], name: x[1] }; }),
 			P.MonadicParser.seq(
                             orNull(propertiesDict.resn).skip(tator),
-			).map(x => { return { resn: x[0]}; })
+			).map(x => { return { resn: x[0] }; })
 		    )
                 )
 	    )
@@ -200,29 +185,32 @@ const lang = P.MonadicParser.createLanguage({
     },
 
     ObjectProperty: () => {
-        const w = h.getReservedWords(special_properties, special_keywords, special_operators)
+        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'));
     },
 
-    Object: (r: any) => {
+    Object2: (r: any) => {
         return r.ObjectProperty2
             .map((x: any) => { throw new Error(`property 'object' not supported, value '${x}'`); });
     },
 
-    AtomExpression: function (r: any) {
-	return P.MonadicParser.seq(r.Resname.or(P.MonadicParser.of(null)));
-    },
 
     
 //    Resname: () => P.MonadicParser.regexp(s/[a-zA-Z0-9]{1,4}/).desc('resname'),
-    Resname: () => P.MonadicParser.regexp(/\[[A-Z0-9]{1,4}\]/).desc('resname'),
+//    Resname: () => P.MonadicParser.regexp(/\[[A-Z0-9]{1,4}\]/).desc('resname'),
    
     NamedAtomProperties: function () {
         return P.MonadicParser.alt(...h.getNamedPropertyRules(properties));

+ 0 - 232
src/mol-script/transpilers/rasmol/special_keywords.ts

@@ -1,232 +0,0 @@
-/**
- * Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- * @author Panagiotis Tourlas <panagiot_tourlov@hotmail.com>
- */
-
-import { MolScriptBuilder } from '../../../mol-script/language/builder';
-const B = MolScriptBuilder;
-import * as h from '../helper';
-import { KeywordDict } from '../types';
-
-const ResDict = {
-    nucleic: ['A', 'C', 'T', 'G', 'U', 'DA', 'DC', 'DT', 'DG', 'DU'],
-    protein: ['ALA', 'ARG', 'ASN', 'ASP', 'CYS', 'CYX', 'GLN', 'GLU', 'GLY', 'HIS', 'HID', 'HIE', 'HIP', 'ILE', 'LEU', 'LYS', 'MET', 'MSE', 'PHE', 'PRO', 'SER', 'THR', 'TRP', 'TYR', 'VAL'],
-    solvent: ['HOH', 'WAT', 'H20', 'TIP', 'SOL']
-};
-
-const Backbone = {
-    nucleic: ['P', "O3'", "O5'", "C5'", "C4'", "C3'", 'OP1', 'OP2', 'O3*', 'O5*', 'C5*', 'C4*', 'C3*'],
-    protein: ['C', 'N', 'CA', 'O']
-};
-
-
-export const special_keywords: KeywordDict = {
-    all: {
-        '@desc': 'All atoms currently loaded into PyMOL',
-        abbr: ['*'],
-        map: () => B.struct.generator.all()
-    },
-    none: {
-        '@desc': 'No atoms (empty selection)',
-        map: () => B.struct.generator.empty()
-    },
-    hydrogens: {
-        '@desc': 'All hydrogen atoms currently loaded into PyMOL',
-        abbr: ['hydro', 'h.'],
-        map: () => B.struct.generator.atomGroups({
-            'atom-test': B.core.rel.eq([
-                B.acp('elementSymbol'),
-                B.es('H')
-            ])
-        })
-    },
-    hetatm: {
-        '@desc': 'All atoms loaded from Protein Data Bank HETATM records',
-        abbr: ['het'],
-        map: () => B.struct.generator.atomGroups({
-            'atom-test': B.core.rel.eq([B.ammp('isHet'), true])
-        })
-    },
-    visible: {
-        '@desc': 'All atoms in enabled objects with at least one visible representation',
-        abbr: ['v.']
-    },
-    polymer: {
-        '@desc': 'All atoms on the polymer (not het). Finds atoms with residue identifiers matching a known polymer, such a peptide and DNA.',
-        abbr: ['pol.'],
-        map: () => B.struct.generator.atomGroups({
-            'residue-test': B.core.set.has([
-                B.core.type.set(ResDict.nucleic.concat(ResDict.protein)),
-                B.ammp('label_comp_id')
-            ])
-        })
-    },
-    sidechain: {
-        '@desc': 'Polymer non-backbone atoms (new in PyMOL 1.6.1)',
-    },
-    present: {
-        '@desc': 'All atoms with defined coordinates in the current state (used in creating movies)',
-        abbr: ['pr.']
-    },
-    center: {
-        '@desc': 'Pseudo-atom at the center of the scene'
-    },
-    origin: {
-        '@desc': 'Pseudo-atom at the origin of rotation',
-    },
-    enabled: {
-        '@desc': 'All enabled objects or selections from the object list.',
-    },
-    masked: {
-        '@desc': 'All masked atoms.',
-        abbr: ['msk.']
-    },
-    protected: {
-        '@desc': 'All protected atoms.',
-        abbr: ['pr.']
-    },
-    bonded: {
-        '@desc': 'All bonded atoms',
-        map: () => B.struct.generator.atomGroups({
-            'atom-test': B.core.rel.gr([B.struct.atomProperty.core.bondCount({
-                flags: B.struct.type.bondFlags(['covalent', 'metallic', 'sulfide'])
-            }), 0])
-        })
-    },
-    donors: {
-        '@desc': 'All hydrogen bond donor atoms.',
-        abbr: ['don.']
-    },
-    acceptors: {
-        '@desc': 'All hydrogen bond acceptor atoms.',
-        abbr: ['acc.']
-    },
-    fixed: {
-        '@desc': 'All fixed atoms.',
-        abbr: ['fxd.']
-    },
-    restrained: {
-        '@desc': 'All restrained atoms.',
-        abbr: ['rst.']
-    },
-    organic: {
-        '@desc': 'All atoms in non-polymer organic compounds (e.g. ligands, buffers). Finds carbon-containing molecules that do not match known polymers.',
-        abbr: ['org.'],
-        map: () => h.asAtoms(B.struct.modifier.expandProperty({
-            '0': B.struct.modifier.union([
-                B.struct.generator.queryInSelection({
-                    '0': B.struct.generator.atomGroups({
-                        'residue-test': B.core.logic.not([
-                            B.core.set.has([
-                                B.core.type.set(ResDict.nucleic.concat(ResDict.protein)),
-                                B.ammp('label_comp_id')
-                            ])
-                        ])
-                    }),
-                    query: B.struct.generator.atomGroups({
-                        'atom-test': B.core.rel.eq([
-                            B.es('C'),
-                            B.acp('elementSymbol')
-                        ])
-                    })
-                })
-            ]),
-            property: B.ammp('residueKey')
-        }))
-    },
-    inorganic: {
-        '@desc': 'All non-polymer inorganic atoms/ions. Finds atoms in molecules that do not contain carbon and do not match any known solvent residues.',
-        abbr: ['ino.'],
-        map: () => h.asAtoms(B.struct.modifier.expandProperty({
-            '0': B.struct.modifier.union([
-                B.struct.filter.pick({
-                    '0': B.struct.generator.atomGroups({
-                        'residue-test': B.core.logic.not([
-                            B.core.set.has([
-                                B.core.type.set(ResDict.nucleic.concat(ResDict.protein).concat(ResDict.solvent)),
-                                B.ammp('label_comp_id')
-                            ])
-                        ]),
-                        'group-by': B.ammp('residueKey')
-                    }),
-                    test: B.core.logic.not([
-                        B.core.set.has([
-                            B.struct.atomSet.propertySet([B.acp('elementSymbol')]),
-                            B.es('C')
-                        ])
-                    ])
-                })
-            ]),
-            property: B.ammp('residueKey')
-        }))
-    },
-    solvent: {
-        '@desc': 'All water molecules. The hardcoded solvent residue identifiers are currently: HOH, WAT, H20, TIP, SOL.',
-        abbr: ['sol.'],
-        map: () => B.struct.generator.atomGroups({
-            'residue-test': B.core.set.has([
-                B.core.type.set(ResDict.solvent),
-                B.ammp('label_comp_id')
-            ])
-        })
-    },
-    guide: {
-        '@desc': 'All protein CA and nucleic acid C4*/C4',
-        map: () => B.struct.combinator.merge([
-            B.struct.generator.atomGroups({
-                'atom-test': B.core.rel.eq([
-                    B.atomName('CA'),
-                    B.ammp('label_atom_id')
-                ]),
-                'residue-test': B.core.set.has([
-                    B.core.type.set(ResDict.protein),
-                    B.ammp('label_comp_id')
-                ])
-            }),
-            B.struct.generator.atomGroups({
-                'atom-test': B.core.set.has([
-                    h.atomNameSet(['C4*', 'C4']),
-                    B.ammp('label_atom_id')
-                ]),
-                'residue-test': B.core.set.has([
-                    B.core.type.set(ResDict.nucleic),
-                    B.ammp('label_comp_id')
-                ])
-            })
-        ]),
-    },
-    metals: {
-        '@desc': 'All metal atoms (new in PyMOL 1.6.1)'
-    },
-    backbone: {
-        '@desc': 'the C, N, CA, and O atoms of a protein and the equivalent atoms in a nucleic acid.',
-        map: () => B.struct.generator.atomGroups({
-            'atom-test': B.core.set.has([
-                B.core.type.set(Backbone.protein.concat(ResDict.protein)),
-                B.ammp('label_atom_id')
-	    ])
-        }),
-    },
-    proteinxxxxxx: {
-        '@desc': 'protein................',
-        abbr: ['polymer.protein'],
-        map: () => B.struct.generator.atomGroups({
-            'residue-test': B.core.set.has([
-                B.core.type.set(ResDict.protein),
-                B.ammp('label_comp_id')
-            ])
-        })
-    },
-    nucleicxxxxx: {
-        '@desc': 'protein................',
-        abbr: ['polymer.nucleic'],
-        map: () => B.struct.generator.atomGroups({
-            'residue-test': B.core.set.has([
-                B.core.type.set(ResDict.nucleic),
-                B.ammp('label_comp_id')
-            ])
-        })
-    }
-};

+ 0 - 369
src/mol-script/transpilers/rasmol/special_operators.ts

@@ -1,369 +0,0 @@
-/**
- * Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- * @author Panagiotis Tourlas <panagiot_tourlov@hotmail.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 { OperatorList } from '../types';
-import { Expression } from '../../language/expression';
-
-export const special_operators: OperatorList = [
-    {
-        '@desc': 'Selects atoms that are not included in s1.',
-        '@examples': [
-            'NOT resn ALA',
-            'not (resi 42 or chain A)',
-            '!resi 42 or chain A',
-        ],
-        name: 'not',
-        type: h.prefix,
-        rule: P.MonadicParser.alt(
-            P.MonadicParser.regexp(/NOT/i).skip(P.MonadicParser.whitespace),
-            P.MonadicParser.string('!').skip(P.MonadicParser.optWhitespace)
-        ),
-        map: (op, selection) => h.invertExpr(selection),
-    },
-    {
-        '@desc': 'Selects atoms included in both s1 and s2.',
-        '@examples': ['chain A AND name CA'],
-        name: 'and',
-        type: h.binaryLeft,
-        rule: h.infixOp(/AND|&/i),
-        map: (op, selection, by) =>
-            B.struct.modifier.intersectBy({ 0: selection, by }),
-    },
-    {
-        '@desc': 'Selects atoms included in either s1 or s2.',
-        '@examples': ['chain A OR chain B'],
-        name: 'or',
-        type: h.binaryLeft,
-        rule: h.infixOp(/OR|\|/i),
-        map: (op: string, s1: Expression, s2: Expression) => B.struct.combinator.merge([s1, s2]),
-    },
-    {
-        '@desc':
-            'Selects atoms in s1 whose identifiers name, resi, resn, chain and segi all match atoms in s2.',
-        '@examples': ['chain A IN chain B'],
-        name: 'in',
-        type: h.binaryLeft,
-        rule: h.infixOp(/IN/i),
-        map: (op: string, selection: Expression, source: Expression) => {
-            return B.struct.filter.withSameAtomProperties({
-                0: selection,
-                source,
-                property: B.core.type.compositeKey([
-                    B.ammp('label_atom_id'),
-                    B.ammp('label_seq_id'),
-                    B.ammp('label_comp_id'),
-                    B.ammp('auth_asym_id'),
-                    B.ammp('label_asym_id'),
-                ]),
-            });
-        },
-    },
-    {
-        '@desc':
-            'Selects atoms in s1 whose identifiers name and resi match atoms in s2.',
-        '@examples': ['chain A LIKE chain B'],
-        name: 'like',
-        type: h.binaryLeft,
-        rule: h.infixOp(/LIKE|l\./i),
-        map: (op: string, selection: Expression, source: Expression) => {
-            return B.struct.filter.withSameAtomProperties({
-                0: selection,
-                source,
-                property: B.core.type.compositeKey([
-                    B.ammp('label_atom_id'),
-                    B.ammp('label_seq_id'),
-                ]),
-            });
-        },
-    },
-    {
-        '@desc':
-            'Selects all atoms whose van der Waals radii are separated from the van der Waals radii of s1 by a minimum of X Angstroms.',
-        '@examples': ['solvent GAP 2'],
-        name: 'gap',
-        type: h.postfix,
-        rule: h
-            .postfixOp(/GAP\s+([-+]?[0-9]*\.?[0-9]+)/i, 1)
-            .map((x: any) => parseFloat(x)),
-        map: (distance: number, target: Expression) => {
-            return B.struct.filter.within({
-                '0': B.struct.generator.all(),
-                target,
-                'atom-radius': B.acp('vdw'),
-                'max-radius': distance,
-                invert: true,
-            });
-        },
-    },
-    {
-        '@desc':
-            'Selects atoms with centers within X Angstroms of the center of any atom in s1.',
-        '@examples': ['resname LIG AROUND 1'],
-        name: 'around',
-        abbr: ['a.'],
-        type: h.postfix,
-        rule: h
-            .postfixOp(/(AROUND|a\.)\s+([-+]?[0-9]*\.?[0-9]+)/i, 2)
-            .map((x: any) => parseFloat(x)),
-        map: (radius: number, target: Expression) => {
-            return B.struct.modifier.exceptBy({
-                '0': B.struct.filter.within({
-                    '0': B.struct.generator.all(),
-                    target,
-                    'max-radius': radius,
-                }),
-                by: target,
-            });
-        },
-    },
-    {
-        '@desc':
-            'Expands s1 by all atoms within X Angstroms of the center of any atom in s1.',
-        '@examples': ['chain A EXPAND 3'],
-        name: 'expand',
-        abbr: ['x.'],
-        type: h.postfix,
-        rule: h
-            .postfixOp(/(EXPAND|x\.)\s+([-+]?[0-9]*\.?[0-9]+)/i, 2)
-            .map((x: any) => parseFloat(x)),
-        map: (radius: number, selection: Expression) => {
-            return B.struct.modifier.includeSurroundings({ 0: selection, radius });
-        },
-    },
-    {
-        '@desc':
-            'Selects atoms in s1 that are within X Angstroms of any atom in s2.',
-        '@examples': ['chain A WITHIN 3 OF chain B'],
-        name: 'within',
-        abbr: ['w.'],
-        type: h.binaryLeft,
-        rule: h.ofOp('WITHIN', 'w.'),
-        map: (radius: number, selection: Expression, target: Expression) => {
-            return B.struct.filter.within({
-                0: selection,
-                target,
-                'max-radius': radius,
-            });
-        },
-    },
-    {
-        '@desc':
-            'Same as within, but excludes s2 from the selection (and thus is identical to s1 and s2 around X).',
-        '@examples': ['chain A NEAR_TO 3 OF chain B'],
-        name: 'near_to',
-        abbr: ['nto.'],
-        type: h.binaryLeft,
-        rule: h.ofOp('NEAR_TO', 'nto.'),
-        map: (radius: number, selection: Expression, target: Expression) => {
-            return B.struct.modifier.exceptBy({
-                '0': B.struct.filter.within({
-                    '0': selection,
-                    target,
-                    'max-radius': radius,
-                }),
-                by: target,
-            });
-        },
-    },
-    {
-        '@desc': 'Selects atoms in s1 that are at least X Anstroms away from s2.',
-        '@examples': ['solvent BEYOND 2 OF chain A'],
-        name: 'beyond',
-        abbr: ['be.'],
-        type: h.binaryLeft,
-        rule: h.ofOp('BEYOND', 'be.'),
-        map: (radius: number, selection: Expression, target: Expression) => {
-            return B.struct.modifier.exceptBy({
-                '0': B.struct.filter.within({
-                    '0': selection,
-                    target,
-                    'max-radius': radius,
-                    invert: true,
-                }),
-                by: target,
-            });
-        },
-    },
-    {
-        '@desc': 'Expands selection to complete residues.',
-        '@examples': ['BYRESIDUE name N'],
-        name: 'byresidue',
-        abbr: ['byresi', 'byres', 'br.'],
-        type: h.prefix,
-        rule: h.prefixOp(/BYRESIDUE|byresi|byres|br\./i),
-        map: (op: string, selection: Expression) => {
-            return h.asAtoms(
-                B.struct.modifier.expandProperty({
-                    '0': B.struct.modifier.union({ 0: selection }),
-                    property: B.ammp('residueKey'),
-                })
-            );
-        },
-    },
-    {
-        '@desc':
-            'Completely selects all alpha carbons in all residues covered by a selection.',
-        '@examples': ['BYCALPHA chain A'],
-        name: 'bycalpha',
-        abbr: ['bca.'],
-        type: h.prefix,
-        rule: h.prefixOp(/BYCALPHA|bca\./i),
-        map: (op: string, selection: Expression) => {
-            return B.struct.generator.queryInSelection({
-                '0': B.struct.modifier.expandProperty({
-                    '0': B.struct.modifier.union({ 0: selection }),
-                    property: B.ammp('residueKey'),
-                }),
-                query: B.struct.generator.atomGroups({
-                    'atom-test': B.core.rel.eq([
-                        B.atomName('CA'),
-                        B.ammp('label_atom_id'),
-                    ]),
-                }),
-            });
-        },
-    },
-    {
-        '@desc': 'Expands selection to complete molecules.',
-        '@examples': ['BYMOLECULE resi 20-30'],
-        name: 'bymolecule',
-        isUnsupported: true, // structure-query.atom-property.topology.connected-component-key' is not implemented
-        abbr: ['bymol', 'bm.'],
-        type: h.prefix,
-        rule: h.prefixOp(/BYMOLECULE|bymol|bm\./i),
-        map: (op: string, selection: Expression) => {
-            return h.asAtoms(
-                B.struct.modifier.expandProperty({
-                    '0': B.struct.modifier.union({ 0: selection }),
-                    property: B.atp('connectedComponentKey'),
-                })
-            );
-        },
-    },
-    {
-        '@desc': 'Expands selection to complete fragments.',
-        '@examples': ['BYFRAGMENT resi 10'],
-        name: 'byfragment',
-        abbr: ['byfrag', 'bf.'],
-        isUnsupported: true,
-        type: h.prefix,
-        rule: h.prefixOp(/BYFRAGMENT|byfrag|bf\./i),
-        map: (op: string, selection: Expression) => [op, selection],
-    },
-    {
-        '@desc': 'Expands selection to complete segments.',
-        '@examples': ['BYSEGMENT resn CYS'],
-        name: 'bysegment',
-        abbr: ['bysegi', 'byseg', 'bs.'],
-        type: h.prefix,
-        rule: h.prefixOp(/BYSEGMENT|bysegi|byseg|bs\./i),
-        map: (op: string, selection: Expression) => {
-            return h.asAtoms(
-                B.struct.modifier.expandProperty({
-                    '0': B.struct.modifier.union({ 0: selection }),
-                    property: B.ammp('chainKey'),
-                })
-            );
-        },
-    },
-    {
-        '@desc': 'Expands selection to complete objects.',
-        '@examples': ['BYOBJECT chain A'],
-        name: 'byobject',
-        abbr: ['byobj', 'bo.'],
-        isUnsupported: true,
-        type: h.prefix,
-        rule: h.prefixOp(/BYOBJECT|byobj|bo\./i),
-        map: (op: string, selection: Expression) => [op, selection],
-    },
-    {
-        '@desc': 'Expands selection to unit cell.',
-        '@examples': ['BYCELL chain A'],
-        name: 'bycell',
-        isUnsupported: true,
-        type: h.prefix,
-        rule: h.prefixOp(/BYCELL/i),
-        map: (op: string, selection: Expression) => [op, selection],
-    },
-    {
-        '@desc': 'All rings of size ≤ 7 which have at least one atom in s1.',
-        '@examples': ['BYRING resn HEM'],
-        name: 'byring',
-        // isUnsupported: true, // structure-query.atom-set.atom-count' is not implemented.
-        type: h.prefix,
-        rule: h.prefixOp(/BYRING/i),
-        map: (op: string, selection: Expression) => {
-            return h.asAtoms(
-                B.struct.modifier.intersectBy({
-                    '0': B.struct.filter.pick({
-                        '0': B.struct.generator.rings(),
-                        test: B.core.logic.and([
-                            B.core.rel.lte([B.struct.atomSet.atomCount(), 7]),
-                            B.core.rel.gr([B.struct.atomSet.countQuery([selection]), 1]),
-                        ]),
-                    }),
-                    by: selection,
-                })
-            );
-        },
-    },
-    {
-        '@desc': 'Selects atoms directly bonded to s1, excludes s1.',
-        '@examples': ['NEIGHBOR resn CYS'],
-        name: 'neighbor',
-        type: h.prefix,
-        abbr: ['nbr.'],
-        rule: h.prefixOp(/NEIGHBOR|nbr\./i),
-        map: (op: string, selection: Expression) => {
-            return B.struct.modifier.exceptBy({
-                '0': h.asAtoms(
-                    B.struct.modifier.includeConnected({
-                        '0': B.struct.modifier.union({ 0: selection }),
-                        'bond-test': true,
-                    })
-                ),
-                by: selection,
-            });
-        },
-    },
-    {
-        '@desc': 'Selects atoms directly bonded to s1, may include s1.',
-        '@examples': ['BOUND_TO name CA'],
-        name: 'bound_to',
-        abbr: ['bto.'],
-        type: h.prefix,
-        rule: h.prefixOp(/BOUND_TO|bto\./i),
-        map: (op: string, selection: Expression) => {
-            return h.asAtoms(
-                B.struct.modifier.includeConnected({
-                    '0': B.struct.modifier.union({ 0: selection }),
-                })
-            );
-        },
-    },
-    {
-        '@desc': 'Extends s1 by X bonds connected to atoms in s1.',
-        '@examples': ['resname LIG EXTEND 3'],
-        name: 'extend',
-        abbr: ['xt.'],
-        type: h.postfix,
-        rule: h.postfixOp(/(EXTEND|xt\.)\s+([0-9]+)/i, 2).map((x: any) => parseInt(x)),
-        map: (count: number, selection: Expression) => {
-            return h.asAtoms(
-                B.struct.modifier.includeConnected({
-                    '0': B.struct.modifier.union({ 0: selection }),
-                    'bond-test': true,
-                    'layer-count': count,
-                })
-            );
-        },
-    },
-];

+ 6 - 0
src/mol-script/transpilers/rasmol/symbols.ts

@@ -8,6 +8,7 @@
 */
 
 import { properties } from './properties';
+import { macroproperties } from './macroproperties';
 import { operators } from './operators';
 import { keywords } from './keywords';
 
@@ -17,6 +18,11 @@ for (const name in properties) {
     Properties.push(name);
     if (properties[name].abbr) Properties.push(...properties[name].abbr!);
 }
+for (const name in macroproperties) {
+    if (macroproperties[name].isUnsupported) continue;
+    Properties.push(name);
+    if (macroproperties[name].abbr) Properties.push(...macroproperties[name].abbr!);
+}
 
 export const Operators: string[] = [];
 operators.forEach(o => {