Ver Fonte

Merge pull request #18 from yakomaxa/rasmol

Merge from RasMol branch and begin answering the reviewers
KoyaS há 2 anos atrás
pai
commit
67eb16a53f

+ 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));
 }

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

@@ -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'],

+ 75 - 4
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
  */
 
 
@@ -13,7 +13,11 @@ import * as h from '../helper';
 import { MolScriptBuilder } from '../../../mol-script/language/builder';
 const B = MolScriptBuilder;
 import { OperatorList } from '../types';
-// import { Expression } from '../../language/expression';
+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 })
     },
     {
@@ -40,6 +45,72 @@ export const operators: OperatorList = [
         type: h.binaryLeft,
         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.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(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'),
+                ]),
+            });
+        },
+    },
 ];
 

+ 65 - 37
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('.');
@@ -34,6 +34,8 @@ 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(']');
 
 
 /* is Parser -> MonadicParser substitution correct? */
@@ -47,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]}'`);
         }
@@ -63,6 +65,12 @@ function atomSelectionQuery2(x: any) {
     return B.struct.generator.atomGroups(tests);
 }
 
+// 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({
 
@@ -71,7 +79,7 @@ const lang = P.MonadicParser.createLanguage({
             r.Parens,
             r.Operator,
             r.Expression
-        ).wrap(P.MonadicParser.string('['), P.MonadicParser.string(']'));
+        ).wrap(P.MonadicParser.string('{'), P.MonadicParser.string('}'));
     },
 
     Expression: function (r: any) {
@@ -80,10 +88,17 @@ const lang = P.MonadicParser.createLanguage({
 	    r.Keywords,
 	    r.NamedAtomProperties,
 	    r.AtomSelectionMacro.map(atomSelectionQuery2),
-	    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
@@ -133,57 +148,70 @@ const lang = P.MonadicParser.createLanguage({
                 )
 	    )),
 	    //  lys:a.ca lys:a lys lys.ca
-	    P.MonadicParser.alt(
+	    //  [lys]:a.ca [lys]:a [lys] [lys].ca
+	    commu.then(P.MonadicParser.alt(
                 P.MonadicParser.alt(
-                    P.MonadicParser.seq(
-                        orNull(propertiesDict.resn).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(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(colon),
-                        orNull(propertiesDict.chain),
-                    ).map(x => { return { resn: x[0], chain: x[1] }; }),
-		    P.MonadicParser.seq(
-                        orNull(propertiesDict.resn).skip(star),
-                        orNull(propertiesDict.chain),
-                    ).map(x => { return { resn: x[0], chain: x[1] }; }),
-		    P.MonadicParser.seq(
-                        orNull(propertiesDict.resn).skip(dot),
-                        orNull(propertiesDict.name),
-                    ).map(x => { return { resn: x[0], name: x[1] }; }),
-		    P.MonadicParser.seq(
-                        orNull(propertiesDict.resn),
-		    ).map(x => { return { resn: x[0] }; }),
+                    P.MonadicParser.alt(
+                        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(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}'`); });
     },
 
+
+
+    //    Resname: () => P.MonadicParser.regexp(s/[a-zA-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 => {