diff --git a/src/mol-script/transpilers/_spec/jmol.spec.ts b/src/mol-script/transpilers/_spec/jmol.spec.ts index 62a134bb70cd06f38c25ea08847f9d46864fb077..4dabd8383b60bde3259d074116043e9e0d2f8795 100644 --- a/src/mol-script/transpilers/_spec/jmol.spec.ts +++ b/src/mol-script/transpilers/_spec/jmol.spec.ts @@ -81,6 +81,12 @@ const general = { '20', // within in the head or the middle of sentence 'within ( 5 , [HEM] ) and backbone', + + // atom expressions with ranges + '19-32:A', + '-2-32:B', + '-10--2:C', + '[1FO]19-32:A', ], unsupported: [ // values outside of comparisons diff --git a/src/mol-script/transpilers/jmol/parser.ts b/src/mol-script/transpilers/jmol/parser.ts index d20f41ec46509ac6ca30b6ce924e3e0314f767cc..8c9d0afc89b517b72f2c7260015b13d74bb95e65 100644 --- a/src/mol-script/transpilers/jmol/parser.ts +++ b/src/mol-script/transpilers/jmol/parser.ts @@ -86,7 +86,7 @@ const valueOperators: OperatorList = [ ]; function atomExpressionQuery(x: any[]) { - const [resname, resno, inscode, chainname, atomname, altloc] = x[1]; + const [resname, resnoRange, resno, inscode, chainname, atomname, altloc] = x[1]; const tests: AtomGroupArgs = {}; if (chainname) { @@ -96,6 +96,10 @@ function atomExpressionQuery(x: any[]) { const resProps = []; if (resname) resProps.push(B.core.rel.eq([B.ammp('label_comp_id'), resname])); + if (resnoRange) resProps.push(B.core.logic.and([ + B.core.rel.gre([B.ammp('auth_seq_id'), resnoRange[0]]), + B.core.rel.lte([B.ammp('auth_seq_id'), resnoRange[1]]) + ])); 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); @@ -123,15 +127,6 @@ const lang = P.MonadicParser.createLanguage({ return P.MonadicParser.alt( r.Keywords, - r.ResnoRange.map((x: [number, number]) => B.struct.generator.atomGroups({ - 'residue-test': B.core.logic.and([ - B.core.rel.gre([B.ammp('auth_seq_id'), x[0]]), - B.core.rel.lte([B.ammp('auth_seq_id'), x[1]]) - ]) - })), - r.Resno.lookahead(P.MonadicParser.regexp(/\s*(?!(LIKE|>=|<=|!=|[\[:^%/.=><]))/i)).map((x: number) => B.struct.generator.atomGroups({ - 'residue-test': B.core.rel.eq([B.ammp('auth_seq_id'), x]) - })), r.AtomExpression.map(atomExpressionQuery), r.Within.map((x: [number, Expression]) => B.struct.modifier.includeSurroundings({ 0: x[1], radius: x[0] })), @@ -155,6 +150,7 @@ const lang = P.MonadicParser.createLanguage({ P.MonadicParser.lookahead(r.AtomPrefix), P.MonadicParser.seq( r.BracketedResname.or(P.MonadicParser.of(null)), + r.ResnoRange.or(P.MonadicParser.of(null)), r.Resno.or(P.MonadicParser.of(null)), r.Inscode.or(P.MonadicParser.of(null)), r.Chainname.or(P.MonadicParser.of(null)), @@ -165,7 +161,7 @@ const lang = P.MonadicParser.createLanguage({ ).desc('expression'); }, - AtomPrefix: () => P.MonadicParser.regexp(/[\[0-9:^%/.]/).desc('atom-prefix'), + 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'),