Переглянути джерело

Added spec, debugged Jmol parser, removed unused definition from RasMol properties/operators

yakomaxa 2 роки тому
батько
коміт
300dd97353

+ 0 - 2
src/mol-model/structure/query/queries/atom-set.ts

@@ -28,8 +28,6 @@ export function countQuery(query: StructureQuery) {
     };
 }
 
-
-// export function propertySet(ctx: QueryContext, prop: UnitTypeProperties) {
 export function propertySet(prop: QueryFn<any>) {
     return (ctx: QueryContext) => {
         const set = new Set();

+ 0 - 29
src/mol-model/structure/query/queries/filters.ts

@@ -17,7 +17,6 @@ import { Structure } from '../../structure/structure';
 import { StructureElement } from '../../structure/element';
 import { SortedArray } from '../../../../mol-data/int';
 
-// export function pick(query: StructureQuery, pred: QueryPredicate): StructureQuery {
 export function pick(query: StructureQuery, pred: QueryFn<any>): StructureQuery {
     return ctx => {
         const sel = query(ctx);
@@ -52,34 +51,6 @@ export function first(query: StructureQuery): StructureQuery {
     };
 }
 
-// export interface UnitTypeProperties { atomic?: QueryFn, coarse?: QueryFn }
-/*
-export function getCurrentStructureProperties(ctx: QueryContext, props: UnitTypeProperties, set: Set<any>) {
-    const { units } = ctx.currentStructure;
-    const l = ctx.pushCurrentElement();
-
-    l.structure = ctx.currentStructure;
-    for (const unit of units) {
-        l.unit = unit;
-        const elements = unit.elements;
-
-        let fn;
-        if (Unit.isAtomic(unit)) fn = props.atomic;
-        else fn = props.coarse;
-        if (!fn) continue;
-
-        for (let j = 0, _j = elements.length; j < _j; j++) {
-            l.element = elements[j];
-            set.add(fn(ctx));
-        }
-
-        ctx.throwIfTimedOut();
-    }
-    ctx.popCurrentElement();
-    return set;
-}
-*/
-
 export function getCurrentStructureProperties(ctx: QueryContext, props: QueryFn<any>, set: Set<any>) {
     const { units } = ctx.currentStructure;
     const l = ctx.pushCurrentElement();

+ 26 - 0
src/mol-script/transpilers/_spec/examples.spec.ts

@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * @author Koya Sakuma <koya.sakuma.work@gmail.com>
+ * Adapted from MolQL project
+**/
+
+import { Transpiler } from '../transpiler';
+import { _transpiler as transpilers } from '../all';
+
+function testTranspilerExamples(name: string, transpiler: Transpiler) {
+    describe(`${name} examples`, () => {
+        const examples = require(`../${name}/examples`).default;
+        for (const e of examples) {
+	    console.log(e);
+            it(e.name, () => {
+                // check if it transpiles and compiles/typechecks.
+                transpiler(e.value);
+            });
+        }
+    });
+}
+
+testTranspilerExamples('pymol', transpilers.pymol);
+testTranspilerExamples('vmd', transpilers.vmd);
+testTranspilerExamples('jmol', transpilers.jmol);
+testTranspilerExamples('rasmol', transpilers.rasmol);

+ 76 - 0
src/mol-script/transpilers/_spec/jmol.spec.ts

@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Koya Sakuma <koya.sakuma.work@gmail.com>
+ * Adapted from MolQL project
+ */
+
+
+import * as u from './utils';
+import { transpiler } from '../jmol/parser';
+import { keywords } from '../jmol/keywords';
+import { properties } from '../jmol/properties';
+import { operators } from '../jmol/operators';
+
+const general = {
+    supported: [
+        // atom expressions
+        '123',
+        '-42',
+        '_C',
+        '.CA',
+        'ALA',
+        '%A',
+        '^B',
+        ':C',
+        '/2',
+        '10^A:F.CA%C/0',
+        '10^A:F.CA%C',
+        '10^A:F.CA',
+        '10^A:F',
+        '10^A',
+        '10:F.CA',
+        '10/0',
+        '32 or 42',
+        '.CA/0 OR 42:A',
+        '!23',
+        'not ASP',
+        '(ASP or .CA)',
+        'ASP and .CA',
+        '123.CA',
+        '(1 or 2) and .CA',
+        '(1 or 2) and (.CA or .N)',
+        '.CA and (2 or 3)',
+        '.CA and (2 or 3) and ^A',
+        '!32 or :A and .CA',
+
+        // trimming
+        '    atomName = CA   ',
+        'atomName = CA   ',
+        '    atomName = CA',
+    ],
+    unsupported: [
+        // values outside of comparisons
+        'foobar',
+        'protein or foobar',
+    ]
+};
+
+describe('jmol general', () => {
+    general.supported.forEach(str => {
+        it(str, () => {
+            transpiler(str);
+        });
+    });
+    general.unsupported.forEach(str => {
+        it(str, () => {
+            const transpileStr = () => transpiler(str);
+            expect(transpileStr).toThrow();
+            expect(transpileStr).not.toThrowError(RangeError);
+        });
+    });
+});
+
+describe('jmol keywords', () => u.testKeywords(keywords, transpiler));
+describe('jmol properties', () => u.testProperties(properties, transpiler));
+describe('jmol operators', () => u.testOperators(operators, transpiler));

+ 0 - 3
src/mol-script/transpilers/_spec/pymol.spec.ts

@@ -12,9 +12,6 @@ import { keywords } from '../pymol/keywords';
 import { properties } from '../pymol/properties';
 import { operators } from '../pymol/operators';
 
-/* FAULTY IMPORTS */
-// import compile from '../../reference-implementation/molql/compiler';
-
 const general = {
     supported: [
         // macros

+ 61 - 0
src/mol-script/transpilers/_spec/rasmol.spec.ts

@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Koya Sakuma <koya.sakuma.work@gmail.com>
+ */
+
+import * as u from './utils';
+import { transpiler } from '../rasmol/parser';
+import { keywords } from '../rasmol/keywords';
+import { properties } from '../rasmol/properties';
+import { operators } from '../rasmol/operators';
+
+const general = {
+    supported: [
+        // value comparison
+        'resno > 10',
+        // atom expression
+        '[LEU]100:A.CA',
+        '[LEU]100:A',
+        '[LEU]100:.CA',
+        '[LEU]:A.CA',
+        '[LEU].CA',
+        // 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]) ',
+    ],
+    unsupported: [
+        // un-braketed residue name
+        'LEU and ILE',
+        // un-parenthesized residue index
+        '100-120',
+        // un-parenthesized within in the head or middle of sentence
+    ]
+};
+
+describe('rasmol general', () => {
+    general.supported.forEach(str => {
+        it(str, () => {
+            transpiler(str);
+            // compile(expr);
+        });
+    });
+    general.unsupported.forEach(str => {
+        it(str, () => {
+            const transpileStr = () => transpiler(str);
+            expect(transpileStr).toThrow();
+            expect(transpileStr).not.toThrowError(RangeError);
+        });
+    });
+});
+
+describe('rasmol keywords', () => u.testKeywords(keywords, transpiler));
+describe('rasmol operators', () => u.testOperators(operators, transpiler));
+describe('rasmol properties', () => u.testProperties(properties, transpiler));

+ 0 - 3
src/mol-script/transpilers/_spec/utils.ts

@@ -9,9 +9,6 @@
 import { Transpiler } from '../transpiler';
 import { KeywordDict, PropertyDict, OperatorList } from '../types';
 
-/* FAULTY IMPORTS */
-// import compile from '../../reference-implementation/molql/compiler';
-
 export function testKeywords(keywords: KeywordDict, transpiler: Transpiler) {
     for (const name in keywords) {
         it(name, () => {

+ 0 - 3
src/mol-script/transpilers/_spec/vmd.spec.ts

@@ -12,9 +12,6 @@ import { keywords } from '../vmd/keywords';
 import { properties } from '../vmd/properties';
 import { operators } from '../vmd/operators';
 
-/* FAULTY IMPORTS */
-// import compile from '../../reference-implementation/molql/compiler';
-
 const general = {
     supported: [
         // trimming

+ 2 - 2
src/mol-script/transpilers/helper.ts

@@ -58,7 +58,7 @@ export function postfix(opParser: P.MonadicParser<any>, nextParser: P.MonadicPar
     // INPUT  :: "4!!!"
     // PARSE  :: [4, "factorial", "factorial", "factorial"]
     // REDUCE :: ["factorial", ["factorial", ["factorial", 4]]]
-    return P.MonadicParser.seqMap(/* no seqMap() in monadic-parser.ts, any suitable replacement? */
+    return P.MonadicParser.seqMap(
         nextParser,
         opParser.many(),
         (x: any, suffixes: any) =>
@@ -80,7 +80,7 @@ export function binaryRight(opParser: P.MonadicParser<any>, nextParser: P.Monadi
                 P.MonadicParser.of(next),
                 parser
             ).map((x) => {
-                console.log(x);
+                //                console.log(x);
                 return x;
             }).or(P.MonadicParser.of(next))
         )

+ 1 - 2
src/mol-script/transpilers/jmol/parser.ts

@@ -31,7 +31,6 @@ const valueOperators: OperatorList = [
         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)]);
@@ -239,7 +238,7 @@ const lang = P.MonadicParser.createLanguage({
     ValueQuery: function (r: any) {
         return P.MonadicParser.alt(
             r.ValueOperator.map((x: any) => {
-                if (x.head.name) {
+                if (x.head) {
                     if (x.head.name.startsWith('structure-query.generator')) return x;
                 } else {
                     if (typeof x === 'string' && x.length <= 4) {

+ 8 - 6
src/mol-script/transpilers/jmol/properties.ts

@@ -37,12 +37,14 @@ const structureDict: {[key: string]: string} = {
     9: 'pi',
 };
 export function structureMap(x: any) {
-    if (x.head && x.head === 'core.type.regex') x = x.args[0].replace(/^\^|\$$/g, '');
-    x = structureDict[x.toString().toLowerCase()] || 'none';
-    if (['dna', 'rna', 'carbohydrate'].indexOf(x) !== -1) {
-        throw new Error("values 'dna', 'rna', 'carbohydrate' not yet supported for 'structure' property");
-    } else {
-        return B.struct.type.secondaryStructureFlags([x]);
+    if (x.head) {
+        if (x.head.name && x.head.name === 'core.type.regex') x = x.args[0].replace(/^\^|\$$/g, '');
+        x = structureDict[x.toString().toLowerCase()] || 'none';
+        if (['dna', 'rna', 'carbohydrate'].indexOf(x) !== -1) {
+            throw new Error("values 'dna', 'rna', 'carbohydrate' not yet supported for 'structure' property");
+        } else {
+            return B.struct.type.secondaryStructureFlags([x]);
+        }
     }
 }
 

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

@@ -22,7 +22,6 @@ const propertiesDict = h.getPropertyRules(properties);
 
 const slash = P.MonadicParser.string('/');
 
-/* is Parser -> MonadicParser substitution correct? */
 function orNull(rule: P.MonadicParser<any>) {
     return rule.or(P.MonadicParser.of(null));
 }

+ 21 - 9
src/mol-script/transpilers/rasmol/examples.ts

@@ -8,19 +8,31 @@
 
 export const rasmolSelectionsExamples = [{
     name: 'Residue 50 or 135',
-    value: '50 or 135'
+    value: '(50) or (135)'
 }, {
-    name: 'Atoms with no covalent bonds',
-    value: 'bondcount = 0'
+    name: 'Residue 50 or 135',
+    value: '(50,135)'
+}, {
+    name: 'Residue 20-22 or 8 or 2-16',
+    value: '(20-22,8,2-16)'
+}, {
+    name: 'Residue with the index more than 10',
+    value: 'resno > 10'
+}, {
+    name: 'Atoms assinged as backbone of protein or nucleic acid',
+    value: 'backbone'
+}, {
+    name: 'ALA, LEU, or aromatic residue within 10 angstrom from HEM ',
+    value: '( [ALA] or [LEU] or aromatic ) and within( 10.0 ,[HEM])'
 }, {
-    name: 'All 3-10 helices',
-    value: 'substructure = "helix310"'
+    name: 'Residue within 10 angstrom from HEM but not HEM',
+    value: 'not [HEM] and within(5, [HEM])'
 }, {
-    name: 'Metal atoms',
-    value: 'metal'
+    name: 'Residue within 10 angstrom from HEM but not HEM',
+    value: '( within(5, [HEM]) ) and not [HEM]'
 }, {
-    name: 'Atoms invloved in aromatic bonds',
-    value: 'isAromatic'
+    name: 'C-beta atom ALA10 in chain A or all C-alpha atoms or all CG atoms from LYS',
+    value: '[ALA]10:A.CB or :.CA or [LYS].CG'
 }, {
     name: 'Pyrimidine residues',
     value: 'pyrimidine'

+ 0 - 1
src/mol-script/transpilers/rasmol/macroproperties.ts

@@ -20,7 +20,6 @@ function rangeMap(x: string) {
 function listOrRangeMap(x: string) {
     if (x.includes('-') && x.includes(',')) {
         const pSplit = x.split(',').map(x => x.replace(/^["']|["']$/g, ''));
-        console.log(pSplit);
         const res: number[] = [];
         pSplit.forEach(x => {
 	    if (x.includes('-')) {

+ 4 - 60
src/mol-script/transpilers/rasmol/operators.ts

@@ -11,16 +11,11 @@ import { MolScriptBuilder } from '../../../mol-script/language/builder';
 const B = MolScriptBuilder;
 import { OperatorList } from '../types';
 import { Expression } from '../../language/expression';
-import { macroproperties } from './macroproperties';
-
-const propNames = Object.keys(macroproperties).sort(h.strLenSortFn)
-    .filter(name => !macroproperties[name].isUnsupported).join('|');
-
 
 export const operators: OperatorList = [
     {
         '@desc': 'Selects atoms that are not included in s1.',
-        '@examples': ['not ARG'],
+        '@examples': ['not [ARG]'],
         name: 'not',
         type: h.prefix,
         rule: P.MonadicParser.alt(P.MonadicParser.regex(/NOT/i).skip(P.MonadicParser.whitespace), P.MonadicParser.string('!').skip(P.MonadicParser.optWhitespace)),
@@ -28,47 +23,28 @@ export const operators: OperatorList = [
     },
     {
         '@desc': 'Selects atoms included in both s1 and s2.',
-        '@examples': ['ASP and .CA'],
+        '@examples': ['[ASP] and :.CA'],
         name: 'and',
         type: h.binaryLeft,
         rule: P.MonadicParser.alt(h.infixOp(/AND|&/i)),
-        // rule: h.infixOp(/AND|&/i),
         map: (op, selection, by) => B.struct.modifier.intersectBy({ 0: selection, by })
     },
     {
         '@desc': 'Selects atoms included in either s1 or s2.',
-        '@examples': ['ASP or GLU'],
+        '@examples': ['[ASP] or [GLU]'],
         name: 'or',
         abbr: [','],
         type: h.binaryLeft,
         rule: P.MonadicParser.alt(h.infixOp(/OR|\||\|\||,/i)),
-        //        rule: h.infixOp(/OR|\||\|\|/i),
         map: (op, s1, s2) => B.struct.combinator.merge([s1, s2])
     },
-    /*
-    {
-        '@desc': 'Selects atoms within a specified distance of a selection',
-        '@examples': ['within (5.0, LYS:A.CA)'],
-        name: 'aaa',
-        type: h.prefixRemoveKet,
-        rule: h.prefixOpNoWhiteSpace(/within\s*\(\s*([-+]?[0-9]*\.?[0-9]+)\s*,/, 1).map((x: any) => {
-            console.log(x)
-	    return parseFloat(x)}),
-	map: (radius: number, selection: Expression) => {
-
-            return B.struct.modifier.includeSurroundings({ 0: selection, radius });
-        }
-    },
-  */
     {
         '@desc': 'Selects atoms in s1 that are within X Angstroms of any atom in s2.',
-        '@examples': ['chain A WITHIN 3 OF chain B'],
+        '@examples': ['within(5.0, [HEM])'],
         name: 'within',
         abbr: ['w2.'],
-        //   type: h.binaryLeft,
         type: h.prefixRemoveKet,
         rule: h.prefixOpNoWhiteSpace(/within\s*\(\s*([-+]?[0-9]*\.?[0-9]+)\s*,/i, 1).map((x: any) => {
-	    console.log(x);
 	    return parseFloat(x);
         }),
         map: (radius: number, target: Expression) => {
@@ -79,37 +55,5 @@ export const operators: OperatorList = [
 	    });
         },
     },
-    {
-        '@desc': 'Selects atoms which have the same keyword as the atoms in a given selection',
-        '@examples': ['same resid as name FE'],
-        name: 'same',
-        type: h.prefix,
-        rule: h.prefixOp(new RegExp(`SAME\\s+(${propNames})\\s+AS`, 'i'), 1).map((x: any) => macroproperties[x].property),
-        map: (property: Expression, source: Expression) => {
-            return B.struct.filter.withSameAtomProperties({
-                '0': B.struct.generator.all(),
-                source,
-                property
-            });
-        }
-    },
-    {
-        '@desc':
-            'Selects atoms in s1 whose identifiers name and resi match atoms in s2.',
-        '@examples': ['chain A LIKE chain B'],
-        name: 'like',
-        type: h.binaryLeft,
-        rule: h.infixOp(/LIKE|l\./i),
-        map: (op: string, selection: Expression, source: Expression) => {
-            return B.struct.filter.withSameAtomProperties({
-                0: selection,
-                source,
-                property: B.core.type.compositeKey([
-                    B.ammp('label_atom_id'),
-                    B.ammp('label_seq_id'),
-                ]),
-            });
-        },
-    },
 ];
 

+ 0 - 14
src/mol-script/transpilers/rasmol/parser.ts

@@ -35,8 +35,6 @@ const ket = P.MonadicParser.string(')');
 const commu = P.MonadicParser.string('[');
 const tator = P.MonadicParser.string(']');
 
-
-/* is Parser -> MonadicParser substitution correct? */
 function orNull(rule: P.MonadicParser<any>) {
     return rule.or(P.MonadicParser.of(null));
 }
@@ -78,18 +76,11 @@ const lang = P.MonadicParser.createLanguage({
 	    r.Keywords,
 	    r.NamedAtomProperties,
 	    r.AtomSelectionMacro.map(atomSelectionQuery2),
-            //	    r.AtomExparession.map(atomExpressionQuery),
 	    r.Object,
 	    r.Object2,
         );
     },
 
-    //    AtomExpression: function (r: any) {
-    //	return P.MonadicParser.seq(r.Resname.or(P.MonadicParser.of(null)));
-    //    },
-
-
-
     //    lys:a.ca  -> resn lys and chain A and name ca
     //    lys*a.ca  -> resn lys and chain A and name ca
     //
@@ -222,11 +213,6 @@ const lang = P.MonadicParser.createLanguage({
             .map((x: any) => { throw new Error(`property 'object' not supported, value '${x}'`); });
     },
 
-
-
-    //    Resname: () => P.MonadicParser.regexp(s/[a-zA-Z0-9]{1,4}/).desc('resname'),
-    //    Resname: () => P.MonadicParser.regexp(/\[[A-Z0-9]{1,4}\]/).desc('resname'),
-
     NamedAtomProperties: function () {
         return P.MonadicParser.alt(...h.getNamedPropertyRules(properties));
     },

Різницю між файлами не показано, бо вона завелика
+ 1 - 423
src/mol-script/transpilers/rasmol/properties.ts


+ 0 - 7
src/mol-script/transpilers/vmd/parser.ts

@@ -17,8 +17,6 @@ import { functions } from './functions';
 import { OperatorList } from '../types';
 import { Transpiler } from '../transpiler';
 
-// const propertiesDict = h.getPropertyRules(properties)
-
 // <, <=, = or ==, >=, >, and !=
 // lt, le, eq, ge, gt, and ne, =~
 const valueOperators: OperatorList = [
@@ -57,8 +55,6 @@ const valueOperators: OperatorList = [
         type: h.binaryLeft,
         rule: P.MonadicParser.alt(P.MonadicParser.regexp(/\s*(=~|==|>=|<=|=|!=|>|<)\s*/, 1), P.MonadicParser.whitespace.result('=')),
         map: (op, e1, e2) => {
-            //	    console.log(e1.head !== undefined && e2.head !==undefined)
-            console.log(op, e1, e2);
             let expr;
 	    if (e1.head !== undefined) {
                 if (e1.head.name === 'structure-query.atom-property.macromolecular.secondary-structure-flags') {
@@ -184,9 +180,6 @@ const lang = P.MonadicParser.createLanguage({
             }
 
 	    return B.struct.generator.atomGroups({ [h.testLevel(property)]: test });
-	    //  h.testLevel is not working for unknown reason, so relaced it by hardcoded 'atom-test'
-            //	    console.log(h.testLevel(property));
-	    // return B.struct.generator.atomGroups({ 'atom-test': test });
         });
     },
 

Деякі файли не було показано, через те що забагато файлів було змінено