| /* |
| * Copyright 2000-2013 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.jetbrains.python.buildout.config; |
| |
| import com.intellij.lang.ASTNode; |
| import com.intellij.lang.PsiBuilder; |
| import com.intellij.lang.PsiParser; |
| import com.intellij.psi.tree.IElementType; |
| import org.jetbrains.annotations.NotNull; |
| |
| /** |
| * @author traff |
| */ |
| public class BuildoutCfgParser implements PsiParser, BuildoutCfgElementTypes, BuildoutCfgTokenTypes { |
| @NotNull |
| public ASTNode parse(IElementType root, PsiBuilder builder) { |
| final PsiBuilder.Marker rootMarker = builder.mark(); |
| Parsing parsing = new Parsing(builder); |
| while (!builder.eof()) { |
| if (!parsing.parseSection()) { |
| parsing.skipLine(); |
| } |
| } |
| rootMarker.done(root); |
| return builder.getTreeBuilt(); |
| } |
| |
| private class Parsing { |
| private final PsiBuilder myBuilder; |
| |
| public Parsing(PsiBuilder builder) { |
| myBuilder = builder; |
| } |
| |
| public boolean parseSection() { |
| PsiBuilder.Marker section = mark(); |
| |
| boolean res = true; |
| |
| PsiBuilder.Marker sectionHeader = mark(); |
| if (parseSectionHeader()) { |
| sectionHeader.done(SECTION_HEADER); |
| } |
| else { |
| error("Section name expected."); |
| sectionHeader.drop(); |
| res = false; |
| } |
| |
| while (is(KEY_CHARACTERS)) { |
| res = true; |
| parseOption(); |
| } |
| section.done(SECTION); |
| |
| if (is(VALUE_CHARACTERS)) { |
| advance(); |
| error("Key expected."); |
| } |
| while (is(VALUE_CHARACTERS)) { |
| skipLine(); |
| } |
| |
| return res; |
| } |
| |
| private void parseOption() { |
| PsiBuilder.Marker option = myBuilder.mark(); |
| if (is(KEY_CHARACTERS)) { |
| doneAdvance(mark(), KEY); |
| } |
| if (is(KEY_VALUE_SEPARATOR)) { |
| advance(); |
| } |
| else { |
| error(": or = expected."); |
| } |
| |
| PsiBuilder.Marker value = mark(); |
| while (is(VALUE_CHARACTERS)) { |
| doneAdvance(mark(), VALUE_LINE); |
| } |
| value.done(VALUE); |
| option.done(OPTION); |
| } |
| |
| private boolean parseSectionHeader() { |
| if (is(LBRACKET)) { |
| |
| advance(); |
| PsiBuilder.Marker sectionName = mark(); |
| boolean flag = false; |
| while (is(SECTION_NAME)) { |
| advance(); |
| flag = true; |
| } |
| |
| if (flag) { |
| sectionName.done(SECTION_NAME); |
| } |
| else { |
| sectionName.drop(); |
| return false; |
| } |
| |
| if (is(RBRACKET)) { |
| advance(); |
| } |
| else { |
| error("] expected."); |
| skipLine(); |
| } |
| |
| return true; |
| } |
| return false; |
| } |
| |
| private boolean is(IElementType type) { |
| return myBuilder.getTokenType() == type; |
| } |
| |
| private void error(String message) { |
| myBuilder.error(message); |
| } |
| |
| private PsiBuilder.Marker mark() { |
| return myBuilder.mark(); |
| } |
| |
| |
| public void doneAdvance(PsiBuilder.Marker marker, IElementType element) { |
| myBuilder.advanceLexer(); |
| marker.done(element); |
| } |
| |
| public void advance() { |
| myBuilder.advanceLexer(); |
| } |
| |
| private void skipLine() { |
| while (!is(null) && !is(LBRACKET) && !is(KEY_CHARACTERS)) { |
| myBuilder.advanceLexer(); |
| } |
| } |
| } |
| } |