/** * Copyright 2010-2017 Evgeny Gryaznov * <p> * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * <p> * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * <p> * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package org.textmapper.idea.lang.syntax.psi; import com.intellij.lang.ASTNode; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import java.util.*; import java.util.stream.Collectors; import java.util.stream.StreamSupport; /** * Gryaznov Evgeny, 1/26/11 */ public class TmGrammar extends TmElement { public TmGrammar(@NotNull ASTNode node) { super(node); } public TmNamedElement[] getNamedElements() { Iterable<TmNamedElement> elements = getElements(TmNamedElement.class); List<TmNamedElement> list = StreamSupport.stream(elements.spliterator(), false).collect(Collectors.toList()); return list.toArray(new TmNamedElement[list.size()]); } public TmHeader getHeader() { return PsiTreeUtil.getChildOfType(this, TmHeader.class); } public List<TmImport> getImports() { return PsiTreeUtil.getChildrenOfTypeAsList(this, TmImport.class); } public List<TmOption> getOptions() { return PsiTreeUtil.getChildrenOfTypeAsList(this, TmOption.class); } public List<TmLexeme> getLexemes() { return PsiTreeUtil.getChildrenOfTypeAsList(this, TmLexeme.class); } public List<TmNonterm> getNonterms() { return PsiTreeUtil.getChildrenOfTypeAsList(this, TmNonterm.class); } public TmLexerState[] getStates() { List<TmLexerState> states = new ArrayList<>(); Set<String> seen = new HashSet<>(); for (TmStatesClause selector : getElements(TmStatesClause.class)) { for (TmLexerState tmLexerState : selector.getStates()) { if (seen.add(tmLexerState.getName())) { states.add(tmLexerState); } } } return states.toArray(new TmLexerState[states.size()]); } public List<TmStartConditionsScope> getStartConditionScopes() { return PsiTreeUtil.getChildrenOfTypeAsList(this, TmStartConditionsScope.class); } public TmNamedElement resolve(String name) { if (name.endsWith("opt") && name.length() > 3) { name = name.substring(0, name.length() - 3); } for (TmNamedElement named : getElements(TmNamedElement.class)) { if (name.equals(named.getName())) { return named; } } return null; } public TmNamedElement resolveState(String name) { for (TmStatesClause clause : getElements(TmStatesClause.class)) { for (TmLexerState state : clause.getStates()) { if (name.equals(state.getName())) { return state; } } } return null; } <T extends TmElement> Iterable<T> getElements(Class<T> c) { return () -> new Iterator<T>() { Stack<Iterator<TmElement>> stack = new Stack<>(); T next; { stack.push(PsiTreeUtil.getChildrenOfAnyType(TmGrammar.this, TmStartConditionsScope.class, c).iterator()); fetch(); } private void fetch() { next = null; while (!stack.empty()) { if (!stack.peek().hasNext()) { stack.pop(); continue; } TmElement next = stack.peek().next(); if (c.isInstance(next)) { this.next = (T) next; return; } if (next instanceof TmStartConditionsScope) { stack.push(PsiTreeUtil.getChildrenOfAnyType(next, TmStartConditionsScope.class, c).iterator()); } } } @Override public boolean hasNext() { return next != null; } @Override public T next() { T r = next; fetch(); return r; } }; } }