|
@@ -34,7 +34,7 @@ const comma = P.MonadicParser.string(',');
|
|
|
const star = P.MonadicParser.string('*');
|
|
|
const bra = P.MonadicParser.string('(');
|
|
|
const ket = P.MonadicParser.string(')');
|
|
|
-const numbers = P.MonadicParser.regexp(/[0-9]/);
|
|
|
+
|
|
|
|
|
|
/* is Parser -> MonadicParser substitution correct? */
|
|
|
function orNull(rule: P.MonadicParser<any>) {
|
|
@@ -64,96 +64,6 @@ function atomSelectionQuery2(x: any) {
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
-// <, <=, =, >=, >, !=, and LIKE
|
|
|
-const valueOperators: OperatorList = [
|
|
|
- {
|
|
|
- '@desc': 'value comparisons',
|
|
|
- '@examples': [],
|
|
|
- name: '=',
|
|
|
- abbr: ['=='],
|
|
|
- type: h.binaryLeft,
|
|
|
- rule: P.MonadicParser.regexp(/\s*(LIKE|>=|<=|=|!=|>|<)\s*/i, 1),
|
|
|
- map: (op, e1, e2) => {
|
|
|
- // console.log(op, e1, e2)
|
|
|
- let expr;
|
|
|
- if (e1 === 'structure') {
|
|
|
- expr = B.core.flags.hasAny([B.ammp('secondaryStructureFlags'), structureMap(e2)]);
|
|
|
- } else if (e2 === 'structure') {
|
|
|
- expr = B.core.flags.hasAny([B.ammp('secondaryStructureFlags'), structureMap(e1)]);
|
|
|
- } else if (e1.head !== undefined) {
|
|
|
- if (e1.head.name === 'core.type.regex') {
|
|
|
- expr = B.core.str.match([e1, B.core.type.str([e2])]);
|
|
|
- }
|
|
|
- } else if (e2.head !== undefined) {
|
|
|
- if (e2.head.name === 'core.type.regex') {
|
|
|
- expr = B.core.str.match([e2, B.core.type.str([e1])]);
|
|
|
- }
|
|
|
- } else if (op.toUpperCase() === 'LIKE') {
|
|
|
- if (e1.head) {
|
|
|
- expr = B.core.str.match([
|
|
|
- B.core.type.regex([`^${e2}$`, 'i']),
|
|
|
- B.core.type.str([e1])
|
|
|
- ]);
|
|
|
- } else {
|
|
|
- expr = B.core.str.match([
|
|
|
- B.core.type.regex([`^${e1}$`, 'i']),
|
|
|
- B.core.type.str([e2])
|
|
|
- ]);
|
|
|
- }
|
|
|
- }
|
|
|
- if (!expr) {
|
|
|
- if (e1.head) e2 = h.wrapValue(e1, e2);
|
|
|
- if (e2.head) e1 = h.wrapValue(e2, e1);
|
|
|
- switch (op) {
|
|
|
- case '=':
|
|
|
- expr = B.core.rel.eq([e1, e2]);
|
|
|
- break;
|
|
|
- case '!=':
|
|
|
- expr = B.core.rel.neq([e1, e2]);
|
|
|
- break;
|
|
|
- case '>':
|
|
|
- expr = B.core.rel.gr([e1, e2]);
|
|
|
- break;
|
|
|
- case '<':
|
|
|
- expr = B.core.rel.lt([e1, e2]);
|
|
|
- break;
|
|
|
- case '>=':
|
|
|
- expr = B.core.rel.gre([e1, e2]);
|
|
|
- break;
|
|
|
- case '<=':
|
|
|
- expr = B.core.rel.lte([e1, e2]);
|
|
|
- break;
|
|
|
- default: throw new Error(`value operator '${op}' not supported`);
|
|
|
- }
|
|
|
- }
|
|
|
- return B.struct.generator.atomGroups({ 'atom-test': expr });
|
|
|
- }
|
|
|
- }
|
|
|
-];
|
|
|
-
|
|
|
-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'),
|
|
|
|
|
@@ -167,26 +77,10 @@ const lang = P.MonadicParser.createLanguage({
|
|
|
|
|
|
Expression: function (r: any) {
|
|
|
return P.MonadicParser.alt(
|
|
|
-// r.Keywords,
|
|
|
-// r.ValueQuery,
|
|
|
+ r.Keywords,
|
|
|
+ r.NamedAtomProperties,
|
|
|
r.AtomSelectionMacro.map(atomSelectionQuery2),
|
|
|
- r.AtomSelectionMacroResi.map(atomSelectionQuery2),
|
|
|
-// r.NamedAtomProperties,
|
|
|
-
|
|
|
-
|
|
|
- // 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.Atomno.lookahead(P.MonadicParser.regexp(/\s*(?!(LIKE|>=|<=|!=|[:^%/.=><]))/i)).map((x: any) => B.struct.generator.atomGroups({
|
|
|
- // 'atom-test': B.core.rel.eq([B.ammp('id'), x])
|
|
|
-// })),
|
|
|
-
|
|
|
-// 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
|
|
|
);
|
|
|
},
|
|
|
|
|
@@ -201,6 +95,7 @@ const lang = P.MonadicParser.createLanguage({
|
|
|
// :.cg -> name ca
|
|
|
AtomSelectionMacro: function (r: any) {
|
|
|
return P.MonadicParser.alt(
|
|
|
+ // :A.CA :.CA
|
|
|
colon.then(P.MonadicParser.alt(
|
|
|
P.MonadicParser.seq(
|
|
|
orNull(propertiesDict.chain).skip(dot),
|
|
@@ -210,6 +105,7 @@ const lang = P.MonadicParser.createLanguage({
|
|
|
orNull(propertiesDict.name).skip(dot)
|
|
|
).map(x => { return {name: x[0] }; }),
|
|
|
)),
|
|
|
+ // *A.CA *.CA
|
|
|
star.then(P.MonadicParser.alt(
|
|
|
P.MonadicParser.seq(
|
|
|
orNull(propertiesDict.chain).skip(dot),
|
|
@@ -219,13 +115,14 @@ const lang = P.MonadicParser.createLanguage({
|
|
|
orNull(propertiesDict.name).skip(dot)
|
|
|
).map(x => { return {name: x[0] }; }),
|
|
|
)),
|
|
|
- // 1-100 lys:a.ca lys:a lys lys.ca
|
|
|
+ // 1-100+201
|
|
|
bra.then(P.MonadicParser.alt(
|
|
|
P.MonadicParser.alt(
|
|
|
P.MonadicParser.seq(
|
|
|
orNull(propertiesDict.resi).skip(ket),
|
|
|
).map(x => { return { resi: x[0] };})
|
|
|
))),
|
|
|
+ // lys:a.ca lys:a lys lys.ca
|
|
|
P.MonadicParser.alt(
|
|
|
P.MonadicParser.alt(
|
|
|
P.MonadicParser.seq(
|
|
@@ -260,23 +157,20 @@ const lang = P.MonadicParser.createLanguage({
|
|
|
|
|
|
},
|
|
|
|
|
|
- AtomSelectionMacroResi: function (r: any) {
|
|
|
- return P.MonadicParser.alt(
|
|
|
- P.MonadicParser.alt(
|
|
|
- P.MonadicParser.seq(
|
|
|
- orNull(propertiesDict.resi)
|
|
|
- ).map(x => { return { resi: x[0] };}),
|
|
|
- ),
|
|
|
- );
|
|
|
- },
|
|
|
-
|
|
|
ObjectProperty: () => {
|
|
|
const w = h.getReservedWords(special_properties, special_keywords, special_operators)
|
|
|
.sort(h.strLenSortFn).map(h.escapeRegExp).join('|');
|
|
|
return P.MonadicParser.regexp(new RegExp(`(?!(${w}))[A-Z0-9_]+`, 'i'));
|
|
|
},
|
|
|
+
|
|
|
+ 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) => {
|
|
|
- return r.ObjectProperty.notFollowedBy(slash)
|
|
|
+ return r.ObjectProperty2
|
|
|
.map((x: any) => { throw new Error(`property 'object' not supported, value '${x}'`); });
|
|
|
},
|
|
|
|
|
@@ -331,60 +225,18 @@ const lang = P.MonadicParser.createLanguage({
|
|
|
});
|
|
|
},
|
|
|
|
|
|
- Operator: function (r: any) {
|
|
|
- return h.combineOperators(operators, P.MonadicParser.alt(r.Parens, r.Expression));
|
|
|
- },
|
|
|
-
|
|
|
- AtomExpression: function (r: any) {
|
|
|
- return P.MonadicParser.seq(
|
|
|
- P.MonadicParser.lookahead(r.AtomPrefix),
|
|
|
- P.MonadicParser.seq(
|
|
|
-// r.ResnoRange.or(P.MonadicParser.of(null)),
|
|
|
- r.Resno.or(P.MonadicParser.of(null)),
|
|
|
- r.Atomno.or(P.MonadicParser.of(null)),
|
|
|
-// r.Resno2.or(P.MonadicParser.of(null)),
|
|
|
- r.Inscode.or(P.MonadicParser.of(null)),
|
|
|
- r.Chainname.or(P.MonadicParser.of(null)),
|
|
|
-// r.Chainname2.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'),
|
|
|
-// Chainname2: () => 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'),
|
|
|
- Atomno: (r: any) => r.Integer.desc('atomno'),
|
|
|
-// 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'),
|
|
|
-
|
|
|
+// Operator: function (r: any) {
|
|
|
+// return h.combineOperators(operators, P.MonadicParser.alt(r.Parens, r.Expression));
|
|
|
+// },
|
|
|
|
|
|
- // 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]
|
|
|
+ Operator: function (r: any) {
|
|
|
+ return h.combineOperators(operators, P.MonadicParser.alt(r.Parens, r.Expression, r.Operator));
|
|
|
},
|
|
|
|
|
|
- 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)),
|
|
|
|
|
|
+
|
|
|
Query: function (r: any) {
|
|
|
return P.MonadicParser.alt(
|
|
|
r.Operator,
|
|
@@ -413,45 +265,7 @@ const lang = P.MonadicParser.createLanguage({
|
|
|
return P.MonadicParser.alt(r.Number, r.String);
|
|
|
},
|
|
|
|
|
|
- ValueParens: function (r: any) {
|
|
|
- return P.MonadicParser.alt(
|
|
|
- r.ValueParens,
|
|
|
- r.ValueOperator,
|
|
|
- r.ValueExpressions
|
|
|
- ).wrap(P.MonadicParser.string('('), P.MonadicParser.string(')'));
|
|
|
- },
|
|
|
-
|
|
|
- ValuePropertyNames: function () {
|
|
|
- return P.MonadicParser.alt(...h.getPropertyNameRules(properties, /LIKE|>=|<=|=|!=|>|<|\)|\s/i));
|
|
|
- },
|
|
|
-
|
|
|
- ValueOperator: function (r: any) {
|
|
|
- return h.combineOperators(valueOperators, P.MonadicParser.alt(r.ValueParens, r.ValueExpressions));
|
|
|
- },
|
|
|
|
|
|
- ValueExpressions: function (r: any) {
|
|
|
- return P.MonadicParser.alt(
|
|
|
- r.Value,
|
|
|
- r.ValuePropertyNames
|
|
|
- );
|
|
|
- },
|
|
|
-
|
|
|
- ValueQuery: function (r: any) {
|
|
|
- return P.MonadicParser.alt(
|
|
|
- r.ValueOperator.map((x: any) => {
|
|
|
- if (x.head.name) {
|
|
|
- if (x.head.name.startsWith('structure-query.generator')) return x;
|
|
|
- } else {
|
|
|
- if (typeof x === 'string' && x.length <= 4) {
|
|
|
- return B.struct.generator.atomGroups({
|
|
|
- 'residue-test': B.core.rel.eq([B.ammp('label_comp_id'), x])
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- throw new Error(`values must be part of an comparison, value '${x}'`);
|
|
|
- })
|
|
|
- );
|
|
|
- }
|
|
|
});
|
|
|
|
|
|
export const transpiler: Transpiler = str => lang.Query.tryParse(str);
|