implements PR-O1.3
This commit is contained in:
parent
9e3d9ccb93
commit
3e14c13979
@ -12,7 +12,9 @@ import p.studio.compiler.pbs.metadata.PbsReservedMetadataExtractor;
|
||||
import p.studio.compiler.pbs.parser.PbsParser;
|
||||
import p.studio.compiler.pbs.semantics.PbsDeclarationSemanticsValidator;
|
||||
import p.studio.compiler.pbs.semantics.PbsFlowSemanticsValidator;
|
||||
import p.studio.compiler.pbs.semantics.PbsSemanticsErrors;
|
||||
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||
import p.studio.compiler.source.diagnostics.DiagnosticPhase;
|
||||
import p.studio.compiler.source.identifiers.FileId;
|
||||
import p.studio.utilities.structures.ReadOnlyList;
|
||||
|
||||
@ -117,9 +119,13 @@ public final class PbsFrontendCompiler {
|
||||
final ReadOnlyList<IRFunction> functions = sourceKind == SourceKind.SDK_INTERFACE
|
||||
? ReadOnlyList.empty()
|
||||
: lowerFunctions(fileId, ast);
|
||||
final var loweringErrorBaseline = diagnostics.errorCount();
|
||||
final ReadOnlyList<IRBackendExecutableFunction> executableFunctions = sourceKind == SourceKind.SDK_INTERFACE
|
||||
? ReadOnlyList.empty()
|
||||
: lowerExecutableFunctions(fileId, ast, moduleKey, reservedMetadata);
|
||||
: lowerExecutableFunctions(fileId, ast, moduleKey, reservedMetadata, diagnostics);
|
||||
if (diagnostics.errorCount() > loweringErrorBaseline) {
|
||||
return IRBackendFile.empty(fileId);
|
||||
}
|
||||
return new IRBackendFile(fileId, functions, executableFunctions, reservedMetadata);
|
||||
}
|
||||
|
||||
@ -140,7 +146,8 @@ public final class PbsFrontendCompiler {
|
||||
final FileId fileId,
|
||||
final PbsAst.File ast,
|
||||
final String moduleKey,
|
||||
final IRReservedMetadata reservedMetadata) {
|
||||
final IRReservedMetadata reservedMetadata,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final var hostByMethodName = new HashMap<String, IRReservedMetadata.HostMethodBinding>();
|
||||
for (final var hostBinding : reservedMetadata.hostMethodBindings()) {
|
||||
hostByMethodName.put(hostBinding.sourceMethodName(), hostBinding);
|
||||
@ -157,8 +164,25 @@ public final class PbsFrontendCompiler {
|
||||
final var instructions = new ArrayList<IRBackendExecutableFunction.Instruction>();
|
||||
final var callsites = new ArrayList<PbsAst.CallExpr>();
|
||||
collectCallsFromBlock(fn.body(), callsites);
|
||||
callsites.sort((a, b) -> {
|
||||
final var deltaStart = Long.compare(a.span().getStart(), b.span().getStart());
|
||||
if (deltaStart != 0) {
|
||||
return deltaStart;
|
||||
}
|
||||
return Long.compare(a.span().getEnd(), b.span().getEnd());
|
||||
});
|
||||
for (final var callExpr : callsites) {
|
||||
final var calleeName = extractSimpleCalleeName(callExpr.callee());
|
||||
if (calleeName == null || calleeName.isBlank()) {
|
||||
diagnostics.error(
|
||||
DiagnosticPhase.STATIC_SEMANTICS,
|
||||
PbsSemanticsErrors.E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE.name(),
|
||||
PbsSemanticsErrors.E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE.name(),
|
||||
Map.of(),
|
||||
"executable lowering requires resolvable callee identity",
|
||||
callExpr.span());
|
||||
continue;
|
||||
}
|
||||
final var host = hostByMethodName.get(calleeName);
|
||||
if (host != null) {
|
||||
instructions.add(new IRBackendExecutableFunction.Instruction(
|
||||
@ -395,7 +419,7 @@ public final class PbsFrontendCompiler {
|
||||
case PbsAst.MemberExpr memberExpr -> memberExpr.memberName();
|
||||
case PbsAst.BindExpr bindExpr -> bindExpr.functionName();
|
||||
case PbsAst.GroupExpr groupExpr -> extractSimpleCalleeName(groupExpr.expression());
|
||||
default -> "<unknown>";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,4 +59,5 @@ public enum PbsSemanticsErrors {
|
||||
E_SEM_HANDLE_NON_RESULT,
|
||||
E_SEM_HANDLE_ERROR_MISMATCH,
|
||||
E_SEM_HANDLE_ARM_TERMINAL_INVALID,
|
||||
E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE,
|
||||
}
|
||||
|
||||
@ -98,6 +98,31 @@ class PbsFrontendCompilerTest {
|
||||
i.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_FUNC));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldLowerExecutableCallsitesInDeterministicSourceOrder() {
|
||||
final var source = """
|
||||
fn b() -> int { return 1; }
|
||||
fn c() -> int { return 2; }
|
||||
fn a() -> int {
|
||||
b();
|
||||
c();
|
||||
return 0;
|
||||
}
|
||||
""";
|
||||
|
||||
final var diagnostics = DiagnosticSink.empty();
|
||||
final var compiler = new PbsFrontendCompiler();
|
||||
final var fileBackend = compiler.compileFile(new FileId(99), source, diagnostics);
|
||||
|
||||
assertTrue(diagnostics.isEmpty(), "Valid program should not report diagnostics");
|
||||
final var executableA = fileBackend.executableFunctions().stream()
|
||||
.filter(fn -> fn.callableName().equals("a"))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
assertEquals("b", executableA.instructions().get(0).calleeCallableName());
|
||||
assertEquals("c", executableA.instructions().get(1).calleeCallableName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotLowerWhenSyntaxErrorsExist() {
|
||||
final var source = """
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user