diff --git a/src/mol-script/transpilers/rasmol/parser.ts b/src/mol-script/transpilers/rasmol/parser.ts index 103dcd1fe7f9e8e25f1ed8339125a9e71d2d3099..bacd5fec962977e45df997460952299c7171a111 100644 --- a/src/mol-script/transpilers/rasmol/parser.ts +++ b/src/mol-script/transpilers/rasmol/parser.ts @@ -38,7 +38,26 @@ function atomSelectionQuery2(x: any) { for (const k in x) { const ps = macroproperties[k]; if (!ps) { - throw new Error(`property '${k}' not supported, value '${x[k]}'`); + const [resno, inscode, chainname, atomname, altloc] = x[1]; + const tests: AtomGroupArgs = {}; + + if (chainname) { + // should be configurable, there is an option in Jmol to use auth or label + tests['chain-test'] = B.core.rel.eq([B.ammp('auth_asym_id'), chainname]); + } + + const resProps = []; + if (resno) resProps.push(B.core.rel.eq([B.ammp('auth_seq_id'), resno])); + if (inscode) resProps.push(B.core.rel.eq([B.ammp('pdbx_PDB_ins_code'), inscode])); + if (resProps.length) tests['residue-test'] = h.andExpr(resProps); + + const atomProps = []; + if (atomname) atomProps.push(B.core.rel.eq([B.ammp('auth_atom_id'), atomname])); + if (altloc) atomProps.push(B.core.rel.eq([B.ammp('label_alt_id'), altloc])); + if (atomProps.length) tests['atom-test'] = h.andExpr(atomProps); + + return B.struct.generator.atomGroups(tests); +// throw new Error(`property '${k}' not supported, value '${x[k]}'`); } if (x[k] === null) continue; if (!props[ps.level]) props[ps.level] = []; @@ -52,8 +71,33 @@ function atomSelectionQuery2(x: any) { return B.struct.generator.atomGroups(tests); } +function atomExpressionQuery(x: any[]) { + const [resno, inscode, chainname, atomname, altloc] = x[1]; + const tests: AtomGroupArgs = {}; + + if (chainname) { + // should be configurable, there is an option in Jmol to use auth or label + tests['chain-test'] = B.core.rel.eq([B.ammp('auth_asym_id'), chainname]); + } + + const resProps = []; + if (resno) resProps.push(B.core.rel.eq([B.ammp('auth_seq_id'), resno])); + if (inscode) resProps.push(B.core.rel.eq([B.ammp('pdbx_PDB_ins_code'), inscode])); + if (resProps.length) tests['residue-test'] = h.andExpr(resProps); + + const atomProps = []; + if (atomname) atomProps.push(B.core.rel.eq([B.ammp('auth_atom_id'), atomname])); + if (altloc) atomProps.push(B.core.rel.eq([B.ammp('label_alt_id'), altloc])); + if (atomProps.length) tests['atom-test'] = h.andExpr(atomProps); + + return B.struct.generator.atomGroups(tests); +} + + const lang = P.MonadicParser.createLanguage({ + Integer: () => P.MonadicParser.regexp(/-?[0-9]+/).map(Number).desc('integer'), + Parens: function (r: any) { return P.MonadicParser.alt( r.Parens, @@ -68,6 +112,16 @@ const lang = P.MonadicParser.createLanguage({ r.Keywords, r.NamedAtomProperties, r.AtomSelectionMacro.map(atomSelectionQuery2), + 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.Element.map((x: string) => B.struct.generator.atomGroups({ + 'atom-test': B.core.rel.eq([B.acp('elementSymbol'), B.struct.type.elementSymbol(x)]) + })), + r.Resname.map((x: string) => B.struct.generator.atomGroups({ + 'residue-test': B.core.rel.eq([B.ammp('label_comp_id'), x]) + })), r.Object, r.Object2, ); @@ -213,6 +267,32 @@ const lang = P.MonadicParser.createLanguage({ return h.combineOperators(operators, P.MonadicParser.alt(r.Parens, r.Expression, r.Operator)); }, + 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)) + ) + ); + }, + + 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-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'), + + + Keywords: () => P.MonadicParser.alt(...h.getKeywordRules(keywords)),