/******************************************************************************* * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. 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 com.cisco.yangide.core.parser; import java.util.BitSet; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.BufferedTokenStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.IntStream; import org.antlr.v4.runtime.Parser; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.atn.ATNConfigSet; import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.tree.ParseTreeWalker; import org.eclipse.core.resources.IProject; import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext; import com.cisco.yangide.core.dom.Module; /** * @author Konstantin Zaitsev * @date Jul 9, 2014 */ public class YangParserUtil { // protect from initializaiton private YangParserUtil() { // empty block } /** * Parses YANG file contents and returns AST tree as {@link Module} * * @param chars file contents * @return AST Tree */ public static Module parseYangFile(char[] chars) { YangContext yangContext = parseYangSource(chars, null); YangParserModelListener modelListener = new YangParserModelListener(); ParseTreeWalker.DEFAULT.walk(modelListener, yangContext); return modelListener.getModule(); } /** * @param chars * @param project * @param validationListener * @return */ public static Module parseYangFile(char[] chars, IProject project, IYangValidationListener validationListener) { YangContext yangContext = parseYangSource(chars, validationListener); if (validationListener != null) { validateYangContext(yangContext, validationListener); } YangParserModelListener modelListener = new YangParserModelListener(); ParseTreeWalker.DEFAULT.walk(modelListener, yangContext); Module module = modelListener.getModule(); if (validationListener != null) { new SemanticValidations(validationListener, project, module).validate(); } return module; } public static void validateYangContext(YangContext context, IYangValidationListener validationListener) { final ParseTreeWalker walker = new ParseTreeWalker(); final YangModelBasicValidationListener yangModelParser = new YangModelBasicValidationListener(); try { walker.walk(yangModelParser, context); } catch (YangValidationException e) { if (validationListener != null) { int lineNumber = -1; int charStart = 0; int charEnd = 0; if (e.getContext() instanceof ParserRuleContext) { Token token = ((ParserRuleContext) e.getContext()).getStart(); lineNumber = token.getLine(); charStart = token.getStartIndex(); charEnd = token.getStopIndex() + 1; } validationListener.validationError(e.getMessage(), lineNumber, charStart, charEnd); } } } public static void validateYangFile(char[] content, IProject project, IYangValidationListener validationListener) { YangContext parseTree = parseYangSource(content, validationListener); validateYangContext(parseTree, validationListener); YangParserModelListener modelListener = new YangParserModelListener(); ParseTreeWalker.DEFAULT.walk(modelListener, parseTree); new SemanticValidations(validationListener, project, modelListener.getModule()).validate(); } public static YangContext parseYangSource(char[] content, final IYangValidationListener validationListener) { final ANTLRInputStream input = new ANTLRInputStream(content, content.length); final YangLexer lexer = new YangLexer(input); final CommonTokenStream tokens = new CommonTokenStream(lexer); final YangParser parser = new YangParser(tokens); parser.removeErrorListeners(); if (validationListener != null) { parser.addErrorListener(new BaseErrorListener() { @Override public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { int charStart = 0; int charEnd = 0; if (offendingSymbol != null && offendingSymbol instanceof Token) { charStart = ((Token) offendingSymbol).getStartIndex(); charEnd = ((Token) offendingSymbol).getStopIndex() + 1; } validationListener.syntaxError(msg, line, charStart, charEnd); } }); } return parser.yang(); } public static String formatYangSource(YangFormattingPreferences preferences, char[] content, int indentationLevel, String lineSeparator) { ANTLRInputStream input = new ANTLRInputStream(content, content.length); final YangLexer lexer = new YangLexer(input) { @Override public void skip() { // disable skipping of comment tokens } }; LexerErrorListener errorListener = new LexerErrorListener(); lexer.addErrorListener(errorListener); final BufferedTokenStream tokens = new BufferedTokenStream(lexer); final ITokenFormatter formatter = new YangTokenFormatter(preferences, indentationLevel, lineSeparator); while (tokens.LT(1).getType() != IntStream.EOF) { formatter.process(tokens.LT(1)); tokens.consume(); } if (errorListener.isErrorDetected()) { // Source that contains parsing errors should never be formatted return String.valueOf(content); } return formatter.getFormattedContent(); } private static final class LexerErrorListener extends BaseErrorListener { private boolean anErrorDetected = false; @Override public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { anErrorDetected = true; } @Override public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, BitSet ambigAlts, ATNConfigSet configs) { anErrorDetected = true; } public boolean isErrorDetected() { return anErrorDetected; } } }