001/* 002 * Copyright 2019 nils.hoffmann. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package de.isas.lipidomics.palinom.goslin; 017 018import de.isas.lipidomics.domain.Adduct; 019import de.isas.lipidomics.domain.Fragment; 020import de.isas.lipidomics.domain.LipidSpecies; 021import de.isas.lipidomics.domain.LipidAdduct; 022import de.isas.lipidomics.domain.LipidCategory; 023import de.isas.lipidomics.palinom.GoslinBaseVisitor; 024import de.isas.lipidomics.palinom.GoslinParser; 025import de.isas.lipidomics.palinom.GoslinParser.Adduct_infoContext; 026import de.isas.lipidomics.palinom.GoslinParser.Lipid_pureContext; 027import de.isas.lipidomics.palinom.exceptions.ParseTreeVisitorException; 028import java.util.Arrays; 029import java.util.BitSet; 030import java.util.Optional; 031import lombok.extern.slf4j.Slf4j; 032 033/** 034 * Base visitor implementation for the Goslin grammar. 035 * 036 * 037 * Overriding implementation of {@link GoslinBaseVisitor}. Creates 038 * {@link LipidAdduct} instances from the provided context. 039 * 040 * @author nils.hoffmann 041 */ 042@Slf4j 043public class GoslinVisitorImpl extends GoslinBaseVisitor<LipidAdduct> { 044 045 /** 046 * Produces a LipidAdduct given the LipidContext. 047 * @throws ParseTreeVisitorException for structural or state-related issues 048 * while trying to process a parsing context. 049 * @throws RuntimeException 050 * @param ctx 051 * @return a LipidAdduct. 052 */ 053 @Override 054 public LipidAdduct visitLipid(GoslinParser.LipidContext ctx) { 055 GoslinParser.Lipid_eofContext lipid = ctx.lipid_eof(); 056 Optional<Lipid_pureContext> categoryContext = Optional.ofNullable(lipid.lipid_pure()); 057 Optional<Adduct_infoContext> adductTermContext = Optional.ofNullable(lipid.adduct_info()); 058 059 LipidAdduct la = new LipidAdduct(categoryContext.map((cc) -> { 060 return new LipidVisitor().visitLipid_pure(cc); 061 }).orElse(LipidSpecies.NONE), adductTermContext.map((t) -> { 062 return new AdductVisitor().visitAdduct_info(t); 063 }).orElse(Adduct.NONE), new Fragment("")); 064 return la; 065 } 066 067 private static class LipidVisitor extends GoslinBaseVisitor<LipidSpecies> { 068 069 @Override 070 public LipidSpecies visitLipid_pure(GoslinParser.Lipid_pureContext ctx) { 071 LipidSpecies lipid = null; 072 BitSet bs = new BitSet(5); 073 bs.set(LipidCategory.ST.ordinal(), ctx.sterol() != null); 074 bs.set(LipidCategory.GL.ordinal(), ctx.gl() != null); 075 bs.set(LipidCategory.FA.ordinal(), ctx.mediatorc() != null); 076 bs.set(LipidCategory.GP.ordinal(), ctx.pl() != null); 077 bs.set(LipidCategory.SP.ordinal(), ctx.sl() != null); 078 final FattyAcylHelper faHelper = new FattyAcylHelper(); 079 final MolecularSubspeciesFasHandler msfh = new MolecularSubspeciesFasHandler(faHelper); 080 final IsomericSubspeciesFasHandler isfh = new IsomericSubspeciesFasHandler(faHelper); 081 final StructuralSubspeciesFasHandler ssfh = new StructuralSubspeciesFasHandler(isfh, faHelper); 082 final IsomericSubspeciesLcbHandler islh = new IsomericSubspeciesLcbHandler(isfh, faHelper); 083 final StructuralSubspeciesLcbHandler sslh = new StructuralSubspeciesLcbHandler(ssfh, islh); 084 final FattyAcylHandler faHandler = new FattyAcylHandler(); 085 LipidCategory contextCategory = LipidCategory.UNDEFINED; 086 switch (bs.cardinality()) { 087 case 0: 088 throw new ParseTreeVisitorException("Parsing context did not contain content for any lipid category. Must contain exactly one of " + Arrays.toString(LipidCategory.values())); 089 case 1: 090 contextCategory = LipidCategory.values()[bs.nextSetBit(0)]; 091 break; 092 default: 093 throw new ParseTreeVisitorException("Parsing context contained content for more than one lipid category. Must contain exactly one of " + Arrays.toString(LipidCategory.values())); 094 } 095 switch (contextCategory) { 096 case ST: 097 lipid = new SterolLipidHandler( 098 ssfh 099 ).handle(ctx); 100 break; 101 case GL: 102 lipid = new GlyceroLipidHandler( 103 msfh, 104 ssfh, 105 faHandler 106 ).handle(ctx); 107 break; 108 case FA: 109 lipid = new FattyAcylHandler().handle(ctx); 110 break; 111 case GP: 112 lipid = new GlycerophosphoLipidHandler( 113 msfh, 114 ssfh, 115 faHandler 116 ).handle(ctx); 117 break; 118 case SP: 119 lipid = new SphingoLipidHandler( 120 sslh, 121 faHandler 122 ).handle(ctx); 123 break; 124 default: 125 throw new ParseTreeVisitorException("Unhandled contextCategory: " + contextCategory); 126 } 127 return lipid; 128 } 129 130 } 131 132 private static class AdductVisitor extends GoslinBaseVisitor<Adduct> { 133 134 @Override 135 public Adduct visitAdduct_info(GoslinParser.Adduct_infoContext ctx) { 136 String chargeSign = ctx.charge_sign().getText(); 137 Integer chargeSignValue = 0; 138 switch (chargeSign) { 139 case "+": 140 chargeSignValue = 1; 141 break; 142 case "-": 143 chargeSignValue = -1; 144 break; 145 default: 146 chargeSignValue = 0; 147 } 148 String adductText = ctx.adduct().getText(); 149 Adduct adduct = new Adduct("", adductText, Integer.parseInt(ctx.charge().getText()), chargeSignValue); 150 return adduct; 151 } 152 } 153}