aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-10-22 22:23:01 +0100
committerMichael Williamson <mike@zwobble.org>2023-10-22 22:23:01 +0100
commitd1d0984bc8a157a2f001d3c991dae5c9498cd790 (patch)
tree89056dc50059c60c4ce1bf9aa18a8045fb282036 /src/main/java
parentbc94a020433c8b7dc0adaa2a6adf235da9c9b4e9 (diff)
Parse function types
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/shedlang/compiler/ast/untyped/UntypedFunctionTypeNode.java13
-rw-r--r--src/main/java/org/shedlang/compiler/ast/untyped/UntypedParamTypesNode.java12
-rw-r--r--src/main/java/org/shedlang/compiler/ast/untyped/UntypedTypeLevelExpressionNode.java2
-rw-r--r--src/main/java/org/shedlang/compiler/parser/Parser.java92
-rw-r--r--src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java3
5 files changed, 113 insertions, 9 deletions
diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedFunctionTypeNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedFunctionTypeNode.java
new file mode 100644
index 00000000..6d4d9502
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedFunctionTypeNode.java
@@ -0,0 +1,13 @@
+package org.shedlang.compiler.ast.untyped;
+
+import org.shedlang.compiler.sources.Source;
+
+import java.util.Optional;
+
+public record UntypedFunctionTypeNode(
+ UntypedParamTypesNode params,
+ Optional<UntypedTypeLevelExpressionNode> effect,
+ UntypedTypeLevelExpressionNode returnType,
+ Source source
+) implements UntypedTypeLevelExpressionNode {
+}
diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedParamTypesNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedParamTypesNode.java
new file mode 100644
index 00000000..60fa66c3
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedParamTypesNode.java
@@ -0,0 +1,12 @@
+package org.shedlang.compiler.ast.untyped;
+
+import org.shedlang.compiler.sources.Source;
+
+import java.util.List;
+
+public record UntypedParamTypesNode(
+ List<UntypedTypeLevelExpressionNode> positional,
+ List<UntypedParamNode> named,
+ Source source
+) implements UntypedNode {
+}
diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedTypeLevelExpressionNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedTypeLevelExpressionNode.java
index fdbc5320..5af90cfa 100644
--- a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedTypeLevelExpressionNode.java
+++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedTypeLevelExpressionNode.java
@@ -1,4 +1,4 @@
package org.shedlang.compiler.ast.untyped;
-public sealed interface UntypedTypeLevelExpressionNode extends UntypedNode permits UntypedTupleTypeNode, UntypedTypeLevelReferenceNode {
+public sealed interface UntypedTypeLevelExpressionNode extends UntypedNode permits UntypedFunctionTypeNode, UntypedTupleTypeNode, UntypedTypeLevelReferenceNode {
}
diff --git a/src/main/java/org/shedlang/compiler/parser/Parser.java b/src/main/java/org/shedlang/compiler/parser/Parser.java
index abd5316e..763d0a01 100644
--- a/src/main/java/org/shedlang/compiler/parser/Parser.java
+++ b/src/main/java/org/shedlang/compiler/parser/Parser.java
@@ -289,12 +289,7 @@ public class Parser {
var params = parseParams(tokens);
tokens.skip(TokenType.SYMBOL_PAREN_CLOSE);
- Optional<UntypedTypeLevelExpressionNode> effect;
- if (tokens.trySkip(TokenType.SYMBOL_BANG)) {
- effect = Optional.of(parseTopLevelTypeLevelExpression(tokens));
- } else {
- effect = Optional.empty();
- }
+ var effect = parseFunctionTypeEffect(tokens);
tokens.skip(TokenType.SYMBOL_THIN_ARROW);
var returnType = parseTopLevelTypeLevelExpression(tokens);
@@ -373,6 +368,42 @@ public class Parser {
}
}
+ private static UntypedTypeLevelExpressionNode parseFunctionType(
+ TokenIterator<TokenType> tokens
+ ) {
+ var start = tokens.position();
+
+ tokens.skip(TokenType.KEYWORD_FN);
+
+ tokens.skip(TokenType.SYMBOL_PAREN_OPEN);
+ var params = parseParamTypes(tokens);
+ tokens.skip(TokenType.SYMBOL_PAREN_CLOSE);
+
+ var effect = parseFunctionTypeEffect(tokens);
+
+ tokens.skip(TokenType.SYMBOL_THIN_ARROW);
+
+ var returnType = parseTopLevelTypeLevelExpression(tokens);
+
+ var end = tokens.position();
+ var source = start.to(end);
+
+ return new UntypedFunctionTypeNode(
+ params,
+ effect,
+ returnType,
+ source
+ );
+ }
+
+ private static Optional<UntypedTypeLevelExpressionNode> parseFunctionTypeEffect(TokenIterator<TokenType> tokens) {
+ if (tokens.trySkip(TokenType.SYMBOL_BANG)) {
+ return Optional.of(parseTopLevelTypeLevelExpression(tokens));
+ } else {
+ return Optional.empty();
+ }
+ }
+
private static UntypedExpressionNode parseIf(TokenIterator<TokenType> tokens) {
var start = tokens.position();
@@ -545,10 +576,10 @@ public class Parser {
parseMany(
() -> tokens.isNext(TokenType.SYMBOL_PAREN_CLOSE),
() -> {
- var isNamed = tokens.trySkip(TokenType.SYMBOL_DOT);
-
var paramStart = tokens.position();
+ var isNamed = tokens.trySkip(TokenType.SYMBOL_DOT);
+
var name = tokens.nextValue(TokenType.IDENTIFIER);
tokens.skip(TokenType.SYMBOL_COLON);
var type = parseTopLevelTypeLevelExpression(tokens);
@@ -572,6 +603,48 @@ public class Parser {
return new UntypedParamsNode(positional, named, paramsSource);
}
+ private static UntypedParamTypesNode parseParamTypes(TokenIterator<TokenType> tokens) {
+ var paramsStart = tokens.position();
+
+ var positional = new ArrayList<UntypedTypeLevelExpressionNode>();
+ var named = new ArrayList<UntypedParamNode>();
+
+ parseMany(
+ () -> tokens.isNext(TokenType.SYMBOL_PAREN_CLOSE),
+ () -> {
+ var paramStart = tokens.position();
+
+ var isNamed = tokens.trySkip(TokenType.SYMBOL_DOT);
+
+ if (isNamed) {
+ var name = tokens.nextValue(TokenType.IDENTIFIER);
+ tokens.skip(TokenType.SYMBOL_COLON);
+ var type = parseTopLevelTypeLevelExpression(tokens);
+
+ var paramEnd = tokens.position();
+ var paramSource = paramStart.to(paramEnd);
+
+ named.add(new UntypedParamNode(name, type, paramSource));
+ } else {
+ var type = parseTopLevelTypeLevelExpression(tokens);
+ if (!named.isEmpty()) {
+ throw new PositionalParamAfterNamedParamError(type.source());
+ }
+
+ positional.add(type);
+ }
+
+ return null;
+ },
+ () -> tokens.trySkip(TokenType.SYMBOL_COMMA)
+ );
+
+ var paramsEnd = tokens.position();
+ var paramsSource = paramsStart.to(paramsEnd);
+
+ return new UntypedParamTypesNode(positional, named, paramsSource);
+ }
+
private static UntypedExpressionNode parsePrimaryExpression(TokenIterator<TokenType> tokens) {
return switch (tokens.peek().tokenType()) {
@@ -713,6 +786,9 @@ public class Parser {
case IDENTIFIER ->
parseTypeLevelReference(tokens);
+ case KEYWORD_FN ->
+ parseFunctionType(tokens);
+
case SYMBOL_HASH_PAREN_OPEN ->
parseTupleType(tokens);
diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java
index b8a487e4..40647834 100644
--- a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java
+++ b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java
@@ -1013,6 +1013,9 @@ public class TypeChecker {
TypeCheckerContext context
) {
return switch (untyped) {
+ case UntypedFunctionTypeNode functionType ->
+ throw new UnsupportedOperationException("TODO");
+
case UntypedTupleTypeNode tuple -> {
var typedTupleNode = typeCheckTupleType(tuple, context);