diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/PbsFlowBodyAnalyzer.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/PbsFlowBodyAnalyzer.java index aa635cbf..a4d73ec9 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/PbsFlowBodyAnalyzer.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/PbsFlowBodyAnalyzer.java @@ -33,11 +33,16 @@ final class PbsFlowBodyAnalyzer { validateCallableBody( functionDecl.parameters(), functionDecl.body(), - typeOps.callableReturnType(functionDecl.returnKind(), functionDecl.returnType(), functionDecl.resultErrorType(), model), - functionDecl.resultErrorType() == null ? null : functionDecl.resultErrorType().name(), - null, - model, - diagnostics); + newCallableContext( + typeOps.callableReturnType( + functionDecl.returnKind(), + functionDecl.returnType(), + functionDecl.resultErrorType(), + model), + functionDecl.resultErrorType() == null ? null : functionDecl.resultErrorType().name(), + null, + model, + diagnostics)); continue; } if (topDecl instanceof PbsAst.StructDecl structDecl) { @@ -46,21 +51,27 @@ final class PbsFlowBodyAnalyzer { validateCallableBody( method.parameters(), method.body(), - typeOps.callableReturnType(method.returnKind(), method.returnType(), method.resultErrorType(), model), - method.resultErrorType() == null ? null : method.resultErrorType().name(), - receiverType, - model, - diagnostics); + newCallableContext( + typeOps.callableReturnType( + method.returnKind(), + method.returnType(), + method.resultErrorType(), + model), + method.resultErrorType() == null ? null : method.resultErrorType().name(), + receiverType, + model, + diagnostics)); } for (final var ctor : structDecl.ctors()) { validateCallableBody( ctor.parameters(), ctor.body(), - TypeView.unit(), - null, - receiverType, - model, - diagnostics); + newCallableContext( + TypeView.unit(), + null, + receiverType, + model, + diagnostics)); } continue; } @@ -70,37 +81,57 @@ final class PbsFlowBodyAnalyzer { validateCallableBody( method.parameters(), method.body(), - typeOps.callableReturnType(method.returnKind(), method.returnType(), method.resultErrorType(), model), - method.resultErrorType() == null ? null : method.resultErrorType().name(), - receiverType, - model, - diagnostics); + newCallableContext( + typeOps.callableReturnType( + method.returnKind(), + method.returnType(), + method.resultErrorType(), + model), + method.resultErrorType() == null ? null : method.resultErrorType().name(), + receiverType, + model, + diagnostics)); } } } } - private void validateCallableBody( - final ReadOnlyList parameters, - final PbsAst.Block body, + private PbsFlowBodyContext newCallableContext( final TypeView returnType, final String resultErrorName, final TypeView receiverType, final Model model, final DiagnosticSink diagnostics) { - final var scope = new Scope(); + return new PbsFlowBodyContext( + new Scope(), + returnType, + resultErrorName, + receiverType, + model, + diagnostics); + } + + private void validateCallableBody( + final ReadOnlyList parameters, + final PbsAst.Block body, + final PbsFlowBodyContext context) { + final var scope = context.scope(); for (final var parameter : parameters) { - scope.bind(parameter.name(), typeOps.typeFromTypeRef(parameter.typeRef(), model, receiverType)); + scope.bind( + parameter.name(), + typeOps.typeFromTypeRef(parameter.typeRef(), context.model(), context.receiverType())); } - analyzeBlock(body, scope, returnType, resultErrorName, receiverType, model, diagnostics, true); - validateCallableCompletion(body, returnType, model, diagnostics); + final var callableContext = context.withScope(scope); + analyzeBlock(body, callableContext, true); + validateCallableCompletion(body, callableContext); } private void validateCallableCompletion( final PbsAst.Block body, - final TypeView returnType, - final Model model, - final DiagnosticSink diagnostics) { + final PbsFlowBodyContext context) { + final var returnType = context.returnType(); + final var model = context.model(); + final var diagnostics = context.diagnostics(); final var returnKind = returnType.kind(); final var enforceResultCompletion = returnKind == Kind.RESULT; final var enforcePlainNonUnitCompletion = returnKind != Kind.RESULT @@ -285,9 +316,26 @@ final class PbsFlowBodyAnalyzer { final Model model, final DiagnosticSink diagnostics, final boolean valueContext) { - final var scope = outerScope.copy(); + return analyzeBlock( + block, + new PbsFlowBodyContext( + outerScope, + returnType, + resultErrorName, + receiverType, + model, + diagnostics), + valueContext); + } + + private TypeView analyzeBlock( + final PbsAst.Block block, + final PbsFlowBodyContext context, + final boolean valueContext) { + final var scope = context.scope().copy(); + final var scopedContext = context.withScope(scope); for (final var statement : block.statements()) { - analyzeStatement(statement, scope, returnType, resultErrorName, receiverType, model, diagnostics); + analyzeStatement(statement, scopedContext); } if (block.tailExpression() == null) { return TypeView.unit(); @@ -296,11 +344,11 @@ final class PbsFlowBodyAnalyzer { block.tailExpression(), scope, null, - returnType, - resultErrorName, - receiverType, - model, - diagnostics, + context.returnType(), + context.resultErrorName(), + context.receiverType(), + context.model(), + context.diagnostics(), ExprUse.VALUE, valueContext, this::analyzeBlock).type(); @@ -308,12 +356,13 @@ final class PbsFlowBodyAnalyzer { private void analyzeStatement( final PbsAst.Statement statement, - final Scope scope, - final TypeView returnType, - final String resultErrorName, - final TypeView receiverType, - final Model model, - final DiagnosticSink diagnostics) { + final PbsFlowBodyContext context) { + final var scope = context.scope(); + final var returnType = context.returnType(); + final var resultErrorName = context.resultErrorName(); + final var receiverType = context.receiverType(); + final var model = context.model(); + final var diagnostics = context.diagnostics(); if (statement instanceof PbsAst.LetStatement letStatement) { final var expected = letStatement.explicitType() == null ? null @@ -335,14 +384,7 @@ final class PbsFlowBodyAnalyzer { } if (statement instanceof PbsAst.ReturnStatement returnStatement) { if (returnStatement.value() != null) { - analyzeReturnStatement( - returnStatement.value(), - scope, - returnType, - resultErrorName, - receiverType, - model, - diagnostics); + analyzeReturnStatement(returnStatement.value(), context); } return; } @@ -365,12 +407,12 @@ final class PbsFlowBodyAnalyzer { "If statement condition must have bool type", ifStatement.condition().span()); } - analyzeBlock(ifStatement.thenBlock(), scope, returnType, resultErrorName, receiverType, model, diagnostics, false); + analyzeBlock(ifStatement.thenBlock(), context, false); if (ifStatement.elseBlock() != null) { - analyzeBlock(ifStatement.elseBlock(), scope, returnType, resultErrorName, receiverType, model, diagnostics, false); + analyzeBlock(ifStatement.elseBlock(), context, false); } if (ifStatement.elseIf() != null) { - analyzeStatement(ifStatement.elseIf(), scope, returnType, resultErrorName, receiverType, model, diagnostics); + analyzeStatement(ifStatement.elseIf(), context); } return; } @@ -432,7 +474,7 @@ final class PbsFlowBodyAnalyzer { } final var bodyScope = scope.copy(); bodyScope.bind(iteratorName, iteratorType); - analyzeBlock(body, bodyScope, returnType, resultErrorName, receiverType, model, diagnostics, false); + analyzeBlock(body, context.withScope(bodyScope), false); return; } if (statement instanceof PbsAst.WhileStatement whileStatement) { @@ -454,7 +496,7 @@ final class PbsFlowBodyAnalyzer { "While condition must have bool type", whileStatement.condition().span()); } - analyzeBlock(whileStatement.body(), scope, returnType, resultErrorName, receiverType, model, diagnostics, false); + analyzeBlock(whileStatement.body(), context, false); return; } if (statement instanceof PbsAst.ExpressionStatement expressionStatement) { @@ -473,36 +515,31 @@ final class PbsFlowBodyAnalyzer { return; } if (statement instanceof PbsAst.AssignStatement assignStatement) { - analyzeAssignmentStatement(assignStatement, scope, returnType, resultErrorName, receiverType, model, diagnostics); + analyzeAssignmentStatement(assignStatement, context); } } private void analyzeReturnStatement( final PbsAst.Expression value, - final Scope scope, - final TypeView returnType, - final String resultErrorName, - final TypeView receiverType, - final Model model, - final DiagnosticSink diagnostics) { + final PbsFlowBodyContext context) { final var root = unwrapGroup(value); if (root instanceof PbsAst.OkExpr okExpr) { - analyzeReturnOk(okExpr, scope, returnType, resultErrorName, receiverType, model, diagnostics); + analyzeReturnOk(okExpr, context); return; } if (root instanceof PbsAst.ErrExpr errExpr) { - analyzeReturnErr(errExpr, returnType, resultErrorName, model, diagnostics); + analyzeReturnErr(errExpr, context); return; } expressionAnalyzer.analyzeExpression( value, - scope, - returnType, - returnType, - resultErrorName, - receiverType, - model, - diagnostics, + context.scope(), + context.returnType(), + context.returnType(), + context.resultErrorName(), + context.receiverType(), + context.model(), + context.diagnostics(), ExprUse.VALUE, true, this::analyzeBlock); @@ -510,12 +547,10 @@ final class PbsFlowBodyAnalyzer { private void analyzeReturnOk( final PbsAst.OkExpr okExpr, - final Scope scope, - final TypeView returnType, - final String resultErrorName, - final TypeView receiverType, - final Model model, - final DiagnosticSink diagnostics) { + final PbsFlowBodyContext context) { + final var returnType = context.returnType(); + final var resultErrorName = context.resultErrorName(); + final var diagnostics = context.diagnostics(); if (returnType.kind() != Kind.RESULT || resultErrorName == null) { Diagnostics.error(diagnostics, PbsSemanticsErrors.E_SEM_RESULT_FLOW_INVALID_POSITION.name(), @@ -523,12 +558,12 @@ final class PbsFlowBodyAnalyzer { okExpr.span()); expressionAnalyzer.analyzeExpression( okExpr.value(), - scope, + context.scope(), null, returnType, resultErrorName, - receiverType, - model, + context.receiverType(), + context.model(), diagnostics, ExprUse.VALUE, true, @@ -539,12 +574,12 @@ final class PbsFlowBodyAnalyzer { final var payloadType = returnType.inner(); final var actualType = expressionAnalyzer.analyzeExpression( okExpr.value(), - scope, + context.scope(), payloadType, returnType, resultErrorName, - receiverType, - model, + context.receiverType(), + context.model(), diagnostics, ExprUse.VALUE, true, @@ -559,10 +594,11 @@ final class PbsFlowBodyAnalyzer { private void analyzeReturnErr( final PbsAst.ErrExpr errExpr, - final TypeView returnType, - final String resultErrorName, - final Model model, - final DiagnosticSink diagnostics) { + final PbsFlowBodyContext context) { + final var returnType = context.returnType(); + final var resultErrorName = context.resultErrorName(); + final var model = context.model(); + final var diagnostics = context.diagnostics(); if (returnType.kind() != Kind.RESULT || resultErrorName == null) { Diagnostics.error(diagnostics, PbsSemanticsErrors.E_SEM_RESULT_FLOW_INVALID_POSITION.name(), @@ -601,13 +637,14 @@ final class PbsFlowBodyAnalyzer { private void analyzeAssignmentStatement( final PbsAst.AssignStatement assignStatement, - final Scope scope, - final TypeView returnType, - final String resultErrorName, - final TypeView receiverType, - final Model model, - final DiagnosticSink diagnostics) { - final var target = resolveAssignmentTarget(assignStatement.target(), scope, receiverType, model, diagnostics); + final PbsFlowBodyContext context) { + final var scope = context.scope(); + final var returnType = context.returnType(); + final var resultErrorName = context.resultErrorName(); + final var receiverType = context.receiverType(); + final var model = context.model(); + final var diagnostics = context.diagnostics(); + final var target = resolveAssignmentTarget(assignStatement.target(), context); final var expectedType = target.type(); final var valueType = expressionAnalyzer.analyzeExpression( assignStatement.value(), @@ -636,10 +673,11 @@ final class PbsFlowBodyAnalyzer { private AssignmentTargetResolution resolveAssignmentTarget( final PbsAst.LValue lValue, - final Scope scope, - final TypeView receiverType, - final Model model, - final DiagnosticSink diagnostics) { + final PbsFlowBodyContext context) { + final var scope = context.scope(); + final var receiverType = context.receiverType(); + final var model = context.model(); + final var diagnostics = context.diagnostics(); final var rootName = lValue.rootName(); final var rootIsThis = "this".equals(rootName); if (lValue.pathSegments().isEmpty()) { diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/PbsFlowBodyContext.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/PbsFlowBodyContext.java new file mode 100644 index 00000000..ee2abc11 --- /dev/null +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/semantics/PbsFlowBodyContext.java @@ -0,0 +1,64 @@ +package p.studio.compiler.pbs.semantics; + +import p.studio.compiler.source.diagnostics.DiagnosticSink; +import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.Model; +import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.Scope; +import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.TypeView; + +final class PbsFlowBodyContext { + private final Scope scope; + private final TypeView returnType; + private final String resultErrorName; + private final TypeView receiverType; + private final Model model; + private final DiagnosticSink diagnostics; + + PbsFlowBodyContext( + final Scope scope, + final TypeView returnType, + final String resultErrorName, + final TypeView receiverType, + final Model model, + final DiagnosticSink diagnostics) { + this.scope = scope; + this.returnType = returnType; + this.resultErrorName = resultErrorName; + this.receiverType = receiverType; + this.model = model; + this.diagnostics = diagnostics; + } + + Scope scope() { + return scope; + } + + TypeView returnType() { + return returnType; + } + + String resultErrorName() { + return resultErrorName; + } + + TypeView receiverType() { + return receiverType; + } + + Model model() { + return model; + } + + DiagnosticSink diagnostics() { + return diagnostics; + } + + PbsFlowBodyContext withScope(final Scope nextScope) { + return new PbsFlowBodyContext( + nextScope, + returnType, + resultErrorName, + receiverType, + model, + diagnostics); + } +}