aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2025-01-12 21:25:32 +0000
committerMichael Williamson <mike@zwobble.org>2025-01-12 21:25:32 +0000
commit6f554d8e265ad2664c97d9d8d6efef2f53e9eb5f (patch)
tree8d2453bd70ce1143be425448a16c4a93d8767461 /src
parenteef0470389d88de6169a6962f14a9d422175e4c2 (diff)
Parse native function declarations
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/shedlang/compiler/ast/untyped/UntypedNamespaceStatementNode.java2
-rw-r--r--src/main/java/org/shedlang/compiler/ast/untyped/UntypedNativeFunctionDeclarationNode.java104
-rw-r--r--src/main/java/org/shedlang/compiler/parser/Parser.java32
-rw-r--r--src/main/java/org/shedlang/compiler/parser/TokenType.java1
-rw-r--r--src/main/java/org/shedlang/compiler/parser/Tokeniser.java1
-rw-r--r--src/main/java/org/shedlang/compiler/typechecker/DeclaredVariables.java6
-rw-r--r--src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java7
-rw-r--r--src/test/java/org/shedlang/compiler/ast/untyped/UntypedNativeFunctionDeclarationNodeMatcher.java52
-rw-r--r--src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java4
-rw-r--r--src/test/java/org/shedlang/compiler/parser/ParserNativeFunctionDeclarationTests.java60
10 files changed, 268 insertions, 1 deletions
diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedNamespaceStatementNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedNamespaceStatementNode.java
index 8d94d5b8..c4981b68 100644
--- a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedNamespaceStatementNode.java
+++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedNamespaceStatementNode.java
@@ -1,4 +1,4 @@
package org.shedlang.compiler.ast.untyped;
-public sealed interface UntypedNamespaceStatementNode extends UntypedNode permits UntypedAssignNode, UntypedEffectDefinitionNode, UntypedFunctionDefinitionNode, UntypedStructDefinitionNode, UntypedSumTypeDefinitionNode {
+public sealed interface UntypedNamespaceStatementNode extends UntypedNode permits UntypedAssignNode, UntypedEffectDefinitionNode, UntypedFunctionDefinitionNode, UntypedNativeFunctionDeclarationNode, UntypedStructDefinitionNode, UntypedSumTypeDefinitionNode {
}
diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedNativeFunctionDeclarationNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedNativeFunctionDeclarationNode.java
new file mode 100644
index 00000000..989d6044
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedNativeFunctionDeclarationNode.java
@@ -0,0 +1,104 @@
+package org.shedlang.compiler.ast.untyped;
+
+import org.shedlang.compiler.sources.Source;
+import org.shedlang.compiler.sources.Sources;
+import org.shedlang.compiler.types.Visibility;
+
+import java.util.Optional;
+
+public record UntypedNativeFunctionDeclarationNode(
+ String name,
+ Visibility visibility,
+ UntypedFunctionSignatureNode signature,
+ Source source
+) implements UntypedNamespaceStatementNode, UntypedVariableDeclarationNode {
+ public static Builder builder() {
+ return new Builder(
+ "f",
+ Visibility.PRIVATE,
+ UntypedFunctionSignatureNode.builder()
+ );
+ }
+
+ public record Builder(
+ String name,
+ Visibility visibility,
+ UntypedFunctionSignatureNode.Builder signature
+ ) {
+ public UntypedNativeFunctionDeclarationNode build() {
+ return new UntypedNativeFunctionDeclarationNode(
+ name,
+ visibility,
+ signature.build(),
+ Sources.NULL
+ );
+ }
+
+ public Builder withName(String name) {
+ return new Builder(
+ name,
+ this.visibility,
+ this.signature
+ );
+ }
+
+ public Builder addPositionalParam(String name, UntypedTypeLevelExpressionNode type) {
+ return addPositionalParam(name, Optional.of(type));
+ }
+
+ public Builder addPositionalParam(
+ String name,
+ Optional<UntypedTypeLevelExpressionNode> type
+ ) {
+ return new Builder(
+ this.name,
+ this.visibility,
+ this.signature.addPositionalParam(name, type)
+ );
+ }
+
+ public Builder addNamedParam(String name, UntypedTypeLevelExpressionNode type) {
+ return new Builder(
+ this.name,
+ this.visibility,
+ this.signature.addNamedParam(name, type)
+ );
+ }
+
+ public Builder withEffect(UntypedTypeLevelExpressionNode effect) {
+ return new Builder(
+ this.name,
+ this.visibility,
+ this.signature.withEffect(effect)
+ );
+ }
+
+ public Builder withReturnTypeUnit() {
+ return withReturnType(new UntypedTypeLevelReferenceNode("Unit", Sources.NULL));
+ }
+
+ public Builder withReturnType(UntypedTypeLevelExpressionNode returnType) {
+ return new Builder(
+ this.name,
+ this.visibility,
+ this.signature.withReturnType(returnType)
+ );
+ }
+
+ public Builder withoutReturnType() {
+ return new Builder(
+ this.name,
+ this.visibility,
+ this.signature.withoutReturnType()
+ );
+ }
+
+ public Builder withVisibility(Visibility visibility) {
+ return new Builder(
+ this.name,
+ visibility,
+ this.signature
+ );
+ }
+ }
+}
diff --git a/src/main/java/org/shedlang/compiler/parser/Parser.java b/src/main/java/org/shedlang/compiler/parser/Parser.java
index cda360e3..45533683 100644
--- a/src/main/java/org/shedlang/compiler/parser/Parser.java
+++ b/src/main/java/org/shedlang/compiler/parser/Parser.java
@@ -776,6 +776,9 @@ public class Parser {
case KEYWORD_FUN ->
parseFunctionDefinition(tokens);
+ case KEYWORD_NATIVE ->
+ parseNativeFunctionDeclaration(tokens);
+
case KEYWORD_PUB ->
switch (tokens.peek(1).tokenType()) {
case KEYWORD_EFFECT ->
@@ -784,6 +787,9 @@ public class Parser {
case KEYWORD_FUN ->
parseFunctionDefinition(tokens);
+ case KEYWORD_NATIVE ->
+ parseNativeFunctionDeclaration(tokens);
+
case KEYWORD_STRUCT ->
parseStructDefinition(tokens);
@@ -811,6 +817,32 @@ public class Parser {
};
}
+ private static UntypedNativeFunctionDeclarationNode parseNativeFunctionDeclaration(
+ TokenIterator<TokenType> tokens
+ ) {
+ var start = tokens.startPosition();
+
+ var visibility = parseVisibility(tokens);
+
+ tokens.skip(TokenType.KEYWORD_NATIVE);
+ tokens.skip(TokenType.KEYWORD_FUN);
+ var name = tokens.nextValue(TokenType.IDENTIFIER);
+
+ var signature = parseFunctionSignature(tokens);
+
+ tokens.skip(TokenType.SYMBOL_SEMICOLON);
+
+ var end = tokens.endPosition();
+ var source = new FileFragmentSource(start.to(end));
+
+ return new UntypedNativeFunctionDeclarationNode(
+ name,
+ visibility,
+ signature,
+ source
+ );
+ }
+
private static UntypedParamsNode parseParams(TokenIterator<TokenType> tokens) {
var paramsStart = tokens.startPosition();
diff --git a/src/main/java/org/shedlang/compiler/parser/TokenType.java b/src/main/java/org/shedlang/compiler/parser/TokenType.java
index dbe32b0d..5eee208c 100644
--- a/src/main/java/org/shedlang/compiler/parser/TokenType.java
+++ b/src/main/java/org/shedlang/compiler/parser/TokenType.java
@@ -21,6 +21,7 @@ public enum TokenType {
KEYWORD_IF,
KEYWORD_IMPORT,
KEYWORD_IS,
+ KEYWORD_NATIVE,
KEYWORD_PUB,
KEYWORD_RESUME,
KEYWORD_RETURN,
diff --git a/src/main/java/org/shedlang/compiler/parser/Tokeniser.java b/src/main/java/org/shedlang/compiler/parser/Tokeniser.java
index dfac78a0..6e5bed3f 100644
--- a/src/main/java/org/shedlang/compiler/parser/Tokeniser.java
+++ b/src/main/java/org/shedlang/compiler/parser/Tokeniser.java
@@ -25,6 +25,7 @@ public class Tokeniser {
Map.entry("if", TokenType.KEYWORD_IF),
Map.entry("import", TokenType.KEYWORD_IMPORT),
Map.entry("is", TokenType.KEYWORD_IS),
+ Map.entry("native", TokenType.KEYWORD_NATIVE),
Map.entry("pub", TokenType.KEYWORD_PUB),
Map.entry("resume", TokenType.KEYWORD_RESUME),
Map.entry("return", TokenType.KEYWORD_RETURN),
diff --git a/src/main/java/org/shedlang/compiler/typechecker/DeclaredVariables.java b/src/main/java/org/shedlang/compiler/typechecker/DeclaredVariables.java
index 2a842d93..a2a8b253 100644
--- a/src/main/java/org/shedlang/compiler/typechecker/DeclaredVariables.java
+++ b/src/main/java/org/shedlang/compiler/typechecker/DeclaredVariables.java
@@ -104,6 +104,12 @@ class DeclaredVariables {
functionDefinition
));
+ case UntypedNativeFunctionDeclarationNode nativeFunctionDeclaration ->
+ variables.plus(DeclaredVariable.fromNode(
+ VariableType.CONSTANT,
+ nativeFunctionDeclaration
+ ));
+
case UntypedStructDefinitionNode struct ->
variables.plus(DeclaredVariable.fromNode(
VariableType.CONSTANT,
diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java
index daee11c4..4486e457 100644
--- a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java
+++ b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java
@@ -1484,6 +1484,10 @@ public class TypeChecker {
);
}
+ case UntypedNativeFunctionDeclarationNode untypedNativeFunctionDeclaration -> {
+ throw new UnsupportedOperationException("TODO");
+ }
+
case UntypedStructDefinitionNode untypedStruct -> {
dependencyChecker = dependencyChecker.addDeferredDependencies(
untypedStruct.name(),
@@ -1556,6 +1560,9 @@ public class TypeChecker {
case UntypedFunctionDefinitionNode functionDefinition ->
typeCheckStepsFunctionDefinition(functionDefinition);
+ case UntypedNativeFunctionDeclarationNode nativeFunctionDeclaration ->
+ throw new UnsupportedOperationException("TODO");
+
case UntypedStructDefinitionNode structDefinition ->
typeCheckStepsStructDefinition(structDefinition);
diff --git a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNativeFunctionDeclarationNodeMatcher.java b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNativeFunctionDeclarationNodeMatcher.java
new file mode 100644
index 00000000..9eb338fd
--- /dev/null
+++ b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNativeFunctionDeclarationNodeMatcher.java
@@ -0,0 +1,52 @@
+package org.shedlang.compiler.ast.untyped;
+
+import org.pcollections.Empty;
+import org.pcollections.PVector;
+import org.shedlang.compiler.testing.MatcherBuilder;
+import org.shedlang.compiler.types.Visibility;
+import org.zwobble.precisely.Matcher;
+
+import static org.zwobble.precisely.Matchers.equalTo;
+import static org.zwobble.precisely.Matchers.has;
+
+public class UntypedNativeFunctionDeclarationNodeMatcher extends MatcherBuilder<
+ UntypedNamespaceStatementNode,
+ UntypedNativeFunctionDeclarationNode,
+ UntypedNativeFunctionDeclarationNodeMatcher
+> {
+ public static UntypedNativeFunctionDeclarationNodeMatcher empty() {
+ return new UntypedNativeFunctionDeclarationNodeMatcher(Empty.vector());
+ }
+
+ public UntypedNativeFunctionDeclarationNodeMatcher(
+ PVector<Matcher<? super UntypedNativeFunctionDeclarationNode>> submatchers
+ ) {
+ super(submatchers);
+ }
+
+ @Override
+ protected Class<UntypedNativeFunctionDeclarationNode> expectedType() {
+ return UntypedNativeFunctionDeclarationNode.class;
+ }
+
+ @Override
+ protected UntypedNativeFunctionDeclarationNodeMatcher create(
+ PVector<Matcher<? super UntypedNativeFunctionDeclarationNode>> submatchers
+ ) {
+ return new UntypedNativeFunctionDeclarationNodeMatcher(submatchers);
+ }
+
+ public UntypedNativeFunctionDeclarationNodeMatcher withSignature(
+ Matcher<? super UntypedFunctionSignatureNode> signature
+ ) {
+ return with(has("signature", x -> x.signature(), signature));
+ }
+
+ public UntypedNativeFunctionDeclarationNodeMatcher withName(String name) {
+ return with(has("name", x -> x.name(), equalTo(name)));
+ }
+
+ public UntypedNativeFunctionDeclarationNodeMatcher withVisibility(Visibility visibility) {
+ return with(has("visibility", x -> x.visibility(), equalTo(visibility)));
+ }
+}
diff --git a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java
index 0e11231b..94fc68e1 100644
--- a/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java
+++ b/src/test/java/org/shedlang/compiler/ast/untyped/UntypedNodeMatchers.java
@@ -235,6 +235,10 @@ public class UntypedNodeMatchers {
);
}
+ public static UntypedNativeFunctionDeclarationNodeMatcher isUntypedNativeFunctionDeclarationNode() {
+ return UntypedNativeFunctionDeclarationNodeMatcher.empty();
+ }
+
public static Matcher<UntypedExpressionNode> isUntypedNotEqualNode(
Matcher<UntypedExpressionNode> left,
Matcher<UntypedExpressionNode> right
diff --git a/src/test/java/org/shedlang/compiler/parser/ParserNativeFunctionDeclarationTests.java b/src/test/java/org/shedlang/compiler/parser/ParserNativeFunctionDeclarationTests.java
new file mode 100644
index 00000000..f11a673c
--- /dev/null
+++ b/src/test/java/org/shedlang/compiler/parser/ParserNativeFunctionDeclarationTests.java
@@ -0,0 +1,60 @@
+package org.shedlang.compiler.parser;
+
+import org.junit.jupiter.api.Test;
+import org.shedlang.compiler.types.Visibility;
+
+import static org.shedlang.compiler.ast.untyped.UntypedNodeMatchers.*;
+import static org.shedlang.compiler.parser.ParserTesting.parseString;
+import static org.zwobble.precisely.AssertThat.assertThat;
+import static org.zwobble.precisely.Matchers.isOptionalEmpty;
+import static org.zwobble.precisely.Matchers.isSequence;
+
+public class ParserNativeFunctionDeclarationTests {
+ @Test
+ public void canParseMinimalFunction() {
+ var source = """
+ native fun f() -> Unit;""";
+
+ var node = parseString(source, Parser::parseNamespaceStatement);
+
+ assertThat(
+ node,
+ isUntypedNativeFunctionDeclarationNode()
+ .withName("f")
+ .withSignature(
+ isUntypedFunctionSignatureNode()
+ .withParams(isUntypedParamsNode(isSequence(), isSequence()))
+ .withEffect(isOptionalEmpty())
+ .withReturnType(isUntypedTypeLevelReferenceNode("Unit"))
+ )
+ );
+ }
+
+ @Test
+ public void defaultVisibilityIsPrivate() {
+ var source = """
+ native fun f() -> Unit;""";
+
+ var node = parseString(source, Parser::parseNamespaceStatement);
+
+ assertThat(
+ node,
+ isUntypedNativeFunctionDeclarationNode()
+ .withVisibility(Visibility.PRIVATE)
+ );
+ }
+
+ @Test
+ public void whenFunIsPrefixedWithPubThenVisibilityIsPublic() {
+ var source = """
+ pub native fun f() -> Unit;""";
+
+ var node = parseString(source, Parser::parseNamespaceStatement);
+
+ assertThat(
+ node,
+ isUntypedNativeFunctionDeclarationNode()
+ .withVisibility(Visibility.PUBLIC)
+ );
+ }
+}