فهرست منبع

Added many properties and keywords for PyMOL and rasmol

yakomaxa 2 سال پیش
والد
کامیت
dd30fef078

+ 1 - 1
src/mol-plugin-state/transforms/model.ts

@@ -786,7 +786,7 @@ const StructureSelectionFromScript = PluginStateTransform.BuiltIn({
     from: SO.Molecule.Structure,
     to: SO.Molecule.Structure,
     params: () => ({
-        script: PD.Script({ language: 'vmd', expression: 'all' }),
+        script: PD.Script({ language: 'pymol', expression: 'all' }),
         label: PD.Optional(PD.Text(''))
     })
 })({

+ 1 - 1
src/mol-script/script.ts

@@ -30,7 +30,7 @@ function Script(expression: string = "(sel.atom.all)", language: Script.Language
 }
 
 namespace Script {
-    export type Language = 'mol-script' | 'pymol' | 'vmd' | 'jmol | rasmol' 
+    export type Language = 'mol-script' | 'pymol' | 'vmd' | 'jmol' | 'rasmol' 
 
     export function is(x: any): x is Script {
         return !!x && typeof (x as Script).expression === 'string' && !!(x as Script).language;

+ 1 - 1
src/mol-script/transpilers/all.ts

@@ -9,7 +9,7 @@ import jmol from './jmol/parser'
 //import molQLscript from './molql-script/parser'
 import pymol from './pymol/parser'
 import vmd from './vmd/parser'
-import ramol from './rasmol/parser'
+import rasmol from './rasmol/parser'
 
 export default {
     pymol,

+ 20 - 67
src/mol-script/transpilers/pymol/keywords.ts

@@ -65,7 +65,6 @@ export const keywords: KeywordDict = {
     },
     sidechain: {
         '@desc': 'Polymer non-backbone atoms (new in PyMOL 1.6.1)',
-        abbr: ['sc.']
     },
     present: {
         '@desc': 'All atoms with defined coordinates in the current state (used in creating movies)',
@@ -203,77 +202,31 @@ export const keywords: KeywordDict = {
     },
     backbone: {
         '@desc': 'the C, N, CA, and O atoms of a protein and the equivalent atoms in a nucleic acid.',
-        map: () => backboneExpr()
-    },
-    protein: {
-        '@desc': 'protein',
+        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')
+            ])
         })
-    }
+    }				   
 };
-
-function backboneExpr() {
-    return B.struct.combinator.merge([
-        B.struct.generator.queryInSelection({
-            0: proteinExpr(),
-            query: B.struct.generator.atomGroups({
-                'atom-test': B.core.set.has([
-                    h.atomNameSet(Backbone.protein),
-                    B.ammp('label_atom_id')
-                ])
-            })
-        }),
-        B.struct.generator.queryInSelection({
-            0: nucleicExpr(),
-            query: B.struct.generator.atomGroups({
-                'atom-test': B.core.set.has([
-                    h.atomNameSet(Backbone.nucleic),
-                    B.ammp('label_atom_id')
-                ])
-            })
-        })
-    ]);
-}
-
-function proteinExpr() {
-    return B.struct.filter.pick({
-        0: B.struct.generator.atomGroups({
-            'group-by': B.ammp('residueKey')
-        }),
-        test: B.core.set.isSubset([
-            h.atomNameSet(['C', 'N', 'CA', 'O']),
-            B.ammpSet('label_atom_id')
-        ])
-    });
-}
-
-function nucleicExpr() {
-    return B.struct.filter.pick({
-        0: B.struct.generator.atomGroups({
-            'group-by': B.ammp('residueKey')
-        }),
-        test: B.core.logic.and([
-            B.core.set.isSubset([
-                // B.core.type.set([ 'P', 'O1P', 'O2P' ]),
-                h.atomNameSet(['P']),
-                B.ammpSet('label_atom_id')
-            ]),
-            B.core.logic.or([
-                B.core.set.isSubset([
-                    h.atomNameSet(["O3'", "C3'", "C4'", "C5'", "O5'"]),
-                    B.ammpSet('label_atom_id')
-                ]),
-                B.core.set.isSubset([
-                    h.atomNameSet(['O3*', 'C3*', 'C4*', 'C5*', 'O5*']),
-                    B.ammpSet('label_atom_id')
-                ])
-            ])
-        ])
-    });
-}
-

+ 1 - 1
src/mol-script/transpilers/pymol/parser.ts

