implements PR008
This commit is contained in:
parent
b4887afacb
commit
b84d4c29f6
@ -6,6 +6,7 @@ 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;
|
||||||
import p.studio.compiler.pbs.semantics.PbsDeclarationSemanticsValidator;
|
import p.studio.compiler.pbs.semantics.PbsDeclarationSemanticsValidator;
|
||||||
|
import p.studio.compiler.pbs.semantics.PbsFlowSemanticsValidator;
|
||||||
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||||
import p.studio.compiler.source.identifiers.FileId;
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
import p.studio.utilities.structures.ReadOnlyList;
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
@ -14,6 +15,7 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
public final class PbsFrontendCompiler {
|
public final class PbsFrontendCompiler {
|
||||||
private final PbsDeclarationSemanticsValidator declarationSemanticsValidator = new PbsDeclarationSemanticsValidator();
|
private final PbsDeclarationSemanticsValidator declarationSemanticsValidator = new PbsDeclarationSemanticsValidator();
|
||||||
|
private final PbsFlowSemanticsValidator flowSemanticsValidator = new PbsFlowSemanticsValidator();
|
||||||
|
|
||||||
public IRBackendFile compileFile(
|
public IRBackendFile compileFile(
|
||||||
final FileId fileId,
|
final FileId fileId,
|
||||||
@ -29,6 +31,7 @@ public final class PbsFrontendCompiler {
|
|||||||
final PbsAst.File ast,
|
final PbsAst.File ast,
|
||||||
final DiagnosticSink diagnostics) {
|
final DiagnosticSink diagnostics) {
|
||||||
declarationSemanticsValidator.validate(ast, diagnostics);
|
declarationSemanticsValidator.validate(ast, diagnostics);
|
||||||
|
flowSemanticsValidator.validate(ast, diagnostics);
|
||||||
return new IRBackendFile(fileId, lowerFunctions(fileId, ast));
|
return new IRBackendFile(fileId, lowerFunctions(fileId, ast));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -13,4 +13,25 @@ public enum PbsSemanticsErrors {
|
|||||||
E_SEM_MISSING_CONST_TYPE_ANNOTATION,
|
E_SEM_MISSING_CONST_TYPE_ANNOTATION,
|
||||||
E_SEM_MISSING_CONST_INITIALIZER,
|
E_SEM_MISSING_CONST_INITIALIZER,
|
||||||
E_SEM_INVALID_RETURN_INSIDE_CTOR,
|
E_SEM_INVALID_RETURN_INSIDE_CTOR,
|
||||||
|
E_SEM_APPLY_NON_CALLABLE_TARGET,
|
||||||
|
E_SEM_APPLY_UNRESOLVED_OVERLOAD,
|
||||||
|
E_SEM_APPLY_AMBIGUOUS_OVERLOAD,
|
||||||
|
E_SEM_BARE_METHOD_EXTRACTION,
|
||||||
|
E_SEM_INVALID_MEMBER_ACCESS,
|
||||||
|
E_SEM_IF_NON_BOOL_CONDITION,
|
||||||
|
E_SEM_IF_BRANCH_TYPE_MISMATCH,
|
||||||
|
E_SEM_SWITCH_SELECTOR_INVALID,
|
||||||
|
E_SEM_SWITCH_PATTERN_TYPE_MISMATCH,
|
||||||
|
E_SEM_SWITCH_DUPLICATE_PATTERN,
|
||||||
|
E_SEM_SWITCH_ARM_TYPE_MISMATCH,
|
||||||
|
E_SEM_SWITCH_NON_EXHAUSTIVE,
|
||||||
|
E_SEM_WHILE_NON_BOOL_CONDITION,
|
||||||
|
E_SEM_FOR_TYPE_MISMATCH,
|
||||||
|
E_SEM_NONE_WITHOUT_EXPECTED_OPTIONAL,
|
||||||
|
E_SEM_ELSE_NON_OPTIONAL_LEFT,
|
||||||
|
E_SEM_ELSE_FALLBACK_TYPE_MISMATCH,
|
||||||
|
E_SEM_RESULT_PROPAGATE_NON_RESULT,
|
||||||
|
E_SEM_RESULT_PROPAGATE_ERROR_MISMATCH,
|
||||||
|
E_SEM_HANDLE_NON_RESULT,
|
||||||
|
E_SEM_HANDLE_ERROR_MISMATCH,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
package p.studio.compiler.pbs.semantics;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.studio.compiler.pbs.PbsFrontendCompiler;
|
||||||
|
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class PbsSemanticsApplyResolutionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldDifferentiateNonCallableUnresolvedAndAmbiguousApply() {
|
||||||
|
final var source = """
|
||||||
|
fn over(x: int) -> int { return x; }
|
||||||
|
fn over(x: float) -> int { return 0; }
|
||||||
|
fn pair(a: int, b: int) -> int { return a + b; }
|
||||||
|
|
||||||
|
fn demo() -> int {
|
||||||
|
let a: int = 1 apply ();
|
||||||
|
let b: int = pair apply 1;
|
||||||
|
let c: int = over apply missing;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
new PbsFrontendCompiler().compileFile(new FileId(0), source, diagnostics);
|
||||||
|
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_APPLY_NON_CALLABLE_TARGET.name())));
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_APPLY_UNRESOLVED_OVERLOAD.name())));
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_APPLY_AMBIGUOUS_OVERLOAD.name())));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package p.studio.compiler.pbs.semantics;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.studio.compiler.pbs.PbsFrontendCompiler;
|
||||||
|
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class PbsSemanticsControlFlowTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldValidateIfSwitchAndProjectionRules() {
|
||||||
|
final var source = """
|
||||||
|
declare enum Mode(Idle, Run);
|
||||||
|
|
||||||
|
declare struct State(v: int) {
|
||||||
|
fn value() -> int { return this.v; }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flow(m: Mode, s: State) -> int {
|
||||||
|
let a: int = if 1 { 1 } else { 2 };
|
||||||
|
let b: int = switch m { Mode.Idle: { 1 } };
|
||||||
|
let c: int = s.missing;
|
||||||
|
let d = s.value;
|
||||||
|
return a + b + c + d;
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
new PbsFrontendCompiler().compileFile(new FileId(0), source, diagnostics);
|
||||||
|
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_IF_NON_BOOL_CONDITION.name())));
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_SWITCH_NON_EXHAUSTIVE.name())));
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_INVALID_MEMBER_ACCESS.name())));
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_BARE_METHOD_EXTRACTION.name())));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package p.studio.compiler.pbs.semantics;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.studio.compiler.pbs.PbsFrontendCompiler;
|
||||||
|
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class PbsSemanticsOptionalResultTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldValidateOptionalAndResultFlowRules() {
|
||||||
|
final var source = """
|
||||||
|
declare error ErrA { Fail; }
|
||||||
|
declare error ErrB { Oops; }
|
||||||
|
|
||||||
|
fn make() -> result<ErrA> int { return ok(1); }
|
||||||
|
|
||||||
|
fn badOptional() -> int {
|
||||||
|
let x = none;
|
||||||
|
let y: int = 1 else 2;
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn badResult() -> result<ErrB> int {
|
||||||
|
let a: int = make()!;
|
||||||
|
let b: int = handle make() { ErrA.Fail -> ErrA.Fail };
|
||||||
|
return ok(a + b);
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
new PbsFrontendCompiler().compileFile(new FileId(0), source, diagnostics);
|
||||||
|
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_NONE_WITHOUT_EXPECTED_OPTIONAL.name())));
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_ELSE_NON_OPTIONAL_LEFT.name())));
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_RESULT_PROPAGATE_ERROR_MISMATCH.name())));
|
||||||
|
assertTrue(diagnostics.stream().anyMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_HANDLE_ERROR_MISMATCH.name())));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user