Skip to content
Snippets Groups Projects
Commit 32080ce9 authored by Alexander Rose's avatar Alexander Rose
Browse files

improve jmol transpiler

- add resno ranges
- add bracketed resnames
- allow comma as OR
parent e2baafc4
No related branches found
No related tags found
No related merge requests found
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
* Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
* *
* @author Koya Sakuma <koya.sakuma.work@gmail.com> * @author Koya Sakuma <koya.sakuma.work@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*
* Adapted from MolQL project * Adapted from MolQL project
*/ */
import * as u from './utils'; import * as u from './utils';
import { transpiler } from '../jmol/parser'; import { transpiler } from '../jmol/parser';
import { keywords } from '../jmol/keywords'; import { keywords } from '../jmol/keywords';
...@@ -48,6 +49,35 @@ const general = { ...@@ -48,6 +49,35 @@ const general = {
' atomName = CA ', ' atomName = CA ',
'atomName = CA ', 'atomName = CA ',
' atomName = CA', ' atomName = CA',
// value comparison
'resno > 10',
// atom expression
'[LEU]100:A.CA',
'[LEU]100:A',
'[LEU]100.CA',
'[LEU]:A.CA',
'[LEU].CA',
// comma as OR
'100, 42, ALA',
// residue numbering
'(1-10,15,21-30)',
// within with parentheses
// '( within(5,[HEM]) ) and backbone',
// trimming
'[ALA] and [VAL] ',
' [ALA] and [VAL] ',
' [ALA] and [VAL]',
// within with whitespaces
// 'within ( 5 , [HEM] ) ',
// un-braketed residue name
'LEU and ILE',
// un-parenthesized residue index range
'100-120,220',
// un-parenthesized residue index
'20',
// within in the head or the middle of sentence
// 'within ( 5 , [HEM] ) and backbone',
], ],
unsupported: [ unsupported: [
// values outside of comparisons // values outside of comparisons
......
...@@ -129,11 +129,11 @@ export function combineOperators(opList: any[], rule: P.MonadicParser<any>) { ...@@ -129,11 +129,11 @@ export function combineOperators(opList: any[], rule: P.MonadicParser<any>) {
} }
export function infixOp(re: RegExp, group: number = 0) { export function infixOp(re: RegExp, group: number = 0) {
return P.MonadicParser.whitespace.then(P.MonadicParser.regexp(re, group).skip(P.MonadicParser.whitespace)); return P.MonadicParser.optWhitespace.then(P.MonadicParser.regexp(re, group).skip(P.MonadicParser.optWhitespace));
} }
export function prefixOp(re: RegExp, group: number = 0) { export function prefixOp(re: RegExp, group: number = 0) {
return P.MonadicParser.regexp(re, group).skip(P.MonadicParser.whitespace); return P.MonadicParser.regexp(re, group).skip(P.MonadicParser.optWhitespace);
} }
export function prefixOpNoWhiteSpace(re: RegExp, group: number = 0) { export function prefixOpNoWhiteSpace(re: RegExp, group: number = 0) {
...@@ -141,7 +141,7 @@ export function prefixOpNoWhiteSpace(re: RegExp, group: number = 0) { ...@@ -141,7 +141,7 @@ export function prefixOpNoWhiteSpace(re: RegExp, group: number = 0) {
} }
export function postfixOp(re: RegExp, group: number = 0) { export function postfixOp(re: RegExp, group: number = 0) {
return P.MonadicParser.whitespace.then(P.MonadicParser.regexp(re, group)); return P.MonadicParser.optWhitespace.then(P.MonadicParser.regexp(re, group));
} }
export function ofOp(name: string, short?: string) { export function ofOp(name: string, short?: string) {
......
/* /**
* Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Koya Sakuma <koya.sakuma.work@gmail.com> * @author Koya Sakuma <koya.sakuma.work@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*
* Adapted from MolQL project * Adapted from MolQL project
*/ */
import * as P from '../../../mol-util/monadic-parser'; import * as P from '../../../mol-util/monadic-parser';
import * as h from '../helper'; import * as h from '../helper';
import { MolScriptBuilder } from '../../../mol-script/language/builder'; import { MolScriptBuilder } from '../../../mol-script/language/builder';
const B = MolScriptBuilder; const B = MolScriptBuilder;
import { OperatorList } from '../types'; import { OperatorList } from '../types';
export const operators: OperatorList = [ export const operators: OperatorList = [
{ {
'@desc': 'Selects atoms that are not included in s1.', '@desc': 'Selects atoms that are not included in s1.',
...@@ -34,7 +35,7 @@ export const operators: OperatorList = [ ...@@ -34,7 +35,7 @@ export const operators: OperatorList = [
'@examples': ['ASP or GLU'], '@examples': ['ASP or GLU'],
name: 'or', name: 'or',
type: h.binaryLeft, type: h.binaryLeft,
rule: h.infixOp(/OR|\|/i), rule: h.infixOp(/OR|\||,/i),
map: (op, s1, s2) => B.struct.combinator.merge([s1, s2]) map: (op, s1, s2) => B.struct.combinator.merge([s1, s2])
} }
]; ];
......
/** /**
* Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Koya Sakuma < koya.sakuma.work@gmail.com> * @author Koya Sakuma < koya.sakuma.work@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*
* Adapted from MolQL project * Adapted from MolQL project
**/ **/
...@@ -83,15 +86,16 @@ const valueOperators: OperatorList = [ ...@@ -83,15 +86,16 @@ const valueOperators: OperatorList = [
]; ];
function atomExpressionQuery(x: any[]) { function atomExpressionQuery(x: any[]) {
const [resno, inscode, chainname, atomname, altloc] = x[1]; const [resname, resno, inscode, chainname, atomname, altloc] = x[1];
const tests: AtomGroupArgs = {}; const tests: AtomGroupArgs = {};
if (chainname) { if (chainname) {
// should be configurable, there is an option in Jmol to use auth or label // TODO: 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]); tests['chain-test'] = B.core.rel.eq([B.ammp('auth_asym_id'), chainname]);
} }
const resProps = []; const resProps = [];
if (resname) resProps.push(B.core.rel.eq([B.ammp('label_comp_id'), resname]));
if (resno) resProps.push(B.core.rel.eq([B.ammp('auth_seq_id'), resno])); 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 (inscode) resProps.push(B.core.rel.eq([B.ammp('pdbx_PDB_ins_code'), inscode]));
if (resProps.length) tests['residue-test'] = h.andExpr(resProps); if (resProps.length) tests['residue-test'] = h.andExpr(resProps);
...@@ -119,7 +123,13 @@ const lang = P.MonadicParser.createLanguage({ ...@@ -119,7 +123,13 @@ const lang = P.MonadicParser.createLanguage({
return P.MonadicParser.alt( return P.MonadicParser.alt(
r.Keywords, r.Keywords,
r.Resno.lookahead(P.MonadicParser.regexp(/\s*(?!(LIKE|>=|<=|!=|[:^%/.=><]))/i)).map((x: any) => B.struct.generator.atomGroups({ 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: any) => B.struct.generator.atomGroups({
'residue-test': B.core.rel.eq([B.ammp('auth_seq_id'), x]) 'residue-test': B.core.rel.eq([B.ammp('auth_seq_id'), x])
})), })),
r.AtomExpression.map(atomExpressionQuery), r.AtomExpression.map(atomExpressionQuery),
...@@ -143,6 +153,7 @@ const lang = P.MonadicParser.createLanguage({ ...@@ -143,6 +153,7 @@ const lang = P.MonadicParser.createLanguage({
return P.MonadicParser.seq( return P.MonadicParser.seq(
P.MonadicParser.lookahead(r.AtomPrefix), P.MonadicParser.lookahead(r.AtomPrefix),
P.MonadicParser.seq( P.MonadicParser.seq(
r.BracketedResname.or(P.MonadicParser.of(null)),
r.Resno.or(P.MonadicParser.of(null)), r.Resno.or(P.MonadicParser.of(null)),
r.Inscode.or(P.MonadicParser.of(null)), r.Inscode.or(P.MonadicParser.of(null)),
r.Chainname.or(P.MonadicParser.of(null)), r.Chainname.or(P.MonadicParser.of(null)),
...@@ -150,10 +161,10 @@ const lang = P.MonadicParser.createLanguage({ ...@@ -150,10 +161,10 @@ const lang = P.MonadicParser.createLanguage({
r.Altloc.or(P.MonadicParser.of(null)), r.Altloc.or(P.MonadicParser.of(null)),
r.Model.or(P.MonadicParser.of(null)) r.Model.or(P.MonadicParser.of(null))
) )
); ).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'), Chainname: () => P.MonadicParser.regexp(/:([A-Za-z]{1,3})/, 1).desc('chainname'),
Model: () => P.MonadicParser.regexp(/\/([0-9]+)/, 1).map(Number).desc('model'), Model: () => P.MonadicParser.regexp(/\/([0-9]+)/, 1).map(Number).desc('model'),
...@@ -164,22 +175,19 @@ const lang = P.MonadicParser.createLanguage({ ...@@ -164,22 +175,19 @@ const lang = P.MonadicParser.createLanguage({
Altloc: () => P.MonadicParser.regexp(/%([a-zA-Z0-9])/, 1).desc('altloc'), Altloc: () => P.MonadicParser.regexp(/%([a-zA-Z0-9])/, 1).desc('altloc'),
Inscode: () => P.MonadicParser.regexp(/\^([a-zA-Z0-9])/, 1).desc('inscode'), Inscode: () => P.MonadicParser.regexp(/\^([a-zA-Z0-9])/, 1).desc('inscode'),
BracketedResname: () => P.MonadicParser.regexp(/\[([a-zA-Z0-9]{1,4})\]/, 1).desc('bracketed-resname'),
ResnoRange: (r: any) => {
return P.MonadicParser.seq(
r.Integer.skip(P.MonadicParser.seq(
P.MonadicParser.optWhitespace,
P.MonadicParser.string('-'),
P.MonadicParser.optWhitespace
)),
r.Integer
).desc('resno-range');
},
// TODO: Support bracketed resname and resno range. Keywords: () => P.MonadicParser.alt(...h.getKeywordRules(keywords)).desc('keyword'),
// BracketedResname: function (r) {
// return P.regex(/\.([a-zA-Z0-9]{1,4})/, 1)
// .desc('bracketed-resname')
// // [0SD]
// },
// ResnoRange: function (r) {
// return P.regex(/\.([\s]){1,3}/, 1)
// .desc('resno-range')
// // 123-200
// // -12--3
// },
Keywords: () => P.MonadicParser.alt(...h.getKeywordRules(keywords)),
Query: function (r: any) { Query: function (r: any) {
return P.MonadicParser.alt( return P.MonadicParser.alt(
...@@ -202,7 +210,7 @@ const lang = P.MonadicParser.createLanguage({ ...@@ -202,7 +210,7 @@ const lang = P.MonadicParser.createLanguage({
P.MonadicParser.regexp(new RegExp(`(?!(${w}))[A-Z0-9_]+`, 'i')), P.MonadicParser.regexp(new RegExp(`(?!(${w}))[A-Z0-9_]+`, 'i')),
P.MonadicParser.regexp(/'((?:[^"\\]|\\.)*)'/, 1), P.MonadicParser.regexp(/'((?:[^"\\]|\\.)*)'/, 1),
P.MonadicParser.regexp(/"((?:[^"\\]|\\.)*)"/, 1).map(x => B.core.type.regex([`^${x}$`, 'i'])) P.MonadicParser.regexp(/"((?:[^"\\]|\\.)*)"/, 1).map(x => B.core.type.regex([`^${x}$`, 'i']))
); ).desc('string');
}, },
Value: function (r: any) { Value: function (r: any) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment