org.eclipse.titan.designer.parsers.ttcn3parser.TTCN3Analyzer.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.titan.designer.parsers.ttcn3parser.TTCN3Analyzer.java

Source

/******************************************************************************
 * Copyright (c) 2000-2016 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 ******************************************************************************/
package org.eclipse.titan.designer.parsers.ttcn3parser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.util.List;

import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenFactory;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.UnbufferedCharStream;
import org.antlr.v4.runtime.atn.ParserATNSimulator;
import org.antlr.v4.runtime.atn.PredictionContextCache;
import org.antlr.v4.runtime.atn.PredictionMode;
import org.antlr.v4.runtime.dfa.DFA;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.titan.common.logging.ErrorReporter;
import org.eclipse.titan.common.parsers.Interval;
import org.eclipse.titan.common.parsers.SyntacticErrorStorage;
import org.eclipse.titan.common.parsers.TITANMarker;
import org.eclipse.titan.common.parsers.TitanListener;
import org.eclipse.titan.designer.AST.TTCN3.definitions.TTCN3Module;
import org.eclipse.titan.designer.parsers.ISourceAnalyzer;
import org.eclipse.titan.designer.parsers.GlobalParser;
import org.eclipse.titan.designer.parsers.ttcn3parser.PreprocessedTokenStream;
import org.eclipse.titan.designer.parsers.ttcn3parser.Ttcn3Lexer;
import org.eclipse.titan.designer.parsers.ttcn3parser.Ttcn3Parser;
import org.eclipse.titan.designer.properties.data.PreprocessorSymbolsOptionsData;

/**
 * TTCN3Analyzer
 * @author Arpad Lovassy
 */
public class TTCN3Analyzer implements ISourceAnalyzer {

    private List<TITANMarker> warnings;
    private List<TITANMarker> unsupportedConstructs;
    private Interval rootInterval;
    private TTCN3Module actualTtc3Module;

    /**
     * The list of markers (ERROR and WARNING) created during parsing
     * NOTE: used from ANTLR v4
     */
    private List<SyntacticErrorStorage> mErrorsStored = null;

    @Override
    public List<SyntacticErrorStorage> getErrorStorage() {
        return mErrorsStored;
    }

    @Override
    public List<TITANMarker> getWarnings() {
        return warnings;
    }

    @Override
    public List<TITANMarker> getUnsupportedConstructs() {
        return unsupportedConstructs;
    }

    @Override
    public TTCN3Module getModule() {
        return actualTtc3Module;
    }

    @Override
    public Interval getRootInterval() {
        return rootInterval;
    }

    /**
     * Parse TTCN-3 file using ANTLR v4
     * @param aFile TTCN-3 file to parse, It cannot be null
     * @param aCode TTCN-3 code to parse in string format
     *              It can be null, in this case code is read from file
     */
    public void parse(IFile aFile, String aCode) {
        Reader reader;
        int rootInt;
        if (aCode != null) {
            reader = new StringReader(aCode);
            rootInt = aCode.length();
        } else if (aFile != null) {
            try {
                InputStreamReader temp = new InputStreamReader(aFile.getContents());
                if (!aFile.getCharset().equals(temp.getEncoding())) {
                    try {
                        temp.close();
                    } catch (IOException e) {
                        ErrorReporter.logWarningExceptionStackTrace(e);
                    }
                    temp = new InputStreamReader(aFile.getContents(), aFile.getCharset());
                }

                reader = new BufferedReader(temp);
            } catch (CoreException e) {
                ErrorReporter.logExceptionStackTrace(e);
                return;
            } catch (UnsupportedEncodingException e) {
                ErrorReporter.logExceptionStackTrace(e);
                return;
            }

            IFileStore store;
            try {
                store = EFS.getStore(aFile.getLocationURI());
            } catch (CoreException e) {
                ErrorReporter.logExceptionStackTrace(e);
                return;
            }
            IFileInfo fileInfo = store.fetchInfo();
            rootInt = (int) fileInfo.getLength();
        } else {
            return;
        }

        parse(reader, rootInt, aFile);
    }

    /**
     * Parse TTCN-3 file using ANTLR v4
     * Eclipse independent version
     * @param aFile TTCN-3 file to parse, It cannot be null
     */
    public void parse(final File aFile) {
        BufferedReader bufferedReader;

        try {
            bufferedReader = new BufferedReader(new FileReader(aFile));
        } catch (FileNotFoundException e) {
            //TODO: handle error
            return;
        }

        final int fileLength = (int) aFile.length();
        parse(bufferedReader, fileLength, null);
    }

