Skip to content

Commit

Permalink
Merge pull request #401 from cdk/patch/smartsisotopes
Browse files Browse the repository at this point in the history
Looks good!
  • Loading branch information
egonw committed Dec 15, 2017
2 parents fe06998 + b59c225 commit 1c27bf4
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 22 deletions.
Expand Up @@ -315,7 +315,7 @@ TOKEN_MGR_DECLS : {
* ImplicitHighAndExpression ::= <NotExpression> ( <ImplicitHighAndExpression> ) ?
* NotExpression ::= "!" ( <PrimitiveAtomExpression> | <RecursiveSmartsExpression> )
* RecursiveSmartsExpression ::= "$" "(" <SmartsExpression> ")"
* PrimitiveAtomExpression ::= <NonHydrogenElement> | "*" | "A" | "a" | "D" (<Digits>)? | "H" (<Digits>)? | "h" (<Digits>)?
* PrimitiveAtomExpression ::= <AtomicMass> | <NonHydrogenElement> | "*" | "A" | "a" | "D" (<Digits>)? | "H" (<Digits>)? | "h" (<Digits>)?
* | "R" (<Digit>+)? | "r" (<Digit>+)? | "v" (<Digit>+)? | "#X" | "G" (<DIGIT>+)
* | "X" (<Digit>+)? | "x" (<Digit>+)? | "^" (<DIGIT>)
* | ("+" | "-") (<Digit>+)? | "#" (<Digit>+) | "@" | "@@" | <Digit>+
Expand Down Expand Up @@ -447,15 +447,14 @@ ASTAtom AtomExpression() #Atom :
}
{
(
(

(
<L_BRACKET> { token_source.SwitchTo(SMARTSParserConstants.ATOM_EXPRESSION);
firstToken = getToken(1);
secondToken = getToken(2); }
( AtomicMass() { massNode = (ASTAtomicMass)jjtree.popNode(); } )?
LowAndExpression()
( LOOKAHEAD(2) AtomicMass() { massNode = (ASTAtomicMass)jjtree.popNode(); } )?
LowAndExpression()
{
if (massNode != null) { // insert AtomicMass node into expression
if (massNode != null) { // insert AtomicMass node into expression
ASTLowAndExpression topNode = (ASTLowAndExpression)jjtree.popNode();
topNode.insertLeafChild(massNode);
jjtree.pushNode(topNode);
Expand Down Expand Up @@ -600,8 +599,7 @@ void RecursiveSmartsExpression() #RecursiveSmartsExpression : {}

void PrimitiveAtomExpression() : {}
{
(
NoHydrogenElement()
( NoHydrogenElement()
|
AnyAtom()
|
Expand Down Expand Up @@ -636,35 +634,37 @@ void PrimitiveAtomExpression() : {}
NonCHHeavyAtom()
|
HybridizationNumber()
|
AtomicMass()
)
}

void TotalHCount() #TotalHCount :
{ StringBuilder digits = new StringBuilder(); }
{
<H> { jjtThis.setCount(1); } [ ( <DIGIT> { digits.append(token.image); } )+
<H> { jjtThis.setCount(1); } [ LOOKAHEAD(1) ( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); } )+
{ jjtThis.setCount( Integer.parseInt(digits.toString()) ); } ]
}

void ImplicitHCount() #ImplicitHCount:
{ StringBuilder digits = new StringBuilder(); }
{
<h> { jjtThis.setCount(1); } [ ( <DIGIT> { digits.append(token.image); } )+
<h> { jjtThis.setCount(1); } [ LOOKAHEAD(1) ( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); } )+
{ jjtThis.setCount( Integer.parseInt(digits.toString()) ); } ]
}

void ExplicitConnectivity() #ExplicitConnectivity :
{ StringBuilder digits = new StringBuilder(); }
{
<D> { jjtThis.setNumOfConnection(1); }
[ ( <DIGIT> { digits.append(token.image); } )+
[ LOOKAHEAD(1) ( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); } )+
{ jjtThis.setNumOfConnection( Integer.parseInt(digits.toString()) ); } ]
}

void AtomicNumber() #AtomicNumber :
{ StringBuilder digits = new StringBuilder(); }
{
"#" ( <DIGIT> { digits.append(token.image); } )+
"#" ( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); } )+
{ jjtThis.setNumber( Integer.parseInt(digits.toString()) ); }
}

Expand All @@ -685,10 +685,10 @@ void Charge() #Charge :
// with more than 8 of them
LOOKAHEAD(2)
"+" { jjtThis.setPositive(true); jjtThis.setCharge(1); }
[ ( <DIGIT> { digits.append(token.image); } )+
[ LOOKAHEAD(1) ( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); } )+
{ jjtThis.setCharge( Integer.parseInt(digits.toString()) ); } ]
| "-" { jjtThis.setPositive(false); jjtThis.setCharge(1); }
[ ( <DIGIT> { digits.append(token.image); } )+
[ LOOKAHEAD(1) ( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); } )+
{ jjtThis.setCharge( Integer.parseInt(digits.toString()) ); } ]
| "--" { jjtThis.setPositive(false); jjtThis.setCharge(2); }
| "---" { jjtThis.setPositive(false); jjtThis.setCharge(3); }
Expand All @@ -709,14 +709,14 @@ void Charge() #Charge :
void RingConnectivity() #RingConnectivity : {}
{
<x> { jjtThis.setNumOfConnection(1); }
[ ( <DIGIT> )+ { jjtThis.setNumOfConnection( Integer.parseInt(token.image) ); } ]
[ LOOKAHEAD(1) ( LOOKAHEAD(1) <DIGIT> )+ { jjtThis.setNumOfConnection( Integer.parseInt(token.image) ); } ]
}

void PeriodicGroupNumber() throws ParseException #PeriodicGroupNumber :
{ StringBuilder digits = new StringBuilder(); }
{
<G> { }
( <DIGIT> { digits.append(token.image); } )+
( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); } )+
{ int tmpInt = Integer.parseInt(digits.toString());
if (tmpInt < 1 || tmpInt > 18) throw new ParseException("Invalid group number");
jjtThis.setGroupNumber( Integer.parseInt(digits.toString()) ); }
Expand All @@ -727,31 +727,31 @@ void TotalConnectivity() #TotalConnectivity :
{ StringBuilder digits = new StringBuilder(); }
{
<X> { jjtThis.setNumOfConnection(1); }
[ ( <DIGIT> { digits.append(token.image); } )+
[ LOOKAHEAD(1) ( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); } )+
{ jjtThis.setNumOfConnection( Integer.parseInt(digits.toString()) ); } ]
}

