implements PR008.1 clean up

This commit is contained in:
bQUARKz 2026-03-05 15:18:43 +00:00
parent b84d4c29f6
commit 099ed96c82
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
5 changed files with 1943 additions and 1822 deletions

View File

@ -0,0 +1,300 @@
package p.studio.compiler.pbs.semantics;
import p.studio.compiler.pbs.ast.PbsAst;
import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.utilities.structures.ReadOnlyList;
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.ExprUse;
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 PbsFlowBodyAnalyzer {
private final PbsFlowTypeOps typeOps = new PbsFlowTypeOps();
private final PbsFlowExpressionAnalyzer expressionAnalyzer = new PbsFlowExpressionAnalyzer(typeOps);
public void validate(final PbsAst.File ast, final DiagnosticSink diagnostics) {
final var model = Model.from(ast);
for (final var topDecl : ast.topDecls()) {
if (topDecl instanceof PbsAst.FunctionDecl functionDecl) {
validateCallableBody(
functionDecl.parameters(),
functionDecl.body(),
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) {
final var receiverType = TypeView.struct(structDecl.name());
for (final var method : structDecl.methods()) {
validateCallableBody(
method.parameters(),
method.body(),
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);
}
continue;
}
if (topDecl instanceof PbsAst.ServiceDecl serviceDecl) {
final var receiverType = TypeView.service(serviceDecl.name());
for (final var method : serviceDecl.methods()) {
validateCallableBody(
method.parameters(),
method.body(),
typeOps.callableReturnType(method.returnKind(), method.returnType(), method.resultErrorType(), model),
method.resultErrorType() == null ? null : method.resultErrorType().name(),
receiverType,
model,
diagnostics);
}
}
}
}
private void validateCallableBody(
final ReadOnlyList<PbsAst.Parameter> parameters,
final PbsAst.Block body,
final TypeView returnType,
final String resultErrorName,
final TypeView receiverType,
final Model model,
final DiagnosticSink diagnostics) {
final var scope = new Scope();
for (final var parameter : parameters) {
scope.bind(parameter.name(), typeOps.typeFromTypeRef(parameter.typeRef(), model, receiverType));
}
analyzeBlock(body, scope, returnType, resultErrorName, receiverType, model, diagnostics, true);
}
private TypeView analyzeBlock(
final PbsAst.Block block,
final Scope outerScope,
final TypeView returnType,
final String resultErrorName,
final TypeView receiverType,
final Model model,
final DiagnosticSink diagnostics,
final boolean valueContext) {
final var scope = outerScope.copy();
for (final var statement : block.statements()) {
analyzeStatement(statement, scope, returnType, resultErrorName, receiverType, model, diagnostics);
}
if (block.tailExpression() == null) {
return TypeView.unit();
}
return expressionAnalyzer.analyzeExpression(
block.tailExpression(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
valueContext,
this::analyzeBlock).type();
}
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) {
if (statement instanceof PbsAst.LetStatement letStatement) {
final var expected = letStatement.explicitType() == null
? null
: typeOps.typeFromTypeRef(letStatement.explicitType(), model, receiverType);
final var initializer = expressionAnalyzer.analyzeExpression(
letStatement.initializer(),
scope,
expected,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true,
this::analyzeBlock);
scope.bind(letStatement.name(), expected == null ? initializer.type() : expected);
return;
}
if (statement instanceof PbsAst.ReturnStatement returnStatement) {
if (returnStatement.value() != null) {
expressionAnalyzer.analyzeExpression(
returnStatement.value(),
scope,
returnType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true,
this::analyzeBlock);
}
return;
}
if (statement instanceof PbsAst.IfStatement ifStatement) {
final var condition = expressionAnalyzer.analyzeExpression(
ifStatement.condition(),
scope,
TypeView.bool(),
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true,
this::analyzeBlock).type();
if (!typeOps.isBool(condition)) {
diagnostics.error(
PbsSemanticsErrors.E_SEM_IF_NON_BOOL_CONDITION.name(),
"If statement condition must have bool type",
ifStatement.condition().span());
}
analyzeBlock(ifStatement.thenBlock(), scope, returnType, resultErrorName, receiverType, model, diagnostics, false);
if (ifStatement.elseBlock() != null) {
analyzeBlock(ifStatement.elseBlock(), scope, returnType, resultErrorName, receiverType, model, diagnostics, false);
}
if (ifStatement.elseIf() != null) {
analyzeStatement(ifStatement.elseIf(), scope, returnType, resultErrorName, receiverType, model, diagnostics);
}
return;
}
if (statement instanceof PbsAst.ForStatement(
String iteratorName, PbsAst.TypeRef type, PbsAst.Expression fromExpression,
PbsAst.Expression untilExpression, PbsAst.Expression stepExpression, PbsAst.Block body,
p.studio.compiler.source.Span span
)) {
final var iteratorType = typeOps.typeFromTypeRef(type, model, receiverType);
final var fromType = expressionAnalyzer.analyzeExpression(
fromExpression,
scope,
iteratorType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true,
this::analyzeBlock).type();
final var untilType = expressionAnalyzer.analyzeExpression(
untilExpression,
scope,
iteratorType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true,
this::analyzeBlock).type();
if (!typeOps.compatible(fromType, iteratorType) || !typeOps.compatible(untilType, iteratorType)) {
diagnostics.error(
PbsSemanticsErrors.E_SEM_FOR_TYPE_MISMATCH.name(),
"For-loop bounds must match declared iterator type",
span);
}
if (stepExpression != null) {
final var stepType = expressionAnalyzer.analyzeExpression(
stepExpression,
scope,
iteratorType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true,
this::analyzeBlock).type();
if (!typeOps.compatible(stepType, iteratorType)) {
diagnostics.error(
PbsSemanticsErrors.E_SEM_FOR_TYPE_MISMATCH.name(),
"For-loop step must match declared iterator type",
stepExpression.span());
}
}
final var bodyScope = scope.copy();
bodyScope.bind(iteratorName, iteratorType);
analyzeBlock(body, bodyScope, returnType, resultErrorName, receiverType, model, diagnostics, false);
return;
}
if (statement instanceof PbsAst.WhileStatement whileStatement) {
final var condition = expressionAnalyzer.analyzeExpression(
whileStatement.condition(),
scope,
TypeView.bool(),
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true,
this::analyzeBlock).type();
if (!typeOps.isBool(condition)) {
diagnostics.error(
PbsSemanticsErrors.E_SEM_WHILE_NON_BOOL_CONDITION.name(),
"While condition must have bool type",
whileStatement.condition().span());
}
analyzeBlock(whileStatement.body(), scope, returnType, resultErrorName, receiverType, model, diagnostics, false);
return;
}
if (statement instanceof PbsAst.ExpressionStatement expressionStatement) {
expressionAnalyzer.analyzeExpression(
expressionStatement.expression(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
false,
this::analyzeBlock);
return;
}
if (statement instanceof PbsAst.AssignStatement assignStatement) {
expressionAnalyzer.analyzeExpression(
assignStatement.value(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true,
this::analyzeBlock);
}
}
}

View File

@ -0,0 +1,367 @@
package p.studio.compiler.pbs.semantics;
import lombok.experimental.UtilityClass;
import p.studio.compiler.pbs.ast.PbsAst;
import p.studio.compiler.source.Span;
import p.studio.utilities.structures.ReadOnlyList;
import java.util.*;
@UtilityClass
final class PbsFlowSemanticSupport {
record ExprResult(
TypeView type,
List<CallableSymbol> callables,
boolean methodTarget) {
static ExprResult type(final TypeView type) {
return new ExprResult(type, List.of(), false);
}
static ExprResult callables(final List<CallableSymbol> callables, final boolean methodTarget) {
return new ExprResult(TypeView.unknown(), List.copyOf(callables), methodTarget);
}
}
enum ExprUse {
VALUE,
CALL_TARGET,
APPLY_TARGET
}
enum Kind {
UNKNOWN,
UNIT,
INT,
FLOAT,
BOOL,
STR,
STRUCT,
SERVICE,
CONTRACT,
CALLBACK,
ENUM,
ERROR,
OPTIONAL,
RESULT,
TUPLE,
TYPE_REF
}
record TupleField(
String label,
TypeView type) {
}
record TypeView(
Kind kind,
String name,
List<TupleField> tupleFields,
TypeView inner,
TypeView errorType,
List<TypeView> callbackInputs,
TypeView callbackOutput) {
static TypeView unknown() {
return new TypeView(Kind.UNKNOWN, null, List.of(), null, null, List.of(), null);
}
static TypeView unit() {
return new TypeView(Kind.UNIT, "unit", List.of(), null, null, List.of(), null);
}
static TypeView intType() {
return new TypeView(Kind.INT, "int", List.of(), null, null, List.of(), null);
}
static TypeView floatType() {
return new TypeView(Kind.FLOAT, "float", List.of(), null, null, List.of(), null);
}
static TypeView bool() {
return new TypeView(Kind.BOOL, "bool", List.of(), null, null, List.of(), null);
}
static TypeView str() {
return new TypeView(Kind.STR, "str", List.of(), null, null, List.of(), null);
}
static TypeView struct(final String name) {
return new TypeView(Kind.STRUCT, name, List.of(), null, null, List.of(), null);
}
static TypeView service(final String name) {
return new TypeView(Kind.SERVICE, name, List.of(), null, null, List.of(), null);
}
static TypeView contract(final String name) {
return new TypeView(Kind.CONTRACT, name, List.of(), null, null, List.of(), null);
}
static TypeView callback(
final String name,
final List<TypeView> inputTypes,
final TypeView outputType) {
return new TypeView(Kind.CALLBACK, name, List.of(), null, null, List.copyOf(inputTypes), outputType);
}
static TypeView enumType(final String name) {
return new TypeView(Kind.ENUM, name, List.of(), null, null, List.of(), null);
}
static TypeView error(final String name) {
return new TypeView(Kind.ERROR, name, List.of(), null, null, List.of(), null);
}
static TypeView optional(final TypeView inner) {
return new TypeView(Kind.OPTIONAL, "optional", List.of(), inner, null, List.of(), null);
}
static TypeView result(final TypeView error, final TypeView payload) {
return new TypeView(Kind.RESULT, "result", List.of(), payload, error, List.of(), null);
}
static TypeView tuple(final List<TupleField> fields) {
return new TypeView(Kind.TUPLE, "tuple", List.copyOf(fields), null, null, List.of(), null);
}
static TypeView typeRef(final String name) {
return new TypeView(Kind.TYPE_REF, name, List.of(), null, null, List.of(), null);
}
}
record CallableSymbol(
String name,
List<TypeView> inputTypes,
TypeView outputType,
Span span) {
}
record CallbackSignature(
List<TypeView> inputTypes,
TypeView outputType) {
}
record StructInfo(
Map<String, TypeView> fields,
Map<String, List<CallableSymbol>> methods) {
}
record ServiceInfo(
Map<String, List<CallableSymbol>> methods) {
}
record ContractInfo(
Map<String, List<CallableSymbol>> methods) {
}
static final class Model {
final Map<String, List<CallableSymbol>> topLevelCallables = new HashMap<>();
final Map<String, StructInfo> structs = new HashMap<>();
final Map<String, ServiceInfo> services = new HashMap<>();
final Map<String, ContractInfo> contracts = new HashMap<>();
final Map<String, CallbackSignature> callbacks = new HashMap<>();
final Map<String, Set<String>> enums = new HashMap<>();
final Map<String, Set<String>> errors = new HashMap<>();
final Map<String, TypeView> constTypes = new HashMap<>();
final Map<String, TypeView> serviceSingletons = new HashMap<>();
static Model from(final PbsAst.File ast) {
final var model = new Model();
for (final var topDecl : ast.topDecls()) {
if (topDecl instanceof PbsAst.StructDecl structDecl) {
final var fields = new HashMap<String, TypeView>();
for (final var field : structDecl.fields()) {
fields.put(field.name(), model.typeFrom(field.typeRef()));
}
final var methods = new HashMap<String, List<CallableSymbol>>();
for (final var method : structDecl.methods()) {
methods.computeIfAbsent(method.name(), ignored -> new ArrayList<>())
.add(model.callableFrom(
method.name(),
method.parameters(),
method.returnKind(),
method.returnType(),
method.resultErrorType(),
method.span()));
}
model.structs.put(structDecl.name(), new StructInfo(fields, methods));
continue;
}
if (topDecl instanceof PbsAst.ServiceDecl serviceDecl) {
final var methods = new HashMap<String, List<CallableSymbol>>();
for (final var method : serviceDecl.methods()) {
methods.computeIfAbsent(method.name(), ignored -> new ArrayList<>())
.add(model.callableFrom(
method.name(),
method.parameters(),
method.returnKind(),
method.returnType(),
method.resultErrorType(),
method.span()));
}
model.services.put(serviceDecl.name(), new ServiceInfo(methods));
model.serviceSingletons.put(serviceDecl.name(), TypeView.service(serviceDecl.name()));
continue;
}
if (topDecl instanceof PbsAst.ContractDecl contractDecl) {
final var methods = new HashMap<String, List<CallableSymbol>>();
for (final var signature : contractDecl.signatures()) {
methods.computeIfAbsent(signature.name(), ignored -> new ArrayList<>())
.add(model.callableFrom(
signature.name(),
signature.parameters(),
signature.returnKind(),
signature.returnType(),
signature.resultErrorType(),
signature.span()));
}
model.contracts.put(contractDecl.name(), new ContractInfo(methods));
continue;
}
if (topDecl instanceof PbsAst.FunctionDecl functionDecl) {
model.topLevelCallables.computeIfAbsent(functionDecl.name(), ignored -> new ArrayList<>())
.add(model.callableFrom(
functionDecl.name(),
functionDecl.parameters(),
functionDecl.returnKind(),
functionDecl.returnType(),
functionDecl.resultErrorType(),
functionDecl.span()));
continue;
}
if (topDecl instanceof PbsAst.CallbackDecl(
String name, ReadOnlyList<PbsAst.Parameter> parameters, PbsAst.ReturnKind returnKind,
PbsAst.TypeRef returnType, PbsAst.TypeRef resultErrorType, Span span
)) {
final var symbol = model.callableFrom(
name,
parameters,
returnKind,
returnType,
resultErrorType,
span);
model.callbacks.put(name, new CallbackSignature(symbol.inputTypes(), symbol.outputType()));
continue;
}
if (topDecl instanceof PbsAst.EnumDecl enumDecl) {
final var cases = new HashSet<String>();
for (final var enumCase : enumDecl.cases()) {
cases.add(enumCase.name());
}
model.enums.put(enumDecl.name(), cases);
continue;
}
if (topDecl instanceof PbsAst.ErrorDecl errorDecl) {
model.errors.put(errorDecl.name(), new HashSet<>(errorDecl.cases().asList()));
continue;
}
if (topDecl instanceof PbsAst.ConstDecl constDecl && constDecl.explicitType() != null) {
model.constTypes.put(constDecl.name(), model.typeFrom(constDecl.explicitType()));
}
}
return model;
}
private CallableSymbol callableFrom(
final String name,
final ReadOnlyList<PbsAst.Parameter> parameters,
final PbsAst.ReturnKind returnKind,
final PbsAst.TypeRef returnType,
final PbsAst.TypeRef resultErrorType,
final Span span) {
final var input = new ArrayList<TypeView>(parameters.size());
for (final var parameter : parameters) {
input.add(typeFrom(parameter.typeRef()));
}
return new CallableSymbol(name, input, callableReturn(returnKind, returnType, resultErrorType), span);
}
private TypeView callableReturn(
final PbsAst.ReturnKind returnKind,
final PbsAst.TypeRef returnType,
final PbsAst.TypeRef resultErrorType) {
return switch (returnKind) {
case INFERRED_UNIT, EXPLICIT_UNIT -> TypeView.unit();
case PLAIN -> collapse(typeFrom(returnType));
case RESULT -> TypeView.result(typeFrom(resultErrorType), collapse(typeFrom(returnType)));
};
}
private TypeView collapse(final TypeView type) {
if (type.kind() == Kind.TUPLE && type.tupleFields().size() == 1) {
return type.tupleFields().getFirst().type();
}
return type;
}
private TypeView typeFrom(final PbsAst.TypeRef typeRef) {
if (typeRef == null) {
return TypeView.unit();
}
return switch (typeRef.kind()) {
case UNIT -> TypeView.unit();
case SELF, ERROR -> TypeView.unknown();
case SIMPLE -> {
if ("int".equals(typeRef.name())) {
yield TypeView.intType();
}
if ("float".equals(typeRef.name())) {
yield TypeView.floatType();
}
if ("bool".equals(typeRef.name())) {
yield TypeView.bool();
}
if ("str".equals(typeRef.name())) {
yield TypeView.str();
}
if (structs.containsKey(typeRef.name())) {
yield TypeView.struct(typeRef.name());
}
if (services.containsKey(typeRef.name())) {
yield TypeView.service(typeRef.name());
}
if (contracts.containsKey(typeRef.name())) {
yield TypeView.contract(typeRef.name());
}
if (enums.containsKey(typeRef.name())) {
yield TypeView.enumType(typeRef.name());
}
if (errors.containsKey(typeRef.name())) {
yield TypeView.error(typeRef.name());
}
final var callbackSignature = callbacks.get(typeRef.name());
if (callbackSignature != null) {
yield TypeView.callback(typeRef.name(), callbackSignature.inputTypes(), callbackSignature.outputType());
}
yield TypeView.unknown();
}
case OPTIONAL -> TypeView.optional(typeFrom(typeRef.inner()));
case GROUP -> typeFrom(typeRef.inner());
case NAMED_TUPLE -> {
final var fields = new ArrayList<TupleField>(typeRef.fields().size());
for (final var field : typeRef.fields()) {
fields.add(new TupleField(field.label(), typeFrom(field.typeRef())));
}
yield TypeView.tuple(fields);
}
};
}
}
static final class Scope {
private final Map<String, TypeView> names = new HashMap<>();
Scope copy() {
final var scope = new Scope();
scope.names.putAll(names);
return scope;
}
void bind(final String name, final TypeView type) {
names.put(name, type);
}
TypeView resolve(final String name) {
return names.get(name);
}
}
}

View File

@ -0,0 +1,197 @@
package p.studio.compiler.pbs.semantics;
import p.studio.compiler.pbs.ast.PbsAst;
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.Kind;
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.Model;
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.TupleField;
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.TypeView;
import java.util.ArrayList;
import java.util.List;
final class PbsFlowTypeOps {
TypeView inferBinaryResult(final String operator, final TypeView left, final TypeView right) {
if ("+".equals(operator) || "-".equals(operator) || "*".equals(operator) || "/".equals(operator) || "%".equals(operator)) {
if (isFloat(left) || isFloat(right)) {
return TypeView.floatType();
}
if (isInt(left) && isInt(right)) {
return TypeView.intType();
}
return TypeView.unknown();
}
if ("==".equals(operator)
|| "!=".equals(operator)
|| "<".equals(operator)
|| "<=".equals(operator)
|| ">".equals(operator)
|| ">=".equals(operator)
|| "and".equals(operator)
|| "or".equals(operator)
|| "&&".equals(operator)
|| "||".equals(operator)) {
return TypeView.bool();
}
return TypeView.unknown();
}
boolean compatible(final TypeView actual, final TypeView expected) {
if (actual == null || expected == null) {
return true;
}
if (actual.kind() == Kind.UNKNOWN || expected.kind() == Kind.UNKNOWN) {
return true;
}
if (actual.kind() != expected.kind()) {
return false;
}
return switch (actual.kind()) {
case UNIT, INT, FLOAT, BOOL, STR -> true;
case STRUCT, SERVICE, CONTRACT, CALLBACK, ENUM, ERROR, TYPE_REF -> actual.name().equals(expected.name());
case OPTIONAL -> compatible(actual.inner(), expected.inner());
case RESULT -> compatible(actual.errorType(), expected.errorType()) && compatible(actual.inner(), expected.inner());
case TUPLE -> tupleCompatible(actual, expected);
case UNKNOWN -> true;
};
}
boolean inputCompatible(final List<TypeView> inputTypes, final TypeView argumentType) {
if (inputTypes.isEmpty()) {
return isUnit(argumentType) || argumentType.kind() == Kind.UNKNOWN;
}
if (inputTypes.size() == 1) {
return compatible(argumentType, inputTypes.getFirst());
}
if (argumentType.kind() != Kind.TUPLE) {
return false;
}
if (argumentType.tupleFields().size() != inputTypes.size()) {
return false;
}
for (int i = 0; i < inputTypes.size(); i++) {
if (!compatible(argumentType.tupleFields().get(i).type(), inputTypes.get(i))) {
return false;
}
}
return true;
}
TypeView callableReturnType(
final PbsAst.ReturnKind returnKind,
final PbsAst.TypeRef returnType,
final PbsAst.TypeRef resultErrorType,
final Model model) {
return switch (returnKind) {
case INFERRED_UNIT, EXPLICIT_UNIT -> TypeView.unit();
case PLAIN -> collapseReturnPayload(typeFromTypeRef(returnType, model, null));
case RESULT -> TypeView.result(
typeFromTypeRef(resultErrorType, model, null),
collapseReturnPayload(typeFromTypeRef(returnType, model, null)));
};
}
TypeView typeFromTypeRef(
final PbsAst.TypeRef typeRef,
final Model model,
final TypeView receiverType) {
if (typeRef == null) {
return TypeView.unit();
}
return switch (typeRef.kind()) {
case UNIT -> TypeView.unit();
case SELF -> receiverType == null ? TypeView.unknown() : receiverType;
case SIMPLE -> simpleType(typeRef.name(), model);
case OPTIONAL -> TypeView.optional(typeFromTypeRef(typeRef.inner(), model, receiverType));
case GROUP -> typeFromTypeRef(typeRef.inner(), model, receiverType);
case NAMED_TUPLE -> {
final var fields = new ArrayList<TupleField>(typeRef.fields().size());
for (final var field : typeRef.fields()) {
fields.add(new TupleField(field.label(), typeFromTypeRef(field.typeRef(), model, receiverType)));
}
yield TypeView.tuple(fields);
}
case ERROR -> TypeView.unknown();
};
}
boolean isScalarComparable(final TypeView type) {
return isBool(type) || isInt(type) || isFloat(type) || isStr(type);
}
boolean isUnit(final TypeView type) {
return type.kind() == Kind.UNIT || type.kind() == Kind.UNKNOWN;
}
boolean isBool(final TypeView type) {
return type.kind() == Kind.BOOL || type.kind() == Kind.UNKNOWN;
}
boolean isInt(final TypeView type) {
return type.kind() == Kind.INT || type.kind() == Kind.UNKNOWN;
}
boolean isFloat(final TypeView type) {
return type.kind() == Kind.FLOAT || type.kind() == Kind.UNKNOWN;
}
boolean isStr(final TypeView type) {
return type.kind() == Kind.STR || type.kind() == Kind.UNKNOWN;
}
private boolean tupleCompatible(final TypeView actual, final TypeView expected) {
if (actual.tupleFields().size() != expected.tupleFields().size()) {
return false;
}
for (int i = 0; i < actual.tupleFields().size(); i++) {
if (!compatible(actual.tupleFields().get(i).type(), expected.tupleFields().get(i).type())) {
return false;
}
}
return true;
}
private TypeView collapseReturnPayload(final TypeView type) {
if (type == null) {
return TypeView.unit();
}
if (type.kind() == Kind.TUPLE && type.tupleFields().size() == 1) {
return type.tupleFields().getFirst().type();
}
return type;
}
private TypeView simpleType(final String name, final Model model) {
if ("int".equals(name)) {
return TypeView.intType();
}
if ("float".equals(name)) {
return TypeView.floatType();
}
if ("bool".equals(name)) {
return TypeView.bool();
}
if ("str".equals(name)) {
return TypeView.str();
}
if (model.structs.containsKey(name)) {
return TypeView.struct(name);
}
if (model.services.containsKey(name)) {
return TypeView.service(name);
}
if (model.contracts.containsKey(name)) {
return TypeView.contract(name);
}
if (model.enums.containsKey(name)) {
return TypeView.enumType(name);
}
if (model.errors.containsKey(name)) {
return TypeView.error(name);
}
final var callbackSignature = model.callbacks.get(name);
if (callbackSignature != null) {
return TypeView.callback(name, callbackSignature.inputTypes(), callbackSignature.outputType());
}
return TypeView.unknown();
}
}