summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java36
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenIterator.java4
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserNamespaceTests.java27
3 files changed, 66 insertions, 1 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java
index 53a852e..106a101 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java
@@ -6,7 +6,10 @@ import org.zwobble.hobgoblin.compiler.sources.Source;
import org.zwobble.hobgoblin.compiler.types.NamespaceName;
import org.zwobble.sourcetext.SourcePosition;
+import java.util.ArrayList;
import java.util.List;
+import java.util.function.BooleanSupplier;
+import java.util.function.Supplier;
public class Parser {
private Parser() {
@@ -18,12 +21,18 @@ public class Parser {
) {
var start = tokens.startPosition();
+ var body = parseMany(
+ () -> tokens.isNext(TokenType.END),
+ () -> parseNamespaceStatement(tokens),
+ () -> true
+ );
+
var end = tokens.endPosition();
var source = createSource(start, end);
return new UntypedNamespaceNode(
namespaceName,
- List.of(),
+ body,
source
);
}
@@ -63,6 +72,31 @@ public class Parser {
);
}
+ /**
+ * Parse zero, one, or many instances of {@code T} using {@code parseOne}.
+ * Each instance is expected to be separated by tokens consumed by
+ * {@code parseSeparator}. Parsing stops either if {@code parseSeparator}
+ * returns false, or if {@code stop} returns false. Trailing separators
+ * are permitted.
+ */
+ private static <T> List<T> parseMany(
+ BooleanSupplier stop,
+ Supplier<T> parseOne,
+ BooleanSupplier parseSeparator
+ ) {
+ var values = new ArrayList<T>();
+
+ while (!stop.getAsBoolean()) {
+ var value = parseOne.get();
+ values.add(value);
+ if (!parseSeparator.getAsBoolean()) {
+ return values;
+ }
+ }
+
+ return values;
+ }
+
private static Source createSource(SourcePosition start, SourcePosition end) {
return new FileFragmentSource(start.to(end));
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenIterator.java b/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenIterator.java
index 4479043..a66ec35 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenIterator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenIterator.java
@@ -19,6 +19,10 @@ public class TokenIterator {
return this.getAbsolute(this.tokenIndex);
}
+ public boolean isNext(TokenType tokenType) {
+ return this.peek().tokenType().equals(tokenType);
+ }
+
public Token next(TokenType tokenType) {
var token = peek();
if (token.tokenType().equals(tokenType)) {
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserNamespaceTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserNamespaceTests.java
index e5796e4..22cddca 100644
--- a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserNamespaceTests.java
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserNamespaceTests.java
@@ -2,6 +2,7 @@ package org.zwobble.hobgoblin.compiler.parser;
import org.junit.jupiter.api.Test;
import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNamespaceNode;
+import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode;
import org.zwobble.hobgoblin.compiler.types.NamespaceName;
import static org.zwobble.hobgoblin.compiler.parser.ParserTesting.parseString;
@@ -24,4 +25,30 @@ public class ParserNamespaceTests {
has("body", x -> x.body(), isSequence())
));
}
+
+ @Test
+ public void bodyContainsStatements() {
+ var source = """
+ struct One {}
+ struct Two {}""";
+
+ var node = parseString(
+ source,
+ tokens -> Parser.parseNamespace(tokens, NamespaceName.of("Example", "Project"))
+ );
+
+ assertThat(node, instanceOf(
+ UntypedNamespaceNode.class,
+ has("body", UntypedNamespaceNode::body, isSequence(
+ instanceOf(
+ UntypedStructDefinitionNode.class,
+ has("name", UntypedStructDefinitionNode::name, equalTo("One"))
+ ),
+ instanceOf(
+ UntypedStructDefinitionNode.class,
+ has("name", UntypedStructDefinitionNode::name, equalTo("Two"))
+ )
+ ))
+ ));
+ }
}