void Valence() #Valence :
{ StringBuilder digits = new StringBuilder(); }
{
<v> { jjtThis.setOrder(1); }
[ ( <DIGIT> { digits.append(token.image); })+
[ LOOKAHEAD(1) ( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); })+
{ jjtThis.setOrder( Integer.parseInt(digits.toString()) ); } ]
}

void RingMembership() #RingMembership :
{ StringBuilder digits = new StringBuilder(); }
{
<R> { jjtThis.setNumOfMembership(-1); }
[ ( <DIGIT> { digits.append(token.image); } )+
[ LOOKAHEAD(1) ( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); } )+
{ jjtThis.setNumOfMembership( Integer.parseInt(digits.toString()) ); } ]
}

void SmallestRingSize() #SmallestRingSize :
{ StringBuilder digits = new StringBuilder(); }
{
<r> { jjtThis.setSize(-1); }
[ ( <DIGIT> { digits.append(token.image); } )+
[ LOOKAHEAD(1) ( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); } )+
{ jjtThis.setSize( Integer.parseInt(digits.toString()) ); } ]
}

Expand All @@ -778,7 +778,7 @@ void AnyAtom() #AnyAtom : {}
void AtomicMass() #AtomicMass :
{ StringBuilder digits = new StringBuilder(); }
{
( <DIGIT> { digits.append(token.image); } )+
( LOOKAHEAD(1) <DIGIT> { digits.append(token.image); } )+
{
jjtThis.setMass( Integer.parseInt(digits.toString()) );
}
Expand All @@ -793,7 +793,7 @@ void Chirality() #Chirality :
{ StringBuilder digits = new StringBuilder(); }
{
"@" { jjtThis.setClockwise(false); }
(
( LOOKAHEAD(1)
"@" { jjtThis.setClockwise(true); }
)?
(
Expand Down
Expand Up @@ -33,17 +33,26 @@
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IBond.Order;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.isomorphism.matchers.IQueryAtom;
import org.openscience.cdk.isomorphism.matchers.OrderQueryBond;
import org.openscience.cdk.isomorphism.matchers.QueryAtomContainer;
import org.openscience.cdk.isomorphism.matchers.SymbolAndChargeQueryAtom;
import org.openscience.cdk.isomorphism.matchers.SymbolQueryAtom;
import org.openscience.cdk.isomorphism.matchers.smarts.AnyAtom;
import org.openscience.cdk.isomorphism.matchers.smarts.AnyOrderQueryBond;
import org.openscience.cdk.isomorphism.matchers.smarts.ImplicitHCountAtom;
import org.openscience.cdk.isomorphism.matchers.smarts.LogicalOperatorAtom;
import org.openscience.cdk.isomorphism.matchers.smarts.MassAtom;
import org.openscience.cdk.isomorphism.matchers.smarts.SMARTSAtom;
import org.openscience.cdk.silent.SilentChemObjectBuilder;
import org.openscience.cdk.smiles.SmilesParser;
import org.openscience.cdk.smiles.smarts.parser.SMARTSParser;
import org.openscience.cdk.templates.TestMoleculeFactory;

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;

/**
* @cdk.module test-smarts
* @cdk.require java1.4+
Expand Down Expand Up @@ -160,4 +169,15 @@ public void testMatchInherited() {
}

}

@Test public void testUnspecifiedIsotope() {
IAtom aexpr = SMARTSParser.parse("[!0]", SilentChemObjectBuilder.getInstance())
.getAtom(0);
assertThat(aexpr, instanceOf(LogicalOperatorAtom.class));
assertThat(((LogicalOperatorAtom)aexpr).getOperator(),
is("not"));
IQueryAtom subexpr = ((LogicalOperatorAtom) aexpr).getLeft();
assertThat(subexpr, instanceOf(MassAtom.class));
assertThat(subexpr.getMassNumber(), is(0));
}
}
Expand Up @@ -232,6 +232,22 @@ public void stereo_ring_closures() throws Exception {
assertTrue(ptrn.matches(smi("[C@@]1(O[C@@]([C@@]([C@]([C@]1(C)O)(C)O)(O)C)(O)C)(O)C")));
}

@Test
public void hasIsotope() throws Exception {
Pattern ptrn = SmartsPattern.create("[!0]");
assertFalse(ptrn.matches(smi("C")));
assertTrue(ptrn.matches(smi("[12C]")));
assertTrue(ptrn.matches(smi("[13C]")));
}

@Test
public void hIsotope() throws Exception {
Pattern ptrn = SmartsPattern.create("[2#1,3#1]");
assertFalse(ptrn.matches(smi("[H][H]")));
assertTrue(ptrn.matches(smi("[2H]")));
assertTrue(ptrn.matches(smi("[3H]")));
}

IAtomContainer smi(String smi) throws Exception {
return new SmilesParser(bldr).parseSmiles(smi);
}
Expand Down

0 comments on commit 1c27bf4

Please sign in to comment.