implements PR-10.1
This commit is contained in:
parent
ba69a64832
commit
e56fe2b9b7
@ -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) {
|
||||
|
||||
@ -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<PbsToken> 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<PbsToken> 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<PbsToken> 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<PbsAst.Attribute> 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(
|
||||
|
||||
@ -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()));
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user