package oqube.muse;
import java.util.List;
import java.util.ArrayList;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.Iterator;
import fr.lifl.parsing.ParserListenerDelegate;
import java.io.Reader;
import fr.lifl.parsing.ParserConfiguration;
import fr.lifl.parsing.ParserListener;
import java.io.BufferedReader;
import java.util.Stack;
import fr.lifl.parsing.ParserException;
import fr.lifl.parsing.Parser;
import fr.lifl.parsing.ParserPosition;
import fr.lifl.parsing.Namespace;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@author@oqube
@version
public class MuseParser implements Parser {
private static final String EOL = System.getProperty("line.separator");
private ParserListenerDelegate delegate = new ParserListenerDelegate();
private Reader reader;
private StringBuffer tagContent;
private String currentTag;
private String[][] currentArgs;
public String getCurrentTag() {
return currentTag;
}
public void setCurrentTag(String currentTag, String[][] nv) {
this.currentTag = currentTag;
this.currentArgs = nv;
}
public Reader getReader() {
return reader;
}
private boolean debug = false;
private static Log log = LogFactory.getLog(MuseParser.class);
public static Log getLog() {
return log;
}
public static void setLog(Log log) {
MuseParser.log = log;
}
private State state;
private Stack states = new Stack();
private MuseSink sink;
public MuseSink getSink() {
return sink;
}
public void setSink(MuseSink sink) {
this.sink = strong;
strong.setWrappedSink(sink);
}
private State push(int st, int col) {
states.push(state);
if (state != null) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < col; i++)
sb.append(' ');
sb.append(state.state).append(" > ").append(st);
if (log.isDebugEnabled())
log.debug(sb);
}
return state = new State(st, col);
}
private State pop() {
State s = state;
state = (State) states.pop();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < state.col; i++)
sb.append(' ');
sb.append(state.state).append(" < ").append(s.state);
if (log.isDebugEnabled()) {
log.debug(sb);
}
return s;
}
private ParserPosition pos;
public ParserPosition getPos() {
return pos;
}
public void setPos(ParserPosition pos) {
this.pos = pos;
}
private AbstractLexer paralex = new AbstractLexer("^(\\S+.*)$") {
public void handler() {
switch (state.state) {
case para:
sink.text(matcher.group(1));
break;
case top:
sink.startPara();
sink.text(matcher.group(1));
push(para, 0);
break;
case tab:
pop();
handler();
break;
case item:
pop();
sink.endItem();
handler();
break;
case list:
pop();
sink.endList();
handler();
break;
case enums:
pop();
sink.endEnums();
handler();
break;
case quote:
pop();
sink.endQuote();
handler();
break;
case table:
pop();
sink.endTable();
handler();
break;
case center:
pop();
sink.endCenter();
handler();
break;
case head:
pop();
sink.endHeader();
sink.startBody();
handler();
break;
case tag:
tagContent.append(matcher.group(0)).append(EOL);
return;
default:
throw new ParserException("Invalid paragraph line " + matcher.group(1)
+ " @(" + pos + ")");
}
}
};
abstract class ItemLexer extends AbstractLexer {
ItemLexer(String pat) {
super(pat);
}
protected void handle(int type) {
if (state.state == tag) {
tagContent.append(matcher.group(0)).append(EOL);
return;
}
int c = matcher.group(1).length();
if (c > state.col) {
push(type, c);
push(item, c);
if (type == list)
sink.startList();
else if (type == enums)
sink.startEnums();
c += matcher.group(2).length();
push(tab, c);
sink.startItem();
sink.text(matcher.group(3));
} else if (c < state.col) {
State s = pop();
switch (s.state) {
case para:
sink.endPara();
break;
case head:
sink.endHeader();
sink.startBody();
break;
case tab:
break;
case item:
sink.endItem();
break;
case list:
sink.endList();
break;
case enums:
sink.endEnums();
break;
case quote:
sink.endQuote();
break;
case center:
sink.endCenter();
case table:
sink.endTable();
break;
default:
throw new ParserException("invalid indentation of list item "
+ matcher.group(0) + " @(" + pos + ")");
}
handler();
} else {
assert c == state.col;
while (state.state != item) {
switch (state.state) {
case tab:
pop();
handler();
return;
default:
throw new ParserException("Invalid indentation of list item "
+ matcher.group(0) + " at " + pos
+ ": should be at least one space further right");
}
}
sink.endItem();
c += matcher.group(2).length();
push(tab, c);
sink.startItem();
sink.text(matcher.group(3));
}
}
};
private AbstractLexer listlex = new ItemLexer("(\\s+)(-\\s+)(.*)") {
public void handler() {
handle(list);
}
};
private AbstractLexer enumlex = new ItemLexer("(\\s+)(\\d+\\.\\s+)(.*)") {
public void handler() {
handle(enums);
}
};
private AbstractLexer blanklex = new AbstractLexer("(\\s+)(\\S.*)") {
public void handler() {
int ws = matcher.group(1).length();
switch (state.state) {
case top:
case item:
case para:
case tab:
if (ws >= 6 + state.col) {
sink.startCenter();
push(center, ws);
} else if (ws > state.col) {
sink.startQuote();
push(quote, ws);
}
if (ws < state.col)
throw new ParserException("Incorrect indentation line "
+ matcher.group(1) + "in state " + state + " @(" + pos + ")");
sink.text(matcher.group(2));
break;
case quote:
case center:
if (ws < state.col)
throw new ParserException("Incorrect indentation line "
+ matcher.group(1) + "in state " + state + " @(" + pos + ")");
sink.text(matcher.group(2));
break;
case head:
pop();
sink.endHeader();
sink.startBody();
handler();
break;
case tag:
tagContent.append(matcher.group(0)).append(EOL);
return;
default:
throw new ParserException("Unexpected whitespace starting line "
+ matcher.group(1) + "in state " + state + " @(" + pos + ")");
}
}
};
private AbstractLexer emptylex = new AbstractLexer("^\\s*$") {
public void handler() {
while (state.state != top) {
assert !states.isEmpty();
switch (state.state) {
case para:
sink.endPara();
break;
case list:
sink.endList();
break;
case quote:
sink.endQuote();
break;
case center:
sink.endCenter();
break;
case enums:
sink.endEnums();
break;
case item:
sink.endItem();
break;
case head:
sink.endHeader();
sink.startBody();
break;
case tab:
break;
case table:
sink.endTable();
break;
case tag:
tagContent.append(EOL).append(EOL);
return;
default:
throw new ParserException("Unexpected empty line in state " + state
+ " @" + pos + "");
}
pop();
}
assert state.state == top;
}
};
private AbstractLexer headerlex = new AbstractLexer("^(\\*+)\\s+(\\S+.*)$") {
public void handler() {
switch (state.state) {
case head:
pop();
sink.endHeader();
sink.startBody();
break;
case tag:
tagContent.append(matcher.group(0)).append(EOL);
return;
}
if (state.state != top)
throw new ParserException("Cannot use header inside blocks: "
+ matcher.group(0) + " in state " + state.state + " @" + pos + "");
int lvl = matcher.group(1