From 550bdc5177fa72234a1359795615df9f80a98657 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Thu, 19 Dec 2024 18:21:30 +0000 Subject: Rename field access to member access --- .../compiler/ast/typed/TypedExpressionNode.java | 2 +- .../compiler/ast/typed/TypedFieldAccessNode.java | 12 -- .../compiler/ast/typed/TypedMemberAccessNode.java | 12 ++ .../ast/untyped/UntypedExpressionNode.java | 2 +- .../ast/untyped/UntypedFieldAccessNode.java | 10 -- .../ast/untyped/UntypedMemberAccessNode.java | 10 ++ .../java/org/shedlang/compiler/parser/Parser.java | 60 ++++---- .../org/shedlang/compiler/shid/ShidCodeGen.java | 86 ++++++------ .../shedlang/compiler/typechecker/TypeChecker.java | 155 ++++++++++----------- 9 files changed, 174 insertions(+), 175 deletions(-) delete mode 100644 src/main/java/org/shedlang/compiler/ast/typed/TypedFieldAccessNode.java create mode 100644 src/main/java/org/shedlang/compiler/ast/typed/TypedMemberAccessNode.java delete mode 100644 src/main/java/org/shedlang/compiler/ast/untyped/UntypedFieldAccessNode.java create mode 100644 src/main/java/org/shedlang/compiler/ast/untyped/UntypedMemberAccessNode.java (limited to 'src/main/java') diff --git a/src/main/java/org/shedlang/compiler/ast/typed/TypedExpressionNode.java b/src/main/java/org/shedlang/compiler/ast/typed/TypedExpressionNode.java index 4c8b2cfd..c31d45ac 100644 --- a/src/main/java/org/shedlang/compiler/ast/typed/TypedExpressionNode.java +++ b/src/main/java/org/shedlang/compiler/ast/typed/TypedExpressionNode.java @@ -4,6 +4,6 @@ import org.shedlang.compiler.types.Type; public sealed interface TypedExpressionNode extends TypedNode - permits TypedBinaryOperationNode, TypedBoolLiteralNode, TypedCallNode, TypedFieldAccessNode, TypedFunctionExpressionNode, TypedIfNode, TypedIntLiteralNode, TypedReferenceNode, TypedStringLiteralNode, TypedTryNode, TypedTupleNode, TypedUnitLiteralNode, TypedWhenNode { + permits TypedBinaryOperationNode, TypedBoolLiteralNode, TypedCallNode, TypedFunctionExpressionNode, TypedIfNode, TypedIntLiteralNode, TypedMemberAccessNode, TypedReferenceNode, TypedStringLiteralNode, TypedTryNode, TypedTupleNode, TypedUnitLiteralNode, TypedWhenNode { Type type(); } diff --git a/src/main/java/org/shedlang/compiler/ast/typed/TypedFieldAccessNode.java b/src/main/java/org/shedlang/compiler/ast/typed/TypedFieldAccessNode.java deleted file mode 100644 index ca088e48..00000000 --- a/src/main/java/org/shedlang/compiler/ast/typed/TypedFieldAccessNode.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.shedlang.compiler.ast.typed; - -import org.shedlang.compiler.sources.Source; -import org.shedlang.compiler.types.Type; - -public record TypedFieldAccessNode( - TypedExpressionNode receiver, - String fieldName, - Type type, - Source source -) implements TypedExpressionNode { -} diff --git a/src/main/java/org/shedlang/compiler/ast/typed/TypedMemberAccessNode.java b/src/main/java/org/shedlang/compiler/ast/typed/TypedMemberAccessNode.java new file mode 100644 index 00000000..481d01b6 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/ast/typed/TypedMemberAccessNode.java @@ -0,0 +1,12 @@ +package org.shedlang.compiler.ast.typed; + +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.types.Type; + +public record TypedMemberAccessNode( + TypedExpressionNode receiver, + String memberName, + Type type, + Source source +) implements TypedExpressionNode { +} diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedExpressionNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedExpressionNode.java index a8c068e0..ba02b9db 100644 --- a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedExpressionNode.java +++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedExpressionNode.java @@ -1,5 +1,5 @@ package org.shedlang.compiler.ast.untyped; public sealed interface UntypedExpressionNode extends UntypedNode - permits UntypedBinaryOperationNode, UntypedBoolLiteralNode, UntypedCallNode, UntypedFieldAccessNode, UntypedFunctionExpressionNode, UntypedIfNode, UntypedIntLiteralNode, UntypedReferenceNode, UntypedStringLiteralNode, UntypedTryNode, UntypedTupleNode, UntypedUnitLiteralNode, UntypedWhenNode { + permits UntypedBinaryOperationNode, UntypedBoolLiteralNode, UntypedCallNode, UntypedFunctionExpressionNode, UntypedIfNode, UntypedIntLiteralNode, UntypedMemberAccessNode, UntypedReferenceNode, UntypedStringLiteralNode, UntypedTryNode, UntypedTupleNode, UntypedUnitLiteralNode, UntypedWhenNode { } diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedFieldAccessNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedFieldAccessNode.java deleted file mode 100644 index f99a3c3c..00000000 --- a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedFieldAccessNode.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.shedlang.compiler.ast.untyped; - -import org.shedlang.compiler.sources.Source; - -public record UntypedFieldAccessNode( - UntypedExpressionNode receiver, - String fieldName, - Source source -) implements UntypedExpressionNode { -} diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedMemberAccessNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedMemberAccessNode.java new file mode 100644 index 00000000..3472f221 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedMemberAccessNode.java @@ -0,0 +1,10 @@ +package org.shedlang.compiler.ast.untyped; + +import org.shedlang.compiler.sources.Source; + +public record UntypedMemberAccessNode( + UntypedExpressionNode receiver, + String memberName, + Source source +) implements UntypedExpressionNode { +} diff --git a/src/main/java/org/shedlang/compiler/parser/Parser.java b/src/main/java/org/shedlang/compiler/parser/Parser.java index 328a1ec9..680ead15 100644 --- a/src/main/java/org/shedlang/compiler/parser/Parser.java +++ b/src/main/java/org/shedlang/compiler/parser/Parser.java @@ -333,7 +333,7 @@ public class Parser { } private static final Map> OPERATION_PARSERS = Stream.of( - new FieldAccessParser(), + new MemberAccessParser(), new BinaryOperationParser(TokenType.SYMBOL_EQUALS_EQUALS, OperatorPrecedence.EQUALS, UntypedBinaryOperator.EQUALS), new BinaryOperationParser(TokenType.SYMBOL_BANG_EQUALS, OperatorPrecedence.EQUALS, UntypedBinaryOperator.NOT_EQUAL), new BinaryOperationParser(TokenType.SYMBOL_PLUS, OperatorPrecedence.ADD, UntypedBinaryOperator.ADD), @@ -405,35 +405,6 @@ public class Parser { ); } - private static class FieldAccessParser implements OperationParser< - OperatorPrecedence, - UntypedExpressionNode - > { - @Override - public OperatorPrecedence precedence() { - return OperatorPrecedence.CALL; - } - - @Override - public Stream operatorTokenTypes() { - return Stream.of(TokenType.SYMBOL_DOT); - } - - @Override - public UntypedExpressionNode parse(UntypedExpressionNode left, TokenIterator tokens) { - var start = left.source().start(); - - tokens.skip(TokenType.SYMBOL_DOT); - - var fieldName = tokens.nextValue(TokenType.IDENTIFIER); - - var end = tokens.position(); - var source = start.to(end); - - return new UntypedFieldAccessNode(left, fieldName, source); - } - } - private static UntypedFunctionDefinitionNode parseFunctionDefinition(TokenIterator tokens) { var start = tokens.position(); @@ -745,6 +716,35 @@ public class Parser { } } + private static class MemberAccessParser implements OperationParser< + OperatorPrecedence, + UntypedExpressionNode + > { + @Override + public OperatorPrecedence precedence() { + return OperatorPrecedence.CALL; + } + + @Override + public Stream operatorTokenTypes() { + return Stream.of(TokenType.SYMBOL_DOT); + } + + @Override + public UntypedExpressionNode parse(UntypedExpressionNode left, TokenIterator tokens) { + var start = left.source().start(); + + tokens.skip(TokenType.SYMBOL_DOT); + + var memberName = tokens.nextValue(TokenType.IDENTIFIER); + + var end = tokens.position(); + var source = start.to(end); + + return new UntypedMemberAccessNode(left, memberName, source); + } + } + public static NamespaceName parseNamespaceName(TokenIterator tokens) { var namespaceNameParts = parseOneOrMoreNoTrailingSeparator( () -> tokens.nextValue(TokenType.IDENTIFIER), diff --git a/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java b/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java index 16c1c3de..48dbbf3c 100644 --- a/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java +++ b/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java @@ -143,9 +143,6 @@ public class ShidCodeGen { case TypedCallNode typedCallNode -> compileCall(typedCallNode, context); - case TypedFieldAccessNode typedFieldAccessNode -> - compileFieldAccess(typedFieldAccessNode, context); - case TypedFunctionExpressionNode typedFunctionExpressionNode -> compileFunctionExpression(typedFunctionExpressionNode, context); @@ -155,6 +152,9 @@ public class ShidCodeGen { case TypedIntLiteralNode typedIntLiteralNode -> compileIntLiteral(typedIntLiteralNode, context); + case TypedMemberAccessNode typedMemberAccessNode -> + compileMemberAccess(typedMemberAccessNode, context); + case TypedReferenceNode typedReferenceNode -> compileReference(typedReferenceNode, context); @@ -184,46 +184,6 @@ public class ShidCodeGen { return context; } - private static Context compileFieldAccess( - TypedFieldAccessNode node, - Context context - ) { - context = compileExpression(node.receiver(), context); - // TODO: handle not a type with fields - var receiverType = node.receiver().type(); - var receiver = receiverTypeToReceiver(receiverType); - - context = context.addInstruction(new ShidFieldLoad( - receiver, - node.fieldName(), - node.source() - )); - return context; - } - - private static ShidFieldLoad.Receiver receiverTypeToReceiver(Type receiverType) { - return switch (receiverType) { - case ConstructedType constructedType -> - receiverTypeToReceiver(constructedType.genericType()); - - case NamespaceType namespaceType -> - new ShidFieldLoad.Receiver.Namespace(namespaceType.namespaceName()); - - case SimpleStructType structType -> - new ShidFieldLoad.Receiver.Struct(structType); - - case TypeLevelValueType typeLevelValueType -> { - if (typeLevelValueType.value() instanceof UserDefinedEffect effect) { - yield new ShidFieldLoad.Receiver.Effect(effect); - } else { - throw new RuntimeException("not a type with fields"); - } - } - - default -> throw new RuntimeException("not a type with fields"); - }; - } - private static Context compileFunction( String name, TypedParamsNode params, @@ -426,6 +386,46 @@ public class ShidCodeGen { return context.addInstruction(new ShidPushInt(node.value(), node.source())); } + private static Context compileMemberAccess( + TypedMemberAccessNode node, + Context context + ) { + context = compileExpression(node.receiver(), context); + // TODO: handle not a type with member + var receiverType = node.receiver().type(); + var receiver = receiverTypeToReceiver(receiverType); + + context = context.addInstruction(new ShidFieldLoad( + receiver, + node.memberName(), + node.source() + )); + return context; + } + + private static ShidFieldLoad.Receiver receiverTypeToReceiver(Type receiverType) { + return switch (receiverType) { + case ConstructedType constructedType -> + receiverTypeToReceiver(constructedType.genericType()); + + case NamespaceType namespaceType -> + new ShidFieldLoad.Receiver.Namespace(namespaceType.namespaceName()); + + case SimpleStructType structType -> + new ShidFieldLoad.Receiver.Struct(structType); + + case TypeLevelValueType typeLevelValueType -> { + if (typeLevelValueType.value() instanceof UserDefinedEffect effect) { + yield new ShidFieldLoad.Receiver.Effect(effect); + } else { + throw new RuntimeException("not a type with fields"); + } + } + + default -> throw new RuntimeException("not a type with fields"); + }; + } + public static ShidNamespace compileNamespace(TypedNamespaceNode node) { var context = Context.EMPTY.enterBlock(node.boundVariables(), node.source()); diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java index 997a4607..181d41e3 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java @@ -623,9 +623,6 @@ public class TypeChecker { case UntypedCallNode untypedCall -> typeCheckCall(untypedCall, context); - case UntypedFieldAccessNode untypedFieldAccess -> - typeCheckFieldAccess(untypedFieldAccess, context); - case UntypedFunctionExpressionNode untypedFunctionExpression -> typeCheckFunctionExpression(untypedFunctionExpression, hint, context); @@ -635,6 +632,9 @@ public class TypeChecker { case UntypedIntLiteralNode untypedIntLiteral -> typeCheckIntLiteral(untypedIntLiteral, context); + case UntypedMemberAccessNode untypedMemberAccess -> + typeCheckMemberAccess(untypedMemberAccess, context); + case UntypedReferenceNode untypedReference -> typeCheckReference(untypedReference, context); @@ -680,81 +680,6 @@ public class TypeChecker { }); } - private static TypeCheckerResult typeCheckFieldAccess( - UntypedFieldAccessNode untyped, - TypeCheckerContext context - ) { - // TODO: introduce notion of members, rename field to member where appropriate - var typedReceiverResult = typeCheckExpression(untyped.receiver(), Optional.empty(), context); - var typedReceiver = typedReceiverResult.value(); - context = typedReceiverResult.context(); - - var fieldType = fieldType( - typedReceiver.type(), - untyped.fieldName(), - untyped.source(), - context - ); - - return context.toResult(new TypedFieldAccessNode( - typedReceiver, - untyped.fieldName(), - fieldType, - untyped.source() - )); - } - - private static Type fieldType( - Type receiverType, - String fieldName, - Source source, - TypeCheckerContext context - ) { - return fieldTypeOrEmpty(receiverType, fieldName, source, context) - .orElseThrow(() -> new NoSuchFieldError(receiverType, fieldName, source)); - } - - private static Optional fieldTypeOrEmpty( - Type receiverType, - String fieldName, - Source source, - TypeCheckerContext context - ) { - switch (receiverType) { - case ConstructedType receiverTypeConstructed -> { - return fieldTypeOrEmpty( - receiverTypeConstructed.genericType(), - fieldName, - source, - context - ).map(genericFieldType -> TypeSubstitution.substituteType( - genericFieldType, - receiverTypeConstructed.typeSubstitutionMap() - )); - } - - case SimpleStructType receiverTypeStruct -> { - var structTypeInfo = context.structTypeInfo(receiverTypeStruct, source); - return structTypeInfo.fieldType(fieldName); - } - - case NamespaceType receiverTypeNamespace -> { - var namespaceTypeInfo = context.namespaceTypeInfo(receiverTypeNamespace, source); - return namespaceTypeInfo.fieldType(fieldName); - } - - case TypeLevelValueType receiverTypeTypeLevelValue when receiverTypeTypeLevelValue.value() instanceof UserDefinedEffect effect -> { - var effectInfo = context.userDefinedEffectInfo(effect, source); - return effectInfo.methodType(fieldName) - .map(x -> x.withEffect(effect)); - } - - default -> { - return Optional.empty(); - } - } - } - static TypeCheckerResult typeCheckFunctionBody( UntypedBlockNode untyped, PartialFunctionSignature signature, @@ -1380,6 +1305,80 @@ public class TypeChecker { )); } + private static TypeCheckerResult typeCheckMemberAccess( + UntypedMemberAccessNode untyped, + TypeCheckerContext context + ) { + var typedReceiverResult = typeCheckExpression(untyped.receiver(), Optional.empty(), context); + var typedReceiver = typedReceiverResult.value(); + context = typedReceiverResult.context(); + + var memberType = memberType( + typedReceiver.type(), + untyped.memberName(), + untyped.source(), + context + ); + + return context.toResult(new TypedMemberAccessNode( + typedReceiver, + untyped.memberName(), + memberType, + untyped.source() + )); + } + + private static Type memberType( + Type receiverType, + String memberName, + Source source, + TypeCheckerContext context + ) { + return memberTypeOrEmpty(receiverType, memberName, source, context) + .orElseThrow(() -> new NoSuchFieldError(receiverType, memberName, source)); + } + + private static Optional memberTypeOrEmpty( + Type receiverType, + String memberName, + Source source, + TypeCheckerContext context + ) { + switch (receiverType) { + case ConstructedType receiverTypeConstructed -> { + return memberTypeOrEmpty( + receiverTypeConstructed.genericType(), + memberName, + source, + context + ).map(genericFieldType -> TypeSubstitution.substituteType( + genericFieldType, + receiverTypeConstructed.typeSubstitutionMap() + )); + } + + case SimpleStructType receiverTypeStruct -> { + var structTypeInfo = context.structTypeInfo(receiverTypeStruct, source); + return structTypeInfo.fieldType(memberName); + } + + case NamespaceType receiverTypeNamespace -> { + var namespaceTypeInfo = context.namespaceTypeInfo(receiverTypeNamespace, source); + return namespaceTypeInfo.fieldType(memberName); + } + + case TypeLevelValueType receiverTypeTypeLevelValue when receiverTypeTypeLevelValue.value() instanceof UserDefinedEffect effect -> { + var effectInfo = context.userDefinedEffectInfo(effect, source); + return effectInfo.methodType(memberName) + .map(x -> x.withEffect(effect)); + } + + default -> { + return Optional.empty(); + } + } + } + public static TypeCheckerResult typeCheckNamespace( UntypedNamespaceNode untyped, TypeCheckerContext context -- cgit v1.2.3