parser is cooler than a Pig Tail's!
[fedora-idea.git] / lang-impl / src / com / intellij / lang / pratt / PrattBuilderImpl.java
blob70c30c6d25fb3b7d219f0348cef182682d6b0e08
1 /*
2 * Copyright (c) 2000-2005 by JetBrains s.r.o. All Rights Reserved.
3 * Use is subject to license terms.
4 */
5 package com.intellij.lang.pratt;
7 import com.intellij.codeInsight.daemon.JavaErrorMessages;
8 import com.intellij.lang.PsiBuilder;
9 import com.intellij.lang.impl.PsiBuilderImpl;
10 import com.intellij.lexer.Lexer;
11 import com.intellij.openapi.util.Trinity;
12 import com.intellij.psi.tree.IElementType;
13 import org.jetbrains.annotations.NotNull;
14 import org.jetbrains.annotations.Nullable;
16 import java.util.LinkedList;
18 /**
19 * @author peter
21 public class PrattBuilderImpl extends PrattBuilder implements PrattBuilderFacade {
22 private final PrattBuilder myParentBuilder;
23 private final PsiBuilder myBuilder;
24 private final LinkedList<IElementType> myLeftSiblings = new LinkedList<IElementType>();
25 private boolean myParsingStarted;
26 private String myExpectedMessage;
27 private int myPriority = Integer.MIN_VALUE;
28 private MutableMarker myStartMarker;
30 private PrattBuilderImpl(final PsiBuilder builder, final PrattBuilder parent) {
31 myBuilder = builder;
32 myParentBuilder = parent;
35 public static PrattBuilderImpl createBuilder(final PsiBuilder builder) {
36 return new PrattBuilderImpl(builder, null);
39 public PrattBuilderFacade expecting(final String expectedMessage) {
40 myExpectedMessage = expectedMessage;
41 return this;
44 public PrattBuilderFacade withLowestPriority(final int priority) {
45 myPriority = priority;
46 return this;
49 public Lexer getLexer() {
50 return ((PsiBuilderImpl) myBuilder).getLexer();
53 public MutableMarker mark() {
54 return new MutableMarker(myLeftSiblings, myBuilder.mark(), myLeftSiblings.size());
57 @Nullable
58 public IElementType parse() {
59 checkParsed();
60 return myLeftSiblings.size() != 1 ? null : myLeftSiblings.getLast();
63 protected PrattBuilderFacade createChildBuilder() {
64 assert myParsingStarted;
65 return new PrattBuilderImpl(myBuilder, this) {
66 protected void doParse() {
67 super.doParse();
68 PrattBuilderImpl.this.myLeftSiblings.addAll(getResultTypes());
73 protected void doParse() {
74 if (isEof()) {
75 error(myExpectedMessage != null ? myExpectedMessage : JavaErrorMessages.message("unexpected.eof"));
76 return;
79 TokenParser parser = findParser();
80 if (parser == null) {
81 error(myExpectedMessage != null ? myExpectedMessage : JavaErrorMessages.message("unexpected.token"));
82 return;
85 myStartMarker = mark();
86 while (!isEof()) {
87 int startOffset = myBuilder.getCurrentOffset();
89 if (!parser.parseToken(this)) break;
91 assert startOffset < myBuilder.getCurrentOffset() : "Endless loop on " + getTokenType();
93 parser = findParser();
94 if (parser == null) break;
96 myStartMarker.drop();
99 @Nullable
100 private TokenParser findParser() {
101 final IElementType tokenType = getTokenType();
102 for (final Trinity<Integer, PathPattern, TokenParser> trinity : PrattRegistry.getParsers(tokenType)) {
103 if (trinity.first > myPriority && trinity.second.accepts(this)) {
104 return trinity.third;
107 return null;
110 public boolean assertToken(final PrattTokenType type, @NotNull final String errorMessage) {
111 return _checkToken(type, errorMessage);
114 public boolean checkToken(final PrattTokenType type) {
115 return _checkToken(type, null);
118 private boolean _checkToken(final PrattTokenType type, @Nullable String errorMessage) {
119 if (isToken(type)) {
120 advance();
121 return true;
123 if (errorMessage != null) {
124 error(errorMessage);
126 return false;
129 public void advance() {
130 myLeftSiblings.addLast(getTokenType());
131 myBuilder.advanceLexer();
134 public void error(final String errorText) {
135 final PsiBuilder.Marker marker = myBuilder.mark();
136 myBuilder.error(errorText);
137 marker.drop();
140 @Nullable
141 public IElementType getTokenType() {
142 return myBuilder.getTokenType();
145 @Nullable
146 public String getTokenText() {
147 return myBuilder.getTokenText();
150 public void reduce(@NotNull final IElementType type) {
151 myStartMarker.finish(type);
152 myStartMarker = myStartMarker.precede();
155 @NotNull
156 public LinkedList<IElementType> getResultTypes() {
157 checkParsed();
158 return myLeftSiblings;
161 private void checkParsed() {
162 if (!myParsingStarted) {
163 myParsingStarted = true;
164 doParse();
168 public PrattBuilder getParent() {
169 return myParentBuilder;
172 public int getPriority() {
173 return myPriority;