small code improvements

This commit is contained in:
bQUARKz 2026-02-27 16:19:50 +00:00
parent 956d3128a9
commit f3be4f7946
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
8 changed files with 72 additions and 28 deletions

View File

@ -1,6 +1,7 @@
package p.studio.compiler.pbs; package p.studio.compiler.pbs;
import p.studio.compiler.models.IRFunction; import p.studio.compiler.models.IRFunction;
import p.studio.compiler.models.IRBackendFile;
import p.studio.compiler.pbs.ast.PbsAst; import p.studio.compiler.pbs.ast.PbsAst;
import p.studio.compiler.pbs.lexer.PbsLexer; import p.studio.compiler.pbs.lexer.PbsLexer;
import p.studio.compiler.pbs.parser.PbsParser; import p.studio.compiler.pbs.parser.PbsParser;
@ -13,14 +14,14 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
public final class PbsFrontendCompiler { public final class PbsFrontendCompiler {
public ReadOnlyList<IRFunction> compileFile( public IRBackendFile compileFile(
final FileId fileId, final FileId fileId,
final String source, final String source,
final DiagnosticSink diagnostics) { final DiagnosticSink diagnostics) {
final var tokens = PbsLexer.lex(source, fileId, diagnostics); final var tokens = PbsLexer.lex(source, fileId, diagnostics);
final var ast = PbsParser.parse(tokens, fileId, diagnostics); final var ast = PbsParser.parse(tokens, fileId, diagnostics);
validateFunctionNames(ast, diagnostics); validateFunctionNames(ast, diagnostics);
return lowerFunctions(fileId, ast); return new IRBackendFile(fileId, lowerFunctions(fileId, ast));
} }
private void validateFunctionNames( private void validateFunctionNames(

View File

@ -4,10 +4,6 @@ import p.studio.compiler.source.Span;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
public final class PbsAst { public final class PbsAst {
public sealed interface Statement permits LetStatement, ReturnStatement, ExpressionStatement {
Span span();
}
private PbsAst() { private PbsAst() {
} }
@ -36,6 +32,10 @@ public final class PbsAst {
Span span) { Span span) {
} }
public sealed interface Statement permits LetStatement, ReturnStatement, ExpressionStatement {
Span span();
}
public record Block( public record Block(
ReadOnlyList<Statement> statements, ReadOnlyList<Statement> statements,
Span span) { Span span) {

View File

@ -4,11 +4,9 @@ import lombok.extern.slf4j.Slf4j;
import p.studio.compiler.messages.BuildingIssueSink; import p.studio.compiler.messages.BuildingIssueSink;
import p.studio.compiler.messages.FrontendPhaseContext; import p.studio.compiler.messages.FrontendPhaseContext;
import p.studio.compiler.models.IRBackend; import p.studio.compiler.models.IRBackend;
import p.studio.compiler.models.IRFunction;
import p.studio.compiler.pbs.PbsFrontendCompiler; import p.studio.compiler.pbs.PbsFrontendCompiler;
import p.studio.compiler.source.diagnostics.DiagnosticSink; import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.utilities.logs.LogAggregator; import p.studio.utilities.logs.LogAggregator;
import p.studio.utilities.structures.MutableList;
@Slf4j @Slf4j
public class PBSFrontendPhaseService implements FrontendPhaseService { public class PBSFrontendPhaseService implements FrontendPhaseService {
@ -20,7 +18,7 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
final DiagnosticSink diagnostics, final DiagnosticSink diagnostics,
final LogAggregator logs, final LogAggregator logs,
final BuildingIssueSink issues) { final BuildingIssueSink issues) {
final MutableList<IRFunction> functions = MutableList.create(); final var irBackendAggregator = IRBackend.aggregator();
for (final var pId : ctx.stack.reverseTopologicalOrder) { for (final var pId : ctx.stack.reverseTopologicalOrder) {
final var fileIds = ctx.fileTable.getFiles(pId); final var fileIds = ctx.fileTable.getFiles(pId);
@ -30,10 +28,11 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
switch (sourceHandle.getExtension()) { switch (sourceHandle.getExtension()) {
case "pbs": { case "pbs": {
sourceHandle.readUtf8().ifPresentOrElse( sourceHandle.readUtf8().ifPresentOrElse(
utf8Content -> functions.addAll(frontendCompiler utf8Content -> {
.compileFile(fId, utf8Content, diagnostics) final var irBackendFile = frontendCompiler
.stream() .compileFile(fId, utf8Content, diagnostics);
.toList()), irBackendAggregator.merge(irBackendFile);
},
() -> issues.report(builder -> builder () -> issues.report(builder -> builder
.error(true) .error(true)
.message("Failed to read file content: %s".formatted(sourceHandle.toString())))); .message("Failed to read file content: %s".formatted(sourceHandle.toString()))));
@ -45,10 +44,8 @@ public class PBSFrontendPhaseService implements FrontendPhaseService {
} }
} }
logs.using(log).debug("PBS frontend lowered %d function(s) to IR".formatted(functions.size())); final var irBackend = irBackendAggregator.emit();
return IRBackend logs.using(log).debug("PBS frontend lowered to IR BE:\n%s".formatted(irBackend));
.builder() return irBackend;
.functions(functions.toReadOnlyList())
.build();
} }
} }

View File

@ -23,7 +23,8 @@ class PbsFrontendCompilerTest {
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var compiler = new PbsFrontendCompiler(); final var compiler = new PbsFrontendCompiler();
final var functions = compiler.compileFile(new FileId(0), source, diagnostics); final var fileBackend = compiler.compileFile(new FileId(0), source, diagnostics);
final var functions = fileBackend.functions();
assertTrue(diagnostics.isEmpty(), "Valid program should not report diagnostics"); assertTrue(diagnostics.isEmpty(), "Valid program should not report diagnostics");
assertEquals(2, functions.size()); assertEquals(2, functions.size());

View File

@ -27,7 +27,6 @@ public class FrontendPhasePipelineStage implements PipelineStage {
final var diagnostics = DiagnosticSink.empty(); final var diagnostics = DiagnosticSink.empty();
final var issues = BuildingIssueSink.empty(); final var issues = BuildingIssueSink.empty();
ctx.irBackend = service.get().compile(frontendPhaseContext, diagnostics, logs, issues); ctx.irBackend = service.get().compile(frontendPhaseContext, diagnostics, logs, issues);
logs.using(log).debug("IR Backend: " + ctx.irBackend);
logs.using(log).debug("Frontend phase completed successfully!"); logs.using(log).debug("Frontend phase completed successfully!");
adaptDiagnostics(diagnostics, issues); adaptDiagnostics(diagnostics, issues);
return issues; return issues;

View File

@ -2,6 +2,7 @@ package p.studio.compiler.models;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import p.studio.utilities.structures.MutableList;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
@Builder @Builder
@ -10,9 +11,28 @@ public class IRBackend {
@Builder.Default @Builder.Default
private final ReadOnlyList<IRFunction> functions = ReadOnlyList.empty(); private final ReadOnlyList<IRFunction> functions = ReadOnlyList.empty();
/** public static IRBackendAggregator aggregator() {
* Returns a stable human-readable representation useful for debug logs and tests. return new IRBackendAggregator();
*/ }
public static final class IRBackendAggregator {
private final MutableList<IRFunction> functions = MutableList.create();
public void merge(final IRBackendFile backendFile) {
if (backendFile == null) {
return;
}
functions.addAll(backendFile.functions());
}
public IRBackend emit() {
return IRBackend
.builder()
.functions(functions.toReadOnlyList())
.build();
}
}
@Override @Override
public String toString() { public String toString() {
final var sb = new StringBuilder(); final var sb = new StringBuilder();

View File

@ -0,0 +1,19 @@
package p.studio.compiler.models;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.utilities.structures.ReadOnlyList;
import java.util.Objects;
public record IRBackendFile(
FileId fileId,
ReadOnlyList<IRFunction> functions) {
public IRBackendFile {
fileId = Objects.requireNonNull(fileId, "fileId");
functions = functions == null ? ReadOnlyList.empty() : functions;
}
public static IRBackendFile empty(final FileId fileId) {
return new IRBackendFile(fileId, ReadOnlyList.empty());
}
}

View File

@ -1,10 +1,6 @@
package p.studio.utilities.structures; package p.studio.utilities.structures;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
import java.util.stream.Stream; import java.util.stream.Stream;
public interface MutableList<T> extends ReadOnlyCollection<T>, List<T> { public interface MutableList<T> extends ReadOnlyCollection<T>, List<T> {
@ -114,6 +110,17 @@ public interface MutableList<T> extends ReadOnlyCollection<T>, List<T> {
return asList().containsAll(c); return asList().containsAll(c);
} }
/**
* Appends all functions from the given file using, similar to
* {@link java.util.List#addAll(java.util.Collection)} semantics.
*/
default boolean addAll(final ReadOnlyCollection<? extends T> c) {
if (ReadOnlyCollection.isEmpty(c)) {
return false;
}
return asList().addAll(c.asCollection());
}
@Override @Override
default boolean addAll(final Collection<? extends T> c) { default boolean addAll(final Collection<? extends T> c) {
return asList().addAll(c); return asList().addAll(c);