Skip to content

Commit

Permalink
Merge pull request #34 from DarthKipsu/lang-syntax
Browse files Browse the repository at this point in the history
Language syntax parser plugin
  • Loading branch information
jamo committed Nov 6, 2015
2 parents e4410ac + cf7c78c commit fdad46d
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package fi.helsinki.cs.tmc.langs.domain;

import java.util.regex.Pattern;

/**
* Information about a language comment syntax used to parse solution and stub
* files with ExerciseBuilder.
*
* <p>Use CommentSyntaxBuilder for easy setup.
*/
public class CommentSyntax {

private final String beginSolutionRegex;
private final String capturingGroups;
private final String endSolutionRegex;
private final String solutionFileRegex;
private final String stubRegex;
private final Pattern stubReplacePattern;

private CommentSyntax(
String beginSolutionRegex,
String capturingGroups,
String endSolutionRegex,
String solutionFileRegex,
String stubRegex) {
this.beginSolutionRegex = beginSolutionRegex;
this.capturingGroups = capturingGroups;
this.endSolutionRegex = endSolutionRegex;
this.solutionFileRegex = solutionFileRegex;
this.stubRegex = stubRegex;

this.stubReplacePattern = Pattern.compile(stubRegex);
}

/**
* Will create a new Comment syntax with the specified comment syntaxes.
*
* <p>If no syntax is specified, will use single line comment syntax from
* Java.
*/
public static Builder newBuilder() {
return new Builder();
}

public String getBeginSolution() {
return beginSolutionRegex;
}

public String getCapturingGroups() {
return capturingGroups;
}

public String getEndSolution() {
return endSolutionRegex;
}

public String getSolutionFile() {
return solutionFileRegex;
}

public String getStub() {
return stubRegex;
}

public Pattern getStubReplacePattern() {
return stubReplacePattern;
}

/**
* Creates a new CommnetSyntax with the specifies language syntaxes.
*/
public static class Builder {

private static final String BEGIN_SOLUTION = "BEGIN[ \\t]+SOLUTION";
private static final String END_SOLUTION = "END[ \\t]+SOLUTION";
private static final String SOLUTION_FILE = "SOLUTION[ \\t]+FILE";
private static final String SPACES = "[ \\t]*";
private static final String STUB = "STUB:[ \\t]*";

private String beginCapturingGroups;
private String beginSolutionRegex;
private int capturingIndex;
private String endCapturingGroups;
private String endSolutionRegex;
private String solutionFileRegex;
private String stubRegex;

/**
* Creates a new CommentSyntac Builder.
*/
public Builder() {
beginCapturingGroups = "";
beginSolutionRegex = "";
capturingIndex = 2;
endCapturingGroups = "";
endSolutionRegex = "";
solutionFileRegex = "";
stubRegex = "";
}

/**
* Adds a single line comment to the comment syntax.
* @param singleLine Single line comment tag in Java regex format.
*/
public Builder addSingleLineComment(String singleLine) {
if (!beginSolutionRegex.isEmpty()) {
addOrPunctuations();
}
String lineStart = "((" + SPACES + ")" + singleLine + SPACES;

beginSolutionRegex += lineStart + BEGIN_SOLUTION + "(.*))";
endSolutionRegex += lineStart + END_SOLUTION + "(.*))";
solutionFileRegex += lineStart + SOLUTION_FILE + "(.*))";
stubRegex += lineStart + STUB + "(.*))";

increaseCapturingGroups();
return this;
}

/**
* Adds a multi line comment to the comment syntax.
* @param beginning Beginning tag for the multi line comment as Java
* regex.
* @param end End tag for the multi line comment as Java regex.
*/
public Builder addMultiLineComment(String beginning,
String end) {
if (!beginSolutionRegex.isEmpty()) {
addOrPunctuations();
}
String beginComment = "((" + SPACES + ")" + beginning + SPACES;
String endComment = SPACES + end + SPACES + ".*)";

beginSolutionRegex += beginComment + BEGIN_SOLUTION + endComment;
endSolutionRegex += beginComment + END_SOLUTION + endComment;
solutionFileRegex += beginComment + SOLUTION_FILE + endComment;
stubRegex += beginComment + STUB + "(.*[^ \\t])" + endComment;

increaseCapturingGroups();
return this;
}

/**
* Builds the CommentSyntax once all syntax tags have been given.
*/
public CommentSyntax build() {
if (beginSolutionRegex.isEmpty()) {
return new Builder()
.addSingleLineComment("\\/\\/")
.build();
}
return new CommentSyntax(
beginSolutionRegex,
beginCapturingGroups + endCapturingGroups,
endSolutionRegex,
solutionFileRegex,
stubRegex);
}

private void increaseCapturingGroups() {
beginCapturingGroups += "$" + capturingIndex++;
endCapturingGroups += "$" + capturingIndex++;
capturingIndex++;
}

private void addOrPunctuations() {
beginSolutionRegex += "|";
endSolutionRegex += "|";
solutionFileRegex += "|";
stubRegex += "|";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,30 @@

public class ExerciseBuilder {

private static final String BEGIN_SOLUTION_REGEX = "[ \\t]*\\/\\/[ \\t]*BEGIN[ \\t]+SOLUTION.*";
private static final String END_SOLUTION_REGEX = "[ \\t]*\\/\\/[ \\t]*END[ \\t]+SOLUTION.*";
private static final String SOLUTION_FILE_REGEX = "[ \\t]*\\/\\/[ \\t]*SOLUTION[ \\t]+FILE.*";
private static final String STUB_REGEX = "([ \\t]*)\\/\\/[ \\t]*STUB:[ \\t]*(.*)";
private static final String SOURCE_FOLDER_NAME = "src";
private static final Charset CHARSET = StandardCharsets.UTF_8;

private static final Logger logger = LoggerFactory.getLogger(ExerciseBuilder.class);
private static final Pattern stubReplacePattern = Pattern.compile(STUB_REGEX);

private String beginSolutionRegex;
private String capturingGroups;
private String endSolutionRegex;
private String solutionFileRegex;
private String stubRegex;
private Pattern stubReplacePattern;

public ExerciseBuilder() {
this(CommentSyntax.newBuilder().build());
}

public ExerciseBuilder(CommentSyntax commentSyntax) {
beginSolutionRegex = commentSyntax.getBeginSolution();
capturingGroups = commentSyntax.getCapturingGroups();
endSolutionRegex = commentSyntax.getEndSolution();
solutionFileRegex = commentSyntax.getSolutionFile();
stubRegex = commentSyntax.getStub();
stubReplacePattern = commentSyntax.getStubReplacePattern();
}

/**
* Prepares a stub exercise from the original.
Expand All @@ -45,17 +60,17 @@ private void prepareStubFile(Path file) {
List<String> filteredLines = new ArrayList<>();
boolean skipLine = false;
for (String line : lines) {
if (line.matches(SOLUTION_FILE_REGEX)) {
if (line.matches(solutionFileRegex)) {
Files.deleteIfExists(file);
return;
}
if (line.matches(BEGIN_SOLUTION_REGEX)) {
if (line.matches(beginSolutionRegex)) {
skipLine = true;
} else if (skipLine && line.matches(END_SOLUTION_REGEX)) {
} else if (skipLine && line.matches(endSolutionRegex)) {
skipLine = false;
} else if (line.matches(STUB_REGEX)) {
} else if (line.matches(stubRegex)) {
Matcher stubMatcher = stubReplacePattern.matcher(line);
filteredLines.add(stubMatcher.replaceAll("$1$2"));
filteredLines.add(stubMatcher.replaceAll(capturingGroups));
} else if (!skipLine) {
filteredLines.add(line);
}
Expand Down Expand Up @@ -108,10 +123,10 @@ private void prepareSolutionFile(Path file) {
List<String> lines = Files.readAllLines(file, CHARSET);
List<String> filteredLines = new ArrayList<>();
for (String line : lines) {
if (line.matches(BEGIN_SOLUTION_REGEX)
|| line.matches(END_SOLUTION_REGEX)
|| line.matches(STUB_REGEX)
|| line.matches(SOLUTION_FILE_REGEX)) {
if (line.matches(beginSolutionRegex)
|| line.matches(endSolutionRegex)
|| line.matches(stubRegex)
|| line.matches(solutionFileRegex)) {
continue;
}
filteredLines.add(line);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ public class ExerciseBuilderTest {

@Before
public void setUp() {
exerciseBuilder = new ExerciseBuilder();
exerciseBuilder = new ExerciseBuilder(CommentSyntax.newBuilder()
.addSingleLineComment("\\/\\/")
.addMultiLineComment("\\/\\*+", "\\*+\\/")
.build());
}

@Test
Expand Down Expand Up @@ -83,10 +86,12 @@ public void solutionFilesAreIgnoredFromStub() throws IOException {
Path solutionFile = temp.resolve(Paths.get("src", "SolutionFile.java"));
Path solutionFile2 = temp.resolve(Paths.get("src", "SolutionFileWithNoSpace.java"));
Path solutionFile3 = temp.resolve(Paths.get("src", "SolutionFileWithExtraSpaces.java"));
Path solutionFile4 = temp.resolve(Paths.get("src", "MultilineSolutionFile.java"));

assertFalse(solutionFile.toFile().exists());
assertFalse(solutionFile2.toFile().exists());
assertFalse(solutionFile3.toFile().exists());
assertFalse(solutionFile4.toFile().exists());
}

private Path createTemporaryCopyOf(Path path) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ public static int mul(int a, int b) {
}

public static int div(int a, int b) {
// BEGIN SOLUTION
/* BEGIN SOLUTION */
return a / b;
// END SOLUTION
// STUB: return 0;
/**END SOLUTION**/
/* STUB: return 0; */
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ public static int mul(int a, int b) {
}

public static int div(int a, int b) {
// BEGIN SOLUTION
/* BEGIN SOLUTION */
return a / b;
// END SOLUTION
// STUB: return 0;
/** END SOLUTION **/
/* STUB: return 0; */
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public class SolutionFile {
/* SOLUTION FILE */
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import fi.helsinki.cs.tmc.langs.AbstractLanguagePlugin;
import fi.helsinki.cs.tmc.langs.abstraction.ValidationResult;
import fi.helsinki.cs.tmc.langs.domain.CommentSyntax;
import fi.helsinki.cs.tmc.langs.domain.CompileResult;
import fi.helsinki.cs.tmc.langs.domain.ExerciseBuilder;
import fi.helsinki.cs.tmc.langs.domain.ExerciseDesc;
Expand Down Expand Up @@ -51,7 +52,10 @@ public abstract class AbstractJavaPlugin extends AbstractLanguagePlugin {
public AbstractJavaPlugin(
Path testFolderPath, SubmissionProcessor submissionProcessor, TestScanner testScanner) {
super(
new ExerciseBuilder(),
new ExerciseBuilder(CommentSyntax.newBuilder()
.addSingleLineComment("\\/\\/")
.addMultiLineComment("\\/\\*+", "\\*+\\/")
.build()),
submissionProcessor,
new StudentFileAwareZipper(),
new StudentFileAwareUnzipper());
Expand Down

0 comments on commit fdad46d

Please sign in to comment.