    /**
     * Parse TTCN-3 file using ANTLR v4
     * @param aReader file to parse (cannot be null, closes aReader)
     * @param aFileLength file length
     * @param aEclipseFile Eclipse dependent resource file
     */
    private void parse(final Reader aReader, final int aFileLength, IFile aEclipseFile) {
        CharStream charStream = new UnbufferedCharStream(aReader);
        Ttcn3Lexer lexer = new Ttcn3Lexer(charStream);

        lexer.setCommentTodo(true);
        lexer.setTokenFactory(new CommonTokenFactory(true));
        lexer.initRootInterval(aFileLength);

        TitanListener lexerListener = new TitanListener();
        // remove ConsoleErrorListener
        lexer.removeErrorListeners();
        lexer.addErrorListener(lexerListener);

        // 1. Previously it was UnbufferedTokenStream(lexer), but it was changed to BufferedTokenStream, because UnbufferedTokenStream seems to be unusable. It is an ANTLR 4 bug.
        // Read this: https://groups.google.com/forum/#!topic/antlr-discussion/gsAu-6d3pKU
        // pr_PatternChunk[StringBuilder builder, boolean[] uni]:
        //   $builder.append($v.text); <-- exception is thrown here: java.lang.UnsupportedOperationException: interval 85..85 not in token buffer window: 86..341
        // 2. Changed from BufferedTokenStream to CommonTokenStream, otherwise tokens with "-> channel(HIDDEN)" are not filtered out in lexer.
        final CommonTokenStream tokenStream = new CommonTokenStream(lexer);

        Ttcn3Parser parser = new Ttcn3Parser(tokenStream);
        parser.setBuildParseTree(false);
        PreprocessedTokenStream preprocessor = null;

        if (aEclipseFile != null && GlobalParser.TTCNPP_EXTENSION.equals(aEclipseFile.getFileExtension())) {
            lexer.setTTCNPP();
            preprocessor = new PreprocessedTokenStream(lexer);
            preprocessor.setActualFile(aEclipseFile);
            if (aEclipseFile.getProject() != null) {
                preprocessor.setMacros(
                        PreprocessorSymbolsOptionsData.getTTCN3PreprocessorDefines(aEclipseFile.getProject()));
            }
            parser = new Ttcn3Parser(preprocessor);
            preprocessor.setActualLexer(lexer);
            preprocessor.setParser(parser);
        }

        if (aEclipseFile != null) {
            lexer.setActualFile(aEclipseFile);
            parser.setActualFile(aEclipseFile);
            parser.setProject(aEclipseFile.getProject());
        }

        parser.setLexer(lexer);
        // remove ConsoleErrorListener
        parser.removeErrorListeners();
        TitanListener parserListener = new TitanListener();
        parser.addErrorListener(parserListener);

        // This is added because of the following ANTLR 4 bug:
        // Memory Leak in PredictionContextCache #499
        // https://github.com/antlr/antlr4/issues/499
        DFA[] decisionToDFA = parser.getInterpreter().decisionToDFA;
        parser.setInterpreter(
                new ParserATNSimulator(parser, parser.getATN(), decisionToDFA, new PredictionContextCache()));

        //try SLL mode
        try {
            parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
            parser.pr_TTCN3File();
            warnings = parser.getWarnings();
            mErrorsStored = lexerListener.getErrorsStored();
            mErrorsStored.addAll(parserListener.getErrorsStored());
        } catch (RecognitionException e) {
            // quit
        }

        if (!warnings.isEmpty() || !mErrorsStored.isEmpty()) {
            //SLL mode might have failed, try LL mode
            try {
                CharStream charStream2 = new UnbufferedCharStream(aReader);
                lexer.setInputStream(charStream2);
                //lexer.reset();
                parser.reset();
                parserListener.reset();
                parser.getInterpreter().setPredictionMode(PredictionMode.LL);
                parser.pr_TTCN3File();
                warnings = parser.getWarnings();
                mErrorsStored = lexerListener.getErrorsStored();
                mErrorsStored.addAll(parserListener.getErrorsStored());
            } catch (RecognitionException e) {

            }
        }

        unsupportedConstructs = parser.getUnsupportedConstructs();
        rootInterval = lexer.getRootInterval();
        actualTtc3Module = parser.getModule();
        if (preprocessor != null) {
            // if the file was preprocessed
            mErrorsStored.addAll(preprocessor.getErrorStorage());
            warnings.addAll(preprocessor.getWarnings());
            unsupportedConstructs.addAll(preprocessor.getUnsupportedConstructs());
            if (actualTtc3Module != null) {
                actualTtc3Module.setIncludedFiles(preprocessor.getIncludedFiles());
                actualTtc3Module.setInactiveCodeLocations(preprocessor.getInactiveCodeLocations());
            }
        }
        //TODO: empty mErrorsStored not to store errors from the previous parse round in case of exception

        try {
            aReader.close();
        } catch (IOException e) {
        }
    }
}