Skip to content

Commit

Permalink
Correct parsing and building of reaction SMARTS queries. Relatively s…
Browse files Browse the repository at this point in the history
…imple adaption to existing parser.
  • Loading branch information
johnmay committed Jun 3, 2016
1 parent cf70611 commit f924784
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2016 John May <jwmay@users.sf.net>
*
* Contact: cdk-devel@lists.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version. All we ask is that proper credit is given
* for our work, which includes - but is not limited to - adding the above
* copyright notice to the beginning of your source code files, and to any
* copyright notice that you may distribute with programs based on this work.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 U
*/
package org.openscience.cdk.isomorphism.matchers.smarts;

import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IChemObjectBuilder;

/**
* Matches atoms with a particular role in a reaction.
*/
public class ReactionRole extends SMARTSAtom {

public static final int ROLE_REACTANT = 0x1;
public static final int ROLE_AGENT = 0x2;
public static final int ROLE_PRODUCT = 0x4;
public static final int ROLE_ANY = ROLE_REACTANT | ROLE_PRODUCT | ROLE_AGENT;

private final int role;

public final static ReactionRole RoleReactant = new ReactionRole(null, ROLE_REACTANT);
public final static ReactionRole RoleAgent = new ReactionRole(null, ROLE_AGENT);
public final static ReactionRole RoleProduct = new ReactionRole(null, ROLE_PRODUCT);

public ReactionRole(IChemObjectBuilder builder, int role) {
super(builder);
this.role = role;
}

@Override
public boolean matches(IAtom atom) {
return true; // TODO
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if ((role & ROLE_REACTANT) != 0)
sb.append("Reactant");
if ((role & ROLE_AGENT) != 0)
sb.append("Agent");
if ((role & ROLE_PRODUCT) != 0)
sb.append("Product");
return "ReactionRole(" + sb.toString() + ")";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/
package org.openscience.cdk.smiles.smarts.parser;

import org.openscience.cdk.isomorphism.matchers.smarts.ReactionRole;

/**
* An AST node. It represents the group notation (.) of smarts.
*
Expand All @@ -28,6 +30,13 @@
*/
class ASTGroup extends SimpleNode {

static final int ROLE_REACTANT = ReactionRole.ROLE_REACTANT;
static final int ROLE_AGENT = ReactionRole.ROLE_AGENT;
static final int ROLE_PRODUCT = ReactionRole.ROLE_PRODUCT;
static final int ROLE_ANY = ReactionRole.ROLE_ANY;

private int role = ROLE_ANY;

/**
* Creates a new instance
*
Expand All @@ -47,6 +56,14 @@ public ASTGroup(SMARTSParser p, int id) {
super(p, id);
}

public void setRole(int role) {
this.role = role;
}

public int getRole() {
return this.role;
}

/*
* (non-Javadoc)
* @see
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.openscience.cdk.isomorphism.matchers.smarts.NonCHHeavyAtom;
import org.openscience.cdk.isomorphism.matchers.smarts.OrderQueryBond;
import org.openscience.cdk.isomorphism.matchers.smarts.PeriodicGroupNumberAtom;
import org.openscience.cdk.isomorphism.matchers.smarts.ReactionRole;
import org.openscience.cdk.isomorphism.matchers.smarts.RecursiveSmartsAtom;
import org.openscience.cdk.isomorphism.matchers.smarts.RingBond;
import org.openscience.cdk.isomorphism.matchers.smarts.RingIdentifierAtom;
Expand Down Expand Up @@ -211,13 +212,48 @@ public Object visit(ASTStart node, Object data) {
return node.jjtGetChild(0).jjtAccept(this, data);
}

// TODO: No QueryReaction API
public Object visit(ASTReaction node, Object data) {
return node.jjtGetChild(0).jjtAccept(this, data);
IAtomContainer query = new QueryAtomContainer(builder);
for (int grpIdx = 0; grpIdx < node.jjtGetNumChildren(); grpIdx++) {

int rollback = query.getAtomCount();

ASTGroup group = (ASTGroup) node.jjtGetChild(grpIdx);
group.jjtAccept(this, query);

// fill in the roles for newly create atoms
if (group.getRole() != ASTGroup.ROLE_ANY) {
IQueryAtom roleQueryAtom = null;

// use single instances
switch (group.getRole()) {
case ASTGroup.ROLE_REACTANT:
roleQueryAtom = ReactionRole.RoleReactant;
break;
case ASTGroup.ROLE_AGENT:
roleQueryAtom = ReactionRole.RoleAgent;
break;
case ASTGroup.ROLE_PRODUCT:
roleQueryAtom = ReactionRole.RoleProduct;
break;
}

if (roleQueryAtom != null) {
while (rollback < query.getAtomCount()) {
query.setAtom(rollback, LogicalOperatorAtom.and(roleQueryAtom, (IQueryAtom) query.getAtom(rollback)));
rollback++;
}
}
}
}
return query;
}

public Object visit(ASTGroup node, Object data) {
IAtomContainer fullQuery = new QueryAtomContainer(builder);
IAtomContainer fullQuery = (IAtomContainer) data;

if (fullQuery == null)
fullQuery = new QueryAtomContainer(builder);

// keeps track of component grouping
int[] components = new int[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,7 @@ TOKEN_MGR_DECLS : {

/**
* Start ::= <ReactionExpression> <#_WS>
* ReactionExpression ::= <GroupExpression> (">>" <GroupExpression>)? |
* ">" <GroupExpression> ">" | ">>" <GroupExpression>
* ReactionExpression ::= <GroupExpression>? (">" <GroupExpression>? ">" <GroupExpression>?)?
* GroupExpression ::= ["("] <SmartsExpresion> [")"] ( "." ["("] <SmartsExpression> [")"] )*
* SmartsExpression ::= <AtomExpression> (
( [ <LowAndBond> ] ( <Digit> | <AtomExpression> ) ) |
Expand Down Expand Up @@ -341,11 +340,24 @@ ASTStart Start() #Start : {}

void ReactionExpression() #Reaction : {}
{
GroupExpression() ( ">>" [GroupExpression()] )?
|
">" GroupExpression() ">"
|
">>" GroupExpression()
[GroupExpression()]
(
">"
{
if(jjtree.nodeArity() > 0)
((ASTGroup)jjtree.peekNode()).setRole(ASTGroup.ROLE_REACTANT);
}
[
GroupExpression()
{
((ASTGroup)jjtree.peekNode()).setRole(ASTGroup.ROLE_AGENT);
}
]
">"
[
GroupExpression(){((ASTGroup)jjtree.peekNode()).setRole(ASTGroup.ROLE_PRODUCT);}
]
)?
}

void GroupExpression() #Group : {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1281,4 +1281,28 @@ public void testRing() throws Exception {
visit("[$([C;#12]=1CCCCC1)]");
}

@Test
public void reaction() throws Exception {
visit("CCO.CC(=O)O>[H+]>CCOC(=O)C.O");
}

@Test
public void reactionNoAgents() throws Exception {
visit("CCO.CC(=O)O>>CCOC(=O)C.O");
}

@Test
public void reactionNoProduct() throws Exception {
visit("CCO.CC(=O)O>>");
}

@Test
public void reactionNoReactant() throws Exception {
visit(">>CCOC(=O)C.O");
}

@Test
public void reactionOnlyAgents() throws Exception {
visit(">>CCOC(=O)C.O");
}
}

0 comments on commit f924784

Please sign in to comment.