@@ -59,11 +59,11 @@ const lang = P.MonadicParser.createLanguage({
 
     Expression: function (r : any) {
         return P.MonadicParser.alt(
+	    r.Keywords,
             r.AtomSelectionMacro.map(atomSelectionQuery),
             r.NamedAtomProperties,
             r.Pepseq,
             r.Rep,
-            r.Keywords,
             r.Object
         );
     },

+ 4 - 5
src/mol-script/transpilers/pymol/properties.ts

@@ -10,7 +10,7 @@ const B = MolScriptBuilder;
 import { PropertyDict } from '../types';
 
 const reFloat = /[-+]?[0-9]*\.?[0-9]+/;
-const rePosInt = /[0-9]+/;
+//const rePosInt = /[0-9]+/;
 
 function atomNameListMap(x: string) { return x.split('+').map(B.atomName); }
 function listMap(x: string) { return x.split('+').map(x => x.replace(/^["']|["']$/g, '')); }
@@ -105,15 +105,14 @@ export const properties: PropertyDict = {
     id: {
         '@desc': 'external-index-number a single integer',
         '@examples': ['id 23'],
-        abbr: [], regex: rePosInt, map: x => parseInt(x),
+	regex: /[0-9+-]+/, map: listOrRangeMap,
         level: 'atom-test', property: B.ammp('id')
     },
     index: {
         '@desc': 'internal-index-number a single integer',
         '@examples': ['index 11'],
-        isUnsupported: true,
-        abbr: ['idx.'], regex: rePosInt, map: x => parseInt(x),
-        level: 'atom-test'
+        regex: /[0-9+-]+/, map: listOrRangeMap,
+        level: 'atom-test',property: B.ammp('id')
     },
     ss: {
         '@desc': 'secondary-structure-type list of single letters. Helical regions should be assigned H and sheet regions S. Loop regions can either be assigned L or be blank.',

+ 324 - 451
src/mol-script/transpilers/rasmol/keywords.ts

@@ -10,506 +10,379 @@ const B = MolScriptBuilder;
 import * as h from '../helper';
 import { KeywordDict } from '../types';
 
+const Backbone = {
+    nucleic: ['P', "O3'", "O5'", "C5'", "C4'", "C3'", 'OP1', 'OP2', 'O3*', 'O5*', 'C5*', 'C4*', 'C3*'],
+    protein: ['C', 'N', 'CA', 'O']
+};
+
 
 function nucleicExpr() {
   return B.struct.combinator.merge([
-    B.struct.generator.atomGroups({
-      'residue-test': B.core.set.has([
-        B.set(...['G', 'C', 'A', 'T', 'U', 'I', 'DG', 'DC', 'DA', 'DT', 'DU', 'DI', '+G', '+C', '+A', '+T', '+U', '+I']),
-        B.ammp('label_comp_id')
-      ])
-    }),
-    B.struct.filter.pick({
-      0: B.struct.generator.atomGroups({
-        'group-by': B.ammp('residueKey')
+      B.struct.generator.atomGroups({
+	  'residue-test': B.core.set.has([
+              B.set(...['G', 'C', 'A', 'T', 'U', 'I', 'DG', 'DC', 'DA', 'DT', 'DU', 'DI', '+G', '+C', '+A', '+T', '+U', '+I']),
+              B.ammp('label_comp_id')
+	  ])
       }),
-      test: B.core.logic.and([
-        B.core.rel.eq([ B.struct.atomSet.atomCount(), 1 ]),
-        B.core.rel.eq([ B.ammp('label_atom_id'), B.atomName('P') ]),
-      ])
-    }),
-    B.struct.filter.pick({
-      0: B.struct.generator.atomGroups({
-        'group-by': B.ammp('residueKey')
+      B.struct.filter.pick({
+	  0: B.struct.generator.atomGroups({
+              'group-by': B.ammp('residueKey')
+	  }),
+	  test: B.core.logic.and([
+              B.core.rel.eq([ B.struct.atomSet.atomCount(), 1 ]),
+              B.core.rel.eq([ B.ammp('label_atom_id'), B.atomName('P') ]),
+	  ])
       }),
-      test: B.core.logic.or([
-        B.core.set.isSubset([
-          h.atomNameSet([ "C1'", "C2'", "O3'", "C3'", "C4'", "C5'", "O5'" ]),
-          B.ammpSet('label_atom_id')
-        ]),
-        B.core.set.isSubset([
-          h.atomNameSet([ 'C1*', 'C2*', 'O3*', 'C3*', 'C4*', 'C5*', 'O5*' ]),
-          B.ammpSet('label_atom_id')
-        ])
-      ])
-    })
+      B.struct.filter.pick({
+	  0: B.struct.generator.atomGroups({
+              'group-by': B.ammp('residueKey')
+	  }),
+	  test: B.core.logic.or([
+              B.core.set.isSubset([
+		  h.atomNameSet([ "C1'", "C2'", "O3'", "C3'", "C4'", "C5'", "O5'" ]),
+		  B.ammpSet('label_atom_id')
+              ]),
+              B.core.set.isSubset([
+		  h.atomNameSet([ 'C1*', 'C2*', 'O3*', 'C3*', 'C4*', 'C5*', 'O5*' ]),
+		  B.ammpSet('label_atom_id')
+              ])
+	  ])
+      })
   ])
 }
 
+
+
 const ResDict = {
-  acidic: ['ASP', 'GLU'],
-  aliphatic: ['ALA', 'GLY', 'ILE', 'LEU', 'VAL'],
-  amino: ['ALA', 'ARG', 'ASN', 'ASP', 'CYS', 'GLN', 'GLU', 'GLY', 'HIS', 'ILE', 'LEU', 'LYS', 'MET', 'PHE', 'PRO', 'SER', 'THR', 'TRP', 'TYR', 'VAL', 'ASX', 'GLX', 'UNK', ],
-  aromatic: ['HIS', 'PHE', 'TRP', 'TYR'],
-  basic: ['ARG', 'HIS', 'LYS'],
-  buried: ['ALA','CYS', 'ILE', 'LEU', 'MET', 'PHE', 'TRP', 'VAL'],
-  cg: ['CYT', 'C', 'GUA', 'G'],
-  cyclic: ['HIS', 'PHE', 'PRO', 'TRP', 'TYR'],
-  hydrophobic: ['ALA', 'GLY', 'ILE', 'LEU', 'MET', 'PHE', 'PRO', 'TRP', 'TYR', 'VAL'],
-  large: ['ARG', 'GLU', 'GLN', 'HIS', 'ILE', 'LEU', 'LYS', 'MET', 'PHE', 'TRP', 'TYR'],
-  medium: ['ASN', 'ASP', 'CYS', 'PRO', 'THR', 'VAL'],
-  small: ['ALA', 'GLY', 'SER'],
-}
+    aliphatic: ['ALA', 'GLY', 'ILE', 'LEU', 'VAL'],
+    amino: ['ALA', 'ARG', 'ASN', 'ASP', 'CYS', 'GLN', 'GLU', 'GLY', 'HIS', 'ILE', 'LEU', 'LYS', 'MET', 'PHE', 'PRO', 'SER', 'THR', 'TRP', 'TYR', 'VAL', 'ASX', 'GLX', 'UNK', ],
+    acidic: ['ASP', 'GLU'],
+    aromatic: ['HIS', 'PHE', 'TRP', 'TYR'],
+    basic: ['ARG', 'HIS', 'LYS'],
+    buried: ['ALA','CYS', 'ILE', 'LEU', 'MET', 'PHE', 'TRP', 'VAL'],
+    cg: ['CYT', 'C', 'GUA', 'G'],
+    cyclic: ['HIS', 'PHE', 'PRO', 'TRP', 'TYR'],
+    hydrophobic: ['ALA', 'GLY', 'ILE', 'LEU', 'MET', 'PHE', 'PRO', 'TRP', 'TYR', 'VAL'],
+    large: ['ARG', 'GLU', 'GLN', 'HIS', 'ILE', 'LEU', 'LYS', 'MET', 'PHE', 'TRP', 'TYR'],
+    medium: ['ASN', 'ASP', 'CYS', 'PRO', 'THR', 'VAL'],
+    small: ['ALA', 'GLY', 'SER'],
+    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']
+};
+
 
 export const keywords: KeywordDict = {
   // general terms
   all: {
-    '@desc': 'all atoms; same as *',
-    abbr: ['*'],
-    map: () => B.struct.generator.all()
-  },
-  bonded: {
-    '@desc': 'covalently bonded',
-    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])
-    })
-  },
-  clickable: {
-    '@desc': 'actually visible -- having some visible aspect such as wireframe, spacefill, or a label showing, or the alpha-carbon or phosphorus atom in a biomolecule that is rendered with only cartoon, rocket, or other biomolecule-specific shape.'
-  },
-  connected: {
-    '@desc': 'bonded in any way, including hydrogen bonds',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.rel.gr([B.struct.atomProperty.core.bondCount({
-        flags: B.struct.type.bondFlags()
-      }), 0])
-    })
-  },
-  displayed: {
-    '@desc': 'displayed using the display or hide command; not necessarily visible'
-  },
-  hidden: {
-    '@desc': 'hidden using the display or hide command'
-  },
-  none: {
-    '@desc': 'no atoms',
-    map: () => B.struct.generator.empty()
-  },
-  selected: {
-    '@desc': 'atoms that have been selected; defaults to all when a file is first loaded'
-  },
-  thisModel: {
-    '@desc': 'atoms in the current frame set, as defined by frame, model, or animation commands. If more than one model is in this set, "thisModel" refers to all of them, regardless of atom displayed/hidden status.'
-  },
-  visible: {
-    '@desc': 'visible in any way, including PDB residue atoms for which a cartoon or other such rendering makes their group visible, even if they themselves are not visible.'
-  },
-  subset: {
-    '@desc': 'the currently defined subset. Note that if a subset is currently defined, then select/display all is the same as select/display subset, restrict none is the same as restrict not subset. In addition, select not subset selects nothing.'
-  },
-  specialPosition: {
-    '@desc': 'atoms in crystal structures that are at special positions - that is, for which there is more than one operator that leads to them.'
-  },
-  unitcell: {
-    '@desc': 'atoms within the current unitcell, which may be offset. This includes atoms on the faces and at the vertices of the unitcell.'
-  },
-  polyhedra: {
-    '@desc': 'all central atoms for which polyhedra have been created. See also polyhera(n), below. (Jmol 14.4)'
-  },
-  nonmetal: {
-    '@desc': '_H,_He,_B,_C,_N,_O,_F,_Ne,_Si,_P,_S,_Cl,_Ar,_As,_Se,_Br,_Kr,_Te,_I,_Xe,_At,_Rn',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.set.has([
-        B.set(...['H','He','B','C','N','O','F','Ne','Si','P','S','Cl','Ar','As','Se','Br','Kr','Te','I','Xe','At','Rn'].map(B.es)),
-        B.acp('elementSymbol')
-      ])
-    })
-  },
-  metal: {
-    '@desc': '!nonmetal',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.logic.not([
-        B.core.set.has([
-          B.set(...['H','He','B','C','N','O','F','Ne','Si','P','S','Cl','Ar','As','Se','Br','Kr','Te','I','Xe','At','Rn'].map(B.es)),
-          B.acp('elementSymbol')
-        ])
-      ])
-    })
-  },
-  alkaliMetal: {
-    '@desc': '_Li,_Na,_K,_Rb,_Cs,_Fr',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.set.has([
-        B.set(...['Li','Na','K','Rb','Cs','Fr'].map(B.es)),
-        B.acp('elementSymbol')
-      ])
-    })
-  },
-  alkalineEarth: {
-    '@desc': '_Be,_Mg,_Ca,_Sr,_Ba,_Ra',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.set.has([
-        B.set(...['Be','Mg','Ca','Sr','Ba','Ra'].map(B.es)),
-        B.acp('elementSymbol')
-      ])
-    })
-  },
-  nobleGas: {
-    '@desc': '_He,_Ne,_Ar,_Kr,_Xe,_Rn',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.set.has([
-        B.set(...['He','Ne','Ar','Kr','Xe','Rn'].map(B.es)),
-        B.acp('elementSymbol')
-      ])
-    })
-  },
-  metalloid: {
-    '@desc': '_B,_Si,_Ge,_As,_Sb,_Te',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.set.has([
-        B.set(...['B','Si','Ge','As','Sb','Te'].map(B.es)),
-        B.acp('elementSymbol')
-      ])
-    })
-  },
-  transitionMetal: {
-    '@desc': '(includes La and Ac) elemno>=21 and elemno<=30, elemno=57, elemno=89, elemno>=39 and elemno<=48, elemno>=72 and elemno<=80, elemno>=104 and elemno<=112',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.logic.or([
-        B.core.rel.inRange([B.acp('atomicNumber'), 21, 30]),
-        B.core.rel.inRange([B.acp('atomicNumber'), 39, 48]),
-        B.core.rel.inRange([B.acp('atomicNumber'), 72, 80]),
-        B.core.rel.inRange([B.acp('atomicNumber'), 104, 112]),
-        B.core.set.has([B.set(57, 89), B.acp('atomicNumber')])
-      ])
-    })
-  },
-  lanthanide: {
-    '@desc': '(does not include La) elemno>57 and elemno<=71',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.rel.inRange([B.acp('atomicNumber'), 57, 71])
-    })
-  },
-  actinide: {
-    '@desc': '(does not include Ac) elemno>89 and elemno<=103',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.rel.inRange([B.acp('atomicNumber'), 89, 103])
-    })
-  },
-  isaromatic: {
-    '@desc': 'atoms connected with the AROMATIC, AROMATICSINGLE, or AROMATICDOUBLE bond types',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.rel.gr([
-        B.struct.atomProperty.core.bondCount({
-          flags: B.struct.type.bondFlags(['aromatic'])
-        }),
-        0
-      ])
-    })
-  },
-
-  carbohydrate: {
-    '@desc': ''
-  },
-  ions: {
-    '@desc': '(specifically the PDB designations "PO4" and "SO4")'
-  },
-  ligand: {
-    '@desc': '(originally "hetero and not solvent"; changed to "!(protein,nucleic,water,UREA)" for Jmol 12.2)'
-  },
-  nucleic: {
-    '@desc': 'any group that (a) has one of the following group names: G, C, A, T, U, I, DG, DC, DA, DT, DU, DI, +G, +C, +A, +T, +U, +I; or (b) can be identified as a group that is only one atom, with name "P"; or (c) has all of the following atoms (prime, \', can replace * here): C1*, C2*, C3*, O3*, C4*, C5*, and O5*.',
-    map: () => nucleicExpr()
-  },
-  purine: {
-    '@desc': 'any nucleic group that (a) has one of the following group names: A, G, I, DA, DG, DI, +A, +G, or +I; or (b) also has atoms N7, C8, and N9.',
-    map: () => B.struct.modifier.intersectBy({
-      0: nucleicExpr(),
-      by: B.struct.combinator.merge([
-        B.struct.generator.atomGroups({
-          'residue-test': B.core.set.has([
-            B.set(...['A', 'G', 'I', 'DA', 'DG', 'DI', '+A', '+G', '+I']),
-            B.ammp('label_comp_id')
-          ])
-        }),
-        B.struct.filter.pick({
-          0: B.struct.generator.atomGroups({
-            'group-by': B.ammp('residueKey')
-          }),
-          test: B.core.set.isSubset([
-            h.atomNameSet([ 'N7', 'C8', 'N9' ]),
-            B.ammpSet('label_atom_id')
-          ])
-        })
-      ])
+      '@desc': 'all atoms; same as *',
+      abbr: ['*'],
+      map: () => B.struct.generator.all()
+  },
+    none: {
+	'@desc': 'no atoms',
+	map: () => B.struct.generator.empty()
+  },
+    selected: {
+	'@desc': 'atoms that have been selected; defaults to all when a file is first loaded'
+    },
+    unitcell: {
+	'@desc': 'atoms within the current unitcell, which may be offset. This includes atoms on the faces and at the vertices of the unitcell.'
+    },
+    ions: {
+	'@desc': '(specifically the PDB designations "PO4" and "SO4")'
+    },
+    ligand: {
+	'@desc': '(originally "hetero and not solvent"; changed to "!(protein,nucleic,water,UREA)" for Jmol 12.2)'
+    },
+    nucleic: {
+	'@desc': 'any group that (a) has one of the following group names: G, C, A, T, U, I, DG, DC, DA, DT, DU, DI, +G, +C, +A, +T, +U, +I; or (b) can be identified as a group that is only one atom, with name "P"; or (c) has all of the following atoms (prime, \', can replace * here): C1*, C2*, C3*, O3*, C4*, C5*, and O5*.',
+	map: () => nucleicExpr()
+    },
+    purine: {
+	'@desc': 'any nucleic group that (a) has one of the following group names: A, G, I, DA, DG, DI, +A, +G, or +I; or (b) also has atoms N7, C8, and N9.',
+	map: () => B.struct.modifier.intersectBy({
+	    0: nucleicExpr(),
+	    by: B.struct.combinator.merge([
+		B.struct.generator.atomGroups({
+		    'residue-test': B.core.set.has([
+			B.set(...['A', 'G', 'I', 'DA', 'DG', 'DI', '+A', '+G', '+I']),
+			B.ammp('label_comp_id')
+		    ])
+		}),
+		B.struct.filter.pick({
+		    0: B.struct.generator.atomGroups({
+			'group-by': B.ammp('residueKey')
+		    }),
+		    test: B.core.set.isSubset([
+			h.atomNameSet([ 'N7', 'C8', 'N9' ]),
+			B.ammpSet('label_atom_id')
+		    ])
+		})
+	    ])
+	})
+    },
+    pyrimidine: {
+	'@desc': 'any nucleic group that (a) has one of the following group names: C, T, U, DC, DT, DU, +C, +T, +U; or (b) also has atom O2.',
+	map: () => B.struct.modifier.intersectBy({
+	    0: nucleicExpr(),
+	    by: B.struct.combinator.merge([
+		B.struct.generator.atomGroups({
+		    'residue-test': B.core.set.has([
+			B.set(...['C', 'T', 'U', 'DC', 'DT', 'DU', '+C', '+T', '+U']),
+			B.ammp('label_comp_id')
+		    ])
+		}),
+		B.struct.filter.pick({
+		    0: B.struct.generator.atomGroups({
+			'group-by': B.ammp('residueKey')
+		    }),
+		    test: B.core.logic.or([
+			B.core.set.has([
+			    B.ammpSet('label_atom_id'),
+			    B.atomName('O2*')
+			]),
+			B.core.set.has([
+			    B.ammpSet('label_atom_id'),
+			    B.atomName("O2'")
+			])
+		    ])
+		})
+	    ])
+	})
+    },
+    dna: {
+	'@desc': 'any nucleic group that (a) has one of the following group names: DG, DC, DA, DT, DU, DI, T, +G, +C, +A, +T; or (b) has neither atom O2* or O2\'.',
+	map: () => B.struct.modifier.intersectBy({
+	    0: nucleicExpr(),
+	    by: B.struct.combinator.merge([
+		B.struct.generator.atomGroups({
+		    'residue-test': B.core.set.has([
+			B.set(...['DG', 'DC', 'DA', 'DT', 'DU', 'DI', 'T', '+G', '+C', '+A', '+T']),
+			B.ammp('label_comp_id')
+		    ])
+		}),
+		B.struct.filter.pick({
+		    0: B.struct.generator.atomGroups({
+			'group-by': B.ammp('residueKey')
+		    }),
+		    test: B.core.logic.not([
+			B.core.logic.or([
+			    B.core.set.has([
+				B.ammpSet('label_atom_id'),
+				B.atomName('O2*')
+			    ]),
+			    B.core.set.has([
+				B.ammpSet('label_atom_id'),
+				B.atomName("O2'")
+			    ])
+			])
+		    ])
+		})
+	    ])
+	})
+    },
+    rna: {
+	'@desc': 'any nucleic group that (a) has one of the following group names: G, C, A, U, I, +U, +I; or (b) has atom O2* or O2\'.',
+	map: () => B.struct.modifier.intersectBy({
+	    0: nucleicExpr(),
+	    by: B.struct.combinator.merge([
+		B.struct.generator.atomGroups({
+		    'residue-test': B.core.set.has([
+			B.set(...['G', 'C', 'A', 'U', 'I', '+U', '+I']),
+			B.ammp('label_comp_id')
+		    ])
+		}),
+		B.struct.filter.pick({
+		    0: B.struct.generator.atomGroups({
+			'group-by': B.ammp('residueKey')
+		    }),
+		    test: B.core.logic.or([
+			B.core.set.has([
+			    B.ammpSet('label_atom_id'),
+			    B.atomName('O2*')
+			]),
+			B.core.set.has([
+			    B.ammpSet('label_atom_id'),
+			    B.atomName("O2'")
+			])
+		    ])
+		})
+	    ])
+	})
+    },
+    protein: {
+	'@desc': 'defined as a group that (a) has one of the following group names: ALA, ARG, ASN, ASP, CYS, GLN, GLU, GLY, HIS, ILE, LEU}, LYS, MET, PHE, PRO, SER, THR, TRP, TYR, VAL, ASX, GLX, or UNK; or (b) contains PDB atom designations [C, O, CA, and N] bonded correctly; or (c) does not contain "O" but contains [C, CA, and N] bonded correctly; or (d) has only one atom, which has name CA and does not have the group name CA (indicating a calcium atom).',
+	map: () => proteinExpr()	
+    },
+    acidic: {
+	'@desc': 'ASP GLU',
+      map: () => h.resnameExpr(ResDict.acidic)
+  },
+    acyclic: {
+      '@desc': 'amino and not cyclic',
+      map: () => B.struct.modifier.intersectBy({
+	0: h.resnameExpr(ResDict.amino),
+	by: h.invertExpr(h.resnameExpr(ResDict.cyclic))
     })
   },
-  pyrimidine: {
-    '@desc': 'any nucleic group that (a) has one of the following group names: C, T, U, DC, DT, DU, +C, +T, +U; or (b) also has atom O2.',
-    map: () => B.struct.modifier.intersectBy({
-      0: nucleicExpr(),
-      by: B.struct.combinator.merge([
-        B.struct.generator.atomGroups({
-          'residue-test': B.core.set.has([
-            B.set(...['C', 'T', 'U', 'DC', 'DT', 'DU', '+C', '+T', '+U']),
-            B.ammp('label_comp_id')
-          ])
-        }),
-        B.struct.filter.pick({
-          0: B.struct.generator.atomGroups({
-            'group-by': B.ammp('residueKey')
-          }),
-          test: B.core.logic.or([
-            B.core.set.has([
-              B.ammpSet('label_atom_id'),
-              B.atomName('O2*')
-            ]),
-            B.core.set.has([
-              B.ammpSet('label_atom_id'),
-              B.atomName("O2'")
-            ])
-          ])
-        })
-      ])
-    })
+    aliphatic: {
+      '@desc': 'ALA GLY ILE LEU VAL',
+      map: () => h.resnameExpr(ResDict.aliphatic)
   },
-  dna: {
-    '@desc': 'any nucleic group that (a) has one of the following group names: DG, DC, DA, DT, DU, DI, T, +G, +C, +A, +T; or (b) has neither atom O2* or O2\'.',
-    map: () => B.struct.modifier.intersectBy({
-      0: nucleicExpr(),
-      by: B.struct.combinator.merge([
-        B.struct.generator.atomGroups({
-          'residue-test': B.core.set.has([
-            B.set(...['DG', 'DC', 'DA', 'DT', 'DU', 'DI', 'T', '+G', '+C', '+A', '+T']),
-            B.ammp('label_comp_id')
-          ])
-        }),
-        B.struct.filter.pick({
-          0: B.struct.generator.atomGroups({
-            'group-by': B.ammp('residueKey')
-          }),
-          test: B.core.logic.not([
-            B.core.logic.or([
-              B.core.set.has([
-                B.ammpSet('label_atom_id'),
-                B.atomName('O2*')
-              ]),
-              B.core.set.has([
-                B.ammpSet('label_atom_id'),
-                B.atomName("O2'")
-              ])
-            ])
-          ])
-        })
-      ])
-    })
+    amino: {
+      '@desc': 'all twenty standard amino acids, plus ASX, GLX, UNK',
+      map: () => h.resnameExpr(ResDict.amino)
   },
-  rna: {
-    '@desc': 'any nucleic group that (a) has one of the following group names: G, C, A, U, I, +U, +I; or (b) has atom O2* or O2\'.',
-    map: () => B.struct.modifier.intersectBy({
-      0: nucleicExpr(),
-      by: B.struct.combinator.merge([
-        B.struct.generator.atomGroups({
-          'residue-test': B.core.set.has([
-            B.set(...['G', 'C', 'A', 'U', 'I', '+U', '+I']),
-            B.ammp('label_comp_id')
-          ])
-        }),
-        B.struct.filter.pick({
-          0: B.struct.generator.atomGroups({
-            'group-by': B.ammp('residueKey')
-          }),
-          test: B.core.logic.or([
-            B.core.set.has([
-              B.ammpSet('label_atom_id'),
-              B.atomName('O2*')
-            ]),
-            B.core.set.has([
-              B.ammpSet('label_atom_id'),
-              B.atomName("O2'")
-            ])
-          ])
-        })
-      ])
-    })
+    aromatic: {
+      '@desc': 'HIS PHE TRP TYR (see also "isaromatic" for aromatic bonds)',
+      map: () => h.resnameExpr(ResDict.aromatic)
   },
-  protein: {
-    '@desc': 'defined as a group that (a) has one of the following group names: ALA, ARG, ASN, ASP, CYS, GLN, GLU, GLY, HIS, ILE, LEU, LYS, MET, PHE, PRO, SER, THR, TRP, TYR, VAL, ASX, GLX, or UNK; or (b) contains PDB atom designations [C, O, CA, and N] bonded correctly; or (c) does not contain "O" but contains [C, CA, and N] bonded correctly; or (d) has only one atom, which has name CA and does not have the group name CA (indicating a calcium atom).'
+    basic: {
+      '@desc': 'ARG HIS LYS',
+      map: () => h.resnameExpr(ResDict.basic)
   },
-  acidic: {
-    '@desc': 'ASP GLU',
-    map: () => h.resnameExpr(ResDict.acidic)
+    buried: {
+      '@desc': 'ALA CYS ILE LEU MET PHE TRP VAL',
+      map: () => h.resnameExpr(ResDict.buried)
   },
-  acyclic: {
-    '@desc': 'amino and not cyclic',
-    map: () => B.struct.modifier.intersectBy({
-      0: h.resnameExpr(ResDict.amino),
-      by: h.invertExpr(h.resnameExpr(ResDict.cyclic))
-    })
+    charged: {
+      '@desc': 'same as acidic or basic -- ASP GLU, ARG HIS LYS',
+      map: () => h.resnameExpr(ResDict.acidic.concat(ResDict.basic))
   },
-  aliphatic: {
-    '@desc': 'ALA GLY ILE LEU VAL',
-    map: () => h.resnameExpr(ResDict.aliphatic)
+    cyclic: {
+      '@desc': 'HIS PHE PRO TRP TYR',
+      map: () => h.resnameExpr(ResDict.cyclic)
   },
-  amino: {
-    '@desc': 'all twenty standard amino acids, plus ASX, GLX, UNK',
-    map: () => h.resnameExpr(ResDict.amino)
-  },
-  aromatic: {
-    '@desc': 'HIS PHE TRP TYR (see also "isaromatic" for aromatic bonds)',
-    map: () => h.resnameExpr(ResDict.aromatic)
-  },
-  basic: {
-    '@desc': 'ARG HIS LYS',
-    map: () => h.resnameExpr(ResDict.basic)
-  },
-  buried: {
-    '@desc': 'ALA CYS ILE LEU MET PHE TRP VAL',
-    map: () => h.resnameExpr(ResDict.buried)
-  },
-  charged: {
-    '@desc': 'same as acidic or basic -- ASP GLU, ARG HIS LYS',
-    map: () => h.resnameExpr(ResDict.acidic.concat(ResDict.basic))
-  },
-  cyclic: {
-    '@desc': 'HIS PHE PRO TRP TYR',
-    map: () => h.resnameExpr(ResDict.cyclic)
-  },
-  helix: {
-    '@desc': 'secondary structure-related.',
-    map: () => B.struct.generator.atomGroups({
-      'residue-test': B.core.flags.hasAny([
-        B.struct.type.secondaryStructureFlags(['helix']),
-        B.ammp('secondaryStructureFlags')
-      ])
-    })
-  },
-  helixalpha: {
-    '@desc': 'secondary structure-related.',
-    map: () => B.struct.generator.atomGroups({
-      'residue-test': B.core.flags.hasAny([
-        B.struct.type.secondaryStructureFlags(['alpha']),
-        B.ammp('secondaryStructureFlags')
-      ])
-    })
-  },
-  helix310: {
-    '@desc': 'secondary structure-related.',
-    map: () => B.struct.generator.atomGroups({
-      'residue-test': B.core.flags.hasAny([
-        B.struct.type.secondaryStructureFlags(['3-10']),
-        B.ammp('secondaryStructureFlags')
-      ])
-    })
-  },
-  helixpi: {
-    '@desc': 'secondary structure-related.',
-    map: () => B.struct.generator.atomGroups({
-      'residue-test': B.core.flags.hasAny([
-        B.struct.type.secondaryStructureFlags(['pi']),
-        B.ammp('secondaryStructureFlags')
+    helix: {
+      '@desc': 'secondary structure-related.',
+      map: () => B.struct.generator.atomGroups({
+	'residue-test': B.core.flags.hasAny([
+          B.struct.type.secondaryStructureFlags(['helix']),
+          B.ammp('secondaryStructureFlags')
       ])
     })
   },
-  hetero: {
-    '@desc': 'PDB atoms designated as HETATM',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.ammp('isHet')
+    hetero: {
+      '@desc': 'PDB atoms designated as HETATM',
+      map: () => B.struct.generator.atomGroups({
+	'atom-test': B.ammp('isHet')
     })
   },
-  hydrophobic: {
-    '@desc': 'ALA GLY ILE LEU MET PHE PRO TRP TYR VAL',
-    map: () => h.resnameExpr(ResDict.hydrophobic)
+    hydrophobic: {
+      '@desc': 'ALA GLY ILE LEU MET PHE PRO TRP TYR VAL',
+      map: () => h.resnameExpr(ResDict.hydrophobic)
   },
-  large: {
-    '@desc': 'ARG GLU GLN HIS ILE LEU LYS MET PHE TRP TYR',
-    map: () => h.resnameExpr(ResDict.large)
+    large: {
+      '@desc': 'ARG GLU GLN HIS ILE LEU LYS MET PHE TRP TYR',
+      map: () => h.resnameExpr(ResDict.large)
   },
-  medium: {
-    '@desc': 'ASN ASP CYS PRO THR VAL',
-    map: () => h.resnameExpr(ResDict.medium)
+    medium: {
+      '@desc': 'ASN ASP CYS PRO THR VAL',
+      map: () => h.resnameExpr(ResDict.medium)
   },
-  negative: {
-    '@desc': 'same as acidic -- ASP GLU',
-    map: () => h.resnameExpr(ResDict.acidic)
+    negative: {
+      '@desc': 'same as acidic -- ASP GLU',
+      map: () => h.resnameExpr(ResDict.acidic)
   },
-  neutral: {
-    '@desc': 'amino and not (acidic or basic)',
-    map: () => B.struct.modifier.intersectBy({
-      0: h.resnameExpr(ResDict.amino),
-      by: h.invertExpr(h.resnameExpr(ResDict.acidic.concat(ResDict.basic)))
+    neutral: {
+      '@desc': 'amino and not (acidic or basic)',
+      map: () => B.struct.modifier.intersectBy({
+	0: h.resnameExpr(ResDict.amino),
+	by: h.invertExpr(h.resnameExpr(ResDict.acidic.concat(ResDict.basic)))
     })
   },
-  polar: {
-    '@desc': 'amino and not hydrophobic',
-    map: () => B.struct.modifier.intersectBy({
-      0: h.resnameExpr(ResDict.amino),
-      by: h.invertExpr(h.resnameExpr(ResDict.hydrophobic))
+    polar: {
+      '@desc': 'amino and not hydrophobic',
+      map: () => B.struct.modifier.intersectBy({
+	0: h.resnameExpr(ResDict.amino),
+	by: h.invertExpr(h.resnameExpr(ResDict.hydrophobic))
     })
   },
-  positive: {
-    '@desc': 'same as basic -- ARG HIS LYS',
-    map: () => h.resnameExpr(ResDict.basic)
+    positive: {
+      '@desc': 'same as basic -- ARG HIS LYS',
+      map: () => h.resnameExpr(ResDict.basic)
   },
-  sheet: {
-    '@desc': 'secondary structure-related',
-    map: () => B.struct.generator.atomGroups({
-      'residue-test': B.core.flags.hasAny([
-        B.struct.type.secondaryStructureFlags(['sheet']),
-        B.ammp('secondaryStructureFlags')
+    sheet: {
+      '@desc': 'secondary structure-related',
+      map: () => B.struct.generator.atomGroups({
+	'residue-test': B.core.flags.hasAny([
+          B.struct.type.secondaryStructureFlags(['sheet']),
+          B.ammp('secondaryStructureFlags')
       ])
     })
   },
-  small: {
-    '@desc': 'ALA GLY SER',
-    map: () => h.resnameExpr(ResDict.small)
-  },
-  surface: {
-    '@desc': 'amino and not buried',
-    map: () => B.struct.modifier.intersectBy({
-      0: h.resnameExpr(ResDict.amino),
-      by: h.invertExpr(h.resnameExpr(ResDict.buried))
-    })
+    small: {
+      '@desc': 'ALA GLY SER',
+      map: () => h.resnameExpr(ResDict.small)
   },
-  turn: {
-    '@desc': 'secondary structure-related',
-    map: () => B.struct.generator.atomGroups({
-      'residue-test': B.core.flags.hasAny([
-        B.struct.type.secondaryStructureFlags(['turn']),
-        B.ammp('secondaryStructureFlags')
+    turn: {
+      '@desc': 'secondary structure-related',
+      map: () => B.struct.generator.atomGroups({
+	'residue-test': B.core.flags.hasAny([
+          B.struct.type.secondaryStructureFlags(['turn']),
+          B.ammp('secondaryStructureFlags')
       ])
     })
   },
-  alpha: {
-    '@desc': '(*.CA)',
-    map: () => B.struct.generator.atomGroups({
-      'atom-test': B.core.rel.eq([
-        B.atomName('CA'),
-        B.ammp('label_atom_id')
+    alpha: {
+      '@desc': '(*.CA)',
+      map: () => B.struct.generator.atomGroups({
+	'atom-test': B.core.rel.eq([
+          B.atomName('CA'),
+          B.ammp('label_atom_id')
       ])
     })
   },
-  base: {
-    '@desc': '(nucleic bases)'
-  },
-  backbone: {
-    '@desc': '(*.C, *.CA, *.N, and all nucleic other than the bases themselves)',
-    abbr: ['mainchain']
+    base: {
+      '@desc': '(nucleic bases)'
   },
-  sidechain: {
-    '@desc': '((protein or nucleic) and not backbone)'
+    backbone: {
+      '@desc': '(*.C, *.CA, *.N, and all nucleic other than the bases themselves)',
+      abbr: ['mainchain'],
+      map: () => backboneExpr()
   },
-  spine: {
-    '@desc': '(*.CA, *.N, *.C for proteins; *.P, *.O3\', *.O5\', *.C3\', *.C4\', *.C5 for nucleic acids)'
-  },
-  leadatom: {
-    '@desc': '(*.CA, *.P, and terminal *.O5\')'
-  },
-  solvent: {
-    '@desc': 'PDB "HOH", water, also the connected set of H-O-H in any model'
+    sidechain: {
+	'@desc': '((protein or nucleic) and not backbone)'
   },
+    solvent: {
+	'@desc': 'PDB "HOH", water, also the connected set of H-O-H in any model',
+	    map: () => h.resnameExpr(ResDict.solvent)	
+    },
+};
+
+function backboneExpr() {
+    return B.struct.combinator.merge([
+        B.struct.generator.queryInSelection({
+            0: proteinExpr(),
+            query: B.struct.generator.atomGroups({
+                'atom-test': B.core.set.has([
+                    h.atomNameSet(Backbone.protein),
+                    B.ammp('label_atom_id')
+                ])
+            })
+        }),
+        B.struct.generator.queryInSelection({
+            0: nucleicExpr(),
+            query: B.struct.generator.atomGroups({
+                'atom-test': B.core.set.has([
+                    h.atomNameSet(Backbone.nucleic),
+                    B.ammp('label_atom_id')
+                ])
+            })
+        })
+    ]);
 }
 
+function proteinExpr() {
+    return B.struct.filter.pick({
+        0: B.struct.generator.atomGroups({
+            'group-by': B.ammp('residueKey')
+        }),
+        test: B.core.set.isSubset([
+            h.atomNameSet(['C', 'N', 'CA', 'O']),
+            B.ammpSet('label_atom_id')
+        ])
+    });
+}
 

+ 58 - 50
src/mol-script/transpilers/rasmol/parser.ts

@@ -120,24 +120,28 @@ const lang = P.MonadicParser.createLanguage({
   },
 
     Expression: function(r:any) {
-    return P.MonadicParser.alt(
-      r.Keywords,
-
-	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.AtomExpression.map(atomExpressionQuery),
-
-      r.ValueQuery,
-
-      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 ])
-      })),
-    )
-  },
+	return P.MonadicParser.alt(
+	    r.NamedAtomProperties,
+	    r.Keywords,
+	    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.AtomExpression.map(atomExpressionQuery),
+	    
+	    r.ValueQuery,
+	    
+	    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 ])
+	    })),
+	)
+    },
+
+    NamedAtomProperties: function () {
+        return P.MonadicParser.alt(...h.getNamedPropertyRules(properties)); 
+    },
 
 Operator: function(r:any) {
     return h.combineOperators(operators, P.MonadicParser.alt(r.Parens, r.Expression))
@@ -145,41 +149,45 @@ Operator: function(r:any) {
 
 AtomExpression: function(r:any) {
     return P.MonadicParser.seq(
-      P.MonadicParser.lookahead(r.AtomPrefix),
-      P.MonadicParser.seq(
-        r.Resno.or(P.MonadicParser.of(null)),
-        r.Inscode.or(P.MonadicParser.of(null)),
-        r.Chainname.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))
-      )
+	P.MonadicParser.lookahead(r.AtomPrefix),
+	P.MonadicParser.seq(
+            r.Resno.or(P.MonadicParser.of(null)),
+            r.Inscode.or(P.MonadicParser.of(null)),
+            r.Chainname.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'),
-  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'),
-  Altloc: () => P.MonadicParser.regexp(/%([a-zA-Z0-9])/, 1).desc('altloc'),
-  Inscode: () => P.MonadicParser.regexp(/\^([a-zA-Z0-9])/, 1).desc('inscode'),
-
-  // BracketedResname: function (r) {
-  //   return P.MonadicParser.regexp(/\.([a-zA-Z0-9]{1,4})/, 1)
-  //     .desc('bracketed-resname')
-  //   // [0SD]
-  // },
-
-  // ResnoRange: function (r) {
-  //   return P.MonadicParser.regexp(/\.([\s]){1,3}/, 1)
-  //     .desc('resno-range')
-  //   // 123-200
-  //   // -12--3
-  // },
+    AtomPrefix: () => P.MonadicParser.regexp(/[0-9:^%/.]/).desc('atom-prefix'),
+    Chainname: () => 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'),
+    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'),
+
+
+//    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]
+    },
+
+    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)),
 

+ 26 - 49
src/mol-script/transpilers/rasmol/properties.ts

@@ -23,10 +23,6 @@ const structureDict: {[key: string]: string} = {
   helix: 'helix',
   dna: 'dna',
   rna: 'rna',
-  carbohydrate: 'carbohydrate',
-  helix310: '3-10',
-  helixalpha: 'alpha',
-  helixpi: 'pi',
 
   0: 'none',
   1: 'turn',
@@ -50,44 +46,23 @@ export function structureMap(x: any) {
 }
 
 export const properties: PropertyDict = {
-  adpmax: {
-    '@desc': 'the maximum anisotropic displacement parameter for the selected atom',
-    '@examples': [''],
-    isUnsupported: true,
-    regex: reFloat, map: x => parseFloat(x),
-    level: 'atom-test'
-  },
-  adpmin: {
-    '@desc': 'the minimum anisotropic displacement parameter for the selected atom',
-    '@examples': [''],
-    isUnsupported: true,
-    regex: reFloat, map: x => parseFloat(x),
-    level: 'atom-test'
-  },
-  altloc: {
-    '@desc': 'PDB alternate location identifier',
-    '@examples': ['altloc = A'],
-    regex: /[a-zA-Z0-9]/, map: str,
-    level: 'atom-test', property: B.ammp('label_alt_id')
-  },
-  altname: {
-    '@desc': 'an alternative name given to atoms by some file readers (for example, P2N)',
-    '@examples': [''],
-    isUnsupported: true,
-    regex: /[a-zA-Z0-9]/, map: str,
-    level: 'atom-test'
-  },
-  atomID: {
-    '@desc': 'special atom IDs for PDB atoms assigned by Jmol',
-    '@examples': [''],
+    altloc: {
+	'@desc': 'PDB alternate location identifier',
+	'@examples': ['altloc = A'],
+	regex: /[a-zA-Z0-9]/, map: str,
+	level: 'atom-test', property: B.ammp('label_alt_id')
+    },    
+    atomID: {
+	'@desc': 'special atom IDs for PDB atoms assigned by Jmol',
+	'@examples': [''],
     isUnsupported: true,
     regex: rePosInt, map: x => parseInt(x),
     level: 'atom-test'
-  },
-  atomIndex: {
-    '@desc': 'atom 0-based index; a unique number for each atom regardless of the number of models loaded',
-    '@examples': [''],
-    isUnsupported: true,
+    },
+    atomIndex: {
+	'@desc': 'atom 0-based index; a unique number for each atom regardless of the number of models loaded',
+	'@examples': [''],
+	isUnsupported: true,
     regex: rePosInt, map: x => parseInt(x),
     level: 'atom-test'
   },
@@ -100,9 +75,9 @@ export const properties: PropertyDict = {
   atomno: {
     '@desc': 'sequential number; you can use "@" instead of "atomno=" -- for example, select @33 or Var x = @33 or @35',
     '@examples': [''],
-    isUnsupported: true,
+    isNumeric: true,
     regex: rePosInt, map: x => parseInt(x),
-    level: 'atom-test'
+    level: 'atom-test', property: B.ammp('id')
   },
   atomType: {
     '@desc': 'atom type (mol2, AMBER files) or atom name (other file types)',
@@ -205,10 +180,11 @@ export const properties: PropertyDict = {
     level: 'atom-test', property: B.acp('elementSymbol')
   },
   elemno: {
-    '@desc': 'atomic element number',
-    '@examples': ['elemno=8'],
-    regex: /[0-9\s{}-]+/, map: x => parseInt(x),
-    level: 'atom-test', property: B.acp('atomicNumber')
+      '@desc': 'atomic element number',
+      '@examples': ['elemno=8'],
+      isNumeric: true,
+      regex: /[0-9\s{}-]+/, map: x => parseInt(x),
+      level: 'atom-test', property: B.acp('atomicNumber')
   },
   eta: {
     '@desc': 'Based on Carlos M. Duarte, Leven M. Wadley, and Anna Marie Pyle, RNA structure comparison, motif search and discovery using a reduced representation of RNA conformational space, Nucleic Acids Research, 2003, Vol. 31, No. 16 4755-4761. The parameter eta is the C4\'[i-1]-P[i]-C4\'[i]-P[i+1] dihedral angle; theta is the P[i]-C4\'[i]-P[i+1]-C4\'[i+1] dihedral angle. Both are measured on a 0-360 degree scale because they are commonly near 180 degrees. Using the commands plot PROPERTIES eta theta resno; select visible;wireframe only one can create these authors\' "RNA worm" graph.',
@@ -464,10 +440,11 @@ export const properties: PropertyDict = {
     level: 'atom-test'
   },
   resno: {
-    '@desc': 'PDB residue number, not including insertion code (see also seqcode, below)',
-    '@examples': ['resno = 100'],
-    regex: /-?[0-9]+/, map: x => parseInt(x),
-    level: 'residue-test', property: B.ammp('auth_seq_id')
+      '@desc': 'PDB residue number, not including insertion code (see also seqcode, below)',
+      '@examples': ['resno = 100'],
+      isNumeric: true,
+      regex: /-?[0-9]+/, map: x => parseInt(x),
+      level: 'residue-test', property: B.ammp('auth_seq_id')
   },
   selected: {
     '@desc': '1.0 if atom is selected; 0.0 if not',