Tweaking to handle empty lines a bit better for #18.

This commit is contained in:
Rob Greene 2018-11-21 14:34:03 -06:00
parent c43baf9c15
commit ceecbd49fa
3 changed files with 96 additions and 20 deletions

View File

@ -1,6 +1,7 @@
package io.github.applecommander.bastools.api; package io.github.applecommander.bastools.api;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.Queue; import java.util.Queue;
import io.github.applecommander.bastools.api.model.Line; import io.github.applecommander.bastools.api.model.Line;
@ -24,26 +25,27 @@ public class Parser {
public Program parse() { public Program parse() {
Program program = new Program(); Program program = new Program();
while (!tokens.isEmpty()) { while (!tokens.isEmpty()) {
Line line = readLine(program); readLine(program).ifPresent(program.lines::add);
program.lines.add(line);
} }
return program; return program;
} }
public Line readLine(Program program) { public Optional<Line> readLine(Program program) {
Line line = new Line(expectNumber(), program); return expectNumber().map(lineNumber -> {
while (!tokens.isEmpty() && tokens.peek().type != Type.EOL) { Line line = new Line(lineNumber, program);
Statement statement = readStatement(); while (!tokens.isEmpty() && tokens.peek().type != Type.EOL) {
if (statement != null) { Statement statement = readStatement();
line.statements.add(statement); if (statement != null) {
} else { line.statements.add(statement);
break; } else {
} break;
} }
if (!tokens.isEmpty() && tokens.peek().type == Type.EOL) { }
tokens.remove(); // Skip that EOL if (!tokens.isEmpty() && tokens.peek().type == Type.EOL) {
} tokens.remove(); // Skip that EOL
return line; }
return line;
});
} }
public Statement readStatement() { public Statement readStatement() {
@ -57,15 +59,14 @@ public class Parser {
return statement; return statement;
} }
public int expectNumber() { public Optional<Integer> expectNumber() {
Token c = tokens.remove(); Token c = tokens.remove();
while (c.type == Type.EOL) { while (c.type == Type.EOL) {
// Allow blank lines... return Optional.empty();
c = tokens.remove();
} }
if (c.type != Type.NUMBER) { if (c.type != Type.NUMBER) {
throw new RuntimeException("Expected a number in line #" + c.line); throw new RuntimeException("Expected a number in line #" + c.line);
} }
return c.number.intValue(); return Optional.of(c.number.intValue());
} }
} }

View File

@ -0,0 +1,25 @@
package io.github.applecommander.bastools.api;
import java.util.Queue;
import org.junit.Assert;
import org.junit.Test;
import io.github.applecommander.bastools.api.model.Program;
import io.github.applecommander.bastools.api.model.Token;
import io.github.applecommander.bastools.api.utils.TokenBuilder;
public class ParserTest {
@Test
public void testBlankLines() {
Queue<Token> tokens = TokenBuilder.builder()
.eol() // Blank line before
.number(10.0).ident("A").syntax('=').number(42.0).eol()
.eol() // Blank line after
.tokens();
Parser parser = new Parser(tokens);
Program program = parser.parse();
Assert.assertNotNull(program);
}
}

View File

@ -0,0 +1,50 @@
package io.github.applecommander.bastools.api.utils;
import java.util.LinkedList;
import java.util.Queue;
import io.github.applecommander.bastools.api.model.ApplesoftKeyword;
import io.github.applecommander.bastools.api.model.Token;
public class TokenBuilder {
private int lineNumber;
private Queue<Token> tokens = new LinkedList<Token>();
public static TokenBuilder builder() {
return new TokenBuilder();
}
public TokenBuilder eol() {
add(Token.eol(lineNumber));
lineNumber += 1;
return this;
}
public TokenBuilder number(Double number) {
return add(Token.number(lineNumber, number));
}
public TokenBuilder ident(String text) {
return add(Token.ident(lineNumber, text));
}
public TokenBuilder comment(String text) {
return add(Token.comment(lineNumber, text));
}
public TokenBuilder string(String text) {
return add(Token.string(lineNumber, text));
}
public TokenBuilder keyword(ApplesoftKeyword keyword) {
return add(Token.keyword(lineNumber, keyword));
}
public TokenBuilder syntax(int ch) {
return add(Token.syntax(lineNumber, ch));
}
public TokenBuilder directive(String text) {
return add(Token.directive(lineNumber, text));
}
private TokenBuilder add(Token token) {
tokens.add(token);
return this;
}
public Queue<Token> tokens() {
return tokens;
}
}