Skip to content

Commit

Permalink
Start reST parser implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
takahi-i committed May 3, 2017
1 parent 76c64c6 commit fd6cc25
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public abstract class LineParser extends BaseDocumentParser {
/**
* Target line of parser
*/
public class TargetLine {
static public class TargetLine {
// target line
public Line line;
// previous line of target line
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cc.redpen.parser.rest;

import cc.redpen.parser.common.Line;
import cc.redpen.parser.common.LineParser;

public class MultiLineProcessUtils {
static boolean processMultiLineMatch(Character prevChar, Character nextChar, LineParser.TargetLine target) {
Line prevLine = target.previousLine;
Line nextLine = target.nextLine;
if (prevChar != null && nextChar != null) {
return processLineMatch(nextChar, nextLine) && processLineMatch(prevChar, prevLine);
} else if (prevChar == null && nextChar != null) {
return processLineMatch(nextChar, nextLine);
} else if (prevChar != null && nextChar == null) {
return processLineMatch(prevChar, prevLine);
} else {
return false;
}
}

static private boolean processLineMatch(char ch, Line line) {
if (line == null) { return false; }
if (line.isAllSameCharacter() && (line.length() >= 4) && line.charAt(0) == ch) {
line.erase();
return true;
}
return false;
}
}
48 changes: 48 additions & 0 deletions redpen-core/src/main/java/cc/redpen/parser/rest/ReSTLine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package cc.redpen.parser.rest;

import cc.redpen.parser.common.Line;

public class ReSTLine extends Line {
/**
* Construct a line using the supplied string
*
* @param str the text of the line
* @param lineno the original line number
*/
public ReSTLine(String str, int lineno) {
super(str, lineno);
this.lineNo = lineno;
this.inlineMarkupDelimiters = " _*`#^~.,";
if (!str.isEmpty()) {
allSameCharacter = true;
char lastCh = 0;
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);

if ((i < str.length() - 1) && (ch == '\\')) {
i++;
ch = str.charAt(i);
escaped.add(true);
}
else {
escaped.add(false);
}

offsets.add(i);
characters.add(ch);
valid.add(true);

if ((lastCh != 0) && (lastCh != ch)) {
allSameCharacter = false;
}
lastCh = ch;
}
}

// trim the end
while (!characters.isEmpty() &&
Character.isWhitespace(characters.get(characters.size() - 1))) {
characters.remove(characters.size() - 1);
}
}
}
101 changes: 101 additions & 0 deletions redpen-core/src/main/java/cc/redpen/parser/rest/ReSTParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package cc.redpen.parser.rest;

import cc.redpen.parser.PreprocessingReader;
import cc.redpen.parser.common.Line;
import cc.redpen.parser.common.LineParser;
import cc.redpen.parser.common.Model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;

import static cc.redpen.parser.rest.MultiLineProcessUtils.processMultiLineMatch;

public class ReSTParser extends LineParser {
private static final Logger LOG = LoggerFactory.getLogger(ReSTParser.class);
/**
* current parser state
*/
private class State {
// are we in a block
public boolean inBlock = false;
// are we in a list?
public boolean inList = false;
// are we in a table?
public boolean inTable = false;
// should we erase lines within the current block?
public boolean eraseBlock = true;
// the sort of block we are in
public String type;
}

@Override
protected void populateModel(Model model, InputStream io) {
State state = new State();
PreprocessingReader reader = createReader(io);

int lineno = 0;
try {
// add the lines to the model
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
lineno++;
model.add(new ReSTLine(line, lineno));
}
reader.close();

model.setPreprocessorRules(reader.getPreprocessorRules());

for (model.rewind(); model.isMore(); model.getNextLine()) {
processLine(model.getCurrentLine(), model, state);
}
} catch (Exception e) {
e.printStackTrace();
LOG.error("Exception when parsing reST file", e);
}
if (LOG.isDebugEnabled()) {
LOG.debug("reST parser model (X=erased line,[=block,section-listlevel-lineno,*=list item):\n" + model.toString());
}
}

private void processLine(Line line, Model model, State state) {
if (line.isErased()) { return; }

TargetLine target = new TargetLine(line,
model.getLine(line.getLineNo() - 1),
model.getLine(line.getLineNo() + 1));

// handle section
int level = extractSectionLevel(target);
if (level > 0) {line.setSectionLevel(level);}
}

private int extractSectionLevel(TargetLine target) {
if (processMultiLineMatch('#', '#', target)) {
return 1;
} if (processMultiLineMatch('*', '*', target)) {
return 2;
} else if (processMultiLineMatch('=', '=', target)) {
return 3;
} else if (processMultiLineMatch(null, '=', target)) {
return 4;
} else if (processMultiLineMatch('-', '-', target)) { // this is a subtitle?
return 0;
} else if (processMultiLineMatch(null, '-', target)) {
return 5;
} else if (processMultiLineMatch('~', '~', target)) {
return 6;
} else if (processMultiLineMatch(null, '~', target)) {
return 7;
} else if (processMultiLineMatch('^', '^', target)) {
return 8;
} else if (processMultiLineMatch(null, '^', target)) {
return 9;
}
return -1;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cc.redpen.parser.rest;

import cc.redpen.parser.common.LineParser;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class MultiLineProcessUtilsTest {
@Test
public void testDetectThreeLineHeader() {
LineParser.TargetLine target = new LineParser.TargetLine(
new ReSTLine("This is a part", 1),
new ReSTLine("#############", 0),
new ReSTLine("#############", 2));
assertEquals(true, MultiLineProcessUtils.processMultiLineMatch('#', '#', target));
}

@Test
public void testDetectTwoLineHeader() {
LineParser.TargetLine target = new LineParser.TargetLine(
new ReSTLine("This is a part", 1),
new ReSTLine("", 0),
new ReSTLine("#############", 2));
assertEquals(true, MultiLineProcessUtils.processMultiLineMatch(null, '#', target));
}
}

0 comments on commit fd6cc25

Please sign in to comment.