/******************************************************************************* * Copyright (c) 2008 SAP * see https://research.qkal.sap.corp/mediawiki/index.php/CoMONET * * Date: $Date: 2010-02-05 15:00:44 +0100 (Fr, 05 Feb 2010) $ * Revision: $Revision: 9371 $ * Author: $Author: c5106462 $ *******************************************************************************/ package com.sap.furcas.runtime.parser.wrapper; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.List; import java.util.Map; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.Lexer; import org.antlr.runtime.Parser; import org.antlr.runtime.TokenStream; import com.sap.furcas.runtime.parser.IModelAdapter; import com.sap.furcas.runtime.parser.IParsingObserver; import com.sap.furcas.runtime.parser.InjectionOptionsBean; import com.sap.furcas.runtime.parser.ParsingError; import com.sap.furcas.runtime.parser.TextLocation; import com.sap.furcas.runtime.parser.exceptions.InvalidParserImplementationException; import com.sap.furcas.runtime.parser.exceptions.UnknownProductionRuleException; import com.sap.furcas.runtime.parser.impl.ModelInjector; import com.sap.furcas.runtime.parser.impl.ObservableInjectingParser; import com.sap.furcas.utils.projects.FileReadHelper; /** * This class provides access to parsers generated for SAP DSL Engineering. * Such generated classes extend org.antlr.Parser and org.antlr.Lexer, but also have * some additional members, such as one method for each production Rule. * This class provides access to these members. */ public class GeneratedParserWrapper { private ObservableInjectingParser parser; private Lexer lexer; private Class<? extends Parser> parserClass; private Class<? extends Lexer> lexerClass; private ModelInjector injector; /** * @param parserClass * @param lexerClass * @throws NoSuchMethodException * @throws InvocationTargetException * @throws IllegalAccessException * @throws InstantiationException * @throws SecurityException * @throws IllegalArgumentException * @throws NoSuchFieldException */ public GeneratedParserWrapper(Class<? extends ObservableInjectingParser> parserClass, Class<? extends Lexer> lexerClass, String languageName) throws InvalidParserImplementationException { if(parserClass == null || lexerClass == null) { throw new IllegalArgumentException("parserClass or lexerclass is null:" + parserClass + "," + lexerClass); } try { this.lexer = lexerClass.getDeclaredConstructor((Class[]) null).newInstance((Object[])null); this.parser = parserClass.getDeclaredConstructor(new Class[] {TokenStream.class}).newInstance(new Object[] {null}); this.parser.setLanguageId(languageName); this.parserClass = parserClass; this.lexerClass = lexerClass; this.injector = new ModelInjector(parser.getTokenNames()); parser.setInjector(injector); try { Field f = lexerClass.getField("ei"); f.set(lexer, injector); } catch (NoSuchFieldException nsfe) { System.out.println("Warning, lexer has no ModelInjector fiel ei, lexer errors will only be reported to System.err"); } } catch (IllegalArgumentException e) { throw new InvalidParserImplementationException(e); } catch (InstantiationException e) { throw new InvalidParserImplementationException(e); } catch (IllegalAccessException e) { throw new InvalidParserImplementationException(e); } catch (InvocationTargetException e) { throw new InvalidParserImplementationException(e); } catch (NoSuchMethodException e) { throw new InvalidParserImplementationException(e); } } /** * @param parser2 * @param lexer2 * @throws InvalidParserImplementationException */ public GeneratedParserWrapper(ObservableInjectingParser parser2, Lexer lexer2) throws InvalidParserImplementationException { this.lexer = lexer2; this.parser = parser2; this.parserClass = parser.getClass(); this.injector = new ModelInjector(parser.getTokenNames()); try { parser.setInjector(injector); try { Field f = lexer.getClass().getField("ei"); f.set(lexer, injector); } catch (NoSuchFieldException nsfe) { System.out.println("Warning, lexer has no ModelInjector fiel ei, lexer errors will only be reported to System.err"); } } catch (IllegalArgumentException e) { throw new InvalidParserImplementationException(e); } catch (IllegalAccessException e) { throw new InvalidParserImplementationException(e); } } /** * returns a modelElement as cretaed by the ModelAdapter, or null * @param in * @param productionRule * @param targetModelAdapter * @param bean * @param observer * @return * @throws IOException * @throws UnknownProductionRuleException */ public Object parse(InputStream in, String productionRule, IModelAdapter targetModelAdapter, InjectionOptionsBean bean, IParsingObserver observer) throws IOException, UnknownProductionRuleException { return parse(in, productionRule, targetModelAdapter, bean, observer, true); } /** * returns a modelElement as cretaed by the ModelAdapter, or null * @param in * @param productionRule * @param targetModelAdapter * @param bean * @param observer * @return * @throws IOException * @throws UnknownProductionRuleException */ public Object parse(InputStream in, String productionRule, IModelAdapter targetModelAdapter, InjectionOptionsBean bean, IParsingObserver observer, boolean setDelayedreferences) throws IOException, UnknownProductionRuleException { if (in == null || productionRule == null || targetModelAdapter == null) { throw new IllegalArgumentException("Argument is null " + in + ", " + productionRule + ", " + targetModelAdapter); } Object parsedModelElement = null; this.injector.setModelAdapter(targetModelAdapter); this.injector.setOptions(bean); try { ANTLRStringStream stream = new ANTLRStringStream(FileReadHelper.readInput(in)); lexer.setCharStream(stream); CommonTokenStream tokens = new CommonTokenStream(lexer); parser.setTokenStream(tokens); parser.setObserver(observer); Method productionRuleMethod = parserClass.getMethod(productionRule, (Class[]) null); if (! Modifier.isFinal(productionRuleMethod.getModifiers())) { throw new UnknownProductionRuleException(productionRule + " is not a production rule in generated Parser."); } parsedModelElement = productionRuleMethod.invoke(parser, (Object[])null); if(setDelayedreferences) { parser.setDelayedReferencesAfterParsing(); } } catch(java.lang.reflect.InvocationTargetException ite) { if (ite.getCause() != null && ite.getCause() instanceof IncompatibleClassChangeError) { // was once caused by having DSLParsing.jar deployed in 2 plugins at the same time ite.printStackTrace(); throw new RuntimeException("Tip: Check classes are only once on the classpath.", ite); } else { ite.printStackTrace(); throw new RuntimeException("invoking method "+ productionRule + "() on parser class " + parserClass + " caused an exception.", ite); } } catch (IllegalAccessException e) { // all generated parsing rule methods should be public, so this should never happen throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new UnknownProductionRuleException("No production rule " + productionRule + " known in parser " + parserClass.getName()); } return parsedModelElement; } /** * @return */ public List<ParsingError> getErrors() { return injector.getErrorList(); } /** * @return */ public Map<Object, TextLocation> getLocationMap() { return injector.getLocationsMap(); } public Class<? extends Parser> getParserClass() { return parserClass; } public Class<? extends Lexer> getLexerClass() { return lexerClass; } }