implements PR-12.2
This commit is contained in:
parent
8edd2c4b4b
commit
8692e94a27
@ -32,9 +32,14 @@ final class PbsFlowExpressionAnalyzer {
|
||||
}
|
||||
|
||||
private final PbsFlowTypeOps typeOps;
|
||||
private final PbsFlowStructuralExpressionAnalyzer structuralExpressionAnalyzer;
|
||||
|
||||
PbsFlowExpressionAnalyzer(final PbsFlowTypeOps typeOps) {
|
||||
this.typeOps = typeOps;
|
||||
this.structuralExpressionAnalyzer = new PbsFlowStructuralExpressionAnalyzer(
|
||||
typeOps,
|
||||
this::analyzeExpressionInternal,
|
||||
this::analyzeBlock);
|
||||
}
|
||||
|
||||
ExprResult analyzeExpression(
|
||||
@ -75,95 +80,9 @@ final class PbsFlowExpressionAnalyzer {
|
||||
final var model = context.model();
|
||||
final var diagnostics = context.diagnostics();
|
||||
final var use = context.use();
|
||||
final var valueContext = context.valueContext();
|
||||
if (expression instanceof PbsAst.IntLiteralExpr) {
|
||||
return ExprResult.type(TypeView.intType());
|
||||
}
|
||||
if (expression instanceof PbsAst.FloatLiteralExpr) {
|
||||
return ExprResult.type(TypeView.floatType());
|
||||
}
|
||||
if (expression instanceof PbsAst.BoundedLiteralExpr) {
|
||||
return ExprResult.type(TypeView.intType());
|
||||
}
|
||||
if (expression instanceof PbsAst.StringLiteralExpr) {
|
||||
return ExprResult.type(TypeView.str());
|
||||
}
|
||||
if (expression instanceof PbsAst.BoolLiteralExpr) {
|
||||
return ExprResult.type(TypeView.bool());
|
||||
}
|
||||
if (expression instanceof PbsAst.UnitExpr) {
|
||||
return ExprResult.type(TypeView.unit());
|
||||
}
|
||||
if (expression instanceof PbsAst.ThisExpr thisExpr) {
|
||||
if (receiverType == null) {
|
||||
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
||||
PbsSemanticsErrors.E_SEM_INVALID_THIS_CONTEXT.name(),
|
||||
"Invalid 'this' usage outside struct/service methods and constructors",
|
||||
thisExpr.span());
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
return ExprResult.type(receiverType);
|
||||
}
|
||||
if (expression instanceof PbsAst.IdentifierExpr identifierExpr) {
|
||||
final var localType = scope.resolve(identifierExpr.name());
|
||||
if (localType != null) {
|
||||
return ExprResult.type(localType);
|
||||
}
|
||||
|
||||
final var serviceType = model.serviceSingletons.get(identifierExpr.name());
|
||||
if (serviceType != null) {
|
||||
return ExprResult.type(serviceType);
|
||||
}
|
||||
|
||||
final var constType = model.constTypes.get(identifierExpr.name());
|
||||
if (constType != null) {
|
||||
return ExprResult.type(constType);
|
||||
}
|
||||
|
||||
final var callbackSignature = model.callbacks.get(identifierExpr.name());
|
||||
if (callbackSignature != null) {
|
||||
return ExprResult.type(TypeView.callback(identifierExpr.name(), callbackSignature.inputTypes(), callbackSignature.outputType()));
|
||||
}
|
||||
|
||||
final var callables = model.topLevelCallables.get(identifierExpr.name());
|
||||
if (callables != null && !callables.isEmpty()) {
|
||||
return ExprResult.callables(callables, false);
|
||||
}
|
||||
|
||||
if (model.enums.containsKey(identifierExpr.name())) {
|
||||
return ExprResult.type(TypeView.typeRef(identifierExpr.name()));
|
||||
}
|
||||
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
if (expression instanceof PbsAst.GroupExpr groupExpr) {
|
||||
return analyzeExpressionInternal(groupExpr.expression(), context);
|
||||
}
|
||||
if (expression instanceof PbsAst.TupleExpr tupleExpr) {
|
||||
final var fields = new ArrayList<TupleField>(tupleExpr.items().size());
|
||||
for (final var item : tupleExpr.items()) {
|
||||
final var value = analyzeValueExpression(item.expression(), context, null).type();
|
||||
fields.add(new TupleField(item.label(), value));
|
||||
}
|
||||
return ExprResult.type(TypeView.tuple(fields));
|
||||
}
|
||||
if (expression instanceof PbsAst.BlockExpr blockExpr) {
|
||||
return ExprResult.type(analyzeBlock(blockExpr.block(), context, valueContext));
|
||||
}
|
||||
if (expression instanceof PbsAst.UnaryExpr unaryExpr) {
|
||||
final var operand = analyzeValueExpression(unaryExpr.expression(), context, null).type();
|
||||
if ("!".equals(unaryExpr.operator()) || "not".equals(unaryExpr.operator())) {
|
||||
return ExprResult.type(TypeView.bool());
|
||||
}
|
||||
if ("-".equals(unaryExpr.operator()) && (typeOps.isInt(operand) || typeOps.isFloat(operand))) {
|
||||
return ExprResult.type(operand);
|
||||
}
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
if (expression instanceof PbsAst.BinaryExpr binaryExpr) {
|
||||
final var left = analyzeValueExpression(binaryExpr.left(), context, null).type();
|
||||
final var right = analyzeValueExpression(binaryExpr.right(), context, null).type();
|
||||
return ExprResult.type(typeOps.inferBinaryResult(binaryExpr.operator(), left, right));
|
||||
final var structural = structuralExpressionAnalyzer.analyze(expression, context);
|
||||
if (structural != null) {
|
||||
return structural;
|
||||
}
|
||||
if (expression instanceof PbsAst.MemberExpr memberExpr) {
|
||||
return analyzeMemberExpression(
|
||||
@ -242,23 +161,6 @@ final class PbsFlowExpressionAnalyzer {
|
||||
if (expression instanceof PbsAst.HandleExpr handleExpr) {
|
||||
return ExprResult.type(analyzeHandleExpression(handleExpr, context));
|
||||
}
|
||||
if (expression instanceof PbsAst.NoneExpr noneExpr) {
|
||||
if (expectedType == null || expectedType.kind() != Kind.OPTIONAL) {
|
||||
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
||||
PbsSemanticsErrors.E_SEM_NONE_WITHOUT_EXPECTED_OPTIONAL.name(),
|
||||
"'none' requires an expected optional type context",
|
||||
noneExpr.span());
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
return ExprResult.type(expectedType);
|
||||
}
|
||||
if (expression instanceof PbsAst.SomeExpr someExpr) {
|
||||
final var payloadExpected = expectedType != null && expectedType.kind() == Kind.OPTIONAL
|
||||
? expectedType.inner()
|
||||
: null;
|
||||
final var payload = analyzeValueExpression(someExpr.value(), context, payloadExpected).type();
|
||||
return ExprResult.type(TypeView.optional(payloadExpected == null ? payload : payloadExpected));
|
||||
}
|
||||
if (expression instanceof PbsAst.BindExpr bindExpr) {
|
||||
final var contextType = analyzeValueExpression(bindExpr.contextExpression(), context, null).type();
|
||||
if (expectedType == null || expectedType.kind() != Kind.CALLBACK) {
|
||||
@ -305,35 +207,6 @@ final class PbsFlowExpressionAnalyzer {
|
||||
}
|
||||
return ExprResult.type(expectedType);
|
||||
}
|
||||
if (expression instanceof PbsAst.NewExpr newExpr) {
|
||||
if (model.structs.containsKey(newExpr.typeName())) {
|
||||
return ExprResult.type(TypeView.struct(newExpr.typeName()));
|
||||
}
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
if (expression instanceof PbsAst.AsExpr asExpr) {
|
||||
analyzeValueExpression(asExpr.expression(), context, null);
|
||||
if (model.contracts.containsKey(asExpr.contractName())) {
|
||||
return ExprResult.type(TypeView.contract(asExpr.contractName()));
|
||||
}
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
|
||||
if (expression instanceof PbsAst.OkExpr okExpr) {
|
||||
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
||||
PbsSemanticsErrors.E_SEM_RESULT_FLOW_INVALID_POSITION.name(),
|
||||
"'ok(...)' is only allowed in result return flow and handle arm terminals",
|
||||
okExpr.span());
|
||||
analyzeValueExpression(okExpr.value(), context, null);
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
if (expression instanceof PbsAst.ErrExpr errExpr) {
|
||||
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
|
||||
PbsSemanticsErrors.E_SEM_RESULT_FLOW_INVALID_POSITION.name(),
|
||||
"'err(...)' is only allowed in result return flow and handle arm terminals",
|
||||
errExpr.span());
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
|
||||
@ -0,0 +1,192 @@
|
||||
package p.studio.compiler.pbs.semantics;
|
||||
|
||||
import p.studio.compiler.pbs.ast.PbsAst;
|
||||
import p.studio.compiler.source.diagnostics.Diagnostics;
|
||||
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.ExprResult;
|
||||
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.Kind;
|
||||
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.TupleField;
|
||||
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.TypeView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
final class PbsFlowStructuralExpressionAnalyzer {
|
||||
@FunctionalInterface
|
||||
interface ExpressionAnalyzerDelegate {
|
||||
ExprResult analyze(PbsAst.Expression expression, PbsFlowExpressionContext context);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface BlockAnalysisDelegate {
|
||||
TypeView analyze(PbsAst.Block block, PbsFlowExpressionContext context, boolean valueContext);
|
||||
}
|
||||
|
||||
private final PbsFlowTypeOps typeOps;
|
||||
private final ExpressionAnalyzerDelegate expressionAnalyzerDelegate;
|
||||
private final BlockAnalysisDelegate blockAnalysisDelegate;
|
||||
|
||||
PbsFlowStructuralExpressionAnalyzer(
|
||||
final PbsFlowTypeOps typeOps,
|
||||
final ExpressionAnalyzerDelegate expressionAnalyzerDelegate,
|
||||
final BlockAnalysisDelegate blockAnalysisDelegate) {
|
||||
this.typeOps = typeOps;
|
||||
this.expressionAnalyzerDelegate = expressionAnalyzerDelegate;
|
||||
this.blockAnalysisDelegate = blockAnalysisDelegate;
|
||||
}
|
||||
|
||||
ExprResult analyze(
|
||||
final PbsAst.Expression expression,
|
||||
final PbsFlowExpressionContext context) {
|
||||
final var expectedType = context.expectedType();
|
||||
final var receiverType = context.receiverType();
|
||||
final var model = context.model();
|
||||
final var diagnostics = context.diagnostics();
|
||||
|
||||
if (expression instanceof PbsAst.IntLiteralExpr) {
|
||||
return ExprResult.type(TypeView.intType());
|
||||
}
|
||||
if (expression instanceof PbsAst.FloatLiteralExpr) {
|
||||
return ExprResult.type(TypeView.floatType());
|
||||
}
|
||||
if (expression instanceof PbsAst.BoundedLiteralExpr) {
|
||||
return ExprResult.type(TypeView.intType());
|
||||
}
|
||||
if (expression instanceof PbsAst.StringLiteralExpr) {
|
||||
return ExprResult.type(TypeView.str());
|
||||
}
|
||||
if (expression instanceof PbsAst.BoolLiteralExpr) {
|
||||
return ExprResult.type(TypeView.bool());
|
||||
}
|
||||
if (expression instanceof PbsAst.UnitExpr) {
|
||||
return ExprResult.type(TypeView.unit());
|
||||
}
|
||||
if (expression instanceof PbsAst.ThisExpr thisExpr) {
|
||||
if (receiverType == null) {
|
||||
Diagnostics.error(diagnostics,
|
||||
PbsSemanticsErrors.E_SEM_INVALID_THIS_CONTEXT.name(),
|
||||
"Invalid 'this' usage outside struct/service methods and constructors",
|
||||
thisExpr.span());
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
return ExprResult.type(receiverType);
|
||||
}
|
||||
if (expression instanceof PbsAst.IdentifierExpr identifierExpr) {
|
||||
final var localType = context.scope().resolve(identifierExpr.name());
|
||||
if (localType != null) {
|
||||
return ExprResult.type(localType);
|
||||
}
|
||||
|
||||
final var serviceType = model.serviceSingletons.get(identifierExpr.name());
|
||||
if (serviceType != null) {
|
||||
return ExprResult.type(serviceType);
|
||||
}
|
||||
|
||||
final var constType = model.constTypes.get(identifierExpr.name());
|
||||
if (constType != null) {
|
||||
return ExprResult.type(constType);
|
||||
}
|
||||
|
||||
final var callbackSignature = model.callbacks.get(identifierExpr.name());
|
||||
if (callbackSignature != null) {
|
||||
return ExprResult.type(TypeView.callback(identifierExpr.name(), callbackSignature.inputTypes(), callbackSignature.outputType()));
|
||||
}
|
||||
|
||||
final var callables = model.topLevelCallables.get(identifierExpr.name());
|
||||
if (callables != null && !callables.isEmpty()) {
|
||||
return ExprResult.callables(callables, false);
|
||||
}
|
||||
|
||||
if (model.enums.containsKey(identifierExpr.name())) {
|
||||
return ExprResult.type(TypeView.typeRef(identifierExpr.name()));
|
||||
}
|
||||
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
if (expression instanceof PbsAst.GroupExpr groupExpr) {
|
||||
return expressionAnalyzerDelegate.analyze(groupExpr.expression(), context);
|
||||
}
|
||||
if (expression instanceof PbsAst.TupleExpr tupleExpr) {
|
||||
final var fields = new ArrayList<TupleField>(tupleExpr.items().size());
|
||||
for (final var item : tupleExpr.items()) {
|
||||
final var value = analyzeValueExpression(item.expression(), context, null).type();
|
||||
fields.add(new TupleField(item.label(), value));
|
||||
}
|
||||
return ExprResult.type(TypeView.tuple(fields));
|
||||
}
|
||||
if (expression instanceof PbsAst.BlockExpr blockExpr) {
|
||||
return ExprResult.type(blockAnalysisDelegate.analyze(blockExpr.block(), context, context.valueContext()));
|
||||
}
|
||||
if (expression instanceof PbsAst.UnaryExpr unaryExpr) {
|
||||
final var operand = analyzeValueExpression(unaryExpr.expression(), context, null).type();
|
||||
if ("!".equals(unaryExpr.operator()) || "not".equals(unaryExpr.operator())) {
|
||||
return ExprResult.type(TypeView.bool());
|
||||
}
|
||||
if ("-".equals(unaryExpr.operator()) && (typeOps.isInt(operand) || typeOps.isFloat(operand))) {
|
||||
return ExprResult.type(operand);
|
||||
}
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
if (expression instanceof PbsAst.BinaryExpr binaryExpr) {
|
||||
final var left = analyzeValueExpression(binaryExpr.left(), context, null).type();
|
||||
final var right = analyzeValueExpression(binaryExpr.right(), context, null).type();
|
||||
return ExprResult.type(typeOps.inferBinaryResult(binaryExpr.operator(), left, right));
|
||||
}
|
||||
if (expression instanceof PbsAst.NoneExpr noneExpr) {
|
||||
if (expectedType == null || expectedType.kind() != Kind.OPTIONAL) {
|
||||
Diagnostics.error(diagnostics,
|
||||
PbsSemanticsErrors.E_SEM_NONE_WITHOUT_EXPECTED_OPTIONAL.name(),
|
||||
"'none' requires an expected optional type context",
|
||||
noneExpr.span());
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
return ExprResult.type(expectedType);
|
||||
}
|
||||
if (expression instanceof PbsAst.SomeExpr someExpr) {
|
||||
final var payloadExpected = expectedType != null && expectedType.kind() == Kind.OPTIONAL
|
||||
? expectedType.inner()
|
||||
: null;
|
||||
final var payload = analyzeValueExpression(someExpr.value(), context, payloadExpected).type();
|
||||
return ExprResult.type(TypeView.optional(payloadExpected == null ? payload : payloadExpected));
|
||||
}
|
||||
if (expression instanceof PbsAst.NewExpr newExpr) {
|
||||
if (model.structs.containsKey(newExpr.typeName())) {
|
||||
return ExprResult.type(TypeView.struct(newExpr.typeName()));
|
||||
}
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
if (expression instanceof PbsAst.AsExpr asExpr) {
|
||||
analyzeValueExpression(asExpr.expression(), context, null);
|
||||
if (model.contracts.containsKey(asExpr.contractName())) {
|
||||
return ExprResult.type(TypeView.contract(asExpr.contractName()));
|
||||
}
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
if (expression instanceof PbsAst.OkExpr okExpr) {
|
||||
Diagnostics.error(diagnostics,
|
||||
PbsSemanticsErrors.E_SEM_RESULT_FLOW_INVALID_POSITION.name(),
|
||||
"'ok(...)' is only allowed in result return flow and handle arm terminals",
|
||||
okExpr.span());
|
||||
analyzeValueExpression(okExpr.value(), context, null);
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
if (expression instanceof PbsAst.ErrExpr errExpr) {
|
||||
Diagnostics.error(diagnostics,
|
||||
PbsSemanticsErrors.E_SEM_RESULT_FLOW_INVALID_POSITION.name(),
|
||||
"'err(...)' is only allowed in result return flow and handle arm terminals",
|
||||
errExpr.span());
|
||||
return ExprResult.type(TypeView.unknown());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ExprResult analyzeValueExpression(
|
||||
final PbsAst.Expression expression,
|
||||
final PbsFlowExpressionContext context,
|
||||
final TypeView expectedType) {
|
||||
return expressionAnalyzerDelegate.analyze(
|
||||
expression,
|
||||
context.withExpectedType(expectedType)
|
||||
.withUse(PbsFlowSemanticSupport.ExprUse.VALUE)
|
||||
.withValueContext(true));
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user