Skip to content

Commit

Permalink
Improve WORD primitive (#201)
Browse files Browse the repository at this point in the history
* Finish collecting characters if new line.
* Use parentheses as comment indicator.
* Fix processing whole lines of comment
  • Loading branch information
bahmanm authored Dec 15, 2024
1 parent 3c62261 commit 6332d1a
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 3 deletions.
21 changes: 18 additions & 3 deletions bjforth/src/main/java/bjforth/primitives/WORD.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
*/
package bjforth.primitives;

import static bjforth.primitives.PrimitiveFactory.KEY;

import bjforth.machine.Machine;
import bjforth.machine.MachineException;

class WORD implements Primitive {

Expand All @@ -32,15 +35,18 @@ private static enum State {
@Override
public void execute(Machine machine) {
var state = State.BEGIN;
var keyWord = PrimitiveFactory.KEY();
var result = new StringBuilder();
int parenthesesCount = 0;
while (state != State.END) {
keyWord.execute(machine);
KEY().execute(machine);
var ch = (int) machine.popFromParameterStack();
switch (state) {
case BEGIN:
if (ch == '\\') {
state = State.IN_COMMENT;
} else if (ch == '(') {
state = State.IN_COMMENT;
parenthesesCount += 1;
} else if (ch != ' ' && ch != '\n') {
result.appendCodePoint(ch);
state = State.IN_WORD;
Expand All @@ -49,10 +55,19 @@ public void execute(Machine machine) {
case IN_COMMENT:
if (ch == '\n') {
state = State.BEGIN;
} else if (ch == ')') {
if (parenthesesCount > 0) {
parenthesesCount -= 1;
} else {
throw new MachineException("Imbalanced parentheses.");
}
if (parenthesesCount == 0) {
state = State.BEGIN;
}
}
break;
case IN_WORD:
if (ch == ' ') {
if (ch == ' ' || ch == '\t' || ch == '\n') {
state = State.END;
} else {
result.appendCodePoint(ch);
Expand Down
42 changes: 42 additions & 0 deletions bjforth/src/test/java/bjforth/primitives/WORDTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,46 @@ void skipsComments() {
// THEN
assertThat(actualState).hasParameterStackEqualTo(aParameterStack().with(wordStr).build());
}

@DisplayName("Finish collecting characters if current character is new line.")
@Test
void endsWordWhenNewLine() {
// GIVEN
var wordStr = RandomStringUtils.randomAlphanumeric(10);
var str = wordStr + '\n';
var inputStream = new ByteArrayInputStream(str.getBytes());
System.setIn(inputStream);

var WORDaddr = getPrimitiveAddress("WORD");
var actualState = aMachineState().withInstrcutionPointer(WORDaddr).build();
var machine = aMachine().withState(actualState).build();
var referenceState = aMachineState().copyFrom(actualState).build();

// WHEN
machine.step();

// THEN
assertThat(actualState).hasParameterStackEqualTo(aParameterStack().with(wordStr).build());
}

@DisplayName("Treat balanced pairs of parentheses and the content between them as comments.")
@Test
void parensAsComments() {
// GIVEN
var wordStr = RandomStringUtils.randomAlphanumeric(10);
var str = wordStr + " ( this is a comment)" + '\n';
var inputStream = new ByteArrayInputStream(str.getBytes());
System.setIn(inputStream);

var WORDaddr = getPrimitiveAddress("WORD");
var actualState = aMachineState().withInstrcutionPointer(WORDaddr).build();
var machine = aMachine().withState(actualState).build();
var referenceState = aMachineState().copyFrom(actualState).build();

// WHEN
machine.step();

// THEN
assertThat(actualState).hasParameterStackEqualTo(aParameterStack().with(wordStr).build());
}
}

0 comments on commit 6332d1a

Please sign in to comment.