diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/parser/PbsExprParser.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/parser/PbsExprParser.java index 6a11e2ea..72220733 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/parser/PbsExprParser.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/parser/PbsExprParser.java @@ -4,8 +4,6 @@ import p.studio.compiler.pbs.ast.PbsAst; import p.studio.compiler.pbs.lexer.PbsToken; import p.studio.compiler.pbs.lexer.PbsTokenKind; import p.studio.compiler.source.Span; -import p.studio.compiler.source.diagnostics.DiagnosticSink; -import p.studio.compiler.source.identifiers.FileId; import p.studio.utilities.structures.ReadOnlyList; import java.util.ArrayList; @@ -21,19 +19,15 @@ final class PbsExprParser { PbsAst.Block parse(String message); } + private final PbsParserContext context; private final PbsTokenCursor cursor; - private final FileId fileId; - private final DiagnosticSink diagnostics; private final BlockParserDelegate blockParserDelegate; PbsExprParser( - final PbsTokenCursor cursor, - final FileId fileId, - final DiagnosticSink diagnostics, + final PbsParserContext context, final BlockParserDelegate blockParserDelegate) { - this.cursor = cursor; - this.fileId = fileId; - this.diagnostics = diagnostics; + this.context = context; + this.cursor = context.cursor(); this.blockParserDelegate = blockParserDelegate; } @@ -644,11 +638,11 @@ final class PbsExprParser { } private Span span(final long start, final long end) { - return new Span(fileId, start, end); + return context.span(start, end); } private void report(final PbsToken token, final ParseErrors parseErrors, final String message) { - p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, parseErrors.name(), message, new Span(fileId, token.start(), token.end())); + context.report(token, parseErrors, message); } private long parseLongOrDefault(final String text) { diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/parser/PbsParser.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/parser/PbsParser.java index 399920fa..38b6c09a 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/parser/PbsParser.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/parser/PbsParser.java @@ -4,7 +4,6 @@ import p.studio.compiler.pbs.ast.PbsAst; import p.studio.compiler.pbs.lexer.PbsToken; import p.studio.compiler.pbs.lexer.PbsTokenKind; import p.studio.compiler.source.Span; -import p.studio.compiler.source.diagnostics.DiagnosticSink; import p.studio.compiler.source.diagnostics.RelatedSpan; import p.studio.compiler.source.identifiers.FileId; import p.studio.utilities.structures.ReadOnlyList; @@ -30,23 +29,18 @@ public final class PbsParser { INTERFACE_MODULE } + private final PbsParserContext context; private final PbsTokenCursor cursor; private final PbsExprParser exprParser; - private final FileId fileId; - private final DiagnosticSink diagnostics; - private final ParseMode parseMode; - private int loopDepth; private PbsParser( final ReadOnlyList tokens, final FileId fileId, - final DiagnosticSink diagnostics, + final p.studio.compiler.source.diagnostics.DiagnosticSink diagnostics, final ParseMode parseMode) { - this.cursor = new PbsTokenCursor(tokens); - this.exprParser = new PbsExprParser(cursor, fileId, diagnostics, this::parseExpressionSurfaceBlock); - this.fileId = fileId; - this.diagnostics = diagnostics; - this.parseMode = parseMode; + this.context = new PbsParserContext(new PbsTokenCursor(tokens), fileId, diagnostics, parseMode); + this.cursor = context.cursor(); + this.exprParser = new PbsExprParser(context, this::parseExpressionSurfaceBlock); } /** @@ -55,14 +49,14 @@ public final class PbsParser { public static PbsAst.File parse( final ReadOnlyList tokens, final FileId fileId, - final DiagnosticSink diagnostics) { + final p.studio.compiler.source.diagnostics.DiagnosticSink diagnostics) { return parse(tokens, fileId, diagnostics, ParseMode.ORDINARY); } public static PbsAst.File parse( final ReadOnlyList tokens, final FileId fileId, - final DiagnosticSink diagnostics, + final p.studio.compiler.source.diagnostics.DiagnosticSink diagnostics, final ParseMode parseMode) { return new PbsParser(tokens, fileId, diagnostics, parseMode).parseFile(); } @@ -374,7 +368,7 @@ public final class PbsParser { final ReadOnlyList attributes, final String message) { for (final var attribute : attributes) { - p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, + p.studio.compiler.source.diagnostics.Diagnostics.error(context.diagnostics(), ParseErrors.E_PARSE_ATTRIBUTES_NOT_ALLOWED.name(), message, attribute.span()); @@ -382,11 +376,11 @@ public final class PbsParser { } private boolean isNotInterfaceMode() { - return parseMode != ParseMode.INTERFACE_MODULE; + return context.parseMode() != ParseMode.INTERFACE_MODULE; } private boolean isOrdinaryMode() { - return parseMode == ParseMode.ORDINARY; + return context.parseMode() == ParseMode.ORDINARY; } private PbsAst.StructDecl parseStructDeclaration(final PbsToken declareToken) { @@ -690,7 +684,7 @@ public final class PbsParser { } else { final var firstIdSpan = explicitCaseIds.putIfAbsent(explicitValue, intTokenSpan); if (firstIdSpan != null) { - p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, + p.studio.compiler.source.diagnostics.Diagnostics.error(context.diagnostics(), ParseErrors.E_PARSE_DUPLICATE_ENUM_CASE_ID.name(), "Duplicate explicit enum identifier '%s'".formatted(explicitValue), intTokenSpan, @@ -703,7 +697,7 @@ public final class PbsParser { final var firstLabelSpan = caseLabels.putIfAbsent(caseName.lexeme(), caseNameSpan); if (firstLabelSpan != null) { - p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, + p.studio.compiler.source.diagnostics.Diagnostics.error(context.diagnostics(), ParseErrors.E_PARSE_DUPLICATE_ENUM_CASE_LABEL.name(), "Duplicate enum case label '%s'".formatted(caseName.lexeme()), caseNameSpan, @@ -1226,9 +1220,9 @@ public final class PbsParser { stepExpression = exprParser.parseExpression(); } - loopDepth++; + context.enterLoop(); final var body = parseBlock(); - loopDepth--; + context.exitLoop(); return new PbsAst.ForStatement( iterator.lexeme(), @@ -1254,15 +1248,15 @@ public final class PbsParser { private PbsAst.Statement parseWhileStatement(final PbsToken whileToken) { final var condition = exprParser.parseExpression(); - loopDepth++; + context.enterLoop(); final var body = parseBlock(); - loopDepth--; + context.exitLoop(); return new PbsAst.WhileStatement(condition, body, span(whileToken.start(), body.span().getEnd())); } private PbsAst.Statement parseBreakStatement(final PbsToken breakToken) { final var semicolon = consume(PbsTokenKind.SEMICOLON, "Expected ';' after 'break'"); - if (loopDepth <= 0) { + if (!context.isInsideLoop()) { report(breakToken, ParseErrors.E_PARSE_LOOP_CONTROL_OUTSIDE_LOOP, "'break' is only valid inside loop contexts"); } @@ -1271,7 +1265,7 @@ public final class PbsParser { private PbsAst.Statement parseContinueStatement(final PbsToken continueToken) { final var semicolon = consume(PbsTokenKind.SEMICOLON, "Expected ';' after 'continue'"); - if (loopDepth <= 0) { + if (!context.isInsideLoop()) { report(continueToken, ParseErrors.E_PARSE_LOOP_CONTROL_OUTSIDE_LOOP, "'continue' is only valid inside loop contexts"); } @@ -1412,14 +1406,14 @@ public final class PbsParser { * Builds a source span for the current file. */ private Span span(final long start, final long end) { - return new Span(fileId, start, end); + return context.span(start, end); } /** * Reports a parser diagnostic at the given token span. */ private void report(final PbsToken token, final ParseErrors parseErrors, final String message) { - p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, parseErrors.name(), message, new Span(fileId, token.start(), token.end())); + context.report(token, parseErrors, message); } private record ParsedReturnSpec( diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/parser/PbsParserContext.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/parser/PbsParserContext.java new file mode 100644 index 00000000..715e23d2 --- /dev/null +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/parser/PbsParserContext.java @@ -0,0 +1,61 @@ +package p.studio.compiler.pbs.parser; + +import p.studio.compiler.pbs.lexer.PbsToken; +import p.studio.compiler.source.Span; +import p.studio.compiler.source.diagnostics.DiagnosticSink; +import p.studio.compiler.source.identifiers.FileId; + +final class PbsParserContext { + private final PbsTokenCursor cursor; + private final FileId fileId; + private final DiagnosticSink diagnostics; + private final PbsParser.ParseMode parseMode; + private int loopDepth; + + PbsParserContext( + final PbsTokenCursor cursor, + final FileId fileId, + final DiagnosticSink diagnostics, + final PbsParser.ParseMode parseMode) { + this.cursor = cursor; + this.fileId = fileId; + this.diagnostics = diagnostics; + this.parseMode = parseMode; + } + + PbsTokenCursor cursor() { + return cursor; + } + + DiagnosticSink diagnostics() { + return diagnostics; + } + + PbsParser.ParseMode parseMode() { + return parseMode; + } + + void enterLoop() { + loopDepth++; + } + + void exitLoop() { + loopDepth--; + } + + boolean isInsideLoop() { + return loopDepth > 0; + } + + Span span(final long start, final long end) { + return new Span(fileId, start, end); + } + + void report(final PbsToken token, final ParseErrors parseErrors, final String message) { + p.studio.compiler.source.diagnostics.Diagnostics.error( + diagnostics, + parseErrors.name(), + message, + span(token.start(), token.end())); + } +}